diff options
Diffstat (limited to 'sc/source/core/tool/rangelst.cxx')
-rw-r--r-- | sc/source/core/tool/rangelst.cxx | 1532 |
1 files changed, 1532 insertions, 0 deletions
diff --git a/sc/source/core/tool/rangelst.cxx b/sc/source/core/tool/rangelst.cxx new file mode 100644 index 000000000..fb880d308 --- /dev/null +++ b/sc/source/core/tool/rangelst.cxx @@ -0,0 +1,1532 @@ +/* -*- 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 <stdlib.h> +#include <unotools/collatorwrapper.hxx> +#include <sal/log.hxx> +#include <o3tl/string_view.hxx> + +#include <rangelst.hxx> +#include <document.hxx> +#include <refupdat.hxx> +#include <compiler.hxx> +#include <algorithm> +#include <memory> + +using ::std::vector; +using ::std::find_if; +using ::std::for_each; +using ::formula::FormulaGrammar; + +namespace { + +template<typename T> +class FindEnclosingRange +{ +public: + explicit FindEnclosingRange(const T& rTest) : mrTest(rTest) {} + bool operator() (const ScRange & rRange) const + { + return rRange.Contains(mrTest); + } +private: + const T& mrTest; +}; + +template<typename T> +class FindIntersectingRange +{ +public: + explicit FindIntersectingRange(const T& rTest) : mrTest(rTest) {} + bool operator() (const ScRange & rRange) const + { + return rRange.Intersects(mrTest); + } +private: + const T& mrTest; +}; + +class CountCells +{ +public: + CountCells() : mnCellCount(0) {} + + void operator() (const ScRange & r) + { + mnCellCount += + sal_uInt64(r.aEnd.Col() - r.aStart.Col() + 1) + * sal_uInt64(r.aEnd.Row() - r.aStart.Row() + 1) + * sal_uInt64(r.aEnd.Tab() - r.aStart.Tab() + 1); + } + + sal_uInt64 getCellCount() const { return mnCellCount; } + +private: + sal_uInt64 mnCellCount; +}; + + +} + +// ScRangeList +ScRangeList::~ScRangeList() +{ +} + +ScRefFlags ScRangeList::Parse( std::u16string_view rStr, const ScDocument& rDoc, + formula::FormulaGrammar::AddressConvention eConv, + SCTAB nDefaultTab, sal_Unicode cDelimiter ) +{ + if ( !rStr.empty() ) + { + if (!cDelimiter) + cDelimiter = ScCompiler::GetNativeSymbolChar(ocSep); + + ScRefFlags nResult = ~ScRefFlags::ZERO; // set all bits + ScRange aRange; + const SCTAB nTab = nDefaultTab; + + sal_Int32 nPos = 0; + do + { + const OUString aOne( o3tl::getToken(rStr, 0, cDelimiter, nPos ) ); + aRange.aStart.SetTab( nTab ); // default tab if not specified + ScRefFlags nRes = aRange.ParseAny( aOne, rDoc, eConv ); + ScRefFlags nEndRangeBits = ScRefFlags::COL2_VALID | ScRefFlags::ROW2_VALID | ScRefFlags::TAB2_VALID; + ScRefFlags nTmp1 = nRes & ScRefFlags::BITS; + ScRefFlags nTmp2 = nRes & nEndRangeBits; + // If we have a valid single range with + // any of the address bits we are interested in + // set - set the equiv end range bits + if ( (nRes & ScRefFlags::VALID ) && (nTmp1 != ScRefFlags::ZERO) && ( nTmp2 != nEndRangeBits ) ) + applyStartToEndFlags(nRes, nTmp1); + + if ( nRes & ScRefFlags::VALID ) + push_back( aRange ); + nResult &= nRes; // all common bits are preserved + } + while (nPos >= 0); + + return nResult; // ScRefFlags::VALID set when all are OK + } + else + return ScRefFlags::ZERO; +} + +void ScRangeList::Format( OUString& rStr, ScRefFlags nFlags, const ScDocument& rDoc, + formula::FormulaGrammar::AddressConvention eConv, + sal_Unicode cDelimiter, bool bFullAddressNotation ) const +{ + if (!cDelimiter) + cDelimiter = ScCompiler::GetNativeSymbolChar(ocSep); + + OUStringBuffer aBuf; + bool bFirst = true; + for( auto const & r : maRanges) + { + if (bFirst) + bFirst = false; + else + aBuf.append(OUStringChar(cDelimiter)); + aBuf.append(r.Format(rDoc, nFlags, eConv, bFullAddressNotation)); + } + rStr = aBuf.makeStringAndClear(); +} + +void ScRangeList::Join( const ScRange& rNewRange, bool bIsInList ) +{ + if ( maRanges.empty() ) + { + push_back( rNewRange ); + return ; + } + + // One common usage is to join ranges that actually are top to bottom + // appends but the caller doesn't exactly know about it, e.g. when invoked + // by ScMarkData::FillRangeListWithMarks(), check for this special case + // first and speed up things by not looping over all ranges for each range + // to be joined. We don't remember the exact encompassing range that would + // have to be updated on refupdates and insertions and deletions, instead + // remember just the maximum row used, even independently of the sheet. + // This satisfies most use cases. + + if (!bIsInList) + { + const SCROW nRow1 = rNewRange.aStart.Row(); + if (nRow1 > mnMaxRowUsed + 1) + { + push_back( rNewRange ); + return; + } + else if (nRow1 == mnMaxRowUsed + 1) + { + // Check if we can simply enlarge the last range. + ScRange & rLast = maRanges.back(); + if (rLast.aEnd.Row() + 1 == nRow1 && + rLast.aStart.Col() == rNewRange.aStart.Col() && rLast.aEnd.Col() == rNewRange.aEnd.Col() && + rLast.aStart.Tab() == rNewRange.aStart.Tab() && rLast.aEnd.Tab() == rNewRange.aEnd.Tab()) + { + const SCROW nRow2 = rNewRange.aEnd.Row(); + rLast.aEnd.SetRow( nRow2 ); + mnMaxRowUsed = nRow2; + return; + } + } + } + + bool bJoinedInput = false; + const ScRange* pOver = &rNewRange; + +Label_Range_Join: + + assert(pOver); + const SCCOL nCol1 = pOver->aStart.Col(); + const SCROW nRow1 = pOver->aStart.Row(); + const SCCOL nTab1 = pOver->aStart.Tab(); + const SCCOL nCol2 = pOver->aEnd.Col(); + const SCROW nRow2 = pOver->aEnd.Row(); + const SCCOL nTab2 = pOver->aEnd.Tab(); + + size_t nOverPos = std::numeric_limits<size_t>::max(); + for (size_t i = 0; i < maRanges.size(); ++i) + { + ScRange & rRange = maRanges[i]; + if ( &rRange == pOver ) + { + nOverPos = i; + continue; // the same one, continue with the next + } + bool bJoined = false; + if ( rRange.Contains( *pOver ) ) + { // range pOver included in or identical to range p + // XXX if we never used Append() before Join() we could remove + // pOver and end processing, but it is not guaranteed and there can + // be duplicates. + if ( bIsInList ) + bJoined = true; // do away with range pOver + else + { // that was all then + bJoinedInput = true; // don't append + break; // for + } + } + else if ( pOver->Contains( rRange ) ) + { // range rRange included in range pOver, make pOver the new range + rRange = *pOver; + bJoined = true; + } + if ( !bJoined && rRange.aStart.Tab() == nTab1 && rRange.aEnd.Tab() == nTab2 ) + { // 2D + if ( rRange.aStart.Col() == nCol1 && rRange.aEnd.Col() == nCol2 ) + { + if ( rRange.aStart.Row() <= nRow2+1 && + rRange.aStart.Row() >= nRow1 ) + { // top + rRange.aStart.SetRow( nRow1 ); + bJoined = true; + } + else if ( rRange.aEnd.Row() >= nRow1-1 && + rRange.aEnd.Row() <= nRow2 ) + { // bottom + rRange.aEnd.SetRow( nRow2 ); + bJoined = true; + } + } + else if ( rRange.aStart.Row() == nRow1 && rRange.aEnd.Row() == nRow2 ) + { + if ( rRange.aStart.Col() <= nCol2+1 && + rRange.aStart.Col() >= nCol1 ) + { // left + rRange.aStart.SetCol( nCol1 ); + bJoined = true; + } + else if ( rRange.aEnd.Col() >= nCol1-1 && + rRange.aEnd.Col() <= nCol2 ) + { // right + rRange.aEnd.SetCol( nCol2 ); + bJoined = true; + } + } + } + if ( bJoined ) + { + if ( bIsInList ) + { // delete range pOver within the list + if (nOverPos != std::numeric_limits<size_t>::max()) + { + Remove(nOverPos); + if (nOverPos < i) + --i; + } + else + { + for (size_t nOver = 0, nRanges = maRanges.size(); nOver < nRanges; ++nOver) + { + if (&maRanges[nOver] == pOver) + { + Remove(nOver); + break; + } + } + } + } + bJoinedInput = true; + pOver = &maRanges[i]; + bIsInList = true; + goto Label_Range_Join; + } + } + if ( !bIsInList && !bJoinedInput ) + push_back( rNewRange ); +} + +void ScRangeList::AddAndPartialCombine( const ScRange& rNewRange ) +{ + if ( maRanges.empty() ) + { + push_back( rNewRange ); + return ; + } + + // One common usage is to join ranges that actually are top to bottom + // appends but the caller doesn't exactly know about it, e.g. when invoked + // by ScMarkData::FillRangeListWithMarks(), check for this special case + // first and speed up things by not looping over all ranges for each range + // to be joined. We don't remember the exact encompassing range that would + // have to be updated on refupdates and insertions and deletions, instead + // remember just the maximum row used, even independently of the sheet. + // This satisfies most use cases. + + const SCROW nRow1 = rNewRange.aStart.Row(); + if (nRow1 > mnMaxRowUsed + 1) + { + push_back( rNewRange ); + return; + } + + // scan backwards 2 rows to see if we can merge with anything + auto it = maRanges.rbegin(); + while (it != maRanges.rend() && it->aStart.Row() >= (rNewRange.aStart.Row() - 2)) + { + // Check if we can simply enlarge this range. + ScRange & rLast = *it; + if (rLast.aEnd.Row() + 1 == nRow1 && + rLast.aStart.Col() == rNewRange.aStart.Col() && rLast.aEnd.Col() == rNewRange.aEnd.Col() && + rLast.aStart.Tab() == rNewRange.aStart.Tab() && rLast.aEnd.Tab() == rNewRange.aEnd.Tab()) + { + const SCROW nRow2 = rNewRange.aEnd.Row(); + rLast.aEnd.SetRow( nRow2 ); + mnMaxRowUsed = std::max(mnMaxRowUsed, nRow2); + return; + } + ++it; + } + + push_back( rNewRange ); +} + +bool ScRangeList::operator==( const ScRangeList& r ) const +{ + if ( this == &r ) + return true; + + return maRanges == r.maRanges; +} + +bool ScRangeList::operator!=( const ScRangeList& r ) const +{ + return !operator==( r ); +} + +bool ScRangeList::UpdateReference( + UpdateRefMode eUpdateRefMode, + const ScDocument* pDoc, + const ScRange& rWhere, + SCCOL nDx, + SCROW nDy, + SCTAB nDz +) +{ + if (maRanges.empty()) + // No ranges to update. Bail out. + return false; + + bool bChanged = false; + SCCOL nCol1; + SCROW nRow1; + SCTAB nTab1; + SCCOL nCol2; + SCROW nRow2; + SCTAB nTab2; + rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); + + if(eUpdateRefMode == URM_INSDEL) + { + // right now this only works for nTab1 == nTab2 + if(nTab1 == nTab2) + { + if(nDx < 0) + { + bChanged = DeleteArea(nCol1+nDx, nRow1, nTab1, nCol1-1, nRow2, nTab2); + } + if(nDy < 0) + { + bChanged = DeleteArea(nCol1, nRow1+nDy, nTab1, nCol2, nRow1-1, nTab2); + } + SAL_WARN_IF(nDx < 0 && nDy < 0, "sc", "nDx and nDy are negative, check why"); + } + } + + if(maRanges.empty()) + return true; + + for (auto& rR : maRanges) + { + SCCOL theCol1; + SCROW theRow1; + SCTAB theTab1; + SCCOL theCol2; + SCROW theRow2; + SCTAB theTab2; + rR.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ); + if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, + nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, + nDx, nDy, nDz, + theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ) + != UR_NOTHING ) + { + bChanged = true; + rR.aStart.Set( theCol1, theRow1, theTab1 ); + rR.aEnd.Set( theCol2, theRow2, theTab2 ); + if (mnMaxRowUsed < theRow2) + mnMaxRowUsed = theRow2; + } + } + + if(eUpdateRefMode == URM_INSDEL) + { + if( nDx < 0 || nDy < 0 ) + { + size_t n = maRanges.size(); + for(size_t i = n-1; i > 0;) + { + Join(maRanges[i], true); + // Join() may merge and remove even more than one item, protect against it. + if(i >= maRanges.size()) + i = maRanges.size()-1; + else + --i; + } + } + } + + return bChanged; +} + +void ScRangeList::InsertRow( SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize ) +{ + std::vector<ScRange> aNewRanges; + for(const auto & rRange : maRanges) + { + if(rRange.aStart.Tab() <= nTab && rRange.aEnd.Tab() >= nTab) + { + if(rRange.aEnd.Row() == nRowPos - 1 && (nColStart <= rRange.aEnd.Col() || nColEnd >= rRange.aStart.Col())) + { + SCCOL nNewRangeStartCol = std::max<SCCOL>(nColStart, rRange.aStart.Col()); + SCCOL nNewRangeEndCol = std::min<SCCOL>(nColEnd, rRange.aEnd.Col()); + SCROW nNewRangeStartRow = rRange.aEnd.Row() + 1; + SCROW nNewRangeEndRow = nRowPos + nSize - 1; + aNewRanges.emplace_back(nNewRangeStartCol, nNewRangeStartRow, nTab, nNewRangeEndCol, + nNewRangeEndRow, nTab); + if (mnMaxRowUsed < nNewRangeEndRow) + mnMaxRowUsed = nNewRangeEndRow; + } + } + } + + for(const auto & rRange : aNewRanges) + { + if(!rRange.IsValid()) + continue; + + Join(rRange); + } +} + +void ScRangeList::InsertCol( SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize ) +{ + std::vector<ScRange> aNewRanges; + for(const auto & rRange : maRanges) + { + if(rRange.aStart.Tab() <= nTab && rRange.aEnd.Tab() >= nTab) + { + if(rRange.aEnd.Col() == nColPos - 1 && (nRowStart <= rRange.aEnd.Row() || nRowEnd >= rRange.aStart.Row())) + { + SCROW nNewRangeStartRow = std::max<SCROW>(nRowStart, rRange.aStart.Row()); + SCROW nNewRangeEndRow = std::min<SCROW>(nRowEnd, rRange.aEnd.Row()); + SCCOL nNewRangeStartCol = rRange.aEnd.Col() + 1; + SCCOL nNewRangeEndCol = nColPos + nSize - 1; + aNewRanges.emplace_back(nNewRangeStartCol, nNewRangeStartRow, nTab, nNewRangeEndCol, + nNewRangeEndRow, nTab); + } + } + } + + for(const auto & rRange : aNewRanges) + { + if(!rRange.IsValid()) + continue; + + Join(rRange); + } +} + +void ScRangeList::InsertCol( SCTAB nTab, SCCOL nCol ) +{ + std::vector<ScRange> aNewRanges; + for(const auto & rRange : maRanges) + { + if(rRange.aStart.Tab() <= nTab && rRange.aEnd.Tab() >= nTab) + { + if(rRange.aEnd.Col() == nCol - 1) + { + SCCOL nNewRangeStartCol = rRange.aEnd.Col() + 1; + SCCOL nNewRangeEndCol = nCol; + aNewRanges.emplace_back(nNewRangeStartCol, rRange.aStart.Row(), nTab, nNewRangeEndCol, + rRange.aEnd.Row(), nTab); + } + } + } + + for(const auto & rRange : aNewRanges) + { + if(!rRange.IsValid()) + continue; + + Join(rRange); + } +} + +namespace { + +/** + * Check if the deleting range cuts the test range exactly into a single + * piece. + * + * X = column ; Y = row + * +------+ +------+ + * |xxxxxx| | | + * +------+ or +------+ + * | | |xxxxxx| + * +------+ +------+ + * + * X = row; Y = column + * +--+--+ +--+--+ + * |xx| | | |xx| + * |xx| | or | |xx| + * |xx| | | |xx| + * +--+--+ +--+--+ + * where xxx is the deleted region. + */ +template<typename X, typename Y> +bool checkForOneRange( + X nDeleteX1, X nDeleteX2, Y nDeleteY1, Y nDeleteY2, X nX1, X nX2, Y nY1, Y nY2) +{ + return nDeleteX1 <= nX1 && nX2 <= nDeleteX2 && (nDeleteY1 <= nY1 || nY2 <= nDeleteY2); +} + +bool handleOneRange( const ScRange& rDeleteRange, ScRange& r ) +{ + const ScAddress& rDelStart = rDeleteRange.aStart; + const ScAddress& rDelEnd = rDeleteRange.aEnd; + ScAddress aPStart = r.aStart; + ScAddress aPEnd = r.aEnd; + SCCOL nDeleteCol1 = rDelStart.Col(); + SCCOL nDeleteCol2 = rDelEnd.Col(); + SCROW nDeleteRow1 = rDelStart.Row(); + SCROW nDeleteRow2 = rDelEnd.Row(); + SCCOL nCol1 = aPStart.Col(); + SCCOL nCol2 = aPEnd.Col(); + SCROW nRow1 = aPStart.Row(); + SCROW nRow2 = aPEnd.Row(); + + if (checkForOneRange(nDeleteCol1, nDeleteCol2, nDeleteRow1, nDeleteRow2, nCol1, nCol2, nRow1, nRow2)) + { + // Deleting range fully overlaps the column range. Adjust the row span. + if (nDeleteRow1 <= nRow1) + { + // +------+ + // |xxxxxx| + // +------+ + // | | + // +------+ (xxx) = deleted region + + r.aStart.SetRow(nDeleteRow1+1); + return true; + } + else if (nRow2 <= nDeleteRow2) + { + // +------+ + // | | + // +------+ + // |xxxxxx| + // +------+ (xxx) = deleted region + + r.aEnd.SetRow(nDeleteRow1-1); + return true; + } + } + else if (checkForOneRange(nDeleteRow1, nDeleteRow2, nDeleteCol1, nDeleteCol2, nRow1, nRow2, nCol1, nCol2)) + { + // Deleting range fully overlaps the row range. Adjust the column span. + if (nDeleteCol1 <= nCol1) + { + // +--+--+ + // |xx| | + // |xx| | + // |xx| | + // +--+--+ (xxx) = deleted region + + r.aStart.SetCol(nDeleteCol2+1); + return true; + } + else if (nCol2 <= nDeleteCol2) + { + // +--+--+ + // | |xx| + // | |xx| + // | |xx| + // +--+--+ (xxx) = deleted region + + r.aEnd.SetCol(nDeleteCol1-1); + return true; + } + } + return false; +} + +bool handleTwoRanges( const ScRange& rDeleteRange, ScRange& r, std::vector<ScRange>& rNewRanges ) +{ + const ScAddress& rDelStart = rDeleteRange.aStart; + const ScAddress& rDelEnd = rDeleteRange.aEnd; + ScAddress aPStart = r.aStart; + ScAddress aPEnd = r.aEnd; + SCCOL nDeleteCol1 = rDelStart.Col(); + SCCOL nDeleteCol2 = rDelEnd.Col(); + SCROW nDeleteRow1 = rDelStart.Row(); + SCROW nDeleteRow2 = rDelEnd.Row(); + SCCOL nCol1 = aPStart.Col(); + SCCOL nCol2 = aPEnd.Col(); + SCROW nRow1 = aPStart.Row(); + SCROW nRow2 = aPEnd.Row(); + SCTAB nTab = aPStart.Tab(); + + if (nCol1 < nDeleteCol1 && nDeleteCol1 <= nCol2 && nCol2 <= nDeleteCol2) + { + // column deleted : |-------| + // column original: |-------| + if (nRow1 < nDeleteRow1 && nDeleteRow1 <= nRow2 && nRow2 <= nDeleteRow2) + { + // row deleted: |------| + // row original: |------| + // + // +-------+ + // | 1 | + // +---+---+---+ + // | 2 |xxxxxxx| + // +---+xxxxxxx| + // |xxxxxxx| + // +-------+ (xxx) deleted region + + ScRange aNewRange( nCol1, nDeleteRow1, nTab, nDeleteCol1-1, nRow2, nTab ); // 2 + rNewRanges.push_back(aNewRange); + + r.aEnd.SetRow(nDeleteRow1-1); // 1 + return true; + } + else if (nRow1 <= nDeleteRow2 && nDeleteRow2 < nRow2 && nDeleteRow1 <= nRow1) + { + // row deleted: |------| + // row original: |------| + // + // +-------+ + // |xxxxxxx| + // +---+xxxxxxx| + // | 1 |xxxxxxx| + // +---+---+---+ + // | 2 | (xxx) deleted region + // +-------+ + + ScRange aNewRange( aPStart, ScAddress(nDeleteCol1-1, nRow2, nTab) ); // 1 + rNewRanges.push_back(aNewRange); + + r.aStart.SetRow(nDeleteRow2+1); // 2 + return true; + } + } + else if (nCol1 <= nDeleteCol2 && nDeleteCol2 < nCol2 && nDeleteCol1 <= nCol1) + { + // column deleted : |-------| + // column original: |-------| + if (nRow1 < nDeleteRow1 && nDeleteRow1 <= nRow2 && nRow2 <= nDeleteRow2) + { + // row deleted: |------| + // row original: |------| + // + // +-------+ + // | 1 | + // +-------+---+ + // |xxxxxxx| 2 | + // |xxxxxxx+---+ + // |xxxxxxx| + // +-------+ + // (xxx) deleted region + + ScRange aNewRange( ScAddress( nDeleteCol2+1, nDeleteRow1, nTab ), aPEnd ); // 2 + rNewRanges.push_back(aNewRange); + + r.aEnd.SetRow(nDeleteRow1-1); // 1 + return true; + } + else if (nRow1 <= nDeleteRow2 && nDeleteRow2 < nRow2 && nDeleteRow1 <= nRow1) + { + // row deleted: |-------| + // row original: |--------| + // + // +-------+ + // |xxxxxxx| + // |xxxxxxx+---+ + // |xxxxxxx| 1 | + // +-------+---+ + // | 2 | + // +-------+ (xxx) deleted region + + ScRange aNewRange(nDeleteCol2+1, nRow1, nTab, nCol2, nDeleteRow2, nTab); // 1 + rNewRanges.push_back(aNewRange); + + r.aStart.SetRow(nDeleteRow2+1); // 2 + return true; + } + } + else if (nRow1 < nDeleteRow1 && nDeleteRow2 < nRow2 && nDeleteCol1 <= nCol1 && nCol2 <= nDeleteCol2) + { + // +--------+ + // | 1 | + // +--------+ + // |xxxxxxxx| (xxx) deleted region + // +--------+ + // | 2 | + // +--------+ + + ScRange aNewRange( aPStart, ScAddress(nCol2, nDeleteRow1-1, nTab) ); // 1 + rNewRanges.push_back(aNewRange); + + r.aStart.SetRow(nDeleteRow2+1); // 2 + return true; + } + else if (nCol1 < nDeleteCol1 && nDeleteCol2 < nCol2 && nDeleteRow1 <= nRow1 && nRow2 <= nDeleteRow2) + { + // +---+-+---+ + // | |x| | + // | |x| | + // | 1 |x| 2 | (xxx) deleted region + // | |x| | + // | |x| | + // +---+-+---+ + + ScRange aNewRange( aPStart, ScAddress(nDeleteCol1-1, nRow2, nTab) ); // 1 + rNewRanges.push_back(aNewRange); + + r.aStart.SetCol(nDeleteCol2+1); // 2 + return true; + } + + return false; +} + +/** + * Check if any of the following applies: + * + * X = column; Y = row + * +----------+ +----------+ + * | | | | + * | +-------+---+ +--+-------+ | + * | |xxxxxxxxxxx| or |xxxxxxxxxx| | + * | +-------+---+ +--+-------+ | + * | | | | + * +----------+ +----------+ + * + * X = row; Y = column + * +--+ + * |xx| + * +---+xx+---+ +----------+ + * | |xx| | | | + * | |xx| | or | +--+ | + * | +--+ | | |xx| | + * | | | |xx| | + * +----------+ +---+xx+---+ + * |xx| + * +--+ (xxx) deleted region + */ +template<typename X, typename Y> +bool checkForThreeRanges( + X nDeleteX1, X nDeleteX2, Y nDeleteY1, Y nDeleteY2, X nX1, X nX2, Y nY1, Y nY2) +{ + if (nX1 <= nDeleteX1 && nX2 <= nDeleteX2 && nY1 < nDeleteY1 && nDeleteY2 < nY2) + return true; + + if (nDeleteX1 <= nX1 && nDeleteX2 <= nX2 && nY1 < nDeleteY1 && nDeleteY2 < nY2) + return true; + + return false; +} + +bool handleThreeRanges( const ScRange& rDeleteRange, ScRange& r, std::vector<ScRange>& rNewRanges ) +{ + const ScAddress& rDelStart = rDeleteRange.aStart; + const ScAddress& rDelEnd = rDeleteRange.aEnd; + ScAddress aPStart = r.aStart; + ScAddress aPEnd = r.aEnd; + SCCOL nDeleteCol1 = rDelStart.Col(); + SCCOL nDeleteCol2 = rDelEnd.Col(); + SCROW nDeleteRow1 = rDelStart.Row(); + SCROW nDeleteRow2 = rDelEnd.Row(); + SCCOL nCol1 = aPStart.Col(); + SCCOL nCol2 = aPEnd.Col(); + SCROW nRow1 = aPStart.Row(); + SCROW nRow2 = aPEnd.Row(); + SCTAB nTab = aPStart.Tab(); + + if (checkForThreeRanges(nDeleteCol1, nDeleteCol2, nDeleteRow1, nDeleteRow2, nCol1, nCol2, nRow1, nRow2)) + { + if (nCol1 < nDeleteCol1) + { + // +---+------+ + // | | 2 | + // | +------+---+ + // | 1 |xxxxxxxxxx| + // | +------+---+ + // | | 3 | + // +---+------+ + + ScRange aNewRange(nDeleteCol1, nRow1, nTab, nCol2, nDeleteRow1-1, nTab); // 2 + rNewRanges.push_back(aNewRange); + + aNewRange = ScRange(ScAddress(nDeleteCol1, nDeleteRow2+1, nTab), aPEnd); // 3 + rNewRanges.push_back(aNewRange); + + r.aEnd.SetCol(nDeleteCol1-1); // 1 + } + else + { + // +------+---+ + // | 1 | | + // +---+------+ | + // |xxxxxxxxxx| 2 | + // +---+------+ | + // | 3 | | + // +------+---+ + + ScRange aNewRange(aPStart, ScAddress(nDeleteCol2, nDeleteRow1-1, nTab)); // 1 + rNewRanges.push_back(aNewRange); + + aNewRange = ScRange(nCol1, nDeleteRow2+1, nTab, nDeleteCol2, nRow2, nTab); // 3 + rNewRanges.push_back(aNewRange); + + r.aStart.SetCol(nDeleteCol2+1); // 2 + } + return true; + } + else if (checkForThreeRanges(nDeleteRow1, nDeleteRow2, nDeleteCol1, nDeleteCol2, nRow1, nRow2, nCol1, nCol2)) + { + if (nRow1 < nDeleteRow1) + { + // +----------+ + // | 1 | + // +---+--+---+ + // | |xx| | + // | 2 |xx| 3 | + // | |xx| | + // +---+xx+---+ + // |xx| + // +--+ + + ScRange aNewRange(nCol1, nDeleteRow1, nTab, nDeleteCol1-1, nRow2, nTab); // 2 + rNewRanges.push_back( aNewRange ); + + aNewRange = ScRange(ScAddress(nDeleteCol2+1, nDeleteRow1, nTab), aPEnd); // 3 + rNewRanges.push_back( aNewRange ); + + r.aEnd.SetRow(nDeleteRow1-1); // 1 + } + else + { + // +--+ + // |xx| + // +---+xx+---+ + // | 1 |xx| 2 | + // | |xx| | + // +---+--+---+ + // | 3 | + // +----------+ + + ScRange aNewRange(aPStart, ScAddress(nDeleteCol1-1, nDeleteRow2, nTab)); // 1 + rNewRanges.push_back(aNewRange); + + aNewRange = ScRange(nDeleteCol2+1, nRow1, nTab, nCol2, nDeleteRow2, nTab); // 2 + rNewRanges.push_back( aNewRange ); + + r.aStart.SetRow(nDeleteRow2+1); // 3 + } + return true; + } + + return false; +} + +bool handleFourRanges( const ScRange& rDelRange, ScRange& r, std::vector<ScRange>& rNewRanges ) +{ + const ScAddress& rDelStart = rDelRange.aStart; + const ScAddress& rDelEnd = rDelRange.aEnd; + ScAddress aPStart = r.aStart; + ScAddress aPEnd = r.aEnd; + SCCOL nDeleteCol1 = rDelStart.Col(); + SCCOL nDeleteCol2 = rDelEnd.Col(); + SCROW nDeleteRow1 = rDelStart.Row(); + SCROW nDeleteRow2 = rDelEnd.Row(); + SCCOL nCol1 = aPStart.Col(); + SCCOL nCol2 = aPEnd.Col(); + SCROW nRow1 = aPStart.Row(); + SCROW nRow2 = aPEnd.Row(); + SCTAB nTab = aPStart.Tab(); + + if (nCol1 < nDeleteCol1 && nDeleteCol2 < nCol2 && nRow1 < nDeleteRow1 && nDeleteRow2 < nRow2) + { + + // +---------------+ + // | 1 | + // +---+-------+---+ + // | |xxxxxxx| | + // | 2 |xxxxxxx| 3 | + // | |xxxxxxx| | + // +---+-------+---+ + // | 4 | + // +---------------+ + + ScRange aNewRange(ScAddress(nCol1, nDeleteRow2+1, nTab), aPEnd); // 4 + rNewRanges.push_back( aNewRange ); + + aNewRange = ScRange(nCol1, nDeleteRow1, nTab, nDeleteCol1-1, nDeleteRow2, nTab); // 2 + rNewRanges.push_back( aNewRange ); + + aNewRange = ScRange(nDeleteCol2+1, nDeleteRow1, nTab, nCol2, nDeleteRow2, nTab); // 3 + rNewRanges.push_back( aNewRange ); + + r.aEnd.SetRow(nDeleteRow1-1); // 1 + + return true; + } + + return false; +} + +} + +bool ScRangeList::DeleteArea( SCCOL nCol1, SCROW nRow1, SCTAB nTab1, + SCCOL nCol2, SCROW nRow2, SCTAB nTab2 ) +{ + bool bChanged = false; + ScRange aRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); + for(size_t i = 0; i < maRanges.size();) + { + if(aRange.Contains(maRanges[i])) + { + Remove(i); + bChanged = true; + } + else + ++i; + } + + std::vector<ScRange> aNewRanges; + + for(auto & rRange : maRanges) + { + // we have two basic cases here: + // 1. Delete area and pRange intersect + // 2. Delete area and pRange are not intersecting + // checking for 2 and if true skip this range + if(!rRange.Intersects(aRange)) + continue; + + // We get between 1 and 4 ranges from the difference of the first with the second + + // X either Col or Row and Y then the opposite + // r = deleteRange, p = entry from ScRangeList + + // getting exactly one range is the simple case + // r.aStart.X() <= p.aStart.X() && r.aEnd.X() >= p.aEnd.X() + // && ( r.aStart.Y() <= p.aStart.Y() || r.aEnd.Y() >= r.aEnd.Y() ) + if(handleOneRange( aRange, rRange )) + { + bChanged = true; + continue; + } + + // getting two ranges + // r.aStart.X() + else if(handleTwoRanges( aRange, rRange, aNewRanges )) + { + bChanged = true; + continue; + } + + // getting 3 ranges + // r.aStart.X() > p.aStart.X() && r.aEnd.X() >= p.aEnd.X() + // && r.aStart.Y() > p.aStart.Y() && r.aEnd.Y() < p.aEnd.Y() + // or + // r.aStart.X() <= p.aStart.X() && r.aEnd.X() < p.aEnd.X() + // && r.aStart.Y() > p.aStart.Y() && r.aEnd.Y() < p.aEnd.Y() + else if(handleThreeRanges( aRange, rRange, aNewRanges )) + { + bChanged = true; + continue; + } + + // getting 4 ranges + // r.aStart.X() > p.aStart.X() && r.aEnd().X() < p.aEnd.X() + // && r.aStart.Y() > p.aStart.Y() && r.aEnd().Y() < p.aEnd.Y() + else if(handleFourRanges( aRange, rRange, aNewRanges )) + { + bChanged = true; + continue; + } + } + for(const auto & rRange : aNewRanges) + Join(rRange); + + return bChanged; +} + +const ScRange* ScRangeList::Find( const ScAddress& rAdr ) const +{ + auto itr = find_if( + maRanges.cbegin(), maRanges.cend(), FindEnclosingRange<ScAddress>(rAdr)); + return itr == maRanges.end() ? nullptr : &*itr; +} + +ScRange* ScRangeList::Find( const ScAddress& rAdr ) +{ + auto itr = find_if( + maRanges.begin(), maRanges.end(), FindEnclosingRange<ScAddress>(rAdr)); + return itr == maRanges.end() ? nullptr : &*itr; +} + +ScRangeList::ScRangeList() : mnMaxRowUsed(-1) {} + +ScRangeList::ScRangeList( const ScRangeList& rList ) : + SvRefBase(rList), + maRanges(rList.maRanges), + mnMaxRowUsed(rList.mnMaxRowUsed) +{ +} + +ScRangeList::ScRangeList(ScRangeList&& rList) noexcept : + maRanges(std::move(rList.maRanges)), + mnMaxRowUsed(rList.mnMaxRowUsed) +{ +} + +ScRangeList::ScRangeList( const ScRange& rRange ) : + mnMaxRowUsed(-1) +{ + maRanges.reserve(1); + push_back(rRange); +} + +ScRangeList& ScRangeList::operator=(const ScRangeList& rList) +{ + maRanges = rList.maRanges; + mnMaxRowUsed = rList.mnMaxRowUsed; + return *this; +} + +ScRangeList& ScRangeList::operator=(ScRangeList&& rList) noexcept +{ + maRanges = std::move(rList.maRanges); + mnMaxRowUsed = rList.mnMaxRowUsed; + return *this; +} + +bool ScRangeList::Intersects( const ScRange& rRange ) const +{ + return std::any_of(maRanges.begin(), maRanges.end(), FindIntersectingRange<ScRange>(rRange)); +} + +bool ScRangeList::Contains( const ScRange& rRange ) const +{ + return std::any_of(maRanges.begin(), maRanges.end(), FindEnclosingRange<ScRange>(rRange)); +} + +sal_uInt64 ScRangeList::GetCellCount() const +{ + CountCells func; + return for_each(maRanges.begin(), maRanges.end(), func).getCellCount(); +} + +void ScRangeList::Remove(size_t nPos) +{ + if (maRanges.size() <= nPos) + // Out-of-bound condition. Bail out. + return; + maRanges.erase(maRanges.begin() + nPos); +} + +void ScRangeList::RemoveAll() +{ + maRanges.clear(); + mnMaxRowUsed = -1; +} + +ScRange ScRangeList::Combine() const +{ + if (maRanges.empty()) + return ScRange(); + + auto itr = maRanges.cbegin(), itrEnd = maRanges.cend(); + ScRange aRet = *itr; + ++itr; + for (; itr != itrEnd; ++itr) + { + const ScRange& r = *itr; + SCROW nRow1 = r.aStart.Row(), nRow2 = r.aEnd.Row(); + SCCOL nCol1 = r.aStart.Col(), nCol2 = r.aEnd.Col(); + SCTAB nTab1 = r.aStart.Tab(), nTab2 = r.aEnd.Tab(); + if (aRet.aStart.Row() > nRow1) + aRet.aStart.SetRow(nRow1); + if (aRet.aStart.Col() > nCol1) + aRet.aStart.SetCol(nCol1); + if (aRet.aStart.Tab() > nTab1) + aRet.aStart.SetTab(nTab1); + if (aRet.aEnd.Row() < nRow2) + aRet.aEnd.SetRow(nRow2); + if (aRet.aEnd.Col() < nCol2) + aRet.aEnd.SetCol(nCol2); + if (aRet.aEnd.Tab() < nTab2) + aRet.aEnd.SetTab(nTab2); + } + return aRet; +} + +void ScRangeList::push_back(const ScRange & r) +{ + maRanges.push_back(r); + if (mnMaxRowUsed < r.aEnd.Row()) + mnMaxRowUsed = r.aEnd.Row(); +} + +void ScRangeList::swap( ScRangeList& r ) +{ + maRanges.swap(r.maRanges); + std::swap(mnMaxRowUsed, r.mnMaxRowUsed); +} + +ScAddress ScRangeList::GetTopLeftCorner() const +{ + if(empty()) + return ScAddress(); + + ScAddress const * pAddr = &maRanges[0].aStart; + for(size_t i = 1, n = size(); i < n; ++i) + { + if(maRanges[i].aStart < *pAddr) + pAddr = &maRanges[i].aStart; + } + + return *pAddr; +} + +ScRangeList ScRangeList::GetIntersectedRange(const ScRange& rRange) const +{ + ScRangeList aReturn; + for(auto& rR : maRanges) + { + if(rR.Intersects(rRange)) + { + SCCOL nColStart1, nColEnd1, nColStart2, nColEnd2; + SCROW nRowStart1, nRowEnd1, nRowStart2, nRowEnd2; + SCTAB nTabStart1, nTabEnd1, nTabStart2, nTabEnd2; + rR.GetVars(nColStart1, nRowStart1, nTabStart1, + nColEnd1, nRowEnd1, nTabEnd1); + rRange.GetVars(nColStart2, nRowStart2, nTabStart2, + nColEnd2, nRowEnd2, nTabEnd2); + + ScRange aNewRange(std::max<SCCOL>(nColStart1, nColStart2), std::max<SCROW>(nRowStart1, nRowStart2), + std::max<SCTAB>(nTabStart1, nTabStart2), std::min<SCCOL>(nColEnd1, nColEnd2), + std::min<SCROW>(nRowEnd1, nRowEnd2), std::min<SCTAB>(nTabEnd1, nTabEnd2)); + aReturn.Join(aNewRange); + } + } + + return aReturn; +} + +// ScRangePairList +ScRangePairList::~ScRangePairList() +{ +} + +void ScRangePairList::Remove(size_t nPos) +{ + if (maPairs.size() <= nPos) + // Out-of-bound condition. Bail out. + return; + maPairs.erase(maPairs.begin() + nPos); +} + +void ScRangePairList::Remove( const ScRangePair & rAdr) +{ + auto itr = std::find_if(maPairs.begin(), maPairs.end(), [&rAdr](const ScRangePair& rPair) { return &rAdr == &rPair; }); + if (itr != maPairs.end()) + { + maPairs.erase( itr ); + return; + } + assert(false); +} + +ScRangePair & ScRangePairList::operator [](size_t idx) +{ + return maPairs[idx]; +} + +const ScRangePair & ScRangePairList::operator [](size_t idx) const +{ + return maPairs[idx]; +} + +size_t ScRangePairList::size() const +{ + return maPairs.size(); +} + +void ScRangePairList::UpdateReference( UpdateRefMode eUpdateRefMode, + const ScDocument* pDoc, const ScRange& rWhere, + SCCOL nDx, SCROW nDy, SCTAB nDz ) +{ + if ( maPairs.empty() ) + return; + + SCCOL nCol1; + SCROW nRow1; + SCTAB nTab1; + SCCOL nCol2; + SCROW nRow2; + SCTAB nTab2; + rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); + for (ScRangePair & rR : maPairs) + { + for ( sal_uInt16 j=0; j<2; j++ ) + { + ScRange& rRange = rR.GetRange(j); + SCCOL theCol1; + SCROW theRow1; + SCTAB theTab1; + SCCOL theCol2; + SCROW theRow2; + SCTAB theTab2; + rRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ); + if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, + nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, + nDx, nDy, nDz, + theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ) + != UR_NOTHING ) + { + rRange.aStart.Set( theCol1, theRow1, theTab1 ); + rRange.aEnd.Set( theCol2, theRow2, theTab2 ); + } + } + } +} + +// Delete entries that have the labels (first range) on nTab +void ScRangePairList::DeleteOnTab( SCTAB nTab ) +{ + maPairs.erase(std::remove_if(maPairs.begin(), maPairs.end(), + [&nTab](const ScRangePair& rR) { + const ScRange & rRange = rR.GetRange(0); + return (rRange.aStart.Tab() == nTab) && (rRange.aEnd.Tab() == nTab); + }), + maPairs.end()); +} + +ScRangePair* ScRangePairList::Find( const ScAddress& rAdr ) +{ + for (ScRangePair & rR : maPairs) + { + if ( rR.GetRange(0).Contains( rAdr ) ) + return &rR; + } + return nullptr; +} + +ScRangePair* ScRangePairList::Find( const ScRange& rRange ) +{ + for (ScRangePair & rR : maPairs) + { + if ( rR.GetRange(0) == rRange ) + return &rR; + } + return nullptr; +} + +ScRangePairList* ScRangePairList::Clone() const +{ + ScRangePairList* pNew = new ScRangePairList; + for (const ScRangePair & rR : maPairs) + { + pNew->Append( rR ); + } + return pNew; +} + +namespace { + +class ScRangePairList_sortNameCompare +{ +public: + ScRangePairList_sortNameCompare(ScDocument& rDoc) : mrDoc(rDoc) {} + + bool operator()( const ScRangePair *ps1, const ScRangePair* ps2 ) const + { + const ScAddress& rStartPos1 = ps1->GetRange(0).aStart; + const ScAddress& rStartPos2 = ps2->GetRange(0).aStart; + OUString aStr1, aStr2; + sal_Int32 nComp; + if ( rStartPos1.Tab() == rStartPos2.Tab() ) + nComp = 0; + else + { + mrDoc.GetName( rStartPos1.Tab(), aStr1 ); + mrDoc.GetName( rStartPos2.Tab(), aStr2 ); + nComp = ScGlobal::GetCollator().compareString( aStr1, aStr2 ); + } + if (nComp < 0) + { + return true; // -1; + } + else if (nComp > 0) + { + return false; // 1; + } + + // equal tabs + if ( rStartPos1.Col() < rStartPos2.Col() ) + return true; // -1; + if ( rStartPos1.Col() > rStartPos2.Col() ) + return false; // 1; + // equal cols + if ( rStartPos1.Row() < rStartPos2.Row() ) + return true; // -1; + if ( rStartPos1.Row() > rStartPos2.Row() ) + return false; // 1; + + // first corner equal, second corner + const ScAddress& rEndPos1 = ps1->GetRange(0).aEnd; + const ScAddress& rEndPos2 = ps2->GetRange(0).aEnd; + if ( rEndPos1.Tab() == rEndPos2.Tab() ) + nComp = 0; + else + { + mrDoc.GetName( rEndPos1.Tab(), aStr1 ); + mrDoc.GetName( rEndPos2.Tab(), aStr2 ); + nComp = ScGlobal::GetCollator().compareString( aStr1, aStr2 ); + } + if (nComp < 0) + { + return true; // -1; + } + else if (nComp > 0) + { + return false; // 1; + } + + // equal tabs + if ( rEndPos1.Col() < rEndPos2.Col() ) + return true; // -1; + if ( rEndPos1.Col() > rEndPos2.Col() ) + return false; // 1; + // equal cols + if ( rEndPos1.Row() < rEndPos2.Row() ) + return true; // -1; + if ( rEndPos1.Row() > rEndPos2.Row() ) + return false; // 1; + + return false; + } +private: + ScDocument& mrDoc; +}; + +} + +void ScRangePairList::Join( const ScRangePair& r, bool bIsInList ) +{ + if ( maPairs.empty() ) + { + Append( r ); + return ; + } + + bool bJoinedInput = false; + const ScRangePair* pOver = &r; + +Label_RangePair_Join: + + assert(pOver); + const ScRange& r1 = pOver->GetRange(0); + const ScRange& r2 = pOver->GetRange(1); + const SCCOL nCol1 = r1.aStart.Col(); + const SCROW nRow1 = r1.aStart.Row(); + const SCTAB nTab1 = r1.aStart.Tab(); + const SCCOL nCol2 = r1.aEnd.Col(); + const SCROW nRow2 = r1.aEnd.Row(); + const SCTAB nTab2 = r1.aEnd.Tab(); + + size_t nOverPos = std::numeric_limits<size_t>::max(); + for (size_t i = 0; i < maPairs.size(); ++i) + { + ScRangePair & rPair = maPairs[ i ]; + if ( &rPair == pOver ) + { + nOverPos = i; + continue; // the same one, continue with the next + } + bool bJoined = false; + ScRange& rp1 = rPair.GetRange(0); + ScRange& rp2 = rPair.GetRange(1); + if ( rp2 == r2 ) + { // only if Range2 is equal + if ( rp1.Contains( r1 ) ) + { // RangePair pOver included in or identical to RangePair p + if ( bIsInList ) + bJoined = true; // do away with RangePair pOver + else + { // that was all then + bJoinedInput = true; // don't append + break; // for + } + } + else if ( r1.Contains( rp1 ) ) + { // RangePair p included in RangePair pOver, make pOver the new RangePair + rPair = *pOver; + bJoined = true; + } + } + if ( !bJoined && rp1.aStart.Tab() == nTab1 && rp1.aEnd.Tab() == nTab2 + && rp2.aStart.Tab() == r2.aStart.Tab() + && rp2.aEnd.Tab() == r2.aEnd.Tab() ) + { // 2D, Range2 must be located side-by-side just like Range1 + if ( rp1.aStart.Col() == nCol1 && rp1.aEnd.Col() == nCol2 + && rp2.aStart.Col() == r2.aStart.Col() + && rp2.aEnd.Col() == r2.aEnd.Col() ) + { + if ( rp1.aStart.Row() == nRow2+1 + && rp2.aStart.Row() == r2.aEnd.Row()+1 ) + { // top + rp1.aStart.SetRow( nRow1 ); + rp2.aStart.SetRow( r2.aStart.Row() ); + bJoined = true; + } + else if ( rp1.aEnd.Row() == nRow1-1 + && rp2.aEnd.Row() == r2.aStart.Row()-1 ) + { // bottom + rp1.aEnd.SetRow( nRow2 ); + rp2.aEnd.SetRow( r2.aEnd.Row() ); + bJoined = true; + } + } + else if ( rp1.aStart.Row() == nRow1 && rp1.aEnd.Row() == nRow2 + && rp2.aStart.Row() == r2.aStart.Row() + && rp2.aEnd.Row() == r2.aEnd.Row() ) + { + if ( rp1.aStart.Col() == nCol2+1 + && rp2.aStart.Col() == r2.aEnd.Col()+1 ) + { // left + rp1.aStart.SetCol( nCol1 ); + rp2.aStart.SetCol( r2.aStart.Col() ); + bJoined = true; + } + else if ( rp1.aEnd.Col() == nCol1-1 + && rp2.aEnd.Col() == r2.aEnd.Col()-1 ) + { // right + rp1.aEnd.SetCol( nCol2 ); + rp2.aEnd.SetCol( r2.aEnd.Col() ); + bJoined = true; + } + } + } + if ( bJoined ) + { + if ( bIsInList ) + { // delete RangePair pOver within the list + if (nOverPos != std::numeric_limits<size_t>::max()) + { + Remove(nOverPos); + if (nOverPos < i) + --i; + } + else + { + for (size_t nOver = 0, nRangePairs = maPairs.size(); nOver < nRangePairs; ++nOver) + { + if (&maPairs[nOver] == pOver) + { + maPairs.erase(maPairs.begin() + nOver); + break; + } + } + assert(false); + } + } + bJoinedInput = true; + pOver = &maPairs[i]; + bIsInList = true; + goto Label_RangePair_Join; + } + } + if ( !bIsInList && !bJoinedInput ) + Append( r ); +} + +std::vector<const ScRangePair*> ScRangePairList::CreateNameSortedArray( ScDocument& rDoc ) const +{ + std::vector<const ScRangePair*> aSortedVec(maPairs.size()); + size_t i = 0; + for ( auto const & rPair : maPairs) + { + aSortedVec[i++] = &rPair; + } + + std::sort( aSortedVec.begin(), aSortedVec.end(), ScRangePairList_sortNameCompare(rDoc) ); + + return aSortedVec; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |