summaryrefslogtreecommitdiff
path: root/svl/source/items/stylepool.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svl/source/items/stylepool.cxx')
-rw-r--r--svl/source/items/stylepool.cxx541
1 files changed, 541 insertions, 0 deletions
diff --git a/svl/source/items/stylepool.cxx b/svl/source/items/stylepool.cxx
new file mode 100644
index 000000000000..8a9f16052a8a
--- /dev/null
+++ b/svl/source/items/stylepool.cxx
@@ -0,0 +1,541 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svl.hxx"
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#include <vector>
+#include <map>
+
+#include "stylepool.hxx"
+#include <svl/itemiter.hxx>
+#include <svl/itempool.hxx>
+
+
+using namespace boost;
+
+namespace {
+ // A "Node" represents a subset of inserted SfxItemSets
+ // The root node represents the empty set
+ // The other nodes contain a SfxPoolItem and represents an item set which contains their
+ // pool item and the pool items of their parents.
+ class Node
+ {
+ std::vector<Node*> mChildren; // child nodes, create by findChildNode(..)
+ // container of shared pointers of inserted item sets; for non-poolable
+ // items more than one item set is needed
+ std::vector< StylePool::SfxItemSet_Pointer_t > maItemSet;
+ const SfxPoolItem *mpItem; // my pool item
+ Node *mpUpper; // if I'm a child node that's my parent node
+ // --> OD 2008-03-07 #i86923#
+ const bool mbIsItemIgnorable;
+ // <--
+ public:
+ // --> OD 2008-03-07 #i86923#
+ Node() // root node Ctor
+ : mChildren(),
+ maItemSet(),
+ mpItem( 0 ),
+ mpUpper( 0 ),
+ mbIsItemIgnorable( false )
+ {}
+ Node( const SfxPoolItem& rItem, Node* pParent, const bool bIgnorable ) // child node Ctor
+ : mChildren(),
+ maItemSet(),
+ mpItem( rItem.Clone() ),
+ mpUpper( pParent ),
+ mbIsItemIgnorable( bIgnorable )
+ {}
+ // <--
+ ~Node();
+ // --> OD 2008-03-11 #i86923#
+ bool hasItemSet( const bool bCheckUsage ) const;
+ // <--
+ // --> OD 2008-04-29 #i87808#
+// const StylePool::SfxItemSet_Pointer_t getItemSet() const { return aItemSet[aItemSet.size()-1]; }
+ const StylePool::SfxItemSet_Pointer_t getItemSet() const
+ {
+ return maItemSet.back();
+ }
+ const StylePool::SfxItemSet_Pointer_t getUsedOrLastAddedItemSet() const;
+ // <--
+ void setItemSet( const SfxItemSet& rSet ){ maItemSet.push_back( StylePool::SfxItemSet_Pointer_t( rSet.Clone() ) ); }
+ // --> OD 2008-03-11 #i86923#
+ Node* findChildNode( const SfxPoolItem& rItem,
+ const bool bIsItemIgnorable = false );
+ Node* nextItemSet( Node* pLast,
+ const bool bSkipUnusedItemSet,
+ const bool bSkipIgnorable );
+ // <--
+ const SfxPoolItem& getPoolItem() const { return *mpItem; }
+ // --> OD 2008-03-11 #i86923#
+ bool hasIgnorableChildren( const bool bCheckUsage ) const;
+ const StylePool::SfxItemSet_Pointer_t getItemSetOfIgnorableChild(
+ const bool bSkipUnusedItemSets ) const;
+ // <--
+ };
+
+ // --> OD 2008-04-29 #i87808#
+ const StylePool::SfxItemSet_Pointer_t Node::getUsedOrLastAddedItemSet() const
+ {
+ std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
+
+ for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
+ {
+ if ( (*aIter).use_count() > 1 )
+ {
+ return *aIter;
+ }
+ }
+
+ return maItemSet.back();
+ }
+ // <--
+
+ // --> OD 2008-05-06 #i86923#
+ bool Node::hasItemSet( const bool bCheckUsage ) const
+ {
+ bool bHasItemSet = false;
+
+ if ( maItemSet.size() > 0 )
+ {
+ if ( bCheckUsage )
+ {
+ std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
+
+ for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
+ {
+ if ( (*aIter).use_count() > 1 )
+ {
+ bHasItemSet = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ bHasItemSet = true;
+ }
+ }
+ return bHasItemSet;
+ }
+ // <--
+
+ // --> OD 2008-03-07 #i86923#
+ Node* Node::findChildNode( const SfxPoolItem& rItem,
+ const bool bIsItemIgnorable )
+ // <--
+ {
+ Node* pNextNode = this;
+ std::vector<Node*>::iterator aIter = mChildren.begin();
+ while( aIter != mChildren.end() )
+ {
+ if( rItem.Which() == (*aIter)->getPoolItem().Which() &&
+ rItem == (*aIter)->getPoolItem() )
+ return *aIter;
+ ++aIter;
+ }
+ // --> OD 2008-03-07 #i86923#
+ pNextNode = new Node( rItem, pNextNode, bIsItemIgnorable );
+ // <--
+ mChildren.push_back( pNextNode );
+ return pNextNode;
+ }
+
+ /* Find the next node which has a SfxItemSet.
+ The input parameter pLast has a sophisticated meaning:
+ downstairs only:
+ pLast == 0 => scan your children and their children
+ but neither your parents neither your siblings
+ downstairs and upstairs:
+ pLast == this => scan your children, their children,
+ the children of your parent behind you, and so on
+ partial downstairs and upstairs
+ pLast != 0 && pLast != this => scan your children behind the given children,
+ the children of your parent behind you and so on.
+
+ OD 2008-03-11 #i86923#
+ introduce parameters <bSkipUnusedItemSets> and <bSkipIgnorable>
+ and its handling.
+ */
+ Node* Node::nextItemSet( Node* pLast,
+ const bool bSkipUnusedItemSets,
+ const bool bSkipIgnorable )
+ {
+ // Searching downstairs
+ std::vector<Node*>::iterator aIter = mChildren.begin();
+ // For pLast == 0 and pLast == this all children are of interest
+ // for another pLast the search starts behind pLast...
+ if( pLast && pLast != this )
+ {
+ aIter = std::find( mChildren.begin(), mChildren.end(), pLast );
+ if( aIter != mChildren.end() )
+ ++aIter;
+ }
+ Node *pNext = 0;
+ while( aIter != mChildren.end() )
+ {
+ // --> OD 2008-03-11 #i86923#
+ if ( bSkipIgnorable && (*aIter)->mbIsItemIgnorable )
+ {
+ ++aIter;
+ continue;
+ }
+ // <--
+ pNext = *aIter;
+ // --> OD 2008-03-11 #i86923#
+ if ( pNext->hasItemSet( bSkipUnusedItemSets ) )
+ {
+ return pNext;
+ }
+ if ( bSkipIgnorable &&
+ pNext->hasIgnorableChildren( bSkipUnusedItemSets ) )
+ {
+ return pNext;
+ }
+ pNext = pNext->nextItemSet( 0, bSkipUnusedItemSets, bSkipIgnorable ); // 0 => downstairs only
+ // <--
+ if( pNext )
+ return pNext;
+ ++aIter;
+ }
+ // Searching upstairs
+ if( pLast && mpUpper )
+ {
+ // --> OD 2008-03-11 #i86923#
+ pNext = mpUpper->nextItemSet( this, bSkipUnusedItemSets, bSkipIgnorable );
+ // <--
+ }
+ return pNext;
+ }
+
+ // --> OD 2008-03-11 #i86923#
+ bool Node::hasIgnorableChildren( const bool bCheckUsage ) const
+ {
+ bool bHasIgnorableChildren( false );
+
+ std::vector<Node*>::const_iterator aIter = mChildren.begin();
+ while( aIter != mChildren.end() && !bHasIgnorableChildren )
+ {
+ Node* pChild = *aIter;
+ if ( pChild->mbIsItemIgnorable )
+ {
+ bHasIgnorableChildren =
+ !bCheckUsage ||
+ ( pChild->hasItemSet( bCheckUsage /* == true */ ) ||
+ pChild->hasIgnorableChildren( bCheckUsage /* == true */ ) );
+ }
+ ++aIter;
+ }
+
+ return bHasIgnorableChildren;
+ }
+
+ const StylePool::SfxItemSet_Pointer_t Node::getItemSetOfIgnorableChild(
+ const bool bSkipUnusedItemSets ) const
+ {
+ DBG_ASSERT( hasIgnorableChildren( bSkipUnusedItemSets ),
+ "<Node::getItemSetOfIgnorableChild> - node has no ignorable children" );
+
+ std::vector<Node*>::const_iterator aIter = mChildren.begin();
+ while( aIter != mChildren.end() )
+ {
+ Node* pChild = *aIter;
+ if ( pChild->mbIsItemIgnorable )
+ {
+ if ( pChild->hasItemSet( bSkipUnusedItemSets ) )
+ {
+ return pChild->getUsedOrLastAddedItemSet();
+ }
+ else
+ {
+ pChild = pChild->nextItemSet( 0, bSkipUnusedItemSets, false );
+ if ( pChild )
+ {
+ return pChild->getUsedOrLastAddedItemSet();
+ }
+ }
+ }
+ ++aIter;
+ }
+
+ StylePool::SfxItemSet_Pointer_t pReturn;
+ return pReturn;
+ }
+ // <--
+
+ Node::~Node()
+ {
+ std::vector<Node*>::iterator aIter = mChildren.begin();
+ while( aIter != mChildren.end() )
+ {
+ delete *aIter;
+ ++aIter;
+ }
+ delete mpItem;
+ }
+
+ class Iterator : public IStylePoolIteratorAccess
+ {
+ std::map< const SfxItemSet*, Node >& mrRoot;
+ std::map< const SfxItemSet*, Node >::iterator mpCurrNode;
+ Node* mpNode;
+ const bool mbSkipUnusedItemSets;
+ const bool mbSkipIgnorable;
+ public:
+ // --> OD 2008-03-07 #i86923#
+ Iterator( std::map< const SfxItemSet*, Node >& rR,
+ const bool bSkipUnusedItemSets,
+ const bool bSkipIgnorable )
+ : mrRoot( rR ),
+ mpCurrNode( rR.begin() ),
+ mpNode(0),
+ mbSkipUnusedItemSets( bSkipUnusedItemSets ),
+ mbSkipIgnorable( bSkipIgnorable )
+ {}
+ // <--
+ virtual StylePool::SfxItemSet_Pointer_t getNext();
+ virtual ::rtl::OUString getName();
+ };
+
+ StylePool::SfxItemSet_Pointer_t Iterator::getNext()
+ {
+ StylePool::SfxItemSet_Pointer_t pReturn;
+ while( mpNode || mpCurrNode != mrRoot.end() )
+ {
+ if( !mpNode )
+ {
+ mpNode = &mpCurrNode->second;
+ ++mpCurrNode;
+ // --> OD 2008-03-11 #i86923#
+ if ( mpNode->hasItemSet( mbSkipUnusedItemSets ) )
+ {
+ // --> OD 2008-04-30 #i87808#
+// return pNode->getItemSet();
+ return mpNode->getUsedOrLastAddedItemSet();
+ // <--
+ }
+ // <--
+ }
+ // --> OD 2008-03-11 #i86923#
+ mpNode = mpNode->nextItemSet( mpNode, mbSkipUnusedItemSets, mbSkipIgnorable );
+ if ( mpNode && mpNode->hasItemSet( mbSkipUnusedItemSets ) )
+ {
+ // --> OD 2008-04-30 #i87808#
+// return pNode->getItemSet();
+ return mpNode->getUsedOrLastAddedItemSet();
+ // <--
+ }
+ if ( mbSkipIgnorable &&
+ mpNode && mpNode->hasIgnorableChildren( mbSkipUnusedItemSets ) )
+ {
+ return mpNode->getItemSetOfIgnorableChild( mbSkipUnusedItemSets );
+ }
+ // <--
+ }
+ return pReturn;
+ }
+
+ ::rtl::OUString Iterator::getName()
+ {
+ ::rtl::OUString aString;
+ if( mpNode && mpNode->hasItemSet( false ) )
+ {
+ // --> OD 2008-04-30 #i87808#
+// aString = StylePool::nameOf( pNode->getItemSet() );
+ aString = StylePool::nameOf( mpNode->getUsedOrLastAddedItemSet() );
+ // <--
+ }
+ return aString;
+ }
+
+}
+
+/* This static method creates a unique name from a shared pointer to a SfxItemSet
+ The name is the memory address of the SfxItemSet itself. */
+
+::rtl::OUString StylePool::nameOf( SfxItemSet_Pointer_t pSet )
+{
+ return ::rtl::OUString::valueOf( reinterpret_cast<sal_IntPtr>( pSet.get() ), 16 );
+}
+
+// class StylePoolImpl organized a tree-structure where every node represents a SfxItemSet.
+// The insertItemSet method adds a SfxItemSet into the tree if necessary and returns a shared_ptr
+// to a copy of the SfxItemSet.
+// The aRoot-Node represents an empty SfxItemSet.
+
+class StylePoolImpl
+{
+private:
+ std::map< const SfxItemSet*, Node > maRoot;
+ sal_Int32 mnCount;
+ // --> OD 2008-03-07 #i86923#
+ SfxItemSet* mpIgnorableItems;
+ // <--
+public:
+ // --> OD 2008-03-07 #i86923#
+ explicit StylePoolImpl( SfxItemSet* pIgnorableItems = 0 )
+ : maRoot(),
+ mnCount(0),
+ mpIgnorableItems( pIgnorableItems != 0
+ ? pIgnorableItems->Clone( FALSE )
+ : 0 )
+ {
+ DBG_ASSERT( !pIgnorableItems || !pIgnorableItems->Count(),
+ "<StylePoolImpl::StylePoolImpl(..)> - misusage: item set for ignorable item should be empty. Please correct usage." );
+ DBG_ASSERT( !mpIgnorableItems || !mpIgnorableItems->Count(),
+ "<StylePoolImpl::StylePoolImpl(..)> - <SfxItemSet::Clone( FALSE )> does not work as excepted - <mpIgnorableItems> is not empty. Please inform OD." );
+ }
+
+ ~StylePoolImpl()
+ {
+ delete mpIgnorableItems;
+ }
+ // <--
+
+ StylePool::SfxItemSet_Pointer_t insertItemSet( const SfxItemSet& rSet );
+
+ // --> OD 2008-03-07 #i86923#
+ IStylePoolIteratorAccess* createIterator( bool bSkipUnusedItemSets = false,
+ bool bSkipIgnorableItems = false );
+ // <--
+ sal_Int32 getCount() const { return mnCount; }
+};
+
+StylePool::SfxItemSet_Pointer_t StylePoolImpl::insertItemSet( const SfxItemSet& rSet )
+{
+ bool bNonPoolable = false;
+ Node* pCurNode = &maRoot[ rSet.GetParent() ];
+ SfxItemIter aIter( rSet );
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+ // Every SfxPoolItem in the SfxItemSet causes a step deeper into the tree,
+ // a complete empty SfxItemSet would stay at the root node.
+ // --> OD 2008-03-07 #i86923#
+ // insert ignorable items to the tree leaves.
+ std::auto_ptr<SfxItemSet> pFoundIgnorableItems;
+ if ( mpIgnorableItems )
+ {
+ pFoundIgnorableItems.reset( new SfxItemSet( *mpIgnorableItems ) );
+ }
+ while( pItem )
+ {
+ if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
+ bNonPoolable = true;
+ if ( !pFoundIgnorableItems.get() ||
+ ( pFoundIgnorableItems.get() &&
+ pFoundIgnorableItems->Put( *pItem ) == 0 ) )
+ {
+ pCurNode = pCurNode->findChildNode( *pItem );
+ }
+ pItem = aIter.NextItem();
+ }
+ if ( pFoundIgnorableItems.get() &&
+ pFoundIgnorableItems->Count() > 0 )
+ {
+ SfxItemIter aIgnorableItemsIter( *pFoundIgnorableItems );
+ pItem = aIgnorableItemsIter.GetCurItem();
+ while( pItem )
+ {
+ if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
+ bNonPoolable = true;
+ pCurNode = pCurNode->findChildNode( *pItem, true );
+ pItem = aIgnorableItemsIter.NextItem();
+ }
+ }
+ // <--
+ // Every leaf node represents an inserted item set, but "non-leaf" nodes represents subsets
+ // of inserted itemsets.
+ // These nodes could have but does not need to have a shared_ptr to a item set.
+ if( !pCurNode->hasItemSet( false ) )
+ {
+ pCurNode->setItemSet( rSet );
+ bNonPoolable = false; // to avoid a double insertion
+ ++mnCount;
+ }
+ // If rSet contains at least one non poolable item, a new itemset has to be inserted
+ if( bNonPoolable )
+ pCurNode->setItemSet( rSet );
+#ifdef DEBUG
+ {
+ sal_Int32 nCheck = -1;
+ sal_Int32 nNo = -1;
+ IStylePoolIteratorAccess* pIter = createIterator();
+ StylePool::SfxItemSet_Pointer_t pTemp;
+ do
+ {
+ ++nCheck;
+ pTemp = pIter->getNext();
+ if( pCurNode->hasItemSet( false ) && pTemp.get() == pCurNode->getItemSet().get() )
+ {
+ ::rtl::OUString aStr = StylePool::nameOf( pTemp );
+ nNo = nCheck;
+ }
+ } while( pTemp.get() );
+ DBG_ASSERT( mnCount == nCheck, "Wrong counting");
+ delete pIter;
+ }
+#endif
+ return pCurNode->getItemSet();
+}
+
+// --> OD 2008-03-07 #i86923#
+IStylePoolIteratorAccess* StylePoolImpl::createIterator( bool bSkipUnusedItemSets,
+ bool bSkipIgnorableItems )
+{
+ return new Iterator( maRoot, bSkipUnusedItemSets, bSkipIgnorableItems );
+}
+// <--
+
+// Ctor, Dtor and redirected methods of class StylePool, nearly inline ;-)
+
+// --> OD 2008-03-07 #i86923#
+StylePool::StylePool( SfxItemSet* pIgnorableItems )
+ : pImpl( new StylePoolImpl( pIgnorableItems ) )
+{}
+// <--
+
+StylePool::SfxItemSet_Pointer_t StylePool::insertItemSet( const SfxItemSet& rSet )
+{ return pImpl->insertItemSet( rSet ); }
+
+// --> OD 2008-03-11 #i86923#
+IStylePoolIteratorAccess* StylePool::createIterator( const bool bSkipUnusedItemSets,
+ const bool bSkipIgnorableItems )
+{
+ return pImpl->createIterator( bSkipUnusedItemSets, bSkipIgnorableItems );
+}
+// <--
+
+sal_Int32 StylePool::getCount() const
+{ return pImpl->getCount(); }
+
+StylePool::~StylePool() { delete pImpl; }
+
+// End of class StylePool
+