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 <olinetab.hxx>
21 #include <address.hxx>
22 #include <table.hxx>
23
24 #include <osl/diagnose.h>
25
ScOutlineEntry(SCCOLROW nNewStart,SCCOLROW nNewSize,bool bNewHidden)26 ScOutlineEntry::ScOutlineEntry( SCCOLROW nNewStart, SCCOLROW nNewSize, bool bNewHidden ) :
27 nStart ( nNewStart ),
28 nSize ( nNewSize ),
29 bHidden ( bNewHidden ),
30 bVisible( true )
31 {
32 }
33
ScOutlineEntry(const ScOutlineEntry & rEntry)34 ScOutlineEntry::ScOutlineEntry( const ScOutlineEntry& rEntry ) :
35 nStart ( rEntry.nStart ),
36 nSize ( rEntry.nSize ),
37 bHidden ( rEntry.bHidden ),
38 bVisible( rEntry.bVisible )
39 {
40 }
41
GetEnd() const42 SCCOLROW ScOutlineEntry::GetEnd() const
43 {
44 return nStart+nSize-1;
45 }
46
Move(SCCOLROW nDelta)47 void ScOutlineEntry::Move( SCCOLROW nDelta )
48 {
49 SCCOLROW nNewPos = nStart + nDelta;
50 if (nNewPos<0)
51 {
52 OSL_FAIL("OutlineEntry < 0");
53 nNewPos = 0;
54 }
55 nStart = nNewPos;
56 }
57
SetSize(SCSIZE nNewSize)58 void ScOutlineEntry::SetSize( SCSIZE nNewSize )
59 {
60 if (nNewSize>0)
61 nSize = nNewSize;
62 else
63 {
64 OSL_FAIL("ScOutlineEntry Size == 0");
65 }
66 }
67
SetPosSize(SCCOLROW nNewPos,SCSIZE nNewSize)68 void ScOutlineEntry::SetPosSize( SCCOLROW nNewPos, SCSIZE nNewSize )
69 {
70 nStart = nNewPos;
71 SetSize( nNewSize );
72 }
73
SetHidden(bool bNewHidden)74 void ScOutlineEntry::SetHidden( bool bNewHidden )
75 {
76 bHidden = bNewHidden;
77 }
78
SetVisible(bool bNewVisible)79 void ScOutlineEntry::SetVisible( bool bNewVisible )
80 {
81 bVisible = bNewVisible;
82 }
83
dumpAsString() const84 OString ScOutlineEntry::dumpAsString() const
85 {
86 const char* const pSep = ":";
87 return OString::number(nStart) + pSep + OString::number(nSize) +
88 pSep + (bHidden ? "1" : "0") + pSep + (bVisible ? "1" : "0");
89 }
90
ScOutlineCollection()91 ScOutlineCollection::ScOutlineCollection() {}
92
size() const93 size_t ScOutlineCollection::size() const
94 {
95 return m_Entries.size();
96 }
97
clear()98 void ScOutlineCollection::clear()
99 {
100 m_Entries.clear();
101 }
102
insert(ScOutlineEntry const & rEntry)103 void ScOutlineCollection::insert(ScOutlineEntry const& rEntry)
104 {
105 SCCOLROW nStart = rEntry.GetStart();
106 m_Entries.insert(std::make_pair(nStart, rEntry));
107 }
108
begin()109 ScOutlineCollection::iterator ScOutlineCollection::begin()
110 {
111 return m_Entries.begin();
112 }
113
end()114 ScOutlineCollection::iterator ScOutlineCollection::end()
115 {
116 return m_Entries.end();
117 }
118
begin() const119 ScOutlineCollection::const_iterator ScOutlineCollection::begin() const
120 {
121 return m_Entries.begin();
122 }
123
end() const124 ScOutlineCollection::const_iterator ScOutlineCollection::end() const
125 {
126 return m_Entries.end();
127 }
128
erase(const iterator & pos)129 ScOutlineCollection::iterator ScOutlineCollection::erase(const iterator& pos)
130 {
131 return m_Entries.erase(pos);
132 }
133
empty() const134 bool ScOutlineCollection::empty() const
135 {
136 return m_Entries.empty();
137 }
138
FindStart(SCCOLROW nMinStart)139 ScOutlineCollection::iterator ScOutlineCollection::FindStart(SCCOLROW nMinStart)
140 {
141 return m_Entries.lower_bound(nMinStart);
142 }
143
dumpAsString() const144 OString ScOutlineCollection::dumpAsString() const
145 {
146 OString aOutput;
147 const char* const pGroupEntrySep = ",";
148 for (const auto& rKeyValuePair : m_Entries)
149 aOutput += rKeyValuePair.second.dumpAsString() + pGroupEntrySep;
150
151 return aOutput;
152 }
153
ScOutlineArray()154 ScOutlineArray::ScOutlineArray() :
155 nDepth(0) {}
156
ScOutlineArray(const ScOutlineArray & rArray)157 ScOutlineArray::ScOutlineArray( const ScOutlineArray& rArray ) :
158 nDepth( rArray.nDepth )
159 {
160 for (size_t nLevel = 0; nLevel < nDepth; ++nLevel)
161 {
162 const ScOutlineCollection& rColl = rArray.aCollections[nLevel];
163 for (const auto& rEntry : rColl)
164 {
165 const ScOutlineEntry *const pEntry = &rEntry.second;
166 aCollections[nLevel].insert(*pEntry);
167 }
168 }
169 }
170
FindEntry(SCCOLROW nSearchPos,size_t & rFindLevel,size_t & rFindIndex,size_t nMaxLevel)171 void ScOutlineArray::FindEntry(
172 SCCOLROW nSearchPos, size_t& rFindLevel, size_t& rFindIndex,
173 size_t nMaxLevel )
174 {
175 rFindLevel = rFindIndex = 0;
176
177 if (nMaxLevel > nDepth)
178 nMaxLevel = nDepth;
179
180 for (size_t nLevel = 0; nLevel < nMaxLevel; ++nLevel) //TODO: Search backwards?
181 {
182 ScOutlineCollection* pCollect = &aCollections[nLevel];
183 size_t nIndex = 0;
184 for (auto& rEntry : *pCollect)
185 {
186 ScOutlineEntry *const pEntry = &rEntry.second;
187 if (pEntry->GetStart() <= nSearchPos && pEntry->GetEnd() >= nSearchPos)
188 {
189 rFindLevel = nLevel + 1; // Next Level (for insertion)
190 rFindIndex = nIndex;
191 }
192 ++nIndex;
193 }
194 }
195 }
196
Insert(SCCOLROW nStartCol,SCCOLROW nEndCol,bool & rSizeChanged,bool bHidden)197 bool ScOutlineArray::Insert(
198 SCCOLROW nStartCol, SCCOLROW nEndCol, bool& rSizeChanged, bool bHidden )
199 {
200 rSizeChanged = false;
201
202 size_t nStartLevel, nEndLevel, nStartIndex, nEndIndex;
203 bool bFound = false;
204
205 bool bCont;
206 sal_uInt16 nFindMax;
207 FindEntry( nStartCol, nStartLevel, nStartIndex ); // nLevel = new Level (old+1)
208 FindEntry( nEndCol, nEndLevel, nEndIndex );
209 nFindMax = std::max(nStartLevel,nEndLevel);
210 do
211 {
212 bCont = false;
213
214 if (nStartLevel == nEndLevel && nStartIndex == nEndIndex && nStartLevel < SC_OL_MAXDEPTH)
215 bFound = true;
216
217 if (!bFound && nFindMax>0)
218 {
219 --nFindMax;
220 if (nStartLevel)
221 {
222 ScOutlineCollection::const_iterator it = aCollections[nStartLevel-1].begin();
223 std::advance(it, nStartIndex);
224 if (it->second.GetStart() == nStartCol)
225 FindEntry(nStartCol, nStartLevel, nStartIndex, nFindMax);
226 }
227
228 if (nEndLevel)
229 {
230 ScOutlineCollection::const_iterator it = aCollections[nEndLevel-1].begin();
231 std::advance(it, nEndIndex);
232 if (it->second.GetEnd() == nEndCol)
233 FindEntry(nEndCol, nEndLevel, nEndIndex, nFindMax);
234 }
235 bCont = true;
236 }
237 }
238 while ( !bFound && bCont );
239
240 if (!bFound)
241 return false;
242
243 size_t nLevel = nStartLevel;
244
245 // Move the ones underneath
246 bool bNeedSize = false;
247 if (nDepth > 0)
248 {
249 for (size_t nMoveLevel = nDepth-1; nMoveLevel >= nLevel; --nMoveLevel)
250 {
251 ScOutlineCollection& rColl = aCollections[nMoveLevel];
252 ScOutlineCollection::iterator it = rColl.begin(), itEnd = rColl.end();
253 while (it != itEnd)
254 {
255 ScOutlineEntry *const pEntry = &it->second;
256 SCCOLROW nEntryStart = pEntry->GetStart();
257 if (nEntryStart >= nStartCol && nEntryStart <= nEndCol)
258 {
259 if (nMoveLevel >= SC_OL_MAXDEPTH - 1)
260 {
261 rSizeChanged = false; // No more room
262 return false;
263 }
264 aCollections[nMoveLevel+1].insert(*pEntry);
265 it = rColl.erase(it);
266 if (nMoveLevel == nDepth - 1)
267 bNeedSize = true;
268 }
269 else
270 ++it;
271 }
272 if (nMoveLevel == 0)
273 break;
274 }
275 }
276
277 if (bNeedSize)
278 {
279 ++nDepth;
280 rSizeChanged = true;
281 }
282
283 if (nDepth <= nLevel)
284 {
285 nDepth = nLevel+1;
286 rSizeChanged = true;
287 }
288
289 ScOutlineEntry aNewEntry(nStartCol, nEndCol+1-nStartCol, bHidden);
290 aNewEntry.SetVisible( true );
291 aCollections[nLevel].insert(aNewEntry);
292
293 return true;
294 }
295
FindTouchedLevel(SCCOLROW nBlockStart,SCCOLROW nBlockEnd,size_t & rFindLevel) const296 bool ScOutlineArray::FindTouchedLevel(
297 SCCOLROW nBlockStart, SCCOLROW nBlockEnd, size_t& rFindLevel) const
298 {
299 bool bFound = false;
300 rFindLevel = 0;
301
302 for (size_t nLevel = 0; nLevel < nDepth; ++nLevel)
303 {
304 const ScOutlineCollection* pCollect = &aCollections[nLevel];
305 for (const auto& rEntry : *pCollect)
306 {
307 const ScOutlineEntry *const pEntry = &rEntry.second;
308 SCCOLROW nStart = pEntry->GetStart();
309 SCCOLROW nEnd = pEntry->GetEnd();
310
311 if ( ( nBlockStart>=nStart && nBlockStart<=nEnd ) ||
312 ( nBlockEnd >=nStart && nBlockEnd <=nEnd ) )
313 {
314 rFindLevel = nLevel; // Actual Level
315 bFound = true;
316 }
317 }
318 }
319
320 return bFound;
321 }
322
PromoteSub(SCCOLROW nStartPos,SCCOLROW nEndPos,size_t nStartLevel)323 void ScOutlineArray::PromoteSub(SCCOLROW nStartPos, SCCOLROW nEndPos, size_t nStartLevel)
324 {
325 if (nStartLevel==0)
326 {
327 OSL_FAIL("PromoteSub with Level 0");
328 return;
329 }
330
331 for (size_t nLevel = nStartLevel; nLevel < nDepth; ++nLevel)
332 {
333 ScOutlineCollection& rColl = aCollections[nLevel];
334 ScOutlineCollection::iterator it = rColl.begin(), itEnd = rColl.end();
335 while (it != itEnd)
336 {
337 ScOutlineEntry *const pEntry = &it->second;
338 SCCOLROW nStart = pEntry->GetStart();
339 SCCOLROW nEnd = pEntry->GetEnd();
340 if (nStart >= nStartPos && nEnd <= nEndPos)
341 {
342 aCollections[nLevel-1].insert(*pEntry);
343
344 it = rColl.erase(it);
345 }
346 else
347 ++it;
348 }
349
350 it = rColl.begin();
351 itEnd = rColl.end();
352
353 while (it != itEnd)
354 {
355 ScOutlineEntry *const pEntry = &it->second;
356 SCCOLROW nStart = pEntry->GetStart();
357 SCCOLROW nEnd = pEntry->GetEnd();
358 if (nStart >= nStartPos && nEnd <= nEndPos)
359 {
360 aCollections[nLevel-1].insert(*pEntry);
361
362 it = rColl.erase(it);
363 }
364 else
365 ++it;
366 }
367 }
368 }
369
370 /**
371 * Adapt nDepth for empty Levels
372 */
DecDepth()373 bool ScOutlineArray::DecDepth()
374 {
375 bool bChanged = false;
376 bool bCont;
377 do
378 {
379 bCont = false;
380 if (nDepth)
381 {
382 if (aCollections[nDepth-1].empty())
383 {
384 --nDepth;
385 bChanged = true;
386 bCont = true;
387 }
388 }
389 }
390 while (bCont);
391
392 return bChanged;
393 }
394
Remove(SCCOLROW nBlockStart,SCCOLROW nBlockEnd,bool & rSizeChanged)395 bool ScOutlineArray::Remove( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, bool& rSizeChanged )
396 {
397 size_t nLevel;
398 FindTouchedLevel( nBlockStart, nBlockEnd, nLevel );
399
400 ScOutlineCollection* pCollect = &aCollections[nLevel];
401 ScOutlineCollection::iterator it = pCollect->begin(), itEnd = pCollect->end();
402 bool bAny = false;
403 while (it != itEnd)
404 {
405 ScOutlineEntry *const pEntry = &it->second;
406 SCCOLROW nStart = pEntry->GetStart();
407 SCCOLROW nEnd = pEntry->GetEnd();
408 if (nBlockStart <= nEnd && nBlockEnd >= nStart)
409 {
410 // Overlaps
411 pCollect->erase(it);
412 PromoteSub( nStart, nEnd, nLevel+1 );
413 itEnd = pCollect->end();
414 it = pCollect->FindStart( nEnd+1 );
415 bAny = true;
416 }
417 else
418 ++it;
419 }
420
421 if (bAny) // Adapt Depth
422 if (DecDepth())
423 rSizeChanged = true;
424
425 return bAny;
426 }
427
GetEntry(size_t nLevel,size_t nIndex)428 ScOutlineEntry* ScOutlineArray::GetEntry(size_t nLevel, size_t nIndex)
429 {
430 if (nLevel >= nDepth)
431 return nullptr;
432
433 ScOutlineCollection& rColl = aCollections[nLevel];
434 if (nIndex >= rColl.size())
435 return nullptr;
436
437 ScOutlineCollection::iterator it = rColl.begin();
438 std::advance(it, nIndex);
439 return &it->second;
440 }
441
GetEntry(size_t nLevel,size_t nIndex) const442 const ScOutlineEntry* ScOutlineArray::GetEntry(size_t nLevel, size_t nIndex) const
443 {
444 if (nLevel >= nDepth)
445 return nullptr;
446
447 const ScOutlineCollection& rColl = aCollections[nLevel];
448 if (nIndex >= rColl.size())
449 return nullptr;
450
451 ScOutlineCollection::const_iterator it = rColl.begin();
452 std::advance(it, nIndex);
453 return &it->second;
454 }
455
GetCount(size_t nLevel) const456 size_t ScOutlineArray::GetCount(size_t nLevel) const
457 {
458 if (nLevel >= nDepth)
459 return 0;
460
461 return aCollections[nLevel].size();
462 }
463
GetEntryByPos(size_t nLevel,SCCOLROW nPos) const464 const ScOutlineEntry* ScOutlineArray::GetEntryByPos(size_t nLevel, SCCOLROW nPos) const
465 {
466 if (nLevel >= nDepth)
467 return nullptr;
468
469 const ScOutlineCollection& rColl = aCollections[nLevel];
470 ScOutlineCollection::const_iterator it = std::find_if(rColl.begin(), rColl.end(),
471 [&nPos](const auto& rEntry) {
472 const ScOutlineEntry *const pEntry = &rEntry.second;
473 return pEntry->GetStart() <= nPos && nPos <= pEntry->GetEnd();
474 });
475 if (it != rColl.end())
476 return &it->second;
477
478 return nullptr;
479 }
480
GetEntryIndex(size_t nLevel,SCCOLROW nPos,size_t & rnIndex) const481 bool ScOutlineArray::GetEntryIndex(size_t nLevel, SCCOLROW nPos, size_t& rnIndex) const
482 {
483 if (nLevel >= nDepth)
484 return false;
485
486 // Found entry contains passed position
487 const ScOutlineCollection& rColl = aCollections[nLevel];
488 ScOutlineCollection::const_iterator it = std::find_if(rColl.begin(), rColl.end(),
489 [&nPos](const auto& rEntry) {
490 const ScOutlineEntry *const p = &rEntry.second;
491 return p->GetStart() <= nPos && nPos <= p->GetEnd();
492 });
493 if (it != rColl.end())
494 {
495 rnIndex = std::distance(rColl.begin(), it);
496 return true;
497 }
498 return false;
499 }
500
GetEntryIndexInRange(size_t nLevel,SCCOLROW nBlockStart,SCCOLROW nBlockEnd,size_t & rnIndex) const501 bool ScOutlineArray::GetEntryIndexInRange(
502 size_t nLevel, SCCOLROW nBlockStart, SCCOLROW nBlockEnd, size_t& rnIndex) const
503 {
504 if (nLevel >= nDepth)
505 return false;
506
507 // Found entry will be completely inside of passed range
508 const ScOutlineCollection& rColl = aCollections[nLevel];
509 ScOutlineCollection::const_iterator it = std::find_if(rColl.begin(), rColl.end(),
510 [&nBlockStart, &nBlockEnd](const auto& rEntry) {
511 const ScOutlineEntry *const p = &rEntry.second;
512 return nBlockStart <= p->GetStart() && p->GetEnd() <= nBlockEnd;
513 });
514 if (it != rColl.end())
515 {
516 rnIndex = std::distance(rColl.begin(), it);
517 return true;
518 }
519 return false;
520 }
521
SetVisibleBelow(size_t nLevel,size_t nEntry,bool bValue,bool bSkipHidden)522 void ScOutlineArray::SetVisibleBelow(
523 size_t nLevel, size_t nEntry, bool bValue, bool bSkipHidden)
524 {
525 const ScOutlineEntry* pEntry = GetEntry( nLevel, nEntry );
526 if (!pEntry)
527 return;
528
529 SCCOLROW nStart = pEntry->GetStart();
530 SCCOLROW nEnd = pEntry->GetEnd();
531
532 for (size_t nSubLevel = nLevel+1; nSubLevel < nDepth; ++nSubLevel)
533 {
534 ScOutlineCollection& rColl = aCollections[nSubLevel];
535 size_t nPos = 0;
536 for (auto& rEntry : rColl)
537 {
538 ScOutlineEntry *const p = &rEntry.second;
539 if (p->GetStart() >= nStart && p->GetEnd() <= nEnd)
540 {
541 p->SetVisible(bValue);
542 if (bSkipHidden && !p->IsHidden())
543 {
544 SetVisibleBelow(nSubLevel, nPos, bValue, true);
545 }
546 }
547 ++nPos;
548 }
549
550 if (bSkipHidden)
551 nSubLevel = nDepth; // Bail out
552 }
553 }
554
GetRange(SCCOLROW & rStart,SCCOLROW & rEnd) const555 void ScOutlineArray::GetRange(SCCOLROW& rStart, SCCOLROW& rEnd) const
556 {
557 const ScOutlineCollection& rColl = aCollections[0];
558 if (!rColl.empty())
559 {
560 ScOutlineCollection::const_iterator it = rColl.begin();
561 rStart = it->second.GetStart();
562 std::advance(it, rColl.size()-1);
563 rEnd = it->second.GetEnd();
564 }
565 else
566 rStart = rEnd = 0;
567 }
568
ExtendBlock(size_t nLevel,SCCOLROW & rBlkStart,SCCOLROW & rBlkEnd)569 void ScOutlineArray::ExtendBlock(size_t nLevel, SCCOLROW& rBlkStart, SCCOLROW& rBlkEnd)
570 {
571 if (nLevel >= nDepth)
572 return;
573
574 const ScOutlineCollection& rColl = aCollections[nLevel];
575 for (const auto& rEntry : rColl)
576 {
577 const ScOutlineEntry *const pEntry = &rEntry.second;
578 SCCOLROW nStart = pEntry->GetStart();
579 SCCOLROW nEnd = pEntry->GetEnd();
580
581 if (rBlkStart <= nEnd && rBlkEnd >= nStart)
582 {
583 if (nStart < rBlkStart)
584 rBlkStart = nStart;
585 if (nEnd > rBlkEnd)
586 rBlkEnd = nEnd;
587 }
588 }
589 }
590
TestInsertSpace(SCSIZE nSize,SCCOLROW nMaxVal) const591 bool ScOutlineArray::TestInsertSpace(SCSIZE nSize, SCCOLROW nMaxVal) const
592 {
593 const ScOutlineCollection& rColl = aCollections[0];
594 if (rColl.empty())
595 return true;
596
597 ScOutlineCollection::const_iterator it = rColl.begin();
598 std::advance(it, rColl.size()-1);
599 SCCOLROW nEnd = it->second.GetEnd();
600 return sal::static_int_cast<SCCOLROW>(nEnd+nSize) <= nMaxVal;
601 }
602
InsertSpace(SCCOLROW nStartPos,SCSIZE nSize)603 void ScOutlineArray::InsertSpace(SCCOLROW nStartPos, SCSIZE nSize)
604 {
605 ScSubOutlineIterator aIter( this );
606 ScOutlineEntry* pEntry;
607 while ((pEntry = aIter.GetNext()) != nullptr)
608 {
609 if ( pEntry->GetStart() >= nStartPos )
610 pEntry->Move(static_cast<SCCOLROW>(nSize));
611 else
612 {
613 SCCOLROW nEnd = pEntry->GetEnd();
614 // Always expand if inserted within the group
615 // When inserting at the end, only if the group is not hidden
616 if ( nEnd >= nStartPos || ( nEnd+1 >= nStartPos && !pEntry->IsHidden() ) )
617 {
618 SCSIZE nEntrySize = pEntry->GetSize();
619 nEntrySize += nSize;
620 pEntry->SetSize( nEntrySize );
621 }
622 }
623 }
624 }
625
DeleteSpace(SCCOLROW nStartPos,SCSIZE nSize)626 bool ScOutlineArray::DeleteSpace(SCCOLROW nStartPos, SCSIZE nSize)
627 {
628 SCCOLROW nEndPos = nStartPos + nSize - 1;
629 bool bNeedSave = false; // Do we need the original one for Undo?
630 bool bChanged = false; // For Level test
631
632 ScSubOutlineIterator aIter( this );
633 ScOutlineEntry* pEntry;
634 while((pEntry=aIter.GetNext())!=nullptr)
635 {
636 SCCOLROW nEntryStart = pEntry->GetStart();
637 SCCOLROW nEntryEnd = pEntry->GetEnd();
638 SCSIZE nEntrySize = pEntry->GetSize();
639
640 if ( nEntryEnd >= nStartPos )
641 {
642 if ( nEntryStart > nEndPos ) // Right
643 pEntry->Move(-static_cast<SCCOLROW>(nSize));
644 else if ( nEntryStart < nStartPos && nEntryEnd >= nEndPos ) // Outside
645 pEntry->SetSize( nEntrySize-nSize );
646 else
647 {
648 bNeedSave = true;
649 if ( nEntryStart >= nStartPos && nEntryEnd <= nEndPos ) // Inside
650 {
651 aIter.DeleteLast();
652 bChanged = true;
653 }
654 else if ( nEntryStart >= nStartPos ) // Top right
655 pEntry->SetPosSize( nStartPos, static_cast<SCSIZE>(nEntryEnd-nEndPos) );
656 else // Top left
657 pEntry->SetSize( static_cast<SCSIZE>(nStartPos-nEntryStart) );
658 }
659 }
660 }
661
662 if (bChanged)
663 DecDepth();
664
665 return bNeedSave;
666 }
667
ManualAction(SCCOLROW nStartPos,SCCOLROW nEndPos,bool bShow,const ScTable & rTable,bool bCol)668 bool ScOutlineArray::ManualAction(
669 SCCOLROW nStartPos, SCCOLROW nEndPos, bool bShow, const ScTable& rTable, bool bCol)
670 {
671 bool bModified = false;
672 ScSubOutlineIterator aIter( this );
673 ScOutlineEntry* pEntry;
674 while((pEntry=aIter.GetNext())!=nullptr)
675 {
676 SCCOLROW nEntryStart = pEntry->GetStart();
677 SCCOLROW nEntryEnd = pEntry->GetEnd();
678
679 if (nEntryEnd>=nStartPos && nEntryStart<=nEndPos)
680 {
681 if ( pEntry->IsHidden() == bShow )
682 {
683 // #i12341# hide if all columns/rows are hidden, show if at least one
684 // is visible
685 SCCOLROW nEnd = rTable.LastHiddenColRow(nEntryStart, bCol);
686 bool bAllHidden = (nEntryEnd <= nEnd && nEnd <
687 ::std::numeric_limits<SCCOLROW>::max());
688
689 bool bToggle = ( bShow != bAllHidden );
690 if ( bToggle )
691 {
692 pEntry->SetHidden( !bShow );
693 SetVisibleBelow( aIter.LastLevel(), aIter.LastEntry(), bShow, bShow );
694 bModified = true;
695 }
696 }
697 }
698 }
699 return bModified;
700 }
701
RemoveAll()702 void ScOutlineArray::RemoveAll()
703 {
704 for (size_t nLevel = 0; nLevel < nDepth; ++nLevel)
705 aCollections[nLevel].clear();
706
707 nDepth = 0;
708 }
709
finalizeImport(const ScTable & rTable)710 void ScOutlineArray::finalizeImport(const ScTable& rTable)
711 {
712 ScSubOutlineIterator aIter( this );
713 ScOutlineEntry* pEntry;
714 while((pEntry=aIter.GetNext())!=nullptr)
715 {
716
717 if (!pEntry->IsHidden())
718 continue;
719
720 SCCOLROW nEntryStart = pEntry->GetStart();
721 SCCOLROW nEntryEnd = pEntry->GetEnd();
722 SCCOLROW nEnd = rTable.LastHiddenColRow(nEntryStart, false/*bCol*/);
723 bool bAllHidden = (nEntryEnd <= nEnd && nEnd <
724 ::std::numeric_limits<SCCOLROW>::max());
725
726 pEntry->SetHidden(bAllHidden);
727 SetVisibleBelow(aIter.LastLevel(), aIter.LastEntry(), !bAllHidden, !bAllHidden);
728 }
729 }
730
dumpAsString() const731 OString ScOutlineArray::dumpAsString() const
732 {
733 OString aOutput;
734 const char* const pLevelSep = " ";
735 for (const auto& rCollection : aCollections)
736 {
737 if (rCollection.empty())
738 continue;
739 aOutput += rCollection.dumpAsString() + pLevelSep;
740 }
741
742 return aOutput;
743 }
744
ScOutlineTable()745 ScOutlineTable::ScOutlineTable()
746 {
747 }
748
ScOutlineTable(const ScOutlineTable & rOutline)749 ScOutlineTable::ScOutlineTable( const ScOutlineTable& rOutline ) :
750 aColOutline( rOutline.aColOutline ),
751 aRowOutline( rOutline.aRowOutline )
752 {
753 }
754
TestInsertCol(SCSIZE nSize)755 bool ScOutlineTable::TestInsertCol( SCSIZE nSize )
756 {
757 return aColOutline.TestInsertSpace( nSize, MAXCOL );
758 }
759
InsertCol(SCCOL nStartCol,SCSIZE nSize)760 void ScOutlineTable::InsertCol( SCCOL nStartCol, SCSIZE nSize )
761 {
762 aColOutline.InsertSpace( nStartCol, nSize );
763 }
764
DeleteCol(SCCOL nStartCol,SCSIZE nSize)765 bool ScOutlineTable::DeleteCol( SCCOL nStartCol, SCSIZE nSize )
766 {
767 return aColOutline.DeleteSpace( nStartCol, nSize );
768 }
769
TestInsertRow(SCSIZE nSize)770 bool ScOutlineTable::TestInsertRow( SCSIZE nSize )
771 {
772 return aRowOutline.TestInsertSpace( nSize, MAXROW );
773 }
774
InsertRow(SCROW nStartRow,SCSIZE nSize)775 void ScOutlineTable::InsertRow( SCROW nStartRow, SCSIZE nSize )
776 {
777 aRowOutline.InsertSpace( nStartRow, nSize );
778 }
779
DeleteRow(SCROW nStartRow,SCSIZE nSize)780 bool ScOutlineTable::DeleteRow( SCROW nStartRow, SCSIZE nSize )
781 {
782 return aRowOutline.DeleteSpace( nStartRow, nSize );
783 }
784
ScSubOutlineIterator(ScOutlineArray * pOutlineArray)785 ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray ) :
786 pArray( pOutlineArray ),
787 nStart( 0 ),
788 nEnd( SCCOLROW_MAX ), // Iterate over all of them
789 nSubLevel( 0 ),
790 nSubEntry( 0 )
791 {
792 nDepth = pArray->nDepth;
793 }
794
ScSubOutlineIterator(ScOutlineArray * pOutlineArray,size_t nLevel,size_t nEntry)795 ScSubOutlineIterator::ScSubOutlineIterator(
796 ScOutlineArray* pOutlineArray, size_t nLevel, size_t nEntry ) :
797 pArray( pOutlineArray )
798 {
799 const ScOutlineCollection& rColl = pArray->aCollections[nLevel];
800 ScOutlineCollection::const_iterator it = rColl.begin();
801 std::advance(it, nEntry);
802 const ScOutlineEntry* pEntry = &it->second;
803 nStart = pEntry->GetStart();
804 nEnd = pEntry->GetEnd();
805 nSubLevel = nLevel + 1;
806 nSubEntry = 0;
807 nDepth = pArray->nDepth;
808 }
809
GetNext()810 ScOutlineEntry* ScSubOutlineIterator::GetNext()
811 {
812 ScOutlineEntry* pEntry = nullptr;
813 bool bFound = false;
814 do
815 {
816 if (nSubLevel >= nDepth)
817 return nullptr;
818
819 ScOutlineCollection& rColl = pArray->aCollections[nSubLevel];
820 if (nSubEntry < rColl.size())
821 {
822 ScOutlineCollection::iterator it = rColl.begin();
823 std::advance(it, nSubEntry);
824 pEntry = &it->second;
825
826 if (pEntry->GetStart() >= nStart && pEntry->GetEnd() <= nEnd)
827 bFound = true;
828
829 ++nSubEntry;
830 }
831 else
832 {
833 // Go to the next sub-level
834 nSubEntry = 0;
835 ++nSubLevel;
836 }
837 }
838 while (!bFound);
839 return pEntry; // nSubLevel valid, if pEntry != 0
840 }
841
LastEntry() const842 size_t ScSubOutlineIterator::LastEntry() const
843 {
844 if (nSubEntry == 0)
845 {
846 OSL_FAIL("ScSubOutlineIterator::LastEntry before GetNext");
847 return 0;
848 }
849 return nSubEntry-1;
850 }
851
DeleteLast()852 void ScSubOutlineIterator::DeleteLast()
853 {
854 if (nSubLevel >= nDepth)
855 {
856 OSL_FAIL("ScSubOutlineIterator::DeleteLast after End");
857 return;
858 }
859 if (nSubEntry == 0)
860 {
861 OSL_FAIL("ScSubOutlineIterator::DeleteLast before GetNext");
862 return;
863 }
864
865 --nSubEntry;
866 ScOutlineCollection& rColl = pArray->aCollections[nSubLevel];
867 assert(nSubEntry < rColl.size());
868 ScOutlineCollection::iterator it = rColl.begin();
869 std::advance(it, nSubEntry);
870 rColl.erase(it);
871 }
872
873 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
874