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