sc/inc/document.hxx | 83 ++++++++ sc/source/core/data/document10.cxx | 356 ++++++++++++++++++++++++++++++++++ sc/source/core/data/formulacell.cxx | 372 ------------------------------------ 3 files changed, 444 insertions(+), 367 deletions(-)
New commits: commit 37b071c9330d28f08d5a9f7bf11e577040925684 Author: Eike Rathke <er...@redhat.com> Date: Thu Apr 28 22:42:14 2016 +0200 move to ScDocument::CopyAdjustRangeName() and namespace Change-Id: I1ec3c8cc1b8d3cb899d49192295b14ffac02849a diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index bb46e2d..a38279f 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -600,6 +600,40 @@ public: SCTAB nGlobalRefTab, SCTAB nLocalRefTab, SCTAB nOldTokenTab, SCTAB nOldTokenTabReplacement, bool bSameDoc, int nRecursion ) const; + /** If necessary (name references sheet rOldPos.Tab()) copy and adjust + named expression/range from sheet-local to sheet-local, or global to + sheet-local if bGlobalNamesToLocal==true. + + Also copies nested names and adjusts the ocName tokens of the calling name. + + @param rSheet + On entry, the original sheet of the named expression/range, <0 global. + On return TRUE, the new sheet. Else unchanged. + + @param rIndex + On entry, the original index of the named expression/range. + On return TRUE, the new index, or 0 if a new copied name couldn't be inserted. Else unchanged. + + @param rpRangeData + On entry, the pointer to the original named expression/range. + On return TRUE, the pointer to the new copied name, or nullptr if hit shappened. + + @param rNewPos + New position of formula cell if called for that, else new base + position of a to be created new name adjusted for Tab. + rNewPos.nTab MUST point to the new sheet copied to. + + @param rOldPos + Old position of formula cell if called for that, else base + position of the existing name adjusted for Tab. + rOldPos.nTab MUST point to the old sheet copied from. + + @return TRUE if copied and caller may need to evaluate rpRangeData and rSheet and rIndex. + FALSE if nothing to be done. + */ + bool CopyAdjustRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRangeData*& rpRangeData, ScDocument& rNewDoc, + const ScAddress& rNewPos, const ScAddress& rOldPos, const bool bGlobalNamesToLocal) const; + /** * Call this immediately before updating all named ranges. */ diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index 80375b8..f7ed6e8 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -513,4 +513,296 @@ bool ScDocument::FindRangeNamesReferencingSheet( sc::UpdatedRangeNames& rIndexes return bRef; } +namespace { + +enum MightReferenceSheet +{ + UNKNOWN, + NONE, + CODE, + NAME +}; + +MightReferenceSheet mightRangeNameReferenceSheet( ScRangeData* pData, SCTAB nRefTab) +{ + ScTokenArray* pCode = pData->GetCode(); + if (!pCode) + return MightReferenceSheet::NONE; + + for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next()) + { + if (p->GetOpCode() == ocName) + return MightReferenceSheet::NAME; + } + + return pCode->ReferencesSheet( nRefTab, pData->GetPos().Tab()) ? + MightReferenceSheet::CODE : MightReferenceSheet::NONE; +} + +ScRangeData* copyRangeName( const ScRangeData* pOldRangeData, ScDocument& rNewDoc, const ScDocument* pOldDoc, + const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal, + SCTAB nOldSheet, const SCTAB nNewSheet, bool bSameDoc) +{ + ScAddress aRangePos( pOldRangeData->GetPos()); + if (nNewSheet >= 0) + aRangePos.SetTab( nNewSheet); + ScRangeData* pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc, &aRangePos); + pRangeData->SetIndex(0); // needed for insert to assign a new index + ScTokenArray* pRangeNameToken = pRangeData->GetCode(); + if (bSameDoc && nNewSheet >= 0) + { + if (bGlobalNamesToLocal && nOldSheet < 0) + { + nOldSheet = rOldPos.Tab(); + if (rNewPos.Tab() <= nOldSheet) + // Sheet was inserted before and references already updated. + ++nOldSheet; + } + pRangeNameToken->AdjustSheetLocalNameReferences( nOldSheet, nNewSheet); + } + if (!bSameDoc) + { + pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(), true); + pRangeNameToken->AdjustAbsoluteRefs(pOldDoc, rOldPos, rNewPos, true); + } + + bool bInserted; + if (nNewSheet < 0) + bInserted = rNewDoc.GetRangeName()->insert(pRangeData); + else + bInserted = rNewDoc.GetRangeName(nNewSheet)->insert(pRangeData); + + return bInserted ? pRangeData : nullptr; +} + +struct SheetIndex +{ + SCTAB mnSheet; + sal_uInt16 mnIndex; + + SheetIndex( SCTAB nSheet, sal_uInt16 nIndex ) : mnSheet(nSheet < -1 ? -1 : nSheet), mnIndex(nIndex) {} + bool operator<( const SheetIndex& r ) const + { + // Ascending order sheet, index + if (mnSheet < r.mnSheet) + return true; + if (mnSheet == r.mnSheet) + return mnIndex < r.mnIndex; + return false; + } +}; +typedef std::map< SheetIndex, SheetIndex > SheetIndexMap; + +ScRangeData* copyRangeNames( SheetIndexMap& rSheetIndexMap, std::vector<ScRangeData*>& rRangeDataVec, + const sc::UpdatedRangeNames& rReferencingNames, SCTAB nTab, + const ScRangeData* pOldRangeData, ScDocument& rNewDoc, const ScDocument* pOldDoc, + const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal, + const SCTAB nOldSheet, const SCTAB nNewSheet, bool bSameDoc) +{ + ScRangeData* pRangeData = nullptr; + const ScRangeName* pOldRangeName = (nTab < 0 ? pOldDoc->GetRangeName() : pOldDoc->GetRangeName(nTab)); + if (pOldRangeName) + { + const ScRangeName* pNewRangeName = (nNewSheet < 0 ? rNewDoc.GetRangeName() : rNewDoc.GetRangeName(nNewSheet)); + sc::UpdatedRangeNames::NameIndicesType aSet( rReferencingNames.getUpdatedNames(nTab)); + for (auto const & rIndex : aSet) + { + const ScRangeData* pCopyData = pOldRangeName->findByIndex(rIndex); + if (pCopyData) + { + // Match the original pOldRangeData to adapt the current + // token's values later. For that no check for an already + // copied name is needed as we only enter here if there was + // none. + if (pCopyData == pOldRangeData) + { + pRangeData = copyRangeName( pCopyData, rNewDoc, pOldDoc, rNewPos, rOldPos, + bGlobalNamesToLocal, nOldSheet, nNewSheet, bSameDoc); + if (pRangeData) + { + rRangeDataVec.push_back(pRangeData); + rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()), + SheetIndex( nNewSheet, pRangeData->GetIndex()))); + } + } + else + { + // First check if the name is already available as copy. + const ScRangeData* pFoundData = pNewRangeName->findByUpperName( pCopyData->GetUpperName()); + if (pFoundData) + { + // Just add the resulting sheet/index mapping. + rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()), + SheetIndex( nNewSheet, pFoundData->GetIndex()))); + } + else + { + ScRangeData* pTmpData = copyRangeName( pCopyData, rNewDoc, pOldDoc, rNewPos, rOldPos, + bGlobalNamesToLocal, nOldSheet, nNewSheet, bSameDoc); + if (pTmpData) + { + rRangeDataVec.push_back(pTmpData); + rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()), + SheetIndex( nNewSheet, pTmpData->GetIndex()))); + } + } + } + } + } + } + return pRangeData; +} + +} // namespace + +bool ScDocument::CopyAdjustRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRangeData*& rpRangeData, + ScDocument& rNewDoc, const ScAddress& rNewPos, const ScAddress& rOldPos, const bool bGlobalNamesToLocal) const +{ + const bool bSameDoc = (rNewDoc.GetPool() == const_cast<ScDocument*>(this)->GetPool()); + if (bSameDoc && ((rSheet < 0 && !bGlobalNamesToLocal) || (rSheet >= 0 && rSheet != rOldPos.Tab()))) + // Same doc and global name, if not copied to local name, or + // sheet-local name on other sheet stays the same. + return false; + + // Ensure we don't fiddle with the references until exit. + const SCTAB nOldSheet = rSheet; + const sal_uInt16 nOldIndex = rIndex; + + SAL_WARN_IF( !bSameDoc && nOldSheet >= 0 && nOldSheet != rOldPos.Tab(), + "sc.core", "adjustCopyRangeName - sheet-local name was on other sheet in other document"); + /* TODO: can we do something about that? e.g. loop over sheets? */ + + OUString aRangeName; + ScRangeData* pOldRangeData = nullptr; + + // XXX bGlobalNamesToLocal is also a synonym for copied sheet. + bool bInsertingBefore = (bGlobalNamesToLocal && bSameDoc && rNewPos.Tab() <= rOldPos.Tab()); + + // The Tab where an old local name is to be found or that a global name + // references. May differ below from nOldSheet if a sheet was inserted + // before the old position. Global names and local names other than on the + // old sheet or new sheet are already updated, local names on the old sheet + // or inserted sheet will be updated later. Confusing stuff. Watch out. + SCTAB nOldTab = (nOldSheet < 0 ? rOldPos.Tab() : nOldSheet); + if (bInsertingBefore) + // Sheet was already inserted before old position. + ++nOldTab; + + // Search the name of the RangeName. + if (nOldSheet >= 0) + { + const ScRangeName* pNames = GetRangeName(nOldTab); + pOldRangeData = pNames ? pNames->findByIndex(nOldIndex) : nullptr; + if (!pOldRangeData) + return false; // might be an error in the formula array + aRangeName = pOldRangeData->GetUpperName(); + } + else + { + pOldRangeData = GetRangeName()->findByIndex(nOldIndex); + if (!pOldRangeData) + return false; // might be an error in the formula array + aRangeName = pOldRangeData->GetUpperName(); + } + + // Find corresponding range name in new document. + // First search for local range name then global range names. + SCTAB nNewSheet = rNewPos.Tab(); + ScRangeName* pNewNames = rNewDoc.GetRangeName(nNewSheet); + // Search local range names. + if (pNewNames) + { + rpRangeData = pNewNames->findByUpperName(aRangeName); + } + // Search global range names. + if (!rpRangeData && !bGlobalNamesToLocal) + { + nNewSheet = -1; + pNewNames = rNewDoc.GetRangeName(); + if (pNewNames) + rpRangeData = pNewNames->findByUpperName(aRangeName); + } + // If no range name was found copy it. + if (!rpRangeData) + { + bool bEarlyBailOut = (nOldSheet < 0 && bSameDoc); + MightReferenceSheet eMightReference = mightRangeNameReferenceSheet( pOldRangeData, nOldTab); + if (bEarlyBailOut && eMightReference == MightReferenceSheet::NONE) + return false; + + if (eMightReference == MightReferenceSheet::NAME) + { + // Name these to clarify what is passed where. + const SCTAB nGlobalRefTab = nOldTab; + const SCTAB nLocalRefTab = (bInsertingBefore ? nOldTab-1 : nOldTab); + const SCTAB nOldTokenTab = (nOldSheet < 0 ? (bInsertingBefore ? nOldTab-1 : nOldTab) : nOldSheet); + const SCTAB nOldTokenTabReplacement = nOldTab; + sc::UpdatedRangeNames aReferencingNames; + FindRangeNamesReferencingSheet( aReferencingNames, nOldSheet, nOldIndex, + nGlobalRefTab, nLocalRefTab, nOldTokenTab, nOldTokenTabReplacement, bSameDoc, 0); + if (bEarlyBailOut && aReferencingNames.isEmpty(-1) && aReferencingNames.isEmpty(nOldTokenTabReplacement)) + return false; + + SheetIndexMap aSheetIndexMap; + std::vector<ScRangeData*> aRangeDataVec; + if (!aReferencingNames.isEmpty(nOldTokenTabReplacement)) + { + const SCTAB nTmpOldSheet = (nOldSheet < 0 ? nOldTab : nOldSheet); + nNewSheet = rNewPos.Tab(); + rpRangeData = copyRangeNames( aSheetIndexMap, aRangeDataVec, aReferencingNames, nOldTab, + pOldRangeData, rNewDoc, this, rNewPos, rOldPos, + bGlobalNamesToLocal, nTmpOldSheet, nNewSheet, bSameDoc); + } + if ((bGlobalNamesToLocal || !bSameDoc) && !aReferencingNames.isEmpty(-1)) + { + const SCTAB nTmpOldSheet = -1; + const SCTAB nTmpNewSheet = (bGlobalNamesToLocal ? rNewPos.Tab() : -1); + ScRangeData* pTmpData = copyRangeNames( aSheetIndexMap, aRangeDataVec, aReferencingNames, -1, + pOldRangeData, rNewDoc, this, rNewPos, rOldPos, + bGlobalNamesToLocal, nTmpOldSheet, nTmpNewSheet, bSameDoc); + if (!rpRangeData) + { + rpRangeData = pTmpData; + nNewSheet = nTmpNewSheet; + } + } + + // Adjust copied nested names to new sheet/index. + for (auto & iRD : aRangeDataVec) + { + ScTokenArray* pCode = iRD->GetCode(); + if (pCode) + { + for (formula::FormulaToken* p = pCode->First(); p; p = pCode->Next()) + { + if (p->GetOpCode() == ocName) + { + auto it = aSheetIndexMap.find( SheetIndex( p->GetSheet(), p->GetIndex())); + if (it != aSheetIndexMap.end()) + { + p->SetSheet( it->second.mnSheet); + p->SetIndex( it->second.mnIndex); + } + else if (!bSameDoc) + { + SAL_WARN("sc.core","adjustCopyRangeName - mapping to new name in other doc missing"); + p->SetIndex(0); // #NAME? error instead of arbitrary name. + } + } + } + } + } + } + else + { + nNewSheet = ((nOldSheet < 0 && !bGlobalNamesToLocal) ? -1 : rNewPos.Tab()); + rpRangeData = copyRangeName( pOldRangeData, rNewDoc, this, rNewPos, rOldPos, bGlobalNamesToLocal, + nOldSheet, nNewSheet, bSameDoc); + } + } + rSheet = nNewSheet; + rIndex = rpRangeData ? rpRangeData->GetIndex() : 0; // 0 means not inserted + return true; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index f2a56dd..b61d89c 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -424,320 +424,13 @@ bool lcl_isReference(const FormulaToken& rToken) rToken.GetType() == svDoubleRef; } -enum MightReferenceSheet -{ - UNKNOWN, - NONE, - CODE, - NAME -}; - -MightReferenceSheet mightRangeNameReferenceSheet( ScRangeData* pData, SCTAB nRefTab) -{ - ScTokenArray* pCode = pData->GetCode(); - if (!pCode) - return MightReferenceSheet::NONE; - - for (const FormulaToken* p = pCode->First(); p; p = pCode->Next()) - { - if (p->GetOpCode() == ocName) - return MightReferenceSheet::NAME; - } - - return pCode->ReferencesSheet( nRefTab, pData->GetPos().Tab()) ? - MightReferenceSheet::CODE : MightReferenceSheet::NONE; -} - -ScRangeData* copyRangeName( const ScRangeData* pOldRangeData, ScDocument& rNewDoc, const ScDocument* pOldDoc, - const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal, - SCTAB nOldSheet, const SCTAB nNewSheet, bool bSameDoc) -{ - ScAddress aRangePos( pOldRangeData->GetPos()); - if (nNewSheet >= 0) - aRangePos.SetTab( nNewSheet); - ScRangeData* pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc, &aRangePos); - pRangeData->SetIndex(0); // needed for insert to assign a new index - ScTokenArray* pRangeNameToken = pRangeData->GetCode(); - if (bSameDoc && nNewSheet >= 0) - { - if (bGlobalNamesToLocal && nOldSheet < 0) - { - nOldSheet = rOldPos.Tab(); - if (rNewPos.Tab() <= nOldSheet) - // Sheet was inserted before and references already updated. - ++nOldSheet; - } - pRangeNameToken->AdjustSheetLocalNameReferences( nOldSheet, nNewSheet); - } - if (!bSameDoc) - { - pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(), true); - pRangeNameToken->AdjustAbsoluteRefs(pOldDoc, rOldPos, rNewPos, true); - } - - bool bInserted; - if (nNewSheet < 0) - bInserted = rNewDoc.GetRangeName()->insert(pRangeData); - else - bInserted = rNewDoc.GetRangeName(nNewSheet)->insert(pRangeData); - - return bInserted ? pRangeData : nullptr; -} - -struct SheetIndex -{ - SCTAB mnSheet; - sal_uInt16 mnIndex; - - SheetIndex( SCTAB nSheet, sal_uInt16 nIndex ) : mnSheet(nSheet < -1 ? -1 : nSheet), mnIndex(nIndex) {} - bool operator<( const SheetIndex& r ) const - { - // Ascending order sheet, index - if (mnSheet < r.mnSheet) - return true; - if (mnSheet == r.mnSheet) - return mnIndex < r.mnIndex; - return false; - } -}; -typedef std::map< SheetIndex, SheetIndex > SheetIndexMap; - -ScRangeData* copyRangeNames( SheetIndexMap& rSheetIndexMap, std::vector<ScRangeData*>& rRangeDataVec, - const sc::UpdatedRangeNames& rReferencingNames, SCTAB nTab, - const ScRangeData* pOldRangeData, ScDocument& rNewDoc, const ScDocument* pOldDoc, - const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal, - const SCTAB nOldSheet, const SCTAB nNewSheet, bool bSameDoc) -{ - ScRangeData* pRangeData = nullptr; - const ScRangeName* pOldRangeName = (nTab < 0 ? pOldDoc->GetRangeName() : pOldDoc->GetRangeName(nTab)); - if (pOldRangeName) - { - const ScRangeName* pNewRangeName = (nNewSheet < 0 ? rNewDoc.GetRangeName() : rNewDoc.GetRangeName(nNewSheet)); - sc::UpdatedRangeNames::NameIndicesType aSet( rReferencingNames.getUpdatedNames(nTab)); - for (auto const & rIndex : aSet) - { - const ScRangeData* pCopyData = pOldRangeName->findByIndex(rIndex); - if (pCopyData) - { - // Match the original pOldRangeData to adapt the current - // token's values later. For that no check for an already - // copied name is needed as we only enter here if there was - // none. - if (pCopyData == pOldRangeData) - { - pRangeData = copyRangeName( pCopyData, rNewDoc, pOldDoc, rNewPos, rOldPos, - bGlobalNamesToLocal, nOldSheet, nNewSheet, bSameDoc); - if (pRangeData) - { - rRangeDataVec.push_back(pRangeData); - rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()), - SheetIndex( nNewSheet, pRangeData->GetIndex()))); - } - } - else - { - // First check if the name is already available as copy. - const ScRangeData* pFoundData = pNewRangeName->findByUpperName( pCopyData->GetUpperName()); - if (pFoundData) - { - // Just add the resulting sheet/index mapping. - rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()), - SheetIndex( nNewSheet, pFoundData->GetIndex()))); - } - else - { - ScRangeData* pTmpData = copyRangeName( pCopyData, rNewDoc, pOldDoc, rNewPos, rOldPos, - bGlobalNamesToLocal, nOldSheet, nNewSheet, bSameDoc); - if (pTmpData) - { - rRangeDataVec.push_back(pTmpData); - rSheetIndexMap.insert( std::make_pair( SheetIndex( nOldSheet, pCopyData->GetIndex()), - SheetIndex( nNewSheet, pTmpData->GetIndex()))); - } - } - } - } - } - } - return pRangeData; -} - -/** Adjust or copy name from sheet-local to sheet-local, or global to - sheet-local if bGlobalNamesToLocal==true. - - @param rSheet - On entry, the original sheet of the named expression/range, <0 global. - On return TRUE, the new sheet. Else unchanged. - - @param rIndex - On entry, the original index of the named expression/range. - On return TRUE, the new index, or 0 if a new copied name couldn't be inserted. Else unchanged. - - @param rpRangeData - On entry, the pointer to the original named expression/range. - On return TRUE, the pointer to the new copied name, or nullptr if hit shappened. - - @return TRUE if copied and caller may need to evaluate rpRangeData and rSheet and rIndex. - FALSE if nothing to be done. - */ -bool adjustCopyRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRangeData*& rpRangeData, - ScDocument& rNewDoc, const ScDocument* pOldDoc, - const ScAddress& rNewPos, const ScAddress& rOldPos, const bool bGlobalNamesToLocal) -{ - const bool bSameDoc = (rNewDoc.GetPool() == const_cast<ScDocument*>(pOldDoc)->GetPool()); - if (bSameDoc && ((rSheet < 0 && !bGlobalNamesToLocal) || (rSheet >= 0 && rSheet != rOldPos.Tab()))) - // Same doc and global name, if not copied to local name, or - // sheet-local name on other sheet stays the same. - return false; - - // Ensure we don't fiddle with the references until exit. - const SCTAB nOldSheet = rSheet; - const sal_uInt16 nOldIndex = rIndex; - - SAL_WARN_IF( !bSameDoc && nOldSheet >= 0 && nOldSheet != rOldPos.Tab(), - "sc.core", "adjustCopyRangeName - sheet-local name was on other sheet in other document"); - /* TODO: can we do something about that? e.g. loop over sheets? */ - - OUString aRangeName; - ScRangeData* pOldRangeData = nullptr; - - // XXX bGlobalNamesToLocal is also a synonym for copied sheet. - bool bInsertingBefore = (bGlobalNamesToLocal && bSameDoc && rNewPos.Tab() <= rOldPos.Tab()); - - // The Tab where an old local name is to be found or that a global name - // references. May differ below from nOldSheet if a sheet was inserted - // before the old position. Global names and local names other than on the - // old sheet or new sheet are already updated, local names on the old sheet - // or inserted sheet will be updated later. Confusing stuff. Watch out. - SCTAB nOldTab = (nOldSheet < 0 ? rOldPos.Tab() : nOldSheet); - if (bInsertingBefore) - // Sheet was already inserted before old position. - ++nOldTab; - - // Search the name of the RangeName. - if (nOldSheet >= 0) - { - const ScRangeName* pRangeName = pOldDoc->GetRangeName(nOldTab); - pOldRangeData = pRangeName ? pRangeName->findByIndex(nOldIndex) : nullptr; - if (!pOldRangeData) - return false; // might be an error in the formula array - aRangeName = pOldRangeData->GetUpperName(); - } - else - { - pOldRangeData = pOldDoc->GetRangeName()->findByIndex(nOldIndex); - if (!pOldRangeData) - return false; // might be an error in the formula array - aRangeName = pOldRangeData->GetUpperName(); - } - - // Find corresponding range name in new document. - // First search for local range name then global range names. - SCTAB nNewSheet = rNewPos.Tab(); - ScRangeName* pRangeName = rNewDoc.GetRangeName(nNewSheet); - // Search local range names. - if (pRangeName) - { - rpRangeData = pRangeName->findByUpperName(aRangeName); - } - // Search global range names. - if (!rpRangeData && !bGlobalNamesToLocal) - { - nNewSheet = -1; - pRangeName = rNewDoc.GetRangeName(); - if (pRangeName) - rpRangeData = pRangeName->findByUpperName(aRangeName); - } - // If no range name was found copy it. - if (!rpRangeData) - { - bool bEarlyBailOut = (nOldSheet < 0 && bSameDoc); - MightReferenceSheet eMightReference = mightRangeNameReferenceSheet( pOldRangeData, nOldTab); - if (bEarlyBailOut && eMightReference == MightReferenceSheet::NONE) - return false; - - if (eMightReference == MightReferenceSheet::NAME) - { - // Name these to clarify what is passed where. - const SCTAB nGlobalRefTab = nOldTab; - const SCTAB nLocalRefTab = (bInsertingBefore ? nOldTab-1 : nOldTab); - const SCTAB nOldTokenTab = (nOldSheet < 0 ? (bInsertingBefore ? nOldTab-1 : nOldTab) : nOldSheet); - const SCTAB nOldTokenTabReplacement = nOldTab; - sc::UpdatedRangeNames aReferencingNames; - pOldDoc->FindRangeNamesReferencingSheet( aReferencingNames, nOldSheet, nOldIndex, - nGlobalRefTab, nLocalRefTab, nOldTokenTab, nOldTokenTabReplacement, bSameDoc, 0); - if (bEarlyBailOut && aReferencingNames.isEmpty(-1) && aReferencingNames.isEmpty(nOldTokenTabReplacement)) - return false; - - SheetIndexMap aSheetIndexMap; - std::vector<ScRangeData*> aRangeDataVec; - if (!aReferencingNames.isEmpty(nOldTokenTabReplacement)) - { - const SCTAB nTmpOldSheet = (nOldSheet < 0 ? nOldTab : nOldSheet); - nNewSheet = rNewPos.Tab(); - rpRangeData = copyRangeNames( aSheetIndexMap, aRangeDataVec, aReferencingNames, nOldTab, - pOldRangeData, rNewDoc, pOldDoc, rNewPos, rOldPos, - bGlobalNamesToLocal, nTmpOldSheet, nNewSheet, bSameDoc); - } - if ((bGlobalNamesToLocal || !bSameDoc) && !aReferencingNames.isEmpty(-1)) - { - const SCTAB nTmpOldSheet = -1; - const SCTAB nTmpNewSheet = (bGlobalNamesToLocal ? rNewPos.Tab() : -1); - ScRangeData* pTmpData = copyRangeNames( aSheetIndexMap, aRangeDataVec, aReferencingNames, -1, - pOldRangeData, rNewDoc, pOldDoc, rNewPos, rOldPos, - bGlobalNamesToLocal, nTmpOldSheet, nTmpNewSheet, bSameDoc); - if (!rpRangeData) - { - rpRangeData = pTmpData; - nNewSheet = nTmpNewSheet; - } - } - - // Adjust copied nested names to new sheet/index. - for (auto & iRD : aRangeDataVec) - { - ScTokenArray* pCode = iRD->GetCode(); - if (pCode) - { - for (FormulaToken* p = pCode->First(); p; p = pCode->Next()) - { - if (p->GetOpCode() == ocName) - { - auto it = aSheetIndexMap.find( SheetIndex( p->GetSheet(), p->GetIndex())); - if (it != aSheetIndexMap.end()) - { - p->SetSheet( it->second.mnSheet); - p->SetIndex( it->second.mnIndex); - } - else if (!bSameDoc) - { - SAL_WARN("sc.core","adjustCopyRangeName - mapping to new name in other doc missing"); - p->SetIndex(0); // #NAME? error instead of arbitrary name. - } - } - } - } - } - } - else - { - nNewSheet = ((nOldSheet < 0 && !bGlobalNamesToLocal) ? -1 : rNewPos.Tab()); - rpRangeData = copyRangeName( pOldRangeData, rNewDoc, pOldDoc, rNewPos, rOldPos, bGlobalNamesToLocal, - nOldSheet, nNewSheet, bSameDoc); - } - } - rSheet = nNewSheet; - rIndex = rpRangeData ? rpRangeData->GetIndex() : 0; // 0 means not inserted - return true; -} - void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal) { ScRangeData* pRangeData = nullptr; SCTAB nSheet = pToken->GetSheet(); sal_uInt16 nIndex = pToken->GetIndex(); - if (!adjustCopyRangeName( nSheet, nIndex, pRangeData, rNewDoc, pOldDoc, rNewPos, rOldPos, bGlobalNamesToLocal)) + if (!pOldDoc->CopyAdjustRangeName( nSheet, nIndex, pRangeData, rNewDoc, rNewPos, rOldPos, bGlobalNamesToLocal)) return; // nothing to do if (!pRangeData) commit 75d588556ebe7f542673de67e87a6cb570ef75d1 Author: Eike Rathke <er...@redhat.com> Date: Thu Apr 28 20:41:25 2016 +0200 move to ScDocument::FindRangeNamesReferencingSheet() Change-Id: I8ddd83eca3eaf0bd04c8c73a16329517ec3c21b3 diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index d04e896..bb46e2d 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -80,6 +80,7 @@ struct SortUndoParam; struct ReorderParam; class FormulaGroupAreaListener; class ColumnSet; +class UpdatedRangeNames; } @@ -551,6 +552,54 @@ public: */ ScRangeData* FindRangeNameBySheetAndIndex( SCTAB nTab, sal_uInt16 nIndex ) const; + /** Recursively find all named expressions that directly or indirectly + (nested) reference a given sheet, starting from a given named + expression nTokenTab/nTokenIndex. + + Used to collect all named expressions/ranges that will need to be + copied along when copying sheets. + + The different tab/sheets passed cater for the situation that a sheet is + copied and was already inserted and global names are already adjusted + but the sheet-local names of the shifted original sheet are not yet. If + no sheet was inserted and global and local names' references not + updated yet, then all 4 tab arguments would be identical. + + @param nTokenTab + Tab/sheet on which to find the name, -1 if global scope. + For example obtained from ocName token. + + @param nTokenIndex + Index of named expression. For example obtained from ocName token. + + @param nGlobalRefTab + Tab to check if used in global names. + + @param nLocalRefTab + Tab to check if used in sheet-local names. + + @param nOldTokenTab + The original tab of the copied sheet, used as sheet-local + base position for relative references. + + @param nOldTokenTabReplacement + The replacement to use for relative references if the name + encountered uses nOldTokenTab as base position. + + @param bSameDoc + FALSE if collecting names for a sheet to be copied to another + document. Then all names encountered are considered to be + referencing the sheet. Else TRUE if collecting names to be + copied into the same document. + + @param nRecursion + Recursion guard, initialize with 0. + */ + bool FindRangeNamesReferencingSheet( sc::UpdatedRangeNames& rIndexes, + SCTAB nTokenTab, const sal_uInt16 nTokenIndex, + SCTAB nGlobalRefTab, SCTAB nLocalRefTab, SCTAB nOldTokenTab, SCTAB nOldTokenTabReplacement, + bool bSameDoc, int nRecursion ) const; + /** * Call this immediately before updating all named ranges. */ diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index 5e8678d..80375b8 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -23,6 +23,7 @@ #include "dociter.hxx" #include "patattr.hxx" +#include "refupdatecontext.hxx" #include <svl/whiter.hxx> #include <editeng/colritem.hxx> #include "scitems.hxx" @@ -449,4 +450,67 @@ void ScDocument::finalizeOutlineImport() } } +bool ScDocument::FindRangeNamesReferencingSheet( sc::UpdatedRangeNames& rIndexes, + SCTAB nTokenTab, const sal_uInt16 nTokenIndex, + SCTAB nGlobalRefTab, SCTAB nLocalRefTab, SCTAB nOldTokenTab, SCTAB nOldTokenTabReplacement, + bool bSameDoc, int nRecursion) const +{ + if (nTokenTab < -1) + { + SAL_WARN("sc.core", "ScDocument::FindRangeNamesReferencingSheet - nTokenTab < -1 : " << + nTokenTab << ", nTokenIndex " << nTokenIndex << " Fix the creator!"); +#if OSL_DEBUG_LEVEL > 0 + const ScRangeData* pData = FindRangeNameBySheetAndIndex( nTokenTab, nTokenIndex); + SAL_WARN_IF( pData, "sc.core", "ScDocument::FindRangeNamesReferencingSheet - named expression is: " << pData->GetName()); +#endif + nTokenTab = -1; + } + SCTAB nRefTab = nGlobalRefTab; + if (nTokenTab == nOldTokenTab) + { + nTokenTab = nOldTokenTabReplacement; + nRefTab = nLocalRefTab; + } + else if (nTokenTab == nOldTokenTabReplacement) + { + nRefTab = nLocalRefTab; + } + + if (rIndexes.isNameUpdated( nTokenTab, nTokenIndex)) + return true; + + ScRangeData* pData = FindRangeNameBySheetAndIndex( nTokenTab, nTokenIndex); + if (!pData) + return false; + + ScTokenArray* pCode = pData->GetCode(); + if (!pCode) + return false; + + bool bRef = !bSameDoc; // include every name used when copying to other doc + if (nRecursion < 126) // whatever.. 42*3 + { + for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next()) + { + if (p->GetOpCode() == ocName) + { + bRef |= FindRangeNamesReferencingSheet( rIndexes, p->GetSheet(), p->GetIndex(), + nGlobalRefTab, nLocalRefTab, nOldTokenTab, nOldTokenTabReplacement, bSameDoc, nRecursion+1); + } + } + } + + if (!bRef) + { + SCTAB nPosTab = pData->GetPos().Tab(); + if (nPosTab == nOldTokenTab) + nPosTab = nOldTokenTabReplacement; + bRef = pCode->ReferencesSheet( nRefTab, nPosTab); + } + if (bRef) + rIndexes.setUpdatedName( nTokenTab, nTokenIndex); + + return bRef; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index ec7b454..f2a56dd 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -448,80 +448,6 @@ MightReferenceSheet mightRangeNameReferenceSheet( ScRangeData* pData, SCTAB nRef MightReferenceSheet::CODE : MightReferenceSheet::NONE; } -// See also lcl_FindRangeNamesInUse() below. -/** Recursively find all named expressions that directly or indirectly (nested) - reference a given sheet, starting from a given named expression - nTokenTab/nTokenIndex. - - @param nTokenTab - Tab/sheet on which to find the name, -1 if global scope. Obtained - from ocName token. - - @param nTokenIndex - Index of named expression. Obtained from ocName token. - */ -bool findRangeNamesReferencingSheet( sc::UpdatedRangeNames& rIndexes, SCTAB nTokenTab, const sal_uInt16 nTokenIndex, - const ScDocument* pDoc, SCTAB nGlobalRefTab, SCTAB nLocalRefTab, - SCTAB nOldTokenTab, SCTAB nOldTokenTabReplacement, bool bSameDoc, int nRecursion) -{ - if (nTokenTab < -1) - { - SAL_WARN("sc.core", "findRangeNamesReferencingSheet - nTokenTab < -1 : " << - nTokenTab << ", nTokenIndex " << nTokenIndex << " Fix the creator!"); -#if OSL_DEBUG_LEVEL > 0 - const ScRangeData* pData = pDoc->FindRangeNameBySheetAndIndex( nTokenTab, nTokenIndex); - SAL_WARN_IF( pData, "sc.core", "findRangeNamesReferencingSheet - named expression is: " << pData->GetName()); -#endif - nTokenTab = -1; - } - SCTAB nRefTab = nGlobalRefTab; - if (nTokenTab == nOldTokenTab) - { - nTokenTab = nOldTokenTabReplacement; - nRefTab = nLocalRefTab; - } - else if (nTokenTab == nOldTokenTabReplacement) - { - nRefTab = nLocalRefTab; - } - - if (rIndexes.isNameUpdated( nTokenTab, nTokenIndex)) - return true; - - ScRangeData* pData = pDoc->FindRangeNameBySheetAndIndex( nTokenTab, nTokenIndex); - if (!pData) - return false; - - ScTokenArray* pCode = pData->GetCode(); - if (!pCode) - return false; - - bool bRef = !bSameDoc; // include every name used when copying to other doc - if (nRecursion < 126) // whatever.. 42*3 - { - for (const FormulaToken* p = pCode->First(); p; p = pCode->Next()) - { - if (p->GetOpCode() == ocName) - { - bRef |= findRangeNamesReferencingSheet( rIndexes, p->GetSheet(), p->GetIndex(), pDoc, - nGlobalRefTab, nLocalRefTab, nOldTokenTab, nOldTokenTabReplacement, bSameDoc, nRecursion+1); - } - } - } - - if (!bRef) - { - SCTAB nPosTab = pData->GetPos().Tab(); - if (nPosTab == nOldTokenTab) - nPosTab = nOldTokenTabReplacement; - bRef = pCode->ReferencesSheet( nRefTab, nPosTab); - } - if (bRef) - rIndexes.setUpdatedName( nTokenTab, nTokenIndex); - - return bRef; -} - ScRangeData* copyRangeName( const ScRangeData* pOldRangeData, ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal, SCTAB nOldSheet, const SCTAB nNewSheet, bool bSameDoc) @@ -738,7 +664,7 @@ bool adjustCopyRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRangeData*& rpRan const SCTAB nOldTokenTab = (nOldSheet < 0 ? (bInsertingBefore ? nOldTab-1 : nOldTab) : nOldSheet); const SCTAB nOldTokenTabReplacement = nOldTab; sc::UpdatedRangeNames aReferencingNames; - findRangeNamesReferencingSheet( aReferencingNames, nOldSheet, nOldIndex, pOldDoc, + pOldDoc->FindRangeNamesReferencingSheet( aReferencingNames, nOldSheet, nOldIndex, nGlobalRefTab, nLocalRefTab, nOldTokenTab, nOldTokenTabReplacement, bSameDoc, 0); if (bEarlyBailOut && aReferencingNames.isEmpty(-1) && aReferencingNames.isEmpty(nOldTokenTabReplacement)) return false; @@ -4020,7 +3946,7 @@ void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY StartListeningTo( pDocument ); // Listener as previous } -// See also findRangeNamesReferencingSheet() above. +// See also ScDocument::FindRangeNamesReferencingSheet() static void lcl_FindRangeNamesInUse(sc::UpdatedRangeNames& rIndexes, ScTokenArray* pCode, const ScDocument* pDoc, int nRecursion) { commit c692b9cda192c8e31ddd59a9a9598c7e798e80d9 Author: Eike Rathke <er...@redhat.com> Date: Thu Apr 28 19:07:56 2016 +0200 adjustCopyRangeName: pass rSheet, rIndex; encapsulate nNewSheet Change-Id: I3de5982b8b8ad179010787ed7be721be54f761af diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 280c1eb..ec7b454 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -636,20 +636,38 @@ ScRangeData* copyRangeNames( SheetIndexMap& rSheetIndexMap, std::vector<ScRangeD return pRangeData; } -/** Adjust or copy name. - @return TRUE if copied and caller may need to evaluate rpRangeData and rNewSheet. +/** Adjust or copy name from sheet-local to sheet-local, or global to + sheet-local if bGlobalNamesToLocal==true. + + @param rSheet + On entry, the original sheet of the named expression/range, <0 global. + On return TRUE, the new sheet. Else unchanged. + + @param rIndex + On entry, the original index of the named expression/range. + On return TRUE, the new index, or 0 if a new copied name couldn't be inserted. Else unchanged. + + @param rpRangeData + On entry, the pointer to the original named expression/range. + On return TRUE, the pointer to the new copied name, or nullptr if hit shappened. + + @return TRUE if copied and caller may need to evaluate rpRangeData and rSheet and rIndex. FALSE if nothing to be done. */ -bool adjustCopyRangeName( const SCTAB nOldSheet, const sal_uInt16 nOldIndex, - ScRangeData*& rpRangeData, SCTAB& rNewSheet, ScDocument& rNewDoc, const ScDocument* pOldDoc, +bool adjustCopyRangeName( SCTAB& rSheet, sal_uInt16& rIndex, ScRangeData*& rpRangeData, + ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& rNewPos, const ScAddress& rOldPos, const bool bGlobalNamesToLocal) { const bool bSameDoc = (rNewDoc.GetPool() == const_cast<ScDocument*>(pOldDoc)->GetPool()); - if (bSameDoc && ((nOldSheet < 0 && !bGlobalNamesToLocal) || (nOldSheet >= 0 && nOldSheet != rOldPos.Tab()))) + if (bSameDoc && ((rSheet < 0 && !bGlobalNamesToLocal) || (rSheet >= 0 && rSheet != rOldPos.Tab()))) // Same doc and global name, if not copied to local name, or // sheet-local name on other sheet stays the same. return false; + // Ensure we don't fiddle with the references until exit. + const SCTAB nOldSheet = rSheet; + const sal_uInt16 nOldIndex = rIndex; + SAL_WARN_IF( !bSameDoc && nOldSheet >= 0 && nOldSheet != rOldPos.Tab(), "sc.core", "adjustCopyRangeName - sheet-local name was on other sheet in other document"); /* TODO: can we do something about that? e.g. loop over sheets? */ @@ -689,8 +707,8 @@ bool adjustCopyRangeName( const SCTAB nOldSheet, const sal_uInt16 nOldIndex, // Find corresponding range name in new document. // First search for local range name then global range names. - rNewSheet = rNewPos.Tab(); - ScRangeName* pRangeName = rNewDoc.GetRangeName(rNewSheet); + SCTAB nNewSheet = rNewPos.Tab(); + ScRangeName* pRangeName = rNewDoc.GetRangeName(nNewSheet); // Search local range names. if (pRangeName) { @@ -699,7 +717,7 @@ bool adjustCopyRangeName( const SCTAB nOldSheet, const sal_uInt16 nOldIndex, // Search global range names. if (!rpRangeData && !bGlobalNamesToLocal) { - rNewSheet = -1; + nNewSheet = -1; pRangeName = rNewDoc.GetRangeName(); if (pRangeName) rpRangeData = pRangeName->findByUpperName(aRangeName); @@ -730,10 +748,10 @@ bool adjustCopyRangeName( const SCTAB nOldSheet, const sal_uInt16 nOldIndex, if (!aReferencingNames.isEmpty(nOldTokenTabReplacement)) { const SCTAB nTmpOldSheet = (nOldSheet < 0 ? nOldTab : nOldSheet); - rNewSheet = rNewPos.Tab(); + nNewSheet = rNewPos.Tab(); rpRangeData = copyRangeNames( aSheetIndexMap, aRangeDataVec, aReferencingNames, nOldTab, pOldRangeData, rNewDoc, pOldDoc, rNewPos, rOldPos, - bGlobalNamesToLocal, nTmpOldSheet, rNewSheet, bSameDoc); + bGlobalNamesToLocal, nTmpOldSheet, nNewSheet, bSameDoc); } if ((bGlobalNamesToLocal || !bSameDoc) && !aReferencingNames.isEmpty(-1)) { @@ -745,7 +763,7 @@ bool adjustCopyRangeName( const SCTAB nOldSheet, const sal_uInt16 nOldIndex, if (!rpRangeData) { rpRangeData = pTmpData; - rNewSheet = nTmpNewSheet; + nNewSheet = nTmpNewSheet; } } @@ -777,11 +795,13 @@ bool adjustCopyRangeName( const SCTAB nOldSheet, const sal_uInt16 nOldIndex, } else { - rNewSheet = ((nOldSheet < 0 && !bGlobalNamesToLocal) ? -1 : rNewPos.Tab()); + nNewSheet = ((nOldSheet < 0 && !bGlobalNamesToLocal) ? -1 : rNewPos.Tab()); rpRangeData = copyRangeName( pOldRangeData, rNewDoc, pOldDoc, rNewPos, rOldPos, bGlobalNamesToLocal, - nOldSheet, rNewSheet, bSameDoc); + nOldSheet, nNewSheet, bSameDoc); } } + rSheet = nNewSheet; + rIndex = rpRangeData ? rpRangeData->GetIndex() : 0; // 0 means not inserted return true; } @@ -789,9 +809,9 @@ void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const S const ScAddress& rNewPos, const ScAddress& rOldPos, bool bGlobalNamesToLocal) { ScRangeData* pRangeData = nullptr; - SCTAB nNewSheet = rNewPos.Tab(); - if (!adjustCopyRangeName( pToken->GetSheet(), pToken->GetIndex(), pRangeData, nNewSheet, rNewDoc, pOldDoc, - rNewPos, rOldPos, bGlobalNamesToLocal)) + SCTAB nSheet = pToken->GetSheet(); + sal_uInt16 nIndex = pToken->GetIndex(); + if (!adjustCopyRangeName( nSheet, nIndex, pRangeData, rNewDoc, pOldDoc, rNewPos, rOldPos, bGlobalNamesToLocal)) return; // nothing to do if (!pRangeData) @@ -802,9 +822,8 @@ void adjustRangeName(formula::FormulaToken* pToken, ScDocument& rNewDoc, const S return; } - sal_Int32 nIndex = pRangeData->GetIndex(); pToken->SetIndex(nIndex); - pToken->SetSheet(nNewSheet); + pToken->SetSheet(nSheet); } void adjustDBRange(formula::FormulaToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits