sc/inc/document.hxx | 2 - sc/inc/rangenam.hxx | 9 ++++-- sc/inc/refupdatecontext.hxx | 14 +++++++++ sc/inc/table.hxx | 2 - sc/inc/tokenarray.hxx | 4 -- sc/qa/unit/ucalc_formula.cxx | 32 ++++++++++++++++++++++ sc/source/core/data/documen3.cxx | 4 +- sc/source/core/data/formulacell.cxx | 15 ++++++---- sc/source/core/data/refupdatecontext.cxx | 37 ++++++++++++++++++++++++- sc/source/core/data/table1.cxx | 4 +- sc/source/core/tool/rangenam.cxx | 13 +++++--- sc/source/core/tool/token.cxx | 45 +++++++++++++++++++++++-------- 12 files changed, 146 insertions(+), 35 deletions(-)
New commits: commit 8c3e5268785054c988d4cdfe791c1f83cdc46603 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Mon Jul 29 17:51:14 2013 -0400 More on getting named range update to work. Change-Id: Id3f2ffe6d91ae43d799182b3744a839be5e1baf6 diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 39334ee..ea2d65f 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1232,7 +1232,7 @@ public: SC_DLLPUBLIC void CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc ); void UpdateReference( - const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, bool bIncludeDraw = true, + sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, bool bIncludeDraw = true, bool bUpdateNoteCaptionPos = true ); SC_DLLPUBLIC void UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDoc, diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx index e3b507e..a040a6b 100644 --- a/sc/inc/rangenam.hxx +++ b/sc/inc/rangenam.hxx @@ -122,7 +122,12 @@ public: SC_DLLPUBLIC void GetSymbol( OUString& rSymbol, const ScAddress& rPos, const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ) const; void UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress&, const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ); - void UpdateReference( const sc::RefUpdateContext& rCxt, bool bLocal = false ); + + /** + * @param nLocalTab sheet index where this name belongs, or -1 for global + * name. + */ + void UpdateReference( sc::RefUpdateContext& rCxt, SCTAB nLocalTab = -1 ); bool IsModified() const { return bModified; } SC_DLLPUBLIC void GuessPosition(); @@ -183,7 +188,7 @@ public: SC_DLLPUBLIC ScRangeData* findByUpperName(const OUString& rName); SC_DLLPUBLIC const ScRangeData* findByUpperName(const OUString& rName) const; SC_DLLPUBLIC ScRangeData* findByIndex(sal_uInt16 i) const; - void UpdateReference(const sc::RefUpdateContext& rCxt, bool bLocal = false); + void UpdateReference( sc::RefUpdateContext& rCxt, SCTAB nLocalTab = -1 ); void UpdateTabRef(SCTAB nTable, ScRangeData::TabRefUpdateMode eMode, SCTAB nNewTable = 0, SCTAB nNewSheets = 1); void UpdateTranspose(const ScRange& rSource, const ScAddress& rDest); void UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY); diff --git a/sc/inc/refupdatecontext.hxx b/sc/inc/refupdatecontext.hxx index af47851..6bb4e73 100644 --- a/sc/inc/refupdatecontext.hxx +++ b/sc/inc/refupdatecontext.hxx @@ -13,12 +13,18 @@ #include "global.hxx" #include "address.hxx" +#include <boost/unordered_map.hpp> +#include <boost/unordered_set.hpp> + class ScDocument; namespace sc { struct RefUpdateContext { + typedef boost::unordered_set<sal_uInt16> NameIndicesType; + typedef boost::unordered_map<SCTAB, NameIndicesType> UpdatedNamesType; + ScDocument& mrDoc; /** @@ -42,16 +48,24 @@ struct RefUpdateContext /** Amount and direction of movement in the sheet direction. */ SCTAB mnTabDelta; + /** All named expressions that have been updated during this reference + * update run. */ + UpdatedNamesType maUpdatedNames; + RefUpdateContext(ScDocument& rDoc); bool isInserted() const; bool isDeleted() const; + + void setUpdatedName(SCTAB nTab, sal_uInt16 nIndex); + bool isNameUpdated(SCTAB nTab, sal_uInt16 nIndex) const; }; struct RefUpdateResult { bool mbValueChanged; bool mbReferenceModified; + bool mbNameModified; RefUpdateResult(); RefUpdateResult(const RefUpdateResult& r); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 2ce8cac..14c68ec 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -502,7 +502,7 @@ public: bool CompileErrorCells(sal_uInt16 nErrCode); void UpdateReference( - const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, + sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, bool bIncludeDraw = true, bool bUpdateNoteCaptionPos = true ); void UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index 71d8c7a..54bd2fb 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -136,13 +136,11 @@ public: * Adjust all references in named expression. In named expression, we only * update absolute positions, and leave relative positions intact. * - * Also, there is no such thing as the base position in named expressions. - * * @param rCxt context that stores details of shifted region * * @return update result. */ - sc::RefUpdateResult AdjustReferenceInName( const sc::RefUpdateContext& rCxt ); + sc::RefUpdateResult AdjustReferenceInName( const sc::RefUpdateContext& rCxt, const ScAddress& rPos ); /** * Adjust all references on sheet deletion. diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx index 68c0f07..d082c19 100644 --- a/sc/qa/unit/ucalc_formula.cxx +++ b/sc/qa/unit/ucalc_formula.cxx @@ -1015,7 +1015,39 @@ void Test::testFormulaRefUpdateNamedExpression() CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(3,3,0)); CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(3,4,0)); + // Fill B10:B12 with values. + m_pDoc->SetValue(ScAddress(1,9,0), 10); + m_pDoc->SetValue(ScAddress(1,10,0), 11); + m_pDoc->SetValue(ScAddress(1,11,0), 12); + + // Insert a new named expression that references these values as absolute range. + pName = new ScRangeData( + m_pDoc, "MyRange", "$B$10:$B$12", ScAddress(0,0,0), RT_NAME, formula::FormulaGrammar::GRAM_NATIVE); + bInserted = pGlobalNames->insert(pName); + CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted); + + // Set formula at C8 that references this named expression. + m_pDoc->SetString(ScAddress(2,7,0), "=SUM(MyRange)"); + CPPUNIT_ASSERT_EQUAL(33.0, m_pDoc->GetValue(ScAddress(2,7,0))); + + // Shift B10:B12 to right by 2 columns. + m_pDoc->InsertCol(ScRange(1,9,0,2,11,0)); + + // This should shift the absolute range B10:B12 that MyRange references. + pName = pGlobalNames->findByUpperName("MYRANGE"); + CPPUNIT_ASSERT_MESSAGE("Failed to find named expression 'MyRange' in the global scope.", pName); + OUString aExpr; + pName->GetSymbol(aExpr); + CPPUNIT_ASSERT_EQUAL(OUString("$D$10:$D$12"), aExpr); + + // This move shouldn't affect the value of C8. + ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,7,0)); + CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC); + CPPUNIT_ASSERT_EQUAL(33.0, m_pDoc->GetValue(ScAddress(2,7,0))); + // Update the value of D10 and make sure C8 gets updated. + m_pDoc->SetValue(ScAddress(3,9,0), 20); + CPPUNIT_ASSERT_EQUAL(43.0, m_pDoc->GetValue(ScAddress(2,7,0))); m_pDoc->DeleteTab(0); } diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index c9254bc..d8b7530 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -975,7 +975,7 @@ sal_Int64 ScDocument::GetNewUnoId() } void ScDocument::UpdateReference( - const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos ) + sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos ) { if (!ValidRange(rCxt.maRange)) return; @@ -1006,7 +1006,7 @@ void ScDocument::UpdateReference( xRowNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz ); pDBCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz ); if (pRangeName) - pRangeName->UpdateReference(rCxt, false); + pRangeName->UpdateReference(rCxt, -1); if ( pDPCollection ) pDPCollection->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz ); UpdateChartRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz ); diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 11388e8..c6c567f 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2269,6 +2269,7 @@ bool ScFormulaCell::UpdateReferenceOnShift( bool bValChanged = false; bool bRefModified = false; bool bRefSizeChanged = false; + bool bRecompile = bCompile; if (bHasRefs) { @@ -2276,6 +2277,8 @@ bool ScFormulaCell::UpdateReferenceOnShift( sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(rCxt, aOldPos); bRefModified = aRes.mbReferenceModified; bValChanged = aRes.mbValueChanged; + if (aRes.mbNameModified) + bRecompile = true; } if (bValChanged || bRefModified) @@ -2285,7 +2288,6 @@ bool ScFormulaCell::UpdateReferenceOnShift( // Cell may reference itself, e.g. ocColumn, ocRow without parameter bOnRefMove = (bValChanged || (aPos != aOldPos)); - bool bColRowNameCompile = false; bool bHasRelName = false; bool bNewListening = false; bool bInDeleteUndo = false; @@ -2294,8 +2296,8 @@ bool ScFormulaCell::UpdateReferenceOnShift( { // Upon Insert ColRowNames have to be recompiled in case the // insertion occurs right in front of the range. - if (bHasColRowNames) - bColRowNameCompile = checkCompileColRowName(rCxt, *pDocument, *pCode, aOldPos, aPos, bValChanged); + if (bHasColRowNames && !bRecompile) + bRecompile = checkCompileColRowName(rCxt, *pDocument, *pCode, aOldPos, aPos, bValChanged); ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack(); bInDeleteUndo = (pChangeTrack && pChangeTrack->IsInDeleteUndo()); @@ -2304,7 +2306,7 @@ bool ScFormulaCell::UpdateReferenceOnShift( bHasRelName = HasRelNameReference(); // Reference changed and new listening needed? // Except in Insert/Delete without specialties. - bNewListening = (bRefModified || bColRowNameCompile + bNewListening = (bRefModified || bRecompile || (bValChanged && (bInDeleteUndo || bRefSizeChanged)) || bHasRelName); if ( bNewListening ) @@ -2312,12 +2314,13 @@ bool ScFormulaCell::UpdateReferenceOnShift( } // NeedDirty for changes except for Copy and Move/Insert without RelNames - bool bNeedDirty = (bValChanged || bColRowNameCompile || bOnRefMove); + bool bNeedDirty = (bValChanged || bRecompile || bOnRefMove); if (pUndoDoc && (bValChanged || bOnRefMove)) setOldCodeToUndo(pUndoDoc, aUndoPos, pOldCode.get(), eTempGrammar, cMatrixFlag); - if ( (bCompile = (bCompile || bColRowNameCompile)) != 0 ) + bCompile |= bRecompile; + if (bCompile) { CompileTokenArray( bNewListening ); // no Listening bNeedDirty = true; diff --git a/sc/source/core/data/refupdatecontext.cxx b/sc/source/core/data/refupdatecontext.cxx index 67e1242..25ffceb 100644 --- a/sc/source/core/data/refupdatecontext.cxx +++ b/sc/source/core/data/refupdatecontext.cxx @@ -24,9 +24,42 @@ bool RefUpdateContext::isDeleted() const return (meMode == URM_INSDEL) && (mnColDelta < 0 || mnRowDelta < 0 || mnTabDelta < 0); } -RefUpdateResult::RefUpdateResult() : mbValueChanged(false), mbReferenceModified(false) {} +void RefUpdateContext::setUpdatedName(SCTAB nTab, sal_uInt16 nIndex) +{ + UpdatedNamesType::iterator it = maUpdatedNames.find(nTab); + if (it == maUpdatedNames.end()) + { + // Insert a new container for this sheet index. + NameIndicesType aIndices; + std::pair<UpdatedNamesType::iterator,bool> r = + maUpdatedNames.insert(UpdatedNamesType::value_type(nTab, aIndices)); + + if (!r.second) + // Insertion failed for whatever reason. + return; + + it = r.first; + } + + NameIndicesType& rIndices = it->second; + rIndices.insert(nIndex); +} + +bool RefUpdateContext::isNameUpdated(SCTAB nTab, sal_uInt16 nIndex) const +{ + UpdatedNamesType::const_iterator it = maUpdatedNames.find(nTab); + if (it == maUpdatedNames.end()) + return false; + + const NameIndicesType& rIndices = it->second; + return rIndices.count(nIndex) > 0; +} + +RefUpdateResult::RefUpdateResult() : mbValueChanged(false), mbReferenceModified(false), mbNameModified(false) {} RefUpdateResult::RefUpdateResult(const RefUpdateResult& r) : - mbValueChanged(r.mbValueChanged), mbReferenceModified(r.mbReferenceModified) {} + mbValueChanged(r.mbValueChanged), + mbReferenceModified(r.mbReferenceModified), + mbNameModified(r.mbNameModified) {} } diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 86e8d1b..f74c09f 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -1448,7 +1448,7 @@ void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nR } void ScTable::UpdateReference( - const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos ) + sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos ) { bool bUpdated = false; SCCOL i; @@ -1475,7 +1475,7 @@ void ScTable::UpdateReference( // Named expressions need to be updated before formulas acessing them. if (mpRangeName) - mpRangeName->UpdateReference(rCxt, true); + mpRangeName->UpdateReference(rCxt, nTab); for ( ; i<=iMax; i++) bUpdated |= aCol[i].UpdateReference(rCxt, pUndoDoc); diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx index 0f99769..846a208c 100644 --- a/sc/source/core/tool/rangenam.cxx +++ b/sc/source/core/tool/rangenam.cxx @@ -271,11 +271,14 @@ void ScRangeData::UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& rPos, aComp.CreateStringFromTokenArray( rBuffer ); } -void ScRangeData::UpdateReference( const sc::RefUpdateContext& rCxt, bool /*bLocal*/ ) +void ScRangeData::UpdateReference( sc::RefUpdateContext& rCxt, SCTAB nLocalTab ) { - bool bChanged = false; - sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt); + OUString aStr; + rCxt.maRange.Format(aStr, SCR_ABS_3D, pDoc); + sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt, aPos); bModified = aRes.mbReferenceModified; + if (aRes.mbReferenceModified) + rCxt.setUpdatedName(nLocalTab, nIndex); } void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest ) @@ -713,11 +716,11 @@ ScRangeData* ScRangeName::findByIndex(sal_uInt16 i) const return nPos < maIndexToData.size() ? maIndexToData[nPos] : NULL; } -void ScRangeName::UpdateReference(const sc::RefUpdateContext& rCxt, bool bLocal) +void ScRangeName::UpdateReference(sc::RefUpdateContext& rCxt, SCTAB nLocalTab ) { DataType::iterator itr = maData.begin(), itrEnd = maData.end(); for (; itr != itrEnd; ++itr) - itr->second->UpdateReference(rCxt, bLocal); + itr->second->UpdateReference(rCxt, nLocalTab); } void ScRangeName::UpdateTabRef(SCTAB nTable, ScRangeData::TabRefUpdateMode eMode, SCTAB nNewTable, SCTAB nNewSheets) diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index c524692..469063c 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2471,6 +2471,21 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon rRef.SetRange(aAbs, aNewPos); } break; + case svIndex: + { + const formula::FormulaToken* pToken = *p; + if (pToken->GetOpCode() == ocName) + { + SCTAB nTab = -1; + if (!pToken->IsGlobal()) + nTab = rOldPos.Tab(); + + // Check if this named expression has been modified. + if (rCxt.isNameUpdated(nTab, pToken->GetIndex())) + aRes.mbNameModified = true; + } + } + break; default: ; } @@ -2533,19 +2548,26 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove( namespace { -bool adjustSingleRefInName( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt ) +bool adjustSingleRefInName( + ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt, const ScAddress& rPos ) { - if (rRef.IsTabRel()) - // Ignore reference with relative sheet position for now. + ScAddress aAbs = rRef.toAbs(rPos); + + if (aAbs.Tab() < rCxt.maRange.aStart.Tab() || rCxt.maRange.aEnd.Tab() < aAbs.Tab()) + { + // This references a sheet that has not shifted. Don't change it. return false; + } - if (rRef.Tab() < rCxt.maRange.aStart.Tab() || rCxt.maRange.aEnd.Tab() < rRef.Tab()) - // References sheet that has not shifted. Don't change it. + if (rRef.IsColRel() || rRef.IsRowRel()) + { + // Adjust references only when both column and row are absolute. return false; + } bool bChanged = false; - if (!rRef.IsColRel() && rCxt.mnColDelta) + if (rCxt.mnColDelta) { // Adjust absolute column reference. if (rCxt.maRange.aStart.Col() <= rRef.Col() && rRef.Col() <= rCxt.maRange.aEnd.Col()) @@ -2555,7 +2577,7 @@ bool adjustSingleRefInName( ScSingleRefData& rRef, const sc::RefUpdateContext& r } } - if (!rRef.IsRowRel() && rCxt.mnRowDelta) + if (rCxt.mnRowDelta) { // Adjust absolute row reference. if (rCxt.maRange.aStart.Row() <= rRef.Row() && rRef.Row() <= rCxt.maRange.aEnd.Row()) @@ -2577,7 +2599,8 @@ bool adjustSingleRefInName( ScSingleRefData& rRef, const sc::RefUpdateContext& r } -sc::RefUpdateResult ScTokenArray::AdjustReferenceInName( const sc::RefUpdateContext& rCxt ) +sc::RefUpdateResult ScTokenArray::AdjustReferenceInName( + const sc::RefUpdateContext& rCxt, const ScAddress& rPos ) { sc::RefUpdateResult aRes; @@ -2591,7 +2614,7 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceInName( const sc::RefUpdateCont { ScToken* pToken = static_cast<ScToken*>(*p); ScSingleRefData& rRef = pToken->GetSingleRef(); - if (adjustSingleRefInName(rRef, rCxt)) + if (adjustSingleRefInName(rRef, rCxt, rPos)) aRes.mbReferenceModified = true; } break; @@ -2599,9 +2622,9 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceInName( const sc::RefUpdateCont { ScToken* pToken = static_cast<ScToken*>(*p); ScComplexRefData& rRef = pToken->GetDoubleRef(); - if (adjustSingleRefInName(rRef.Ref1, rCxt)) + if (adjustSingleRefInName(rRef.Ref1, rCxt, rPos)) aRes.mbReferenceModified = true; - if (adjustSingleRefInName(rRef.Ref2, rCxt)) + if (adjustSingleRefInName(rRef.Ref2, rCxt, rPos)) aRes.mbReferenceModified = true; } break; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits