Kaydet (Commit) 0c17ccc4 authored tarafından Tobias Lippert's avatar Tobias Lippert Kaydeden (comit) Caolán McNamara

fdo#30770 - Speed up xslx import

Conflicts:
	include/svl/style.hxx

Change-Id: Ie3d855923c651b6e05c0054c8e30155218279045
Reviewed-on: https://gerrit.libreoffice.org/8485Reviewed-by: 's avatarCaolán McNamara <caolanm@redhat.com>
Tested-by: 's avatarCaolán McNamara <caolanm@redhat.com>
üst e3e1f9f3
/* -*- 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: */
......@@ -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;
};
......
......@@ -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;
}
......
......@@ -1103,6 +1103,7 @@ void SdDrawDocument::RenameLayoutTemplate(const OUString& rOldLayoutName, const
aReplList.push_back(aReplData);
pSheet->SetName(aSheetName);
mxStyleSheetPool.get()->Reindex();
}
pSheet = aIter.Next();
......
......@@ -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
......
# -*- 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:
......@@ -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 \
......
......@@ -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
......
/* -*- 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();
/* -*- 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: */
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment