[Libreoffice-commits] .: sc/inc sc/source

Kohei Yoshida kohei at kemper.freedesktop.org
Thu Jul 5 08:18:56 PDT 2012


 sc/inc/dpcachetable.hxx            |    6 +++
 sc/inc/dpgroup.hxx                 |    1 
 sc/inc/dpobject.hxx                |    6 +++
 sc/inc/dpsave.hxx                  |    5 ++
 sc/inc/dpsdbtab.hxx                |    1 
 sc/inc/dpshttab.hxx                |    1 
 sc/inc/dptabdat.hxx                |    1 
 sc/source/core/data/dpgroup.cxx    |    5 ++
 sc/source/core/data/dpobject.cxx   |   17 +++++++++
 sc/source/core/data/dpsave.cxx     |   65 +++++++++++++++++++++++++++++++++++++
 sc/source/core/data/dpsdbtab.cxx   |    5 ++
 sc/source/core/data/dpshttab.cxx   |    5 ++
 sc/source/ui/docshell/dbdocfun.cxx |    1 
 13 files changed, 119 insertions(+)

New commits:
commit fa2b7eff2d40b6455970b521306c5961e4e3cec4
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Thu Jul 5 11:17:19 2012 -0400

    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

diff --git a/sc/inc/dpcachetable.hxx b/sc/inc/dpcachetable.hxx
index f104d3b..d834910 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 4bf9972..5d48af0 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 da0fc09..e163ef1 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 c4df4ed..28bfafd 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 eba6da2..a96b011 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 3a0fcb3..510105d 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 1bbc4d6..f19a6ba 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 203dbe9..4a263df 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 5a32643..6d33843 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 41148a4..62bda08 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 b5935c7..f1621eb 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 09230f0..797fa27 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 2bf2e58..ffcc59e 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);


More information about the Libreoffice-commits mailing list