1
0
Fork 0
libreoffice/sc/source/core/data/olinetab.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

873 lines
24 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <olinetab.hxx>
#include <address.hxx>
#include <table.hxx>
#include <osl/diagnose.h>
ScOutlineEntry::ScOutlineEntry( SCCOLROW nNewStart, SCCOLROW nNewSize, bool bNewHidden ) :
nStart ( nNewStart ),
nSize ( nNewSize ),
bHidden ( bNewHidden ),
bVisible( true )
{
}
ScOutlineEntry::ScOutlineEntry( const ScOutlineEntry& rEntry ) :
nStart ( rEntry.nStart ),
nSize ( rEntry.nSize ),
bHidden ( rEntry.bHidden ),
bVisible( rEntry.bVisible )
{
}
SCCOLROW ScOutlineEntry::GetEnd() const
{
return nStart+nSize-1;
}
void ScOutlineEntry::Move( SCCOLROW nDelta )
{
SCCOLROW nNewPos = nStart + nDelta;
if (nNewPos<0)
{
OSL_FAIL("OutlineEntry < 0");
nNewPos = 0;
}
nStart = nNewPos;
}
void ScOutlineEntry::SetSize( SCSIZE nNewSize )
{
if (nNewSize>0)
nSize = nNewSize;
else
{
OSL_FAIL("ScOutlineEntry Size == 0");
}
}
void ScOutlineEntry::SetPosSize( SCCOLROW nNewPos, SCSIZE nNewSize )
{
nStart = nNewPos;
SetSize( nNewSize );
}
void ScOutlineEntry::SetHidden( bool bNewHidden )
{
bHidden = bNewHidden;
}
void ScOutlineEntry::SetVisible( bool bNewVisible )
{
bVisible = bNewVisible;
}
OString ScOutlineEntry::dumpAsString() const
{
const char* const pSep = ":";
return OString::number(nStart) + pSep + OString::number(nSize) +
pSep + (bHidden ? "1" : "0") + pSep + (bVisible ? "1" : "0");
}
ScOutlineCollection::ScOutlineCollection() {}
size_t ScOutlineCollection::size() const
{
return m_Entries.size();
}
void ScOutlineCollection::clear()
{
m_Entries.clear();
}
void ScOutlineCollection::insert(ScOutlineEntry const& rEntry)
{
SCCOLROW nStart = rEntry.GetStart();
m_Entries.insert(std::make_pair(nStart, rEntry));
}
ScOutlineCollection::iterator ScOutlineCollection::begin()
{
return m_Entries.begin();
}
ScOutlineCollection::iterator ScOutlineCollection::end()
{
return m_Entries.end();
}
ScOutlineCollection::const_iterator ScOutlineCollection::begin() const
{
return m_Entries.begin();
}
ScOutlineCollection::const_iterator ScOutlineCollection::end() const
{
return m_Entries.end();
}
ScOutlineCollection::iterator ScOutlineCollection::erase(const iterator& pos)
{
return m_Entries.erase(pos);
}
bool ScOutlineCollection::empty() const
{
return m_Entries.empty();
}
ScOutlineCollection::iterator ScOutlineCollection::FindStart(SCCOLROW nMinStart)
{
return m_Entries.lower_bound(nMinStart);
}
OString ScOutlineCollection::dumpAsString() const
{
OString aOutput;
const char* const pGroupEntrySep = ",";
for (const auto& rKeyValuePair : m_Entries)
aOutput += rKeyValuePair.second.dumpAsString() + pGroupEntrySep;
return aOutput;
}
ScOutlineArray::ScOutlineArray() :
nDepth(0) {}
ScOutlineArray::ScOutlineArray( const ScOutlineArray& rArray ) :
nDepth( rArray.nDepth )
{
for (size_t nLevel = 0; nLevel < nDepth; ++nLevel)
{
const ScOutlineCollection& rColl = rArray.aCollections[nLevel];
for (const auto& rEntry : rColl)
{
const ScOutlineEntry *const pEntry = &rEntry.second;
aCollections[nLevel].insert(*pEntry);
}
}
}
void ScOutlineArray::FindEntry(
SCCOLROW nSearchPos, size_t& rFindLevel, size_t& rFindIndex,
size_t nMaxLevel )
{
rFindLevel = rFindIndex = 0;
if (nMaxLevel > nDepth)
nMaxLevel = nDepth;
for (size_t nLevel = 0; nLevel < nMaxLevel; ++nLevel) //TODO: Search backwards?
{
ScOutlineCollection* pCollect = &aCollections[nLevel];
size_t nIndex = 0;
for (auto& rEntry : *pCollect)
{
ScOutlineEntry *const pEntry = &rEntry.second;
if (pEntry->GetStart() <= nSearchPos && pEntry->GetEnd() >= nSearchPos)
{
rFindLevel = nLevel + 1; // Next Level (for insertion)
rFindIndex = nIndex;
}
++nIndex;
}
}
}
bool ScOutlineArray::Insert(
SCCOLROW nStartCol, SCCOLROW nEndCol, bool& rSizeChanged, bool bHidden )
{
rSizeChanged = false;
size_t nStartLevel, nEndLevel, nStartIndex, nEndIndex;
bool bFound = false;
bool bCont;
sal_uInt16 nFindMax;
FindEntry( nStartCol, nStartLevel, nStartIndex ); // nLevel = new Level (old+1)
FindEntry( nEndCol, nEndLevel, nEndIndex );
nFindMax = std::max(nStartLevel,nEndLevel);
do
{
bCont = false;
if (nStartLevel == nEndLevel && nStartIndex == nEndIndex && nStartLevel < SC_OL_MAXDEPTH)
bFound = true;
if (!bFound && nFindMax>0)
{
--nFindMax;
if (nStartLevel)
{
ScOutlineCollection::const_iterator it = aCollections[nStartLevel-1].begin();
std::advance(it, nStartIndex);
if (it->second.GetStart() == nStartCol)
FindEntry(nStartCol, nStartLevel, nStartIndex, nFindMax);
}
if (nEndLevel)
{
ScOutlineCollection::const_iterator it = aCollections[nEndLevel-1].begin();
std::advance(it, nEndIndex);
if (it->second.GetEnd() == nEndCol)
FindEntry(nEndCol, nEndLevel, nEndIndex, nFindMax);
}
bCont = true;
}
}
while ( !bFound && bCont );
if (!bFound)
return false;
size_t nLevel = nStartLevel;
// Move the ones underneath
bool bNeedSize = false;
if (nDepth > 0)
{
for (size_t nMoveLevel = nDepth-1; nMoveLevel >= nLevel; --nMoveLevel)
{
ScOutlineCollection& rColl = aCollections[nMoveLevel];
ScOutlineCollection::iterator it = rColl.begin(), itEnd = rColl.end();
while (it != itEnd)
{
ScOutlineEntry *const pEntry = &it->second;
SCCOLROW nEntryStart = pEntry->GetStart();
if (nEntryStart >= nStartCol && nEntryStart <= nEndCol)
{
if (nMoveLevel >= SC_OL_MAXDEPTH - 1)
{
rSizeChanged = false; // No more room
return false;
}
aCollections[nMoveLevel+1].insert(*pEntry);
it = rColl.erase(it);
if (nMoveLevel == nDepth - 1)
bNeedSize = true;
}
else
++it;
}
if (nMoveLevel == 0)
break;
}
}
if (bNeedSize)
{
++nDepth;
rSizeChanged = true;
}
if (nDepth <= nLevel)
{
nDepth = nLevel+1;
rSizeChanged = true;
}
ScOutlineEntry aNewEntry(nStartCol, nEndCol+1-nStartCol, bHidden);
aNewEntry.SetVisible( true );
aCollections[nLevel].insert(aNewEntry);
return true;
}
bool ScOutlineArray::FindTouchedLevel(
SCCOLROW nBlockStart, SCCOLROW nBlockEnd, size_t& rFindLevel) const
{
bool bFound = false;
rFindLevel = 0;
for (size_t nLevel = 0; nLevel < nDepth; ++nLevel)
{
const ScOutlineCollection* pCollect = &aCollections[nLevel];
for (const auto& rEntry : *pCollect)
{
const ScOutlineEntry *const pEntry = &rEntry.second;
SCCOLROW nStart = pEntry->GetStart();
SCCOLROW nEnd = pEntry->GetEnd();
if ( ( nBlockStart>=nStart && nBlockStart<=nEnd ) ||
( nBlockEnd >=nStart && nBlockEnd <=nEnd ) )
{
rFindLevel = nLevel; // Actual Level
bFound = true;
}
}
}
return bFound;
}
void ScOutlineArray::PromoteSub(SCCOLROW nStartPos, SCCOLROW nEndPos, size_t nStartLevel)
{
if (nStartLevel==0)
{
OSL_FAIL("PromoteSub with Level 0");
return;
}
for (size_t nLevel = nStartLevel; nLevel < nDepth; ++nLevel)
{
ScOutlineCollection& rColl = aCollections[nLevel];
ScOutlineCollection::iterator it = rColl.begin(), itEnd = rColl.end();
while (it != itEnd)
{
ScOutlineEntry *const pEntry = &it->second;
SCCOLROW nStart = pEntry->GetStart();
SCCOLROW nEnd = pEntry->GetEnd();
if (nStart >= nStartPos && nEnd <= nEndPos)
{
aCollections[nLevel-1].insert(*pEntry);
it = rColl.erase(it);
}
else
++it;
}
it = rColl.begin();
itEnd = rColl.end();
while (it != itEnd)
{
ScOutlineEntry *const pEntry = &it->second;
SCCOLROW nStart = pEntry->GetStart();
SCCOLROW nEnd = pEntry->GetEnd();
if (nStart >= nStartPos && nEnd <= nEndPos)
{
aCollections[nLevel-1].insert(*pEntry);
it = rColl.erase(it);
}
else
++it;
}
}
}
/**
* Adapt nDepth for empty Levels
*/
bool ScOutlineArray::DecDepth()
{
bool bChanged = false;
bool bCont;
do
{
bCont = false;
if (nDepth)
{
if (aCollections[nDepth-1].empty())
{
--nDepth;
bChanged = true;
bCont = true;
}
}
}
while (bCont);
return bChanged;
}
bool ScOutlineArray::Remove( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, bool& rSizeChanged )
{
size_t nLevel;
FindTouchedLevel( nBlockStart, nBlockEnd, nLevel );
ScOutlineCollection* pCollect = &aCollections[nLevel];
ScOutlineCollection::iterator it = pCollect->begin(), itEnd = pCollect->end();
bool bAny = false;
while (it != itEnd)
{
ScOutlineEntry *const pEntry = &it->second;
SCCOLROW nStart = pEntry->GetStart();
SCCOLROW nEnd = pEntry->GetEnd();
if (nBlockStart <= nEnd && nBlockEnd >= nStart)
{
// Overlaps
pCollect->erase(it);
PromoteSub( nStart, nEnd, nLevel+1 );
itEnd = pCollect->end();
it = pCollect->FindStart( nEnd+1 );
bAny = true;
}
else
++it;
}
if (bAny) // Adapt Depth
if (DecDepth())
rSizeChanged = true;
return bAny;
}
ScOutlineEntry* ScOutlineArray::GetEntry(size_t nLevel, size_t nIndex)
{
if (nLevel >= nDepth)
return nullptr;
ScOutlineCollection& rColl = aCollections[nLevel];
if (nIndex >= rColl.size())
return nullptr;
ScOutlineCollection::iterator it = rColl.begin();
std::advance(it, nIndex);
return &it->second;
}
const ScOutlineEntry* ScOutlineArray::GetEntry(size_t nLevel, size_t nIndex) const
{
if (nLevel >= nDepth)
return nullptr;
const ScOutlineCollection& rColl = aCollections[nLevel];
if (nIndex >= rColl.size())
return nullptr;
ScOutlineCollection::const_iterator it = rColl.begin();
std::advance(it, nIndex);
return &it->second;
}
size_t ScOutlineArray::GetCount(size_t nLevel) const
{
if (nLevel >= nDepth)
return 0;
return aCollections[nLevel].size();
}
const ScOutlineEntry* ScOutlineArray::GetEntryByPos(size_t nLevel, SCCOLROW nPos) const
{
if (nLevel >= nDepth)
return nullptr;
const ScOutlineCollection& rColl = aCollections[nLevel];
ScOutlineCollection::const_iterator it = std::find_if(rColl.begin(), rColl.end(),
[&nPos](const auto& rEntry) {
const ScOutlineEntry *const pEntry = &rEntry.second;
return pEntry->GetStart() <= nPos && nPos <= pEntry->GetEnd();
});
if (it != rColl.end())
return &it->second;
return nullptr;
}
bool ScOutlineArray::GetEntryIndex(size_t nLevel, SCCOLROW nPos, size_t& rnIndex) const
{
if (nLevel >= nDepth)
return false;
// Found entry contains passed position
const ScOutlineCollection& rColl = aCollections[nLevel];
ScOutlineCollection::const_iterator it = std::find_if(rColl.begin(), rColl.end(),
[&nPos](const auto& rEntry) {
const ScOutlineEntry *const p = &rEntry.second;
return p->GetStart() <= nPos && nPos <= p->GetEnd();
});
if (it != rColl.end())
{
rnIndex = std::distance(rColl.begin(), it);
return true;
}
return false;
}
bool ScOutlineArray::GetEntryIndexInRange(
size_t nLevel, SCCOLROW nBlockStart, SCCOLROW nBlockEnd, size_t& rnIndex) const
{
if (nLevel >= nDepth)
return false;
// Found entry will be completely inside of passed range
const ScOutlineCollection& rColl = aCollections[nLevel];
ScOutlineCollection::const_iterator it = std::find_if(rColl.begin(), rColl.end(),
[&nBlockStart, &nBlockEnd](const auto& rEntry) {
const ScOutlineEntry *const p = &rEntry.second;
return nBlockStart <= p->GetStart() && p->GetEnd() <= nBlockEnd;
});
if (it != rColl.end())
{
rnIndex = std::distance(rColl.begin(), it);
return true;
}
return false;
}
void ScOutlineArray::SetVisibleBelow(
size_t nLevel, size_t nEntry, bool bValue, bool bSkipHidden)
{
const ScOutlineEntry* pEntry = GetEntry( nLevel, nEntry );
if (!pEntry)
return;
SCCOLROW nStart = pEntry->GetStart();
SCCOLROW nEnd = pEntry->GetEnd();
for (size_t nSubLevel = nLevel+1; nSubLevel < nDepth; ++nSubLevel)
{
ScOutlineCollection& rColl = aCollections[nSubLevel];
size_t nPos = 0;
for (auto& rEntry : rColl)
{
ScOutlineEntry *const p = &rEntry.second;
if (p->GetStart() >= nStart && p->GetEnd() <= nEnd)
{
p->SetVisible(bValue);
if (bSkipHidden && !p->IsHidden())
{
SetVisibleBelow(nSubLevel, nPos, bValue, true);
}
}
++nPos;
}
if (bSkipHidden)
nSubLevel = nDepth; // Bail out
}
}
void ScOutlineArray::GetRange(SCCOLROW& rStart, SCCOLROW& rEnd) const
{
const ScOutlineCollection& rColl = aCollections[0];
if (!rColl.empty())
{
ScOutlineCollection::const_iterator it = rColl.begin();
rStart = it->second.GetStart();
std::advance(it, rColl.size()-1);
rEnd = it->second.GetEnd();
}
else
rStart = rEnd = 0;
}
void ScOutlineArray::ExtendBlock(size_t nLevel, SCCOLROW& rBlkStart, SCCOLROW& rBlkEnd)
{
if (nLevel >= nDepth)
return;
const ScOutlineCollection& rColl = aCollections[nLevel];
for (const auto& rEntry : rColl)
{
const ScOutlineEntry *const pEntry = &rEntry.second;
SCCOLROW nStart = pEntry->GetStart();
SCCOLROW nEnd = pEntry->GetEnd();
if (rBlkStart <= nEnd && rBlkEnd >= nStart)
{
if (nStart < rBlkStart)
rBlkStart = nStart;
if (nEnd > rBlkEnd)
rBlkEnd = nEnd;
}
}
}
bool ScOutlineArray::TestInsertSpace(SCSIZE nSize, SCCOLROW nMaxVal) const
{
const ScOutlineCollection& rColl = aCollections[0];
if (rColl.empty())
return true;
ScOutlineCollection::const_iterator it = rColl.begin();
std::advance(it, rColl.size()-1);
SCCOLROW nEnd = it->second.GetEnd();
return sal::static_int_cast<SCCOLROW>(nEnd+nSize) <= nMaxVal;
}
void ScOutlineArray::InsertSpace(SCCOLROW nStartPos, SCSIZE nSize)
{
ScSubOutlineIterator aIter( this );
ScOutlineEntry* pEntry;
while ((pEntry = aIter.GetNext()) != nullptr)
{
if ( pEntry->GetStart() >= nStartPos )
pEntry->Move(static_cast<SCCOLROW>(nSize));
else
{
SCCOLROW nEnd = pEntry->GetEnd();
// Always expand if inserted within the group
// When inserting at the end, only if the group is not hidden
if ( nEnd >= nStartPos || ( nEnd+1 >= nStartPos && !pEntry->IsHidden() ) )
{
SCSIZE nEntrySize = pEntry->GetSize();
nEntrySize += nSize;
pEntry->SetSize( nEntrySize );
}
}
}
}
bool ScOutlineArray::DeleteSpace(SCCOLROW nStartPos, SCSIZE nSize)
{
SCCOLROW nEndPos = nStartPos + nSize - 1;
bool bNeedSave = false; // Do we need the original one for Undo?
bool bChanged = false; // For Level test
ScSubOutlineIterator aIter( this );
ScOutlineEntry* pEntry;
while((pEntry=aIter.GetNext())!=nullptr)
{
SCCOLROW nEntryStart = pEntry->GetStart();
SCCOLROW nEntryEnd = pEntry->GetEnd();
SCSIZE nEntrySize = pEntry->GetSize();
if ( nEntryEnd >= nStartPos )
{
if ( nEntryStart > nEndPos ) // Right
pEntry->Move(-static_cast<SCCOLROW>(nSize));
else if ( nEntryStart < nStartPos && nEntryEnd >= nEndPos ) // Outside
pEntry->SetSize( nEntrySize-nSize );
else
{
bNeedSave = true;
if ( nEntryStart >= nStartPos && nEntryEnd <= nEndPos ) // Inside
{
aIter.DeleteLast();
bChanged = true;
}
else if ( nEntryStart >= nStartPos ) // Top right
pEntry->SetPosSize( nStartPos, static_cast<SCSIZE>(nEntryEnd-nEndPos) );
else // Top left
pEntry->SetSize( static_cast<SCSIZE>(nStartPos-nEntryStart) );
}
}
}
if (bChanged)
DecDepth();
return bNeedSave;
}
bool ScOutlineArray::ManualAction(
SCCOLROW nStartPos, SCCOLROW nEndPos, bool bShow, const ScTable& rTable, bool bCol)
{
bool bModified = false;
ScSubOutlineIterator aIter( this );
ScOutlineEntry* pEntry;
while((pEntry=aIter.GetNext())!=nullptr)
{
SCCOLROW nEntryStart = pEntry->GetStart();
SCCOLROW nEntryEnd = pEntry->GetEnd();
if (nEntryEnd>=nStartPos && nEntryStart<=nEndPos)
{
if ( pEntry->IsHidden() == bShow )
{
// #i12341# hide if all columns/rows are hidden, show if at least one
// is visible
SCCOLROW nEnd = rTable.LastHiddenColRow(nEntryStart, bCol);
bool bAllHidden = (nEntryEnd <= nEnd && nEnd <
::std::numeric_limits<SCCOLROW>::max());
bool bToggle = ( bShow != bAllHidden );
if ( bToggle )
{
pEntry->SetHidden( !bShow );
SetVisibleBelow( aIter.LastLevel(), aIter.LastEntry(), bShow, bShow );
bModified = true;
}
}
}
}
return bModified;
}
void ScOutlineArray::RemoveAll()
{
for (size_t nLevel = 0; nLevel < nDepth; ++nLevel)
aCollections[nLevel].clear();
nDepth = 0;
}
void ScOutlineArray::finalizeImport(const ScTable& rTable)
{
ScSubOutlineIterator aIter( this );
ScOutlineEntry* pEntry;
while((pEntry=aIter.GetNext())!=nullptr)
{
if (!pEntry->IsHidden())
continue;
SCCOLROW nEntryStart = pEntry->GetStart();
SCCOLROW nEntryEnd = pEntry->GetEnd();
SCCOLROW nEnd = rTable.LastHiddenColRow(nEntryStart, false/*bCol*/);
bool bAllHidden = (nEntryEnd <= nEnd && nEnd <
::std::numeric_limits<SCCOLROW>::max());
pEntry->SetHidden(bAllHidden);
SetVisibleBelow(aIter.LastLevel(), aIter.LastEntry(), !bAllHidden, !bAllHidden);
}
}
OString ScOutlineArray::dumpAsString() const
{
OString aOutput;
const char* const pLevelSep = " ";
for (const auto& rCollection : aCollections)
{
if (rCollection.empty())
continue;
aOutput += rCollection.dumpAsString() + pLevelSep;
}
return aOutput;
}
ScOutlineTable::ScOutlineTable()
{
}
ScOutlineTable::ScOutlineTable( const ScOutlineTable& rOutline ) :
aColOutline( rOutline.aColOutline ),
aRowOutline( rOutline.aRowOutline )
{
}
bool ScOutlineTable::TestInsertCol( SCSIZE nSize )
{
return aColOutline.TestInsertSpace( nSize, MAXCOL );
}
void ScOutlineTable::InsertCol( SCCOL nStartCol, SCSIZE nSize )
{
aColOutline.InsertSpace( nStartCol, nSize );
}
bool ScOutlineTable::DeleteCol( SCCOL nStartCol, SCSIZE nSize )
{
return aColOutline.DeleteSpace( nStartCol, nSize );
}
bool ScOutlineTable::TestInsertRow( SCSIZE nSize )
{
return aRowOutline.TestInsertSpace( nSize, MAXROW );
}
void ScOutlineTable::InsertRow( SCROW nStartRow, SCSIZE nSize )
{
aRowOutline.InsertSpace( nStartRow, nSize );
}
bool ScOutlineTable::DeleteRow( SCROW nStartRow, SCSIZE nSize )
{
return aRowOutline.DeleteSpace( nStartRow, nSize );
}
ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray ) :
pArray( pOutlineArray ),
nStart( 0 ),
nEnd( SCCOLROW_MAX ), // Iterate over all of them
nSubLevel( 0 ),
nSubEntry( 0 )
{
nDepth = pArray->nDepth;
}
ScSubOutlineIterator::ScSubOutlineIterator(
ScOutlineArray* pOutlineArray, size_t nLevel, size_t nEntry ) :
pArray( pOutlineArray )
{
const ScOutlineCollection& rColl = pArray->aCollections[nLevel];
ScOutlineCollection::const_iterator it = rColl.begin();
std::advance(it, nEntry);
const ScOutlineEntry* pEntry = &it->second;
nStart = pEntry->GetStart();
nEnd = pEntry->GetEnd();
nSubLevel = nLevel + 1;
nSubEntry = 0;
nDepth = pArray->nDepth;
}
ScOutlineEntry* ScSubOutlineIterator::GetNext()
{
ScOutlineEntry* pEntry = nullptr;
bool bFound = false;
do
{
if (nSubLevel >= nDepth)
return nullptr;
ScOutlineCollection& rColl = pArray->aCollections[nSubLevel];
if (nSubEntry < rColl.size())
{
ScOutlineCollection::iterator it = rColl.begin();
std::advance(it, nSubEntry);
pEntry = &it->second;
if (pEntry->GetStart() >= nStart && pEntry->GetEnd() <= nEnd)
bFound = true;
++nSubEntry;
}
else
{
// Go to the next sub-level
nSubEntry = 0;
++nSubLevel;
}
}
while (!bFound);
return pEntry; // nSubLevel valid, if pEntry != 0
}
size_t ScSubOutlineIterator::LastEntry() const
{
if (nSubEntry == 0)
{
OSL_FAIL("ScSubOutlineIterator::LastEntry before GetNext");
return 0;
}
return nSubEntry-1;
}
void ScSubOutlineIterator::DeleteLast()
{
if (nSubLevel >= nDepth)
{
OSL_FAIL("ScSubOutlineIterator::DeleteLast after End");
return;
}
if (nSubEntry == 0)
{
OSL_FAIL("ScSubOutlineIterator::DeleteLast before GetNext");
return;
}
--nSubEntry;
ScOutlineCollection& rColl = pArray->aCollections[nSubLevel];
assert(nSubEntry < rColl.size());
ScOutlineCollection::iterator it = rColl.begin();
std::advance(it, nSubEntry);
rColl.erase(it);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */