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