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