diff options
-rw-r--r-- | sc/inc/rangenam.hxx | 15 | ||||
-rw-r--r-- | sc/inc/tokenarray.hxx | 12 | ||||
-rw-r--r-- | sc/qa/unit/ucalc.hxx | 2 | ||||
-rw-r--r-- | sc/qa/unit/ucalc_formula.cxx | 56 | ||||
-rw-r--r-- | sc/source/core/data/documen3.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/data/table1.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/tool/rangenam.cxx | 39 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 85 |
8 files changed, 171 insertions, 42 deletions
diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx index 4a5944f8814b..e3b507e924c8 100644 --- a/sc/inc/rangenam.hxx +++ b/sc/inc/rangenam.hxx @@ -33,6 +33,10 @@ class ScDocument; class ScTokenArray; +namespace sc { + struct RefUpdateContext; +} + typedef sal_uInt16 RangeType; #define RT_NAME ((RangeType)0x0000) @@ -65,7 +69,7 @@ private: SCROW mnMaxRow; SCCOL mnMaxCol; - void CompileRangeData( const String& rSymbol, bool bSetError ); + void CompileRangeData( const OUString& rSymbol, bool bSetError ); void InitCode(); public: @@ -75,7 +79,7 @@ public: SC_DLLPUBLIC ScRangeData( ScDocument* pDoc, const OUString& rName, - const String& rSymbol, + const OUString& rSymbol, const ScAddress& rAdr = ScAddress(), RangeType nType = RT_NAME, const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ); @@ -118,9 +122,7 @@ 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( UpdateRefMode eUpdateRefMode, - const ScRange& r, - SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal = false ); + void UpdateReference( const sc::RefUpdateContext& rCxt, bool bLocal = false ); bool IsModified() const { return bModified; } SC_DLLPUBLIC void GuessPosition(); @@ -181,8 +183,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(UpdateRefMode eUpdateRefMode, const ScRange& rRange, - SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal = false); + void UpdateReference(const sc::RefUpdateContext& rCxt, bool bLocal = false); 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/tokenarray.hxx b/sc/inc/tokenarray.hxx index b3fb5ef375da..71d8c7aa442f 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -133,6 +133,18 @@ public: const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos ); /** + * 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 ); + + /** * Adjust all references on sheet deletion. * * @param nDelPos position of sheet being deleted. diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index 5a1d0aea89e9..241331791c5a 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -90,6 +90,7 @@ public: void testFormulaRefUpdateRange(); void testFormulaRefUpdateSheets(); void testFormulaRefUpdateMove(); + void testFormulaRefUpdateNamedExpression(); void testFuncCOLUMN(); void testFuncROW(); void testFuncSUM(); @@ -282,6 +283,7 @@ public: CPPUNIT_TEST(testFormulaRefUpdateRange); CPPUNIT_TEST(testFormulaRefUpdateSheets); CPPUNIT_TEST(testFormulaRefUpdateMove); + CPPUNIT_TEST(testFormulaRefUpdateNamedExpression); CPPUNIT_TEST(testFuncCOLUMN); CPPUNIT_TEST(testFuncROW); CPPUNIT_TEST(testFuncSUM); diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx index def390273859..68c0f07ae3cb 100644 --- a/sc/qa/unit/ucalc_formula.cxx +++ b/sc/qa/unit/ucalc_formula.cxx @@ -964,6 +964,62 @@ void Test::testFormulaRefUpdateMove() m_pDoc->DeleteTab(0); } +void Test::testFormulaRefUpdateNamedExpression() +{ + m_pDoc->InsertTab(0, "Formula"); + + sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on. + + // Fill C2:C5 with values. + m_pDoc->SetValue(ScAddress(2,1,0), 1); + m_pDoc->SetValue(ScAddress(2,2,0), 2); + m_pDoc->SetValue(ScAddress(2,3,0), 3); + m_pDoc->SetValue(ScAddress(2,4,0), 4); + + // Add a named expression that references the immediate left cell. + ScRangeName* pGlobalNames = m_pDoc->GetRangeName(); + CPPUNIT_ASSERT_MESSAGE("Failed to obtain global named expression object.", pGlobalNames); + ScRangeData* pName = new ScRangeData( + m_pDoc, "ToLeft", "RC[-1]", ScAddress(2,1,0), RT_NAME, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1); + + bool bInserted = pGlobalNames->insert(pName); + CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted); + + // Insert formulas in D2:D5 using the named expression. + m_pDoc->SetString(ScAddress(3,1,0), "=ToLeft"); + m_pDoc->SetString(ScAddress(3,2,0), "=ToLeft"); + m_pDoc->SetString(ScAddress(3,3,0), "=ToLeft"); + m_pDoc->SetString(ScAddress(3,4,0), "=ToLeft"); + + // Make sure the results are correct. + CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(3,1,0)); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(3,2,0)); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(3,3,0)); + CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(3,4,0)); + + // Push cells in column C down by one cell. + m_pDoc->InsertRow(ScRange(2,0,0,2,0,0)); + + // Make sure the results change accordingly. + CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(3,1,0)); + CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(3,2,0)); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(3,3,0)); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(3,4,0)); + + // Move cells back. + m_pDoc->DeleteRow(ScRange(2,0,0,2,0,0)); + + // Make sure the results are back as well. + CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(3,1,0)); + CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(3,2,0)); + CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(3,3,0)); + CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(3,4,0)); + + + + m_pDoc->DeleteTab(0); +} + void Test::testFuncCOLUMN() { m_pDoc->InsertTab(0, "Formula"); diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index 04973f4db031..c9254bc0ce3b 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -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( eUpdateRefMode, aRange, nDx, nDy, nDz ); + pRangeName->UpdateReference(rCxt, false); 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/table1.cxx b/sc/source/core/data/table1.cxx index f4bb6b9aac6e..86e8d1b2bd25 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -1475,7 +1475,7 @@ void ScTable::UpdateReference( // Named expressions need to be updated before formulas acessing them. if (mpRangeName) - mpRangeName->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, true ); + mpRangeName->UpdateReference(rCxt, true); 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 e838b49a412d..0f99769f87ee 100644 --- a/sc/source/core/tool/rangenam.cxx +++ b/sc/source/core/tool/rangenam.cxx @@ -33,6 +33,7 @@ #include "rechead.hxx" #include "refupdat.hxx" #include "document.hxx" +#include "refupdatecontext.hxx" #include "formula/errorcodes.hxx" @@ -46,7 +47,7 @@ using ::std::unary_function; ScRangeData::ScRangeData( ScDocument* pDok, const OUString& rName, - const String& rSymbol, + const OUString& rSymbol, const ScAddress& rAddress, RangeType nType, const FormulaGrammar::Grammar eGrammar ) : @@ -62,7 +63,7 @@ ScRangeData::ScRangeData( ScDocument* pDok, mnMaxRow (-1), mnMaxCol (-1) { - if (rSymbol.Len() > 0) + if (!rSymbol.isEmpty()) CompileRangeData( rSymbol, pDoc->IsImportingXML()); // Let the compiler set an error on unknown names for a subsequent // CompileUnresolvedXML(). @@ -141,7 +142,7 @@ ScRangeData::~ScRangeData() delete pCode; } -void ScRangeData::CompileRangeData( const String& rSymbol, bool bSetError ) +void ScRangeData::CompileRangeData( const OUString& rSymbol, bool bSetError ) { if (eTempGrammar == FormulaGrammar::GRAM_UNSPECIFIED) { @@ -270,34 +271,13 @@ void ScRangeData::UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& rPos, aComp.CreateStringFromTokenArray( rBuffer ); } -void ScRangeData::UpdateReference( UpdateRefMode eUpdateRefMode, - const ScRange& r, - SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal ) +void ScRangeData::UpdateReference( const sc::RefUpdateContext& rCxt, bool /*bLocal*/ ) { bool bChanged = false; - - pCode->Reset(); - if( pCode->GetNextReference() ) - { - bool bSharedFormula = ((eType & RT_SHARED) == RT_SHARED); - ScCompiler aComp( pDoc, aPos, *pCode ); - aComp.SetGrammar(pDoc->GetGrammar()); - const bool bRelRef = aComp.UpdateNameReference( eUpdateRefMode, r, - nDx, nDy, nDz, - bChanged, bSharedFormula, bLocal); - if (bSharedFormula) - { - if (bRelRef) - eType = eType | RT_SHAREDMOD; - else - eType = eType & ~RT_SHAREDMOD; - } - } - - bModified = bChanged; + sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt); + bModified = aRes.mbReferenceModified; } - void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest ) { bool bChanged = false; @@ -733,12 +713,11 @@ ScRangeData* ScRangeName::findByIndex(sal_uInt16 i) const return nPos < maIndexToData.size() ? maIndexToData[nPos] : NULL; } -void ScRangeName::UpdateReference( - UpdateRefMode eUpdateRefMode, const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal) +void ScRangeName::UpdateReference(const sc::RefUpdateContext& rCxt, bool bLocal) { DataType::iterator itr = maData.begin(), itrEnd = maData.end(); for (; itr != itrEnd; ++itr) - itr->second->UpdateReference(eUpdateRefMode, rRange, nDx, nDy, nDz, bLocal); + itr->second->UpdateReference(rCxt, bLocal); } 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 df54e8fbdacc..c5246920c578 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -2156,7 +2156,6 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddres AdjustSingleRefData( rRef1, rOldPos, rNewPos ); if (!bRangeName || !(rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel())) AdjustSingleRefData( rRef2, rOldPos, rNewPos ); - } break; case svSingleRef : @@ -2169,8 +2168,6 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddres // for range names only adjust if all parts are absolute if (!bRangeName || !(rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel())) AdjustSingleRefData( rRef, rOldPos, rNewPos ); - - } break; default: @@ -2536,6 +2533,88 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove( namespace { +bool adjustSingleRefInName( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt ) +{ + if (rRef.IsTabRel()) + // Ignore reference with relative sheet position for now. + 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. + return false; + + bool bChanged = false; + + if (!rRef.IsColRel() && rCxt.mnColDelta) + { + // Adjust absolute column reference. + if (rCxt.maRange.aStart.Col() <= rRef.Col() && rRef.Col() <= rCxt.maRange.aEnd.Col()) + { + rRef.IncCol(rCxt.mnColDelta); + bChanged = true; + } + } + + if (!rRef.IsRowRel() && rCxt.mnRowDelta) + { + // Adjust absolute row reference. + if (rCxt.maRange.aStart.Row() <= rRef.Row() && rRef.Row() <= rCxt.maRange.aEnd.Row()) + { + rRef.IncRow(rCxt.mnRowDelta); + bChanged = true; + } + } + + if (!rRef.IsTabRel() && rCxt.mnTabDelta) + { + // Sheet range has already been checked above. + rRef.IncTab(rCxt.mnTabDelta); + bChanged = true; + } + + return bChanged; +} + +} + +sc::RefUpdateResult ScTokenArray::AdjustReferenceInName( const sc::RefUpdateContext& rCxt ) +{ + sc::RefUpdateResult aRes; + + FormulaToken** p = pCode; + FormulaToken** pEnd = p + static_cast<size_t>(nLen); + for (; p != pEnd; ++p) + { + switch ((*p)->GetType()) + { + case svSingleRef: + { + ScToken* pToken = static_cast<ScToken*>(*p); + ScSingleRefData& rRef = pToken->GetSingleRef(); + if (adjustSingleRefInName(rRef, rCxt)) + aRes.mbReferenceModified = true; + } + break; + case svDoubleRef: + { + ScToken* pToken = static_cast<ScToken*>(*p); + ScComplexRefData& rRef = pToken->GetDoubleRef(); + if (adjustSingleRefInName(rRef.Ref1, rCxt)) + aRes.mbReferenceModified = true; + if (adjustSingleRefInName(rRef.Ref2, rCxt)) + aRes.mbReferenceModified = true; + } + break; + default: + ; + } + } + + return aRes; +} + +namespace { + bool adjustSingleRefOnDeletedTab( ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos ) { ScAddress aAbs = rRef.toAbs(rOldPos); |