summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2016-07-26 16:32:15 +0200
committerEike Rathke <erack@redhat.com>2016-07-26 16:34:30 +0200
commit9710fd565f17278dc5e5ee645b3924544a8c4235 (patch)
treeda9ec3f57dbd9c8caaf6d29a0c2f4718595c1e2d
parentc1b665fcdacd4141137f1e369527e2c0d94513ae (diff)
Resolves: tdf#87474 handle renaming of named expressions/ranges in formulas
Change-Id: If82b62505624c3c259371fa37de1994a94bbceb5
-rw-r--r--sc/inc/document.hxx4
-rw-r--r--sc/inc/rangenam.hxx20
-rw-r--r--sc/source/core/data/document10.cxx48
-rw-r--r--sc/source/core/tool/rangenam.cxx23
-rw-r--r--sc/source/ui/docshell/docfunc.cxx2
-rw-r--r--sc/source/ui/namedlg/namedefdlg.cxx2
-rw-r--r--sc/source/ui/namedlg/namedlg.cxx7
-rw-r--r--sc/source/ui/undo/undorangename.cxx2
8 files changed, 91 insertions, 17 deletions
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 5d034189f120..eccc49cf4603 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -648,8 +648,12 @@ public:
/**
* Call this immediately before updating all named ranges.
*/
+ SC_DLLPUBLIC void PreprocessAllRangeNamesUpdate( const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap );
SC_DLLPUBLIC void PreprocessRangeNameUpdate();
SC_DLLPUBLIC void PreprocessDBDataUpdate();
+ /**
+ * Call this immediately after updating named ranges.
+ */
SC_DLLPUBLIC void CompileHybridFormula();
/**
diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx
index a7a5aa81ccd3..e21c5b3312c0 100644
--- a/sc/inc/rangenam.hxx
+++ b/sc/inc/rangenam.hxx
@@ -60,8 +60,9 @@ public:
};
private:
- OUString aName;
- OUString aUpperName; // #i62977# for faster searching (aName is never modified after ctor)
+ OUString aName;
+ OUString aUpperName; // #i62977# for faster searching (aName is never modified after ctor)
+ OUString maNewName; ///< used for formulas after changing names in the dialog
ScTokenArray* pCode;
ScAddress aPos;
Type eType;
@@ -106,13 +107,15 @@ public:
bool operator== (const ScRangeData& rData) const;
- void GetName( OUString& rName ) const { rName = aName; }
- const OUString& GetName() const { return aName; }
+ void GetName( OUString& rName ) const { rName = maNewName.isEmpty() ? aName : maNewName; }
+ const OUString& GetName() const { return maNewName.isEmpty() ? aName : maNewName; }
const OUString& GetUpperName() const { return aUpperName; }
const ScAddress& GetPos() const { return aPos; }
// The index has to be unique. If index=0 a new index value is assigned.
void SetIndex( sal_uInt16 nInd ) { nIndex = nInd; }
sal_uInt16 GetIndex() const { return nIndex; }
+ /// Does not change the name, but sets maNewName for formula update after dialog.
+ void SetNewName( const OUString& rNewName ) { maNewName = rNewName; }
ScTokenArray* GetCode() { return pCode; }
SC_DLLPUBLIC void SetCode( ScTokenArray& );
const ScTokenArray* GetCode() const { return pCode; }
@@ -244,8 +247,15 @@ public:
@ATTENTION: The underlying ::std::map<std::unique_ptr>::insert(p) takes
ownership of p and if it can't insert it deletes the object! So, if
this insert here returns false the object where p pointed to is gone!
+
+ @param bReuseFreeIndex
+ If the ScRangeData p points to has an index value of 0:
+ If `TRUE` then reuse a free index slot if available.
+ If `FALSE` then assign a new index slot. The Manage Names
+ dialog uses this so that deleting and adding ranges in the same
+ run is guaranteed to not reuse previously assigned indexes.
*/
- SC_DLLPUBLIC bool insert(ScRangeData* p);
+ SC_DLLPUBLIC bool insert( ScRangeData* p, bool bReuseFreeIndex = true );
void erase(const ScRangeData& r);
void erase(const OUString& rName);
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 0530566d3b4c..be9c855aeece 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -227,6 +227,54 @@ void ScDocument::SwapNonEmpty( sc::TableValues& rValues )
aEndCxt.purgeEmptyBroadcasters();
}
+void ScDocument::PreprocessAllRangeNamesUpdate( const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap )
+{
+ // Update all existing names with new names.
+ // The prerequisites are that the name dialog preserves ScRangeData index
+ // for changes and does not reuse free index slots for new names.
+ // ScDocument::SetAllRangeNames() hereafter then will replace the
+ // ScRangeName containers of ScRangeData instances with empty
+ // ScRangeData::maNewName.
+ std::map<OUString, ScRangeName*> aRangeNameMap;
+ GetRangeNameMap( aRangeNameMap);
+ for (const auto& itTab : aRangeNameMap)
+ {
+ ScRangeName* pOldRangeNames = itTab.second;
+ if (!pOldRangeNames)
+ continue;
+
+ const auto& itNewTab( rRangeMap.find( itTab.first));
+ if (itNewTab == rRangeMap.end())
+ continue;
+
+ const ScRangeName* pNewRangeNames = itNewTab->second.get();
+ if (!pNewRangeNames)
+ continue;
+
+ for (ScRangeName::iterator it( pOldRangeNames->begin()), itEnd( pOldRangeNames->end());
+ it != itEnd; ++it)
+ {
+ ScRangeData* pOldData = it->second.get();
+ if (!pOldData)
+ continue;
+
+ const ScRangeData* pNewData = pNewRangeNames->findByIndex( pOldData->GetIndex());
+ if (pNewData)
+ pOldData->SetNewName( pNewData->GetName());
+ }
+ }
+
+ sc::EndListeningContext aEndListenCxt(*this);
+ sc::CompileFormulaContext aCompileCxt(this);
+
+ TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
+ for (; it != itEnd; ++it)
+ {
+ ScTable* p = *it;
+ p->PreprocessRangeNameUpdate(aEndListenCxt, aCompileCxt);
+ }
+}
+
void ScDocument::PreprocessRangeNameUpdate()
{
sc::EndListeningContext aEndListenCxt(*this);
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
index 7626e16ae5f6..19d403d64632 100644
--- a/sc/source/core/tool/rangenam.cxx
+++ b/sc/source/core/tool/rangenam.cxx
@@ -831,7 +831,7 @@ bool ScRangeName::empty() const
return m_Data.empty();
}
-bool ScRangeName::insert(ScRangeData* p)
+bool ScRangeName::insert( ScRangeData* p, bool bReuseFreeIndex )
{
if (!p)
return false;
@@ -839,17 +839,24 @@ bool ScRangeName::insert(ScRangeData* p)
if (!p->GetIndex())
{
// Assign a new index. An index must be unique and is never 0.
- IndexDataType::iterator itr = std::find(
- maIndexToData.begin(), maIndexToData.end(), static_cast<ScRangeData*>(nullptr));
- if (itr != maIndexToData.end())
+ if (bReuseFreeIndex)
{
- // Empty slot exists. Re-use it.
- size_t nPos = std::distance(maIndexToData.begin(), itr);
- p->SetIndex(nPos + 1);
+ IndexDataType::iterator itr = std::find(
+ maIndexToData.begin(), maIndexToData.end(), static_cast<ScRangeData*>(nullptr));
+ if (itr != maIndexToData.end())
+ {
+ // Empty slot exists. Re-use it.
+ size_t nPos = std::distance(maIndexToData.begin(), itr);
+ p->SetIndex(nPos + 1);
+ }
+ else
+ // No empty slot. Append it to the end.
+ p->SetIndex(maIndexToData.size() + 1);
}
else
- // No empty slot. Append it to the end.
+ {
p->SetIndex(maIndexToData.size() + 1);
+ }
}
OUString aName(p->GetUpperName());
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
index d2b1cc852afe..1f4ed8d3fdf6 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -4908,7 +4908,7 @@ void ScDocFunc::ModifyAllRangeNames(const std::map<OUString, std::unique_ptr<ScR
new ScUndoAllRangeNames(&rDocShell, aOldRangeMap, rRangeMap));
}
- rDoc.PreprocessRangeNameUpdate();
+ rDoc.PreprocessAllRangeNamesUpdate(rRangeMap);
rDoc.SetAllRangeNames(rRangeMap);
rDoc.CompileHybridFormula();
diff --git a/sc/source/ui/namedlg/namedefdlg.cxx b/sc/source/ui/namedlg/namedefdlg.cxx
index bb65077b07d5..73a293b7931e 100644
--- a/sc/source/ui/namedlg/namedefdlg.cxx
+++ b/sc/source/ui/namedlg/namedefdlg.cxx
@@ -235,7 +235,7 @@ void ScNameDefDlg::AddPushed()
// aExpression valid?
if ( 0 == pNewEntry->GetErrCode() )
{
- if ( !pRangeName->insert( pNewEntry ) )
+ if ( !pRangeName->insert( pNewEntry, false /*bReuseFreeIndex*/ ) )
pNewEntry = nullptr;
if (mbUndo)
diff --git a/sc/source/ui/namedlg/namedlg.cxx b/sc/source/ui/namedlg/namedlg.cxx
index 4f0164ef724c..ba3d9cd6b77d 100644
--- a/sc/source/ui/namedlg/namedlg.cxx
+++ b/sc/source/ui/namedlg/namedlg.cxx
@@ -405,6 +405,10 @@ void ScNameDlg::NameModified()
// be safe and check for range data
if (pData)
{
+ // Assign new index (0) only if the scope is changed, else keep the
+ // existing index.
+ sal_uInt16 nIndex = (aNewScope != aOldScope ? 0 : pData->GetIndex());
+
pOldRangeName->erase(*pData);
mbNeedUpdate = false;
m_pRangeManagerTable->DeleteSelectedEntries();
@@ -416,7 +420,8 @@ void ScNameDlg::NameModified()
ScRangeData* pNewEntry = new ScRangeData( mpDoc, aNewName, aExpr,
maCursorPos, nType);
- pNewRangeName->insert(pNewEntry);
+ pNewEntry->SetIndex( nIndex);
+ pNewRangeName->insert(pNewEntry, false /*bReuseFreeIndex*/);
aLine.aName = aNewName;
aLine.aExpression = aExpr;
aLine.aScope = aNewScope;
diff --git a/sc/source/ui/undo/undorangename.cxx b/sc/source/ui/undo/undorangename.cxx
index eb42eb442121..f775269a14cb 100644
--- a/sc/source/ui/undo/undorangename.cxx
+++ b/sc/source/ui/undo/undorangename.cxx
@@ -70,7 +70,7 @@ void ScUndoAllRangeNames::DoChange(const std::map<OUString, std::unique_ptr<ScRa
{
ScDocument& rDoc = pDocShell->GetDocument();
- rDoc.PreprocessRangeNameUpdate();
+ rDoc.PreprocessAllRangeNamesUpdate(rNames);
rDoc.SetAllRangeNames(rNames);
rDoc.CompileHybridFormula();