Line data Source code
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 "markdata.hxx"
21 : #include "markarr.hxx"
22 : #include "rangelst.hxx"
23 : #include <columnspanset.hxx>
24 : #include <fstalgorithm.hxx>
25 :
26 : #include <osl/diagnose.h>
27 :
28 : #include <mdds/flat_segment_tree.hpp>
29 :
30 : // STATIC DATA -----------------------------------------------------------
31 :
32 10150 : ScMarkData::ScMarkData() :
33 : maTabMarked(),
34 10150 : pMultiSel( NULL )
35 : {
36 10150 : ResetMark();
37 10150 : }
38 :
39 2442732 : ScMarkData::ScMarkData(const ScMarkData& rData) :
40 : maTabMarked( rData.maTabMarked ),
41 : aMarkRange( rData.aMarkRange ),
42 : aMultiRange( rData.aMultiRange ),
43 2442732 : pMultiSel( NULL )
44 : {
45 2442732 : bMarked = rData.bMarked;
46 2442732 : bMultiMarked = rData.bMultiMarked;
47 2442732 : bMarking = rData.bMarking;
48 2442732 : bMarkIsNeg = rData.bMarkIsNeg;
49 :
50 2442732 : if (rData.pMultiSel)
51 : {
52 229 : pMultiSel = new ScMarkArray[MAXCOLCOUNT];
53 234725 : for (SCCOL j=0; j<MAXCOLCOUNT; j++)
54 234496 : rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
55 : }
56 2442732 : }
57 :
58 36 : ScMarkData& ScMarkData::operator=(const ScMarkData& rData)
59 : {
60 36 : if ( &rData == this )
61 0 : return *this;
62 :
63 36 : delete[] pMultiSel;
64 36 : pMultiSel = NULL;
65 :
66 36 : aMarkRange = rData.aMarkRange;
67 36 : aMultiRange = rData.aMultiRange;
68 36 : bMarked = rData.bMarked;
69 36 : bMultiMarked = rData.bMultiMarked;
70 36 : bMarking = rData.bMarking;
71 36 : bMarkIsNeg = rData.bMarkIsNeg;
72 :
73 36 : maTabMarked = rData.maTabMarked;
74 :
75 36 : if (rData.pMultiSel)
76 : {
77 0 : pMultiSel = new ScMarkArray[MAXCOLCOUNT];
78 0 : for (SCCOL j=0; j<MAXCOLCOUNT; j++)
79 0 : rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
80 : }
81 :
82 36 : return *this;
83 : }
84 :
85 4905692 : ScMarkData::~ScMarkData()
86 : {
87 2452846 : delete[] pMultiSel;
88 2452846 : }
89 :
90 10386 : void ScMarkData::ResetMark()
91 : {
92 10386 : delete[] pMultiSel;
93 10386 : pMultiSel = NULL;
94 :
95 10386 : bMarked = bMultiMarked = false;
96 10386 : bMarking = bMarkIsNeg = false;
97 10386 : }
98 :
99 16976 : void ScMarkData::SetMarkArea( const ScRange& rRange )
100 : {
101 16976 : aMarkRange = rRange;
102 16976 : aMarkRange.Justify();
103 16976 : if ( !bMarked )
104 : {
105 : // Upon creation of a document ScFormatShell GetTextAttrState
106 : // may query (default) attributes although no sheet is marked yet.
107 : // => mark that one.
108 16950 : if ( !GetSelectCount() )
109 6714 : maTabMarked.insert( aMarkRange.aStart.Tab() );
110 16950 : bMarked = true;
111 : }
112 16976 : }
113 :
114 25475 : void ScMarkData::GetMarkArea( ScRange& rRange ) const
115 : {
116 25475 : rRange = aMarkRange; //TODO: inline ?
117 25475 : }
118 :
119 979 : void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const
120 : {
121 979 : rRange = aMultiRange;
122 979 : }
123 :
124 4511 : void ScMarkData::SetMultiMarkArea( const ScRange& rRange, bool bMark )
125 : {
126 4511 : if (!pMultiSel)
127 : {
128 908 : pMultiSel = new ScMarkArray[MAXCOL+1];
129 :
130 : // if simple mark range is set, copy to multi marks
131 908 : if ( bMarked && !bMarkIsNeg )
132 : {
133 531 : bMarked = false;
134 531 : SetMultiMarkArea( aMarkRange, true );
135 : }
136 : }
137 :
138 4511 : SCCOL nStartCol = rRange.aStart.Col();
139 4511 : SCROW nStartRow = rRange.aStart.Row();
140 4511 : SCCOL nEndCol = rRange.aEnd.Col();
141 4511 : SCROW nEndRow = rRange.aEnd.Row();
142 4511 : PutInOrder( nStartRow, nEndRow );
143 4511 : PutInOrder( nStartCol, nEndCol );
144 :
145 : SCCOL nCol;
146 192483 : for (nCol=nStartCol; nCol<=nEndCol; nCol++)
147 187972 : pMultiSel[nCol].SetMarkArea( nStartRow, nEndRow, bMark );
148 :
149 4511 : if ( bMultiMarked ) // Update aMultiRange
150 : {
151 3603 : if ( nStartCol < aMultiRange.aStart.Col() )
152 114 : aMultiRange.aStart.SetCol( nStartCol );
153 3603 : if ( nStartRow < aMultiRange.aStart.Row() )
154 11 : aMultiRange.aStart.SetRow( nStartRow );
155 3603 : if ( nEndCol > aMultiRange.aEnd.Col() )
156 350 : aMultiRange.aEnd.SetCol( nEndCol );
157 3603 : if ( nEndRow > aMultiRange.aEnd.Row() )
158 1553 : aMultiRange.aEnd.SetRow( nEndRow );
159 : }
160 : else
161 : {
162 908 : aMultiRange = rRange; // new
163 908 : bMultiMarked = true;
164 : }
165 4511 : }
166 :
167 1 : void ScMarkData::SetAreaTab( SCTAB nTab )
168 : {
169 1 : aMarkRange.aStart.SetTab(nTab);
170 1 : aMarkRange.aEnd.SetTab(nTab);
171 1 : aMultiRange.aStart.SetTab(nTab);
172 1 : aMultiRange.aEnd.SetTab(nTab);
173 1 : }
174 :
175 10359 : void ScMarkData::SelectTable( SCTAB nTab, bool bNew )
176 : {
177 10359 : if ( bNew )
178 : {
179 10264 : maTabMarked.insert( nTab );
180 : }
181 : else
182 : {
183 95 : maTabMarked.erase( nTab );
184 : }
185 10359 : }
186 :
187 6441 : bool ScMarkData::GetTableSelect( SCTAB nTab ) const
188 : {
189 6441 : return (maTabMarked.find( nTab ) != maTabMarked.end());
190 : }
191 :
192 655 : void ScMarkData::SelectOneTable( SCTAB nTab )
193 : {
194 655 : maTabMarked.clear();
195 655 : maTabMarked.insert( nTab );
196 655 : }
197 :
198 22819 : SCTAB ScMarkData::GetSelectCount() const
199 : {
200 22819 : return static_cast<SCTAB> ( maTabMarked.size() );
201 : }
202 :
203 128 : SCTAB ScMarkData::GetFirstSelected() const
204 : {
205 128 : if (maTabMarked.size() > 0)
206 128 : return (*maTabMarked.begin());
207 :
208 : OSL_FAIL("GetFirstSelected: nothing selected");
209 0 : return 0;
210 : }
211 :
212 41 : SCTAB ScMarkData::GetLastSelected() const
213 : {
214 41 : if (maTabMarked.size() > 0)
215 41 : return (*maTabMarked.rbegin());
216 :
217 : OSL_FAIL("GetLastSelected: nothing selected");
218 0 : return 0;
219 : }
220 :
221 0 : void ScMarkData::SetSelectedTabs(const MarkedTabsType& rTabs)
222 : {
223 0 : MarkedTabsType aTabs(rTabs.begin(), rTabs.end());
224 0 : maTabMarked.swap(aTabs);
225 0 : }
226 :
227 3045 : void ScMarkData::MarkToMulti()
228 : {
229 3045 : if ( bMarked && !bMarking )
230 : {
231 510 : SetMultiMarkArea( aMarkRange, !bMarkIsNeg );
232 510 : bMarked = false;
233 :
234 : // check if all multi mark ranges have been removed
235 510 : if ( bMarkIsNeg && !HasAnyMultiMarks() )
236 0 : ResetMark();
237 : }
238 3045 : }
239 :
240 50 : void ScMarkData::MarkToSimple()
241 : {
242 50 : if ( bMarking )
243 50 : return;
244 :
245 50 : if ( bMultiMarked && bMarked )
246 0 : MarkToMulti(); // may result in bMarked and bMultiMarked reset
247 :
248 50 : if ( bMultiMarked )
249 : {
250 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
251 :
252 47 : ScRange aNew = aMultiRange;
253 :
254 47 : bool bOk = false;
255 47 : SCCOL nStartCol = aNew.aStart.Col();
256 47 : SCCOL nEndCol = aNew.aEnd.Col();
257 :
258 94 : while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() )
259 0 : ++nStartCol;
260 94 : while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() )
261 0 : --nEndCol;
262 :
263 : // Rows are only taken from MarkArray
264 : SCROW nStartRow, nEndRow;
265 47 : if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) )
266 : {
267 47 : bOk = true;
268 : SCROW nCmpStart, nCmpEnd;
269 131 : for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++)
270 168 : if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd )
271 84 : || nCmpStart != nStartRow || nCmpEnd != nEndRow )
272 38 : bOk = false;
273 : }
274 :
275 47 : if (bOk)
276 : {
277 9 : aNew.aStart.SetCol(nStartCol);
278 9 : aNew.aStart.SetRow(nStartRow);
279 9 : aNew.aEnd.SetCol(nEndCol);
280 9 : aNew.aEnd.SetRow(nEndRow);
281 :
282 9 : ResetMark();
283 9 : aMarkRange = aNew;
284 9 : bMarked = true;
285 9 : bMarkIsNeg = false;
286 : }
287 : }
288 : }
289 :
290 6830 : bool ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, bool bNoSimple ) const
291 : {
292 6830 : if ( bMarked && !bNoSimple && !bMarkIsNeg )
293 11996 : if ( aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
294 6376 : aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
295 836 : return true;
296 :
297 5994 : if (bMultiMarked)
298 : {
299 : //TODO: test here for negative Marking ?
300 :
301 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
302 2710 : return pMultiSel[nCol].GetMark( nRow );
303 : }
304 :
305 3284 : return false;
306 : }
307 :
308 0 : bool ScMarkData::IsColumnMarked( SCCOL nCol ) const
309 : {
310 : // bMarkIsNeg meanwhile also for columns heads
311 : //TODO: GetMarkColumnRanges for completely marked column
312 :
313 0 : if ( bMarked && !bMarkIsNeg &&
314 0 : aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
315 0 : aMarkRange.aStart.Row() == 0 && aMarkRange.aEnd.Row() == MAXROW )
316 0 : return true;
317 :
318 0 : if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) )
319 0 : return true;
320 :
321 0 : return false;
322 : }
323 :
324 0 : bool ScMarkData::IsRowMarked( SCROW nRow ) const
325 : {
326 : // bMarkIsNeg meanwhile also for row heads
327 : //TODO: GetMarkRowRanges for completely marked rows
328 :
329 0 : if ( bMarked && !bMarkIsNeg &&
330 0 : aMarkRange.aStart.Col() == 0 && aMarkRange.aEnd.Col() == MAXCOL &&
331 0 : aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
332 0 : return true;
333 :
334 0 : if ( bMultiMarked )
335 : {
336 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
337 0 : for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
338 0 : if (!pMultiSel[nCol].GetMark(nRow))
339 0 : return false;
340 0 : return true;
341 : }
342 :
343 0 : return false;
344 : }
345 :
346 6821 : void ScMarkData::MarkFromRangeList( const ScRangeList& rList, bool bReset )
347 : {
348 6821 : if (bReset)
349 : {
350 4 : maTabMarked.clear();
351 4 : ResetMark();
352 : }
353 :
354 6821 : size_t nCount = rList.size();
355 6821 : if ( nCount == 1 && !bMarked && !bMultiMarked )
356 : {
357 6472 : const ScRange& rRange = *rList[ 0 ];
358 6472 : SetMarkArea( rRange );
359 6472 : SelectTable( rRange.aStart.Tab(), true );
360 : }
361 : else
362 : {
363 3419 : for (size_t i=0; i < nCount; i++)
364 : {
365 3070 : const ScRange& rRange = *rList[ i ];
366 3070 : SetMultiMarkArea( rRange, true );
367 3070 : SelectTable( rRange.aStart.Tab(), true );
368 : }
369 : }
370 6821 : }
371 :
372 978 : void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, bool bClear ) const
373 : {
374 978 : if (!pList)
375 978 : return;
376 :
377 978 : if (bClear)
378 39 : pList->RemoveAll();
379 :
380 : //TODO: for muliple selected tables enter multiple ranges !!!
381 :
382 978 : if ( bMultiMarked )
383 : {
384 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
385 :
386 699 : SCTAB nTab = aMultiRange.aStart.Tab();
387 :
388 699 : SCCOL nStartCol = aMultiRange.aStart.Col();
389 699 : SCCOL nEndCol = aMultiRange.aEnd.Col();
390 16151 : for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
391 : {
392 15452 : if (pMultiSel[nCol].HasMarks())
393 : {
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 1959 : SCCOL nToCol = nCol+1;
400 5387 : for ( ; nToCol <= nEndCol; ++nToCol)
401 : {
402 4712 : if (!pMultiSel[nCol].HasEqualRowsMarked( pMultiSel[nToCol]))
403 1284 : break;
404 : }
405 1959 : --nToCol;
406 1959 : ScRange aRange( nCol, 0, nTab, nToCol, 0, nTab );
407 : SCROW nTop, nBottom;
408 1959 : ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
409 5891 : while ( aMarkIter.Next( nTop, nBottom ) )
410 : {
411 1973 : aRange.aStart.SetRow( nTop );
412 1973 : aRange.aEnd.SetRow( nBottom );
413 1973 : pList->Join( aRange );
414 : }
415 1959 : nCol = nToCol;
416 : }
417 : }
418 : }
419 :
420 978 : if ( bMarked )
421 243 : pList->Append( aMarkRange );
422 : }
423 :
424 0 : void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const
425 : {
426 0 : if (!pList)
427 0 : return;
428 :
429 0 : ScRangeList aOldList(*pList);
430 0 : pList->RemoveAll(); //TODO: or skip the existing below
431 :
432 0 : std::set<SCTAB>::const_iterator it = maTabMarked.begin();
433 0 : for (; it != maTabMarked.end(); ++it)
434 0 : for ( size_t i=0, nCount = aOldList.size(); i<nCount; i++)
435 : {
436 0 : ScRange aRange = *aOldList[ i ];
437 0 : aRange.aStart.SetTab(*it);
438 0 : aRange.aEnd.SetTab(*it);
439 0 : pList->Append( aRange );
440 0 : }
441 : }
442 :
443 749 : ScRangeList ScMarkData::GetMarkedRanges() const
444 : {
445 749 : ScRangeList aRet;
446 749 : FillRangeListWithMarks(&aRet, false);
447 749 : return aRet;
448 : }
449 :
450 21 : std::vector<sc::ColRowSpan> ScMarkData::GetMarkedRowSpans() const
451 : {
452 : typedef mdds::flat_segment_tree<SCCOLROW, bool> SpansType;
453 :
454 21 : ScRangeList aRanges = GetMarkedRanges();
455 42 : SpansType aSpans(0, MAXROW+1, false);
456 21 : SpansType::const_iterator itPos = aSpans.begin();
457 :
458 45 : for (size_t i = 0, n = aRanges.size(); i < n; ++i)
459 : {
460 24 : const ScRange& r = *aRanges[i];
461 24 : itPos = aSpans.insert(itPos, r.aStart.Row(), r.aEnd.Row()+1, true).first;
462 : }
463 :
464 42 : return sc::toSpanArray<SCCOLROW,sc::ColRowSpan>(aSpans);
465 : }
466 :
467 65 : std::vector<sc::ColRowSpan> ScMarkData::GetMarkedColSpans() const
468 : {
469 : typedef mdds::flat_segment_tree<SCCOLROW, bool> SpansType;
470 :
471 65 : ScRangeList aRanges = GetMarkedRanges();
472 130 : SpansType aSpans(0, MAXCOL+1, false);
473 65 : SpansType::const_iterator itPos = aSpans.begin();
474 :
475 285 : for (size_t i = 0, n = aRanges.size(); i < n; ++i)
476 : {
477 220 : const ScRange& r = *aRanges[i];
478 220 : itPos = aSpans.insert(itPos, r.aStart.Col(), r.aEnd.Col()+1, true).first;
479 : }
480 :
481 130 : return sc::toSpanArray<SCCOLROW,sc::ColRowSpan>(aSpans);
482 : }
483 :
484 33 : bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
485 : {
486 33 : if ( !bMultiMarked )
487 19 : return false;
488 :
489 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
490 :
491 14 : SCCOL nStartCol = rRange.aStart.Col();
492 14 : SCROW nStartRow = rRange.aStart.Row();
493 14 : SCCOL nEndCol = rRange.aEnd.Col();
494 14 : SCROW nEndRow = rRange.aEnd.Row();
495 14 : bool bOk = true;
496 50 : for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
497 36 : if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) )
498 0 : bOk = false;
499 :
500 14 : return bOk;
501 : }
502 :
503 0 : SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, bool bUp ) const
504 : {
505 0 : if ( !bMultiMarked )
506 0 : return nRow;
507 :
508 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
509 :
510 0 : return pMultiSel[nCol].GetNextMarked( nRow, bUp );
511 : }
512 :
513 22528 : bool ScMarkData::HasMultiMarks( SCCOL nCol ) const
514 : {
515 22528 : if ( !bMultiMarked )
516 0 : return false;
517 :
518 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
519 :
520 22528 : return pMultiSel[nCol].HasMarks();
521 : }
522 :
523 0 : bool ScMarkData::HasAnyMultiMarks() const
524 : {
525 0 : if ( !bMultiMarked )
526 0 : return false;
527 :
528 : OSL_ENSURE(pMultiSel, "bMultiMarked, but pMultiSel == 0");
529 :
530 0 : for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
531 0 : if ( pMultiSel[nCol].HasMarks() )
532 0 : return true;
533 :
534 0 : return false; // no
535 : }
536 :
537 46 : void ScMarkData::InsertTab( SCTAB nTab )
538 : {
539 46 : std::set<SCTAB> tabMarked(maTabMarked.begin(), maTabMarked.upper_bound(nTab));
540 46 : std::set<SCTAB>::iterator it = maTabMarked.upper_bound(nTab);
541 55 : for (; it != maTabMarked.end(); ++it)
542 9 : tabMarked.insert(*it + 1);
543 46 : maTabMarked.swap(tabMarked);
544 46 : }
545 :
546 18 : void ScMarkData::DeleteTab( SCTAB nTab )
547 : {
548 18 : std::set<SCTAB> tabMarked(maTabMarked.begin(), maTabMarked.find(nTab));
549 18 : tabMarked.erase( nTab );
550 18 : std::set<SCTAB>::iterator it = maTabMarked.find(nTab);
551 35 : for (; it != maTabMarked.end(); ++it)
552 17 : tabMarked.insert(*it + 1);
553 18 : maTabMarked.swap(tabMarked);
554 18 : }
555 :
556 : //iterators
557 577 : ScMarkData::iterator ScMarkData::begin()
558 : {
559 577 : return maTabMarked.begin();
560 : }
561 :
562 417 : ScMarkData::iterator ScMarkData::end()
563 : {
564 417 : return maTabMarked.end();
565 : }
566 :
567 21596 : ScMarkData::const_iterator ScMarkData::begin() const
568 : {
569 21596 : return maTabMarked.begin();
570 : }
571 :
572 21540 : ScMarkData::const_iterator ScMarkData::end() const
573 : {
574 21540 : return maTabMarked.end();
575 156 : }
576 :
577 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|