LCOV - code coverage report
Current view: top level - sc/source/core/tool - chartlis.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 230 377 61.0 %
Date: 2015-06-13 12:38:46 Functions: 54 73 74.0 %
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             : #include <vcl/svapp.hxx>
      21             : 
      22             : #include "chartlis.hxx"
      23             : #include "brdcst.hxx"
      24             : #include "document.hxx"
      25             : #include "reftokenhelper.hxx"
      26             : 
      27             : #include <boost/checked_delete.hpp>
      28             : 
      29             : using namespace com::sun::star;
      30             : using ::std::vector;
      31             : using ::std::list;
      32             : using ::std::unary_function;
      33             : using ::std::for_each;
      34             : 
      35             : // Update chart listeners quickly, to get a similar behavior to loaded charts
      36             : // which register UNO listeners.
      37             : 
      38           0 : class ScChartUnoData
      39             : {
      40             :     uno::Reference< chart::XChartDataChangeEventListener >  xListener;
      41             :     uno::Reference< chart::XChartData >                     xSource;
      42             : 
      43             : public:
      44           2 :             ScChartUnoData( const uno::Reference< chart::XChartDataChangeEventListener >& rL,
      45             :                             const uno::Reference< chart::XChartData >& rS ) :
      46           2 :                     xListener( rL ), xSource( rS ) {}
      47           2 :             ~ScChartUnoData() {}
      48             : 
      49           6 :     const uno::Reference< chart::XChartDataChangeEventListener >& GetListener() const   { return xListener; }
      50           8 :     const uno::Reference< chart::XChartData >& GetSource() const                        { return xSource; }
      51             : };
      52             : 
      53             : // ScChartListener
      54           0 : ScChartListener::ExternalRefListener::ExternalRefListener(ScChartListener& rParent, ScDocument* pDoc) :
      55           0 :     mrParent(rParent), mpDoc(pDoc)
      56             : {
      57           0 : }
      58             : 
      59           0 : ScChartListener::ExternalRefListener::~ExternalRefListener()
      60             : {
      61           0 :     if (!mpDoc || mpDoc->IsInDtorClear())
      62             :         // The document is being destroyed.  Do nothing.
      63           0 :         return;
      64             : 
      65             :     // Make sure to remove all pointers to this object.
      66           0 :     mpDoc->GetExternalRefManager()->removeLinkListener(this);
      67           0 : }
      68             : 
      69           0 : void ScChartListener::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
      70             : {
      71           0 :     switch (eType)
      72             :     {
      73             :         case ScExternalRefManager::LINK_MODIFIED:
      74             :         {
      75           0 :             if (maFileIds.count(nFileId))
      76             :                 // We are listening to this external document.  Send an update
      77             :                 // requst to the chart.
      78           0 :                 mrParent.SetUpdateQueue();
      79             :         }
      80           0 :         break;
      81             :         case ScExternalRefManager::LINK_BROKEN:
      82           0 :             removeFileId(nFileId);
      83           0 :         break;
      84             :     }
      85           0 : }
      86             : 
      87           0 : void ScChartListener::ExternalRefListener::addFileId(sal_uInt16 nFileId)
      88             : {
      89           0 :     maFileIds.insert(nFileId);
      90           0 : }
      91             : 
      92           0 : void ScChartListener::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
      93             : {
      94           0 :     maFileIds.erase(nFileId);
      95           0 : }
      96             : 
      97           9 : ScChartListener::ScChartListener( const OUString& rName, ScDocument* pDocP,
      98             :         const ScRangeListRef& rRangeList ) :
      99             :     SvtListener(),
     100             :     mpExtRefListener(NULL),
     101           9 :     mpTokens(new vector<ScTokenRef>),
     102             :     maName(rName),
     103             :     pUnoData( NULL ),
     104             :     mpDoc( pDocP ),
     105             :     bUsed( false ),
     106             :     bDirty( false ),
     107          18 :     bSeriesRangesScheduled( false )
     108             : {
     109           9 :     ScRefTokenHelper::getTokensFromRangeList(*mpTokens, *rRangeList);
     110           9 : }
     111             : 
     112          76 : ScChartListener::ScChartListener( const OUString& rName, ScDocument* pDocP, vector<ScTokenRef>* pTokens ) :
     113             :     SvtListener(),
     114             :     mpExtRefListener(NULL),
     115             :     mpTokens(pTokens),
     116             :     maName(rName),
     117             :     pUnoData( NULL ),
     118             :     mpDoc( pDocP ),
     119             :     bUsed( false ),
     120             :     bDirty( false ),
     121          76 :     bSeriesRangesScheduled( false )
     122             : {
     123          76 : }
     124             : 
     125         228 : ScChartListener::ScChartListener( const ScChartListener& r ) :
     126             :     SvtListener(),
     127             :     mpExtRefListener(NULL),
     128         456 :     mpTokens(new vector<ScTokenRef>(*r.mpTokens)),
     129             :     maName(r.maName),
     130             :     pUnoData( NULL ),
     131             :     mpDoc( r.mpDoc ),
     132             :     bUsed( false ),
     133             :     bDirty( r.bDirty ),
     134         684 :     bSeriesRangesScheduled( r.bSeriesRangesScheduled )
     135             : {
     136         228 :     if ( r.pUnoData )
     137           0 :         pUnoData = new ScChartUnoData( *r.pUnoData );
     138             : 
     139         228 :     if (r.mpExtRefListener.get())
     140             :     {
     141             :         // Re-register this new listener for the files that the old listener
     142             :         // was listening to.
     143             : 
     144           0 :         ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
     145           0 :         const std::unordered_set<sal_uInt16>& rFileIds = r.mpExtRefListener->getAllFileIds();
     146           0 :         mpExtRefListener.reset(new ExternalRefListener(*this, mpDoc));
     147           0 :         std::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
     148           0 :         for (; itr != itrEnd; ++itr)
     149             :         {
     150           0 :             pRefMgr->addLinkListener(*itr, mpExtRefListener.get());
     151           0 :             mpExtRefListener->addFileId(*itr);
     152             :         }
     153             :     }
     154         228 : }
     155             : 
     156         939 : ScChartListener::~ScChartListener()
     157             : {
     158         313 :     if ( HasBroadcaster() )
     159          90 :         EndListeningTo();
     160         313 :     delete pUnoData;
     161             : 
     162         313 :     if (mpExtRefListener.get())
     163             :     {
     164             :         // Stop listening to all external files.
     165           0 :         ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
     166           0 :         const std::unordered_set<sal_uInt16>& rFileIds = mpExtRefListener->getAllFileIds();
     167           0 :         std::unordered_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
     168           0 :         for (; itr != itrEnd; ++itr)
     169           0 :             pRefMgr->removeLinkListener(*itr, mpExtRefListener.get());
     170             :     }
     171         626 : }
     172             : 
     173           2 : void ScChartListener::SetUno(
     174             :         const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
     175             :         const uno::Reference< chart::XChartData >& rSource )
     176             : {
     177           2 :     delete pUnoData;
     178           2 :     pUnoData = new ScChartUnoData( rListener, rSource );
     179           2 : }
     180             : 
     181           3 : uno::Reference< chart::XChartDataChangeEventListener > ScChartListener::GetUnoListener() const
     182             : {
     183           3 :     if ( pUnoData )
     184           3 :         return pUnoData->GetListener();
     185           0 :     return uno::Reference< chart::XChartDataChangeEventListener >();
     186             : }
     187             : 
     188           5 : uno::Reference< chart::XChartData > ScChartListener::GetUnoSource() const
     189             : {
     190           5 :     if ( pUnoData )
     191           5 :         return pUnoData->GetSource();
     192           0 :     return uno::Reference< chart::XChartData >();
     193             : }
     194             : 
     195          72 : void ScChartListener::Notify( const SfxHint& rHint )
     196             : {
     197          72 :     const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
     198          72 :     if (p && (p->GetId() & SC_HINT_DATACHANGED))
     199          72 :         SetUpdateQueue();
     200          72 : }
     201             : 
     202          33 : void ScChartListener::Update()
     203             : {
     204          33 :     if ( mpDoc->IsInInterpreter() )
     205             :     {   // If interpreting do nothing and restart timer so we don't
     206             :         // interfere with interpreter and don't produce an Err522 or similar.
     207             :         // This may happen if we are rescheduled via Basic function.
     208           0 :         mpDoc->GetChartListenerCollection()->StartTimer();
     209          33 :         return ;
     210             :     }
     211          33 :     if ( pUnoData )
     212             :     {
     213           3 :         bDirty = false;
     214             :         // recognize some day what has changed inside the Chart
     215           3 :         chart::ChartDataChangeEvent aEvent( pUnoData->GetSource(),
     216             :                                         chart::ChartDataChangeType_ALL,
     217           6 :                                         0, 0, 0, 0 );
     218           3 :         pUnoData->GetListener()->chartDataChanged( aEvent );
     219             :     }
     220          30 :     else if ( mpDoc->GetAutoCalc() )
     221             :     {
     222          30 :         bDirty = false;
     223          30 :         mpDoc->UpdateChart(GetName());
     224             :     }
     225             : }
     226             : 
     227          50 : ScRangeListRef ScChartListener::GetRangeList() const
     228             : {
     229          50 :     ScRangeListRef aRLRef(new ScRangeList);
     230          50 :     ScRefTokenHelper::getRangeListFromTokens(*aRLRef, *mpTokens, ScAddress());
     231          50 :     return aRLRef;
     232             : }
     233             : 
     234          40 : void ScChartListener::SetRangeList( const ScRangeListRef& rNew )
     235             : {
     236          40 :     vector<ScTokenRef> aTokens;
     237          40 :     ScRefTokenHelper::getTokensFromRangeList(aTokens, *rNew);
     238          40 :     mpTokens->swap(aTokens);
     239          40 : }
     240             : 
     241             : namespace {
     242             : 
     243             : class StartEndListening : public unary_function<ScTokenRef, void>
     244             : {
     245             : public:
     246         221 :     StartEndListening(ScDocument* pDoc, ScChartListener& rParent, bool bStart) :
     247         221 :         mpDoc(pDoc), mrParent(rParent), mbStart(bStart) {}
     248             : 
     249         434 :     void operator() (const ScTokenRef& pToken)
     250             :     {
     251         434 :         if (!ScRefTokenHelper::isRef(pToken))
     252         434 :             return;
     253             : 
     254         434 :         bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
     255         434 :         if (bExternal)
     256             :         {
     257           0 :             sal_uInt16 nFileId = pToken->GetIndex();
     258           0 :             ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
     259           0 :             ScChartListener::ExternalRefListener* pExtRefListener = mrParent.GetExtRefListener();
     260           0 :             if (mbStart)
     261             :             {
     262           0 :                 pRefMgr->addLinkListener(nFileId, pExtRefListener);
     263           0 :                 pExtRefListener->addFileId(nFileId);
     264             :             }
     265             :             else
     266             :             {
     267           0 :                 pRefMgr->removeLinkListener(nFileId, pExtRefListener);
     268           0 :                 pExtRefListener->removeFileId(nFileId);
     269             :             }
     270             :         }
     271             :         else
     272             :         {
     273         434 :             ScRange aRange;
     274         434 :             ScRefTokenHelper::getRangeFromToken(aRange, pToken, ScAddress(), bExternal);
     275         434 :             if (mbStart)
     276         172 :                 startListening(aRange);
     277             :             else
     278         262 :                 endListening(aRange);
     279             :         }
     280             :     }
     281             : private:
     282         172 :     void startListening(const ScRange& rRange)
     283             :     {
     284         172 :         if (rRange.aStart == rRange.aEnd)
     285          42 :             mpDoc->StartListeningCell(rRange.aStart, &mrParent);
     286             :         else
     287         130 :             mpDoc->StartListeningArea(rRange, false, &mrParent);
     288         172 :     }
     289             : 
     290         262 :     void endListening(const ScRange& rRange)
     291             :     {
     292         262 :         if (rRange.aStart == rRange.aEnd)
     293          76 :             mpDoc->EndListeningCell(rRange.aStart, &mrParent);
     294             :         else
     295         186 :             mpDoc->EndListeningArea(rRange, false, &mrParent);
     296         262 :     }
     297             : private:
     298             :     ScDocument* mpDoc;
     299             :     ScChartListener& mrParent;
     300             :     bool mbStart;
     301             : };
     302             : 
     303             : }
     304             : 
     305         125 : void ScChartListener::StartListeningTo()
     306             : {
     307         125 :     if (!mpTokens.get() || mpTokens->empty())
     308             :         // no references to listen to.
     309         155 :         return;
     310             : 
     311          95 :     for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(mpDoc, *this, true));
     312             : }
     313             : 
     314         130 : void ScChartListener::EndListeningTo()
     315             : {
     316         130 :     if (!mpTokens.get() || mpTokens->empty())
     317             :         // no references to listen to.
     318         134 :         return;
     319             : 
     320         126 :     for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(mpDoc, *this, false));
     321             : }
     322             : 
     323           0 : void ScChartListener::ChangeListening( const ScRangeListRef& rRangeListRef,
     324             :                                        bool bDirtyP )
     325             : {
     326           0 :     EndListeningTo();
     327           0 :     SetRangeList( rRangeListRef );
     328           0 :     StartListeningTo();
     329           0 :     if ( bDirtyP )
     330           0 :         SetDirty( true );
     331           0 : }
     332             : 
     333           0 : void ScChartListener::UpdateScheduledSeriesRanges()
     334             : {
     335           0 :     if ( bSeriesRangesScheduled )
     336             :     {
     337           0 :         bSeriesRangesScheduled = false;
     338           0 :         UpdateSeriesRanges();
     339             :     }
     340           0 : }
     341             : 
     342           0 : void ScChartListener::UpdateChartIntersecting( const ScRange& rRange )
     343             : {
     344           0 :     ScTokenRef pToken;
     345           0 :     ScRefTokenHelper::getTokenFromRange(pToken, rRange);
     346             : 
     347           0 :     if (ScRefTokenHelper::intersects(*mpTokens, pToken, ScAddress()))
     348             :     {
     349             :         // force update (chart has to be loaded), don't use ScChartListener::Update
     350           0 :         mpDoc->UpdateChart(GetName());
     351           0 :     }
     352           0 : }
     353             : 
     354           0 : void ScChartListener::UpdateSeriesRanges()
     355             : {
     356           0 :     ScRangeListRef pRangeList(new ScRangeList);
     357           0 :     ScRefTokenHelper::getRangeListFromTokens(*pRangeList, *mpTokens, ScAddress());
     358           0 :     mpDoc->SetChartRangeList(GetName(), pRangeList);
     359           0 : }
     360             : 
     361           0 : ScChartListener::ExternalRefListener* ScChartListener::GetExtRefListener()
     362             : {
     363           0 :     if (!mpExtRefListener.get())
     364           0 :         mpExtRefListener.reset(new ExternalRefListener(*this, mpDoc));
     365             : 
     366           0 :     return mpExtRefListener.get();
     367             : }
     368             : 
     369          72 : void ScChartListener::SetUpdateQueue()
     370             : {
     371          72 :     bDirty = true;
     372          72 :     mpDoc->GetChartListenerCollection()->StartTimer();
     373          72 : }
     374             : 
     375           0 : bool ScChartListener::operator==( const ScChartListener& r ) const
     376             : {
     377           0 :     bool b1 = (mpTokens.get() && !mpTokens->empty());
     378           0 :     bool b2 = (r.mpTokens.get() && !r.mpTokens->empty());
     379             : 
     380           0 :     if (mpDoc != r.mpDoc || bUsed != r.bUsed || bDirty != r.bDirty ||
     381           0 :         bSeriesRangesScheduled != r.bSeriesRangesScheduled ||
     382           0 :         GetName() != r.GetName() || b1 != b2)
     383           0 :         return false;
     384             : 
     385           0 :     if (!b1 && !b2)
     386             :         // both token list instances are empty.
     387           0 :         return true;
     388             : 
     389           0 :     return *mpTokens == *r.mpTokens;
     390             : }
     391             : 
     392           0 : bool ScChartListener::operator!=( const ScChartListener& r ) const
     393             : {
     394           0 :     return !operator==(r);
     395             : }
     396             : 
     397        4111 : ScChartHiddenRangeListener::ScChartHiddenRangeListener()
     398             : {
     399        4111 : }
     400             : 
     401        4111 : ScChartHiddenRangeListener::~ScChartHiddenRangeListener()
     402             : {
     403             :     // empty d'tor
     404        4111 : }
     405             : 
     406             : // ScChartListenerCollection
     407        4109 : ScChartListenerCollection::RangeListenerItem::RangeListenerItem(const ScRange& rRange, ScChartHiddenRangeListener* p) :
     408        4109 :     maRange(rRange), mpListener(p)
     409             : {
     410        4109 : }
     411             : 
     412        1325 : ScChartListenerCollection::ScChartListenerCollection( ScDocument* pDocP ) :
     413             :     meModifiedDuringUpdate( SC_CLCUPDATE_NONE ),
     414        1325 :     pDoc( pDocP )
     415             : {
     416        1325 :     aIdle.SetIdleHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
     417        1325 : }
     418             : 
     419          66 : ScChartListenerCollection::ScChartListenerCollection(
     420             :         const ScChartListenerCollection& rColl ) :
     421             :     meModifiedDuringUpdate( SC_CLCUPDATE_NONE ),
     422          66 :     pDoc( rColl.pDoc )
     423             : {
     424          66 :     aIdle.SetIdleHdl( LINK( this, ScChartListenerCollection, TimerHdl ) );
     425          66 : }
     426             : 
     427        2720 : ScChartListenerCollection::~ScChartListenerCollection()
     428             : {
     429             :     //  remove ChartListener objects before aIdle dtor is called, because
     430             :     //  ScChartListener::EndListeningTo may cause ScChartListenerCollection::StartTimer
     431             :     //  to be called if an empty ScNoteCell is deleted
     432             : 
     433        1360 :     maListeners.clear();
     434        1360 : }
     435             : 
     436           0 : void ScChartListenerCollection::StartAllListeners()
     437             : {
     438           0 :     ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     439           0 :     for (; it != itEnd; ++it)
     440           0 :         it->second->StartListeningTo();
     441           0 : }
     442             : 
     443          85 : void ScChartListenerCollection::insert(ScChartListener* pListener)
     444             : {
     445          85 :     if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
     446           0 :         meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;
     447          85 :     OUString aName = pListener->GetName();
     448          85 :     maListeners.insert(aName, pListener);
     449          85 : }
     450             : 
     451           1 : void ScChartListenerCollection::removeByName(const OUString& rName)
     452             : {
     453           1 :     if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
     454           0 :         meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;
     455           1 :     maListeners.erase(rName);
     456           1 : }
     457             : 
     458         234 : ScChartListener* ScChartListenerCollection::findByName(const OUString& rName)
     459             : {
     460         234 :     ListenersType::iterator it = maListeners.find(rName);
     461         234 :     return it == maListeners.end() ? NULL : it->second;
     462             : }
     463             : 
     464           0 : const ScChartListener* ScChartListenerCollection::findByName(const OUString& rName) const
     465             : {
     466           0 :     ListenersType::const_iterator it = maListeners.find(rName);
     467           0 :     return it == maListeners.end() ? NULL : it->second;
     468             : }
     469             : 
     470           4 : bool ScChartListenerCollection::hasListeners() const
     471             : {
     472           4 :     return !maListeners.empty();
     473             : }
     474             : 
     475           2 : OUString ScChartListenerCollection::getUniqueName(const OUString& rPrefix) const
     476             : {
     477           3 :     for (sal_Int32 nNum = 1; nNum < 10000; ++nNum) // arbitrary limit to prevent infinite loop.
     478             :     {
     479           3 :         OUStringBuffer aBuf(rPrefix);
     480           3 :         aBuf.append(nNum);
     481           4 :         OUString aTestName = aBuf.makeStringAndClear();
     482           3 :         if (maListeners.find(aTestName) == maListeners.end())
     483           2 :             return aTestName;
     484           1 :     }
     485           0 :     return OUString();
     486             : }
     487             : 
     488          40 : void ScChartListenerCollection::ChangeListening( const OUString& rName,
     489             :         const ScRangeListRef& rRangeListRef, bool bDirty )
     490             : {
     491          40 :     ScChartListener* pCL = findByName(rName);
     492          40 :     if (pCL)
     493             :     {
     494          40 :         pCL->EndListeningTo();
     495          40 :         pCL->SetRangeList( rRangeListRef );
     496             :     }
     497             :     else
     498             :     {
     499           0 :         pCL = new ScChartListener(rName, pDoc, rRangeListRef);
     500           0 :         insert(pCL);
     501             :     }
     502          40 :     pCL->StartListeningTo();
     503          40 :     if ( bDirty )
     504           0 :         pCL->SetDirty( true );
     505          40 : }
     506             : 
     507             : namespace {
     508             : 
     509             : class InsertChartListener : public std::unary_function<ScChartListener*, void>
     510             : {
     511             :     ScChartListenerCollection::ListenersType& mrListeners;
     512             : public:
     513           2 :     InsertChartListener(ScChartListenerCollection::ListenersType& rListeners) :
     514           2 :         mrListeners(rListeners) {}
     515             : 
     516           1 :     void operator() (ScChartListener* p)
     517             :     {
     518           1 :         OUString aName = p->GetName();
     519           1 :         mrListeners.insert(aName, p);
     520           1 :     }
     521             : };
     522             : 
     523             : }
     524             : 
     525         658 : void ScChartListenerCollection::FreeUnused()
     526             : {
     527         658 :     if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
     528           0 :         meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;
     529             : 
     530        1316 :     ListenersType aUsed, aUnused;
     531             : 
     532             :     // First, filter each listener into 'used' and 'unused' categories.
     533             :     {
     534        1430 :         while(!maListeners.empty())
     535             :         {
     536         114 :             ScChartListener* p = maListeners.begin()->second;
     537         114 :             if (p->IsUno())
     538             :             {
     539             :                 // We don't delete UNO charts; they are to be deleted separately via FreeUno().
     540           0 :                 aUsed.transfer(maListeners.begin(), maListeners);
     541           0 :                 continue;
     542             :             }
     543             : 
     544         114 :             if (p->IsUsed())
     545             :             {
     546         114 :                 p->SetUsed(false);
     547         114 :                 aUsed.transfer(maListeners.begin(), maListeners);
     548             :             }
     549             :             else
     550           0 :                 aUnused.transfer(maListeners.begin(), maListeners);
     551             : 
     552             :         }
     553             :     }
     554             : 
     555        1316 :     std::swap(aUsed, maListeners);
     556         658 : }
     557             : 
     558           2 : void ScChartListenerCollection::FreeUno( const uno::Reference< chart::XChartDataChangeEventListener >& rListener,
     559             :                                          const uno::Reference< chart::XChartData >& rSource )
     560             : {
     561           2 :     if (meModifiedDuringUpdate == SC_CLCUPDATE_RUNNING)
     562           0 :         meModifiedDuringUpdate =  SC_CLCUPDATE_MODIFIED;
     563             : 
     564           4 :     std::vector<ScChartListener*> aUsed, aUnused;
     565             : 
     566             :     // First, filter each listener into 'used' and 'unused' categories.
     567             :     {
     568           2 :         ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     569           5 :         for (; it != itEnd; ++it)
     570             :         {
     571           3 :             ScChartListener* p = it->second;
     572           3 :             if (p->IsUno() && p->GetUnoListener() == rListener && p->GetUnoSource() == rSource)
     573           2 :                 aUnused.push_back(p);
     574             :             else
     575           1 :                 aUsed.push_back(p);
     576             :         }
     577             :     }
     578             : 
     579             :     // Release all pointers currently managed by the ptr_map container.
     580             :     // coverity[leaked_storage] - no leak, because because we will take care of them below
     581           2 :     maListeners.release().release();
     582             : 
     583             :     // Re-insert the listeners we need to keep.
     584           2 :     std::for_each(aUsed.begin(), aUsed.end(), InsertChartListener(maListeners));
     585             : 
     586             :     // Now, delete the ones no longer needed.
     587           4 :     std::for_each(aUnused.begin(), aUnused.end(), boost::checked_deleter<ScChartListener>());
     588           2 : }
     589             : 
     590         669 : void ScChartListenerCollection::StartTimer()
     591             : {
     592         669 :     aIdle.SetPriority( SchedulerPriority::REPAINT );
     593         669 :     aIdle.Start();
     594         669 : }
     595             : 
     596         264 : IMPL_LINK_NOARG_TYPED(ScChartListenerCollection, TimerHdl, Idle *, void)
     597             : {
     598         132 :     if ( Application::AnyInput( VclInputFlags::KEYBOARD ) )
     599             :     {
     600           0 :         aIdle.Start();
     601         132 :         return;
     602             :     }
     603         132 :     UpdateDirtyCharts();
     604             : }
     605             : 
     606         528 : void ScChartListenerCollection::UpdateDirtyCharts()
     607             : {
     608             :     // During ScChartListener::Update() the most nasty things can happen due to
     609             :     // UNO listeners, e.g. reentrant calls via BASIC to insert() and FreeUno()
     610             :     // and similar that modify maListeners and invalidate iterators.
     611         528 :     meModifiedDuringUpdate = SC_CLCUPDATE_RUNNING;
     612             : 
     613         528 :     ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     614         565 :     for (; it != itEnd; ++it)
     615             :     {
     616          37 :         ScChartListener* p = it->second;
     617          37 :         if (p->IsDirty())
     618          30 :             p->Update();
     619             : 
     620          37 :         if (meModifiedDuringUpdate == SC_CLCUPDATE_MODIFIED)
     621           0 :             break;      // iterator is invalid
     622             : 
     623          37 :         if (aIdle.IsActive() && !pDoc->IsImportingXML())
     624           0 :             break;                      // one interfered
     625             :     }
     626         528 :     meModifiedDuringUpdate = SC_CLCUPDATE_NONE;
     627         528 : }
     628             : 
     629         597 : void ScChartListenerCollection::SetDirty()
     630             : {
     631         597 :     ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     632         597 :     for (; it != itEnd; ++it)
     633           0 :         it->second->SetDirty(true);
     634             : 
     635         597 :     StartTimer();
     636         597 : }
     637             : 
     638           0 : void ScChartListenerCollection::SetDiffDirty(
     639             :             const ScChartListenerCollection& rCmp, bool bSetChartRangeLists )
     640             : {
     641           0 :     bool bDirty = false;
     642           0 :     ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     643           0 :     for (; it != itEnd; ++it)
     644             :     {
     645           0 :         ScChartListener* pCL = it->second;
     646             :         OSL_ASSERT(pCL);
     647           0 :         const ScChartListener* pCLCmp = rCmp.findByName(pCL->GetName());
     648           0 :         if (!pCLCmp || *pCL != *pCLCmp)
     649             :         {
     650           0 :             if ( bSetChartRangeLists )
     651             :             {
     652           0 :                 if (pCLCmp)
     653             :                 {
     654           0 :                     const ScRangeListRef& rList1 = pCL->GetRangeList();
     655           0 :                     const ScRangeListRef& rList2 = pCLCmp->GetRangeList();
     656           0 :                     bool b1 = rList1.Is();
     657           0 :                     bool b2 = rList2.Is();
     658           0 :                     if ( b1 != b2 || (b1 && b2 && (*rList1 != *rList2)) )
     659           0 :                         pDoc->SetChartRangeList( pCL->GetName(), rList1 );
     660             :                 }
     661             :                 else
     662           0 :                     pDoc->SetChartRangeList( pCL->GetName(), pCL->GetRangeList() );
     663             :             }
     664           0 :             bDirty = true;
     665           0 :             pCL->SetDirty( true );
     666             :         }
     667             :     }
     668           0 :     if ( bDirty )
     669           0 :         StartTimer();
     670           0 : }
     671             : 
     672         275 : void ScChartListenerCollection::SetRangeDirty( const ScRange& rRange )
     673             : {
     674         275 :     bool bDirty = false;
     675         275 :     ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     676         275 :     for (; it != itEnd; ++it)
     677             :     {
     678           0 :         ScChartListener* pCL = it->second;
     679           0 :         const ScRangeListRef& rList = pCL->GetRangeList();
     680           0 :         if ( rList.Is() && rList->Intersects( rRange ) )
     681             :         {
     682           0 :             bDirty = true;
     683           0 :             pCL->SetDirty( true );
     684             :         }
     685           0 :     }
     686         275 :     if ( bDirty )
     687           0 :         StartTimer();
     688             : 
     689             :     // New hidden range listener implementation
     690         275 :     for (list<RangeListenerItem>::iterator itr = maHiddenListeners.begin(), itrEnd = maHiddenListeners.end();
     691             :           itr != itrEnd; ++itr)
     692             :     {
     693           0 :         if (itr->maRange.Intersects(rRange))
     694           0 :             itr->mpListener->notify();
     695             :     }
     696         275 : }
     697             : 
     698         178 : void ScChartListenerCollection::UpdateScheduledSeriesRanges()
     699             : {
     700         178 :     ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     701         178 :     for (; it != itEnd; ++it)
     702           0 :         it->second->UpdateScheduledSeriesRanges();
     703         178 : }
     704             : 
     705         251 : void ScChartListenerCollection::UpdateChartsContainingTab( SCTAB nTab )
     706             : {
     707         251 :     ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
     708         251 :     ListenersType::iterator it = maListeners.begin(), itEnd = maListeners.end();
     709         251 :     for (; it != itEnd; ++it)
     710           0 :         it->second->UpdateChartIntersecting(aRange);
     711         251 : }
     712             : 
     713          66 : bool ScChartListenerCollection::operator==( const ScChartListenerCollection& r ) const
     714             : {
     715             :     // Do not use ScStrCollection::operator==() here that uses IsEqual und Compare.
     716             :     // Use ScChartListener::operator==() instead.
     717          66 :     if (pDoc != r.pDoc || maListeners.size() != r.maListeners.size())
     718           0 :         return false;
     719             : 
     720          66 :     ListenersType::const_iterator it = maListeners.begin(), itEnd = maListeners.end();
     721          66 :     ListenersType::const_iterator it2 = r.maListeners.begin();
     722          66 :     for (; it != itEnd; ++it, ++it2)
     723             :     {
     724           0 :         if (*it != *it2)
     725           0 :             return false;
     726             :     }
     727          66 :     return true;
     728             : }
     729             : 
     730           0 : bool ScChartListenerCollection::operator!=( const ScChartListenerCollection& r ) const
     731             : {
     732           0 :     return !operator==(r);
     733             : }
     734             : 
     735        4109 : void ScChartListenerCollection::StartListeningHiddenRange( const ScRange& rRange, ScChartHiddenRangeListener* pListener )
     736             : {
     737        4109 :     RangeListenerItem aItem(rRange, pListener);
     738        4109 :     maHiddenListeners.push_back(aItem);
     739        4109 : }
     740             : 
     741             : namespace {
     742             : 
     743             : struct MatchListener : public ::std::unary_function<
     744             :         ScChartListenerCollection::RangeListenerItem, bool>
     745             : {
     746        7040 :     MatchListener(const ScChartHiddenRangeListener* pMatch) :
     747        7040 :         mpMatch(pMatch)
     748             :     {
     749        7040 :     }
     750             : 
     751      210805 :     bool operator() (const ScChartListenerCollection::RangeListenerItem& rItem) const
     752             :     {
     753      210805 :         return mpMatch == rItem.mpListener;
     754             :     }
     755             : 
     756             : private:
     757             :     const ScChartHiddenRangeListener* mpMatch;
     758             : };
     759             : 
     760             : }
     761        7040 : void ScChartListenerCollection::EndListeningHiddenRange( ScChartHiddenRangeListener* pListener )
     762             : {
     763        7040 :     maHiddenListeners.remove_if(MatchListener(pListener));
     764        7196 : }
     765             : 
     766             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11