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