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& rDoc, SCCOL nStartCol, long nColOffset)
652 {
653  if (bMarked)
654  {
655  aMarkRange.IncColIfNotLessThan(rDoc, nStartCol, nColOffset);
656  }
657  else if (bMultiMarked)
658  {
659  aMultiSel.ShiftCols(nStartCol, nColOffset);
660  aMultiRange.IncColIfNotLessThan(rDoc, nStartCol, nColOffset);
661  }
662 }
663 
664 void ScMarkData::ShiftRows(const ScDocument& rDoc, SCROW nStartRow, long nRowOffset)
665 {
666  if (bMarked)
667  {
668  aMarkRange.IncRowIfNotLessThan(rDoc, nStartRow, nRowOffset);
669  }
670  else if (bMultiMarked)
671  {
672  aMultiSel.ShiftRows(nStartRow, nRowOffset);
673  aMultiRange.IncRowIfNotLessThan(rDoc, nStartRow, nRowOffset);
674  }
675 }
676 
677 static void lcl_AddRanges(ScRange& rRangeDest, const ScRange& rNewRange )
678 {
679  SCCOL nStartCol = rNewRange.aStart.Col();
680  SCROW nStartRow = rNewRange.aStart.Row();
681  SCCOL nEndCol = rNewRange.aEnd.Col();
682  SCROW nEndRow = rNewRange.aEnd.Row();
683  PutInOrder( nStartRow, nEndRow );
684  PutInOrder( nStartCol, nEndCol );
685  if ( nStartCol < rRangeDest.aStart.Col() )
686  rRangeDest.aStart.SetCol( nStartCol );
687  if ( nStartRow < rRangeDest.aStart.Row() )
688  rRangeDest.aStart.SetRow( nStartRow );
689  if ( nEndCol > rRangeDest.aEnd.Col() )
690  rRangeDest.aEnd.SetCol( nEndCol );
691  if ( nEndRow > rRangeDest.aEnd.Row() )
692  rRangeDest.aEnd.SetRow( nEndRow );
693 }
694 
696 {
697  if( bMultiMarked )
698  {
699  rRange = aMultiRange;
700  SCCOL nStartCol = aMultiRange.aStart.Col(), nEndCol = aMultiRange.aEnd.Col();
701  PutInOrder( nStartCol, nEndCol );
702  nStartCol = ( nStartCol == 0 ) ? nStartCol : nStartCol - 1;
703  nEndCol = ( nEndCol == mrSheetLimits.mnMaxCol ) ? nEndCol : nEndCol + 1;
704  std::unique_ptr<ScFlatBoolRowSegments> pPrevColMarkedRows;
705  std::unique_ptr<ScFlatBoolRowSegments> pCurColMarkedRows;
706  std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInTopEnvelope;
707  std::unordered_map<SCROW,ScFlatBoolColSegments> aRowToColSegmentsInBottomEnvelope;
709  aNoRowsMarked.setFalse( 0, mrSheetLimits.mnMaxRow );
710 
711  bool bPrevColUnMarked = false;
712 
713  for ( SCCOL nCol=nStartCol; nCol <= nEndCol; nCol++ )
714  {
715  SCROW nTop, nBottom;
716  bool bCurColUnMarked = !aMultiSel.HasMarks( nCol );
717  if ( !bCurColUnMarked )
718  {
719  pCurColMarkedRows.reset( new ScFlatBoolRowSegments(mrSheetLimits.mnMaxRow) );
720  pCurColMarkedRows->setFalse( 0, mrSheetLimits.mnMaxRow );
721  ScMultiSelIter aMultiIter( aMultiSel, nCol );
723  pPrevColMarkedRows ? *pPrevColMarkedRows
724  : aNoRowsMarked); // For finding left envelope
726  pPrevColMarkedRows ? *pPrevColMarkedRows
727  : aNoRowsMarked); // For finding right envelope
728  SCROW nTopPrev = 0, nBottomPrev = 0; // For right envelope
729  while ( aMultiIter.Next( nTop, nBottom ) )
730  {
731  pCurColMarkedRows->setTrue( nTop, nBottom );
732  if( bPrevColUnMarked && ( nCol > nStartCol ))
733  {
734  ScRange aAddRange(nCol - 1, nTop, aMultiRange.aStart.Tab(),
735  nCol - 1, nBottom, aMultiRange.aStart.Tab());
736  lcl_AddRanges( rRange, aAddRange ); // Left envelope
737  aLeftEnvelope.push_back( aAddRange );
738  }
739  else if( nCol > nStartCol )
740  {
741  SCROW nTop1 = nTop, nBottom1 = nTop;
742  while( nTop1 <= nBottom && nBottom1 <= nBottom )
743  {
744  bool bRangeMarked = false;
745  const bool bHasValue = aPrevItr.getValue( nTop1, bRangeMarked );
746  assert(bHasValue); (void)bHasValue;
747  if( bRangeMarked )
748  {
749  nTop1 = aPrevItr.getLastPos() + 1;
750  nBottom1 = nTop1;
751  }
752  else
753  {
754  nBottom1 = aPrevItr.getLastPos();
755  if( nBottom1 > nBottom )
756  nBottom1 = nBottom;
757  ScRange aAddRange( nCol - 1, nTop1, aMultiRange.aStart.Tab(),
758  nCol - 1, nBottom1, aMultiRange.aStart.Tab() );
759  lcl_AddRanges( rRange, aAddRange ); // Left envelope
760  aLeftEnvelope.push_back( aAddRange );
761  nTop1 = ++nBottom1;
762  }
763  }
764  while( nTopPrev <= nBottom && nBottomPrev <= nBottom )
765  {
766  bool bRangeMarked;
767  const bool bHasValue = aPrevItr1.getValue( nTopPrev, bRangeMarked );
768  assert(bHasValue); (void)bHasValue;
769  if( bRangeMarked )
770  {
771  nBottomPrev = aPrevItr1.getLastPos();
772  if( nTopPrev < nTop )
773  {
774  if( nBottomPrev >= nTop )
775  {
776  nBottomPrev = nTop - 1;
777  ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(),
778  nCol, nBottomPrev, aMultiRange.aStart.Tab());
779  lcl_AddRanges( rRange, aAddRange ); // Right envelope
780  aRightEnvelope.push_back( aAddRange );
781  nTopPrev = nBottomPrev = (nBottom + 1);
782  }
783  else
784  {
785  ScRange aAddRange( nCol, nTopPrev, aMultiRange.aStart.Tab(),
786  nCol, nBottomPrev, aMultiRange.aStart.Tab());
787  lcl_AddRanges( rRange, aAddRange ); // Right envelope
788  aRightEnvelope.push_back( aAddRange );
789  nTopPrev = ++nBottomPrev;
790  }
791  }
792  else
793  nTopPrev = nBottomPrev = ( nBottom + 1 );
794  }
795  else
796  {
797  nBottomPrev = aPrevItr1.getLastPos();
798  nTopPrev = ++nBottomPrev;
799  }
800  }
801  }
802  if( nTop )
803  {
804  ScRange aAddRange( nCol, nTop - 1, aMultiRange.aStart.Tab(),
805  nCol, nTop - 1, aMultiRange.aStart.Tab());
806  lcl_AddRanges( rRange, aAddRange ); // Top envelope
807  auto it = aRowToColSegmentsInTopEnvelope.find(nTop - 1);
808  if (it == aRowToColSegmentsInTopEnvelope.end())
809  it = aRowToColSegmentsInTopEnvelope.emplace(nTop - 1, ScFlatBoolColSegments(mrSheetLimits.mnMaxCol)).first;
810  it->second.setTrue( nCol, nCol );
811  }
812  if( nBottom < mrSheetLimits.mnMaxRow )
813  {
814  ScRange aAddRange(nCol, nBottom + 1, aMultiRange.aStart.Tab(),
815  nCol, nBottom + 1, aMultiRange.aStart.Tab());
816  lcl_AddRanges( rRange, aAddRange ); // Bottom envelope
817  auto it = aRowToColSegmentsInBottomEnvelope.find(nBottom + 1);
818  if (it == aRowToColSegmentsInBottomEnvelope.end())
819  it = aRowToColSegmentsInBottomEnvelope.emplace(nBottom + 1, ScFlatBoolColSegments(mrSheetLimits.mnMaxCol)).first;
820  it->second.setTrue( nCol, nCol );
821  }
822  }
823 
824  while( nTopPrev <= mrSheetLimits.mnMaxRow && nBottomPrev <= mrSheetLimits.mnMaxRow && ( nCol > nStartCol ) )
825  {
826  bool bRangeMarked;
827  const bool bHasValue = aPrevItr1.getValue( nTopPrev, bRangeMarked );
828  assert(bHasValue); (void)bHasValue;
829  if( bRangeMarked )
830  {
831  nBottomPrev = aPrevItr1.getLastPos();
832  ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(),
833  nCol, nBottomPrev, aMultiRange.aStart.Tab());
834  lcl_AddRanges( rRange, aAddRange ); // Right envelope
835  aRightEnvelope.push_back( aAddRange );
836  nTopPrev = ++nBottomPrev;
837  }
838  else
839  {
840  nBottomPrev = aPrevItr1.getLastPos();
841  nTopPrev = ++nBottomPrev;
842  }
843  }
844  }
845  else if( nCol > nStartCol )
846  {
847  bPrevColUnMarked = true;
848  SCROW nTopPrev = 0, nBottomPrev = 0;
849  bool bRangeMarked = false;
851  pPrevColMarkedRows ? *pPrevColMarkedRows : aNoRowsMarked);
852  while( nTopPrev <= mrSheetLimits.mnMaxRow && nBottomPrev <= mrSheetLimits.mnMaxRow )
853  {
854  const bool bHasValue = aPrevItr.getValue(nTopPrev, bRangeMarked);
855  assert(bHasValue); (void)bHasValue;
856  if( bRangeMarked )
857  {
858  nBottomPrev = aPrevItr.getLastPos();
859  ScRange aAddRange(nCol, nTopPrev, aMultiRange.aStart.Tab(),
860  nCol, nBottomPrev, aMultiRange.aStart.Tab());
861  lcl_AddRanges( rRange, aAddRange ); // Right envelope
862  aRightEnvelope.push_back( aAddRange );
863  nTopPrev = ++nBottomPrev;
864  }
865  else
866  {
867  nBottomPrev = aPrevItr.getLastPos();
868  nTopPrev = ++nBottomPrev;
869  }
870  }
871  }
872  if ( bCurColUnMarked )
873  pPrevColMarkedRows.reset();
874  else
875  pPrevColMarkedRows = std::move( pCurColMarkedRows );
876  }
877  for( auto& rKV : aRowToColSegmentsInTopEnvelope )
878  {
879  SCCOL nStart = nStartCol;
881  while( nStart <= nEndCol )
882  {
883  if( !rKV.second.getRangeData( nStart, aRange ) )
884  break;
885  if( aRange.mbValue ) // is marked
886  aTopEnvelope.push_back( ScRange( aRange.mnCol1, rKV.first, aMultiRange.aStart.Tab(),
887  aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) );
888  nStart = aRange.mnCol2 + 1;
889  }
890  }
891  for( auto& rKV : aRowToColSegmentsInBottomEnvelope )
892  {
893  SCCOL nStart = nStartCol;
895  while( nStart <= nEndCol )
896  {
897  if( !rKV.second.getRangeData( nStart, aRange ) )
898  break;
899  if( aRange.mbValue ) // is marked
901  aRange.mnCol2, rKV.first, aMultiRange.aStart.Tab() ) );
902  nStart = aRange.mnCol2 + 1;
903  }
904  }
905  }
906  else if( bMarked )
907  {
909  SCROW nRow1, nRow2, nRow1New, nRow2New;
910  SCCOL nCol1, nCol2, nCol1New, nCol2New;
911  SCTAB nTab1, nTab2;
912  aMarkRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
913  nCol1New = nCol1;
914  nCol2New = nCol2;
915  nRow1New = nRow1;
916  nRow2New = nRow2;
917  // Each envelope will have zero or more ranges for single rectangle selection.
918  if( nCol1 > 0 )
919  {
920  aLeftEnvelope.push_back( ScRange( nCol1 - 1, nRow1, nTab1, nCol1 - 1, nRow2, nTab2 ) );
921  --nCol1New;
922  }
923  if( nRow1 > 0 )
924  {
925  aTopEnvelope.push_back( ScRange( nCol1, nRow1 - 1, nTab1, nCol2, nRow1 - 1, nTab2 ) );
926  --nRow1New;
927  }
928  if( nCol2 < mrSheetLimits.mnMaxCol )
929  {
930  aRightEnvelope.push_back( ScRange( nCol2 + 1, nRow1, nTab1, nCol2 + 1, nRow2, nTab2 ) );
931  ++nCol2New;
932  }
933  if( nRow2 < mrSheetLimits.mnMaxRow )
934  {
935  aBottomEnvelope.push_back( ScRange( nCol1, nRow2 + 1, nTab1, nCol2, nRow2 + 1, nTab2 ) );
936  ++nRow2New;
937  }
938  rRange = ScRange( nCol1New, nRow1New, nTab1, nCol2New, nRow2New, nTab2 );
939  }
940 }
941 
943 {
944  return aMultiSel.GetMarkArray( nCol );
945 }
946 
947 //iterators
949 {
950  return maTabMarked.begin();
951 }
952 
954 {
955  return maTabMarked.end();
956 }
957 
959 {
960  return maTabMarked.begin();
961 }
962 
964 {
965  return maTabMarked.end();
966 }
967 
969 {
970  return maTabMarked.rbegin();
971 }
972 
973 /* 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
void ShiftCols(const ScDocument &rDoc, SCCOL nStartCol, long nColOffset)
Definition: markdata.cxx:651
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
SC_DLLPUBLIC void IncColIfNotLessThan(const ScDocument &rDoc, SCCOL nStartCol, SCCOL nOffset)
Definition: address.cxx:2407
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
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:677
ScRange aMarkRange
Definition: markdata.hxx:50
void SetCol(SCCOL nColP)
Definition: address.hxx:279
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:695
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:942
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
SC_DLLPUBLIC void IncRowIfNotLessThan(const ScDocument &rDoc, SCROW nStartRow, SCROW nOffset)
Definition: address.cxx:2427
bool HasAnyMarks() const
Definition: markmulti.cxx:334
iterator end()
Definition: markdata.cxx:953
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
iterator begin()
Definition: markdata.cxx:948
sal_Int32 SCROW
Definition: types.hxx:18
SC_DLLPUBLIC void PutInOrder()
Definition: address.cxx:1573
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:968
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 &rDoc, SCROW nStartRow, long nRowOffset)
Definition: markdata.cxx:664
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo