xref: /trunk/main/svl/source/items/stylepool.cxx (revision 40df464e)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_svl.hxx"
25 
26 #ifdef _MSC_VER
27 #pragma hdrstop
28 #endif
29 
30 #include <vector>
31 #include <map>
32 
33 #include <svl/stylepool.hxx>
34 #include <svl/itemiter.hxx>
35 #include <svl/itempool.hxx>
36 
37 
38 using namespace boost;
39 
40 namespace {
41     // A "Node" represents a subset of inserted SfxItemSets
42     // The root node represents the empty set
43     // The other nodes contain a SfxPoolItem and represents an item set which contains their
44     // pool item and the pool items of their parents.
45     class Node
46     {
47         std::vector<Node*> mChildren; // child nodes, create by findChildNode(..)
48         // container of shared pointers of inserted item sets; for non-poolable
49         // items more than one item set is needed
50         std::vector< StylePool::SfxItemSet_Pointer_t > maItemSet;
51         const SfxPoolItem *mpItem;   // my pool item
52         Node *mpUpper;               // if I'm a child node that's my parent node
53         // --> OD 2008-03-07 #i86923#
54         const bool mbIsItemIgnorable;
55         // <--
56     public:
57         // --> OD 2008-03-07 #i86923#
Node()58         Node() // root node Ctor
59             : mChildren(),
60               maItemSet(),
61               mpItem( 0 ),
62               mpUpper( 0 ),
63               mbIsItemIgnorable( false )
64         {}
Node(const SfxPoolItem & rItem,Node * pParent,const bool bIgnorable)65         Node( const SfxPoolItem& rItem, Node* pParent, const bool bIgnorable ) // child node Ctor
66             : mChildren(),
67               maItemSet(),
68               mpItem( rItem.Clone() ),
69               mpUpper( pParent ),
70               mbIsItemIgnorable( bIgnorable )
71         {}
72         // <--
73         ~Node();
74         // --> OD 2008-03-11 #i86923#
75         bool hasItemSet( const bool bCheckUsage ) const;
76         // <--
77         // --> OD 2008-04-29 #i87808#
78 //        const StylePool::SfxItemSet_Pointer_t getItemSet() const { return aItemSet[aItemSet.size()-1]; }
getItemSet() const79         const StylePool::SfxItemSet_Pointer_t getItemSet() const
80         {
81             return maItemSet.back();
82         }
83         const StylePool::SfxItemSet_Pointer_t getUsedOrLastAddedItemSet() const;
84         // <--
setItemSet(const SfxItemSet & rSet)85         void setItemSet( const SfxItemSet& rSet ){ maItemSet.push_back( StylePool::SfxItemSet_Pointer_t( rSet.Clone() ) ); }
86         // --> OD 2008-03-11 #i86923#
87         Node* findChildNode( const SfxPoolItem& rItem,
88                              const bool bIsItemIgnorable = false );
89         Node* nextItemSet( Node* pLast,
90                            const bool bSkipUnusedItemSet,
91                            const bool bSkipIgnorable );
92         // <--
getPoolItem() const93         const SfxPoolItem& getPoolItem() const { return *mpItem; }
94         // --> OD 2008-03-11 #i86923#
95         bool hasIgnorableChildren( const bool bCheckUsage ) const;
96         const StylePool::SfxItemSet_Pointer_t getItemSetOfIgnorableChild(
97                                         const bool bSkipUnusedItemSets ) const;
98         // <--
99     };
100 
101     // --> OD 2008-04-29 #i87808#
getUsedOrLastAddedItemSet() const102     const StylePool::SfxItemSet_Pointer_t Node::getUsedOrLastAddedItemSet() const
103     {
104         std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
105 
106         for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
107         {
108             if ( (*aIter).use_count() > 1 )
109             {
110                 return *aIter;
111             }
112         }
113 
114         return maItemSet.back();
115     }
116     // <--
117 
118     // --> OD 2008-05-06 #i86923#
hasItemSet(const bool bCheckUsage) const119     bool Node::hasItemSet( const bool bCheckUsage ) const
120     {
121         bool bHasItemSet = false;
122 
123         if ( maItemSet.size() > 0 )
124         {
125             if ( bCheckUsage )
126             {
127                 std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
128 
129                 for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
130                 {
131                     if ( (*aIter).use_count() > 1 )
132                     {
133                         bHasItemSet = true;
134                         break;
135                     }
136                 }
137             }
138             else
139             {
140                 bHasItemSet = true;
141             }
142         }
143         return bHasItemSet;
144     }
145     // <--
146 
147     // --> OD 2008-03-07 #i86923#
findChildNode(const SfxPoolItem & rItem,const bool bIsItemIgnorable)148     Node* Node::findChildNode( const SfxPoolItem& rItem,
149                                const bool bIsItemIgnorable )
150     // <--
151     {
152         Node* pNextNode = this;
153         std::vector<Node*>::iterator aIter = mChildren.begin();
154         while( aIter != mChildren.end() )
155         {
156             if( rItem.Which() == (*aIter)->getPoolItem().Which() &&
157                 rItem == (*aIter)->getPoolItem() )
158                 return *aIter;
159             ++aIter;
160         }
161         // --> OD 2008-03-07 #i86923#
162         pNextNode = new Node( rItem, pNextNode, bIsItemIgnorable );
163         // <--
164         mChildren.push_back( pNextNode );
165         return pNextNode;
166     }
167 
168     /* Find the next node which has a SfxItemSet.
169        The input parameter pLast has a sophisticated meaning:
170        downstairs only:
171        pLast == 0 => scan your children and their children
172                      but neither your parents neither your siblings
173        downstairs and upstairs:
174        pLast == this => scan your children, their children,
175                         the children of your parent behind you, and so on
176        partial downstairs and upstairs
177        pLast != 0 && pLast != this => scan your children behind the given children,
178                         the children of your parent behind you and so on.
179 
180        OD 2008-03-11 #i86923#
181        introduce parameters <bSkipUnusedItemSets> and <bSkipIgnorable>
182        and its handling.
183     */
nextItemSet(Node * pLast,const bool bSkipUnusedItemSets,const bool bSkipIgnorable)184     Node* Node::nextItemSet( Node* pLast,
185                              const bool bSkipUnusedItemSets,
186                              const bool bSkipIgnorable )
187     {
188         // Searching downstairs
189         std::vector<Node*>::iterator aIter = mChildren.begin();
190         // For pLast == 0 and pLast == this all children are of interest
191         // for another pLast the search starts behind pLast...
192         if( pLast && pLast != this )
193         {
194             aIter = std::find( mChildren.begin(), mChildren.end(), pLast );
195             if( aIter != mChildren.end() )
196                 ++aIter;
197         }
198         Node *pNext = 0;
199         while( aIter != mChildren.end() )
200         {
201             // --> OD 2008-03-11 #i86923#
202             if ( bSkipIgnorable && (*aIter)->mbIsItemIgnorable )
203             {
204                 ++aIter;
205                 continue;
206             }
207             // <--
208             pNext = *aIter;
209             // --> OD 2008-03-11 #i86923#
210             if ( pNext->hasItemSet( bSkipUnusedItemSets ) )
211             {
212                 return pNext;
213             }
214             if ( bSkipIgnorable &&
215                  pNext->hasIgnorableChildren( bSkipUnusedItemSets ) )
216             {
217                 return pNext;
218             }
219             pNext = pNext->nextItemSet( 0, bSkipUnusedItemSets, bSkipIgnorable ); // 0 => downstairs only
220             // <--
221             if( pNext )
222                 return pNext;
223             ++aIter;
224         }
225         // Searching upstairs
226         if( pLast && mpUpper )
227         {
228             // --> OD 2008-03-11 #i86923#
229             pNext = mpUpper->nextItemSet( this, bSkipUnusedItemSets, bSkipIgnorable );
230             // <--
231         }
232         return pNext;
233     }
234 
235     // --> OD 2008-03-11 #i86923#
hasIgnorableChildren(const bool bCheckUsage) const236     bool Node::hasIgnorableChildren( const bool bCheckUsage ) const
237     {
238         bool bHasIgnorableChildren( false );
239 
240         std::vector<Node*>::const_iterator aIter = mChildren.begin();
241         while( aIter != mChildren.end() && !bHasIgnorableChildren )
242         {
243             Node* pChild = *aIter;
244             if ( pChild->mbIsItemIgnorable )
245             {
246                 bHasIgnorableChildren =
247                     !bCheckUsage ||
248                     ( pChild->hasItemSet( bCheckUsage /* == true */ ) ||
249                       pChild->hasIgnorableChildren( bCheckUsage /* == true */ ) );
250             }
251             ++aIter;
252         }
253 
254         return bHasIgnorableChildren;
255     }
256 
getItemSetOfIgnorableChild(const bool bSkipUnusedItemSets) const257     const StylePool::SfxItemSet_Pointer_t Node::getItemSetOfIgnorableChild(
258                                         const bool bSkipUnusedItemSets ) const
259     {
260         DBG_ASSERT( hasIgnorableChildren( bSkipUnusedItemSets ),
261                     "<Node::getItemSetOfIgnorableChild> - node has no ignorable children" );
262 
263         std::vector<Node*>::const_iterator aIter = mChildren.begin();
264         while( aIter != mChildren.end() )
265         {
266             Node* pChild = *aIter;
267             if ( pChild->mbIsItemIgnorable )
268             {
269                 if ( pChild->hasItemSet( bSkipUnusedItemSets ) )
270                 {
271                     return pChild->getUsedOrLastAddedItemSet();
272                 }
273                 else
274                 {
275                     pChild = pChild->nextItemSet( 0, bSkipUnusedItemSets, false );
276                     if ( pChild )
277                     {
278                         return pChild->getUsedOrLastAddedItemSet();
279                     }
280                 }
281             }
282             ++aIter;
283         }
284 
285         StylePool::SfxItemSet_Pointer_t pReturn;
286         return pReturn;
287     }
288     // <--
289 
~Node()290     Node::~Node()
291     {
292         std::vector<Node*>::iterator aIter = mChildren.begin();
293         while( aIter != mChildren.end() )
294         {
295             delete *aIter;
296             ++aIter;
297         }
298         delete mpItem;
299     }
300 
301     class Iterator : public IStylePoolIteratorAccess
302     {
303         std::map< const SfxItemSet*, Node >& mrRoot;
304         std::map< const SfxItemSet*, Node >::iterator mpCurrNode;
305         Node* mpNode;
306         const bool mbSkipUnusedItemSets;
307         const bool mbSkipIgnorable;
308     public:
309         // --> OD 2008-03-07 #i86923#
Iterator(std::map<const SfxItemSet *,Node> & rR,const bool bSkipUnusedItemSets,const bool bSkipIgnorable)310         Iterator( std::map< const SfxItemSet*, Node >& rR,
311                   const bool bSkipUnusedItemSets,
312                   const bool bSkipIgnorable )
313             : mrRoot( rR ),
314               mpCurrNode( rR.begin() ),
315               mpNode(0),
316               mbSkipUnusedItemSets( bSkipUnusedItemSets ),
317               mbSkipIgnorable( bSkipIgnorable )
318         {}
319         // <--
320         virtual StylePool::SfxItemSet_Pointer_t getNext();
321         virtual ::rtl::OUString getName();
322     };
323 
getNext()324     StylePool::SfxItemSet_Pointer_t Iterator::getNext()
325     {
326         StylePool::SfxItemSet_Pointer_t pReturn;
327         while( mpNode || mpCurrNode != mrRoot.end() )
328         {
329             if( !mpNode )
330             {
331                 mpNode = &mpCurrNode->second;
332                 ++mpCurrNode;
333                 // --> OD 2008-03-11 #i86923#
334                 if ( mpNode->hasItemSet( mbSkipUnusedItemSets ) )
335                 {
336                     // --> OD 2008-04-30 #i87808#
337 //                    return pNode->getItemSet();
338                     return mpNode->getUsedOrLastAddedItemSet();
339                     // <--
340                 }
341                 // <--
342             }
343             // --> OD 2008-03-11 #i86923#
344             mpNode = mpNode->nextItemSet( mpNode, mbSkipUnusedItemSets, mbSkipIgnorable );
345             if ( mpNode && mpNode->hasItemSet( mbSkipUnusedItemSets ) )
346             {
347                 // --> OD 2008-04-30 #i87808#
348 //                return pNode->getItemSet();
349                 return mpNode->getUsedOrLastAddedItemSet();
350                 // <--
351             }
352             if ( mbSkipIgnorable &&
353                  mpNode && mpNode->hasIgnorableChildren( mbSkipUnusedItemSets ) )
354             {
355                 return mpNode->getItemSetOfIgnorableChild( mbSkipUnusedItemSets );
356             }
357             // <--
358         }
359         return pReturn;
360     }
361 
getName()362     ::rtl::OUString Iterator::getName()
363     {
364         ::rtl::OUString aString;
365         if( mpNode && mpNode->hasItemSet( false ) )
366         {
367             // --> OD 2008-04-30 #i87808#
368 //            aString = StylePool::nameOf( pNode->getItemSet() );
369             aString = StylePool::nameOf( mpNode->getUsedOrLastAddedItemSet() );
370             // <--
371         }
372         return aString;
373     }
374 
375 }
376 
377 /* This static method creates a unique name from a shared pointer to a SfxItemSet
378    The name is the memory address of the SfxItemSet itself. */
379 
nameOf(SfxItemSet_Pointer_t pSet)380 ::rtl::OUString StylePool::nameOf( SfxItemSet_Pointer_t pSet )
381 {
382     return ::rtl::OUString::valueOf( reinterpret_cast<sal_IntPtr>( pSet.get() ), 16 );
383 }
384 
385 // class StylePoolImpl organized a tree-structure where every node represents a SfxItemSet.
386 // The insertItemSet method adds a SfxItemSet into the tree if necessary and returns a shared_ptr
387 // to a copy of the SfxItemSet.
388 // The aRoot-Node represents an empty SfxItemSet.
389 
390 class StylePoolImpl
391 {
392 private:
393     std::map< const SfxItemSet*, Node > maRoot;
394     sal_Int32 mnCount;
395     // --> OD 2008-03-07 #i86923#
396     SfxItemSet* mpIgnorableItems;
397     // <--
398 public:
399     // --> OD 2008-03-07 #i86923#
StylePoolImpl(SfxItemSet * pIgnorableItems=0)400     explicit StylePoolImpl( SfxItemSet* pIgnorableItems = 0 )
401         : maRoot(),
402           mnCount(0),
403           mpIgnorableItems( pIgnorableItems != 0
404                             ? pIgnorableItems->Clone( sal_False )
405                             : 0 )
406     {
407         DBG_ASSERT( !pIgnorableItems || !pIgnorableItems->Count(),
408                     "<StylePoolImpl::StylePoolImpl(..)> - misusage: item set for ignorable item should be empty. Please correct usage." );
409         DBG_ASSERT( !mpIgnorableItems || !mpIgnorableItems->Count(),
410                     "<StylePoolImpl::StylePoolImpl(..)> - <SfxItemSet::Clone( sal_False )> does not work as excepted - <mpIgnorableItems> is not empty. Please inform OD." );
411     }
412 
~StylePoolImpl()413     ~StylePoolImpl()
414     {
415         delete mpIgnorableItems;
416     }
417     // <--
418 
419     StylePool::SfxItemSet_Pointer_t insertItemSet( const SfxItemSet& rSet );
420 
421     // --> OD 2008-03-07 #i86923#
422     IStylePoolIteratorAccess* createIterator( bool bSkipUnusedItemSets = false,
423                                               bool bSkipIgnorableItems = false );
424     // <--
getCount() const425     sal_Int32 getCount() const { return mnCount; }
426 };
427 
insertItemSet(const SfxItemSet & rSet)428 StylePool::SfxItemSet_Pointer_t StylePoolImpl::insertItemSet( const SfxItemSet& rSet )
429 {
430     bool bNonPoolable = false;
431     Node* pCurNode = &maRoot[ rSet.GetParent() ];
432     SfxItemIter aIter( rSet );
433     const SfxPoolItem* pItem = aIter.GetCurItem();
434     // Every SfxPoolItem in the SfxItemSet causes a step deeper into the tree,
435     // a complete empty SfxItemSet would stay at the root node.
436     // --> OD 2008-03-07 #i86923#
437     // insert ignorable items to the tree leaves.
438     std::auto_ptr<SfxItemSet> pFoundIgnorableItems;
439     if ( mpIgnorableItems )
440     {
441         pFoundIgnorableItems.reset( new SfxItemSet( *mpIgnorableItems ) );
442     }
443     while( pItem )
444     {
445         if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
446             bNonPoolable = true;
447         if ( !pFoundIgnorableItems.get() ||
448              ( pFoundIgnorableItems.get() &&
449                pFoundIgnorableItems->Put( *pItem ) == 0 ) )
450         {
451             pCurNode = pCurNode->findChildNode( *pItem );
452         }
453 		pItem = aIter.NextItem();
454     }
455     if ( pFoundIgnorableItems.get() &&
456          pFoundIgnorableItems->Count() > 0 )
457     {
458         SfxItemIter aIgnorableItemsIter( *pFoundIgnorableItems );
459         pItem = aIgnorableItemsIter.GetCurItem();
460         while( pItem )
461         {
462             if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
463                 bNonPoolable = true;
464             pCurNode = pCurNode->findChildNode( *pItem, true );
465             pItem = aIgnorableItemsIter.NextItem();
466         }
467     }
468     // <--
469     // Every leaf node represents an inserted item set, but "non-leaf" nodes represents subsets
470     // of inserted itemsets.
471     // These nodes could have but does not need to have a shared_ptr to a item set.
472     if( !pCurNode->hasItemSet( false ) )
473     {
474         pCurNode->setItemSet( rSet );
475         bNonPoolable = false; // to avoid a double insertion
476         ++mnCount;
477     }
478     // If rSet contains at least one non poolable item, a new itemset has to be inserted
479     if( bNonPoolable )
480         pCurNode->setItemSet( rSet );
481 #ifdef DEBUG
482     {
483         sal_Int32 nCheck = -1;
484         sal_Int32 nNo = -1;
485         IStylePoolIteratorAccess* pIter = createIterator();
486         StylePool::SfxItemSet_Pointer_t pTemp;
487         do
488         {
489             ++nCheck;
490             pTemp = pIter->getNext();
491             if( pCurNode->hasItemSet( false ) && pTemp.get() == pCurNode->getItemSet().get() )
492             {
493                 ::rtl::OUString aStr = StylePool::nameOf( pTemp );
494                 nNo = nCheck;
495             }
496         } while( pTemp.get() );
497         DBG_ASSERT( mnCount == nCheck, "Wrong counting");
498         delete pIter;
499     }
500 #endif
501     return pCurNode->getItemSet();
502 }
503 
504 // --> OD 2008-03-07 #i86923#
createIterator(bool bSkipUnusedItemSets,bool bSkipIgnorableItems)505 IStylePoolIteratorAccess* StylePoolImpl::createIterator( bool bSkipUnusedItemSets,
506                                                          bool bSkipIgnorableItems )
507 {
508     return new Iterator( maRoot, bSkipUnusedItemSets, bSkipIgnorableItems );
509 }
510 // <--
511 
512 // Ctor, Dtor and redirected methods of class StylePool, nearly inline ;-)
513 
514 // --> OD 2008-03-07 #i86923#
StylePool(SfxItemSet * pIgnorableItems)515 StylePool::StylePool( SfxItemSet* pIgnorableItems )
516     : pImpl( new StylePoolImpl( pIgnorableItems ) )
517 {}
518 // <--
519 
insertItemSet(const SfxItemSet & rSet)520 StylePool::SfxItemSet_Pointer_t StylePool::insertItemSet( const SfxItemSet& rSet )
521 { return pImpl->insertItemSet( rSet ); }
522 
523 // --> OD 2008-03-11 #i86923#
createIterator(const bool bSkipUnusedItemSets,const bool bSkipIgnorableItems)524 IStylePoolIteratorAccess* StylePool::createIterator( const bool bSkipUnusedItemSets,
525                                                      const bool bSkipIgnorableItems )
526 {
527     return pImpl->createIterator( bSkipUnusedItemSets, bSkipIgnorableItems );
528 }
529 // <--
530 
getCount() const531 sal_Int32 StylePool::getCount() const
532 { return pImpl->getCount(); }
533 
~StylePool()534 StylePool::~StylePool() { delete pImpl; }
535 
536 // End of class StylePool
537 
538