1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
32 #include <osl/diagnose.h>
34 #include <mdds/flat_segment_tree.hpp>
38 ScMarkData::ScMarkData(const ScSheetLimits
& rSheetLimits
) :
39 aMultiSel(rSheetLimits
),
40 mrSheetLimits(rSheetLimits
)
45 ScMarkData
& ScMarkData::operator=(const ScMarkData
& rOther
)
47 maTabMarked
= rOther
.maTabMarked
;
48 aMarkRange
= rOther
.aMarkRange
;
49 aMultiRange
= rOther
.aMultiRange
;
50 aMultiSel
= rOther
.aMultiSel
;
51 aTopEnvelope
= rOther
.aTopEnvelope
;
52 aBottomEnvelope
= rOther
.aBottomEnvelope
;
53 aLeftEnvelope
= rOther
.aLeftEnvelope
;
54 aRightEnvelope
= rOther
.aRightEnvelope
;
55 bMarked
= rOther
.bMarked
;
56 bMultiMarked
= rOther
.bMultiMarked
;
57 bMarking
= rOther
.bMarking
;
58 bMarkIsNeg
= rOther
.bMarkIsNeg
;
62 ScMarkData
& ScMarkData::operator=(ScMarkData
&& rOther
)
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
;
80 void ScMarkData::ResetMark()
84 bMarked
= bMultiMarked
= false;
85 bMarking
= bMarkIsNeg
= false;
86 aTopEnvelope
.RemoveAll();
87 aBottomEnvelope
.RemoveAll();
88 aLeftEnvelope
.RemoveAll();
89 aRightEnvelope
.RemoveAll();
92 void ScMarkData::SetMarkArea( const ScRange
& rRange
)
95 aMarkRange
.PutInOrder();
98 // Upon creation of a document ScFormatShell GetTextAttrState
99 // may query (default) attributes although no sheet is marked yet.
101 if ( !GetSelectCount() )
102 maTabMarked
.insert( aMarkRange
.aStart
.Tab() );
107 void ScMarkData::SetMultiMarkArea( const ScRange
& rRange
, bool bMark
, bool bSetupMulti
)
109 if ( aMultiSel
.IsEmpty() )
111 // if simple mark range is set, copy to multi marks
112 if ( bMarked
&& !bMarkIsNeg
&& !bSetupMulti
)
115 SCCOL nStartCol
= aMarkRange
.aStart
.Col();
116 SCCOL nEndCol
= aMarkRange
.aEnd
.Col();
117 PutInOrder( nStartCol
, nEndCol
);
118 SetMultiMarkArea( aMarkRange
, true, true );
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
);
129 aMultiSel
.SetMarkArea( nStartCol
, nEndCol
, nStartRow
, nEndRow
, bMark
);
131 if ( bMultiMarked
) // Update aMultiRange
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
);
144 aMultiRange
= rRange
; // new
149 void ScMarkData::SetAreaTab( SCTAB nTab
)
151 aMarkRange
.aStart
.SetTab(nTab
);
152 aMarkRange
.aEnd
.SetTab(nTab
);
153 aMultiRange
.aStart
.SetTab(nTab
);
154 aMultiRange
.aEnd
.SetTab(nTab
);
157 void ScMarkData::SelectTable( SCTAB nTab
, bool bNew
)
161 maTabMarked
.insert( nTab
);
165 maTabMarked
.erase( nTab
);
169 bool ScMarkData::GetTableSelect( SCTAB nTab
) const
171 return (maTabMarked
.find( nTab
) != maTabMarked
.end());
174 void ScMarkData::SelectOneTable( SCTAB nTab
)
177 maTabMarked
.insert( nTab
);
180 SCTAB
ScMarkData::GetSelectCount() const
182 return static_cast<SCTAB
> ( maTabMarked
.size() );
185 SCTAB
ScMarkData::GetFirstSelected() const
187 if (!maTabMarked
.empty())
188 return (*maTabMarked
.begin());
190 OSL_FAIL("GetFirstSelected: nothing selected");
194 SCTAB
ScMarkData::GetLastSelected() const
196 if (!maTabMarked
.empty())
197 return (*maTabMarked
.rbegin());
199 OSL_FAIL("GetLastSelected: nothing selected");
203 void ScMarkData::SetSelectedTabs(const MarkedTabsType
& rTabs
)
205 MarkedTabsType
aTabs(rTabs
.begin(), rTabs
.end());
206 maTabMarked
.swap(aTabs
);
209 void ScMarkData::MarkToMulti()
211 if ( bMarked
&& !bMarking
)
213 SetMultiMarkArea( aMarkRange
, !bMarkIsNeg
);
216 // check if all multi mark ranges have been removed
217 if ( bMarkIsNeg
&& !HasAnyMultiMarks() )
222 void ScMarkData::MarkToSimple()
227 if ( bMultiMarked
&& bMarked
)
228 MarkToMulti(); // may result in bMarked and bMultiMarked reset
233 ScRange aNew
= aMultiRange
;
236 SCCOL nStartCol
= aNew
.aStart
.Col();
237 SCCOL nEndCol
= aNew
.aEnd
.Col();
239 while ( nStartCol
< nEndCol
&& !aMultiSel
.HasMarks( nStartCol
) )
241 while ( nStartCol
< nEndCol
&& !aMultiSel
.HasMarks( nEndCol
) )
244 // Rows are only taken from MarkArray
245 SCROW nStartRow
, nEndRow
;
246 if ( aMultiSel
.HasOneMark( nStartCol
, nStartRow
, nEndRow
) )
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
)
258 aNew
.aStart
.SetCol(nStartCol
);
259 aNew
.aStart
.SetRow(nStartRow
);
260 aNew
.aEnd
.SetCol(nEndCol
);
261 aNew
.aEnd
.SetRow(nEndRow
);
270 bool ScMarkData::IsCellMarked( SCCOL nCol
, SCROW nRow
, bool bNoSimple
) const
272 if ( bMarked
&& !bNoSimple
&& !bMarkIsNeg
)
273 if ( aMarkRange
.aStart
.Col() <= nCol
&& aMarkRange
.aEnd
.Col() >= nCol
&&
274 aMarkRange
.aStart
.Row() <= nRow
&& aMarkRange
.aEnd
.Row() >= nRow
)
279 //TODO: test here for negative Marking ?
281 return aMultiSel
.GetMark( nCol
, nRow
);
287 bool ScMarkData::IsColumnMarked( SCCOL nCol
) const
289 // bMarkIsNeg meanwhile also for columns heads
290 //TODO: GetMarkColumnRanges for completely marked column
292 if ( bMarked
&& !bMarkIsNeg
&&
293 aMarkRange
.aStart
.Col() <= nCol
&& aMarkRange
.aEnd
.Col() >= nCol
&&
294 aMarkRange
.aStart
.Row() == 0 && aMarkRange
.aEnd
.Row() == mrSheetLimits
.mnMaxRow
)
297 if ( bMultiMarked
&& aMultiSel
.IsAllMarked( nCol
, 0, mrSheetLimits
.mnMaxRow
) )
303 bool ScMarkData::IsRowMarked( SCROW nRow
) const
305 // bMarkIsNeg meanwhile also for row heads
306 //TODO: GetMarkRowRanges for completely marked rows
308 if ( bMarked
&& !bMarkIsNeg
&&
309 aMarkRange
.aStart
.Col() == 0 && aMarkRange
.aEnd
.Col() == mrSheetLimits
.mnMaxCol
&&
310 aMarkRange
.aStart
.Row() <= nRow
&& aMarkRange
.aEnd
.Row() >= nRow
)
314 return aMultiSel
.IsRowMarked( nRow
);
319 void ScMarkData::MarkFromRangeList( const ScRangeList
& rList
, bool bReset
)
327 size_t nCount
= rList
.size();
328 if ( nCount
== 1 && !bMarked
&& !bMultiMarked
)
330 const ScRange
& rRange
= rList
[ 0 ];
331 SetMarkArea( rRange
);
332 SelectTable( rRange
.aStart
.Tab(), true );
336 for (size_t i
=0; i
< nCount
; i
++)
338 const ScRange
& rRange
= rList
[ i
];
339 SetMultiMarkArea( rRange
);
340 SelectTable( rRange
.aStart
.Tab(), true );
346 Optimise the case of constructing from a range list, speeds up import.
348 ScMarkData::ScMarkData(const ScSheetLimits
& rLimits
, const ScRangeList
& rList
)
349 : aMultiSel(rLimits
),
350 mrSheetLimits(rLimits
)
354 for (const ScRange
& rRange
: rList
)
355 maTabMarked
.insert( rRange
.aStart
.Tab() );
357 if (rList
.size() > 1)
360 aMultiRange
= rList
.Combine();
362 aMultiSel
.Set( rList
);
364 else if (rList
.size() == 1)
366 const ScRange
& rRange
= rList
[ 0 ];
367 SetMarkArea( rRange
);
372 void ScMarkData::FillRangeListWithMarks( ScRangeList
* pList
, bool bClear
, SCTAB nForTab
) const
380 //TODO: for multiple selected tables enter multiple ranges !!!
384 SCTAB nTab
= (nForTab
< 0 ? aMultiRange
.aStart
.Tab() : nForTab
);
386 SCCOL nStartCol
= aMultiRange
.aStart
.Col();
387 SCCOL nEndCol
= aMultiRange
.aEnd
.Col();
388 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
390 if (aMultiSel
.HasMarks( nCol
))
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
397 SCCOL nToCol
= nCol
+1;
398 for ( ; nToCol
<= nEndCol
; ++nToCol
)
400 if (!aMultiSel
.HasEqualRowsMarked(nCol
, nToCol
))
404 ScRange
aRange( nCol
, 0, nTab
, nToCol
, 0, nTab
);
406 ScMultiSelIter
aMultiIter( aMultiSel
, nCol
);
407 while ( aMultiIter
.Next( nTop
, nBottom
) )
409 aRange
.aStart
.SetRow( nTop
);
410 aRange
.aEnd
.SetRow( nBottom
);
411 pList
->Join( aRange
);
421 pList
->push_back( aMarkRange
);
424 ScRange
aRange( aMarkRange
);
425 aRange
.aStart
.SetTab( nForTab
);
426 aRange
.aEnd
.SetTab( nForTab
);
427 pList
->push_back( aRange
);
432 void ScMarkData::ExtendRangeListTables( ScRangeList
* pList
) const
437 ScRangeList
aOldList(*pList
);
438 pList
->RemoveAll(); //TODO: or skip the existing below
440 for (const auto& rTab
: maTabMarked
)
441 for ( size_t i
=0, nCount
= aOldList
.size(); i
<nCount
; i
++)
443 ScRange aRange
= aOldList
[ i
];
444 aRange
.aStart
.SetTab(rTab
);
445 aRange
.aEnd
.SetTab(rTab
);
446 pList
->push_back( aRange
);
450 ScRangeList
ScMarkData::GetMarkedRanges() const
453 FillRangeListWithMarks(&aRet
, false);
457 ScRangeList
ScMarkData::GetMarkedRangesForTab( SCTAB nTab
) const
460 FillRangeListWithMarks(&aRet
, false, nTab
);
464 std::vector
<sc::ColRowSpan
> ScMarkData::GetMarkedRowSpans() const
466 typedef mdds::flat_segment_tree
<SCCOLROW
, bool> SpansType
;
468 ScRangeList aRanges
= GetMarkedRanges();
469 SpansType
aSpans(0, mrSheetLimits
.mnMaxRow
+1, false);
470 SpansType::const_iterator itPos
= aSpans
.begin();
472 for (size_t i
= 0, n
= aRanges
.size(); i
< n
; ++i
)
474 const ScRange
& r
= aRanges
[i
];
475 itPos
= aSpans
.insert(itPos
, r
.aStart
.Row(), r
.aEnd
.Row()+1, true).first
;
478 return sc::toSpanArray
<SCCOLROW
,sc::ColRowSpan
>(aSpans
);
481 std::vector
<sc::ColRowSpan
> ScMarkData::GetMarkedColSpans() const
486 SCCOL nStartCol
= aMultiRange
.aStart
.Col();
487 SCCOL nEndCol
= aMultiRange
.aEnd
.Col();
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();
496 if (aMultiSel
.GetRowSelArray().HasMarks())
498 itPos
= aSpans
.insert(itPos
, nStartCol
, nEndCol
+1, true).first
;
499 break; // do; all columns marked
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
505 for (SCCOL nCol
= nStartCol
; nCol
<= nEndCol
; ++nCol
)
507 const ScMarkArray
* pMultiArray
= aMultiSel
.GetMultiSelArray( nCol
);
508 if (pMultiArray
&& pMultiArray
->HasMarks())
509 itPos
= aSpans
.insert(itPos
, nCol
, nCol
+1, true).first
;
515 aSpans
.insert(itPos
, aMarkRange
.aStart
.Col(), aMarkRange
.aEnd
.Col()+1, true);
517 return sc::toSpanArray
<SCCOLROW
,sc::ColRowSpan
>(aSpans
);
521 // A plain vector is sufficient, avoid segment tree and conversion
522 // to vector overhead.
523 std::vector
<sc::ColRowSpan
> aVec
;
524 if (aMultiSel
.GetRowSelArray().HasMarks())
526 aVec
.emplace_back( nStartCol
, nEndCol
);
527 return aVec
; // all columns marked
529 sc::ColRowSpan
aSpan( -1, -1);
530 for (SCCOL nCol
= nStartCol
; nCol
<= nEndCol
; ++nCol
)
532 const ScMarkArray
* pMultiArray
= aMultiSel
.GetMultiSelArray( nCol
);
533 if (pMultiArray
&& pMultiArray
->HasMarks())
535 if (aSpan
.mnStart
== -1)
536 aSpan
.mnStart
= nCol
;
541 // Add span gathered so far, if any.
542 if (aSpan
.mnStart
!= -1)
544 aVec
.push_back( aSpan
);
549 // Add last span, if any.
550 if (aSpan
.mnStart
!= -1)
551 aVec
.push_back( aSpan
);
556 // Only reached if not multi marked.
557 std::vector
<sc::ColRowSpan
> aVec
;
560 aVec
.emplace_back( aMarkRange
.aStart
.Col(), aMarkRange
.aEnd
.Col());
565 bool ScMarkData::IsAllMarked( const ScRange
& rRange
) const
567 SCCOL nStartCol
= rRange
.aStart
.Col();
568 SCROW nStartRow
= rRange
.aStart
.Row();
569 SCCOL nEndCol
= rRange
.aEnd
.Col();
570 SCROW nEndRow
= rRange
.aEnd
.Row();
574 if ( bMarked
&& !bMarkIsNeg
&&
575 aMarkRange
.aStart
.Col() <= nStartCol
&& aMarkRange
.aEnd
.Col() >= nEndCol
&&
576 aMarkRange
.aStart
.Row() <= nStartRow
&& aMarkRange
.aEnd
.Row() >= nEndRow
)
583 if ( nStartCol
== 0 && nEndCol
== mrSheetLimits
.mnMaxCol
)
584 return aMultiSel
.IsRowRangeMarked( nStartRow
, nEndRow
);
586 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
&& bOk
; nCol
++)
587 if ( !aMultiSel
.IsAllMarked( nCol
, nStartRow
, nEndRow
) )
593 SCCOL
ScMarkData::GetStartOfEqualColumns( SCCOL nLastCol
, SCCOL nMinCol
) const
597 if ( bMarked
&& !bMarkIsNeg
)
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();
606 return aMultiSel
.GetStartOfEqualColumns( nLastCol
, nMinCol
);
609 SCROW
ScMarkData::GetNextMarked( SCCOL nCol
, SCROW nRow
, bool bUp
) const
614 return aMultiSel
.GetNextMarked( nCol
, nRow
, bUp
);
617 bool ScMarkData::HasMultiMarks( SCCOL nCol
) const
622 return aMultiSel
.HasMarks( nCol
);
625 bool ScMarkData::HasAnyMultiMarks() const
630 return aMultiSel
.HasAnyMarks();
633 void ScMarkData::InsertTab( SCTAB nTab
)
635 std::set
<SCTAB
> tabMarked
;
636 for (const auto& rTab
: maTabMarked
)
639 tabMarked
.insert(rTab
);
641 tabMarked
.insert(rTab
+ 1);
643 maTabMarked
.swap(tabMarked
);
646 void ScMarkData::DeleteTab( SCTAB nTab
)
648 std::set
<SCTAB
> tabMarked
;
649 for (const auto& rTab
: maTabMarked
)
652 tabMarked
.insert(rTab
);
653 else if (rTab
> nTab
)
654 tabMarked
.insert(rTab
- 1);
656 maTabMarked
.swap(tabMarked
);
659 void ScMarkData::ShiftCols(const ScDocument
& rDoc
, SCCOL nStartCol
, sal_Int32 nColOffset
)
662 aMarkRange
.IncColIfNotLessThan(rDoc
, nStartCol
, nColOffset
);
665 aMultiRange
.IncColIfNotLessThan(rDoc
, nStartCol
, nColOffset
);
666 aMultiSel
.ShiftCols(nStartCol
, nColOffset
);
670 void ScMarkData::ShiftRows(const ScDocument
& rDoc
, SCROW nStartRow
, sal_Int32 nRowOffset
)
673 aMarkRange
.IncRowIfNotLessThan(rDoc
, nStartRow
, nRowOffset
);
676 aMultiRange
.IncRowIfNotLessThan(rDoc
, nStartRow
, nRowOffset
);
677 aMultiSel
.ShiftRows(nStartRow
, nRowOffset
);
681 static void lcl_AddRanges(ScRange
& rRangeDest
, const ScRange
& rNewRange
)
683 SCCOL nStartCol
= rNewRange
.aStart
.Col();
684 SCROW nStartRow
= rNewRange
.aStart
.Row();
685 SCCOL nEndCol
= rNewRange
.aEnd
.Col();
686 SCROW nEndRow
= rNewRange
.aEnd
.Row();
687 PutInOrder( nStartRow
, nEndRow
);
688 PutInOrder( nStartCol
, nEndCol
);
689 if ( nStartCol
< rRangeDest
.aStart
.Col() )
690 rRangeDest
.aStart
.SetCol( nStartCol
);
691 if ( nStartRow
< rRangeDest
.aStart
.Row() )
692 rRangeDest
.aStart
.SetRow( nStartRow
);
693 if ( nEndCol
> rRangeDest
.aEnd
.Col() )
694 rRangeDest
.aEnd
.SetCol( nEndCol
);
695 if ( nEndRow
> rRangeDest
.aEnd
.Row() )
696 rRangeDest
.aEnd
.SetRow( nEndRow
);
699 void ScMarkData::GetSelectionCover( ScRange
& rRange
)
703 rRange
= aMultiRange
;
704 SCCOL nStartCol
= aMultiRange
.aStart
.Col(), nEndCol
= aMultiRange
.aEnd
.Col();
705 PutInOrder( nStartCol
, nEndCol
);
706 nStartCol
= ( nStartCol
== 0 ) ? nStartCol
: nStartCol
- 1;
707 nEndCol
= ( nEndCol
== mrSheetLimits
.mnMaxCol
) ? nEndCol
: nEndCol
+ 1;
708 std::unique_ptr
<ScFlatBoolRowSegments
> pPrevColMarkedRows
;
709 std::unique_ptr
<ScFlatBoolRowSegments
> pCurColMarkedRows
;
710 std::unordered_map
<SCROW
,ScFlatBoolColSegments
> aRowToColSegmentsInTopEnvelope
;
711 std::unordered_map
<SCROW
,ScFlatBoolColSegments
> aRowToColSegmentsInBottomEnvelope
;
712 ScFlatBoolRowSegments
aNoRowsMarked(mrSheetLimits
.mnMaxRow
);
713 aNoRowsMarked
.setFalse( 0, mrSheetLimits
.mnMaxRow
);
715 bool bPrevColUnMarked
= false;
717 for ( SCCOL nCol
=nStartCol
; nCol
<= nEndCol
; nCol
++ )
720 bool bCurColUnMarked
= !aMultiSel
.HasMarks( nCol
);
721 if ( !bCurColUnMarked
)
723 pCurColMarkedRows
.reset( new ScFlatBoolRowSegments(mrSheetLimits
.mnMaxRow
) );
724 pCurColMarkedRows
->setFalse( 0, mrSheetLimits
.mnMaxRow
);
725 ScMultiSelIter
aMultiIter( aMultiSel
, nCol
);
726 ScFlatBoolRowSegments::ForwardIterator
aPrevItr(
727 pPrevColMarkedRows
? *pPrevColMarkedRows
728 : aNoRowsMarked
); // For finding left envelope
729 ScFlatBoolRowSegments::ForwardIterator
aPrevItr1(
730 pPrevColMarkedRows
? *pPrevColMarkedRows
731 : aNoRowsMarked
); // For finding right envelope
732 SCROW nTopPrev
= 0, nBottomPrev
= 0; // For right envelope
733 while ( aMultiIter
.Next( nTop
, nBottom
) )
735 pCurColMarkedRows
->setTrue( nTop
, nBottom
);
736 if( bPrevColUnMarked
&& ( nCol
> nStartCol
))
738 ScRange
aAddRange(nCol
- 1, nTop
, aMultiRange
.aStart
.Tab(),
739 nCol
- 1, nBottom
, aMultiRange
.aStart
.Tab());
740 lcl_AddRanges( rRange
, aAddRange
); // Left envelope
741 aLeftEnvelope
.push_back( aAddRange
);
743 else if( nCol
> nStartCol
)
745 SCROW nTop1
= nTop
, nBottom1
= nTop
;
746 while( nTop1
<= nBottom
&& nBottom1
<= nBottom
)
748 bool bRangeMarked
= false;
749 const bool bHasValue
= aPrevItr
.getValue( nTop1
, bRangeMarked
);
750 assert(bHasValue
); (void)bHasValue
;
753 nTop1
= aPrevItr
.getLastPos() + 1;
758 nBottom1
= aPrevItr
.getLastPos();
759 if( nBottom1
> nBottom
)
761 ScRange
aAddRange( nCol
- 1, nTop1
, aMultiRange
.aStart
.Tab(),
762 nCol
- 1, nBottom1
, aMultiRange
.aStart
.Tab() );
763 lcl_AddRanges( rRange
, aAddRange
); // Left envelope
764 aLeftEnvelope
.push_back( aAddRange
);
768 while( nTopPrev
<= nBottom
&& nBottomPrev
<= nBottom
)
771 const bool bHasValue
= aPrevItr1
.getValue( nTopPrev
, bRangeMarked
);
772 assert(bHasValue
); (void)bHasValue
;
775 nBottomPrev
= aPrevItr1
.getLastPos();
776 if( nTopPrev
< nTop
)
778 if( nBottomPrev
>= nTop
)
780 nBottomPrev
= nTop
- 1;
781 ScRange
aAddRange( nCol
, nTopPrev
, aMultiRange
.aStart
.Tab(),
782 nCol
, nBottomPrev
, aMultiRange
.aStart
.Tab());
783 lcl_AddRanges( rRange
, aAddRange
); // Right envelope
784 aRightEnvelope
.push_back( aAddRange
);
785 nTopPrev
= nBottomPrev
= (nBottom
+ 1);
789 ScRange
aAddRange( nCol
, nTopPrev
, aMultiRange
.aStart
.Tab(),
790 nCol
, nBottomPrev
, aMultiRange
.aStart
.Tab());
791 lcl_AddRanges( rRange
, aAddRange
); // Right envelope
792 aRightEnvelope
.push_back( aAddRange
);
793 nTopPrev
= ++nBottomPrev
;
797 nTopPrev
= nBottomPrev
= ( nBottom
+ 1 );
801 nBottomPrev
= aPrevItr1
.getLastPos();
802 nTopPrev
= ++nBottomPrev
;
808 ScRange
aAddRange( nCol
, nTop
- 1, aMultiRange
.aStart
.Tab(),
809 nCol
, nTop
- 1, aMultiRange
.aStart
.Tab());
810 lcl_AddRanges( rRange
, aAddRange
); // Top envelope
811 auto it
= aRowToColSegmentsInTopEnvelope
.find(nTop
- 1);
812 if (it
== aRowToColSegmentsInTopEnvelope
.end())
813 it
= aRowToColSegmentsInTopEnvelope
.emplace(nTop
- 1, ScFlatBoolColSegments(mrSheetLimits
.mnMaxCol
)).first
;
814 it
->second
.setTrue( nCol
, nCol
);
816 if( nBottom
< mrSheetLimits
.mnMaxRow
)
818 ScRange
aAddRange(nCol
, nBottom
+ 1, aMultiRange
.aStart
.Tab(),
819 nCol
, nBottom
+ 1, aMultiRange
.aStart
.Tab());
820 lcl_AddRanges( rRange
, aAddRange
); // Bottom envelope
821 auto it
= aRowToColSegmentsInBottomEnvelope
.find(nBottom
+ 1);
822 if (it
== aRowToColSegmentsInBottomEnvelope
.end())
823 it
= aRowToColSegmentsInBottomEnvelope
.emplace(nBottom
+ 1, ScFlatBoolColSegments(mrSheetLimits
.mnMaxCol
)).first
;
824 it
->second
.setTrue( nCol
, nCol
);
828 while( nTopPrev
<= mrSheetLimits
.mnMaxRow
&& nBottomPrev
<= mrSheetLimits
.mnMaxRow
&& ( nCol
> nStartCol
) )
831 const bool bHasValue
= aPrevItr1
.getValue( nTopPrev
, bRangeMarked
);
832 assert(bHasValue
); (void)bHasValue
;
835 nBottomPrev
= aPrevItr1
.getLastPos();
836 ScRange
aAddRange(nCol
, nTopPrev
, aMultiRange
.aStart
.Tab(),
837 nCol
, nBottomPrev
, aMultiRange
.aStart
.Tab());
838 lcl_AddRanges( rRange
, aAddRange
); // Right envelope
839 aRightEnvelope
.push_back( aAddRange
);
840 nTopPrev
= ++nBottomPrev
;
844 nBottomPrev
= aPrevItr1
.getLastPos();
845 nTopPrev
= ++nBottomPrev
;
849 else if( nCol
> nStartCol
)
851 bPrevColUnMarked
= true;
852 SCROW nTopPrev
= 0, nBottomPrev
= 0;
853 bool bRangeMarked
= false;
854 ScFlatBoolRowSegments::ForwardIterator
aPrevItr(
855 pPrevColMarkedRows
? *pPrevColMarkedRows
: aNoRowsMarked
);
856 while( nTopPrev
<= mrSheetLimits
.mnMaxRow
&& nBottomPrev
<= mrSheetLimits
.mnMaxRow
)
858 const bool bHasValue
= aPrevItr
.getValue(nTopPrev
, bRangeMarked
);
859 assert(bHasValue
); (void)bHasValue
;
862 nBottomPrev
= aPrevItr
.getLastPos();
863 ScRange
aAddRange(nCol
, nTopPrev
, aMultiRange
.aStart
.Tab(),
864 nCol
, nBottomPrev
, aMultiRange
.aStart
.Tab());
865 lcl_AddRanges( rRange
, aAddRange
); // Right envelope
866 aRightEnvelope
.push_back( aAddRange
);
867 nTopPrev
= ++nBottomPrev
;
871 nBottomPrev
= aPrevItr
.getLastPos();
872 nTopPrev
= ++nBottomPrev
;
876 if ( bCurColUnMarked
)
877 pPrevColMarkedRows
.reset();
879 pPrevColMarkedRows
= std::move( pCurColMarkedRows
);
881 for( auto& rKV
: aRowToColSegmentsInTopEnvelope
)
883 SCCOL nStart
= nStartCol
;
884 ScFlatBoolColSegments::RangeData aRange
;
885 while( nStart
<= nEndCol
)
887 if( !rKV
.second
.getRangeData( nStart
, aRange
) )
889 if( aRange
.mbValue
) // is marked
890 aTopEnvelope
.push_back( ScRange( aRange
.mnCol1
, rKV
.first
, aMultiRange
.aStart
.Tab(),
891 aRange
.mnCol2
, rKV
.first
, aMultiRange
.aStart
.Tab() ) );
892 nStart
= aRange
.mnCol2
+ 1;
895 for( auto& rKV
: aRowToColSegmentsInBottomEnvelope
)
897 SCCOL nStart
= nStartCol
;
898 ScFlatBoolColSegments::RangeData aRange
;
899 while( nStart
<= nEndCol
)
901 if( !rKV
.second
.getRangeData( nStart
, aRange
) )
903 if( aRange
.mbValue
) // is marked
904 aBottomEnvelope
.push_back( ScRange( aRange
.mnCol1
, rKV
.first
, aMultiRange
.aStart
.Tab(),
905 aRange
.mnCol2
, rKV
.first
, aMultiRange
.aStart
.Tab() ) );
906 nStart
= aRange
.mnCol2
+ 1;
912 aMarkRange
.PutInOrder();
913 SCROW nRow1
, nRow2
, nRow1New
, nRow2New
;
914 SCCOL nCol1
, nCol2
, nCol1New
, nCol2New
;
916 aMarkRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
921 // Each envelope will have zero or more ranges for single rectangle selection.
924 aLeftEnvelope
.push_back( ScRange( nCol1
- 1, nRow1
, nTab1
, nCol1
- 1, nRow2
, nTab2
) );
929 aTopEnvelope
.push_back( ScRange( nCol1
, nRow1
- 1, nTab1
, nCol2
, nRow1
- 1, nTab2
) );
932 if( nCol2
< mrSheetLimits
.mnMaxCol
)
934 aRightEnvelope
.push_back( ScRange( nCol2
+ 1, nRow1
, nTab1
, nCol2
+ 1, nRow2
, nTab2
) );
937 if( nRow2
< mrSheetLimits
.mnMaxRow
)
939 aBottomEnvelope
.push_back( ScRange( nCol1
, nRow2
+ 1, nTab1
, nCol2
, nRow2
+ 1, nTab2
) );
942 rRange
= ScRange( nCol1New
, nRow1New
, nTab1
, nCol2New
, nRow2New
, nTab2
);
946 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */