Update ooo320-m1
[ooovba.git] / svtools / source / items1 / stylepool.cxx
blob5f31500be73c5307dd5ce57ee714835f6c7f0b31
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: stylepool.cxx,v $
10 * $Revision: 1.10.78.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #ifdef _MSC_VER
32 #pragma hdrstop
33 #endif
35 #include <vector>
36 #include <map>
38 #include "stylepool.hxx"
39 #include <svtools/itemiter.hxx>
40 #include <svtools/itempool.hxx>
43 using namespace boost;
45 namespace {
46 // A "Node" represents a subset of inserted SfxItemSets
47 // The root node represents the empty set
48 // The other nodes contain a SfxPoolItem and represents an item set which contains their
49 // pool item and the pool items of their parents.
50 class Node
52 std::vector<Node*> mChildren; // child nodes, create by findChildNode(..)
53 // container of shared pointers of inserted item sets; for non-poolable
54 // items more than one item set is needed
55 std::vector< StylePool::SfxItemSet_Pointer_t > maItemSet;
56 const SfxPoolItem *mpItem; // my pool item
57 Node *mpUpper; // if I'm a child node that's my parent node
58 // --> OD 2008-03-07 #i86923#
59 const bool mbIsItemIgnorable;
60 // <--
61 public:
62 // --> OD 2008-03-07 #i86923#
63 Node() // root node Ctor
64 : mChildren(),
65 maItemSet(),
66 mpItem( 0 ),
67 mpUpper( 0 ),
68 mbIsItemIgnorable( false )
70 Node( const SfxPoolItem& rItem, Node* pParent, const bool bIgnorable ) // child node Ctor
71 : mChildren(),
72 maItemSet(),
73 mpItem( rItem.Clone() ),
74 mpUpper( pParent ),
75 mbIsItemIgnorable( bIgnorable )
77 // <--
78 ~Node();
79 // --> OD 2008-03-11 #i86923#
80 bool hasItemSet( const bool bCheckUsage ) const;
81 // <--
82 // --> OD 2008-04-29 #i87808#
83 // const StylePool::SfxItemSet_Pointer_t getItemSet() const { return aItemSet[aItemSet.size()-1]; }
84 const StylePool::SfxItemSet_Pointer_t getItemSet() const
86 return maItemSet.back();
88 const StylePool::SfxItemSet_Pointer_t getUsedOrLastAddedItemSet() const;
89 // <--
90 void setItemSet( const SfxItemSet& rSet ){ maItemSet.push_back( StylePool::SfxItemSet_Pointer_t( rSet.Clone() ) ); }
91 // --> OD 2008-03-11 #i86923#
92 Node* findChildNode( const SfxPoolItem& rItem,
93 const bool bIsItemIgnorable = false );
94 Node* nextItemSet( Node* pLast,
95 const bool bSkipUnusedItemSet,
96 const bool bSkipIgnorable );
97 // <--
98 const SfxPoolItem& getPoolItem() const { return *mpItem; }
99 // --> OD 2008-03-11 #i86923#
100 bool hasIgnorableChildren( const bool bCheckUsage ) const;
101 const StylePool::SfxItemSet_Pointer_t getItemSetOfIgnorableChild(
102 const bool bSkipUnusedItemSets ) const;
103 // <--
106 // --> OD 2008-04-29 #i87808#
107 const StylePool::SfxItemSet_Pointer_t Node::getUsedOrLastAddedItemSet() const
109 std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
111 for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
113 if ( (*aIter).use_count() > 1 )
115 return *aIter;
119 return maItemSet.back();
121 // <--
123 // --> OD 2008-05-06 #i86923#
124 bool Node::hasItemSet( const bool bCheckUsage ) const
126 bool bHasItemSet = false;
128 if ( maItemSet.size() > 0 )
130 if ( bCheckUsage )
132 std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
134 for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
136 if ( (*aIter).use_count() > 1 )
138 bHasItemSet = true;
139 break;
143 else
145 bHasItemSet = true;
148 return bHasItemSet;
150 // <--
152 // --> OD 2008-03-07 #i86923#
153 Node* Node::findChildNode( const SfxPoolItem& rItem,
154 const bool bIsItemIgnorable )
155 // <--
157 Node* pNextNode = this;
158 std::vector<Node*>::iterator aIter = mChildren.begin();
159 while( aIter != mChildren.end() )
161 if( rItem.Which() == (*aIter)->getPoolItem().Which() &&
162 rItem == (*aIter)->getPoolItem() )
163 return *aIter;
164 ++aIter;
166 // --> OD 2008-03-07 #i86923#
167 pNextNode = new Node( rItem, pNextNode, bIsItemIgnorable );
168 // <--
169 mChildren.push_back( pNextNode );
170 return pNextNode;
173 /* Find the next node which has a SfxItemSet.
174 The input parameter pLast has a sophisticated meaning:
175 downstairs only:
176 pLast == 0 => scan your children and their children
177 but neither your parents neither your siblings
178 downstairs and upstairs:
179 pLast == this => scan your children, their children,
180 the children of your parent behind you, and so on
181 partial downstairs and upstairs
182 pLast != 0 && pLast != this => scan your children behind the given children,
183 the children of your parent behind you and so on.
185 OD 2008-03-11 #i86923#
186 introduce parameters <bSkipUnusedItemSets> and <bSkipIgnorable>
187 and its handling.
189 Node* Node::nextItemSet( Node* pLast,
190 const bool bSkipUnusedItemSets,
191 const bool bSkipIgnorable )
193 // Searching downstairs
194 std::vector<Node*>::iterator aIter = mChildren.begin();
195 // For pLast == 0 and pLast == this all children are of interest
196 // for another pLast the search starts behind pLast...
197 if( pLast && pLast != this )
199 aIter = std::find( mChildren.begin(), mChildren.end(), pLast );
200 if( aIter != mChildren.end() )
201 ++aIter;
203 Node *pNext = 0;
204 while( aIter != mChildren.end() )
206 // --> OD 2008-03-11 #i86923#
207 if ( bSkipIgnorable && (*aIter)->mbIsItemIgnorable )
209 ++aIter;
210 continue;
212 // <--
213 pNext = *aIter;
214 // --> OD 2008-03-11 #i86923#
215 if ( pNext->hasItemSet( bSkipUnusedItemSets ) )
217 return pNext;
219 if ( bSkipIgnorable &&
220 pNext->hasIgnorableChildren( bSkipUnusedItemSets ) )
222 return pNext;
224 pNext = pNext->nextItemSet( 0, bSkipUnusedItemSets, bSkipIgnorable ); // 0 => downstairs only
225 // <--
226 if( pNext )
227 return pNext;
228 ++aIter;
230 // Searching upstairs
231 if( pLast && mpUpper )
233 // --> OD 2008-03-11 #i86923#
234 pNext = mpUpper->nextItemSet( this, bSkipUnusedItemSets, bSkipIgnorable );
235 // <--
237 return pNext;
240 // --> OD 2008-03-11 #i86923#
241 bool Node::hasIgnorableChildren( const bool bCheckUsage ) const
243 bool bHasIgnorableChildren( false );
245 std::vector<Node*>::const_iterator aIter = mChildren.begin();
246 while( aIter != mChildren.end() && !bHasIgnorableChildren )
248 Node* pChild = *aIter;
249 if ( pChild->mbIsItemIgnorable )
251 bHasIgnorableChildren =
252 !bCheckUsage ||
253 ( pChild->hasItemSet( bCheckUsage /* == true */ ) ||
254 pChild->hasIgnorableChildren( bCheckUsage /* == true */ ) );
256 ++aIter;
259 return bHasIgnorableChildren;
262 const StylePool::SfxItemSet_Pointer_t Node::getItemSetOfIgnorableChild(
263 const bool bSkipUnusedItemSets ) const
265 DBG_ASSERT( hasIgnorableChildren( bSkipUnusedItemSets ),
266 "<Node::getItemSetOfIgnorableChild> - node has no ignorable children" );
268 std::vector<Node*>::const_iterator aIter = mChildren.begin();
269 while( aIter != mChildren.end() )
271 Node* pChild = *aIter;
272 if ( pChild->mbIsItemIgnorable )
274 if ( pChild->hasItemSet( bSkipUnusedItemSets ) )
276 return pChild->getUsedOrLastAddedItemSet();
278 else
280 pChild = pChild->nextItemSet( 0, bSkipUnusedItemSets, false );
281 if ( pChild )
283 return pChild->getUsedOrLastAddedItemSet();
287 ++aIter;
290 StylePool::SfxItemSet_Pointer_t pReturn;
291 return pReturn;
293 // <--
295 Node::~Node()
297 std::vector<Node*>::iterator aIter = mChildren.begin();
298 while( aIter != mChildren.end() )
300 delete *aIter;
301 ++aIter;
303 delete mpItem;
306 class Iterator : public IStylePoolIteratorAccess
308 std::map< const SfxItemSet*, Node >& mrRoot;
309 std::map< const SfxItemSet*, Node >::iterator mpCurrNode;
310 Node* mpNode;
311 const bool mbSkipUnusedItemSets;
312 const bool mbSkipIgnorable;
313 public:
314 // --> OD 2008-03-07 #i86923#
315 Iterator( std::map< const SfxItemSet*, Node >& rR,
316 const bool bSkipUnusedItemSets,
317 const bool bSkipIgnorable )
318 : mrRoot( rR ),
319 mpCurrNode( rR.begin() ),
320 mpNode(0),
321 mbSkipUnusedItemSets( bSkipUnusedItemSets ),
322 mbSkipIgnorable( bSkipIgnorable )
324 // <--
325 virtual StylePool::SfxItemSet_Pointer_t getNext();
326 virtual ::rtl::OUString getName();
329 StylePool::SfxItemSet_Pointer_t Iterator::getNext()
331 StylePool::SfxItemSet_Pointer_t pReturn;
332 while( mpNode || mpCurrNode != mrRoot.end() )
334 if( !mpNode )
336 mpNode = &mpCurrNode->second;
337 ++mpCurrNode;
338 // --> OD 2008-03-11 #i86923#
339 if ( mpNode->hasItemSet( mbSkipUnusedItemSets ) )
341 // --> OD 2008-04-30 #i87808#
342 // return pNode->getItemSet();
343 return mpNode->getUsedOrLastAddedItemSet();
344 // <--
346 // <--
348 // --> OD 2008-03-11 #i86923#
349 mpNode = mpNode->nextItemSet( mpNode, mbSkipUnusedItemSets, mbSkipIgnorable );
350 if ( mpNode && mpNode->hasItemSet( mbSkipUnusedItemSets ) )
352 // --> OD 2008-04-30 #i87808#
353 // return pNode->getItemSet();
354 return mpNode->getUsedOrLastAddedItemSet();
355 // <--
357 if ( mbSkipIgnorable &&
358 mpNode && mpNode->hasIgnorableChildren( mbSkipUnusedItemSets ) )
360 return mpNode->getItemSetOfIgnorableChild( mbSkipUnusedItemSets );
362 // <--
364 return pReturn;
367 ::rtl::OUString Iterator::getName()
369 ::rtl::OUString aString;
370 if( mpNode && mpNode->hasItemSet( false ) )
372 // --> OD 2008-04-30 #i87808#
373 // aString = StylePool::nameOf( pNode->getItemSet() );
374 aString = StylePool::nameOf( mpNode->getUsedOrLastAddedItemSet() );
375 // <--
377 return aString;
382 /* This static method creates a unique name from a shared pointer to a SfxItemSet
383 The name is the memory address of the SfxItemSet itself. */
385 ::rtl::OUString StylePool::nameOf( SfxItemSet_Pointer_t pSet )
387 return ::rtl::OUString::valueOf( reinterpret_cast<sal_IntPtr>( pSet.get() ), 16 );
390 // class StylePoolImpl organized a tree-structure where every node represents a SfxItemSet.
391 // The insertItemSet method adds a SfxItemSet into the tree if necessary and returns a shared_ptr
392 // to a copy of the SfxItemSet.
393 // The aRoot-Node represents an empty SfxItemSet.
395 class StylePoolImpl
397 private:
398 std::map< const SfxItemSet*, Node > maRoot;
399 sal_Int32 mnCount;
400 // --> OD 2008-03-07 #i86923#
401 SfxItemSet* mpIgnorableItems;
402 // <--
403 public:
404 // --> OD 2008-03-07 #i86923#
405 explicit StylePoolImpl( SfxItemSet* pIgnorableItems = 0 )
406 : maRoot(),
407 mnCount(0),
408 mpIgnorableItems( pIgnorableItems != 0
409 ? pIgnorableItems->Clone( FALSE )
410 : 0 )
412 DBG_ASSERT( !pIgnorableItems || !pIgnorableItems->Count(),
413 "<StylePoolImpl::StylePoolImpl(..)> - misusage: item set for ignorable item should be empty. Please correct usage." );
414 DBG_ASSERT( !mpIgnorableItems || !mpIgnorableItems->Count(),
415 "<StylePoolImpl::StylePoolImpl(..)> - <SfxItemSet::Clone( FALSE )> does not work as excepted - <mpIgnorableItems> is not empty. Please inform OD." );
418 ~StylePoolImpl()
420 delete mpIgnorableItems;
422 // <--
424 StylePool::SfxItemSet_Pointer_t insertItemSet( const SfxItemSet& rSet );
426 // --> OD 2008-03-07 #i86923#
427 IStylePoolIteratorAccess* createIterator( bool bSkipUnusedItemSets = false,
428 bool bSkipIgnorableItems = false );
429 // <--
430 sal_Int32 getCount() const { return mnCount; }
433 StylePool::SfxItemSet_Pointer_t StylePoolImpl::insertItemSet( const SfxItemSet& rSet )
435 bool bNonPoolable = false;
436 Node* pCurNode = &maRoot[ rSet.GetParent() ];
437 SfxItemIter aIter( rSet );
438 const SfxPoolItem* pItem = aIter.GetCurItem();
439 // Every SfxPoolItem in the SfxItemSet causes a step deeper into the tree,
440 // a complete empty SfxItemSet would stay at the root node.
441 // --> OD 2008-03-07 #i86923#
442 // insert ignorable items to the tree leaves.
443 std::auto_ptr<SfxItemSet> pFoundIgnorableItems;
444 if ( mpIgnorableItems )
446 pFoundIgnorableItems.reset( new SfxItemSet( *mpIgnorableItems ) );
448 while( pItem )
450 if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
451 bNonPoolable = true;
452 if ( !pFoundIgnorableItems.get() ||
453 ( pFoundIgnorableItems.get() &&
454 pFoundIgnorableItems->Put( *pItem ) == 0 ) )
456 pCurNode = pCurNode->findChildNode( *pItem );
458 pItem = aIter.NextItem();
460 if ( pFoundIgnorableItems.get() &&
461 pFoundIgnorableItems->Count() > 0 )
463 SfxItemIter aIgnorableItemsIter( *pFoundIgnorableItems );
464 pItem = aIgnorableItemsIter.GetCurItem();
465 while( pItem )
467 if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
468 bNonPoolable = true;
469 pCurNode = pCurNode->findChildNode( *pItem, true );
470 pItem = aIgnorableItemsIter.NextItem();
473 // <--
474 // Every leaf node represents an inserted item set, but "non-leaf" nodes represents subsets
475 // of inserted itemsets.
476 // These nodes could have but does not need to have a shared_ptr to a item set.
477 if( !pCurNode->hasItemSet( false ) )
479 pCurNode->setItemSet( rSet );
480 bNonPoolable = false; // to avoid a double insertion
481 ++mnCount;
483 // If rSet contains at least one non poolable item, a new itemset has to be inserted
484 if( bNonPoolable )
485 pCurNode->setItemSet( rSet );
486 #ifdef DEBUG
488 sal_Int32 nCheck = -1;
489 sal_Int32 nNo = -1;
490 IStylePoolIteratorAccess* pIter = createIterator();
491 StylePool::SfxItemSet_Pointer_t pTemp;
494 ++nCheck;
495 pTemp = pIter->getNext();
496 if( pCurNode->hasItemSet( false ) && pTemp.get() == pCurNode->getItemSet().get() )
498 ::rtl::OUString aStr = StylePool::nameOf( pTemp );
499 nNo = nCheck;
501 } while( pTemp.get() );
502 DBG_ASSERT( mnCount == nCheck, "Wrong counting");
503 delete pIter;
505 #endif
506 return pCurNode->getItemSet();
509 // --> OD 2008-03-07 #i86923#
510 IStylePoolIteratorAccess* StylePoolImpl::createIterator( bool bSkipUnusedItemSets,
511 bool bSkipIgnorableItems )
513 return new Iterator( maRoot, bSkipUnusedItemSets, bSkipIgnorableItems );
515 // <--
517 // Ctor, Dtor and redirected methods of class StylePool, nearly inline ;-)
519 // --> OD 2008-03-07 #i86923#
520 StylePool::StylePool( SfxItemSet* pIgnorableItems )
521 : pImpl( new StylePoolImpl( pIgnorableItems ) )
523 // <--
525 StylePool::SfxItemSet_Pointer_t StylePool::insertItemSet( const SfxItemSet& rSet )
526 { return pImpl->insertItemSet( rSet ); }
528 // --> OD 2008-03-11 #i86923#
529 IStylePoolIteratorAccess* StylePool::createIterator( const bool bSkipUnusedItemSets,
530 const bool bSkipIgnorableItems )
532 return pImpl->createIterator( bSkipUnusedItemSets, bSkipIgnorableItems );
534 // <--
536 sal_Int32 StylePool::getCount() const
537 { return pImpl->getCount(); }
539 StylePool::~StylePool() { delete pImpl; }
541 // End of class StylePool