xref: /AOO41X/main/sc/source/core/data/markdata.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 // INCLUDE ---------------------------------------------------------------
30 
31 #include <tools/debug.hxx>
32 
33 #include "markdata.hxx"
34 #include "markarr.hxx"
35 #include "rangelst.hxx"
36 
37 // STATIC DATA -----------------------------------------------------------
38 
39 //------------------------------------------------------------------------
40 
ScMarkData()41 ScMarkData::ScMarkData() :
42     pMultiSel( NULL )
43 {
44     for (SCTAB i=0; i<=MAXTAB; i++)
45         bTabMarked[i] = sal_False;
46 
47     ResetMark();
48 }
49 
ScMarkData(const ScMarkData & rData)50 ScMarkData::ScMarkData(const ScMarkData& rData) :
51     aMarkRange( rData.aMarkRange ),
52     aMultiRange( rData.aMultiRange ),
53     pMultiSel( NULL )
54 {
55     bMarked      = rData.bMarked;
56     bMultiMarked = rData.bMultiMarked;
57     bMarking     = rData.bMarking;
58     bMarkIsNeg   = rData.bMarkIsNeg;
59 
60     for (SCTAB i=0; i<=MAXTAB; i++)
61         bTabMarked[i] = rData.bTabMarked[i];
62 
63     if (rData.pMultiSel)
64     {
65         pMultiSel = new ScMarkArray[MAXCOLCOUNT];
66         for (SCCOL j=0; j<MAXCOLCOUNT; j++)
67             rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
68     }
69 }
70 
operator =(const ScMarkData & rData)71 ScMarkData& ScMarkData::operator=(const ScMarkData& rData)
72 {
73     if ( &rData == this )
74         return *this;
75 
76     delete[] pMultiSel;
77     pMultiSel = NULL;
78 
79     aMarkRange   = rData.aMarkRange;
80     aMultiRange  = rData.aMultiRange;
81     bMarked      = rData.bMarked;
82     bMultiMarked = rData.bMultiMarked;
83     bMarking     = rData.bMarking;
84     bMarkIsNeg   = rData.bMarkIsNeg;
85 
86     for (SCTAB i=0; i<=MAXTAB; i++)
87         bTabMarked[i] = rData.bTabMarked[i];
88 
89     if (rData.pMultiSel)
90     {
91         pMultiSel = new ScMarkArray[MAXCOLCOUNT];
92         for (SCCOL j=0; j<MAXCOLCOUNT; j++)
93             rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
94     }
95 
96     return *this;
97 }
98 
~ScMarkData()99 ScMarkData::~ScMarkData()
100 {
101     delete[] pMultiSel;
102 }
103 
ResetMark()104 void ScMarkData::ResetMark()
105 {
106     delete[] pMultiSel;
107     pMultiSel = NULL;
108 
109     bMarked = bMultiMarked = sal_False;
110     bMarking = bMarkIsNeg = sal_False;
111 }
112 
SetMarkArea(const ScRange & rRange)113 void ScMarkData::SetMarkArea( const ScRange& rRange )
114 {
115     aMarkRange = rRange;
116     aMarkRange.Justify();
117     if ( !bMarked )
118     {
119         // #77987# Upon creation of a document ScFormatShell GetTextAttrState
120         // may query (default) attributes although no sheet is marked yet.
121         // => mark that one.
122         if ( !GetSelectCount() )
123             bTabMarked[ aMarkRange.aStart.Tab() ] = sal_True;
124         bMarked = sal_True;
125     }
126 }
127 
GetMarkArea(ScRange & rRange) const128 void ScMarkData::GetMarkArea( ScRange& rRange ) const
129 {
130     rRange = aMarkRange;        //! inline ?
131 }
132 
GetMultiMarkArea(ScRange & rRange) const133 void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const
134 {
135     rRange = aMultiRange;
136 }
137 
SetMultiMarkArea(const ScRange & rRange,sal_Bool bMark)138 void ScMarkData::SetMultiMarkArea( const ScRange& rRange, sal_Bool bMark )
139 {
140     if (!pMultiSel)
141     {
142         pMultiSel = new ScMarkArray[MAXCOL+1];
143 
144         // if simple mark range is set, copy to multi marks
145         if ( bMarked && !bMarkIsNeg )
146         {
147             bMarked = sal_False;
148             SetMultiMarkArea( aMarkRange, sal_True );
149         }
150     }
151 
152     SCCOL nStartCol = rRange.aStart.Col();
153     SCROW nStartRow = rRange.aStart.Row();
154     SCCOL nEndCol = rRange.aEnd.Col();
155     SCROW nEndRow = rRange.aEnd.Row();
156     PutInOrder( nStartRow, nEndRow );
157     PutInOrder( nStartCol, nEndCol );
158 
159     SCCOL nCol;
160     for (nCol=nStartCol; nCol<=nEndCol; nCol++)
161         pMultiSel[nCol].SetMarkArea( nStartRow, nEndRow, bMark );
162 
163     if ( bMultiMarked )                 // aMultiRange updaten
164     {
165         if ( nStartCol < aMultiRange.aStart.Col() )
166             aMultiRange.aStart.SetCol( nStartCol );
167         if ( nStartRow < aMultiRange.aStart.Row() )
168             aMultiRange.aStart.SetRow( nStartRow );
169         if ( nEndCol > aMultiRange.aEnd.Col() )
170             aMultiRange.aEnd.SetCol( nEndCol );
171         if ( nEndRow > aMultiRange.aEnd.Row() )
172             aMultiRange.aEnd.SetRow( nEndRow );
173     }
174     else
175     {
176         aMultiRange = rRange;           // neu
177         bMultiMarked = sal_True;
178     }
179 }
180 
SetAreaTab(SCTAB nTab)181 void ScMarkData::SetAreaTab( SCTAB nTab )
182 {
183     aMarkRange.aStart.SetTab(nTab);
184     aMarkRange.aEnd.SetTab(nTab);
185     aMultiRange.aStart.SetTab(nTab);
186     aMultiRange.aEnd.SetTab(nTab);
187 }
188 
SelectOneTable(SCTAB nTab)189 void ScMarkData::SelectOneTable( SCTAB nTab )
190 {
191     for (SCTAB i=0; i<=MAXTAB; i++)
192         bTabMarked[i] = ( nTab == i );
193 }
194 
GetSelectCount() const195 SCTAB ScMarkData::GetSelectCount() const
196 {
197     SCTAB nCount = 0;
198     for (SCTAB i=0; i<=MAXTAB; i++)
199         if (bTabMarked[i])
200             ++nCount;
201 
202     return nCount;
203 }
204 
GetFirstSelected() const205 SCTAB ScMarkData::GetFirstSelected() const
206 {
207     for (SCTAB i=0; i<=MAXTAB; i++)
208         if (bTabMarked[i])
209             return i;
210 
211     DBG_ERROR("GetFirstSelected: keine markiert");
212     return 0;
213 }
214 
MarkToMulti()215 void ScMarkData::MarkToMulti()
216 {
217     if ( bMarked && !bMarking )
218     {
219         SetMultiMarkArea( aMarkRange, !bMarkIsNeg );
220         bMarked = sal_False;
221 
222         //  check if all multi mark ranges have been removed
223         if ( bMarkIsNeg && !HasAnyMultiMarks() )
224             ResetMark();
225     }
226 }
227 
MarkToSimple()228 void ScMarkData::MarkToSimple()
229 {
230     if ( bMarking )
231         return;
232 
233     if ( bMultiMarked && bMarked )
234         MarkToMulti();                  // may result in bMarked and bMultiMarked reset
235 
236     if ( bMultiMarked )
237     {
238         DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
239 
240         ScRange aNew = aMultiRange;
241 
242         sal_Bool bOk = sal_False;
243         SCCOL nStartCol = aNew.aStart.Col();
244         SCCOL nEndCol   = aNew.aEnd.Col();
245 
246         while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() )
247             ++nStartCol;
248         while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() )
249             --nEndCol;
250 
251         //  Zeilen werden nur aus MarkArray genommen
252         SCROW nStartRow, nEndRow;
253         if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) )
254         {
255             bOk = sal_True;
256             SCROW nCmpStart, nCmpEnd;
257             for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++)
258                 if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd )
259                         || nCmpStart != nStartRow || nCmpEnd != nEndRow )
260                     bOk = sal_False;
261         }
262 
263         if (bOk)
264         {
265             aNew.aStart.SetCol(nStartCol);
266             aNew.aStart.SetRow(nStartRow);
267             aNew.aEnd.SetCol(nEndCol);
268             aNew.aEnd.SetRow(nEndRow);
269 
270             ResetMark();
271             aMarkRange = aNew;
272             bMarked = sal_True;
273             bMarkIsNeg = sal_False;
274         }
275     }
276 }
277 
IsCellMarked(SCCOL nCol,SCROW nRow,sal_Bool bNoSimple) const278 sal_Bool ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, sal_Bool bNoSimple ) const
279 {
280     if ( bMarked && !bNoSimple && !bMarkIsNeg )
281         if ( aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
282              aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
283             return sal_True;
284 
285     if (bMultiMarked)
286     {
287         //! hier auf negative Markierung testen ?
288 
289         DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
290         return pMultiSel[nCol].GetMark( nRow );
291     }
292 
293     return sal_False;
294 }
295 
IsColumnMarked(SCCOL nCol) const296 sal_Bool ScMarkData::IsColumnMarked( SCCOL nCol ) const
297 {
298     //  bMarkIsNeg inzwischen auch fuer Spaltenkoepfe
299     //! GetMarkColumnRanges fuer komplett markierte Spalten
300 
301     if ( bMarked && !bMarkIsNeg &&
302                     aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
303                     aMarkRange.aStart.Row() == 0    && aMarkRange.aEnd.Row() == MAXROW )
304         return sal_True;
305 
306     if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) )
307         return sal_True;
308 
309     return sal_False;
310 }
311 
IsRowMarked(SCROW nRow) const312 sal_Bool ScMarkData::IsRowMarked( SCROW nRow ) const
313 {
314     //  bMarkIsNeg inzwischen auch fuer Zeilenkoepfe
315     //! GetMarkRowRanges fuer komplett markierte Zeilen
316 
317     if ( bMarked && !bMarkIsNeg &&
318                     aMarkRange.aStart.Col() == 0    && aMarkRange.aEnd.Col() == MAXCOL &&
319                     aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
320         return sal_True;
321 
322     if ( bMultiMarked )
323     {
324         DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
325         for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
326             if (!pMultiSel[nCol].GetMark(nRow))
327                 return sal_False;
328         return sal_True;
329     }
330 
331     return sal_False;
332 }
333 
MarkFromRangeList(const ScRangeList & rList,sal_Bool bReset)334 void ScMarkData::MarkFromRangeList( const ScRangeList& rList, sal_Bool bReset )
335 {
336     if (bReset)
337     {
338         for (SCTAB i=0; i<=MAXTAB; i++)
339             bTabMarked[i] = sal_False;              // Tabellen sind nicht in ResetMark
340         ResetMark();
341     }
342 
343     sal_uLong nCount = rList.Count();
344     if ( nCount == 1 && !bMarked && !bMultiMarked )
345     {
346         ScRange aRange = *rList.GetObject(0);
347         SetMarkArea( aRange );
348         SelectTable( aRange.aStart.Tab(), sal_True );
349     }
350     else
351     {
352         for (sal_uLong i=0; i<nCount; i++)
353         {
354             ScRange aRange = *rList.GetObject(i);
355             SetMultiMarkArea( aRange, sal_True );
356             SelectTable( aRange.aStart.Tab(), sal_True );
357         }
358     }
359 }
360 
FillRangeListWithMarks(ScRangeList * pList,sal_Bool bClear) const361 void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, sal_Bool bClear ) const
362 {
363     if (!pList)
364         return;
365 
366     if (bClear)
367         pList->RemoveAll();
368 
369     //!     bei mehreren selektierten Tabellen mehrere Ranges eintragen !!!
370 
371     if ( bMultiMarked )
372     {
373         DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
374 
375         SCTAB nTab = aMultiRange.aStart.Tab();
376 
377         SCCOL nStartCol = aMultiRange.aStart.Col();
378         SCCOL nEndCol = aMultiRange.aEnd.Col();
379         for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
380             if (pMultiSel[nCol].HasMarks())
381             {
382                 SCROW nTop, nBottom;
383                 ScRange aRange( nCol, 0, nTab );
384                 ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
385                 while ( aMarkIter.Next( nTop, nBottom ) )
386                 {
387                     aRange.aStart.SetRow( nTop );
388                     aRange.aEnd.SetRow( nBottom );
389                     pList->Join( aRange );
390                 }
391             }
392     }
393 
394     if ( bMarked )
395         pList->Append( aMarkRange );
396 }
397 
ExtendRangeListTables(ScRangeList * pList) const398 void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const
399 {
400     if (!pList)
401         return;
402 
403     ScRangeList aOldList(*pList);
404     pList->RemoveAll();                 //! oder die vorhandenen unten weglassen
405 
406     for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
407         if (bTabMarked[nTab])
408         {
409             sal_uLong nCount = aOldList.Count();
410             for (sal_uLong i=0; i<nCount; i++)
411             {
412                 ScRange aRange = *aOldList.GetObject(i);
413                 aRange.aStart.SetTab(nTab);
414                 aRange.aEnd.SetTab(nTab);
415                 pList->Append( aRange );
416             }
417         }
418 }
419 
GetMarkColumnRanges(SCCOLROW * pRanges)420 SCCOLROW ScMarkData::GetMarkColumnRanges( SCCOLROW* pRanges )
421 {
422     if (bMarked)
423         MarkToMulti();
424 
425     if (!bMultiMarked)
426         return 0;
427 
428     DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0");
429 
430     const SCCOLROW nMultiStart = aMultiRange.aStart.Col();
431     const SCCOLROW nMultiEnd = aMultiRange.aEnd.Col();
432     if (nMultiStart == 0 && nMultiEnd == MAXCOL)
433     {
434         // One or more entire rows.
435         pRanges[0] = 0;
436         pRanges[1] = MAXCOL;
437         return 1;
438     }
439 
440     SCCOLROW nRangeCnt = 0;
441     SCCOLROW nStart = nMultiStart;
442     while (nStart <= nMultiEnd)
443     {
444         while (nStart < nMultiEnd && !pMultiSel[nStart].HasMarks())
445             ++nStart;
446         if (pMultiSel[nStart].HasMarks())
447         {
448             SCCOLROW nEnd = nStart;
449             while (nEnd < nMultiEnd && pMultiSel[nEnd].HasMarks())
450                 ++nEnd;
451             if (!pMultiSel[nEnd].HasMarks())
452                 --nEnd;
453             pRanges[2*nRangeCnt  ] = nStart;
454             pRanges[2*nRangeCnt+1] = nEnd;
455             ++nRangeCnt;
456             nStart = nEnd+1;
457         }
458         else
459             nStart = nMultiEnd+1;
460     }
461 
462     return nRangeCnt;
463 }
464 
GetMarkRowRanges(SCCOLROW * pRanges)465 SCCOLROW ScMarkData::GetMarkRowRanges( SCCOLROW* pRanges )
466 {
467     if (bMarked)
468         MarkToMulti();
469 
470     if (!bMultiMarked)
471         return 0;
472 
473     DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0");
474 
475     // Which rows are marked?
476 
477     // Optimized to not loop over MAXCOL*MAXROW as worst case, i.e. Ctrl+A
478 
479     const SCCOLROW nMultiStart = aMultiRange.aStart.Row();
480     const SCCOLROW nMultiEnd = aMultiRange.aEnd.Row();
481 
482     sal_Bool*   bRowMarked = new sal_Bool[MAXROWCOUNT];
483     memset( bRowMarked, 0, sizeof(sal_Bool) * MAXROWCOUNT);
484     SCROW  nRow;
485     SCCOL  nCol;
486 
487     SCROW nTop = -1, nBottom = -1;
488     for (nCol = aMultiRange.aStart.Col(); nCol <= aMultiRange.aEnd.Col(); ++nCol)
489     {
490         ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
491         while (aMarkIter.Next( nTop, nBottom ))
492             for (nRow=nTop; nRow<=nBottom; nRow++)
493                 bRowMarked[nRow] = sal_True;
494         if (nTop == nMultiStart && nBottom == nMultiEnd)
495             break;  // for, all relevant rows marked
496     }
497 
498     if (nTop == nMultiStart && nBottom == nMultiEnd)
499     {
500         pRanges[0] = nTop;
501         pRanges[1] = nBottom;
502         delete[] bRowMarked;
503         return 1;
504     }
505 
506     // Combine to ranges of rows.
507 
508     SCCOLROW nRangeCnt = 0;
509     SCCOLROW nStart = nMultiStart;
510     while (nStart <= nMultiEnd)
511     {
512         while (nStart < nMultiEnd && !bRowMarked[nStart])
513             ++nStart;
514         if (bRowMarked[nStart])
515         {
516             SCCOLROW nEnd = nStart;
517             while (nEnd < nMultiEnd && bRowMarked[nEnd])
518                 ++nEnd;
519             if (!bRowMarked[nEnd])
520                 --nEnd;
521             pRanges[2*nRangeCnt  ] = nStart;
522             pRanges[2*nRangeCnt+1] = nEnd;
523             ++nRangeCnt;
524             nStart = nEnd+1;
525         }
526         else
527             nStart = nMultiEnd+1;
528     }
529 
530     delete[] bRowMarked;
531     return nRangeCnt;
532 }
533 
IsAllMarked(const ScRange & rRange) const534 sal_Bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
535 {
536     if ( !bMultiMarked )
537         return sal_False;
538 
539     DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
540 
541     SCCOL nStartCol = rRange.aStart.Col();
542     SCROW nStartRow = rRange.aStart.Row();
543     SCCOL nEndCol = rRange.aEnd.Col();
544     SCROW nEndRow = rRange.aEnd.Row();
545     sal_Bool bOk = sal_True;
546     for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
547         if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) )
548             bOk = sal_False;
549 
550     return bOk;
551 }
552 
GetNextMarked(SCCOL nCol,SCsROW nRow,sal_Bool bUp) const553 SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, sal_Bool bUp ) const
554 {
555     if ( !bMultiMarked )
556         return nRow;
557 
558     DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
559 
560     return pMultiSel[nCol].GetNextMarked( nRow, bUp );
561 }
562 
HasMultiMarks(SCCOL nCol) const563 sal_Bool ScMarkData::HasMultiMarks( SCCOL nCol ) const
564 {
565     if ( !bMultiMarked )
566         return sal_False;
567 
568     DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
569 
570     return pMultiSel[nCol].HasMarks();
571 }
572 
HasAnyMultiMarks() const573 sal_Bool ScMarkData::HasAnyMultiMarks() const
574 {
575     if ( !bMultiMarked )
576         return sal_False;
577 
578     DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
579 
580     for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
581         if ( pMultiSel[nCol].HasMarks() )
582             return sal_True;
583 
584     return sal_False;       // nix
585 }
586 
InsertTab(SCTAB nTab)587 void ScMarkData::InsertTab( SCTAB nTab )
588 {
589     for (SCTAB i=MAXTAB; i>nTab; i--)
590         bTabMarked[i] = bTabMarked[i-1];
591     bTabMarked[nTab] = sal_False;
592 }
593 
DeleteTab(SCTAB nTab)594 void ScMarkData::DeleteTab( SCTAB nTab )
595 {
596     for (SCTAB i=nTab; i<MAXTAB; i++)
597         bTabMarked[i] = bTabMarked[i+1];
598     bTabMarked[MAXTAB] = sal_False;
599 }
600 
601 
602 
603 
604 
605