summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2015-09-04 18:30:22 +0200
committerEike Rathke <erack@redhat.com>2015-09-04 21:14:41 +0200
commit679a5dc0cf838579e320dd199f02a9a8300c8820 (patch)
tree406ff67a3115b3943f4fcd76d9b697cd7bb35b0d /sc
parent6d64d2f38d9f6c2f54e05675ecd0709eabf6d8ca (diff)
TableRef: update table column names when cell content changed
Change-Id: Id699358c7dae635b13ed4b981326a6490255a4d4
Diffstat (limited to 'sc')
-rw-r--r--sc/inc/dbdata.hxx41
-rw-r--r--sc/inc/document.hxx1
-rw-r--r--sc/source/core/data/documen3.cxx6
-rw-r--r--sc/source/core/tool/dbdata.cxx230
-rw-r--r--sc/source/ui/docshell/docsh.cxx1
5 files changed, 242 insertions, 37 deletions
diff --git a/sc/inc/dbdata.hxx b/sc/inc/dbdata.hxx
index bf1ac4cb8c2e..7584f6751651 100644
--- a/sc/inc/dbdata.hxx
+++ b/sc/inc/dbdata.hxx
@@ -24,6 +24,9 @@
#include "refreshtimer.hxx"
#include "address.hxx"
#include "global.hxx"
+#include "rangelst.hxx"
+
+#include <svl/listener.hxx>
#include <boost/scoped_ptr.hpp>
@@ -45,7 +48,21 @@ enum class ScDBDataPortion
AREA ///< entire area
};
-class ScDBData : public ScRefreshTimer
+/** Container base class to provide selected access for ScDBData. */
+class ScDBDataContainerBase
+{
+public:
+ ScDBDataContainerBase( ScDocument& rDoc ) : mrDoc(rDoc) {}
+ virtual ~ScDBDataContainerBase() {}
+ ScDocument* GetDocument() const;
+ ScRangeList& GetDirtyTableColumnNames();
+
+protected:
+ ScDocument& mrDoc;
+ ScRangeList maDirtyTableColumnNames;
+};
+
+class ScDBData : public SvtListener, public ScRefreshTimer
{
private:
boost::scoped_ptr<ScSortParam> mpSortParam;
@@ -53,6 +70,8 @@ private:
boost::scoped_ptr<ScSubTotalParam> mpSubTotal;
boost::scoped_ptr<ScImportParam> mpImportParam;
+ ScDBDataContainerBase* mpContainer;
+
/// DBParam
const OUString aName;
OUString aUpper;
@@ -79,6 +98,7 @@ private:
bool bModified; ///< is set/cleared for/by(?) UpdateReference
::std::vector< OUString > maTableColumnNames; ///< names of table columns
+ bool mbTableColumnNamesDirty;
using ScRefreshTimer::operator==;
@@ -96,7 +116,9 @@ public:
ScDBData(const OUString& rName, const ScDBData& rData);
virtual ~ScDBData();
- ScDBData& operator= (const ScDBData& rData);
+ virtual void Notify( const SfxHint& rHint ) SAL_OVERRIDE;
+
+ ScDBData& operator= (const ScDBData& rData) ;
bool operator== (const ScDBData& rData) const;
@@ -119,8 +141,13 @@ public:
void SetKeepFmt(bool bSet) { bKeepFmt = bSet; }
bool IsStripData() const { return bStripData; }
void SetStripData(bool bSet) { bStripData = bSet; }
- void SetTableColumnNames( const ::std::vector< OUString >& rNames ) { maTableColumnNames = rNames; }
- const ::std::vector< OUString >& GetTableColumnNames() const { return maTableColumnNames; }
+
+ void SetContainer( ScDBDataContainerBase* pContainer ) { mpContainer = pContainer; }
+ void StartTableColumnNamesListener();
+ void EndTableColumnNamesListener();
+ SC_DLLPUBLIC void SetTableColumnNames( const ::std::vector< OUString >& rNames );
+ SC_DLLPUBLIC const ::std::vector< OUString >& GetTableColumnNames() const { return maTableColumnNames; }
+ bool AreTableColumnNamesDirty() const { return mbTableColumnNamesDirty; }
/** Refresh/update the column names with the header row's cell contents. */
SC_DLLPUBLIC void RefreshTableColumnNames( ScDocument* pDoc );
@@ -202,16 +229,16 @@ public:
/**
* Stores global named database ranges.
*/
- class SC_DLLPUBLIC NamedDBs
+ class SC_DLLPUBLIC NamedDBs : public ScDBDataContainerBase
{
friend class ScDBCollection;
typedef ::std::set<std::unique_ptr<ScDBData>, ScDBData::less> DBsType;
DBsType m_DBs;
ScDBCollection& mrParent;
- ScDocument& mrDoc;
NamedDBs(ScDBCollection& rParent, ScDocument& rDoc);
NamedDBs(const NamedDBs& r);
+ virtual ~NamedDBs();
NamedDBs & operator=(NamedDBs const&) = delete;
public:
@@ -287,6 +314,8 @@ public:
ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
ScDBData* GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab );
+ void RefreshDirtyTableColumnNames();
+
void DeleteOnTab( SCTAB nTab );
void UpdateReference(UpdateRefMode eUpdateRefMode,
SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 9ea6729f6377..7016d7f88911 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -570,6 +570,7 @@ public:
ScDBData* GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion);
const ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const;
ScDBData* GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
+ void RefreshDirtyTableColumnNames();
SC_DLLPUBLIC const ScRangeData* GetRangeAtBlock( const ScRange& rBlock, OUString* pName=NULL ) const;
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 32791dab34d1..0e6998a07caf 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -313,6 +313,12 @@ ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nC
return NULL;
}
+void ScDocument::RefreshDirtyTableColumnNames()
+{
+ if (pDBCollection)
+ pDBCollection->RefreshDirtyTableColumnNames();
+}
+
bool ScDocument::HasPivotTable() const
{
return pDPCollection && pDPCollection->GetCount();
diff --git a/sc/source/core/tool/dbdata.cxx b/sc/source/core/tool/dbdata.cxx
index 8375f557e918..42a2c815df97 100644
--- a/sc/source/core/tool/dbdata.cxx
+++ b/sc/source/core/tool/dbdata.cxx
@@ -32,6 +32,7 @@
#include "subtotalparam.hxx"
#include "sortparam.hxx"
#include "dociter.hxx"
+#include "brdcst.hxx"
#include <memory>
#include <utility>
@@ -52,10 +53,12 @@ ScDBData::ScDBData( const OUString& rName,
SCTAB nTab,
SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
bool bByR, bool bHasH, bool bTotals) :
+ // Listeners are to be setup by the "parent" container.
mpSortParam(new ScSortParam),
mpQueryParam(new ScQueryParam),
mpSubTotal(new ScSubTotalParam),
mpImportParam(new ScImportParam),
+ mpContainer (nullptr),
aName (rName),
aUpper (rName),
nTable (nTab),
@@ -73,17 +76,21 @@ ScDBData::ScDBData( const OUString& rName,
bDBSelection(false),
nIndex (0),
bAutoFilter (false),
- bModified (false)
+ bModified (false),
+ mbTableColumnNamesDirty(bHasH)
{
aUpper = ScGlobal::pCharClass->uppercase(aUpper);
}
ScDBData::ScDBData( const ScDBData& rData ) :
+ // Listeners are to be setup by the "parent" container.
+ SvtListener (),
ScRefreshTimer ( rData ),
mpSortParam(new ScSortParam(*rData.mpSortParam)),
mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
mpImportParam(new ScImportParam(*rData.mpImportParam)),
+ mpContainer (nullptr),
aName (rData.aName),
aUpper (rData.aUpper),
nTable (rData.nTable),
@@ -103,16 +110,20 @@ ScDBData::ScDBData( const ScDBData& rData ) :
nIndex (rData.nIndex),
bAutoFilter (rData.bAutoFilter),
bModified (rData.bModified),
- maTableColumnNames (rData.maTableColumnNames)
+ maTableColumnNames (rData.maTableColumnNames),
+ mbTableColumnNamesDirty(rData.mbTableColumnNamesDirty)
{
}
ScDBData::ScDBData( const OUString& rName, const ScDBData& rData ) :
+ // Listeners are to be setup by the "parent" container.
+ SvtListener (),
ScRefreshTimer ( rData ),
mpSortParam(new ScSortParam(*rData.mpSortParam)),
mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
mpImportParam(new ScImportParam(*rData.mpImportParam)),
+ mpContainer (nullptr),
aName (rName),
aUpper (rName),
nTable (rData.nTable),
@@ -132,7 +143,8 @@ ScDBData::ScDBData( const OUString& rName, const ScDBData& rData ) :
nIndex (rData.nIndex),
bAutoFilter (rData.bAutoFilter),
bModified (rData.bModified),
- maTableColumnNames (rData.maTableColumnNames)
+ maTableColumnNames (rData.maTableColumnNames),
+ mbTableColumnNamesDirty (rData.mbTableColumnNamesDirty)
{
aUpper = ScGlobal::pCharClass->uppercase(aUpper);
}
@@ -141,11 +153,20 @@ ScDBData& ScDBData::operator= (const ScDBData& rData)
{
// Don't modify the name. The name is not mutable as it is used as a key
// in the container to keep the db ranges sorted by the name.
+
+ bool bHeaderRangeDiffers = (nTable != rData.nTable || nStartCol != rData.nStartCol ||
+ nEndCol != rData.nEndCol || nStartRow != rData.nStartRow);
+ bool bNeedsListening = ((bHasHeader && bHeaderRangeDiffers) || (!bHasHeader && rData.bHasHeader));
+ if (bHasHeader && (!rData.bHasHeader || bHeaderRangeDiffers))
+ {
+ EndTableColumnNamesListener();
+ }
ScRefreshTimer::operator=( rData );
mpSortParam.reset(new ScSortParam(*rData.mpSortParam));
mpQueryParam.reset(new ScQueryParam(*rData.mpQueryParam));
mpSubTotal.reset(new ScSubTotalParam(*rData.mpSubTotal));
mpImportParam.reset(new ScImportParam(*rData.mpImportParam));
+ // Keep mpContainer.
nTable = rData.nTable;
nStartCol = rData.nStartCol;
nStartRow = rData.nStartRow;
@@ -162,7 +183,35 @@ ScDBData& ScDBData::operator= (const ScDBData& rData)
bDBSelection = rData.bDBSelection;
nIndex = rData.nIndex;
bAutoFilter = rData.bAutoFilter;
- maTableColumnNames = rData.maTableColumnNames;
+
+ if (bHeaderRangeDiffers)
+ {
+ if (!maTableColumnNames.empty())
+ ::std::vector<OUString>().swap( maTableColumnNames);
+ if (bHasHeader)
+ {
+ mbTableColumnNamesDirty = true;
+ if (mpContainer)
+ {
+ ScRange aHeaderRange( ScAddress::UNINITIALIZED);
+ GetArea( aHeaderRange);
+ aHeaderRange.aEnd.SetRow( aHeaderRange.aStart.Row());
+ mpContainer->GetDirtyTableColumnNames().Join( aHeaderRange);
+ }
+ }
+ else
+ {
+ mbTableColumnNamesDirty = false;
+ }
+ }
+ else
+ {
+ maTableColumnNames = rData.maTableColumnNames;
+ mbTableColumnNamesDirty = rData.mbTableColumnNamesDirty;
+ }
+
+ if (bNeedsListening)
+ StartTableColumnNamesListener();
return *this;
}
@@ -276,12 +325,15 @@ void ScDBData::GetArea(ScRange& rRange) const
void ScDBData::SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
{
- if (nCol2 - nCol1 != nEndCol - nStartCol)
+ bool bHeaderRangeChange = (nTab != nTable || nCol1 != nStartCol || nCol2 != nEndCol || nRow1 != nStartRow);
+ if (bHeaderRangeChange)
{
+ EndTableColumnNamesListener();
if (!maTableColumnNames.empty())
{
SAL_WARN("sc.core", "ScDBData::SetArea - invalidating column names/offsets");
::std::vector<OUString>().swap( maTableColumnNames);
+ mbTableColumnNamesDirty = true;
}
}
@@ -290,6 +342,9 @@ void ScDBData::SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW
nStartRow = nRow1;
nEndCol = nCol2;
nEndRow = nRow2;
+
+ if (bHeaderRangeChange)
+ StartTableColumnNamesListener();
}
void ScDBData::MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
@@ -507,9 +562,16 @@ void ScDBData::UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
bool bChanged = ( nTab != aRange.aStart.Tab() );
if (bChanged)
{
- // Same column range, SetArea() does not invalidate column names.
+ // SetArea() invalidates column names, but it is the same column range
+ // just on a different sheet; remember and set new.
+ ::std::vector<OUString> aNames( maTableColumnNames);
+ bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
+ // Same column range.
SetArea( nTab, aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(),aRange.aEnd.Row() );
+ // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
+ maTableColumnNames = aNames;
+ mbTableColumnNamesDirty = bTableColumnNamesDirty;
}
// MoveTo() is not necessary if only the sheet changed.
@@ -538,12 +600,14 @@ void ScDBData::UpdateReference(ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) != UR_NOTHING;
if (bDoUpdate)
{
- // MoveTo() invalidates column names via SetArea(); adjust, remember
- // and set new column offsets for names.
+ // MoveTo() invalidates column names via SetArea(); adjust, remember and set new.
AdjustTableColumnNames( eUpdateRefMode, nDx, nCol1, nOldCol1, nOldCol2, theCol1, theCol2);
::std::vector<OUString> aNames( maTableColumnNames);
+ bool bTableColumnNamesDirty = mbTableColumnNamesDirty;
MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
+ // Do not use SetTableColumnNames() because that resets mbTableColumnNamesDirty.
maTableColumnNames = aNames;
+ mbTableColumnNamesDirty = bTableColumnNamesDirty;
}
ScRange aRangeAdvSource;
@@ -579,10 +643,37 @@ void ScDBData::ExtendDataArea(ScDocument* pDoc)
{
SAL_WARN("sc.core", "ScDBData::ExtendDataArea - invalidating column names/offsets");
::std::vector<OUString>().swap( maTableColumnNames);
+ mbTableColumnNamesDirty = true;
}
}
}
+void ScDBData::StartTableColumnNamesListener()
+{
+ if (mpContainer && bHasHeader)
+ {
+ ScDocument* pDoc = mpContainer->GetDocument();
+ if (!pDoc->IsClipOrUndo())
+ {
+ ScRange aHeaderRange( ScAddress::UNINITIALIZED);
+ GetArea( aHeaderRange);
+ aHeaderRange.aEnd.SetRow( aHeaderRange.aStart.Row());
+ pDoc->StartListeningArea( aHeaderRange, false, this);
+ }
+ }
+}
+
+void ScDBData::EndTableColumnNamesListener()
+{
+ EndListeningAll();
+}
+
+void ScDBData::SetTableColumnNames( const ::std::vector< OUString >& rNames )
+{
+ maTableColumnNames = rNames;
+ mbTableColumnNamesDirty = false;
+}
+
void ScDBData::AdjustTableColumnNames( UpdateRefMode eUpdateRefMode, SCCOL nDx, SCCOL nCol1,
SCCOL nOldCol1, SCCOL nOldCol2, SCCOL nNewCol1, SCCOL nNewCol2 )
{
@@ -597,6 +688,9 @@ void ScDBData::AdjustTableColumnNames( UpdateRefMode eUpdateRefMode, SCCOL nDx,
::std::vector<OUString> aNewNames;
if (eUpdateRefMode == URM_INSDEL)
{
+ if (nDx > 0)
+ mbTableColumnNamesDirty = true; // inserted columns will have empty names
+
// nCol1 is the first column of the block that gets shifted, determine
// the head and tail elements that are to be copied for deletion or
// insertion.
@@ -624,6 +718,8 @@ void ScDBData::AdjustTableColumnNames( UpdateRefMode eUpdateRefMode, SCCOL nDx,
SAL_WARN_IF( !maTableColumnNames.empty() && aNewNames.empty(),
"sc.core", "ScDBData::AdjustTableColumnNames - invalidating column names/offsets");
aNewNames.swap( maTableColumnNames);
+ if (maTableColumnNames.empty())
+ mbTableColumnNamesDirty = true;
}
namespace {
@@ -730,22 +826,27 @@ void ScDBData::RefreshTableColumnNames( ScDocument* pDoc )
}
aNewNames.swap( maTableColumnNames);
+ mbTableColumnNamesDirty = false;
}
void ScDBData::RefreshTableColumnNames( ScDocument* pDoc, const ScRange& rRange )
{
- if (!HasHeader())
+ // Header-less tables get names generated, completely empty a full refresh.
+ if (!HasHeader() || maTableColumnNames.empty())
+ {
+ RefreshTableColumnNames( pDoc);
return;
+ }
- ScRange aRange( ScAddress::UNINITIALIZED);
- GetArea( aRange);
- aRange.aEnd.SetRow( aRange.aStart.Row());
- ScRange aIntersection( aRange.Intersection( rRange));
+ ScRange aHeaderRange( ScAddress::UNINITIALIZED);
+ GetArea( aHeaderRange);
+ aHeaderRange.aEnd.SetRow( aHeaderRange.aStart.Row());
+ ScRange aIntersection( aHeaderRange.Intersection( rRange));
if (!aIntersection.IsValid())
return;
- if (maTableColumnNames.empty() ||
- maTableColumnNames.size() < static_cast<size_t>(aIntersection.aEnd.Col() - nStartCol + 1))
+ // Full refresh if sizes don't match.
+ if (maTableColumnNames.size() < static_cast<size_t>(aIntersection.aEnd.Col() - nStartCol + 1))
{
RefreshTableColumnNames( pDoc);
return;
@@ -760,20 +861,27 @@ void ScDBData::RefreshTableColumnNames( ScDocument* pDoc, const ScRange& rRange
SCROW nRow;
while((pCell = aIter.GetNext( nCol, nRow)) != nullptr)
{
- if (pCell->hasString())
+ size_t nOff = nCol - nStartCol;
+ bool bEmpty = maTableColumnNames[nOff].isEmpty();
+ if (!pCell->hasString())
+ bEmpty &= true;
+ else
{
const OUString& rStr = pCell->getString( pDoc);
- if (!rStr.isEmpty())
- maTableColumnNames[nCol-nStartCol] = rStr;
+ if (rStr.isEmpty())
+ bEmpty &= true;
else
- {
- // Usually this is called for only a few positions of which
- // most are not empty, so init from resource only if necessary.
- OUString aColumn( ScGlobal::GetRscString(STR_COLUMN));
- SetTableColumnName( maTableColumnNames, nCol-nStartCol, aColumn, nCol-nStartCol+1);
- }
+ maTableColumnNames[nOff] = rStr;
+ }
+ if (bEmpty)
+ {
+ OUString aColumn( ScGlobal::GetRscString(STR_COLUMN));
+ SetTableColumnName( maTableColumnNames, nOff, aColumn, nOff+1);
}
}
+
+ if (aIntersection == aHeaderRange)
+ mbTableColumnNamesDirty = false;
}
sal_Int32 ScDBData::GetColumnNameOffset( const OUString& rName ) const
@@ -801,6 +909,24 @@ const OUString& ScDBData::GetTableColumnName( SCCOL nCol ) const
return maTableColumnNames[nOffset];
}
+void ScDBData::Notify( const SfxHint& rHint )
+{
+ const ScHint* pScHint = dynamic_cast<const ScHint*>(&rHint);
+ if (!pScHint)
+ return;
+
+ sal_uLong nHint = pScHint->GetId();
+ if (nHint & SC_HINT_DATACHANGED)
+ {
+ mbTableColumnNamesDirty = true;
+ if (mpContainer)
+ mpContainer->GetDirtyTableColumnNames().Join( pScHint->GetAddress());
+ }
+
+ // Do not refresh column names here, which might trigger unwanted
+ // recalculation.
+}
+
namespace {
class FindByTable : public unary_function<std::unique_ptr<ScDBData>, bool>
@@ -923,19 +1049,39 @@ public:
}
+ScDocument* ScDBDataContainerBase::GetDocument() const
+{
+ return &mrDoc;
+}
+
+ScRangeList& ScDBDataContainerBase::GetDirtyTableColumnNames()
+{
+ return maDirtyTableColumnNames;
+}
+
ScDBCollection::NamedDBs::NamedDBs(ScDBCollection& rParent, ScDocument& rDoc) :
- mrParent(rParent), mrDoc(rDoc) {}
+ ScDBDataContainerBase(rDoc), mrParent(rParent) {}
ScDBCollection::NamedDBs::NamedDBs(const NamedDBs& r)
- : mrParent(r.mrParent)
- , mrDoc(r.mrDoc)
+ : ScDBDataContainerBase(r.mrDoc)
+ , mrParent(r.mrParent)
{
for (auto const& it : r.m_DBs)
{
- m_DBs.insert(std::unique_ptr<ScDBData>(new ScDBData(*it)));
+ ScDBData* p = new ScDBData(*it);
+ std::unique_ptr<ScDBData> pData(p);
+ if (m_DBs.insert( std::move(pData)).second)
+ {
+ p->SetContainer( this);
+ p->StartTableColumnNamesListener(); // needs the container be set already
+ }
}
}
+ScDBCollection::NamedDBs::~NamedDBs()
+{
+}
+
ScDBCollection::NamedDBs::iterator ScDBCollection::NamedDBs::begin()
{
return m_DBs.begin();
@@ -984,10 +1130,18 @@ bool ScDBCollection::NamedDBs::insert(ScDBData* p)
pair<DBsType::iterator, bool> r = m_DBs.insert(std::move(pData));
- if (r.second && p->HasImportParam() && !p->HasImportSelection())
+ if (r.second)
{
- p->SetRefreshHandler(mrParent.GetRefreshHandler());
- p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
+ p->SetContainer( this);
+ p->StartTableColumnNamesListener(); // needs the container be set already
+
+ /* TODO: shouldn't the import refresh not be setup for
+ * clipboard/undo documents? It was already like this before.. */
+ if (p->HasImportParam() && !p->HasImportSelection())
+ {
+ p->SetRefreshHandler(mrParent.GetRefreshHandler());
+ p->SetRefreshControl(&mrDoc.GetRefreshTimerControlAddress());
+ }
}
return r.second;
}
@@ -1221,6 +1375,20 @@ ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCO
return NULL;
}
+void ScDBCollection::RefreshDirtyTableColumnNames()
+{
+ for (size_t i=0; i < maNamedDBs.maDirtyTableColumnNames.size(); ++i)
+ {
+ const ScRange* pRange = maNamedDBs.maDirtyTableColumnNames[i];
+ for (auto const& it : maNamedDBs)
+ {
+ if (it->AreTableColumnNamesDirty())
+ it->RefreshTableColumnNames( &maNamedDBs.mrDoc, *pRange);
+ }
+ }
+ maNamedDBs.maDirtyTableColumnNames.RemoveAll();
+}
+
void ScDBCollection::DeleteOnTab( SCTAB nTab )
{
FindByTable func(nTab);
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
index c9c6b7029f53..18add14fadfc 100644
--- a/sc/source/ui/docshell/docsh.cxx
+++ b/sc/source/ui/docshell/docsh.cxx
@@ -2800,6 +2800,7 @@ void ScDocShell::SetDocumentModified( bool bIsModified /* = true */ )
aDocument.Broadcast(ScHint(SC_HINT_DATACHANGED, BCA_BRDCST_ALWAYS));
if ( aDocument.IsForcedFormulaPending() && aDocument.GetAutoCalc() )
aDocument.CalcFormulaTree( true );
+ aDocument.RefreshDirtyTableColumnNames();
PostDataChanged();
// Detective AutoUpdate: