LCOV - code coverage report
Current view: top level - svl/source/items - stylepool.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 143 174 82.2 %
Date: 2014-11-03 Functions: 24 29 82.8 %
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             : #include <boost/scoped_ptr.hpp>
      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             :      */
      40             :     class Node
      41             :     {
      42             :         std::vector<Node*> mChildren; // child nodes, create by findChildNode(..)
      43             :         // container of shared pointers of inserted item sets; for non-poolable
      44             :         // items more than one item set is needed
      45             :         std::vector< StylePool::SfxItemSet_Pointer_t > maItemSet;
      46             :         const SfxPoolItem *mpItem;   // my pool item
      47             :         Node *mpUpper;               // if I'm a child node that's my parent node
      48             :         // #i86923#
      49             :         const bool mbIsItemIgnorable;
      50             :     public:
      51             :         // #i86923#
      52        8932 :         Node() // root node Ctor
      53             :             : mChildren(),
      54             :               maItemSet(),
      55             :               mpItem( 0 ),
      56             :               mpUpper( 0 ),
      57        8932 :               mbIsItemIgnorable( false )
      58        8932 :         {}
      59      144486 :         Node( const SfxPoolItem& rItem, Node* pParent, const bool bIgnorable ) // child node Ctor
      60             :             : mChildren(),
      61             :               maItemSet(),
      62      144486 :               mpItem( rItem.Clone() ),
      63             :               mpUpper( pParent ),
      64      288972 :               mbIsItemIgnorable( bIgnorable )
      65      144486 :         {}
      66             :         ~Node();
      67             :         // #i86923#
      68             :         bool hasItemSet( const bool bCheckUsage ) const;
      69             :         // #i87808#
      70      373312 :         const StylePool::SfxItemSet_Pointer_t getItemSet() const
      71             :         {
      72      373312 :             return maItemSet.back();
      73             :         }
      74             :         const StylePool::SfxItemSet_Pointer_t getUsedOrLastAddedItemSet() const;
      75       47778 :         void setItemSet( const SfxItemSet& rSet ){ maItemSet.push_back( StylePool::SfxItemSet_Pointer_t( rSet.Clone() ) ); }
      76             :         // #i86923#
      77             :         Node* findChildNode( const SfxPoolItem& rItem,
      78             :                              const bool bIsItemIgnorable = false );
      79             :         Node* nextItemSet( Node* pLast,
      80             :                            const bool bSkipUnusedItemSet,
      81             :                            const bool bSkipIgnorable );
      82     5143422 :         const SfxPoolItem& getPoolItem() const { return *mpItem; }
      83             :         // #i86923#
      84             :         bool hasIgnorableChildren( const bool bCheckUsage ) const;
      85             :         const StylePool::SfxItemSet_Pointer_t getItemSetOfIgnorableChild(
      86             :                                         const bool bSkipUnusedItemSets ) const;
      87             :     };
      88             : 
      89             :     // #i87808#
      90          88 :     const StylePool::SfxItemSet_Pointer_t Node::getUsedOrLastAddedItemSet() const
      91             :     {
      92          88 :         std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
      93             : 
      94          88 :         for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
      95             :         {
      96          88 :             if ( (*aIter).use_count() > 1 )
      97             :             {
      98          88 :                 return *aIter;
      99             :             }
     100             :         }
     101             : 
     102           0 :         return maItemSet.back();
     103             :     }
     104             : 
     105             :     // #i86923#
     106      373942 :     bool Node::hasItemSet( const bool bCheckUsage ) const
     107             :     {
     108      373942 :         bool bHasItemSet = false;
     109             : 
     110      373942 :         if ( !maItemSet.empty())
     111             :         {
     112      325902 :             if ( bCheckUsage )
     113             :             {
     114         228 :                 std::vector< StylePool::SfxItemSet_Pointer_t >::const_reverse_iterator aIter;
     115             : 
     116         282 :                 for ( aIter = maItemSet.rbegin(); aIter != maItemSet.rend(); ++aIter )
     117             :                 {
     118         230 :                     if ( (*aIter).use_count() > 1 )
     119             :                     {
     120         176 :                         bHasItemSet = true;
     121         176 :                         break;
     122             :                     }
     123             :                 }
     124             :             }
     125             :             else
     126             :             {
     127      325674 :                 bHasItemSet = true;
     128             :             }
     129             :         }
     130      373942 :         return bHasItemSet;
     131             :     }
     132             : 
     133             :     // #i86923#
     134     1505902 :     Node* Node::findChildNode( const SfxPoolItem& rItem,
     135             :                                const bool bIsItemIgnorable )
     136             :     {
     137     1505902 :         Node* pNextNode = this;
     138     1505902 :         std::vector<Node*>::iterator aIter = mChildren.begin();
     139     5142076 :         while( aIter != mChildren.end() )
     140             :         {
     141     5143422 :             if( rItem.Which() == (*aIter)->getPoolItem().Which() &&
     142     1651734 :                 rItem == (*aIter)->getPoolItem() )
     143     1361416 :                 return *aIter;
     144     2130272 :             ++aIter;
     145             :         }
     146             :         // #i86923#
     147      144486 :         pNextNode = new Node( rItem, pNextNode, bIsItemIgnorable );
     148      144486 :         mChildren.push_back( pNextNode );
     149      144486 :         return pNextNode;
     150             :     }
     151             : 
     152             :     /**
     153             :      * Find the next node which has a SfxItemSet.
     154             :      * The input parameter pLast has a sophisticated meaning:
     155             :      * downstairs only:
     156             :      * pLast == 0 => scan your children and their children
     157             :      *               but neither your parents neither your siblings
     158             :      * downstairs and upstairs:
     159             :      * pLast == this => scan your children, their children,
     160             :      *                  the children of your parent behind you, and so on
     161             :      * partial downstairs and upstairs
     162             :      *  pLast != 0 && pLast != this => scan your children behind the given children,
     163             :      *                 the children of your parent behind you and so on.
     164             :      *
     165             :      * OD 2008-03-11 #i86923#
     166             :      * introduce parameters <bSkipUnusedItemSets> and <bSkipIgnorable>
     167             :      * and its handling.
     168             :      */
     169         854 :     Node* Node::nextItemSet( Node* pLast,
     170             :                              const bool bSkipUnusedItemSets,
     171             :                              const bool bSkipIgnorable )
     172             :     {
     173             :         // Searching downstairs
     174         854 :         std::vector<Node*>::iterator aIter = mChildren.begin();
     175             :         // For pLast == 0 and pLast == this all children are of interest
     176             :         // for another pLast the search starts behind pLast...
     177         854 :         if( pLast && pLast != this )
     178             :         {
     179         312 :             aIter = std::find( mChildren.begin(), mChildren.end(), pLast );
     180         312 :             if( aIter != mChildren.end() )
     181         312 :                 ++aIter;
     182             :         }
     183         854 :         Node *pNext = 0;
     184        1852 :         while( aIter != mChildren.end() )
     185             :         {
     186             :             // #i86923#
     187         456 :             if ( bSkipIgnorable && (*aIter)->mbIsItemIgnorable )
     188             :             {
     189           0 :                 ++aIter;
     190           0 :                 continue;
     191             :             }
     192         456 :             pNext = *aIter;
     193             :             // #i86923#
     194         456 :             if ( pNext->hasItemSet( bSkipUnusedItemSets ) )
     195             :             {
     196          88 :                 return pNext;
     197             :             }
     198         736 :             if ( bSkipIgnorable &&
     199         368 :                  pNext->hasIgnorableChildren( bSkipUnusedItemSets ) )
     200             :             {
     201           0 :                 return pNext;
     202             :             }
     203         368 :             pNext = pNext->nextItemSet( 0, bSkipUnusedItemSets, bSkipIgnorable ); // 0 => downstairs only
     204         368 :             if( pNext )
     205         224 :                 return pNext;
     206         144 :             ++aIter;
     207             :         }
     208             :         // Searching upstairs
     209         542 :         if( pLast && mpUpper )
     210             :         {
     211             :             // #i86923#
     212         312 :             pNext = mpUpper->nextItemSet( this, bSkipUnusedItemSets, bSkipIgnorable );
     213             :         }
     214         542 :         return pNext;
     215             :     }
     216             : 
     217             :     // #i86923#
     218         368 :     bool Node::hasIgnorableChildren( const bool bCheckUsage ) const
     219             :     {
     220         368 :         bool bHasIgnorableChildren( false );
     221             : 
     222         368 :         std::vector<Node*>::const_iterator aIter = mChildren.begin();
     223        1066 :         while( aIter != mChildren.end() && !bHasIgnorableChildren )
     224             :         {
     225         330 :             Node* pChild = *aIter;
     226         330 :             if ( pChild->mbIsItemIgnorable )
     227             :             {
     228             :                 bHasIgnorableChildren =
     229           0 :                     !bCheckUsage ||
     230           0 :                     ( pChild->hasItemSet( bCheckUsage /* == true */ ) ||
     231           0 :                       pChild->hasIgnorableChildren( bCheckUsage /* == true */ ) );
     232             :             }
     233         330 :             ++aIter;
     234             :         }
     235             : 
     236         368 :         return bHasIgnorableChildren;
     237             :     }
     238             : 
     239           0 :     const StylePool::SfxItemSet_Pointer_t Node::getItemSetOfIgnorableChild(
     240             :                                         const bool bSkipUnusedItemSets ) const
     241             :     {
     242             :         DBG_ASSERT( hasIgnorableChildren( bSkipUnusedItemSets ),
     243             :                     "<Node::getItemSetOfIgnorableChild> - node has no ignorable children" );
     244             : 
     245           0 :         std::vector<Node*>::const_iterator aIter = mChildren.begin();
     246           0 :         while( aIter != mChildren.end() )
     247             :         {
     248           0 :             Node* pChild = *aIter;
     249           0 :             if ( pChild->mbIsItemIgnorable )
     250             :             {
     251           0 :                 if ( pChild->hasItemSet( bSkipUnusedItemSets ) )
     252             :                 {
     253           0 :                     return pChild->getUsedOrLastAddedItemSet();
     254             :                 }
     255             :                 else
     256             :                 {
     257           0 :                     pChild = pChild->nextItemSet( 0, bSkipUnusedItemSets, false );
     258           0 :                     if ( pChild )
     259             :                     {
     260           0 :                         return pChild->getUsedOrLastAddedItemSet();
     261             :                     }
     262             :                 }
     263             :             }
     264           0 :             ++aIter;
     265             :         }
     266             : 
     267           0 :         StylePool::SfxItemSet_Pointer_t pReturn;
     268           0 :         return pReturn;
     269             :     }
     270             : 
     271      306472 :     Node::~Node()
     272             :     {
     273      153236 :         std::vector<Node*>::iterator aIter = mChildren.begin();
     274      450791 :         while( aIter != mChildren.end() )
     275             :         {
     276      144319 :             delete *aIter;
     277      144319 :             ++aIter;
     278             :         }
     279      153236 :         delete mpItem;
     280      153236 :     }
     281             : 
     282         264 :     class Iterator : public IStylePoolIteratorAccess
     283             :     {
     284             :         std::map< const SfxItemSet*, Node >& mrRoot;
     285             :         std::map< const SfxItemSet*, Node >::iterator mpCurrNode;
     286             :         Node* mpNode;
     287             :         const bool mbSkipUnusedItemSets;
     288             :         const bool mbSkipIgnorable;
     289             :     public:
     290             :         // #i86923#
     291         132 :         Iterator( std::map< const SfxItemSet*, Node >& rR,
     292             :                   const bool bSkipUnusedItemSets,
     293             :                   const bool bSkipIgnorable )
     294             :             : mrRoot( rR ),
     295             :               mpCurrNode( rR.begin() ),
     296             :               mpNode(0),
     297             :               mbSkipUnusedItemSets( bSkipUnusedItemSets ),
     298         132 :               mbSkipIgnorable( bSkipIgnorable )
     299         132 :         {}
     300             :         virtual StylePool::SfxItemSet_Pointer_t getNext() SAL_OVERRIDE;
     301             :         virtual OUString getName() SAL_OVERRIDE;
     302             :     };
     303             : 
     304         220 :     StylePool::SfxItemSet_Pointer_t Iterator::getNext()
     305             :     {
     306         220 :         StylePool::SfxItemSet_Pointer_t pReturn;
     307         220 :         while( mpNode || mpCurrNode != mrRoot.end() )
     308             :         {
     309         174 :             if( !mpNode )
     310             :             {
     311          86 :                 mpNode = &mpCurrNode->second;
     312          86 :                 ++mpCurrNode;
     313             :                 // #i86923#
     314          86 :                 if ( mpNode->hasItemSet( mbSkipUnusedItemSets ) )
     315             :                 {
     316             :                     // #i87808#
     317           0 :                     return mpNode->getUsedOrLastAddedItemSet();
     318             :                 }
     319             :             }
     320             :             // #i86923#
     321         174 :             mpNode = mpNode->nextItemSet( mpNode, mbSkipUnusedItemSets, mbSkipIgnorable );
     322         174 :             if ( mpNode && mpNode->hasItemSet( mbSkipUnusedItemSets ) )
     323             :             {
     324             :                 // #i87808#
     325          88 :                 return mpNode->getUsedOrLastAddedItemSet();
     326             :             }
     327         172 :             if ( mbSkipIgnorable &&
     328          86 :                  mpNode && mpNode->hasIgnorableChildren( mbSkipUnusedItemSets ) )
     329             :             {
     330           0 :                 return mpNode->getItemSetOfIgnorableChild( mbSkipUnusedItemSets );
     331             :             }
     332             :         }
     333         132 :         return pReturn;
     334             :     }
     335             : 
     336           0 :     OUString Iterator::getName()
     337             :     {
     338           0 :         OUString aString;
     339           0 :         if( mpNode && mpNode->hasItemSet( false ) )
     340             :         {
     341           0 :             aString = StylePool::nameOf( mpNode->getUsedOrLastAddedItemSet() );
     342             :         }
     343           0 :         return aString;
     344             :     }
     345             : 
     346             : }
     347             : 
     348             : /**
     349             :  * This static method creates a unique name from a shared pointer to a SfxItemSet
     350             :  * The name is the memory address of the SfxItemSet itself.
     351             :  */
     352        5356 : OUString StylePool::nameOf( SfxItemSet_Pointer_t pSet )
     353             : {
     354        5356 :     return OUString::number( reinterpret_cast<sal_IntPtr>( pSet.get() ), 16 );
     355             : }
     356             : 
     357             : /**
     358             :  * class StylePoolImpl organized a tree-structure where every node represents a SfxItemSet.
     359             :  * The insertItemSet method adds a SfxItemSet into the tree if necessary and returns a shared_ptr
     360             :  * to a copy of the SfxItemSet.
     361             :  * The aRoot-Node represents an empty SfxItemSet.
     362             :  */
     363             : class StylePoolImpl
     364             : {
     365             : private:
     366             :     std::map< const SfxItemSet*, Node > maRoot;
     367             :     sal_Int32 mnCount;
     368             :     // #i86923#
     369             :     SfxItemSet* mpIgnorableItems;
     370             : public:
     371             :     // #i86923#
     372       10104 :     explicit StylePoolImpl( SfxItemSet* pIgnorableItems = 0 )
     373             :         : maRoot(),
     374             :           mnCount(0),
     375             :           mpIgnorableItems( pIgnorableItems != 0
     376        5052 :                             ? pIgnorableItems->Clone( false )
     377       15156 :                             : 0 )
     378             :     {
     379             :         DBG_ASSERT( !pIgnorableItems || !pIgnorableItems->Count(),
     380             :                     "<StylePoolImpl::StylePoolImpl(..)> - misusage: item set for ignorable item should be empty. Please correct usage." );
     381             :         DBG_ASSERT( !mpIgnorableItems || !mpIgnorableItems->Count(),
     382             :                     "<StylePoolImpl::StylePoolImpl(..)> - <SfxItemSet::Clone( sal_False )> does not work as excepted - <mpIgnorableItems> is not empty. Please inform OD." );
     383       10104 :     }
     384             : 
     385       10090 :     ~StylePoolImpl()
     386       10090 :     {
     387       10090 :         delete mpIgnorableItems;
     388       10090 :     }
     389             : 
     390             :     StylePool::SfxItemSet_Pointer_t insertItemSet( const SfxItemSet& rSet );
     391             : 
     392             :     // #i86923#
     393             :     IStylePoolIteratorAccess* createIterator( bool bSkipUnusedItemSets = false,
     394             :                                               bool bSkipIgnorableItems = false );
     395           0 :     sal_Int32 getCount() const { return mnCount; }
     396             : };
     397             : 
     398      373312 : StylePool::SfxItemSet_Pointer_t StylePoolImpl::insertItemSet( const SfxItemSet& rSet )
     399             : {
     400      373312 :     bool bNonPoolable = false;
     401      373312 :     Node* pCurNode = &maRoot[ rSet.GetParent() ];
     402      373312 :     SfxItemIter aIter( rSet );
     403      373312 :     const SfxPoolItem* pItem = aIter.GetCurItem();
     404             :     // Every SfxPoolItem in the SfxItemSet causes a step deeper into the tree,
     405             :     // a complete empty SfxItemSet would stay at the root node.
     406             :     // #i86923# insert ignorable items to the tree leaves.
     407      746624 :     boost::scoped_ptr<SfxItemSet> pFoundIgnorableItems;
     408      373312 :     if ( mpIgnorableItems )
     409             :     {
     410      197932 :         pFoundIgnorableItems.reset( new SfxItemSet( *mpIgnorableItems ) );
     411             :     }
     412     2252526 :     while( pItem )
     413             :     {
     414     1505902 :         if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
     415        5274 :             bNonPoolable = true;
     416     3846194 :         if ( !pFoundIgnorableItems.get() ||
     417     1705548 :              ( pFoundIgnorableItems.get() &&
     418      852774 :                pFoundIgnorableItems->Put( *pItem ) == 0 ) )
     419             :         {
     420     1487518 :             pCurNode = pCurNode->findChildNode( *pItem );
     421             :         }
     422     1505902 :         pItem = aIter.NextItem();
     423             :     }
     424      571244 :     if ( pFoundIgnorableItems.get() &&
     425      197932 :          pFoundIgnorableItems->Count() > 0 )
     426             :     {
     427       17846 :         SfxItemIter aIgnorableItemsIter( *pFoundIgnorableItems );
     428       17846 :         pItem = aIgnorableItemsIter.GetCurItem();
     429       54076 :         while( pItem )
     430             :         {
     431       18384 :             if( !rSet.GetPool()->IsItemFlag(pItem->Which(), SFX_ITEM_POOLABLE ) )
     432           0 :                 bNonPoolable = true;
     433       18384 :             pCurNode = pCurNode->findChildNode( *pItem, true );
     434       18384 :             pItem = aIgnorableItemsIter.NextItem();
     435       17846 :         }
     436             :     }
     437             :     // Every leaf node represents an inserted item set, but "non-leaf" nodes represents subsets
     438             :     // of inserted itemsets.
     439             :     // These nodes could have but does not need to have a shared_ptr to a item set.
     440      373312 :     if( !pCurNode->hasItemSet( false ) )
     441             :     {
     442       47638 :         pCurNode->setItemSet( rSet );
     443       47638 :         bNonPoolable = false; // to avoid a double insertion
     444       47638 :         ++mnCount;
     445             :     }
     446             :     // If rSet contains at least one non poolable item, a new itemset has to be inserted
     447      373312 :     if( bNonPoolable )
     448         140 :         pCurNode->setItemSet( rSet );
     449             : #ifdef DEBUG
     450             :     {
     451             :         sal_Int32 nCheck = -1;
     452             :         IStylePoolIteratorAccess* pIter = createIterator();
     453             :         StylePool::SfxItemSet_Pointer_t pTemp;
     454             :         do
     455             :         {
     456             :             ++nCheck;
     457             :             pTemp = pIter->getNext();
     458             :         } while( pTemp.get() );
     459             :         DBG_ASSERT( mnCount == nCheck, "Wrong counting");
     460             :         delete pIter;
     461             :     }
     462             : #endif
     463      746624 :     return pCurNode->getItemSet();
     464             : }
     465             : 
     466             : // #i86923#
     467         132 : IStylePoolIteratorAccess* StylePoolImpl::createIterator( bool bSkipUnusedItemSets,
     468             :                                                          bool bSkipIgnorableItems )
     469             : {
     470         132 :     return new Iterator( maRoot, bSkipUnusedItemSets, bSkipIgnorableItems );
     471             : }
     472             : // Ctor, Dtor and redirected methods of class StylePool, nearly inline ;-)
     473             : 
     474             : // #i86923#
     475       10104 : StylePool::StylePool( SfxItemSet* pIgnorableItems )
     476       10104 :     : pImpl( new StylePoolImpl( pIgnorableItems ) )
     477       10104 : {}
     478             : 
     479      373312 : StylePool::SfxItemSet_Pointer_t StylePool::insertItemSet( const SfxItemSet& rSet )
     480      373312 : { return pImpl->insertItemSet( rSet ); }
     481             : 
     482             : // #i86923#
     483         132 : IStylePoolIteratorAccess* StylePool::createIterator( const bool bSkipUnusedItemSets,
     484             :                                                      const bool bSkipIgnorableItems )
     485             : {
     486         132 :     return pImpl->createIterator( bSkipUnusedItemSets, bSkipIgnorableItems );
     487             : }
     488             : 
     489           0 : sal_Int32 StylePool::getCount() const
     490           0 : { return pImpl->getCount(); }
     491             : 
     492       10090 : StylePool::~StylePool() { delete pImpl; }
     493             : 
     494             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10