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 .
20 #include "markdata.hxx"
21 #include "markarr.hxx"
22 #include "rangelst.hxx"
23 #include <columnspanset.hxx>
24 #include <fstalgorithm.hxx>
26 #include <osl/diagnose.h>
28 #include <mdds/flat_segment_tree.hpp>
30 // STATIC DATA -----------------------------------------------------------
32 ScMarkData::ScMarkData() :
39 ScMarkData::ScMarkData(const ScMarkData
& rData
) :
40 maTabMarked( rData
.maTabMarked
),
41 aMarkRange( rData
.aMarkRange
),
42 aMultiRange( rData
.aMultiRange
),
45 bMarked
= rData
.bMarked
;
46 bMultiMarked
= rData
.bMultiMarked
;
47 bMarking
= rData
.bMarking
;
48 bMarkIsNeg
= rData
.bMarkIsNeg
;
52 pMultiSel
= new ScMarkArray
[MAXCOLCOUNT
];
53 for (SCCOL j
=0; j
<MAXCOLCOUNT
; j
++)
54 rData
.pMultiSel
[j
].CopyMarksTo( pMultiSel
[j
] );
58 ScMarkData
& ScMarkData::operator=(const ScMarkData
& rData
)
66 aMarkRange
= rData
.aMarkRange
;
67 aMultiRange
= rData
.aMultiRange
;
68 bMarked
= rData
.bMarked
;
69 bMultiMarked
= rData
.bMultiMarked
;
70 bMarking
= rData
.bMarking
;
71 bMarkIsNeg
= rData
.bMarkIsNeg
;
73 maTabMarked
= rData
.maTabMarked
;
77 pMultiSel
= new ScMarkArray
[MAXCOLCOUNT
];
78 for (SCCOL j
=0; j
<MAXCOLCOUNT
; j
++)
79 rData
.pMultiSel
[j
].CopyMarksTo( pMultiSel
[j
] );
85 ScMarkData::~ScMarkData()
90 void ScMarkData::ResetMark()
95 bMarked
= bMultiMarked
= false;
96 bMarking
= bMarkIsNeg
= false;
99 void ScMarkData::SetMarkArea( const ScRange
& rRange
)
102 aMarkRange
.Justify();
105 // Upon creation of a document ScFormatShell GetTextAttrState
106 // may query (default) attributes although no sheet is marked yet.
108 if ( !GetSelectCount() )
109 maTabMarked
.insert( aMarkRange
.aStart
.Tab() );
114 void ScMarkData::GetMarkArea( ScRange
& rRange
) const
116 rRange
= aMarkRange
; //TODO: inline ?
119 void ScMarkData::GetMultiMarkArea( ScRange
& rRange
) const
121 rRange
= aMultiRange
;
124 void ScMarkData::SetMultiMarkArea( const ScRange
& rRange
, bool bMark
)
128 pMultiSel
= new ScMarkArray
[MAXCOL
+1];
130 // if simple mark range is set, copy to multi marks
131 if ( bMarked
&& !bMarkIsNeg
)
134 SetMultiMarkArea( aMarkRange
, true );
138 SCCOL nStartCol
= rRange
.aStart
.Col();
139 SCROW nStartRow
= rRange
.aStart
.Row();
140 SCCOL nEndCol
= rRange
.aEnd
.Col();
141 SCROW nEndRow
= rRange
.aEnd
.Row();
142 PutInOrder( nStartRow
, nEndRow
);
143 PutInOrder( nStartCol
, nEndCol
);
146 for (nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
147 pMultiSel
[nCol
].SetMarkArea( nStartRow
, nEndRow
, bMark
);
149 if ( bMultiMarked
) // Update aMultiRange
151 if ( nStartCol
< aMultiRange
.aStart
.Col() )
152 aMultiRange
.aStart
.SetCol( nStartCol
);
153 if ( nStartRow
< aMultiRange
.aStart
.Row() )
154 aMultiRange
.aStart
.SetRow( nStartRow
);
155 if ( nEndCol
> aMultiRange
.aEnd
.Col() )
156 aMultiRange
.aEnd
.SetCol( nEndCol
);
157 if ( nEndRow
> aMultiRange
.aEnd
.Row() )
158 aMultiRange
.aEnd
.SetRow( nEndRow
);
162 aMultiRange
= rRange
; // new
167 void ScMarkData::SetAreaTab( SCTAB nTab
)
169 aMarkRange
.aStart
.SetTab(nTab
);
170 aMarkRange
.aEnd
.SetTab(nTab
);
171 aMultiRange
.aStart
.SetTab(nTab
);
172 aMultiRange
.aEnd
.SetTab(nTab
);
175 void ScMarkData::SelectTable( SCTAB nTab
, bool bNew
)
179 maTabMarked
.insert( nTab
);
183 maTabMarked
.erase( nTab
);
187 bool ScMarkData::GetTableSelect( SCTAB nTab
) const
189 return (maTabMarked
.find( nTab
) != maTabMarked
.end());
192 void ScMarkData::SelectOneTable( SCTAB nTab
)
195 maTabMarked
.insert( nTab
);
198 SCTAB
ScMarkData::GetSelectCount() const
200 return static_cast<SCTAB
> ( maTabMarked
.size() );
203 SCTAB
ScMarkData::GetFirstSelected() const
205 if (maTabMarked
.size() > 0)
206 return (*maTabMarked
.begin());
208 OSL_FAIL("GetFirstSelected: nothing selected");
212 SCTAB
ScMarkData::GetLastSelected() const
214 if (maTabMarked
.size() > 0)
215 return (*maTabMarked
.rbegin());
217 OSL_FAIL("GetLastSelected: nothing selected");
221 void ScMarkData::SetSelectedTabs(const MarkedTabsType
& rTabs
)
223 MarkedTabsType
aTabs(rTabs
.begin(), rTabs
.end());
224 maTabMarked
.swap(aTabs
);
227 void ScMarkData::MarkToMulti()
229 if ( bMarked
&& !bMarking
)
231 SetMultiMarkArea( aMarkRange
, !bMarkIsNeg
);
234 // check if all multi mark ranges have been removed
235 if ( bMarkIsNeg
&& !HasAnyMultiMarks() )
240 void ScMarkData::MarkToSimple()
245 if ( bMultiMarked
&& bMarked
)
246 MarkToMulti(); // may result in bMarked and bMultiMarked reset
250 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
252 ScRange aNew
= aMultiRange
;
255 SCCOL nStartCol
= aNew
.aStart
.Col();
256 SCCOL nEndCol
= aNew
.aEnd
.Col();
258 while ( nStartCol
< nEndCol
&& !pMultiSel
[nStartCol
].HasMarks() )
260 while ( nStartCol
< nEndCol
&& !pMultiSel
[nEndCol
].HasMarks() )
263 // Rows are only taken from MarkArray
264 SCROW nStartRow
, nEndRow
;
265 if ( pMultiSel
[nStartCol
].HasOneMark( nStartRow
, nEndRow
) )
268 SCROW nCmpStart
, nCmpEnd
;
269 for (SCCOL nCol
=nStartCol
+1; nCol
<=nEndCol
&& bOk
; nCol
++)
270 if ( !pMultiSel
[nCol
].HasOneMark( nCmpStart
, nCmpEnd
)
271 || nCmpStart
!= nStartRow
|| nCmpEnd
!= nEndRow
)
277 aNew
.aStart
.SetCol(nStartCol
);
278 aNew
.aStart
.SetRow(nStartRow
);
279 aNew
.aEnd
.SetCol(nEndCol
);
280 aNew
.aEnd
.SetRow(nEndRow
);
290 bool ScMarkData::IsCellMarked( SCCOL nCol
, SCROW nRow
, bool bNoSimple
) const
292 if ( bMarked
&& !bNoSimple
&& !bMarkIsNeg
)
293 if ( aMarkRange
.aStart
.Col() <= nCol
&& aMarkRange
.aEnd
.Col() >= nCol
&&
294 aMarkRange
.aStart
.Row() <= nRow
&& aMarkRange
.aEnd
.Row() >= nRow
)
299 //TODO: test here for negative Marking ?
301 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
302 return pMultiSel
[nCol
].GetMark( nRow
);
308 bool ScMarkData::IsColumnMarked( SCCOL nCol
) const
310 // bMarkIsNeg meanwhile also for columns heads
311 //TODO: GetMarkColumnRanges for completely marked column
313 if ( bMarked
&& !bMarkIsNeg
&&
314 aMarkRange
.aStart
.Col() <= nCol
&& aMarkRange
.aEnd
.Col() >= nCol
&&
315 aMarkRange
.aStart
.Row() == 0 && aMarkRange
.aEnd
.Row() == MAXROW
)
318 if ( bMultiMarked
&& pMultiSel
[nCol
].IsAllMarked(0,MAXROW
) )
324 bool ScMarkData::IsRowMarked( SCROW nRow
) const
326 // bMarkIsNeg meanwhile also for row heads
327 //TODO: GetMarkRowRanges for completely marked rows
329 if ( bMarked
&& !bMarkIsNeg
&&
330 aMarkRange
.aStart
.Col() == 0 && aMarkRange
.aEnd
.Col() == MAXCOL
&&
331 aMarkRange
.aStart
.Row() <= nRow
&& aMarkRange
.aEnd
.Row() >= nRow
)
336 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
337 for (SCCOL nCol
=0; nCol
<=MAXCOL
; nCol
++)
338 if (!pMultiSel
[nCol
].GetMark(nRow
))
346 void ScMarkData::MarkFromRangeList( const ScRangeList
& rList
, bool bReset
)
354 size_t nCount
= rList
.size();
355 if ( nCount
== 1 && !bMarked
&& !bMultiMarked
)
357 const ScRange
& rRange
= *rList
[ 0 ];
358 SetMarkArea( rRange
);
359 SelectTable( rRange
.aStart
.Tab(), true );
363 for (size_t i
=0; i
< nCount
; i
++)
365 const ScRange
& rRange
= *rList
[ i
];
366 SetMultiMarkArea( rRange
, true );
367 SelectTable( rRange
.aStart
.Tab(), true );
372 void ScMarkData::FillRangeListWithMarks( ScRangeList
* pList
, bool bClear
) const
380 //TODO: for muliple selected tables enter multiple ranges !!!
384 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
386 SCTAB nTab
= aMultiRange
.aStart
.Tab();
388 SCCOL nStartCol
= aMultiRange
.aStart
.Col();
389 SCCOL nEndCol
= aMultiRange
.aEnd
.Col();
390 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
; nCol
++)
392 if (pMultiSel
[nCol
].HasMarks())
394 // Feeding column-wise fragments to ScRangeList::Join() is a
395 // huge bottleneck, speed this up for multiple columns
396 // consisting of identical row sets by building a column span
397 // first. This is usually the case for filtered data, for
399 SCCOL nToCol
= nCol
+1;
400 for ( ; nToCol
<= nEndCol
; ++nToCol
)
402 if (!pMultiSel
[nCol
].HasEqualRowsMarked( pMultiSel
[nToCol
]))
406 ScRange
aRange( nCol
, 0, nTab
, nToCol
, 0, nTab
);
408 ScMarkArrayIter
aMarkIter( &pMultiSel
[nCol
] );
409 while ( aMarkIter
.Next( nTop
, nBottom
) )
411 aRange
.aStart
.SetRow( nTop
);
412 aRange
.aEnd
.SetRow( nBottom
);
413 pList
->Join( aRange
);
421 pList
->Append( aMarkRange
);
424 void ScMarkData::ExtendRangeListTables( ScRangeList
* pList
) const
429 ScRangeList
aOldList(*pList
);
430 pList
->RemoveAll(); //TODO: or skip the existing below
432 std::set
<SCTAB
>::const_iterator it
= maTabMarked
.begin();
433 for (; it
!= maTabMarked
.end(); ++it
)
434 for ( size_t i
=0, nCount
= aOldList
.size(); i
<nCount
; i
++)
436 ScRange aRange
= *aOldList
[ i
];
437 aRange
.aStart
.SetTab(*it
);
438 aRange
.aEnd
.SetTab(*it
);
439 pList
->Append( aRange
);
443 ScRangeList
ScMarkData::GetMarkedRanges() const
446 FillRangeListWithMarks(&aRet
, false);
450 std::vector
<sc::ColRowSpan
> ScMarkData::GetMarkedRowSpans() const
452 typedef mdds::flat_segment_tree
<SCCOLROW
, bool> SpansType
;
454 ScRangeList aRanges
= GetMarkedRanges();
455 SpansType
aSpans(0, MAXROW
+1, false);
456 SpansType::const_iterator itPos
= aSpans
.begin();
458 for (size_t i
= 0, n
= aRanges
.size(); i
< n
; ++i
)
460 const ScRange
& r
= *aRanges
[i
];
461 itPos
= aSpans
.insert(itPos
, r
.aStart
.Row(), r
.aEnd
.Row()+1, true).first
;
464 return sc::toSpanArray
<SCCOLROW
,sc::ColRowSpan
>(aSpans
);
467 std::vector
<sc::ColRowSpan
> ScMarkData::GetMarkedColSpans() const
469 typedef mdds::flat_segment_tree
<SCCOLROW
, bool> SpansType
;
471 ScRangeList aRanges
= GetMarkedRanges();
472 SpansType
aSpans(0, MAXCOL
+1, false);
473 SpansType::const_iterator itPos
= aSpans
.begin();
475 for (size_t i
= 0, n
= aRanges
.size(); i
< n
; ++i
)
477 const ScRange
& r
= *aRanges
[i
];
478 itPos
= aSpans
.insert(itPos
, r
.aStart
.Col(), r
.aEnd
.Col()+1, true).first
;
481 return sc::toSpanArray
<SCCOLROW
,sc::ColRowSpan
>(aSpans
);
484 bool ScMarkData::IsAllMarked( const ScRange
& rRange
) const
489 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
491 SCCOL nStartCol
= rRange
.aStart
.Col();
492 SCROW nStartRow
= rRange
.aStart
.Row();
493 SCCOL nEndCol
= rRange
.aEnd
.Col();
494 SCROW nEndRow
= rRange
.aEnd
.Row();
496 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
&& bOk
; nCol
++)
497 if ( !pMultiSel
[nCol
].IsAllMarked( nStartRow
, nEndRow
) )
503 SCsROW
ScMarkData::GetNextMarked( SCCOL nCol
, SCsROW nRow
, bool bUp
) const
508 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
510 return pMultiSel
[nCol
].GetNextMarked( nRow
, bUp
);
513 bool ScMarkData::HasMultiMarks( SCCOL nCol
) const
518 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
520 return pMultiSel
[nCol
].HasMarks();
523 bool ScMarkData::HasAnyMultiMarks() const
528 OSL_ENSURE(pMultiSel
, "bMultiMarked, but pMultiSel == 0");
530 for (SCCOL nCol
=0; nCol
<=MAXCOL
; nCol
++)
531 if ( pMultiSel
[nCol
].HasMarks() )
537 void ScMarkData::InsertTab( SCTAB nTab
)
539 std::set
<SCTAB
> tabMarked(maTabMarked
.begin(), maTabMarked
.upper_bound(nTab
));
540 std::set
<SCTAB
>::iterator it
= maTabMarked
.upper_bound(nTab
);
541 for (; it
!= maTabMarked
.end(); ++it
)
542 tabMarked
.insert(*it
+ 1);
543 maTabMarked
.swap(tabMarked
);
546 void ScMarkData::DeleteTab( SCTAB nTab
)
548 std::set
<SCTAB
> tabMarked(maTabMarked
.begin(), maTabMarked
.find(nTab
));
549 tabMarked
.erase( nTab
);
550 std::set
<SCTAB
>::iterator it
= maTabMarked
.find(nTab
);
551 for (; it
!= maTabMarked
.end(); ++it
)
552 tabMarked
.insert(*it
+ 1);
553 maTabMarked
.swap(tabMarked
);
557 ScMarkData::iterator
ScMarkData::begin()
559 return maTabMarked
.begin();
562 ScMarkData::iterator
ScMarkData::end()
564 return maTabMarked
.end();
567 ScMarkData::const_iterator
ScMarkData::begin() const
569 return maTabMarked
.begin();
572 ScMarkData::const_iterator
ScMarkData::end() const
574 return maTabMarked
.end();
577 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */