summaryrefslogtreecommitdiff
path: root/binfilter/bf_svtools/source/items1/svt_stylepool.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'binfilter/bf_svtools/source/items1/svt_stylepool.cxx')
-rw-r--r--binfilter/bf_svtools/source/items1/svt_stylepool.cxx271
1 files changed, 271 insertions, 0 deletions
diff --git a/binfilter/bf_svtools/source/items1/svt_stylepool.cxx b/binfilter/bf_svtools/source/items1/svt_stylepool.cxx
new file mode 100644
index 000000000000..83e4ea3c1ae3
--- /dev/null
+++ b/binfilter/bf_svtools/source/items1/svt_stylepool.cxx
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#include <vector>
+#include <map>
+
+#include "stylepool.hxx"
+#include <bf_svtools/itemiter.hxx>
+#include <bf_svtools/itempool.hxx>
+
+
+using namespace boost;
+
+namespace binfilter
+{
+ // 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(..)
+ std::vector< StylePool::SfxItemSet_Pointer_t > aItemSet; // shared pointer an inserted item set or nul
+ const SfxPoolItem *pItem; // my pool item
+ Node *pUpper; // if I'm a child node that's my parent node
+ public:
+ Node() : pItem( 0 ), pUpper( 0 ) {} // root node Ctor
+ Node( const SfxPoolItem& rItem, Node* pParent ) : // child node Ctor
+ pItem( rItem.Clone() ), pUpper( pParent ){}
+ ~Node();
+ bool hasItemSet() const { return 0 < aItemSet.size(); }
+ const StylePool::SfxItemSet_Pointer_t getItemSet() const { return aItemSet[aItemSet.size()-1]; }
+ void setItemSet( const SfxItemSet& rSet ){ aItemSet.push_back( StylePool::SfxItemSet_Pointer_t( rSet.Clone() ) ); }
+ Node* findChildNode( const SfxPoolItem& rItem );
+ Node* nextItemSet( Node* pLast );
+ const SfxPoolItem& getPoolItem() const { return *pItem; }
+ };
+
+ Node* Node::findChildNode( const SfxPoolItem& rItem )
+ {
+ 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;
+ }
+ pNextNode = new Node( rItem, pNextNode );
+ 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.
+ */
+
+ Node* Node::nextItemSet( Node* pLast )
+ {
+ // 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() )
+ {
+ pNext = *aIter;
+ if( pNext->hasItemSet() ) // any child with item set?
+ return pNext;
+ pNext = pNext->nextItemSet( 0 ); // 0 => downstairs only
+ if( pNext )
+ return pNext;
+ ++aIter;
+ }
+ // Searching upstairs
+ if( pLast && pUpper )
+ pNext = pUpper->nextItemSet( this );
+ return pNext;
+ }
+
+ Node::~Node()
+ {
+ std::vector<Node*>::iterator aIter = mChildren.begin();
+ while( aIter != mChildren.end() )
+ {
+ delete *aIter;
+ ++aIter;
+ }
+ delete pItem;
+ }
+
+ class Iterator : public IStylePoolIteratorAccess
+ {
+ std::map< const SfxItemSet*, Node >& rRoot;
+ std::map< const SfxItemSet*, Node >::iterator pCurrNode;
+ Node* pNode;
+ public:
+ Iterator( std::map< const SfxItemSet*, Node >& rR )
+ : rRoot( rR ), pCurrNode( rR.begin() ), pNode(0) {}
+ virtual StylePool::SfxItemSet_Pointer_t getNext();
+ virtual ::rtl::OUString getName();
+ };
+
+ StylePool::SfxItemSet_Pointer_t Iterator::getNext()
+ {
+ StylePool::SfxItemSet_Pointer_t pReturn;
+ while( pNode || pCurrNode != rRoot.end() )
+ {
+ if( !pNode )
+ {
+ pNode = &pCurrNode->second;
+ ++pCurrNode;
+ if( pNode->hasItemSet() )
+ return pNode->getItemSet();
+ }
+ pNode = pNode->nextItemSet( pNode );
+ if( pNode && pNode->hasItemSet() )
+ return pNode->getItemSet();
+ }
+ return pReturn;
+ }
+
+ ::rtl::OUString Iterator::getName()
+ {
+ ::rtl::OUString aString;
+ if( pNode && pNode->hasItemSet() )
+ aString = StylePool::nameOf( pNode->getItemSet() );
+ 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 > aRoot;
+ sal_Int32 nCount;
+public:
+ StylePoolImpl() : nCount(0) {}
+ StylePool::SfxItemSet_Pointer_t insertItemSet( const SfxItemSet& rSet );
+ IStylePoolIteratorAccess* createIterator();
+ sal_Int32 getCount() const { return nCount; }
+};
+
+StylePool::SfxItemSet_Pointer_t StylePoolImpl::insertItemSet( const SfxItemSet& rSet )
+{
+ bool bNonPoolable = false;
+ Node* pCurNode = &aRoot[ 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.
+ while( pItem )
+ {
+ if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
+ bNonPoolable = true;
+ pCurNode = pCurNode->findChildNode( *pItem );
+ pItem = aIter.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() )
+ {
+ pCurNode->setItemSet( rSet );
+ bNonPoolable = false; // to avoid a double insertion
+ ++nCount;
+ }
+ // 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() && pTemp.get() == pCurNode->getItemSet().get() )
+ {
+ ::rtl::OUString aStr = pIter->getName();
+ nNo = nCheck;
+ }
+ } while( pTemp.get() );
+ DBG_ASSERT( nCount == nCheck, "Wrong counting");
+ delete pIter;
+ }
+#endif
+ return pCurNode->getItemSet();
+}
+
+IStylePoolIteratorAccess* StylePoolImpl::createIterator()
+{ return new Iterator( aRoot ); }
+
+// Ctor, Dtor and redirected methods of class StylePool, nearly inline ;-)
+
+StylePool::SfxItemSet_Pointer_t StylePool::insertItemSet( const SfxItemSet& rSet )
+{ return pImpl->insertItemSet( rSet ); }
+
+IStylePoolIteratorAccess* StylePool::createIterator()
+{ return pImpl->createIterator(); }
+
+sal_Int32 StylePool::getCount() const
+{ return pImpl->getCount(); }
+
+StylePool::~StylePool() { delete pImpl; }
+
+// End of class StylePool
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */