diff options
author | Tobias Lippert <drtl@fastmail.fm> | 2014-03-05 20:06:39 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2014-03-11 08:54:37 -0500 |
commit | 0c17ccc493d0c7a80f37600dae76a09a119bef78 (patch) | |
tree | 70fd1963d59bbb8dba95ed4d92053f2c9f3115cb | |
parent | e3e1f9f30d80961fd282f9ce765ffb1111201344 (diff) |
fdo#30770 - Speed up xslx import
Conflicts:
include/svl/style.hxx
Change-Id: Ie3d855923c651b6e05c0054c8e30155218279045
Reviewed-on: https://gerrit.libreoffice.org/8485
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | include/svl/IndexedStyleSheets.hxx | 180 | ||||
-rw-r--r-- | include/svl/style.hxx | 39 | ||||
-rw-r--r-- | sc/source/core/data/stlpool.cxx | 51 | ||||
-rw-r--r-- | sd/source/core/drawdoc4.cxx | 1 | ||||
-rw-r--r-- | sd/source/core/stlpool.cxx | 99 | ||||
-rw-r--r-- | svl/CppunitTest_svl_items.mk | 42 | ||||
-rw-r--r-- | svl/Library_svl.mk | 1 | ||||
-rw-r--r-- | svl/Module_svl.mk | 1 | ||||
-rw-r--r-- | svl/qa/unit/items/test_IndexedStyleSheets.cxx | 160 | ||||
-rw-r--r-- | svl/source/items/IndexedStyleSheets.cxx | 210 | ||||
-rw-r--r-- | svl/source/items/style.cxx | 268 |
11 files changed, 894 insertions, 158 deletions
diff --git a/include/svl/IndexedStyleSheets.hxx b/include/svl/IndexedStyleSheets.hxx new file mode 100644 index 000000000000..6980a978bd1d --- /dev/null +++ b/include/svl/IndexedStyleSheets.hxx @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SVL_INDEXEDSTYLESHEETS_HXX_ +#define SVL_INDEXEDSTYLESHEETS_HXX_ + +#include <sal/types.h> + +#include <rtl/ustring.hxx> +#include <rtl/ref.hxx> + +#include <boost/unordered_map.hpp> +#include <vector> + +class SfxStyleSheetBase; + +namespace svl { + +/** Function object to check whether a style sheet a fulfills specific criteria. + * Derive from this class and override the Check() method. + */ +struct StyleSheetPredicate { + virtual bool Check(const SfxStyleSheetBase& styleSheet) = 0; + virtual ~StyleSheetPredicate() {;} +}; + +/** Function object for cleanup-Strategy for IndexedSfxStyleSheets::Clear(). + * Derive from it and do what is necessary to dispose of a style sheet in Dispose(). + */ +struct StyleSheetDisposer { + virtual void Dispose(rtl::Reference<SfxStyleSheetBase> styleSheet) = 0; + virtual ~StyleSheetDisposer() {;} +}; + +/** Function object to apply a method on all style sheets. + * Derive from it and do whatever you want to with the style sheet in the DoIt() method. + */ +struct StyleSheetCallback { + virtual void DoIt(const SfxStyleSheetBase& styleSheet) = 0; + virtual ~StyleSheetCallback() {;} +}; + +/** This class holds SfxStyleSheets and allows for access via an id and a name. + * + * @warning + * The identification of style sheets happens by their name. If the name of a sheet changes, + * it will not be found again! Please call Reindex() after changing a style sheet's name. + * + * @internal + * This class was implemented to mitigate solve #fdo 30770. + * The issue describes an Excel file which takes several hours to open. + * An analysis revealed that the time is spent searching for style sheets with linear scans in an array. + * This class implements access to the style sheets via their name in (usually) constant time. + * + * The return type for most methods is a vector of unsigned integers which denote the position + * of the style sheets in the vector, and not of pointers to style sheets. + * You will need a non-const StyleSheetPool to obtain the actual style sheets. + * + * + * Index-based access is required in several code portions. Hence we have to store the style sheets + * in a vector as well as in a map. + */ +class SAL_DLLPUBLIC IndexedStyleSheets SAL_FINAL { +public: + IndexedStyleSheets(); + + /** Destructor. + * + * @internal + * Is explicit because it has to know how to dispose of SfxStyleSheetBase objects. + */ + ~IndexedStyleSheets(); + + /** Adds a style sheet. + * + * If the style sheet is already contained, this call has no effect. + */ + void + AddStyleSheet(rtl::Reference< SfxStyleSheetBase > style); + + /** Removes a style sheet. */ + bool + RemoveStyleSheet(rtl::Reference< SfxStyleSheetBase > style); + + /** Check whether a specified style sheet is stored. */ + bool + HasStyleSheet(rtl::Reference< SfxStyleSheetBase > style) const; + + /** Obtain the number of style sheets which are held */ + unsigned + GetNumberOfStyleSheets() const; + + /** Obtain the number of style sheets for which a certain condition holds */ + unsigned + GetNumberOfStyleSheetsWithPredicate(StyleSheetPredicate& predicate) const; + + /** Return the stylesheet by its position. + * You can obtain the position by, e.g., FindStyleSheetPosition() + * @internal + * Method is not const because the returned style sheet is not const + */ + rtl::Reference< SfxStyleSheetBase > + GetStyleSheetByPosition(unsigned pos); + + /** Find the position of a provided style. + * + * @throws std::runtime_error if the style has not been found. + */ + unsigned + FindStyleSheetPosition(const SfxStyleSheetBase& style) const; + + /** Obtain the positions of all styles which have a given name + */ + std::vector<unsigned> + FindPositionsByName(const rtl::OUString& name) const; + + /** Obtain the positions of all styles which have a certain name and fulfill a certain condition. + * + * This method is fast because it can use the name-based index + */ + std::vector<unsigned> + FindPositionsByNameAndPredicate(const rtl::OUString& name, StyleSheetPredicate& predicate) const; + + /** Obtain the positions of all styles which fulfill a certain condition. + * + * This method is slow because it cannot use the name-based index + */ + std::vector<unsigned> + FindPositionsByPredicate(StyleSheetPredicate& predicate) const; + + /** Execute a callback on all style sheets */ + void + ApplyToAllStyleSheets(StyleSheetCallback& callback) const; + + /** Clear the contents of the index. + * The StyleSheetDisposer::Dispose() method is called on each style sheet, e.g., if you want to broadcast + * changes. + */ + void + Clear(StyleSheetDisposer& cleanup); + + void + Reindex(); + + /** Warning: counting for n starts at 0, i.e., the 0th style sheet is the first that is found. */ + rtl::Reference<SfxStyleSheetBase> + GetNthStyleSheetThatMatchesPredicate(unsigned n, StyleSheetPredicate& predicate, + unsigned startAt = 0); + +private: + /** Register the position of a styleName in the index */ + void + Register(const rtl::OUString& styleName, unsigned pos); + + typedef std::vector<rtl::Reference<SfxStyleSheetBase> > VectorType; + /** Vector with the stylesheets to allow for index-based access. + */ + VectorType mStyleSheets; + + /** The map type that is used to store the mapping from strings to ids in mStyleSheets + * + * @internal + * Must be an unordered map. A regular map is too slow for some files. */ + typedef boost::unordered_multimap<rtl::OUString, unsigned, rtl::OUStringHash> MapType; + + /** A map which stores the positions of style sheets by their name */ + MapType mPositionsByName; +}; + +} /* namespace svl */ + +#endif /* SVL_INDEXEDSTYLESHEETS_HXX_ */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/svl/style.hxx b/include/svl/style.hxx index 7a558e4f94b9..da6931b63e37 100644 --- a/include/svl/style.hxx +++ b/include/svl/style.hxx @@ -43,6 +43,7 @@ class SfxItemPool; class SfxStyleSheetBasePool; class SvStream; +namespace svl { class IndexedStyleSheets; } /* Everyone changing instances of SfxStyleSheetBasePool or SfxStyleSheetBase must broadcast this using <SfxStyleSheetBasePool::GetBroadcaster()> broadcasts. @@ -144,12 +145,6 @@ public: virtual sal_uInt16 GetVersion() const; }; - - -typedef std::vector< rtl::Reference< SfxStyleSheetBase > > SfxStyles; - - - class SVL_DLLPUBLIC SfxStyleSheetIterator /* [Beschreibung] @@ -174,18 +169,18 @@ public: virtual SfxStyleSheetBase* Find(const OUString& rStr); virtual ~SfxStyleSheetIterator(); + bool SearchUsed() const { return bSearchUsed; } + protected: SfxStyleSheetBasePool* pBasePool; SfxStyleFamily nSearchFamily; sal_uInt16 nMask; - bool SearchUsed() const { return bSearchUsed; } private: sal_uInt16 GetPos() { return nAktPosition; } SVL_DLLPRIVATE bool IsTrivialSearch(); - SVL_DLLPRIVATE bool DoesStyleMatch(SfxStyleSheetBase *pStyle); SfxStyleSheetBase* pAktStyle; sal_uInt16 nAktPosition; @@ -211,17 +206,24 @@ protected: OUString aAppName; SfxItemPool& rPool; - SfxStyles aStyles; SfxStyleFamily nSearchFamily; sal_uInt16 nMask; - SfxStyleSheetBase& Add( SfxStyleSheetBase& ); void ChangeParent( const OUString&, const OUString&, bool bVirtual = true ); virtual SfxStyleSheetBase* Create( const OUString&, SfxStyleFamily, sal_uInt16 ); virtual SfxStyleSheetBase* Create( const SfxStyleSheetBase& ); virtual ~SfxStyleSheetBasePool(); + void StoreStyleSheet(rtl::Reference< SfxStyleSheetBase >); + + /** Obtain the indexed style sheets. + */ + const svl::IndexedStyleSheets& + GetIndexedStyleSheets() const; + rtl::Reference<SfxStyleSheetBase> + GetStyleSheetByPositionInIndex(unsigned pos); + public: SfxStyleSheetBasePool( SfxItemPool& ); SfxStyleSheetBasePool( const SfxStyleSheetBasePool& ); @@ -250,6 +252,8 @@ public: SfxStyleSheetBasePool& operator=( const SfxStyleSheetBasePool& ); SfxStyleSheetBasePool& operator+=( const SfxStyleSheetBasePool& ); + unsigned GetNumberOfStyles(); + virtual SfxStyleSheetBase* First(); virtual SfxStyleSheetBase* Next(); virtual SfxStyleSheetBase* Find( const OUString&, SfxStyleFamily eFam, sal_uInt16 n=SFXSTYLEBIT_ALL ); @@ -264,6 +268,21 @@ public: void SetSearchMask(SfxStyleFamily eFam, sal_uInt16 n=SFXSTYLEBIT_ALL ); sal_uInt16 GetSearchMask() const; SfxStyleFamily GetSearchFamily() const { return nSearchFamily; } + + void Reindex(); + /** Add a style sheet. + * Not an actual public function. Do not call it from non-subclasses. + */ + SfxStyleSheetBase& Add( const SfxStyleSheetBase& ); + +private: + /** This member holds the indexed style sheets. + * + * @internal + * This member is private and not protected in order to have more control which style sheets are added + * where. Ideally, all calls which add/remove/change style sheets are done in the base class. + */ + boost::shared_ptr<svl::IndexedStyleSheets> mIndexedStyleSheets; }; diff --git a/sc/source/core/data/stlpool.cxx b/sc/source/core/data/stlpool.cxx index 455c483365f5..67a28622388a 100644 --- a/sc/source/core/data/stlpool.cxx +++ b/sc/source/core/data/stlpool.cxx @@ -36,6 +36,7 @@ #include <editeng/justifyitem.hxx> #include <svl/itemset.hxx> #include <svl/zforlist.hxx> +#include <svl/IndexedStyleSheets.hxx> #include <unotools/charclass.hxx> #include <unotools/fontcvt.hxx> #include <vcl/outdev.hxx> @@ -93,7 +94,7 @@ SfxStyleSheetBase& ScStyleSheetPool::Make( const OUString& rName, if ( rName == STRING_STANDARD && Find( rName, eFam ) != NULL ) { OSL_FAIL("renaming additional default style"); - sal_uInt32 nCount = aStyles.size(); + sal_uInt32 nCount = GetIndexedStyleSheets().GetNumberOfStyleSheets(); for ( sal_uInt32 nAdd = 1; nAdd <= nCount; nAdd++ ) { OUString aNewName = ScGlobal::GetRscString(STR_STYLENAME_STANDARD); @@ -102,7 +103,6 @@ SfxStyleSheetBase& ScStyleSheetPool::Make( const OUString& rName, return SfxStyleSheetPool::Make(aNewName, eFam, mask); } } - return SfxStyleSheetPool::Make(rName, eFam, mask); } @@ -480,25 +480,54 @@ void ScStyleSheetPool::CreateStandardStyles() DELETEZ( pEdEngine ); } +namespace { + +struct CaseInsensitiveNamePredicate : svl::StyleSheetPredicate +{ + CaseInsensitiveNamePredicate(const rtl::OUString& rName, SfxStyleFamily eFam) + : mFamily(eFam) + { + mUppercaseName = ScGlobal::pCharClass->uppercase(rName); + } + + bool + Check(const SfxStyleSheetBase& rStyleSheet) + { + if (rStyleSheet.GetFamily() == mFamily) + { + rtl::OUString aUpName = ScGlobal::pCharClass->uppercase(rStyleSheet.GetName()); + if (mUppercaseName == aUpName) + { + return true; + } + } + return false; + } + rtl::OUString mUppercaseName; + SfxStyleFamily mFamily; +}; +} +// Functor object to find all style sheets of a family which match a given name caseinsensitively ScStyleSheet* ScStyleSheetPool::FindCaseIns( const OUString& rName, SfxStyleFamily eFam ) { - OUString aUpSearch = ScGlobal::pCharClass->uppercase(rName); + CaseInsensitiveNamePredicate aPredicate(rName, eFam); + std::vector<unsigned> aFoundPositions = GetIndexedStyleSheets().FindPositionsByPredicate(aPredicate); + std::vector<unsigned>::const_iterator it = aFoundPositions.begin(); - sal_uInt32 nCount = aStyles.size(); - for (sal_uInt32 n=0; n<nCount; n++) + for (/**/;it != aFoundPositions.end(); ++it) { - SfxStyleSheetBase* pStyle = aStyles[n].get(); - if ( pStyle->GetFamily() == eFam ) + SfxStyleSheetBase *pFound = GetStyleSheetByPositionInIndex(*it).get(); + ScStyleSheet* pSheet = NULL; + // we do not know what kind of sheets we have. + pSheet = dynamic_cast<ScStyleSheet*>(pFound); + if (pSheet != NULL) { - OUString aUpName = ScGlobal::pCharClass->uppercase(pStyle->GetName()); - if (aUpName == aUpSearch) - return (ScStyleSheet*)pStyle; + return pSheet; } } - return NULL; } diff --git a/sd/source/core/drawdoc4.cxx b/sd/source/core/drawdoc4.cxx index a6f939b7639d..8ebb9250a3b7 100644 --- a/sd/source/core/drawdoc4.cxx +++ b/sd/source/core/drawdoc4.cxx @@ -1103,6 +1103,7 @@ void SdDrawDocument::RenameLayoutTemplate(const OUString& rOldLayoutName, const aReplList.push_back(aReplData); pSheet->SetName(aSheetName); + mxStyleSheetPool.get()->Reindex(); } pSheet = aIter.Next(); diff --git a/sd/source/core/stlpool.cxx b/sd/source/core/stlpool.cxx index 457350afd8b8..6b88b0bc6e75 100644 --- a/sd/source/core/stlpool.cxx +++ b/sd/source/core/stlpool.cxx @@ -53,6 +53,7 @@ #include <editeng/adjustitem.hxx> #include <editeng/numdef.hxx> #include <svl/itempool.hxx> +#include <svl/IndexedStyleSheets.hxx> #include "stlpool.hxx" #include "sdresid.hxx" @@ -127,8 +128,6 @@ SdStyleSheetPool::SdStyleSheetPool(SfxItemPool const& _rPool, SdDrawDocument* pD } } - - SdStyleSheetPool::~SdStyleSheetPool() { DBG_ASSERT( mpDoc == NULL, "sd::SdStyleSheetPool::~SdStyleSheetPool(), dispose me first!" ); @@ -624,41 +623,66 @@ void SdStyleSheetPool::CopySheets(SdStyleSheetPool& rSourcePool, SfxStyleFamily CopySheets(rSourcePool, eFamily, rCreatedSheets, emptyName); } +namespace +{ + +struct HasFamilyPredicate : svl::StyleSheetPredicate +{ + HasFamilyPredicate(SfxStyleFamily eFamily) + : meFamily(eFamily) {;} + + bool Check(const SfxStyleSheetBase& sheet) + { + return sheet.GetFamily() == meFamily; + } + SfxStyleFamily meFamily; +}; + +} + void SdStyleSheetPool::CopySheets(SdStyleSheetPool& rSourcePool, SfxStyleFamily eFamily, SdStyleSheetVector& rCreatedSheets, OUString& rRenameSuffix) { OUString aHelpFile; - sal_uInt32 nCount = rSourcePool.aStyles.size(); - std::vector< std::pair< rtl::Reference< SfxStyleSheetBase >, OUString > > aNewStyles; std::vector< std::pair< OUString, OUString > > aRenamedList; - for (sal_uInt32 n = 0; n < nCount; n++) + // find all style sheets of the source pool which have the same family + HasFamilyPredicate aHasFamilyPredicate(eFamily); + std::vector<unsigned> aSheetsWithFamily = rSourcePool.GetIndexedStyleSheets().FindPositionsByPredicate(aHasFamilyPredicate); + + for (std::vector<unsigned>::const_iterator it = aSheetsWithFamily.begin(); + it != aSheetsWithFamily.end(); ++it ) { - rtl::Reference< SfxStyleSheetBase > xSheet( rSourcePool.aStyles[sal::static_int_cast<sal_uInt16>(n)] ); + rtl::Reference< SfxStyleSheetBase > xSheet = GetStyleSheetByPositionInIndex( *it ); + rtl::OUString aName( xSheet->GetName() ); - if( xSheet->GetFamily() == eFamily ) + // now check whether we already have a sheet with the same name + std::vector<unsigned> aSheetsWithName = GetIndexedStyleSheets().FindPositionsByName(aName); + bool bAddToList = false; + if (!aSheetsWithName.empty() && !rRenameSuffix.isEmpty()) { - bool bAddToList = false; - OUString aName( xSheet->GetName() ); - SfxStyleSheetBase* pExistingSheet = Find(aName, eFamily); - if( pExistingSheet && !rRenameSuffix.isEmpty() ) + // if we have a rename suffix, try to find a new name + SfxStyleSheetBase* pExistingSheet = GetStyleSheetByPositionInIndex(aSheetsWithName.front()).get(); + sal_Int32 nHash = xSheet->GetItemSet().getHash(); + if( pExistingSheet->GetItemSet().getHash() != nHash ) { - sal_Int32 nHash = xSheet->GetItemSet().getHash(); - if( pExistingSheet->GetItemSet().getHash() != nHash ) + // we have found a sheet with the same name, but different contents. Try to find a new name. + // If we already have a sheet with the new name, and it is equal to the one in the source pool, + // do nothing. + OUString aTmpName = aName + rRenameSuffix; + sal_Int32 nSuffix = 1; + do { - OUString aTmpName = aName + rRenameSuffix; - sal_Int32 nSuffix = 1; - do - { - aTmpName = aName + rRenameSuffix + OUString::number(nSuffix); - pExistingSheet = Find(aTmpName, eFamily); - nSuffix++; - } while( pExistingSheet && pExistingSheet->GetItemSet().getHash() != nHash ); - aName = aTmpName; - bAddToList = true; - } + aTmpName = aName + rRenameSuffix + OUString::number(nSuffix); + pExistingSheet = Find(aTmpName, eFamily); + nSuffix++; + } while( pExistingSheet && pExistingSheet->GetItemSet().getHash() != nHash ); + aName = aTmpName; + bAddToList = true; } + + // we do not already have a sheet with the same name and contents. Create a new one. if ( !pExistingSheet ) { rtl::Reference< SfxStyleSheetBase > xNewSheet( &Make( aName, eFamily ) ); @@ -701,6 +725,8 @@ void SdStyleSheetPool::CopySheets(SdStyleSheetPool& rSourcePool, SfxStyleFamily DBG_ASSERT( rSourcePool.Find( (*aIter).second, eFamily ), "StyleSheet has invalid parent: Family mismatch" ); (*aIter).first->SetParent( (*aIter).second ); } + // we have changed names of style sheets. Trigger reindexing. + Reindex(); } @@ -902,15 +928,30 @@ void SdStyleSheetPool::CreatePseudosIfNecessary() |* \************************************************************************/ +namespace +{ +struct StyleSheetIsUserDefinedPredicate : svl::StyleSheetPredicate +{ + StyleSheetIsUserDefinedPredicate() + {;} + + bool Check(const SfxStyleSheetBase& sheet) + { + return sheet.IsUserDefined(); + } +}; +} + void SdStyleSheetPool::UpdateStdNames() { OUString aHelpFile; - sal_uInt32 nCount = aStyles.size(); + StyleSheetIsUserDefinedPredicate aPredicate; std::vector<SfxStyleSheetBase*> aEraseList; - - for( sal_uInt32 n=0; n < nCount; n++ ) + std::vector<unsigned> aUserDefinedStyles = GetIndexedStyleSheets().FindPositionsByPredicate(aPredicate); + for (std::vector<unsigned>::const_iterator it = aUserDefinedStyles.begin(); + it != aUserDefinedStyles.end(); ++it) { - SfxStyleSheetBase* pStyle = aStyles[ n ].get(); + SfxStyleSheetBase* pStyle = GetStyleSheetByPositionInIndex(*it).get(); if( !pStyle->IsUserDefined() ) { @@ -991,6 +1032,7 @@ void SdStyleSheetPool::UpdateStdNames() // Sheet does exist: old sheet has to be removed aEraseList.push_back( pStyle ); } + Reindex(); } } } @@ -999,6 +1041,7 @@ void SdStyleSheetPool::UpdateStdNames() // styles that could not be renamed, must be removed for ( size_t i = 0, n = aEraseList.size(); i < n; ++i ) Remove( aEraseList[ i ] ); + Reindex(); } // Set new SvxNumBulletItem for the respective style sheet diff --git a/svl/CppunitTest_svl_items.mk b/svl/CppunitTest_svl_items.mk new file mode 100644 index 000000000000..d51b8fc43af3 --- /dev/null +++ b/svl/CppunitTest_svl_items.mk @@ -0,0 +1,42 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,svl_items)) + +$(eval $(call gb_CppunitTest_use_external,svl_items,boost_headers)) + +$(eval $(call gb_CppunitTest_use_api,svl_items, \ + offapi \ + udkapi \ +)) + + +#$(eval $(call gb_CppunitTest_use_components,svl_items, \ +# ucb/source/core/ucb1 \ +#)) + +$(eval $(call gb_CppunitTest_add_exception_objects,svl_items, \ + svl/qa/unit/items/test_IndexedStyleSheets \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,svl_items, \ + svl \ + comphelper \ + sal \ + cppu \ + cppuhelper \ +)) + +#$(eval $(call gb_CppunitTest_use_ure,svl_items)) + +#$(eval $(call gb_CppunitTest_use_components,svl_urihelper,\ +# i18npool/util/i18npool \ +#)) + +# vim: set noet sw=4 ts=4: diff --git a/svl/Library_svl.mk b/svl/Library_svl.mk index ba4d9b9b6121..a53b22340b58 100644 --- a/svl/Library_svl.mk +++ b/svl/Library_svl.mk @@ -79,6 +79,7 @@ $(eval $(call gb_Library_add_exception_objects,svl,\ svl/source/items/itemiter \ svl/source/items/itempool \ svl/source/items/itemprop \ + svl/source/items/IndexedStyleSheets \ svl/source/items/itemset \ svl/source/items/lckbitem \ svl/source/items/macitem \ diff --git a/svl/Module_svl.mk b/svl/Module_svl.mk index 684642c188ea..2e5e6a06dae3 100644 --- a/svl/Module_svl.mk +++ b/svl/Module_svl.mk @@ -32,6 +32,7 @@ $(eval $(call gb_Module_add_l10n_targets,svl,\ $(eval $(call gb_Module_add_check_targets,svl,\ CppunitTest_svl_lngmisc \ CppunitTest_svl_qa_cppunit \ + CppunitTest_svl_items \ )) #TODO: CppunitTest_svl_urihelper depends on ucb, can only be added once svl is diff --git a/svl/qa/unit/items/test_IndexedStyleSheets.cxx b/svl/qa/unit/items/test_IndexedStyleSheets.cxx new file mode 100644 index 000000000000..ec8d82dcd5fd --- /dev/null +++ b/svl/qa/unit/items/test_IndexedStyleSheets.cxx @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <svl/IndexedStyleSheets.hxx> + +// for SfxStyleSheetBase +#include <svl/style.hxx> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +using namespace svl; + +class MockedStyleSheet : public SfxStyleSheetBase +{ + public: + MockedStyleSheet(const rtl::OUString& name) + : SfxStyleSheetBase(name, NULL, SFX_STYLE_FAMILY_CHAR, 0) + {;} + +}; + +class IndexedStyleSheetsTest : public CppUnit::TestFixture +{ + void InstantiationWorks(); + void AddedStylesheetsCanBeFoundAndRetrievedByPosition(); + void AddingSameStylesheetTwiceHasNoEffect(); + void RemovedStyleSheetIsNotFound(); + void RemovingStyleSheetWhichIsNotAvailableHasNoEffect(); + void StyleSheetsCanBeRetrievedByTheirName(); + void KnowsThatItStoresAStyleSheet(); + + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE(IndexedStyleSheetsTest); + + CPPUNIT_TEST(InstantiationWorks); + CPPUNIT_TEST(AddedStylesheetsCanBeFoundAndRetrievedByPosition); + CPPUNIT_TEST(AddingSameStylesheetTwiceHasNoEffect); + CPPUNIT_TEST(RemovedStyleSheetIsNotFound); + CPPUNIT_TEST(RemovingStyleSheetWhichIsNotAvailableHasNoEffect); + CPPUNIT_TEST(StyleSheetsCanBeRetrievedByTheirName); + CPPUNIT_TEST(KnowsThatItStoresAStyleSheet); + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); + +}; + +void IndexedStyleSheetsTest::InstantiationWorks() +{ + IndexedStyleSheets iss; +} + +void IndexedStyleSheetsTest::AddedStylesheetsCanBeFoundAndRetrievedByPosition() +{ + rtl::OUString name1("name1"); + rtl::OUString name2("name2"); + rtl::Reference<SfxStyleSheetBase> sheet1(new MockedStyleSheet(name1)); + rtl::Reference<SfxStyleSheetBase> sheet2(new MockedStyleSheet(name2)); + IndexedStyleSheets iss; + iss.AddStyleSheet(sheet1); + iss.AddStyleSheet(sheet2); + unsigned pos = iss.FindStyleSheetPosition(*sheet2); + rtl::Reference<SfxStyleSheetBase> retrieved = iss.GetStyleSheetByPosition(pos); + CPPUNIT_ASSERT_EQUAL_MESSAGE("retrieved sheet is that which has been inserted.", sheet2.get(), retrieved.get()); +} + +void IndexedStyleSheetsTest::AddingSameStylesheetTwiceHasNoEffect() +{ + rtl::Reference<SfxStyleSheetBase> sheet1(new MockedStyleSheet(rtl::OUString("sheet1"))); + IndexedStyleSheets iss; + iss.AddStyleSheet(sheet1); + CPPUNIT_ASSERT_EQUAL(1u, iss.GetNumberOfStyleSheets()); + iss.AddStyleSheet(sheet1); + CPPUNIT_ASSERT_EQUAL(1u, iss.GetNumberOfStyleSheets()); +} + +void IndexedStyleSheetsTest::RemovedStyleSheetIsNotFound() +{ + rtl::OUString name1("name1"); + rtl::OUString name2("name2"); + rtl::Reference<SfxStyleSheetBase> sheet1(new MockedStyleSheet(name1)); + rtl::Reference<SfxStyleSheetBase> sheet2(new MockedStyleSheet(name2)); + IndexedStyleSheets iss; + iss.AddStyleSheet(sheet1); + iss.AddStyleSheet(sheet2); + iss.RemoveStyleSheet(sheet1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Removed style sheet is not found.", + false, iss.HasStyleSheet(sheet1)); +} + +void IndexedStyleSheetsTest::RemovingStyleSheetWhichIsNotAvailableHasNoEffect() +{ + rtl::Reference<SfxStyleSheetBase> sheet1(new MockedStyleSheet(rtl::OUString("sheet1"))); + rtl::Reference<SfxStyleSheetBase> sheet2(new MockedStyleSheet(rtl::OUString("sheet2"))); + IndexedStyleSheets iss; + iss.AddStyleSheet(sheet1); + CPPUNIT_ASSERT_EQUAL(1u, iss.GetNumberOfStyleSheets()); + iss.RemoveStyleSheet(sheet2); + CPPUNIT_ASSERT_EQUAL(1u, iss.GetNumberOfStyleSheets()); +} + +void IndexedStyleSheetsTest::StyleSheetsCanBeRetrievedByTheirName() +{ + rtl::OUString name1("name1"); + rtl::OUString name2("name2"); + rtl::Reference<SfxStyleSheetBase> sheet1(new MockedStyleSheet(name1)); + rtl::Reference<SfxStyleSheetBase> sheet2(new MockedStyleSheet(name2)); + rtl::Reference<SfxStyleSheetBase> sheet3(new MockedStyleSheet(name1)); + IndexedStyleSheets iss; + iss.AddStyleSheet(sheet1); + iss.AddStyleSheet(sheet2); + iss.AddStyleSheet(sheet3); + + std::vector<unsigned> r = iss.FindPositionsByName(name1); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Two style sheets are found by 'name1'", + 2u, static_cast<unsigned>(r.size())); + CPPUNIT_ASSERT_EQUAL(0u, r.at(0)); + CPPUNIT_ASSERT_EQUAL(2u, r.at(1)); + + r = iss.FindPositionsByName(name2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("One style sheets is found by 'name2'", + 1u, static_cast<unsigned>(r.size())); + CPPUNIT_ASSERT_EQUAL(1u, r.at(0)); +} + +void IndexedStyleSheetsTest::KnowsThatItStoresAStyleSheet() +{ + rtl::OUString name1("name1"); + rtl::OUString name2("name2"); + rtl::Reference<SfxStyleSheetBase> sheet1(new MockedStyleSheet(name1)); + rtl::Reference<SfxStyleSheetBase> sheet2(new MockedStyleSheet(name1)); + rtl::Reference<SfxStyleSheetBase> sheet3(new MockedStyleSheet(name2)); + rtl::Reference<SfxStyleSheetBase> sheet4(new MockedStyleSheet(name1)); + IndexedStyleSheets iss; + iss.AddStyleSheet(sheet1); + iss.AddStyleSheet(sheet2); + iss.AddStyleSheet(sheet3); + // do not add sheet 4 + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Finds first stored style sheet even though two style sheets have the same name.", + true, iss.HasStyleSheet(sheet1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Finds second stored style sheet even though two style sheets have the same name.", + true, iss.HasStyleSheet(sheet2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Does not find style sheet which is not stored and has the same name as a stored.", + false, iss.HasStyleSheet(sheet4)); + +} + +CPPUNIT_TEST_SUITE_REGISTRATION(IndexedStyleSheetsTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/svl/source/items/IndexedStyleSheets.cxx b/svl/source/items/IndexedStyleSheets.cxx new file mode 100644 index 000000000000..ca45b534ee92 --- /dev/null +++ b/svl/source/items/IndexedStyleSheets.cxx @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + + +#include <svl/IndexedStyleSheets.hxx> +#include <svl/style.hxx> + +#include <stdexcept> +#include <utility> + +using rtl::OUString; + +namespace svl { + +IndexedStyleSheets::IndexedStyleSheets() +{;} + + +void +IndexedStyleSheets::Register(const rtl::OUString& name, unsigned pos) +{ + mPositionsByName.insert(std::make_pair(name, pos)); +} + +void +IndexedStyleSheets::Reindex() +{ + mPositionsByName.clear(); + unsigned i = 0; + for (VectorType::const_iterator it = mStyleSheets.begin(); + it != mStyleSheets.end(); ++it) { + SfxStyleSheetBase* p = it->get(); + Register(p->GetName(), i); + ++i; + } +} + +unsigned +IndexedStyleSheets::GetNumberOfStyleSheets() const +{ + return mStyleSheets.size(); +} + +void +IndexedStyleSheets::AddStyleSheet(rtl::Reference< SfxStyleSheetBase > style) +{ + if (!HasStyleSheet(style)) { + mStyleSheets.push_back(style); + // since we just added an element to the vector, we can safely do -1 as it will always be >= 1 + Register(style->GetName(), mStyleSheets.size()-1); + } +} + +bool +IndexedStyleSheets::RemoveStyleSheet(rtl::Reference< SfxStyleSheetBase > style) +{ + rtl::OUString styleName = style->GetName(); + std::vector<unsigned> positions = FindPositionsByName(styleName); + bool found = false; + unsigned stylePosition = 0; + for (std::vector<unsigned>::const_iterator it = positions.begin(); + it != positions.end(); ++it) { + if (mStyleSheets.at(*it) == style) { + found = true; + stylePosition = *it; + break; + } + } + + if (found) { + mStyleSheets.erase(mStyleSheets.begin() + stylePosition); + Reindex(); + } + return found; +} + +std::vector<unsigned> +IndexedStyleSheets::FindPositionsByName(const rtl::OUString& name) const +{ + std::vector<unsigned> r; + std::pair<MapType::const_iterator, MapType::const_iterator> range = mPositionsByName.equal_range(name); + for (MapType::const_iterator it = range.first; it != range.second; ++it) { + r.push_back(it->second); + } + return r; +} + +std::vector<unsigned> +IndexedStyleSheets::FindPositionsByNameAndPredicate(const rtl::OUString& name, + StyleSheetPredicate& predicate) const +{ + std::vector<unsigned> r; + MapType::const_iterator it = mPositionsByName.find(name); + for (/**/; it != mPositionsByName.end(); ++it) { + unsigned pos = it->second; + SfxStyleSheetBase *ssheet = mStyleSheets.at(pos).get(); + if (predicate.Check(*ssheet)) { + r.push_back(pos); + } + } + return r; +} + + +unsigned +IndexedStyleSheets::GetNumberOfStyleSheetsWithPredicate(StyleSheetPredicate& predicate) const +{ + unsigned r = 0; + for (VectorType::const_iterator it = mStyleSheets.begin(); it != mStyleSheets.end(); ++it) { + const SfxStyleSheetBase *ssheet = it->get(); + if (predicate.Check(*ssheet)) { + ++r; + } + } + return r; +} + +rtl::Reference<SfxStyleSheetBase> +IndexedStyleSheets::GetNthStyleSheetThatMatchesPredicate( + unsigned n, + StyleSheetPredicate& predicate, + unsigned startAt) +{ + rtl::Reference<SfxStyleSheetBase> retval; + unsigned matching = 0; + for (VectorType::iterator it = mStyleSheets.begin()+startAt; it != mStyleSheets.end(); ++it) { + SfxStyleSheetBase *ssheet = it->get(); + if (predicate.Check(*ssheet)) { + if (matching == n) { + retval = *it; + break; + } + ++matching; + } + } + return retval; +} + +unsigned +IndexedStyleSheets::FindStyleSheetPosition(const SfxStyleSheetBase& style) const +{ + VectorType::const_iterator it = std::find(mStyleSheets.begin(), mStyleSheets.end(), &style); + if (it == mStyleSheets.end()) { + throw std::runtime_error("IndexedStyleSheets::FindStylePosition Looked for style not in index"); + } + return std::distance(mStyleSheets.begin(), it); +} + +void +IndexedStyleSheets::Clear(StyleSheetDisposer& disposer) +{ + for (VectorType::iterator it = mStyleSheets.begin(); it != mStyleSheets.end(); ++it) { + disposer.Dispose(*it); + } + mStyleSheets.clear(); + mPositionsByName.clear(); +} + +IndexedStyleSheets::~IndexedStyleSheets() +{;} + +bool +IndexedStyleSheets::HasStyleSheet(rtl::Reference< SfxStyleSheetBase > style) const +{ + rtl::OUString styleName = style->GetName(); + std::vector<unsigned> positions = FindPositionsByName(styleName); + for (std::vector<unsigned>::const_iterator it = positions.begin(); + it != positions.end(); ++it) { + if (mStyleSheets.at(*it) == style) { + return true; + } + } + return false; +} + +rtl::Reference< SfxStyleSheetBase > +IndexedStyleSheets::GetStyleSheetByPosition(unsigned pos) +{ + return mStyleSheets.at(pos); +} + +void +IndexedStyleSheets::ApplyToAllStyleSheets(StyleSheetCallback& callback) const +{ + for (VectorType::const_iterator it = mStyleSheets.begin(); it != mStyleSheets.end(); ++it) { + callback.DoIt(**it); + } +} + +std::vector<unsigned> +IndexedStyleSheets::FindPositionsByPredicate(StyleSheetPredicate& predicate) const +{ + std::vector<unsigned> r; + for (VectorType::const_iterator it = mStyleSheets.begin(); it != mStyleSheets.end(); ++it) { + if (predicate.Check(**it)) { + r.push_back(std::distance(mStyleSheets.begin(), it)); + } + } + return r; +} + +} /* namespace svl */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svl/source/items/style.cxx b/svl/source/items/style.cxx index 126cd814b4cb..ab9800e29bb2 100644 --- a/svl/source/items/style.cxx +++ b/svl/source/items/style.cxx @@ -26,12 +26,16 @@ #include <svl/poolitem.hxx> #include <svl/itemset.hxx> #include <svl/itempool.hxx> +#include <svl/IndexedStyleSheets.hxx> #include <poolio.hxx> #include <svl/itemiter.hxx> #include <svl/style.hxx> #include <unotools/syslocale.hxx> #include <algorithm> #include <comphelper/servicehelper.hxx> + +#include <boost/numeric/conversion/cast.hpp> + #include <string.h> #ifdef DBG_UTIL @@ -362,22 +366,35 @@ inline bool SfxStyleSheetIterator::IsTrivialSearch() (GetSearchFamily() == SFX_STYLE_FAMILY_ALL); } -bool SfxStyleSheetIterator::DoesStyleMatch(SfxStyleSheetBase *pStyle) +namespace { + +struct DoesStyleMatchStyleSheetPredicate SAL_FINAL : public svl::StyleSheetPredicate { - bool bMatchFamily = ((GetSearchFamily() == SFX_STYLE_FAMILY_ALL) || - ( pStyle->GetFamily() == GetSearchFamily() )); + DoesStyleMatchStyleSheetPredicate(SfxStyleSheetIterator *it) + : mIterator(it) {;} - bool bUsed = bSearchUsed ? pStyle->IsUsed( ) : false; + bool + Check(const SfxStyleSheetBase& styleSheet) + { + bool bMatchFamily = ((mIterator->GetSearchFamily() == SFX_STYLE_FAMILY_ALL) || + ( styleSheet.GetFamily() == mIterator->GetSearchFamily() )); + + bool bUsed = mIterator->SearchUsed() ? styleSheet.IsUsed( ) : false; - bool bSearchHidden = ( GetSearchMask() & SFXSTYLEBIT_HIDDEN ); - bool bMatchVisibility = !( !bSearchHidden && pStyle->IsHidden() && !bUsed ); - bool bOnlyHidden = GetSearchMask( ) == SFXSTYLEBIT_HIDDEN && pStyle->IsHidden( ); + bool bSearchHidden = ( mIterator->GetSearchMask() & SFXSTYLEBIT_HIDDEN ); + bool bMatchVisibility = !( !bSearchHidden && styleSheet.IsHidden() && !bUsed ); + bool bOnlyHidden = mIterator->GetSearchMask( ) == SFXSTYLEBIT_HIDDEN && styleSheet.IsHidden( ); + + bool bMatches = bMatchFamily && bMatchVisibility + && (( styleSheet.GetMask() & ( mIterator->GetSearchMask() & ~SFXSTYLEBIT_USED )) || + bUsed || bOnlyHidden || + ( mIterator->GetSearchMask() & SFXSTYLEBIT_ALL_VISIBLE ) == SFXSTYLEBIT_ALL_VISIBLE ); + return bMatches; + } + + SfxStyleSheetIterator *mIterator; +}; - bool bMatches = bMatchFamily && bMatchVisibility - && (( pStyle->GetMask() & ( GetSearchMask() & ~SFXSTYLEBIT_USED )) || - bUsed || bOnlyHidden || - ( GetSearchMask() & SFXSTYLEBIT_ALL_VISIBLE ) == SFXSTYLEBIT_ALL_VISIBLE ); - return bMatches; } SfxStyleSheetIterator::SfxStyleSheetIterator(SfxStyleSheetBasePool *pBase, @@ -403,111 +420,94 @@ sal_uInt16 SfxStyleSheetIterator::Count() { sal_uInt16 n = 0; if( IsTrivialSearch()) - n = (sal_uInt16) pBasePool->aStyles.size(); + { + n = (sal_uInt16) pBasePool->mIndexedStyleSheets->GetNumberOfStyleSheets(); + } else - for(sal_uInt16 i=0; i<pBasePool->aStyles.size(); i++) - { - SfxStyleSheetBase* pStyle = pBasePool->aStyles[i].get(); - if(DoesStyleMatch(pStyle)) - n++; - } + { + DoesStyleMatchStyleSheetPredicate predicate(this); + n = pBasePool->mIndexedStyleSheets->GetNumberOfStyleSheetsWithPredicate(predicate); + } return n; } SfxStyleSheetBase* SfxStyleSheetIterator::operator[](sal_uInt16 nIdx) { + SfxStyleSheetBase* retval = NULL; if( IsTrivialSearch()) - return pBasePool->aStyles[nIdx].get(); - - sal_uInt16 z = 0; - for(sal_uInt16 n=0; n<pBasePool->aStyles.size(); n++) { - SfxStyleSheetBase* pStyle = pBasePool->aStyles[n].get(); - if( DoesStyleMatch(pStyle)) - { - if(z == nIdx) - { - nAktPosition=n; - return pAktStyle=pStyle; - } - ++z; - } + retval = pBasePool->mIndexedStyleSheets->GetStyleSheetByPosition(nIdx).get(); } - OSL_FAIL("Incorrect index"); - return 0; -} - -SfxStyleSheetBase* SfxStyleSheetIterator::First() -{ - sal_Int32 nIdx = -1; - - if ( IsTrivialSearch() && pBasePool->aStyles.size() ) - nIdx = 0; else - for( sal_uInt16 n = 0; n < pBasePool->aStyles.size(); n++ ) + { + DoesStyleMatchStyleSheetPredicate predicate(this); + rtl::Reference< SfxStyleSheetBase > ref = + pBasePool->mIndexedStyleSheets->GetNthStyleSheetThatMatchesPredicate(nIdx, predicate); + if (ref.get() != NULL) { - SfxStyleSheetBase* pStyle = pBasePool->aStyles[n].get(); - - if ( DoesStyleMatch( pStyle ) ) - { - nIdx = n; - break; - } + nAktPosition = pBasePool->mIndexedStyleSheets->FindStyleSheetPosition(*ref); + retval = ref.get(); } + } - if ( nIdx != -1 ) + if (retval == NULL) { - nAktPosition = (sal_uInt16)nIdx; - return pAktStyle = pBasePool->aStyles[nIdx].get(); + OSL_FAIL("Incorrect index"); } - return 0; + + return retval; +} + +SfxStyleSheetBase* SfxStyleSheetIterator::First() +{ + return operator[](0); } SfxStyleSheetBase* SfxStyleSheetIterator::Next() { - sal_Int32 nIdx = -1; + SfxStyleSheetBase* retval = NULL; - if ( IsTrivialSearch() && - (sal_uInt16)pBasePool->aStyles.size() > nAktPosition + 1 ) - nIdx = nAktPosition + 1; - else - for( sal_uInt16 n = nAktPosition + 1; n < pBasePool->aStyles.size(); n++ ) + if ( IsTrivialSearch() ) + { + unsigned nStyleSheets = pBasePool->mIndexedStyleSheets->GetNumberOfStyleSheets(); + unsigned newPosition = nAktPosition +1; + if (nStyleSheets > newPosition) { - SfxStyleSheetBase* pStyle = pBasePool->aStyles[n].get(); - - if ( DoesStyleMatch( pStyle ) ) - { - nIdx = n; - break; - } + nAktPosition = newPosition; + retval = pBasePool->mIndexedStyleSheets->GetStyleSheetByPosition(nAktPosition).get(); } - - if ( nIdx != -1 ) + } + else { - nAktPosition = (sal_uInt16)nIdx; - return pAktStyle = pBasePool->aStyles[nIdx].get(); + DoesStyleMatchStyleSheetPredicate predicate(this); + rtl::Reference< SfxStyleSheetBase > ref = + pBasePool->mIndexedStyleSheets->GetNthStyleSheetThatMatchesPredicate( + 0, predicate, nAktPosition+1); + retval = ref.get(); + if (retval != NULL) { + nAktPosition = pBasePool->mIndexedStyleSheets->FindStyleSheetPosition(*ref); + } } - return 0; + pAktStyle = retval; + return retval; } - SfxStyleSheetBase* SfxStyleSheetIterator::Find(const OUString& rStr) { - for ( sal_uInt16 n = 0; n < pBasePool->aStyles.size(); ++n ) - { - SfxStyleSheetBase* pStyle = pBasePool->aStyles[n].get(); + DoesStyleMatchStyleSheetPredicate predicate(this); - // #98454# performance: in case of bSearchUsed==sal_True it may be - // significant to first compare the name and only if it matches to call - // the style sheet IsUsed() method in DoesStyleMatch(). - if ( pStyle->GetName() == rStr && DoesStyleMatch( pStyle ) ) - { - nAktPosition = n; - return pAktStyle = pStyle; - } + std::vector<unsigned> positions = + pBasePool->mIndexedStyleSheets->FindPositionsByNameAndPredicate(rStr, predicate); + if (positions.empty()) { + return NULL; } - return 0; + + unsigned pos = positions.front(); + SfxStyleSheetBase* pStyle = pBasePool->mIndexedStyleSheets->GetStyleSheetByPosition(pos).get(); + nAktPosition = pos; + pAktStyle = pStyle; + return pAktStyle; } sal_uInt16 SfxStyleSheetIterator::GetSearchMask() const @@ -545,6 +545,7 @@ SfxStyleSheetBasePool::SfxStyleSheetBasePool( SfxItemPool& r ) , rPool(r) , nSearchFamily(SFX_STYLE_FAMILY_PARA) , nMask(SFXSTYLEBIT_ALL) + , mIndexedStyleSheets(new svl::IndexedStyleSheets) { #ifdef DBG_UTIL aDbgStyleSheetReferences.mnPools++; @@ -560,6 +561,7 @@ SfxStyleSheetBasePool::SfxStyleSheetBasePool( const SfxStyleSheetBasePool& r ) , rPool(r.rPool) , nSearchFamily(r.nSearchFamily) , nMask( r.nMask ) + , mIndexedStyleSheets(new svl::IndexedStyleSheets) { #ifdef DBG_UTIL aDbgStyleSheetReferences.mnPools++; @@ -637,7 +639,7 @@ SfxStyleSheetBase& SfxStyleSheetBasePool::Make( const OUString& rName, SfxStyleF if( !xStyle.is() ) { xStyle = Create( rName, eFam, mask ); - aStyles.push_back(xStyle); + StoreStyleSheet(xStyle); Broadcast( SfxStyleSheetHint( SFX_STYLESHEET_CREATED, *xStyle.get() ) ); } return *xStyle.get(); @@ -647,13 +649,15 @@ SfxStyleSheetBase& SfxStyleSheetBasePool::Make( const OUString& rName, SfxStyleF // sie neu erzeugt. Alle Vorlagen, die diese Vorlage zum Parent haben, // werden umgehaengt. -SfxStyleSheetBase& SfxStyleSheetBasePool::Add( SfxStyleSheetBase& rSheet ) +SfxStyleSheetBase& SfxStyleSheetBasePool::Add( const SfxStyleSheetBase& rSheet ) { SfxStyleSheetIterator aIter(this, rSheet.GetFamily(), nMask); SfxStyleSheetBase* pOld = aIter.Find( rSheet.GetName() ); - Remove( pOld ); + if (pOld) { + Remove( pOld ); + } rtl::Reference< SfxStyleSheetBase > xNew( Create( rSheet ) ); - aStyles.push_back( xNew ); + mIndexedStyleSheets->AddStyleSheet(xNew); Broadcast( SfxStyleSheetHint( SFX_STYLESHEET_CHANGED, *xNew.get() ) ); return *xNew.get(); } @@ -668,15 +672,27 @@ SfxStyleSheetBasePool& SfxStyleSheetBasePool::operator=( const SfxStyleSheetBase return *this; } +namespace { +struct AddStyleSheetCallback : svl::StyleSheetCallback +{ + AddStyleSheetCallback(SfxStyleSheetBasePool *pool) + : mPool(pool) {;} + + void DoIt(const SfxStyleSheetBase& ssheet) + { + mPool->Add(ssheet); + } + + SfxStyleSheetBasePool *mPool; +}; +} + SfxStyleSheetBasePool& SfxStyleSheetBasePool::operator+=( const SfxStyleSheetBasePool& r ) { if( &r != this ) { - SfxStyles::const_iterator aIter( r.aStyles.begin() ); - while( aIter != r.aStyles.end() ) - { - Add(*(*aIter++).get()); - } + AddStyleSheetCallback callback(this); + mIndexedStyleSheets->ApplyToAllStyleSheets(callback); } return *this; } @@ -715,9 +731,8 @@ void SfxStyleSheetBasePool::Remove( SfxStyleSheetBase* p ) { // Reference to keep p alive until after Broadcast call! rtl::Reference<SfxStyleSheetBase> xP(p); - SfxStyles::iterator const aIter( - std::find(aStyles.begin(), aStyles.end(), xP)); - if( aIter != aStyles.end() ) + bool bWasRemoved = mIndexedStyleSheets->RemoveStyleSheet(xP); + if( bWasRemoved ) { // Alle Styles umsetzen, deren Parent dieser hier ist ChangeParent( p->GetName(), p->GetParent() ); @@ -735,8 +750,6 @@ void SfxStyleSheetBasePool::Remove( SfxStyleSheetBase* p ) // catch( com::sun::star::uno::Exception& ) // { // } - - aStyles.erase(aIter); Broadcast( SfxStyleSheetHint( SFX_STYLESHEET_ERASED, *p ) ); } } @@ -756,19 +769,24 @@ void SfxStyleSheetBasePool::Insert( SfxStyleSheetBase* p ) OSL_ENSURE( pOld, "svl::SfxStyleSheetBasePool::Insert(), Parent not found!" ); } #endif - aStyles.push_back( rtl::Reference< SfxStyleSheetBase >( p ) ); + StoreStyleSheet(rtl::Reference< SfxStyleSheetBase >( p ) ); Broadcast( SfxStyleSheetHint( SFX_STYLESHEET_CREATED, *p ) ); } -void SfxStyleSheetBasePool::Clear() +namespace { - SfxStyles aClearStyles; - aClearStyles.swap( aStyles ); - SfxStyles::iterator aIter( aClearStyles.begin() ); - while( aIter != aClearStyles.end() ) +struct StyleSheetDisposerFunctor SAL_FINAL : public svl::StyleSheetDisposer +{ + StyleSheetDisposerFunctor(SfxStyleSheetBasePool* pool) + : mPool(pool) {;} + + void + Dispose(rtl::Reference<SfxStyleSheetBase> styleSheet) { - com::sun::star::uno::Reference< com::sun::star::lang::XComponent > xComp( static_cast< ::cppu::OWeakObject* >((*aIter).get()), com::sun::star::uno::UNO_QUERY ); + cppu::OWeakObject* weakObject = static_cast< ::cppu::OWeakObject* >(styleSheet.get()); + com::sun::star::uno::Reference< com::sun::star::lang::XComponent > + xComp( weakObject, com::sun::star::uno::UNO_QUERY ); if( xComp.is() ) try { xComp->dispose(); @@ -776,9 +794,18 @@ void SfxStyleSheetBasePool::Clear() catch( com::sun::star::uno::Exception& ) { } - - Broadcast( SfxStyleSheetHint( SFX_STYLESHEET_ERASED, *(*aIter++).get() ) ); + mPool->Broadcast( SfxStyleSheetHint( SFX_STYLESHEET_ERASED, *styleSheet.get() ) ); } + + SfxStyleSheetBasePool* mPool; +}; + +} + +void SfxStyleSheetBasePool::Clear() +{ + StyleSheetDisposerFunctor cleanup(this); + mIndexedStyleSheets->Clear(cleanup); } void SfxStyleSheetBasePool::ChangeParent(const OUString& rOld, @@ -928,6 +955,11 @@ SfxUnoStyleSheet* SfxUnoStyleSheet::getUnoStyleSheet( const ::com::sun::star::un } } +void +SfxStyleSheetBasePool::StoreStyleSheet(rtl::Reference< SfxStyleSheetBase > xStyle) +{ + mIndexedStyleSheets->AddStyleSheet(xStyle); +} namespace { @@ -939,4 +971,22 @@ const ::com::sun::star::uno::Sequence< ::sal_Int8 >& SfxUnoStyleSheet::getIdenti return theSfxUnoStyleSheetIdentifier::get().getSeq(); } +void +SfxStyleSheetBasePool::Reindex() +{ + mIndexedStyleSheets->Reindex(); +} + +const svl::IndexedStyleSheets& +SfxStyleSheetBasePool::GetIndexedStyleSheets() const +{ + return *mIndexedStyleSheets; +} + +rtl::Reference<SfxStyleSheetBase> +SfxStyleSheetBasePool::GetStyleSheetByPositionInIndex(unsigned pos) +{ + return mIndexedStyleSheets->GetStyleSheetByPosition(pos); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |