LCOV - code coverage report
Current view: top level - libreoffice/svl/source/items - stylepool.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 142 175 81.1 %
Date: 2012-12-27 Functions: 25 30 83.3 %
Legend: Lines: hit not hit

          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         902 :     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         451 :         Node() // root node Ctor
      52             :             : mChildren(),
      53             :               maItemSet(),
      54             :               mpItem( 0 ),
      55             :               mpUpper( 0 ),
      56         451 :               mbIsItemIgnorable( false )
      57         451 :         {}
      58        5651 :         Node( const SfxPoolItem& rItem, Node* pParent, const bool bIgnorable ) // child node Ctor
      59             :             : mChildren(),
      60             :               maItemSet(),
      61        5651 :               mpItem( rItem.Clone() ),
      62             :               mpUpper( pParent ),
      63       11302 :               mbIsItemIgnorable( bIgnorable )
      64        5651 :         {}
      65             :         ~Node();
      66             :         // #i86923#
      67             :         bool hasItemSet( const bool bCheckUsage ) const;
      68             :         // #i87808#
      69       33668 :         const StylePool::SfxItemSet_Pointer_t getItemSet() const
      70             :         {
      71       33668 :             return maItemSet.back();
      72             :         }
      73             :         const StylePool::SfxItemSet_Pointer_t getUsedOrLastAddedItemSet() const;
      74        2802 :         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      462197 :         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           3 :     const StylePool::SfxItemSet_Pointer_t Node::getUsedOrLastAddedItemSet() const
      90             :     {
      91           3 :         std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
      92             : 
      93           3 :         for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
      94             :         {
      95           3 :             if ( (*aIter).use_count() > 1 )
      96             :             {
      97           3 :                 return *aIter;
      98             :             }
      99             :         }
     100             : 
     101           0 :         return maItemSet.back();
     102             :     }
     103             : 
     104             :     // #i86923#
     105       33690 :     bool Node::hasItemSet( const bool bCheckUsage ) const
     106             :     {
     107       33690 :         bool bHasItemSet = false;
     108             : 
     109       33690 :         if ( !maItemSet.empty())
     110             :         {
     111       30874 :             if ( bCheckUsage )
     112             :             {
     113           8 :                 std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
     114             : 
     115          10 :                 for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
     116             :                 {
     117           8 :                     if ( (*aIter).use_count() > 1 )
     118             :                     {
     119           6 :                         bHasItemSet = true;
     120           6 :                         break;
     121             :                     }
     122             :                 }
     123             :             }
     124             :             else
     125             :             {
     126       30866 :                 bHasItemSet = true;
     127             :             }
     128             :         }
     129       33690 :         return bHasItemSet;
     130             :     }
     131             : 
     132             :     // #i86923#
     133       92089 :     Node* Node::findChildNode( const SfxPoolItem& rItem,
     134             :                                const bool bIsItemIgnorable )
     135             :     {
     136       92089 :         Node* pNextNode = this;
     137       92089 :         std::vector<Node*>::iterator aIter = mChildren.begin();
     138      441232 :         while( aIter != mChildren.end() )
     139             :         {
     140      462197 :             if( rItem.Which() == (*aIter)->getPoolItem().Which() &&
     141      118705 :                 rItem == (*aIter)->getPoolItem() )
     142       86438 :                 return *aIter;
     143      257054 :             ++aIter;
     144             :         }
     145             :         // #i86923#
     146        5651 :         pNextNode = new Node( rItem, pNextNode, bIsItemIgnorable );
     147        5651 :         mChildren.push_back( pNextNode );
     148        5651 :         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          28 :     Node* Node::nextItemSet( Node* pLast,
     168             :                              const bool bSkipUnusedItemSets,
     169             :                              const bool bSkipIgnorable )
     170             :     {
     171             :         // Searching downstairs
     172          28 :         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          28 :         if( pLast && pLast != this )
     176             :         {
     177           9 :             aIter = std::find( mChildren.begin(), mChildren.end(), pLast );
     178           9 :             if( aIter != mChildren.end() )
     179           9 :                 ++aIter;
     180             :         }
     181          28 :         Node *pNext = 0;
     182          62 :         while( aIter != mChildren.end() )
     183             :         {
     184             :             // #i86923#
     185          15 :             if ( bSkipIgnorable && (*aIter)->mbIsItemIgnorable )
     186             :             {
     187           0 :                 ++aIter;
     188           0 :                 continue;
     189             :             }
     190          15 :             pNext = *aIter;
     191             :             // #i86923#
     192          15 :             if ( pNext->hasItemSet( bSkipUnusedItemSets ) )
     193             :             {
     194           3 :                 return pNext;
     195             :             }
     196          24 :             if ( bSkipIgnorable &&
     197          12 :                  pNext->hasIgnorableChildren( bSkipUnusedItemSets ) )
     198             :             {
     199           0 :                 return pNext;
     200             :             }
     201          12 :             pNext = pNext->nextItemSet( 0, bSkipUnusedItemSets, bSkipIgnorable ); // 0 => downstairs only
     202          12 :             if( pNext )
     203           6 :                 return pNext;
     204           6 :             ++aIter;
     205             :         }
     206             :         // Searching upstairs
     207          19 :         if( pLast && mpUpper )
     208             :         {
     209             :             // #i86923#
     210           9 :             pNext = mpUpper->nextItemSet( this, bSkipUnusedItemSets, bSkipIgnorable );
     211             :         }
     212          19 :         return pNext;
     213             :     }
     214             : 
     215             :     // #i86923#
     216          12 :     bool Node::hasIgnorableChildren( const bool bCheckUsage ) const
     217             :     {
     218          12 :         bool bHasIgnorableChildren( false );
     219             : 
     220          12 :         std::vector<Node*>::const_iterator aIter = mChildren.begin();
     221          34 :         while( aIter != mChildren.end() && !bHasIgnorableChildren )
     222             :         {
     223          10 :             Node* pChild = *aIter;
     224          10 :             if ( pChild->mbIsItemIgnorable )
     225             :             {
     226             :                 bHasIgnorableChildren =
     227           0 :                     !bCheckUsage ||
     228           0 :                     ( pChild->hasItemSet( bCheckUsage /* == true */ ) ||
     229           0 :                       pChild->hasIgnorableChildren( bCheckUsage /* == true */ ) );
     230             :             }
     231          10 :             ++aIter;
     232             :         }
     233             : 
     234          12 :         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        8994 :     Node::~Node()
     270             :     {
     271        4497 :         std::vector<Node*>::iterator aIter = mChildren.begin();
     272       12389 :         while( aIter != mChildren.end() )
     273             :         {
     274        3395 :             delete *aIter;
     275        3395 :             ++aIter;
     276             :         }
     277        4497 :         delete mpItem;
     278        4497 :     }
     279             : 
     280           8 :     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           4 :         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           4 :               mbSkipIgnorable( bSkipIgnorable )
     297           4 :         {}
     298             :         virtual StylePool::SfxItemSet_Pointer_t getNext();
     299             :         virtual ::rtl::OUString getName();
     300             :     };
     301             : 
     302           7 :     StylePool::SfxItemSet_Pointer_t Iterator::getNext()
     303             :     {
     304           7 :         StylePool::SfxItemSet_Pointer_t pReturn;
     305          18 :         while( mpNode || mpCurrNode != mrRoot.end() )
     306             :         {
     307           7 :             if( !mpNode )
     308             :             {
     309           4 :                 mpNode = &mpCurrNode->second;
     310           4 :                 ++mpCurrNode;
     311             :                 // #i86923#
     312           4 :                 if ( mpNode->hasItemSet( mbSkipUnusedItemSets ) )
     313             :                 {
     314             :                     // #i87808#
     315           0 :                     return mpNode->getUsedOrLastAddedItemSet();
     316             :                 }
     317             :             }
     318             :             // #i86923#
     319           7 :             mpNode = mpNode->nextItemSet( mpNode, mbSkipUnusedItemSets, mbSkipIgnorable );
     320           7 :             if ( mpNode && mpNode->hasItemSet( mbSkipUnusedItemSets ) )
     321             :             {
     322             :                 // #i87808#
     323           3 :                 return mpNode->getUsedOrLastAddedItemSet();
     324             :             }
     325           4 :             if ( mbSkipIgnorable &&
     326           0 :                  mpNode && mpNode->hasIgnorableChildren( mbSkipUnusedItemSets ) )
     327             :             {
     328           0 :                 return mpNode->getItemSetOfIgnorableChild( mbSkipUnusedItemSets );
     329             :             }
     330             :         }
     331           4 :         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          46 : ::rtl::OUString StylePool::nameOf( SfxItemSet_Pointer_t pSet )
     350             : {
     351          46 :     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         552 :     explicit StylePoolImpl( SfxItemSet* pIgnorableItems = 0 )
     369             :         : maRoot(),
     370             :           mnCount(0),
     371             :           mpIgnorableItems( pIgnorableItems != 0
     372         276 :                             ? pIgnorableItems->Clone( sal_False )
     373         828 :                             : 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         552 :     }
     380             : 
     381         204 :     ~StylePoolImpl()
     382         204 :     {
     383         204 :         delete mpIgnorableItems;
     384         204 :     }
     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       33668 : StylePool::SfxItemSet_Pointer_t StylePoolImpl::insertItemSet( const SfxItemSet& rSet )
     395             : {
     396       33668 :     bool bNonPoolable = false;
     397       33668 :     Node* pCurNode = &maRoot[ rSet.GetParent() ];
     398       33668 :     SfxItemIter aIter( rSet );
     399       33668 :     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       33668 :     std::auto_ptr<SfxItemSet> pFoundIgnorableItems;
     404       33668 :     if ( mpIgnorableItems )
     405             :     {
     406       15015 :         pFoundIgnorableItems.reset( new SfxItemSet( *mpIgnorableItems ) );
     407             :     }
     408      159425 :     while( pItem )
     409             :     {
     410       92089 :         if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
     411         269 :             bNonPoolable = true;
     412      188187 :         if ( !pFoundIgnorableItems.get() ||
     413       48049 :              ( pFoundIgnorableItems.get() &&
     414       48049 :                pFoundIgnorableItems->Put( *pItem ) == 0 ) )
     415             :         {
     416       88574 :             pCurNode = pCurNode->findChildNode( *pItem );
     417             :         }
     418       92089 :         pItem = aIter.NextItem();
     419             :     }
     420       48683 :     if ( pFoundIgnorableItems.get() &&
     421       15015 :          pFoundIgnorableItems->Count() > 0 )
     422             :     {
     423        3380 :         SfxItemIter aIgnorableItemsIter( *pFoundIgnorableItems );
     424        3380 :         pItem = aIgnorableItemsIter.GetCurItem();
     425       10275 :         while( pItem )
     426             :         {
     427        3515 :             if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
     428           0 :                 bNonPoolable = true;
     429        3515 :             pCurNode = pCurNode->findChildNode( *pItem, true );
     430        3515 :             pItem = aIgnorableItemsIter.NextItem();
     431        3380 :         }
     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       33668 :     if( !pCurNode->hasItemSet( false ) )
     437             :     {
     438        2802 :         pCurNode->setItemSet( rSet );
     439        2802 :         bNonPoolable = false; // to avoid a double insertion
     440        2802 :         ++mnCount;
     441             :     }
     442             :     // If rSet contains at least one non poolable item, a new itemset has to be inserted
     443       33668 :     if( bNonPoolable )
     444           0 :         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       33668 :     return pCurNode->getItemSet();
     460             : }
     461             : 
     462             : // #i86923#
     463           4 : IStylePoolIteratorAccess* StylePoolImpl::createIterator( bool bSkipUnusedItemSets,
     464             :                                                          bool bSkipIgnorableItems )
     465             : {
     466           4 :     return new Iterator( maRoot, bSkipUnusedItemSets, bSkipIgnorableItems );
     467             : }
     468             : // Ctor, Dtor and redirected methods of class StylePool, nearly inline ;-)
     469             : 
     470             : // #i86923#
     471         552 : StylePool::StylePool( SfxItemSet* pIgnorableItems )
     472         552 :     : pImpl( new StylePoolImpl( pIgnorableItems ) )
     473         552 : {}
     474             : 
     475       33668 : StylePool::SfxItemSet_Pointer_t StylePool::insertItemSet( const SfxItemSet& rSet )
     476       33668 : { return pImpl->insertItemSet( rSet ); }
     477             : 
     478             : // #i86923#
     479           4 : IStylePoolIteratorAccess* StylePool::createIterator( const bool bSkipUnusedItemSets,
     480             :                                                      const bool bSkipIgnorableItems )
     481             : {
     482           4 :     return pImpl->createIterator( bSkipUnusedItemSets, bSkipIgnorableItems );
     483             : }
     484             : 
     485           0 : sal_Int32 StylePool::getCount() const
     486           0 : { return pImpl->getCount(); }
     487             : 
     488         204 : StylePool::~StylePool() { delete pImpl; }
     489             : 
     490             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10