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 ************************************************************************/
38 #include "stylepool.hxx"
39 #include <svtools/itemiter.hxx>
40 #include <svtools/itempool.hxx>
43 using namespace boost
;
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.
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
;
62 // --> OD 2008-03-07 #i86923#
63 Node() // root node Ctor
68 mbIsItemIgnorable( false )
70 Node( const SfxPoolItem
& rItem
, Node
* pParent
, const bool bIgnorable
) // child node Ctor
73 mpItem( rItem
.Clone() ),
75 mbIsItemIgnorable( bIgnorable
)
79 // --> OD 2008-03-11 #i86923#
80 bool hasItemSet( const bool bCheckUsage
) const;
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;
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
);
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;
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 )
119 return maItemSet
.back();
123 // --> OD 2008-05-06 #i86923#
124 bool Node::hasItemSet( const bool bCheckUsage
) const
126 bool bHasItemSet
= false;
128 if ( maItemSet
.size() > 0 )
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 )
152 // --> OD 2008-03-07 #i86923#
153 Node
* Node::findChildNode( const SfxPoolItem
& rItem
,
154 const bool bIsItemIgnorable
)
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() )
166 // --> OD 2008-03-07 #i86923#
167 pNextNode
= new Node( rItem
, pNextNode
, bIsItemIgnorable
);
169 mChildren
.push_back( pNextNode
);
173 /* Find the next node which has a SfxItemSet.
174 The input parameter pLast has a sophisticated meaning:
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>
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() )
204 while( aIter
!= mChildren
.end() )
206 // --> OD 2008-03-11 #i86923#
207 if ( bSkipIgnorable
&& (*aIter
)->mbIsItemIgnorable
)
214 // --> OD 2008-03-11 #i86923#
215 if ( pNext
->hasItemSet( bSkipUnusedItemSets
) )
219 if ( bSkipIgnorable
&&
220 pNext
->hasIgnorableChildren( bSkipUnusedItemSets
) )
224 pNext
= pNext
->nextItemSet( 0, bSkipUnusedItemSets
, bSkipIgnorable
); // 0 => downstairs only
230 // Searching upstairs
231 if( pLast
&& mpUpper
)
233 // --> OD 2008-03-11 #i86923#
234 pNext
= mpUpper
->nextItemSet( this, bSkipUnusedItemSets
, bSkipIgnorable
);
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
=
253 ( pChild
->hasItemSet( bCheckUsage
/* == true */ ) ||
254 pChild
->hasIgnorableChildren( bCheckUsage
/* == true */ ) );
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();
280 pChild
= pChild
->nextItemSet( 0, bSkipUnusedItemSets
, false );
283 return pChild
->getUsedOrLastAddedItemSet();
290 StylePool::SfxItemSet_Pointer_t pReturn
;
297 std::vector
<Node
*>::iterator aIter
= mChildren
.begin();
298 while( aIter
!= mChildren
.end() )
306 class Iterator
: public IStylePoolIteratorAccess
308 std::map
< const SfxItemSet
*, Node
>& mrRoot
;
309 std::map
< const SfxItemSet
*, Node
>::iterator mpCurrNode
;
311 const bool mbSkipUnusedItemSets
;
312 const bool mbSkipIgnorable
;
314 // --> OD 2008-03-07 #i86923#
315 Iterator( std::map
< const SfxItemSet
*, Node
>& rR
,
316 const bool bSkipUnusedItemSets
,
317 const bool bSkipIgnorable
)
319 mpCurrNode( rR
.begin() ),
321 mbSkipUnusedItemSets( bSkipUnusedItemSets
),
322 mbSkipIgnorable( bSkipIgnorable
)
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() )
336 mpNode
= &mpCurrNode
->second
;
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();
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();
357 if ( mbSkipIgnorable
&&
358 mpNode
&& mpNode
->hasIgnorableChildren( mbSkipUnusedItemSets
) )
360 return mpNode
->getItemSetOfIgnorableChild( mbSkipUnusedItemSets
);
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() );
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.
398 std::map
< const SfxItemSet
*, Node
> maRoot
;
400 // --> OD 2008-03-07 #i86923#
401 SfxItemSet
* mpIgnorableItems
;
404 // --> OD 2008-03-07 #i86923#
405 explicit StylePoolImpl( SfxItemSet
* pIgnorableItems
= 0 )
408 mpIgnorableItems( pIgnorableItems
!= 0
409 ? pIgnorableItems
->Clone( FALSE
)
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." );
420 delete mpIgnorableItems
;
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 );
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
) );
450 if( !rSet
.GetPool()->IsItemFlag(pItem
->Which(), SFX_ITEM_POOLABLE
) )
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();
467 if( !rSet
.GetPool()->IsItemFlag(pItem
->Which(), SFX_ITEM_POOLABLE
) )
469 pCurNode
= pCurNode
->findChildNode( *pItem
, true );
470 pItem
= aIgnorableItemsIter
.NextItem();
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
483 // If rSet contains at least one non poolable item, a new itemset has to be inserted
485 pCurNode
->setItemSet( rSet
);
488 sal_Int32 nCheck
= -1;
490 IStylePoolIteratorAccess
* pIter
= createIterator();
491 StylePool::SfxItemSet_Pointer_t pTemp
;
495 pTemp
= pIter
->getNext();
496 if( pCurNode
->hasItemSet( false ) && pTemp
.get() == pCurNode
->getItemSet().get() )
498 ::rtl::OUString aStr
= StylePool::nameOf( pTemp
);
501 } while( pTemp
.get() );
502 DBG_ASSERT( mnCount
== nCheck
, "Wrong counting");
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
);
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
) )
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
);
536 sal_Int32
StylePool::getCount() const
537 { return pImpl
->getCount(); }
539 StylePool::~StylePool() { delete pImpl
; }
541 // End of class StylePool