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