diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-07-05 11:17:19 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-07-05 11:19:52 -0400 |
commit | fa2b7eff2d40b6455970b521306c5961e4e3cec4 (patch) | |
tree | b6867782e1eef0e00d791ebd5f700e904567c9ea | |
parent | 40faf88cf0bef76e653e7e9dab707b4c936e7a3e (diff) |
fdo#51266: Sync dimension members in several places upon refresh.
Or else the pivot table would generate erroneous results or crash
after refresh.
Change-Id: Ia14a6e3d25112e6ecd62d21928639f75e6a8ba7c
-rw-r--r-- | sc/inc/dpcachetable.hxx | 6 | ||||
-rw-r--r-- | sc/inc/dpgroup.hxx | 1 | ||||
-rw-r--r-- | sc/inc/dpobject.hxx | 6 | ||||
-rw-r--r-- | sc/inc/dpsave.hxx | 5 | ||||
-rw-r--r-- | sc/inc/dpsdbtab.hxx | 1 | ||||
-rw-r--r-- | sc/inc/dpshttab.hxx | 1 | ||||
-rw-r--r-- | sc/inc/dptabdat.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/dpgroup.cxx | 5 | ||||
-rw-r--r-- | sc/source/core/data/dpobject.cxx | 17 | ||||
-rw-r--r-- | sc/source/core/data/dpsave.cxx | 65 | ||||
-rw-r--r-- | sc/source/core/data/dpsdbtab.cxx | 5 | ||||
-rw-r--r-- | sc/source/core/data/dpshttab.cxx | 5 | ||||
-rw-r--r-- | sc/source/ui/docshell/dbdocfun.cxx | 1 |
13 files changed, 119 insertions, 0 deletions
diff --git a/sc/inc/dpcachetable.hxx b/sc/inc/dpcachetable.hxx index f104d3b200ba..d83491089d16 100644 --- a/sc/inc/dpcachetable.hxx +++ b/sc/inc/dpcachetable.hxx @@ -56,6 +56,12 @@ class ScRange; struct ScDPValueData; struct ScQueryParam; +/** + * Despite the name, this class is only a wrapper to the actual cache, to + * provide filtering on the raw data based on the query filter and/or page + * field filters. I will rename this class to a more appropriate name in the + * future. + */ class SC_DLLPUBLIC ScDPCacheTable { struct RowFlag diff --git a/sc/inc/dpgroup.hxx b/sc/inc/dpgroup.hxx index 4bf9972f7b29..5d48af06231e 100644 --- a/sc/inc/dpgroup.hxx +++ b/sc/inc/dpgroup.hxx @@ -182,6 +182,7 @@ public: ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& rData); virtual void CalcResults(CalcInfo& rInfo, bool bAutoShow); virtual const ScDPCacheTable& GetCacheTable() const; + virtual void ClearCacheTable(); virtual sal_Bool IsBaseForGroup(long nDim) const; virtual long GetGroupBase(long nGroupDim) const; diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx index da0fc0943da8..e163ef1cb82c 100644 --- a/sc/inc/dpobject.hxx +++ b/sc/inc/dpobject.hxx @@ -239,6 +239,12 @@ public: void BuildAllDimensionMembers(); + /** + * Remove in the save data entries for members that don't exist anymore. + * This is called during pivot table refresh. + */ + void SyncAllDimensionMembers(); + static bool HasRegisteredSources(); static com::sun::star::uno::Sequence<rtl::OUString> GetRegisteredSources(); static com::sun::star::uno::Reference<com::sun::star::sheet::XDimensionsSupplier> diff --git a/sc/inc/dpsave.hxx b/sc/inc/dpsave.hxx index c4df4eda7b76..28bfafdbe1f4 100644 --- a/sc/inc/dpsave.hxx +++ b/sc/inc/dpsave.hxx @@ -33,6 +33,7 @@ #include <boost/ptr_container/ptr_vector.hpp> #include <boost/unordered_map.hpp> +#include <boost/unordered_set.hpp> #include <boost/scoped_ptr.hpp> #include <com/sun/star/sheet/XDimensionsSupplier.hpp> @@ -122,6 +123,7 @@ private: ::com::sun::star::sheet::DataPilotFieldLayoutInfo* pLayoutInfo; // (level) public: + typedef boost::unordered_set<rtl::OUString, rtl::OUStringHash> MemberSetType; typedef boost::unordered_map <rtl::OUString, ScDPSaveMember*, rtl::OUStringHash> MemberHash; typedef std::list <ScDPSaveMember*> MemberList; @@ -230,6 +232,8 @@ public: void UpdateMemberVisibility(const ::boost::unordered_map< ::rtl::OUString, bool, ::rtl::OUStringHash>& rData); bool HasInvisibleMember() const; + + void RemoveObsoleteMembers(const MemberSetType& rMembers); }; @@ -344,6 +348,7 @@ public: SC_DLLPUBLIC ScDPDimensionSaveData* GetDimensionData(); // create if not there void SetDimensionData( const ScDPDimensionSaveData* pNew ); // copied void BuildAllDimensionMembers(ScDPTableData* pData); + void SyncAllDimensionMembers(ScDPTableData* pData); /** * Check whether a dimension has one or more invisible members. diff --git a/sc/inc/dpsdbtab.hxx b/sc/inc/dpsdbtab.hxx index eba6da20d52d..a96b0115014b 100644 --- a/sc/inc/dpsdbtab.hxx +++ b/sc/inc/dpsdbtab.hxx @@ -88,6 +88,7 @@ public: ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& rData); virtual void CalcResults(CalcInfo& rInfo, bool bAutoShow); virtual const ScDPCacheTable& GetCacheTable() const; + virtual void ClearCacheTable(); }; diff --git a/sc/inc/dpshttab.hxx b/sc/inc/dpshttab.hxx index 3a0fcb3e94f1..510105d36723 100644 --- a/sc/inc/dpshttab.hxx +++ b/sc/inc/dpshttab.hxx @@ -128,6 +128,7 @@ public: ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& rData); virtual void CalcResults(CalcInfo& rInfo, bool bAutoShow); virtual const ScDPCacheTable& GetCacheTable() const; + virtual void ClearCacheTable(); }; diff --git a/sc/inc/dptabdat.hxx b/sc/inc/dptabdat.hxx index 1bbc4d6c70cc..f19a6ba7a0a4 100644 --- a/sc/inc/dptabdat.hxx +++ b/sc/inc/dptabdat.hxx @@ -154,6 +154,7 @@ public: ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& rData) = 0; virtual void CalcResults(CalcInfo& rInfo, bool bAutoShow) = 0; virtual const ScDPCacheTable& GetCacheTable() const = 0; + virtual void ClearCacheTable() = 0; // overloaded in ScDPGroupTableData: virtual sal_Bool IsBaseForGroup(long nDim) const; diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx index 203dbe9529c7..4a263df2c22c 100644 --- a/sc/source/core/data/dpgroup.cxx +++ b/sc/source/core/data/dpgroup.cxx @@ -784,6 +784,11 @@ const ScDPCacheTable& ScDPGroupTableData::GetCacheTable() const return pSourceData->GetCacheTable(); } +void ScDPGroupTableData::ClearCacheTable() +{ + pSourceData->ClearCacheTable(); +} + void ScDPGroupTableData::FillGroupValues(vector<SCROW>& rItems, const vector<long>& rDims) { long nGroupedColumns = aGroups.size(); diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index 5a3264372542..6d33843a8d7f 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -696,6 +696,23 @@ void ScDPObject::BuildAllDimensionMembers() pSaveData->BuildAllDimensionMembers(GetTableData()); } +void ScDPObject::SyncAllDimensionMembers() +{ + if (!pSaveData) + return; + + // #i111857# don't always create empty mpTableData for external service. + // Ideally, xSource should be used instead of mpTableData. + if (pServDesc) + return; + + ScDPTableData* pData = GetTableData(); + // Refresh the cache wrapper since the cache may have changed. + pData->ClearCacheTable(); + pData->CreateCacheTable(); + pSaveData->SyncAllDimensionMembers(pData); +} + bool ScDPObject::GetMemberNames( sal_Int32 nDim, Sequence<OUString>& rNames ) { vector<ScDPLabelData::Member> aMembers; diff --git a/sc/source/core/data/dpsave.cxx b/sc/source/core/data/dpsave.cxx index 41148a41c753..62bda087b3a5 100644 --- a/sc/source/core/data/dpsave.cxx +++ b/sc/source/core/data/dpsave.cxx @@ -34,6 +34,7 @@ #include "global.hxx" #include "dptabsrc.hxx" #include "dputil.hxx" +#include "stlalgorithm.hxx" #include <sal/types.h> #include "comphelper/string.hxx" @@ -729,6 +730,30 @@ bool ScDPSaveDimension::HasInvisibleMember() const return false; } +void ScDPSaveDimension::RemoveObsoleteMembers(const MemberSetType& rMembers) +{ + maMemberHash.clear(); + MemberList aNew; + MemberList::iterator it = maMemberList.begin(), itEnd = maMemberList.end(); + for (; it != itEnd; ++it) + { + ScDPSaveMember* pMem = *it; + if (rMembers.count(pMem->GetName())) + { + // This member still exists. + maMemberHash.insert(MemberHash::value_type(pMem->GetName(), pMem)); + aNew.push_back(pMem); + } + else + { + // This member no longer exists. + delete pMem; + } + } + + maMemberList.swap(aNew); +} + ScDPSaveData::ScDPSaveData() : pDimensionData( NULL ), nColumnGrandMode( SC_DPSAVEMODE_DONTKNOW ), @@ -1257,6 +1282,46 @@ void ScDPSaveData::BuildAllDimensionMembers(ScDPTableData* pData) mbDimensionMembersBuilt = true; } +void ScDPSaveData::SyncAllDimensionMembers(ScDPTableData* pData) +{ + typedef boost::unordered_map<rtl::OUString, long, rtl::OUStringHash> NameIndexMap; + + // First, build a dimension name-to-index map. + NameIndexMap aMap; + long nColCount = pData->GetColumnCount(); + for (long i = 0; i < nColCount; ++i) + aMap.insert(NameIndexMap::value_type(pData->getDimensionName(i), i)); + + NameIndexMap::const_iterator itMapEnd = aMap.end(); + + DimsType::iterator it = aDimList.begin(), itEnd = aDimList.end(); + for (it = aDimList.begin(); it != itEnd; ++it) + { + const ::rtl::OUString& rDimName = it->GetName(); + if (rDimName.isEmpty()) + // empty dimension name. It must be data layout. + continue; + + NameIndexMap::const_iterator itMap = aMap.find(rDimName); + if (itMap == itMapEnd) + // dimension name not in the data. This should never happen! + continue; + + ScDPSaveDimension::MemberSetType aMemNames; + long nDimIndex = itMap->second; + const std::vector<SCROW>& rMembers = pData->GetColumnEntries(nDimIndex); + size_t nMemberCount = rMembers.size(); + for (size_t j = 0; j < nMemberCount; ++j) + { + const ScDPItemData* pMemberData = pData->GetMemberById(nDimIndex, rMembers[j]); + rtl::OUString aMemName = pData->GetFormattedString(nDimIndex, *pMemberData); + aMemNames.insert(aMemName); + } + + it->RemoveObsoleteMembers(aMemNames); + } +} + bool ScDPSaveData::HasInvisibleMember(const OUString& rDimName) const { ScDPSaveDimension* pDim = GetExistingDimensionByName(rDimName); diff --git a/sc/source/core/data/dpsdbtab.cxx b/sc/source/core/data/dpsdbtab.cxx index b5935c708c5c..f1621eb08f64 100644 --- a/sc/source/core/data/dpsdbtab.cxx +++ b/sc/source/core/data/dpsdbtab.cxx @@ -172,6 +172,11 @@ const ScDPCacheTable& ScDatabaseDPData::GetCacheTable() const return aCacheTable; } +void ScDatabaseDPData::ClearCacheTable() +{ + aCacheTable.clear(); +} + // ----------------------------------------------------------------------- diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx index 09230f06b97f..797fa274cafd 100644 --- a/sc/source/core/data/dpshttab.cxx +++ b/sc/source/core/data/dpshttab.cxx @@ -223,6 +223,11 @@ const ScDPCacheTable& ScSheetDPData::GetCacheTable() const return aCacheTable; } +void ScSheetDPData::ClearCacheTable() +{ + aCacheTable.clear(); +} + ScSheetSourceDesc::ScSheetSourceDesc(ScDocument* pDoc) : mpDoc(pDoc) {} diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx index 2bf2e58ace67..ffcc59e0e7ee 100644 --- a/sc/source/ui/docshell/dbdocfun.cxx +++ b/sc/source/ui/docshell/dbdocfun.cxx @@ -1473,6 +1473,7 @@ sal_uLong ScDBDocFunc::RefreshPivotTables(ScDPObject* pDPObj, bool bApi) for (; it != itEnd; ++it) { ScDPObject* pObj = *it; + pObj->SyncAllDimensionMembers(); // This action is intentionally not undoable since it modifies cache. DataPilotUpdate(pObj, pObj, false, bApi); |