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
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;
55 bMarked = rOther.bMarked;
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{
83
84 bMarked = bMultiMarked = false;
85 bMarking = bMarkIsNeg = false;
90}
91
92void 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
107void 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{
152 aMarkRange.aEnd.SetTab(nTab);
154 aMultiRange.aEnd.SetTab(nTab);
155}
156
157void 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
270bool 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
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
319void 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
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
372void 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
464std::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
481std::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
565bool 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
609SCROW 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
659void 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
672void 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
685static 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
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: */
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:150
SCTAB Tab() const
Definition: address.hxx:283
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
SCCOL Col() const
Definition: address.hxx:279
bool getValue(SCROW nPos, bool &rVal)
bool setFalse(SCROW nRow1, SCROW nRow2)
This is a rather odd datastructure.
Definition: markarr.hxx:44
bool HasMarks() const
Definition: markarr.hxx:62
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
void ExtendRangeListTables(ScRangeList *pList) const
Definition: markdata.cxx:432
bool bMarkIsNeg
Definition: markdata.hxx:61
const ScSheetLimits & mrSheetLimits
Definition: markdata.hxx:56
bool IsAllMarked(const ScRange &rRange) const
Definition: markdata.cxx:565
ScRangeList GetMarkedRangesForTab(SCTAB nTab) const
Get marked ranges with sheet-tab set to nTab.
Definition: markdata.cxx:457
void SelectTable(SCTAB nTab, bool bNew)
Definition: markdata.cxx:157
void ShiftRows(const ScDocument &rDoc, SCROW nStartRow, sal_Int32 nRowOffset)
Definition: markdata.cxx:672
SCTAB GetFirstSelected() const
Definition: markdata.cxx:185
void SelectOneTable(SCTAB nTab)
Definition: markdata.cxx:174
bool HasMultiMarks(SCCOL nCol) const
Definition: markdata.cxx:617
SCROW GetNextMarked(SCCOL nCol, SCROW nRow, bool bUp) const
May return -1.
Definition: markdata.cxx:609
void FillRangeListWithMarks(ScRangeList *pList, bool bClear, SCTAB nForTab=-1) const
Create a range list of marks.
Definition: markdata.cxx:372
ScRangeList aBottomEnvelope
Definition: markdata.hxx:53
ScRangeList GetMarkedRanges() const
Definition: markdata.cxx:450
SCTAB GetLastSelected() const
Definition: markdata.cxx:194
bool HasAnyMultiMarks() const
Definition: markdata.cxx:625
void SetSelectedTabs(const MarkedTabsType &rTabs)
Definition: markdata.cxx:203
bool GetTableSelect(SCTAB nTab) const
Definition: markdata.cxx:169
bool IsColumnMarked(SCCOL nCol) const
Definition: markdata.cxx:287
std::set< SCTAB > MarkedTabsType
Definition: markdata.hxx:45
ScRangeList aTopEnvelope
Definition: markdata.hxx:52
void SetMultiMarkArea(const ScRange &rRange, bool bMark=true, bool bSetupMulti=false)
Definition: markdata.cxx:107
ScMultiSel aMultiSel
Definition: markdata.hxx:51
ScMarkData & operator=(const ScMarkData &rData)
Definition: markdata.cxx:45
void GetSelectionCover(ScRange &rRange)
Definition: markdata.cxx:703
bool IsRowMarked(SCROW nRow) const
Definition: markdata.cxx:303
MarkedTabsType maTabMarked
Definition: markdata.hxx:47
void ShiftCols(const ScDocument &rDoc, SCCOL nStartCol, sal_Int32 nColOffset)
Definition: markdata.cxx:659
bool bMarked
Definition: markdata.hxx:57
std::vector< sc::ColRowSpan > GetMarkedColSpans() const
Definition: markdata.cxx:481
bool IsCellMarked(SCCOL nCol, SCROW nRow, bool bNoSimple=false) const
Definition: markdata.cxx:270
void ResetMark()
Definition: markdata.cxx:80
ScRange aMarkRange
Definition: markdata.hxx:49
ScMarkData(const ScSheetLimits &rSheetLimits)
Definition: markdata.cxx:38
ScRangeList aRightEnvelope
Definition: markdata.hxx:55
SCTAB GetSelectCount() const
Definition: markdata.cxx:180
void SetAreaTab(SCTAB nTab)
Definition: markdata.cxx:149
ScRange aMultiRange
Definition: markdata.hxx:50
void MarkToMulti()
Definition: markdata.cxx:209
void SetMarkArea(const ScRange &rRange)
Definition: markdata.cxx:92
void InsertTab(SCTAB nTab)
Definition: markdata.cxx:633
ScRangeList aLeftEnvelope
Definition: markdata.hxx:54
SCCOL GetStartOfEqualColumns(SCCOL nLastCol, SCCOL nMinCol=0) const
Definition: markdata.cxx:593
std::vector< sc::ColRowSpan > GetMarkedRowSpans() const
Definition: markdata.cxx:464
bool bMultiMarked
Definition: markdata.hxx:58
bool bMarking
Definition: markdata.hxx:60
void DeleteTab(SCTAB nTab)
Definition: markdata.cxx:646
void MarkFromRangeList(const ScRangeList &rList, bool bReset)
Definition: markdata.cxx:319
void MarkToSimple()
Definition: markdata.cxx:222
bool Next(SCROW &rTop, SCROW &rBottom)
Definition: markmulti.cxx:455
bool GetMark(SCCOL nCol, SCROW nRow) const
Definition: markmulti.cxx:108
bool HasOneMark(SCCOL nCol, SCROW &rStartRow, SCROW &rEndRow) const
Definition: markmulti.cxx:72
bool IsAllMarked(SCCOL nCol, SCROW nStartRow, SCROW nEndRow) const
Definition: markmulti.cxx:115
bool IsRowMarked(SCROW nRow) const
Definition: markmulti.cxx:321
const ScMarkArray & GetRowSelArray() const
Definition: markmulti.hxx:72
bool HasAnyMarks() const
Definition: markmulti.cxx:344
const ScMarkArray * GetMultiSelArray(SCCOL nCol) const
Definition: markmulti.cxx:412
SCCOL GetStartOfEqualColumns(SCCOL nLastCol, SCCOL nMinCol=0) const
Definition: markmulti.cxx:157
void ShiftRows(SCROW nStartRow, sal_Int32 nRowOffset)
Definition: markmulti.cxx:405
void Set(ScRangeList const &)
optimised init-from-range-list.
Definition: markmulti.cxx:264
void ShiftCols(SCCOL nStartCol, sal_Int32 nColOffset)
Definition: markmulti.cxx:354
void Clear()
Definition: markmulti.cxx:50
bool HasMarks(SCCOL nCol) const
Definition: markmulti.cxx:65
bool IsEmpty() const
Definition: markmulti.hxx:62
bool HasEqualRowsMarked(SCCOL nCol1, SCCOL nCol2) const
Definition: markmulti.cxx:140
bool IsRowRangeMarked(SCROW nStartRow, SCROW nEndRow) const
Definition: markmulti.cxx:326
void SetMarkArea(SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow, bool bMark)
Definition: markmulti.cxx:204
SCROW GetNextMarked(SCCOL nCol, SCROW nRow, bool bUp) const
Definition: markmulti.cxx:176
void RemoveAll()
Definition: rangelst.cxx:1101
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:152
ScRange Combine() const
Definition: rangelst.cxx:1107
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1137
size_t size() const
Definition: rangelst.hxx:89
void insert(std::vector< ScRange >::iterator aPos, std::vector< ScRange >::const_iterator aSourceBegin, std::vector< ScRange >::const_iterator aSourceEnd)
Definition: rangelst.hxx:101
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:690
void PutInOrder()
Definition: address.hxx:622
ScAddress aEnd
Definition: address.hxx:498
void IncColIfNotLessThan(const ScDocument &rDoc, SCCOL nStartCol, SCCOL nOffset)
Definition: address.cxx:2374
void IncRowIfNotLessThan(const ScDocument &rDoc, SCROW nStartRow, SCROW nOffset)
Definition: address.cxx:2394
ScAddress aStart
Definition: address.hxx:497
int nCount
sal_Int64 n
static void lcl_AddRanges(ScRange &rRangeDest, const ScRange &rNewRange)
Definition: markdata.cxx:685
int i
const SCCOL mnMaxCol
Definition: sheetlimits.hxx:29
const SCROW mnMaxRow
Maximum addressable column.
Definition: sheetlimits.hxx:30
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17