fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / markdata.cxx
blob55537b23f12cb8680cb49e5bf761d52c10e1905e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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() :
33 maTabMarked(),
34 pMultiSel( NULL )
36 ResetMark();
39 ScMarkData::ScMarkData(const ScMarkData& rData) :
40 maTabMarked( rData.maTabMarked ),
41 aMarkRange( rData.aMarkRange ),
42 aMultiRange( rData.aMultiRange ),
43 pMultiSel( NULL )
45 bMarked = rData.bMarked;
46 bMultiMarked = rData.bMultiMarked;
47 bMarking = rData.bMarking;
48 bMarkIsNeg = rData.bMarkIsNeg;
50 if (rData.pMultiSel)
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)
60 if ( &rData == this )
61 return *this;
63 delete[] pMultiSel;
64 pMultiSel = NULL;
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;
75 if (rData.pMultiSel)
77 pMultiSel = new ScMarkArray[MAXCOLCOUNT];
78 for (SCCOL j=0; j<MAXCOLCOUNT; j++)
79 rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
82 return *this;
85 ScMarkData::~ScMarkData()
87 delete[] pMultiSel;
90 void ScMarkData::ResetMark()
92 delete[] pMultiSel;
93 pMultiSel = NULL;
95 bMarked = bMultiMarked = false;
96 bMarking = bMarkIsNeg = false;
99 void ScMarkData::SetMarkArea( const ScRange& rRange )
101 aMarkRange = rRange;
102 aMarkRange.Justify();
103 if ( !bMarked )
105 // Upon creation of a document ScFormatShell GetTextAttrState
106 // may query (default) attributes although no sheet is marked yet.
107 // => mark that one.
108 if ( !GetSelectCount() )
109 maTabMarked.insert( aMarkRange.aStart.Tab() );
110 bMarked = true;
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 )
126 if (!pMultiSel)
128 pMultiSel = new ScMarkArray[MAXCOL+1];
130 // if simple mark range is set, copy to multi marks
131 if ( bMarked && !bMarkIsNeg )
133 bMarked = false;
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 );
145 SCCOL nCol;
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 );
160 else
162 aMultiRange = rRange; // new
163 bMultiMarked = true;
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 )
177 if ( bNew )
179 maTabMarked.insert( nTab );
181 else
183 maTabMarked.erase( nTab );
187 bool ScMarkData::GetTableSelect( SCTAB nTab ) const
189 return (maTabMarked.find( nTab ) != maTabMarked.end());
192 void ScMarkData::SelectOneTable( SCTAB nTab )
194 maTabMarked.clear();
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");
209 return 0;
212 SCTAB ScMarkData::GetLastSelected() const
214 if (maTabMarked.size() > 0)
215 return (*maTabMarked.rbegin());
217 OSL_FAIL("GetLastSelected: nothing selected");
218 return 0;
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 );
232 bMarked = false;
234 // check if all multi mark ranges have been removed
235 if ( bMarkIsNeg && !HasAnyMultiMarks() )
236 ResetMark();
240 void ScMarkData::MarkToSimple()
242 if ( bMarking )
243 return;
245 if ( bMultiMarked && bMarked )
246 MarkToMulti(); // may result in bMarked and bMultiMarked reset
248 if ( bMultiMarked )
250 OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
252 ScRange aNew = aMultiRange;
254 bool bOk = false;
255 SCCOL nStartCol = aNew.aStart.Col();
256 SCCOL nEndCol = aNew.aEnd.Col();
258 while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() )
259 ++nStartCol;
260 while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() )
261 --nEndCol;
263 // Rows are only taken from MarkArray
264 SCROW nStartRow, nEndRow;
265 if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) )
267 bOk = true;
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 )
272 bOk = false;
275 if (bOk)
277 aNew.aStart.SetCol(nStartCol);
278 aNew.aStart.SetRow(nStartRow);
279 aNew.aEnd.SetCol(nEndCol);
280 aNew.aEnd.SetRow(nEndRow);
282 ResetMark();
283 aMarkRange = aNew;
284 bMarked = true;
285 bMarkIsNeg = false;
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 )
295 return true;
297 if (bMultiMarked)
299 //TODO: test here for negative Marking ?
301 OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
302 return pMultiSel[nCol].GetMark( nRow );
305 return false;
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 )
316 return true;
318 if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) )
319 return true;
321 return false;
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 )
332 return true;
334 if ( bMultiMarked )
336 OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
337 for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
338 if (!pMultiSel[nCol].GetMark(nRow))
339 return false;
340 return true;
343 return false;
346 void ScMarkData::MarkFromRangeList( const ScRangeList& rList, bool bReset )
348 if (bReset)
350 maTabMarked.clear();
351 ResetMark();
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 );
361 else
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
374 if (!pList)
375 return;
377 if (bClear)
378 pList->RemoveAll();
380 //TODO: for muliple selected tables enter multiple ranges !!!
382 if ( bMultiMarked )
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
398 // example.
399 SCCOL nToCol = nCol+1;
400 for ( ; nToCol <= nEndCol; ++nToCol)
402 if (!pMultiSel[nCol].HasEqualRowsMarked( pMultiSel[nToCol]))
403 break;
405 --nToCol;
406 ScRange aRange( nCol, 0, nTab, nToCol, 0, nTab );
407 SCROW nTop, nBottom;
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 );
415 nCol = nToCol;
420 if ( bMarked )
421 pList->Append( aMarkRange );
424 void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const
426 if (!pList)
427 return;
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
445 ScRangeList aRet;
446 FillRangeListWithMarks(&aRet, false);
447 return aRet;
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
486 if ( !bMultiMarked )
487 return false;
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();
495 bool bOk = true;
496 for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
497 if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) )
498 bOk = false;
500 return bOk;
503 SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, bool bUp ) const
505 if ( !bMultiMarked )
506 return nRow;
508 OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
510 return pMultiSel[nCol].GetNextMarked( nRow, bUp );
513 bool ScMarkData::HasMultiMarks( SCCOL nCol ) const
515 if ( !bMultiMarked )
516 return false;
518 OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
520 return pMultiSel[nCol].HasMarks();
523 bool ScMarkData::HasAnyMultiMarks() const
525 if ( !bMultiMarked )
526 return false;
528 OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
530 for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
531 if ( pMultiSel[nCol].HasMarks() )
532 return true;
534 return false; // no
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);
556 //iterators
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: */