diff options
author | Kohei Yoshida <kohei.yoshida@suse.com> | 2012-01-11 15:24:52 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@suse.com> | 2012-01-11 15:29:20 -0500 |
commit | e33702442a22a72f96a093fbfdf8bfac217f416f (patch) | |
tree | 9277d890f38bcbe0d94b48dff1b08d4d1414891c /sc | |
parent | extensions: remove unused xmx library (diff) | |
download | core-e33702442a22a72f96a093fbfdf8bfac217f416f.tar.gz core-e33702442a22a72f96a093fbfdf8bfac217f416f.zip |
fdo#44661: Properly update range keys for pivot cache.
When the internal data source range gets modified, we should also
update the affected range keys that are used to look up pivot caches.
Otherwise we'll end up creating a brand new cache, without removing
the old one that's no longer referenced.
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/dpobject.hxx | 8 | ||||
-rw-r--r-- | sc/source/core/data/dpobject.cxx | 100 |
2 files changed, 99 insertions, 9 deletions
diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx index cc73fcbee82a..db8ea9222f0f 100644 --- a/sc/inc/dpobject.hxx +++ b/sc/inc/dpobject.hxx @@ -259,12 +259,18 @@ public: class SheetCaches { friend class ScDPCollection; - typedef ::boost::ptr_map<ScRange, ScDPCache> CachesType; + typedef boost::ptr_map<size_t, ScDPCache> CachesType; + typedef std::vector<ScRange> RangeIndexType; CachesType maCaches; + RangeIndexType maRanges; ScDocument* mpDoc; public: SheetCaches(ScDocument* pDoc); const ScDPCache* getCache(const ScRange& rRange); + + void updateReference( + UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz); + private: void removeCache(const ScRange& rRange); }; diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index 51be02db8971..b0bbace516fa 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -2459,27 +2459,108 @@ uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPS ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {} +namespace { + +struct FindInvalidRange : public std::unary_function<ScRange, bool> +{ + bool operator() (const ScRange& r) const + { + return !r.IsValid(); + } +}; + +} + const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange) { - CachesType::const_iterator itr = maCaches.find(rRange); - if (itr != maCaches.end()) - // already cached. - return itr->second; + RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); + if (it != maRanges.end()) + { + // Already cached. + size_t nIndex = std::distance(maRanges.begin(), it); + CachesType::iterator itCache = maCaches.find(nIndex); + if (itCache == maCaches.end()) + // cache pool and index pool out-of-sync !!! + return NULL; + return itCache->second; + } + + // Not cached. Create a new cache. SAL_WNODEPRECATED_DECLARATIONS_PUSH ::std::auto_ptr<ScDPCache> pCache(new ScDPCache(mpDoc)); SAL_WNODEPRECATED_DECLARATIONS_POP pCache->InitFromDoc(mpDoc, rRange); + + // Get the smallest available range index. + it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange()); + + size_t nIndex = maRanges.size(); + if (it == maRanges.end()) + { + // All range indices are valid. Append a new index. + maRanges.push_back(rRange); + } + else + { + // Slot with invalid range. Re-use this slot. + *it = rRange; + nIndex = std::distance(maRanges.begin(), it); + } + const ScDPCache* p = pCache.get(); - maCaches.insert(rRange, pCache); + maCaches.insert(nIndex, pCache); return p; } +void ScDPCollection::SheetCaches::updateReference( + UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz) +{ + if (maRanges.empty()) + // No caches. + return; + + RangeIndexType::iterator it = maRanges.begin(), itEnd = maRanges.end(); + for (; it != itEnd; ++it) + { + const ScRange& rKeyRange = *it; + SCCOL nCol1 = rKeyRange.aStart.Col(); + SCROW nRow1 = rKeyRange.aStart.Row(); + SCTAB nTab1 = rKeyRange.aStart.Tab(); + SCCOL nCol2 = rKeyRange.aEnd.Col(); + SCROW nRow2 = rKeyRange.aEnd.Row(); + SCTAB nTab2 = rKeyRange.aEnd.Tab(); + + ScRefUpdateRes eRes = ScRefUpdate::Update( + mpDoc, eMode, + r.aStart.Col(), r.aStart.Row(), r.aStart.Tab(), + r.aEnd.Col(), r.aEnd.Row(), r.aEnd.Tab(), nDx, nDy, nDz, + nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + + if (eRes != UR_NOTHING) + { + // range updated. + ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + *it = aNew; + } + } +} + void ScDPCollection::SheetCaches::removeCache(const ScRange& rRange) { - CachesType::iterator itr = maCaches.find(rRange); - if (itr != maCaches.end()) - maCaches.erase(itr); + RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); + if (it == maRanges.end()) + // Not cached. Nothing to do. + return; + + size_t nIndex = std::distance(maRanges.begin(), it); + CachesType::iterator itCache = maCaches.find(nIndex); + if (itCache == maCaches.end()) + // Cache pool and index pool out-of-sync !!! + return; + + it->SetInvalid(); // Make this slot available for future caches. + maCaches.erase(itCache); } ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {} @@ -2687,6 +2768,9 @@ void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode, TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end(); for (; itr != itrEnd; ++itr) itr->UpdateReference(eUpdateRefMode, r, nDx, nDy, nDz); + + // Update the source ranges of the caches. + maSheetCaches.updateReference(eUpdateRefMode, r, nDx, nDy, nDz); } bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const |