LCOV - code coverage report
Current view: top level - sw/inc - calbck.hxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 101 115 87.8 %
Date: 2015-06-13 12:38:46 Functions: 173 271 63.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             : #ifndef INCLUDED_SW_INC_CALBCK_HXX
      21             : #define INCLUDED_SW_INC_CALBCK_HXX
      22             : 
      23             : #include <tools/rtti.hxx>
      24             : #include "swdllapi.h"
      25             : #include <boost/noncopyable.hpp>
      26             : #include <ring.hxx>
      27             : #include <hintids.hxx>
      28             : #include <hints.hxx>
      29             : #include <typeinfo>
      30             : #include <type_traits>
      31             : 
      32             : 
      33             : class SwModify;
      34             : class SfxPoolItem;
      35             : class SfxHint;
      36             : 
      37             : /*
      38             :     SwModify and SwClient cooperate in propagating attribute changes.
      39             :     If an attribute changes, the change is notified to all dependent
      40             :     formats and other interested objects, e.g. Nodes. The clients will detect
      41             :     if the change affects them. It could be that the changed attribute is
      42             :     overruled in the receiving object so that its change does not become
      43             :     effective or that the receiver is not interested in the particular attribute
      44             :     in general (though probably in other attributes of the SwModify object they
      45             :     are registered in).
      46             :     As SwModify objects are derived from SwClient, they can create a chain of SwClient
      47             :     objects where changes can get propagated through.
      48             :     Each SwClient can be registered at only one SwModify object, while each SwModify
      49             :     object is connected to a list of SwClient objects. If an object derived from SwClient
      50             :     wants to get notifications from more than one SwModify object, it must create additional
      51             :     SwClient objects. The SwDepend class allows to handle their notifications in the same
      52             :     notification callback as it forwards the Modify() calls it receives to a "master"
      53             :     SwClient implementation.
      54             :     The SwIterator class allows to iterate over the SwClient objects registered at an
      55             :     SwModify. For historical reasons its ability to use TypeInfo to restrict this iteration
      56             :     to objects of a particular type created a lot of code that misuses SwClient-SwModify
      57             :     relationships that basically should be used only for Modify/Notify callbacks.
      58             :     This is still subject to refactoring.
      59             :  */
      60             : 
      61             : class SwModify;
      62             : class SwClient;
      63             : template<typename E, typename S> class SwIterator;
      64             : 
      65             : namespace sw
      66             : {
      67             :     class ClientIteratorBase;
      68             :     struct SW_DLLPUBLIC LegacyModifyHint SAL_FINAL: SfxHint
      69             :     {
      70      660090 :         LegacyModifyHint(const SfxPoolItem* pOld, const SfxPoolItem* pNew) : m_pOld(pOld), m_pNew(pNew) {};
      71             :         virtual ~LegacyModifyHint();
      72             :         const SfxPoolItem* m_pOld;
      73             :         const SfxPoolItem* m_pNew;
      74             :     };
      75             :     /// refactoring out the some of the more sane SwClient functionality
      76             :     class SW_DLLPUBLIC WriterListener : ::boost::noncopyable
      77             :     {
      78             :         friend class ::SwModify;
      79             :         friend class ::sw::ClientIteratorBase;
      80             :         private:
      81             :             WriterListener* m_pLeft;
      82             :             WriterListener* m_pRight; ///< double-linked list of other clients
      83             :         protected:
      84     9174398 :             WriterListener()
      85     9174398 :                 : m_pLeft(nullptr), m_pRight(nullptr)
      86     9174398 :             {}
      87     9170986 :             virtual ~WriterListener() {};
      88             :             virtual void SwClientNotify( const SwModify&, const SfxHint& rHint) =0;
      89             :         public:
      90        6781 :             bool IsLast() const { return !m_pLeft && !m_pRight; }
      91             :    };
      92             : }
      93             : // SwClient
      94             : class SW_DLLPUBLIC SwClient : ::sw::WriterListener
      95             : {
      96             :     // avoids making the details of the linked list and the callback method public
      97             :     friend class SwModify;
      98             :     friend class sw::ClientIteratorBase;
      99             :     template<typename E, typename S> friend class SwIterator;
     100             : 
     101             :     SwModify *pRegisteredIn;        ///< event source
     102             : 
     103             : protected:
     104             :     // single argument ctors shall be explicit.
     105             :     inline explicit SwClient( SwModify* pToRegisterIn );
     106             : 
     107             :     // write access to pRegisteredIn shall be granted only to the object itself (protected access)
     108    85416076 :     SwModify* GetRegisteredInNonConst() const { return pRegisteredIn; }
     109             : 
     110             : public:
     111             : 
     112     2041711 :     SwClient() : pRegisteredIn(nullptr) {}
     113             :     virtual ~SwClient() SAL_OVERRIDE;
     114             :     // callbacks received from SwModify (friend class - so these methods can be private)
     115             :     // should be called only from SwModify the client is registered in
     116             :     // mba: IMHO this method should be pure virtual
     117             :     // DO NOT USE IN NEW CODE! use SwClientNotify instead.
     118             :     virtual void Modify(const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue);
     119             :     // when overriding this, you MUST call SwClient::SwClientModify() in the override!
     120             :     virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) SAL_OVERRIDE;
     121             : 
     122             :     // in case an SwModify object is destroyed that itself is registered in another SwModify,
     123             :     // its SwClient objects can decide to get registered to the latter instead by calling this method
     124             :     void CheckRegistration( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
     125             : 
     126             :     // controlled access to Modify method
     127             :     // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier
     128     1871317 :     void ModifyNotification( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) { this->Modify ( pOldValue, pNewValue ); }
     129        4000 :     void SwClientNotifyCall( const SwModify& rModify, const SfxHint& rHint ) { SwClientNotify( rModify, rHint ); }
     130             : 
     131   485987282 :     const SwModify* GetRegisteredIn() const { return pRegisteredIn; }
     132     3937956 :     SwModify* GetRegisteredIn() { return pRegisteredIn; }
     133             : 
     134             :     // needed for class SwClientIter
     135             :     TYPEINFO();
     136             : 
     137             :     // get information about attribute
     138        2498 :     virtual bool GetInfo( SfxPoolItem& ) const { return true; }
     139             : };
     140             : 
     141             : 
     142             : // SwModify
     143             : 
     144             : // class has a doubly linked list for dependencies
     145             : class SW_DLLPUBLIC SwModify: public SwClient
     146             : {
     147             :     friend class sw::ClientIteratorBase;
     148             :     template<typename E, typename S> friend class SwIterator;
     149             :     sw::WriterListener* m_pWriterListeners;                // the start of the linked list of clients
     150             :     bool m_bModifyLocked : 1;         // don't broadcast changes now
     151             :     bool bLockClientList : 1;       // may be set when this instance notifies its clients
     152             :     bool m_bInDocDTOR : 1;            // workaround for problems when a lot of objects are destroyed
     153             :     bool m_bInCache   : 1;
     154             :     bool m_bInSwFntCache : 1;
     155             : 
     156             :     // mba: IMHO this method should be pure virtual
     157             :     // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
     158      102009 :     virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) SAL_OVERRIDE
     159      102009 :         { NotifyClients( pOld, pNew ); };
     160             : 
     161             : public:
     162      111960 :     SwModify()
     163      111960 :         : SwClient(nullptr), m_pWriterListeners(nullptr), m_bModifyLocked(false), bLockClientList(false), m_bInDocDTOR(false), m_bInCache(false), m_bInSwFntCache(false)
     164      111960 :     {}
     165      949170 :     explicit SwModify( SwModify* pToRegisterIn )
     166      949170 :         : SwClient(pToRegisterIn), m_pWriterListeners(nullptr), m_bModifyLocked(false), bLockClientList(false), m_bInDocDTOR(false), m_bInCache(false), m_bInSwFntCache(false)
     167      949170 :     {}
     168             : 
     169             :     // broadcasting: send notifications to all clients
     170             :     // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
     171             :     void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
     172             :     // the same, but without setting m_bModifyLocked or checking for any of the flags
     173             :     // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
     174      660090 :     void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue)
     175      660090 :         { CallSwClientNotify( sw::LegacyModifyHint{ pOldValue, pNewValue } ); };
     176             : 
     177             :     // a more universal broadcasting mechanism
     178             :     inline void CallSwClientNotify( const SfxHint& rHint ) const;
     179             : 
     180             :     virtual ~SwModify();
     181             : 
     182             :     void Add(SwClient *pDepend);
     183             :     SwClient* Remove(SwClient *pDepend);
     184     4632000 :     bool HasWriterListeners() const { return m_pWriterListeners; }
     185             : 
     186             :     // get information about attribute
     187             :     virtual bool GetInfo( SfxPoolItem& ) const SAL_OVERRIDE;
     188             : 
     189      685815 :     void LockModify()                   { m_bModifyLocked = true;  }
     190      685815 :     void UnlockModify()                 { m_bModifyLocked = false; }
     191      172356 :     void SetInCache( bool bNew )        { m_bInCache = bNew;       }
     192      487048 :     void SetInSwFntCache( bool bNew )   { m_bInSwFntCache = bNew;  }
     193       23760 :     void SetInDocDTOR()                 { m_bInDocDTOR = true; }
     194     4433169 :     bool IsModifyLocked() const     { return m_bModifyLocked;  }
     195      194539 :     bool IsInDocDTOR()    const     { return m_bInDocDTOR;     }
     196     7934648 :     bool IsInCache()      const     { return m_bInCache;       }
     197     7111740 :     bool IsInSwFntCache() const     { return m_bInSwFntCache;  }
     198             : 
     199             :     void CheckCaching( const sal_uInt16 nWhich );
     200        6782 :     bool HasOnlyOneListener() { return m_pWriterListeners && m_pWriterListeners->IsLast(); }
     201             : };
     202             : 
     203             : // SwDepend
     204             : 
     205             : /*
     206             :  * Helper class for objects that need to depend on more than one SwClient
     207             :  */
     208      233729 : class SW_DLLPUBLIC SwDepend SAL_FINAL : public SwClient
     209             : {
     210             :     SwClient *m_pToTell;
     211             : 
     212             : public:
     213             :     SwDepend() : m_pToTell(nullptr) {}
     214      233801 :     SwDepend(SwClient *pTellHim, SwModify *pDepend) : SwClient(pDepend), m_pToTell(pTellHim) {}
     215             : 
     216           0 :     SwClient* GetToTell() { return m_pToTell; }
     217             : 
     218             :     /** get Client information */
     219          12 :     virtual bool GetInfo( SfxPoolItem& rInfo) const SAL_OVERRIDE
     220          12 :         { return m_pToTell == nullptr || m_pToTell->GetInfo( rInfo ); }
     221             : protected:
     222         245 :     virtual void Modify( const SfxPoolItem* pOldValue, const SfxPoolItem *pNewValue ) SAL_OVERRIDE
     223             :     {
     224         245 :         if( pNewValue && pNewValue->Which() == RES_OBJECTDYING )
     225           0 :             CheckRegistration(pOldValue,pNewValue);
     226         245 :         else if( m_pToTell )
     227         245 :             m_pToTell->ModifyNotification(pOldValue, pNewValue);
     228         245 :     }
     229        4000 :     virtual void SwClientNotify( const SwModify& rModify, const SfxHint& rHint ) SAL_OVERRIDE
     230        4000 :         { if(m_pToTell) m_pToTell->SwClientNotifyCall(rModify, rHint); }
     231             : };
     232             : 
     233             : namespace sw
     234             : {
     235             :     class ClientIteratorBase : public sw::Ring< ::sw::ClientIteratorBase >
     236             :     {
     237             :             friend SwClient* SwModify::Remove(SwClient*);
     238             :             friend void SwModify::Add(SwClient*);
     239             :         protected:
     240             :             const SwModify& m_rRoot;
     241             :             // the current object in an iteration
     242             :             WriterListener* m_pCurrent;
     243             :             // in case the current object is already removed, the next object in the list
     244             :             // is marked down to become the current object in the next step
     245             :             // this is necessary because iteration requires access to members of the current object
     246             :             WriterListener* m_pPosition;
     247             :             static SW_DLLPUBLIC ClientIteratorBase* our_pClientIters;
     248             : 
     249     2539537 :             ClientIteratorBase( const SwModify& rModify )
     250     2539537 :                 : m_rRoot(rModify)
     251             :             {
     252     2539537 :                 MoveTo(our_pClientIters);
     253     2539537 :                 our_pClientIters = this;
     254     2539537 :                 m_pCurrent = m_pPosition = m_rRoot.m_pWriterListeners;
     255     2539537 :             }
     256           0 :             WriterListener* GetLeftOfPos() { return m_pPosition->m_pLeft; }
     257     3147122 :             WriterListener* GetRightOfPos() { return m_pPosition->m_pRight; }
     258     2538949 :             WriterListener* GoStart()
     259             :             {
     260     2538949 :                 if((m_pPosition = m_rRoot.m_pWriterListeners))
     261     4452868 :                     while( m_pPosition->m_pLeft )
     262           0 :                         m_pPosition = m_pPosition->m_pLeft;
     263     2538949 :                 return m_pCurrent = m_pPosition;
     264             :             }
     265     2539537 :             ~ClientIteratorBase() SAL_OVERRIDE
     266     5079074 :             {
     267             :                 assert(our_pClientIters);
     268     2539537 :                 if(our_pClientIters == this)
     269     2539537 :                     our_pClientIters = unique() ? nullptr : GetNextInRing();
     270     2539537 :                 MoveTo(nullptr);
     271     2539537 :             }
     272             :             // return "true" if an object was removed from a client chain in iteration
     273             :             // adding objects to a client chain in iteration is forbidden
     274             :             // SwModify::Add() asserts this
     275     3891626 :             bool IsChanged() const { return m_pPosition != m_pCurrent; }
     276             :             // ensures the iterator to point at a current client
     277     3662885 :             WriterListener* Sync() { return m_pCurrent = m_pPosition; }
     278             :     };
     279             : }
     280             : 
     281     1391900 : template< typename TElementType, typename TSource > class SwIterator SAL_FINAL : private sw::ClientIteratorBase
     282             : {
     283             :     static_assert(std::is_base_of<SwClient,TElementType>::value, "TElementType needs to be derived from SwClient");
     284             :     static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify");
     285             : public:
     286     1389504 :     SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
     287     1388916 :     TElementType* First()
     288             :     {
     289     1388916 :         GoStart();
     290     1388916 :         if(!m_pPosition)
     291      290387 :             return nullptr;
     292     1098529 :         m_pCurrent = nullptr;
     293     1098529 :         return Next();
     294             :     }
     295         612 :     TElementType* Last()
     296             :     {
     297         612 :         if(!m_pPosition)
     298         612 :             m_pPosition = m_rRoot.m_pWriterListeners;
     299         612 :         if(!m_pPosition)
     300         612 :             return static_cast<TElementType*>(Sync());
     301           0 :         while(GetRightOfPos())
     302           0 :             m_pPosition = GetRightOfPos();
     303           0 :         if(static_cast<SwClient*>(m_pPosition)->IsA(TYPE(TElementType)))
     304           0 :             return static_cast<TElementType*>(Sync());
     305           0 :         return Previous();
     306             :     }
     307     1420636 :     TElementType* Next()
     308             :     {
     309     1420636 :         if(!IsChanged())
     310      321074 :             m_pPosition = GetRightOfPos();
     311     3697978 :         while(m_pPosition && !static_cast<SwClient*>(m_pPosition)->IsA( TYPE(TElementType) ) )
     312      856706 :             m_pPosition = GetRightOfPos();
     313     1420636 :         return static_cast<TElementType*>(Sync());
     314             :     }
     315           0 :     TElementType* Previous()
     316             :     {
     317           0 :         m_pPosition = GetLeftOfPos();
     318           0 :         while(m_pPosition && !static_cast<SwClient*>(m_pPosition)->IsA( TYPE(TElementType) ) )
     319           0 :             m_pPosition = GetLeftOfPos();
     320           0 :         return static_cast<TElementType*>(Sync());
     321             :     }
     322             :     using sw::ClientIteratorBase::IsChanged;
     323             : };
     324             : 
     325     1150033 : template< typename TSource > class SwIterator<SwClient, TSource> SAL_FINAL : private sw::ClientIteratorBase
     326             : {
     327             :     static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify");
     328             : public:
     329     1150033 :     SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
     330     1150033 :     SwClient* First()
     331     1150033 :         { return static_cast<SwClient*>(GoStart()); }
     332             :     SwClient* Last()
     333             :     {
     334             :         if(!m_pPosition)
     335             :             m_pPosition = m_rRoot.m_pWriterListeners;
     336             :         if(!m_pPosition)
     337             :             return m_pCurrent = nullptr;
     338             :         while(GetRightOfPos())
     339             :             m_pPosition = GetRightOfPos();
     340             :         return static_cast<SwClient*>(Sync());
     341             :     }
     342     2241637 :     SwClient* Next()
     343             :     {
     344     2241637 :         if(!IsChanged())
     345     1969342 :             m_pPosition = GetRightOfPos();
     346     2241637 :         return static_cast<SwClient*>(Sync());
     347             :     }
     348             :     SwClient* Previous()
     349             :     {
     350             :         m_pPosition = GetLeftOfPos();
     351             :         return static_cast<SwClient*>(Sync());
     352             :     }
     353             :     using sw::ClientIteratorBase::IsChanged;
     354             : };
     355             : 
     356     7132687 : SwClient::SwClient( SwModify* pToRegisterIn )
     357     7132687 :     : pRegisteredIn( nullptr )
     358             : {
     359     7132687 :     if(pToRegisterIn)
     360      906442 :         pToRegisterIn->Add(this);
     361     7132687 : }
     362             : 
     363      698227 : void SwModify::CallSwClientNotify( const SfxHint& rHint ) const
     364             : {
     365      698227 :     SwIterator<SwClient,SwModify> aIter(*this);
     366     1997868 :     for(SwClient* pClient = aIter.First(); pClient; pClient = aIter.Next())
     367     1997868 :         pClient->SwClientNotify( *this, rHint );
     368      698227 : }
     369             : #endif
     370             : 
     371             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11