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