LibreOffice Module sc (master)  1
markdata.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <memory>
21 #include <markdata.hxx>
22 #include <markarr.hxx>
23 #include <markmulti.hxx>
24 #include <rangelst.hxx>
25 #include <segmenttree.hxx>
26 #include <sheetlimits.hxx>
27 #include <document.hxx>
28 #include <columnspanset.hxx>
29 #include <fstalgorithm.hxx>
30 #include <unordered_map>
31 
32 #include <osl/diagnose.h>
33 
34 #include <mdds/flat_segment_tree.hpp>
35 #include <cassert>
36 
37 
38 ScMarkData::ScMarkData(const ScSheetLimits& rSheetLimits) :
39  maTabMarked(),
40  aMultiSel(rSheetLimits),
41  mrSheetLimits(rSheetLimits)
42 {
43  ResetMark();
44 }
45 
47 {
48 }
49 
51 {
52  maTabMarked = rOther.maTabMarked;
53  aMarkRange = rOther.aMarkRange;
54  aMultiRange = rOther.aMultiRange;
55  aMultiSel = rOther.aMultiSel;
56  aTopEnvelope = rOther.aTopEnvelope;
60  bMarked = rOther.bMarked;
61  bMultiMarked = rOther.bMultiMarked;
62  bMarking = rOther.bMarking;
63  bMarkIsNeg = rOther.bMarkIsNeg;
64  return *this;
65 }
66 
68 {
69  maTabMarked = std::move(rOther.maTabMarked);
70  aMarkRange = std::move(rOther.aMarkRange);
71  aMultiRange = std::move(rOther.aMultiRange);
72  aMultiSel = std::move(rOther.aMultiSel);
73  aTopEnvelope = std::move(rOther.aTopEnvelope);
74  aBottomEnvelope = std::move(rOther.aBottomEnvelope);
75  aLeftEnvelope = std::move(rOther.aLeftEnvelope);
76  aRightEnvelope = std::move(rOther.aRightEnvelope);
77  bMarked = rOther.bMarked;
78  bMultiMarked = rOther.bMultiMarked;
79  bMarking = rOther.bMarking;
80  bMarkIsNeg = rOther.bMarkIsNeg;
81  return *this;
82 }
83 
84 
86 {
87  aMultiSel.Clear();
88 
89  bMarked = bMultiMarked = false;
90  bMarking = bMarkIsNeg = false;
95 }
96 
97 void ScMarkData::SetMarkArea( const ScRange& rRange )
98 {
99  aMarkRange = rRange;
101  if ( !bMarked )
102  {
103  // Upon creation of a document ScFormatShell GetTextAttrState
104  // may query (default) attributes although no sheet is marked yet.
105  // => mark that one.
106  if ( !GetSelectCount() )
107  maTabMarked.insert( aMarkRange.aStart.Tab() );
108  bMarked = true;
109  }
110 }
111 
112 void ScMarkData::GetMarkArea( ScRange& rRange ) const
113 {
114  rRange = aMarkRange; //TODO: inline ?
115 }
116 
118 {
119  rRange = aMultiRange;
120 }
121 
122 void ScMarkData::SetMultiMarkArea( const ScRange& rRange, bool bMark, bool bSetupMulti )
123 {
124  if ( aMultiSel.IsEmpty() )
125  {
126  // if simple mark range is set, copy to multi marks
127  if ( bMarked && !bMarkIsNeg && !bSetupMulti )
128  {
129  bMarked = false;
130  SCCOL nStartCol = aMarkRange.aStart.Col();
131  SCCOL nEndCol = aMarkRange.aEnd.Col();
132  PutInOrder( nStartCol, nEndCol );
133  SetMultiMarkArea( aMarkRange, true, true );
134  }
135  }
136 
137  SCCOL nStartCol = rRange.aStart.Col();
138  SCROW nStartRow = rRange.aStart.Row();
139  SCCOL nEndCol = rRange.aEnd.Col();
140  SCROW nEndRow = rRange.aEnd.Row();
141  PutInOrder( nStartRow, nEndRow );
142  PutInOrder( nStartCol, nEndCol );
143 
144  aMultiSel.SetMarkArea( nStartCol, nEndCol, nStartRow, nEndRow, bMark );
145 
146  if ( bMultiMarked ) // Update aMultiRange
147  {
148  if ( nStartCol < aMultiRange.aStart.Col() )
149  aMultiRange.aStart.SetCol( nStartCol );
150  if ( nStartRow < aMultiRange.aStart.Row() )
151  aMultiRange.aStart.SetRow( nStartRow );
152  if ( nEndCol > aMultiRange.aEnd.Col() )
153  aMultiRange.aEnd.SetCol( nEndCol );
154  if ( nEndRow > aMultiRange.aEnd.Row() )
155  aMultiRange.aEnd.SetRow( nEndRow );
156  }
157  else
158  {
159  aMultiRange = rRange; // new
160  bMultiMarked = true;
161  }
162 }
163 
165 {
166  aMarkRange.aStart.SetTab(nTab);
167  aMarkRange.aEnd.SetTab(nTab);
168  aMultiRange.aStart.SetTab(nTab);
169  aMultiRange.aEnd.SetTab(nTab);
170 }
171 
172 void ScMarkData::SelectTable( SCTAB nTab, bool bNew )
173 {
174  if ( bNew )
175  {
176  maTabMarked.insert( nTab );
177  }
178  else
179  {
180  maTabMarked.erase( nTab );
181  }
182 }
183 
185 {
186  return (maTabMarked.find( nTab ) != maTabMarked.end());
187 }
188 
190 {
191  maTabMarked.clear();
192  maTabMarked.insert( nTab );
193 }
194 
196 {
197  return static_cast<SCTAB> ( maTabMarked.size() );
198 }
199 
201 {
202  if (!maTabMarked.empty())
203  return (*maTabMarked.begin());
204 
205  OSL_FAIL("GetFirstSelected: nothing selected");
206  return 0;
207 }
208 
210 {
211  if (!maTabMarked.empty())
212  return (*maTabMarked.rbegin());
213 
214  OSL_FAIL("GetLastSelected: nothing selected");
215  return 0;
216 }
217 
219 {
220  MarkedTabsType aTabs(rTabs.begin(), rTabs.end());
221  maTabMarked.swap(aTabs);
222 }
223 
225 {
226  if ( bMarked && !bMarking )
227  {
229  bMarked = false;
230 
231  // check if all multi mark ranges have been removed
232  if ( bMarkIsNeg && !HasAnyMultiMarks() )
233  ResetMark();
234  }
235 }
236 
238 {
239  if ( bMarking )
240  return;
241 
242  if ( bMultiMarked && bMarked )
243  MarkToMulti(); // may result in bMarked and bMultiMarked reset
244 
245  if ( !bMultiMarked )
246  return;
247 
248  ScRange aNew = aMultiRange;
249 
250  bool bOk = false;
251  SCCOL nStartCol = aNew.aStart.Col();
252  SCCOL nEndCol = aNew.aEnd.Col();
253 
254  while ( nStartCol < nEndCol && !aMultiSel.HasMarks( nStartCol ) )
255  ++nStartCol;
256  while ( nStartCol < nEndCol && !aMultiSel.HasMarks( nEndCol ) )
257  --nEndCol;
258 
259  // Rows are only taken from MarkArray
260  SCROW nStartRow, nEndRow;
261  if ( aMultiSel.HasOneMark( nStartCol, nStartRow, nEndRow ) )
262  {
263  bOk = true;
264  SCROW nCmpStart, nCmpEnd;
265  for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++)
266  if ( !aMultiSel.HasOneMark( nCol, nCmpStart, nCmpEnd )
267  || nCmpStart != nStartRow || nCmpEnd != nEndRow )
268  bOk = false;
269  }
270 
271  if (bOk)
272  {
273  aNew.aStart.SetCol(nStartCol);
274  aNew.aStart.SetRow(nStartRow);
275  aNew.aEnd.SetCol(nEndCol);
276  aNew.aEnd.SetRow(nEndRow);
277 
278  ResetMark();
279  aMarkRange = aNew;
280  bMarked = true;
281  bMarkIsNeg = false;
282  }
283 }
284 
285 bool ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, bool bNoSimple ) const
286 {
287  if ( bMarked && !bNoSimple && !bMarkIsNeg )
288  if ( aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
289  aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
290  return true;
291 
292  if (bMultiMarked)
293  {
294  //TODO: test here for negative Marking ?
295 
296  return aMultiSel.GetMark( nCol, nRow );
297  }
298 
299  return false;
300 }
301 
303 {
304  // bMarkIsNeg meanwhile also for columns heads
305  //TODO: GetMarkColumnRanges for completely marked column
306 
307  if ( bMarked && !bMarkIsNeg &&
308  aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
310  return true;
311 
313  return true;
314 
315  return false;
316 }
317 
318 bool ScMarkData::IsRowMarked( SCROW nRow ) const
319 {
320  // bMarkIsNeg meanwhile also for row heads
321  //TODO: GetMarkRowRanges for completely marked rows
322 
323  if ( bMarked && !bMarkIsNeg &&
325  aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
326  return true;
327 
328  if ( bMultiMarked )
329  return aMultiSel.IsRowMarked( nRow );
330 
331  return false;
332 }
333 
334 void ScMarkData::MarkFromRangeList( const ScRangeList& rList, bool bReset )
335 {
336  if (bReset)
337  {
338  maTabMarked.clear();
339  ResetMark();
340  }
341 
342  size_t nCount = rList.size();
343  if ( nCount == 1 && !bMarked && !bMultiMarked )
344  {
345  const ScRange& rRange = rList[ 0 ];
346  SetMarkArea( rRange );
347  SelectTable( rRange.aStart.Tab(), true );
348  }
349  else
350  {
351  for (size_t i=0; i < nCount; i++)
352  {
353  const ScRange& rRange = rList[ i ];
354  SetMultiMarkArea( rRange );
355  SelectTable( rRange.aStart.Tab(), true );
356  }
357  }
358 }
359 
363 ScMarkData::ScMarkData(const ScSheetLimits& rLimits, const ScRangeList& rList)
364  : aMultiSel(rLimits),
365  mrSheetLimits(rLimits)
366 {
367  ResetMark();
368 
369  for (const ScRange& rRange : rList)
370  maTabMarked.insert( rRange.aStart.Tab() );
371 
372  if (rList.size() > 1)
373  {
374  bMultiMarked = true;
375  aMultiRange = rList.Combine();
376 
377  aMultiSel.Set( rList );
378  }
379  else if (rList.size() == 1)
380  {
381  const ScRange& rRange = rList[ 0 ];
382  SetMarkArea( rRange );
383  }
384 }
385 
386 
387 void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, bool bClear, SCTAB nForTab ) const
388 {
389  if (!pList)
390  return;
391 
392  if (bClear)
393  pList->RemoveAll();
394 
395  //TODO: for multiple selected tables enter multiple ranges !!!
396 
397  if ( bMultiMarked )
398  {
399  SCTAB nTab = (nForTab < 0 ? aMultiRange.aStart.Tab() : nForTab);
400 
401  SCCOL nStartCol = aMultiRange.aStart.Col();
402  SCCOL nEndCol = aMultiRange.aEnd.Col();
403  for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
404  {
405  if (aMultiSel.HasMarks( nCol ))
406  {
407  // Feeding column-wise fragments to ScRangeList::Join() is a
408  // huge bottleneck, speed this up for multiple columns
409  // consisting of identical row sets by building a column span
410  // first. This is usually the case for filtered data, for
411  // example.
412  SCCOL nToCol = nCol+1;
413  for ( ; nToCol <= nEndCol; ++nToCol)
414  {
415  if (!aMultiSel.HasEqualRowsMarked(nCol, nToCol))
416  break;
417  }
418  --nToCol;
419  ScRange aRange( nCol, 0, nTab, nToCol, 0, nTab );
420  SCROW nTop, nBottom;
421  ScMultiSelIter aMultiIter( aMultiSel, nCol );
422  while ( aMultiIter.Next( nTop, nBottom ) )
423  {
424  aRange.aStart.SetRow( nTop );
425  aRange.aEnd.SetRow( nBottom );
426  pList->Join( aRange );
427  }
428  nCol = nToCol;
429  }
430  }
431  }
432 
433  if ( bMarked )
434  {
435  if (nForTab < 0)
436  pList->push_back( aMarkRange );
437  else
438  {
439  ScRange aRange( aMarkRange );
440  aRange.aStart.SetTab( nForTab );
441  aRange.aEnd.SetTab( nForTab );
442  pList->push_back( aRange );
443  }
444  }
445 }
446 
448 {
449  if (!pList)
450  return;
451 
452  ScRangeList aOldList(*pList);
453  pList->RemoveAll(); //TODO: or skip the existing below
454 
455  for (const auto& rTab : maTabMarked)
456  for ( size_t i=0, nCount = aOldList.size(); i<nCount; i++)
457  {
458  ScRange aRange = aOldList[ i ];
459  aRange.aStart.SetTab(rTab);
460  aRange.aEnd.SetTab(rTab);
461  pList->push_back( aRange );
462  }
463 }
464 
466 {
467  ScRangeList aRet;
468  FillRangeListWithMarks(&aRet, false);
469  return aRet;
470 }
471 
473 {
474  ScRangeList aRet;
475  FillRangeListWithMarks(&aRet, false, nTab);
476  return aRet;
477 }
478 
479 std::vector<sc::ColRowSpan> ScMarkData::GetMarkedRowSpans() const
480 {
481  typedef mdds::flat_segment_tree<SCCOLROW, bool> SpansType;
482 
483  ScRangeList aRanges = GetMarkedRanges();
484  SpansType aSpans(0, mrSheetLimits.mnMaxRow+1, false);
485  SpansType::const_iterator itPos = aSpans.begin();
486 
487  for (size_t i = 0, n = aRanges.size(); i < n; ++i)
488  {
489  const ScRange& r = aRanges[i];
490  itPos = aSpans.insert(itPos, r.aStart.Row(), r.aEnd.Row()+1, true).first;
491  }
492 
493  return sc::toSpanArray<SCCOLROW,sc::ColRowSpan>(aSpans);
494 }
495 
496 std::vector<sc::ColRowSpan> ScMarkData::GetMarkedColSpans() const
497 {
498 
499  if (bMultiMarked)
500  {
501  SCCOL nStartCol = aMultiRange.aStart.Col();
502  SCCOL nEndCol = aMultiRange.aEnd.Col();
503  if (bMarked)
504  {
505  // Use segment tree to merge marked with multi marked.
506  typedef mdds::flat_segment_tree<SCCOLROW, bool> SpansType;
507  SpansType aSpans(0, mrSheetLimits.mnMaxCol+1, false);
508  SpansType::const_iterator itPos = aSpans.begin();
509  do
510  {
512  {
513  itPos = aSpans.insert(itPos, nStartCol, nEndCol+1, true).first;
514  break; // do; all columns marked
515  }
516 
517  /* XXX if it turns out that span insert is too slow for lots of
518  * subsequent columns we could gather each span first and then
519  * insert. */
520  for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
521  {
522  const ScMarkArray* pMultiArray = aMultiSel.GetMultiSelArray( nCol );
523  if (pMultiArray && pMultiArray->HasMarks())
524  itPos = aSpans.insert(itPos, nCol, nCol+1, true).first;
525  }
526  }
527  while(false);
528 
529  // Merge marked.
530  aSpans.insert(itPos, aMarkRange.aStart.Col(), aMarkRange.aEnd.Col()+1, true);
531 
532  return sc::toSpanArray<SCCOLROW,sc::ColRowSpan>(aSpans);
533  }
534  else
535  {
536  // A plain vector is sufficient, avoid segment tree and conversion
537  // to vector overhead.
538  std::vector<sc::ColRowSpan> aVec;
540  {
541  aVec.emplace_back( nStartCol, nEndCol);
542  return aVec; // all columns marked
543  }
544  sc::ColRowSpan aSpan( -1, -1);
545  for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
546  {
547  const ScMarkArray* pMultiArray = aMultiSel.GetMultiSelArray( nCol );
548  if (pMultiArray && pMultiArray->HasMarks())
549  {
550  if (aSpan.mnStart == -1)
551  aSpan.mnStart = nCol;
552  aSpan.mnEnd = nCol;
553  }
554  else
555  {
556  // Add span gathered so far, if any.
557  if (aSpan.mnStart != -1)
558  {
559  aVec.push_back( aSpan);
560  aSpan.mnStart = -1;
561  }
562  }
563  }
564  // Add last span, if any.
565  if (aSpan.mnStart != -1)
566  aVec.push_back( aSpan);
567  return aVec;
568  }
569  }
570 
571  // Only reached if not multi marked.
572  std::vector<sc::ColRowSpan> aVec;
573  if (bMarked)
574  {
575  aVec.emplace_back( aMarkRange.aStart.Col(), aMarkRange.aEnd.Col());
576  }
577  return aVec;
578 }
579 
580 bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
581 {
582  if ( !bMultiMarked )
583  return false;
584 
585  SCCOL nStartCol = rRange.aStart.Col();
586  SCROW nStartRow = rRange.aStart.Row();
587  SCCOL nEndCol = rRange.aEnd.Col();
588  SCROW nEndRow = rRange.aEnd.Row();
589  bool bOk = true;
590 
591  if ( nStartCol == 0 && nEndCol == mrSheetLimits.mnMaxCol )
592  return aMultiSel.IsRowRangeMarked( nStartRow, nEndRow );
593 
594  for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
595  if ( !aMultiSel.IsAllMarked( nCol, nStartRow, nEndRow ) )
596  bOk = false;
597 
598  return bOk;
599 }
600 
601 SCROW ScMarkData::GetNextMarked( SCCOL nCol, SCROW nRow, bool bUp ) const
602 {
603  if ( !bMultiMarked )
604  return nRow;
605 
606  return aMultiSel.GetNextMarked( nCol, nRow, bUp );
607 }
608 
610 {
611  if ( !bMultiMarked )
612  return false;
613 
614  return aMultiSel.HasMarks( nCol );
615 }
616 
618 {
619  if ( !bMultiMarked )
620  return false;
621 
622  return aMultiSel.HasAnyMarks();
623 }
624 
626 {
627  std::set<SCTAB> tabMarked;
628  for (const auto& rTab : maTabMarked)
629  {
630  if (rTab < nTab)
631  tabMarked.insert(rTab);
632  else
633  tabMarked.insert(rTab + 1);
634  }
635  maTabMarked.swap(tabMarked);
636 }
637 
639 {
640  std::set<SCTAB> tabMarked;
641  for (const auto& rTab : maTabMarked)
642  {
643  if (rTab < nTab)
644  tabMarked.insert(rTab);
645  else if (rTab > nTab)
646  tabMarked.insert(rTab - 1);
647  }
648  maTabMarked.swap(tabMarked);
649 }
650 
651 void ScMarkData::ShiftCols(const ScDocument* pDoc, SCCOL nStartCol, long nColOffset)
652 {
653  if (bMarked)
654  {
655  aMarkRange.IncColIfNotLessThan(pDoc, nStartCol, nColOffset);
656  }
657  else if (bMultiMarked)
658  {
659  aMultiSel.ShiftCols(nStartCol, nColOffset);
660  aMultiRange.IncColIfNotLessThan(pDoc, nStartCol, nColOffset);
661  }
662 }
663 
664 void ScMarkData::ShiftRows(const ScDocument* pDoc, SCROW nStartRow, long nRowOffset)
665 {
666  if (bMarked)
667  {
668  aMarkRange.IncRowIfNotLessThan(pDoc, nStartRow, nRowOffset);
669  }
670  else if (bMultiMarked)
671  {
672  aMultiSel.ShiftRows(nStartRow, nRowOffset);
673  aMultiRange.IncRowIfNotLessThan(pDoc, nStartRow, nRowOffset);
674  }
675 
676 }
677 
678 static void lcl_AddRanges(ScRange& rRangeDest, const ScRange& rNewRange )
679 {
680  SCCOL nStartCol = rNewRange.aStart.Col();
681  SCROW nStartRow = rNewRange.aStart.Row();
682  SCCOL nEndCol = rNewRange.aEnd.Col();
683  SCROW nEndRow = rNewRange.aEnd.Row();
684  PutInOrder( nStartRow, nEndRow );
685  PutInOrder( nStartCol, nEndCol );
686  if ( nStartCol < rRangeDest.aStart.Col() )
687  rRangeDest.aStart.SetCol( nStartCol );
688  if ( nStartRow < rRangeDest.aStart.Row() )
689  rRangeDest.aStart.SetRow( nStartRow );
690  if ( nEndCol > rRangeDest.aEnd.Col() )
691  rRangeDest.aEnd.SetCol( nEndCol );
692  if ( nEndRow > rRangeDest.aEnd.Row() )
693  rRangeDest.aEnd.SetRow( nEndRow );
694 }
695 
697 {
698  if( bMultiMarked )
699  {
700  rRange = aMultiRange;
701  SCCOL nStartCol = aMultiRange.aStart.Col(), nEndCol = aMultiRange.aEnd.Col();
702  PutInOrder( nStartCol, nEndCol );
703  nStartCol = ( nStartCol == 0 ) ? nStartCol : nStartCol - 1;
704  nEndCol = ( nEndCol == mrSheetLimits.mnMaxCol ) ? nEndCol : nEndCol + 1;
705  std::unique_ptr<ScFlatBoolRowSegments> pPrevColMarkedRows;
706  std::unique_ptr<ScFlatBoolRowSegments> pCurColMarkedRows;
707  std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInTopEnvelope;
708  std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInBottomEnvelope;
710  aNoRowsMarked.setFalse( 0, mrSheetLimits.mnMaxRow );
711 
712  bool bPrevColUnMarked = false;
713 
714  for ( SCCOL nCol=nStartCol; nCol <= nEndCol; nCol++ )
715  {
716  SCROW nTop, nBottom;
717  bool bCurColUnMarked = !aMultiSel.HasMarks( nCol );
718  if ( !bCurColUnMarked )
719  {
720  pCurColMarkedRows.reset( new ScFlatBoolRowSegments(mrSheetLimits.mnMaxRow) );
721  pCurColMarkedRows->setFalse( 0, mrSheetLimits.mnMaxRow );
722  ScMultiSelIter aMultiIter( aMultiSel, nCol );
724  pPrevColMarkedRows ? *pPrevColMarkedRows
725  : aNoRowsMarked); // For finding left envelope
727  pPrevColMarkedRows ? *pPrevColMarkedRows
728  : aNoRowsMarked); // For finding right envelope
729  SCROW nTopPrev = 0, nBottomPrev = 0; // For right envelope
730  while ( aMultiIter.Next( nTop, nBottom ) )
731  {
732  pCurColMarkedRows->setTrue( nTop, nBottom );
733  if( bPrevColUnMarked && ( nCol > nStartCol ))
734  {
735  ScRange aAddRange(nCol - 1, nTop, aMultiRange.aStart.Tab(),
736  nCol - 1, nBottom, aMultiRange.aStart.Tab());
737  lcl_AddRanges( rRange, aAddRange ); // Left envelope
738  aLeftEnvelope.push_back( aAddRange );
739  }
740  else if( nCol > nStartCol )
741  {
742  SCROW nTop1 = nTop, nBottom1 = nTop;
743  while( nTop1 <= nBottom && nBottom1 <= nBottom )
744  {
745  bool bRangeMarked = false;
746  const bool bHasValue = aPrevItr.getValue( nTop1, bRangeMarked );
747  assert(bHasValue); (void)bHasValue;
748  if( bRangeMarked )
749  {
750  nTop1 = aPrevItr.getLastPos() + 1;
751  nBottom1 = nTop1;
752  }
753  else
754  {
755  nBottom1 = aPrevItr.getLastPos();
756  if( nBottom1 > nBottom )
757  nBottom1 = nBottom;
758  ScRange aAddRange( nCol - 1, nTop1, aMultiRange.aStart.Tab(),
759  nCol - 1, nBottom1, aMultiRange.aStart.Tab() );
760  lcl_AddRanges( rRange, aAddRange ); // Left envelope
761  aLeftEnvelope.push_back( aAddRange );
762  nTop1 = ++nBottom1;
763  }
764  }
765  while( nTopPrev <= nBottom && nBottomPrev <= nBottom )
766  {
767  bool bRangeMarked;
768  const bool bHasValue = aPrevItr1.getValue( nTopPrev, bRangeMarked );
769  assert(bHasValue); (void)bHasValue;
770  if( bRangeMarked )
771  {
772  nBottomPrev = aPrevItr1.getLastPos();
773  if( nTopPrev < nTop )
774  {
775  if( nBottomPrev >= nTop )
776  {
777  nBottomPrev = nTop - 1;
778  ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(),
779  nCol, nBottomPrev, aMultiRange.aStart.Tab());
780  lcl_AddRanges( rRange, aAddRange ); // Right envelope
781  aRightEnvelope.push_back( aAddRange );
782  nTopPrev = nBottomPrev = (nBottom + 1);
783  }
784  else
785  {
786  ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(),
787  nCol, nBottomPrev, aMultiRange.aStart.Tab());
788  lcl_AddRanges( rRange, aAddRange ); // Right envelope
789  aRightEnvelope.push_back( aAddRange );
790  nTopPrev = ++nBottomPrev;
791  }
792  }
793  else
794  nTopPrev = nBottomPrev = ( nBottom + 1 );
795  }
796  else
797  {
798  nBottomPrev = aPrevItr1.getLastPos();
799  nTopPrev = ++nBottomPrev;
800  }
801  }
802  }
803  if( nTop )
804  {
805  ScRange aAddRange( nCol, nTop - 1, aMultiRange.aStart.Tab(),
806  nCol, nTop - 1, aMultiRange.aStart.Tab());
807  lcl_AddRanges( rRange, aAddRange ); // Top envelope
808  auto it = aRowToColSegmentsInTopEnvelope.find(nTop - 1);
809  if (it == aRowToColSegmentsInTopEnvelope.end())
810  it = aRowToColSegmentsInTopEnvelope.emplace(nTop - 1, ScFlatBoolColSegments(mrSheetLimits.mnMaxCol)).first;
811  it->second.setTrue( nCol, nCol );
812  }
813  if( nBottom < mrSheetLimits.mnMaxRow )
814  {
815  ScRange aAddRange(nCol, nBottom + 1, aMultiRange.aStart.Tab(),
816  nCol, nBottom + 1, aMultiRange.aStart.Tab());
817  lcl_AddRanges( rRange, aAddRange ); // Bottom envelope
818  auto it = aRowToColSegmentsInBottomEnvelope.find(nBottom + 1);
819  if (it == aRowToColSegmentsInBottomEnvelope.end())
820  it = aRowToColSegmentsInBottomEnvelope.emplace(nBottom + 1, ScFlatBoolColSegments(mrSheetLimits.mnMaxCol)).first;
821  it->second.setTrue( nCol, nCol );
822  }
823  }
824 
825  while( nTopPrev <= mrSheetLimits.mnMaxRow && nBottomPrev <= mrSheetLimits.mnMaxRow && ( nCol > nStartCol ) )
826  {
827  bool bRangeMarked;
828  const bool bHasValue = aPrevItr1.getValue( nTopPrev, bRangeMarked );
829  assert(bHasValue); (void)bHasValue;
830  if( bRangeMarked )
831  {
832  nBottomPrev = aPrevItr1.getLastPos();
833  ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(),
834  nCol, nBottomPrev, aMultiRange.aStart.Tab());
835  lcl_AddRanges( rRange, aAddRange ); // Right envelope
836  aRightEnvelope.push_back( aAddRange );
837  nTopPrev = ++nBottomPrev;
838  }
839  else
840  {
841  nBottomPrev = aPrevItr1.getLastPos();
842  nTopPrev = ++nBottomPrev;
843  }
844  }
845  }
846  else if( nCol > nStartCol )
847  {
848  bPrevColUnMarked = true;
849  SCROW nTopPrev = 0, nBottomPrev = 0;
850  bool bRangeMarked = false;
852  pPrevColMarkedRows ? *pPrevColMarkedRows : aNoRowsMarked);
853  while( nTopPrev <= mrSheetLimits.mnMaxRow && nBottomPrev <= mrSheetLimits.mnMaxRow )
854  {
855  const bool bHasValue = aPrevItr.getValue(nTopPrev, bRangeMarked);
856  assert(bHasValue); (void)bHasValue;
857  if( bRangeMarked )
858  {
859  nBottomPrev = aPrevItr.getLastPos();
860  ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(),
861  nCol, nBottomPrev, aMultiRange.aStart.Tab());
862  lcl_AddRanges( rRange, aAddRange ); // Right envelope
863  aRightEnvelope.push_back( aAddRange );
864  nTopPrev = ++nBottomPrev;
865  }
866  else
867  {
868  nBottomPrev = aPrevItr.getLastPos();
869  nTopPrev = ++nBottomPrev;
870  }
871  }
872  }
873  if ( bCurColUnMarked )
874  pPrevColMarkedRows.reset();
875  else
876  pPrevColMarkedRows = std::move( pCurColMarkedRows );
877  }
878  for( auto& rKV : aRowToColSegmentsInTopEnvelope )
879  {
880  SCCOL nStart = nStartCol;
882  while( nStart <= nEndCol )
883  {
884  if( !rKV.second.getRangeData( nStart, aRange ) )
885  break;
886  if( aRange.mbValue ) // is marked
887  aTopEnvelope.push_back( ScRange( aRange.mnCol1, rKV.first, aMultiRange.aStart.Tab(),
888  aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) );
889  nStart = aRange.mnCol2 + 1;
890  }
891  }
892  for( auto& rKV : aRowToColSegmentsInBottomEnvelope )
893  {
894  SCCOL nStart = nStartCol;
896  while( nStart <= nEndCol )
897  {
898  if( !rKV.second.getRangeData( nStart, aRange ) )
899  break;
900  if( aRange.mbValue ) // is marked
902  aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) );
903  nStart = aRange.mnCol2 + 1;
904  }
905  }
906  }
907  else if( bMarked )
908  {
910  SCROW nRow1, nRow2, nRow1New, nRow2New;
911  SCCOL nCol1, nCol2, nCol1New, nCol2New;
912  SCTAB nTab1, nTab2;
913  aMarkRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
914  nCol1New = nCol1;
915  nCol2New = nCol2;
916  nRow1New = nRow1;
917  nRow2New = nRow2;
918  // Each envelope will have zero or more ranges for single rectangle selection.
919  if( nCol1 > 0 )
920  {
921  aLeftEnvelope.push_back( ScRange( nCol1 - 1, nRow1, nTab1, nCol1 - 1, nRow2, nTab2 ) );
922  --nCol1New;
923  }
924  if( nRow1 > 0 )
925  {
926  aTopEnvelope.push_back( ScRange( nCol1, nRow1 - 1, nTab1, nCol2, nRow1 - 1, nTab2 ) );
927  --nRow1New;
928  }
929  if( nCol2 < mrSheetLimits.mnMaxCol )
930  {
931  aRightEnvelope.push_back( ScRange( nCol2 + 1, nRow1, nTab1, nCol2 + 1, nRow2, nTab2 ) );
932  ++nCol2New;
933  }
934  if( nRow2 < mrSheetLimits.mnMaxRow )
935  {
936  aBottomEnvelope.push_back( ScRange( nCol1, nRow2 + 1, nTab1, nCol2, nRow2 + 1, nTab2 ) );
937  ++nRow2New;
938  }
939  rRange = ScRange( nCol1New, nRow1New, nTab1, nCol2New, nRow2New, nTab2 );
940  }
941 }
942 
944 {
945  return aMultiSel.GetMarkArray( nCol );
946 }
947 
948 //iterators
950 {
951  return maTabMarked.begin();
952 }
953 
955 {
956  return maTabMarked.end();
957 }
958 
960 {
961  return maTabMarked.begin();
962 }
963 
965 {
966  return maTabMarked.end();
967 }
968 
970 {
971  return maTabMarked.rbegin();
972 }
973 
974 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SCROW GetNextMarked(SCCOL nCol, SCROW nRow, bool bUp) const
May return -1.
Definition: markdata.cxx:601
void MarkToSimple()
Definition: markdata.cxx:237
ScAddress aStart
Definition: address.hxx:500
void SetMarkArea(SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow, bool bMark)
Definition: markmulti.cxx:189
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
bool bMarked
Definition: markdata.hxx:58
ScMultiSel aMultiSel
Definition: markdata.hxx:52
SCROW Row() const
Definition: address.hxx:262
const ScSheetLimits & mrSheetLimits
Definition: markdata.hxx:57
void MarkToMulti()
Definition: markdata.cxx:224
bool HasOneMark(SCCOL nCol, SCROW &rStartRow, SCROW &rEndRow) const
Definition: markmulti.cxx:76
void SetMultiMarkArea(const ScRange &rRange, bool bMark=true, bool bSetupMulti=false)
Definition: markdata.cxx:122
void ResetMark()
Definition: markdata.cxx:85
bool getValue(SCROW nPos, bool &rVal)
bool IsEmpty() const
Definition: markmulti.hxx:62
bool setFalse(SCROW nRow1, SCROW nRow2)
sal_Int64 n
std::vector< sc::ColRowSpan > GetMarkedRowSpans() const
Definition: markdata.cxx:479
void FillRangeListWithMarks(ScRangeList *pList, bool bClear, SCTAB nForTab=-1) const
Create a range list of marks.
Definition: markdata.cxx:387
const ScMarkArray * GetMultiSelArray(SCCOL nCol) const
Definition: markmulti.cxx:407
ScAddress aEnd
Definition: address.hxx:501
ScRange aMultiRange
Definition: markdata.hxx:51
void MarkFromRangeList(const ScRangeList &rList, bool bReset)
Definition: markdata.cxx:334
bool IsCellMarked(SCCOL nCol, SCROW nRow, bool bNoSimple=false) const
Definition: markdata.cxx:285
void GetMarkArea(ScRange &rRange) const
Definition: markdata.cxx:112
bool Next(SCROW &rTop, SCROW &rBottom)
Definition: markmulti.cxx:454
bool HasMarks(SCCOL nCol) const
Definition: markmulti.cxx:69
void DeleteTab(SCTAB nTab)
Definition: markdata.cxx:638
bool GetMark(SCCOL nCol, SCROW nRow) const
Definition: markmulti.cxx:112
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
This is a rather odd datastructure.
Definition: markarr.hxx:43
void ShiftCols(const ScDocument *pDoc, SCCOL nStartCol, long nColOffset)
Definition: markdata.cxx:651
SCTAB GetSelectCount() const
Definition: markdata.cxx:195
void SetAreaTab(SCTAB nTab)
Definition: markdata.cxx:164
int nCount
bool bMarkIsNeg
Definition: markdata.hxx:62
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1144
SCTAB Tab() const
Definition: address.hxx:271
void SetRow(SCROW nRowP)
Definition: address.hxx:275
bool IsRowMarked(SCROW nRow) const
Definition: markmulti.cxx:311
static void lcl_AddRanges(ScRange &rRangeDest, const ScRange &rNewRange)
Definition: markdata.cxx:678
ScRange aMarkRange
Definition: markdata.hxx:50
void SetCol(SCCOL nColP)
Definition: address.hxx:279
SC_DLLPUBLIC void IncColIfNotLessThan(const ScDocument *pDoc, SCCOL nStartCol, SCCOL nOffset)
Definition: address.cxx:2411
void Clear()
Definition: markmulti.cxx:54
bool HasMarks() const
Definition: markarr.hxx:63
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:954
bool IsRowMarked(SCROW nRow) const
Definition: markdata.cxx:318
void SetMarkArea(const ScRange &rRange)
Definition: markdata.cxx:97
void SetTab(SCTAB nTabP)
Definition: address.hxx:283
int i
bool IsColumnMarked(SCCOL nCol) const
Definition: markdata.cxx:302
void ExtendRangeListTables(ScRangeList *pList) const
Definition: markdata.cxx:447
void GetSelectionCover(ScRange &rRange)
Definition: markdata.cxx:696
const SCROW mnMaxRow
Maximum addressable column.
Definition: sheetlimits.hxx:30
SCROW GetNextMarked(SCCOL nCol, SCROW nRow, bool bUp) const
Definition: markmulti.cxx:161
void SelectTable(SCTAB nTab, bool bNew)
Definition: markdata.cxx:172
sal_Int16 SCCOL
Definition: types.hxx:22
ScRangeList aTopEnvelope
Definition: markdata.hxx:53
size_t size() const
Definition: rangelst.hxx:90
void SelectOneTable(SCTAB nTab)
Definition: markdata.cxx:189
ScMarkArray GetMarkArray(SCCOL nCol) const
Definition: markdata.cxx:943
ScMarkData & operator=(const ScMarkData &rData)
Definition: markdata.cxx:50
bool HasEqualRowsMarked(SCCOL nCol1, SCCOL nCol2) const
Definition: markmulti.cxx:144
std::set< SCTAB >::iterator iterator
Definition: markdata.hxx:158
bool HasAnyMarks() const
Definition: markmulti.cxx:334
iterator end()
Definition: markdata.cxx:954
const ScMarkArray & GetRowSelArray() const
Definition: markmulti.cxx:402
void InsertTab(SCTAB nTab)
Definition: markdata.cxx:625
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:693
ScRangeList aLeftEnvelope
Definition: markdata.hxx:55
std::set< SCTAB >::const_iterator const_iterator
Definition: markdata.hxx:159
SCCOL Col() const
Definition: address.hxx:267
SC_DLLPUBLIC void IncRowIfNotLessThan(const ScDocument *pDoc, SCROW nStartRow, SCROW nOffset)
Definition: address.cxx:2431
iterator begin()
Definition: markdata.cxx:949
sal_Int32 SCROW
Definition: types.hxx:18
SC_DLLPUBLIC void PutInOrder()
Definition: address.cxx:1577
ScRangeList aBottomEnvelope
Definition: markdata.hxx:54
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:166
MarkedTabsType maTabMarked
Definition: markdata.hxx:48
SCTAB GetFirstSelected() const
Definition: markdata.cxx:200
ScMarkArray GetMarkArray(SCCOL nCol) const
Definition: markmulti.cxx:324
SCTAB GetLastSelected() const
Definition: markdata.cxx:209
bool IsRowRangeMarked(SCROW nStartRow, SCROW nEndRow) const
Definition: markmulti.cxx:316
ScRangeList GetMarkedRangesForTab(SCTAB nTab) const
Get marked ranges with sheet-tab set to nTab.
Definition: markdata.cxx:472
bool IsAllMarked(SCCOL nCol, SCROW nStartRow, SCROW nEndRow) const
Definition: markmulti.cxx:119
bool bMarking
Definition: markdata.hxx:61
std::set< SCTAB >::const_reverse_iterator const_reverse_iterator
Definition: markdata.hxx:160
const SCCOL mnMaxCol
Definition: sheetlimits.hxx:29
bool HasAnyMultiMarks() const
Definition: markdata.cxx:617
ScRangeList GetMarkedRanges() const
Definition: markdata.cxx:465
ScRangeList aRightEnvelope
Definition: markdata.hxx:56
void GetMultiMarkArea(ScRange &rRange) const
Definition: markdata.cxx:117
ScMarkData(const ScSheetLimits &rSheetLimits)
Definition: markdata.cxx:38
void Set(ScRangeList const &)
optimised init-from-range-list.
Definition: markmulti.cxx:249
bool GetTableSelect(SCTAB nTab) const
Definition: markdata.cxx:184
std::vector< sc::ColRowSpan > GetMarkedColSpans() const
Definition: markdata.cxx:496
bool bMultiMarked
Definition: markdata.hxx:59
std::set< SCTAB > MarkedTabsType
Definition: markdata.hxx:46
const_reverse_iterator rbegin() const
Definition: markdata.cxx:969
void RemoveAll()
Definition: rangelst.cxx:1108
bool IsAllMarked(const ScRange &rRange) const
Definition: markdata.cxx:580
bool HasMultiMarks(SCCOL nCol) const
Definition: markdata.cxx:609
sal_Int16 SCTAB
Definition: types.hxx:23
const char first[]
void SetSelectedTabs(const MarkedTabsType &rTabs)
Definition: markdata.cxx:218
void ShiftCols(SCCOL nStartCol, long nColOffset)
Definition: markmulti.cxx:344
void ShiftRows(SCROW nStartRow, long nRowOffset)
Definition: markmulti.cxx:395
void ShiftRows(const ScDocument *pDoc, SCROW nStartRow, long nRowOffset)
Definition: markdata.cxx:664
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo