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# 58 Node() // root node Ctor 59 : mChildren(), 60 maItemSet(), 61 mpItem( 0 ), 62 mpUpper( 0 ), 63 mbIsItemIgnorable( false ) 64 {} 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]; } 79 const StylePool::SfxItemSet_Pointer_t getItemSet() const 80 { 81 return maItemSet.back(); 82 } 83 const StylePool::SfxItemSet_Pointer_t getUsedOrLastAddedItemSet() const; 84 // <-- 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 // <-- 93 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# 102 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# 119 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# 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 */ 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# 236 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 257 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 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# 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 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 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 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# 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 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 // <-- 425 sal_Int32 getCount() const { return mnCount; } 426 }; 427 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# 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# 515 StylePool::StylePool( SfxItemSet* pIgnorableItems ) 516 : pImpl( new StylePoolImpl( pIgnorableItems ) ) 517 {} 518 // <-- 519 520 StylePool::SfxItemSet_Pointer_t StylePool::insertItemSet( const SfxItemSet& rSet ) 521 { return pImpl->insertItemSet( rSet ); } 522 523 // --> OD 2008-03-11 #i86923# 524 IStylePoolIteratorAccess* StylePool::createIterator( const bool bSkipUnusedItemSets, 525 const bool bSkipIgnorableItems ) 526 { 527 return pImpl->createIterator( bSkipUnusedItemSets, bSkipIgnorableItems ); 528 } 529 // <-- 530 531 sal_Int32 StylePool::getCount() const 532 { return pImpl->getCount(); } 533 534 StylePool::~StylePool() { delete pImpl; } 535 536 // End of class StylePool 537 538