summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2012-03-14 00:31:56 -0400
committerKohei Yoshida <kohei.yoshida@gmail.com>2012-03-14 00:35:29 -0400
commit49d3e30ec975a348b7b3d82c37137eb8ff6bb52e (patch)
tree24406babfbffc1700442367369ddb6684e9eb758
parent6aeed3c93bb8c123154bbe47702080c9c1176f39 (diff)
When changing grouping in one pivot table, update all linked tables.
We need to do this now because we now store the group field data directly in the pivot cache, which is shared by all referencing tables. Also, actions involving modification of the cache is not undoable, and making it undoable would significantly increase Calc's runtime memory footprint. So, no way.
-rw-r--r--sc/inc/dpcache.hxx1
-rw-r--r--sc/inc/dpgroup.hxx2
-rw-r--r--sc/inc/dpobject.hxx9
-rw-r--r--sc/source/core/data/dpcache.cxx6
-rw-r--r--sc/source/core/data/dpgroup.cxx5
-rw-r--r--sc/source/core/data/dpobject.cxx162
-rw-r--r--sc/source/ui/docshell/dbdocfun.cxx42
-rw-r--r--sc/source/ui/inc/dbdocfun.hxx8
-rw-r--r--sc/source/ui/unoobj/dapiuno.cxx2
-rw-r--r--sc/source/ui/view/dbfunc3.cxx17
10 files changed, 239 insertions, 15 deletions
diff --git a/sc/inc/dpcache.hxx b/sc/inc/dpcache.hxx
index 8ece78052ed2..ea0c0857e609 100644
--- a/sc/inc/dpcache.hxx
+++ b/sc/inc/dpcache.hxx
@@ -137,6 +137,7 @@ public:
void ResetGroupItems(long nDim, const ScDPNumGroupInfo& rNumInfo);
SCROW SetGroupItem(long nDim, const ScDPItemData& rData);
void GetGroupDimMemberIds(long nDim, std::vector<SCROW>& rIds) const;
+ void ClearGroupFields();
SCCOL GetDimensionIndex(const rtl::OUString& sName) const;
sal_uLong GetNumberFormat( long nDim ) const;
diff --git a/sc/inc/dpgroup.hxx b/sc/inc/dpgroup.hxx
index b81db64d26d5..987c806de872 100644
--- a/sc/inc/dpgroup.hxx
+++ b/sc/inc/dpgroup.hxx
@@ -176,6 +176,8 @@ public:
ScDPGroupTableData( const ::boost::shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument );
virtual ~ScDPGroupTableData();
+ boost::shared_ptr<ScDPTableData> GetSourceTableData();
+
void AddGroupDimension( const ScDPGroupDimension& rGroup );
void SetNumGroupDimension( long nIndex, const ScDPNumGroupDimension& rGroup );
long GetDimensionIndex( const rtl::OUString& rName );
diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx
index 5b16b599ebbc..917759d495bf 100644
--- a/sc/inc/dpobject.hxx
+++ b/sc/inc/dpobject.hxx
@@ -137,6 +137,7 @@ public:
void InvalidateData();
void ClearTableData();
+ void ReloadGroupTableData();
void Output( const ScAddress& rPos );
ScRange GetNewOutputRange( bool& rOverflow );
@@ -286,6 +287,8 @@ public:
UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz);
private:
+ ScDPCache* getExistingCache(const ScRange& rRange);
+
void updateCache(const ScRange& rRange, const ScDPDimensionSaveData* pDimData, std::set<ScDPObject*>& rRefs);
bool remove(const ScDPCache* p);
};
@@ -306,6 +309,8 @@ public:
const ::rtl::OUString& rName, const ScRange& rRange, const ScDPDimensionSaveData* pDimData);
size_t size() const;
private:
+ ScDPCache* getExistingCache(const rtl::OUString& rName);
+
void updateCache(
const rtl::OUString& rName, const ScRange& rRange,
const ScDPDimensionSaveData* pDimData, std::set<ScDPObject*>& rRefs);
@@ -346,6 +351,9 @@ public:
const ScDPDimensionSaveData* pDimData);
private:
+ ScDPCache* getExistingCache(
+ sal_Int32 nSdbType, const ::rtl::OUString& rDBName, const ::rtl::OUString& rCommand);
+
com::sun::star::uno::Reference<com::sun::star::sdbc::XRowSet> createRowSet(
sal_Int32 nSdbType, const ::rtl::OUString& rDBName, const ::rtl::OUString& rCommand);
@@ -359,6 +367,7 @@ public:
~ScDPCollection();
sal_uLong ReloadCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs);
+ bool ReloadGroupsInCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs);
SC_DLLPUBLIC size_t GetCount() const;
SC_DLLPUBLIC ScDPObject* operator[](size_t nIndex);
diff --git a/sc/source/core/data/dpcache.cxx b/sc/source/core/data/dpcache.cxx
index 6ad497ee7826..fe262ac2c8cc 100644
--- a/sc/source/core/data/dpcache.cxx
+++ b/sc/source/core/data/dpcache.cxx
@@ -1053,6 +1053,12 @@ struct ClearGroupItems : std::unary_function<ScDPCache::Field, void>
}
+void ScDPCache::ClearGroupFields()
+{
+ maGroupFields.clear();
+ std::for_each(maFields.begin(), maFields.end(), ClearGroupItems());
+}
+
SCROW ScDPCache::GetOrder(long nDim, SCROW nIndex) const
{
OSL_ENSURE( nDim >=0 && nDim < mnColumnCount, "ScDPTableDataCache::GetOrder : out of bound" );
diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx
index 9b7720d80c81..aca81eb9a25a 100644
--- a/sc/source/core/data/dpgroup.cxx
+++ b/sc/source/core/data/dpgroup.cxx
@@ -547,6 +547,11 @@ ScDPGroupTableData::~ScDPGroupTableData()
delete[] pNumGroups;
}
+boost::shared_ptr<ScDPTableData> ScDPGroupTableData::GetSourceTableData()
+{
+ return pSourceData;
+}
+
void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup )
{
ScDPGroupDimension aNewGroup( rGroup );
diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx
index e5496c83a867..6348b7f5f3fa 100644
--- a/sc/source/core/data/dpobject.cxx
+++ b/sc/source/core/data/dpobject.cxx
@@ -483,10 +483,6 @@ ScDPTableData* ScDPObject::GetTableData()
void ScDPObject::CreateObjects()
{
- // if groups are involved, create a new source with the ScDPGroupTableData
- if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
- ClearTableData();
-
if (!xSource.is())
{
//! cache DPSource and/or Output?
@@ -551,6 +547,43 @@ void ScDPObject::ClearTableData()
mpTableData.reset();
}
+void ScDPObject::ReloadGroupTableData()
+{
+ ClearSource();
+
+ if (!mpTableData)
+ // Table data not built yet. No need to reload the group data.
+ return;
+
+ if (!pSaveData)
+ // How could it not have the save data... but whatever.
+ return;
+
+ const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
+ if (!pDimData)
+ // No dimension data. Most likey it doesn't have any group dimensions.
+ return;
+
+ ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get());
+ if (pData)
+ {
+ // This is already a group table data. Salvage the source data and
+ // re-create a new group data.
+ shared_ptr<ScDPTableData> pSource = pData->GetSourceTableData();
+ shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(pSource, pDoc));
+ pDimData->WriteToData(*pGroupData);
+ mpTableData = pGroupData;
+ }
+ else
+ {
+ // This is a source data. Create a group data based on it.
+ shared_ptr<ScDPGroupTableData> pGroupData(new ScDPGroupTableData(mpTableData, pDoc));
+ pDimData->WriteToData(*pGroupData);
+ mpTableData = pGroupData;
+ }
+ bSettingsChanged = true;
+}
+
void ScDPObject::ClearSource()
{
Reference< XComponent > xObjectComp( xSource, UNO_QUERY );
@@ -2548,6 +2581,25 @@ const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange, co
return p;
}
+ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
+{
+ RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
+ if (it == maRanges.end())
+ // Not cached.
+ return NULL;
+
+ // Already cached.
+ size_t nIndex = std::distance(maRanges.begin(), it);
+ CachesType::iterator itCache = maCaches.find(nIndex);
+ if (itCache == maCaches.end())
+ {
+ OSL_FAIL("Cache pool and index pool out-of-sync !!!");
+ return NULL;
+ }
+
+ return itCache->second;
+}
+
size_t ScDPCollection::SheetCaches::size() const
{
return maCaches.size();
@@ -2658,6 +2710,12 @@ const ScDPCache* ScDPCollection::NameCaches::getCache(
return p;
}
+ScDPCache* ScDPCollection::NameCaches::getExistingCache(const OUString& rName)
+{
+ CachesType::iterator itr = maCaches.find(rName);
+ return itr != maCaches.end() ? itr->second : NULL;
+}
+
size_t ScDPCollection::NameCaches::size() const
{
return maCaches.size();
@@ -2742,6 +2800,14 @@ const ScDPCache* ScDPCollection::DBCaches::getCache(
return p;
}
+ScDPCache* ScDPCollection::DBCaches::getExistingCache(
+ sal_Int32 nSdbType, const OUString& rDBName, const OUString& rCommand)
+{
+ DBType aType(nSdbType, rDBName, rCommand);
+ CachesType::iterator itr = maCaches.find(aType);
+ return itr != maCaches.end() ? itr->second : NULL;
+}
+
uno::Reference<sdbc::XRowSet> ScDPCollection::DBCaches::createRowSet(
sal_Int32 nSdbType, const ::rtl::OUString& rDBName, const ::rtl::OUString& rCommand)
{
@@ -2966,6 +3032,94 @@ sal_uLong ScDPCollection::ReloadCache(ScDPObject* pDPObj, std::set<ScDPObject*>&
return 0;
}
+bool ScDPCollection::ReloadGroupsInCache(ScDPObject* pDPObj, std::set<ScDPObject*>& rRefs)
+{
+ if (!pDPObj)
+ return false;
+
+ const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ if (!pSaveData)
+ return false;
+
+ // Note: Unlike reloading cache, when modifying the group dimensions the
+ // cache may not have all its references when this method is called.
+ // Therefore, we need to always call GetAllTables to get its correct
+ // references even when the cache exists. This may become a non-issue
+ // if/when we implement loading and saving of pivot caches.
+
+ ScDPCache* pCache = NULL;
+
+ if (pDPObj->IsSheetData())
+ {
+ // data source is internal sheet.
+ const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
+ if (!pDesc)
+ return false;
+
+ if (pDesc->HasRangeName())
+ {
+ // cache by named range
+ ScDPCollection::NameCaches& rCaches = GetNameCaches();
+ if (rCaches.hasCache(pDesc->GetRangeName()))
+ pCache = rCaches.getExistingCache(pDesc->GetRangeName());
+ else
+ {
+ // Not cached yet. Cache the source dimensions. Groups will
+ // be added below.
+ pCache = const_cast<ScDPCache*>(
+ rCaches.getCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), NULL));
+ }
+ GetAllTables(pDesc->GetRangeName(), rRefs);
+ }
+ else
+ {
+ // cache by cell range
+ ScDPCollection::SheetCaches& rCaches = GetSheetCaches();
+ if (rCaches.hasCache(pDesc->GetSourceRange()))
+ pCache = rCaches.getExistingCache(pDesc->GetSourceRange());
+ else
+ {
+ // Not cached yet. Cache the source dimensions. Groups will
+ // be added below.
+ pCache = const_cast<ScDPCache*>(
+ rCaches.getCache(pDesc->GetSourceRange(), NULL));
+ }
+ GetAllTables(pDesc->GetSourceRange(), rRefs);
+ }
+ }
+ else if (pDPObj->IsImportData())
+ {
+ // data source is external database.
+ const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc();
+ if (!pDesc)
+ return false;
+
+ ScDPCollection::DBCaches& rCaches = GetDBCaches();
+ if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
+ pCache = rCaches.getExistingCache(
+ pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject);
+ else
+ {
+ // Not cached yet. Cache the source dimensions. Groups will
+ // be added below.
+ pCache = const_cast<ScDPCache*>(
+ rCaches.getCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, NULL));
+ }
+ GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
+ }
+
+ if (!pCache)
+ return false;
+
+ // Clear the existing group data from the cache, and rebuild it from the
+ // dimension data.
+ pCache->ClearGroupFields();
+ const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
+ if (pDimData)
+ pDimData->WriteToCache(*pCache);
+ return true;
+}
+
void ScDPCollection::DeleteOnTab( SCTAB nTab )
{
maTables.erase_if(MatchByTable(nTab));
diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx
index d1644b4938b4..2881e1d43feb 100644
--- a/sc/source/ui/docshell/dbdocfun.cxx
+++ b/sc/source/ui/docshell/dbdocfun.cxx
@@ -51,6 +51,7 @@
#include "rangenam.hxx"
#include "olinetab.hxx"
#include "dpobject.hxx"
+#include "dpsave.hxx"
#include "dociter.hxx" // for lcl_EmptyExcept
#include "cell.hxx" // for lcl_EmptyExcept
#include "editable.hxx"
@@ -1453,7 +1454,7 @@ bool ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewOb
return bDone;
}
-sal_uLong ScDBDocFunc::RefreshPivotTables(ScDPObject* pDPObj, bool bRecord, bool bApi)
+sal_uLong ScDBDocFunc::RefreshPivotTables(ScDPObject* pDPObj, bool bApi)
{
ScDPCollection* pDPs = rDocShell.GetDocument()->GetDPCollection();
if (!pDPs)
@@ -1468,12 +1469,49 @@ sal_uLong ScDBDocFunc::RefreshPivotTables(ScDPObject* pDPObj, bool bRecord, bool
for (; it != itEnd; ++it)
{
ScDPObject* pObj = *it;
- DataPilotUpdate(pObj, pObj, bRecord, bApi);
+ // This action is intentionally not undoable since it modifies cache.
+ DataPilotUpdate(pObj, pObj, false, bApi);
}
return 0;
}
+void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject* pDPObj)
+{
+ if (!pDPObj)
+ return;
+
+ ScDPCollection* pDPs = rDocShell.GetDocument()->GetDPCollection();
+ if (!pDPs)
+ return;
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ if (!pSaveData)
+ return;
+
+ std::set<ScDPObject*> aRefs;
+ if (!pDPs->ReloadGroupsInCache(pDPObj, aRefs))
+ return;
+
+ // We allow pDimData being NULL.
+ const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
+ std::set<ScDPObject*>::iterator it = aRefs.begin(), itEnd = aRefs.end();
+ for (; it != itEnd; ++it)
+ {
+ ScDPObject* pObj = *it;
+ if (pObj != pDPObj)
+ {
+ pSaveData = pObj->GetSaveData();
+ if (pSaveData)
+ pSaveData->SetDimensionData(pDimData);
+ }
+
+ pObj->ReloadGroupTableData();
+ // This action is intentionally not undoable since it modifies cache.
+ DataPilotUpdate(pObj, pObj, false, false);
+ }
+}
+
//==================================================================
//
// database import
diff --git a/sc/source/ui/inc/dbdocfun.hxx b/sc/source/ui/inc/dbdocfun.hxx
index b7beda90392c..9658fef2560f 100644
--- a/sc/source/ui/inc/dbdocfun.hxx
+++ b/sc/source/ui/inc/dbdocfun.hxx
@@ -105,7 +105,13 @@ public:
* Reload the referenced pivot cache, and refresh all pivot tables that
* reference the cache.
*/
- sal_uLong RefreshPivotTables(ScDPObject* pDPObj, bool bRecord, bool bApi);
+ sal_uLong RefreshPivotTables(ScDPObject* pDPObj, bool bApi);
+
+ /**
+ * Refresh the group dimensions of all pivot tables referencing the same
+ * cache.
+ */
+ void RefreshPivotTableGroups(ScDPObject* pDPObj);
};
diff --git a/sc/source/ui/unoobj/dapiuno.cxx b/sc/source/ui/unoobj/dapiuno.cxx
index 85e249534cee..d1d7d962ad73 100644
--- a/sc/source/ui/unoobj/dapiuno.cxx
+++ b/sc/source/ui/unoobj/dapiuno.cxx
@@ -1276,7 +1276,7 @@ void SAL_CALL ScDataPilotTableObj::refresh() throw(RuntimeException)
if (pDPObj)
{
ScDBDocFunc aFunc(*GetDocShell());
- aFunc.RefreshPivotTables(pDPObj, true, true);
+ aFunc.RefreshPivotTables(pDPObj, true);
}
}
diff --git a/sc/source/ui/view/dbfunc3.cxx b/sc/source/ui/view/dbfunc3.cxx
index e86d5858d051..f6eb887b830e 100644
--- a/sc/source/ui/view/dbfunc3.cxx
+++ b/sc/source/ui/view/dbfunc3.cxx
@@ -707,7 +707,7 @@ void ScDBFunc::RecalcPivotTable()
// Remove existing data cache for the data that this datapilot uses,
// to force re-build data cache.
ScDBDocFunc aFunc(*pDocSh);
- aFunc.RefreshPivotTables(pDPObj, true, false);
+ aFunc.RefreshPivotTables(pDPObj, false);
CursorPosChanged(); // shells may be switched
}
@@ -1081,7 +1081,7 @@ void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nPar
// apply changes
ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
pDPObj->SetSaveData( aData );
- aFunc.DataPilotUpdate( pDPObj, pDPObj, true, false );
+ aFunc.RefreshPivotTableGroups(pDPObj);
// unmark cell selection
Unmark();
@@ -1123,7 +1123,7 @@ void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo& rInfo )
// apply changes
ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
pDPObj->SetSaveData( aData );
- aFunc.DataPilotUpdate( pDPObj, pDPObj, true, false );
+ aFunc.RefreshPivotTableGroups(pDPObj);
// unmark cell selection
Unmark();
@@ -1264,7 +1264,7 @@ void ScDBFunc::GroupDataPilot()
// apply changes
ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
pDPObj->SetSaveData( aData );
- aFunc.DataPilotUpdate( pDPObj, pDPObj, true, false );
+ aFunc.RefreshPivotTableGroups(pDPObj);
// unmark cell selection
Unmark();
@@ -1288,8 +1288,11 @@ void ScDBFunc::UngroupDataPilot()
OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
ScDPSaveData aData( *pDPObj->GetSaveData() );
- ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
- //! test first if DimensionData exists?
+ if (!aData.GetExistingDimensionData())
+ // There is nothing to ungroup.
+ return;
+
+ ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
bool bApply = false;
@@ -1343,7 +1346,7 @@ void ScDBFunc::UngroupDataPilot()
// apply changes
ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
pDPObj->SetSaveData( aData );
- aFunc.DataPilotUpdate( pDPObj, pDPObj, true, false );
+ aFunc.RefreshPivotTableGroups(pDPObj);
// unmark cell selection
Unmark();