[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - sc/inc sc/qa sc/source
Kohei Yoshida
kohei.yoshida at gmail.com
Mon Jul 29 15:59:27 PDT 2013
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.yoshida at 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;
More information about the Libreoffice-commits
mailing list