LCOV - code coverage report
Current view: top level - sc/source/core/data - bcaslot.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 408 505 80.8 %
Date: 2014-11-03 Functions: 36 40 90.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 <sfx2/objsh.hxx>
      21             : #include <svl/listener.hxx>
      22             : 
      23             : #include "document.hxx"
      24             : #include "brdcst.hxx"
      25             : #include "bcaslot.hxx"
      26             : #include "scerrors.hxx"
      27             : #include "docoptio.hxx"
      28             : #include "refupdat.hxx"
      29             : #include "table.hxx"
      30             : 
      31             : // Number of slots per dimension
      32             : // must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
      33             : #define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
      34             : #if MAXROWCOUNT_DEFINE == 32000
      35             : #define BCA_SLOTS_ROW 256
      36             : #define BCA_SLICE 125
      37             : #else
      38             : #define BCA_SLICE 128
      39             : #define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / BCA_SLICE)
      40             : #endif
      41             : #define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
      42             : #define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
      43             : // multiple?
      44             : #if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
      45             : #error bad BCA_SLOTS_COL value!
      46             : #endif
      47             : #if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
      48             : #error bad BCA_SLOTS_ROW value!
      49             : #endif
      50             : // size of slot array if linear
      51             : #define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
      52             : // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
      53             : // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
      54             : // anyway, once you reached these values..
      55             : #if BCA_SLOTS_DEFINE > 268435456
      56             : #error BCA_SLOTS_DEFINE DOOMed!
      57             : #endif
      58             : 
      59             : // STATIC DATA -----------------------------------------------------------
      60             : 
      61             : struct ScSlotData
      62             : {
      63             :     SCROW  nStartRow;   // first row of this segment
      64             :     SCROW  nStopRow;    // first row of next segment
      65             :     SCSIZE nSlice;      // slice size in this segment
      66             :     SCSIZE nCumulated;  // cumulated slots of previous segments
      67             : 
      68         456 :     ScSlotData( SCROW r1, SCROW r2, SCSIZE s, SCSIZE c ) : nStartRow(r1), nStopRow(r2), nSlice(s), nCumulated(c) {}
      69             : };
      70             : typedef ::std::vector< ScSlotData > ScSlotDistribution;
      71             : #if MAXROWCOUNT_DEFINE <= 65536
      72             : // Linear distribution.
      73             : static ScSlotDistribution aSlotDistribution( ScSlotData( 0, MAXROWCOUNT, BCA_SLOT_ROWS, 0));
      74             : static SCSIZE nBcaSlotsRow = BCA_SLOTS_ROW;
      75             : static SCSIZE nBcaSlots = BCA_SLOTS_DEFINE;
      76             : #else
      77             : // Logarithmic or any other distribution.
      78             : // Upper sheet part usually is more populated and referenced and gets fine
      79             : // grained resolution, larger data in larger hunks.
      80             : // Could be further enhanced by also applying a different distribution of
      81             : // column slots.
      82          76 : static SCSIZE initSlotDistribution( ScSlotDistribution & rSD, SCSIZE & rBSR )
      83             : {
      84          76 :     SCSIZE nSlots = 0;
      85          76 :     SCROW nRow1 = 0;
      86          76 :     SCROW nRow2 = 32*1024;
      87          76 :     SCSIZE nSlice = 128;
      88             :     // Must be sorted by row1,row2!
      89         608 :     while (nRow2 <= MAXROWCOUNT)
      90             :     {
      91         456 :         rSD.push_back( ScSlotData( nRow1, nRow2, nSlice, nSlots));
      92         456 :         nSlots += (nRow2 - nRow1) / nSlice;
      93         456 :         nRow1 = nRow2;
      94         456 :         nRow2 *= 2;
      95         456 :         nSlice *= 2;
      96             :     }
      97          76 :     rBSR = nSlots;
      98          76 :     return nSlots;
      99             : }
     100          76 : static ScSlotDistribution aSlotDistribution;
     101             : static SCSIZE nBcaSlotsRow;
     102          76 : static SCSIZE nBcaSlots = initSlotDistribution( aSlotDistribution, nBcaSlotsRow) * BCA_SLOTS_COL;
     103             : // Ensure that all static variables are initialized with this one call.
     104             : #endif
     105             : 
     106        2342 : ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
     107             :         ScBroadcastAreaSlotMachine* pBASMa ) :
     108             :     aTmpSeekBroadcastArea( ScRange()),
     109             :     pDoc( pDocument ),
     110             :     pBASM( pBASMa ),
     111        2342 :     mbInBroadcastIteration( false)
     112             : {
     113        2342 : }
     114             : 
     115        4684 : ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
     116             : {
     117       19318 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     118       16976 :             aIter != aBroadcastAreaTbl.end(); /* none */)
     119             :     {
     120             :         // Prevent hash from accessing dangling pointer in case area is
     121             :         // deleted.
     122        6146 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     123             :         // Erase all so no hash will be accessed upon destruction of the
     124             :         // boost::unordered_map.
     125        6146 :         aBroadcastAreaTbl.erase( aIter++);
     126        6146 :         if (!pArea->DecRef())
     127        4262 :             delete pArea;
     128             :     }
     129        2342 : }
     130             : 
     131       21598 : bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
     132             : {
     133       21598 :     if ( pDoc->GetHardRecalcState() )
     134           0 :         return true;
     135       21598 :     if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
     136             :     {   // this is more hypothetical now, check existed for old SV_PTRARR_SORT
     137           0 :         if ( !pDoc->GetHardRecalcState() )
     138             :         {
     139           0 :             SfxObjectShell* pShell = pDoc->GetDocumentShell();
     140             :             OSL_ENSURE( pShell, "Missing DocShell :-/" );
     141             : 
     142           0 :             if ( pShell )
     143           0 :                 pShell->SetError( SCWARN_CORE_HARD_RECALC, OUString( OSL_LOG_PREFIX ) );
     144             : 
     145           0 :             pDoc->SetAutoCalc( false );
     146           0 :             pDoc->SetHardRecalcState( true );
     147             :         }
     148           0 :         return true;
     149             :     }
     150       21598 :     return false;
     151             : }
     152             : 
     153       19714 : bool ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
     154             :         SvtListener* pListener, ScBroadcastArea*& rpArea )
     155             : {
     156       19714 :     bool bNewArea = false;
     157             :     OSL_ENSURE(pListener, "StartListeningArea: pListener Null");
     158       19714 :     if (CheckHardRecalcStateCondition())
     159           0 :         return false;
     160       19714 :     if ( !rpArea )
     161             :     {
     162             :         // Even if most times the area doesn't exist yet and immediately trying
     163             :         // to new and insert it would save an attempt to find it, on mass
     164             :         // operations like identical large [HV]LOOKUP() areas the new/delete
     165             :         // would add quite some penalty for all but the first formula cell.
     166       19714 :         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
     167       19714 :         if (aIter != aBroadcastAreaTbl.end())
     168       14894 :             rpArea = (*aIter).mpArea;
     169             :         else
     170             :         {
     171        4820 :             rpArea = new ScBroadcastArea( rRange);
     172        4820 :             if (aBroadcastAreaTbl.insert( rpArea).second)
     173             :             {
     174        4820 :                 rpArea->IncRef();
     175        4820 :                 bNewArea = true;
     176             :             }
     177             :             else
     178             :             {
     179             :                 OSL_FAIL("StartListeningArea: area not found and not inserted in slot?!?");
     180           0 :                 delete rpArea;
     181           0 :                 rpArea = 0;
     182             :             }
     183             :         }
     184       19714 :         if (rpArea)
     185       19714 :             pListener->StartListening( rpArea->GetBroadcaster());
     186             :     }
     187             :     else
     188             :     {
     189           0 :         if (aBroadcastAreaTbl.insert( rpArea).second)
     190           0 :             rpArea->IncRef();
     191             :     }
     192       19714 :     return bNewArea;
     193             : }
     194             : 
     195        1884 : void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea* pArea )
     196             : {
     197             :     OSL_ENSURE( pArea, "InsertListeningArea: pArea NULL");
     198        1884 :     if (CheckHardRecalcStateCondition())
     199        1884 :         return;
     200        1884 :     if (aBroadcastAreaTbl.insert( pArea).second)
     201        1884 :         pArea->IncRef();
     202             : }
     203             : 
     204             : // If rpArea != NULL then no listeners are stopped, only the area is removed
     205             : // and the reference count decremented.
     206         946 : void ScBroadcastAreaSlot::EndListeningArea( const ScRange& rRange,
     207             :         SvtListener* pListener, ScBroadcastArea*& rpArea )
     208             : {
     209             :     OSL_ENSURE(pListener, "EndListeningArea: pListener Null");
     210         946 :     if ( !rpArea )
     211             :     {
     212         946 :         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
     213         946 :         if (aIter == aBroadcastAreaTbl.end() || isMarkedErased( aIter))
     214          64 :             return;
     215         882 :         rpArea = (*aIter).mpArea;
     216         882 :         pListener->EndListening( rpArea->GetBroadcaster() );
     217         882 :         if ( !rpArea->GetBroadcaster().HasListeners() )
     218             :         {   // if nobody is listening we can dispose it
     219         550 :             if (rpArea->GetRef() == 1)
     220         550 :                 rpArea = NULL;      // will be deleted by erase
     221         550 :             EraseArea( aIter);
     222             :         }
     223             :     }
     224             :     else
     225             :     {
     226           0 :         if (rpArea && !rpArea->GetBroadcaster().HasListeners())
     227             :         {
     228           0 :             ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
     229           0 :             if (aIter == aBroadcastAreaTbl.end() || isMarkedErased( aIter))
     230           0 :                 return;
     231             :             OSL_ENSURE( (*aIter).mpArea == rpArea, "EndListeningArea: area pointer mismatch");
     232           0 :             if (rpArea->GetRef() == 1)
     233           0 :                 rpArea = NULL;      // will be deleted by erase
     234           0 :             EraseArea( aIter);
     235             :         }
     236             :     }
     237             : }
     238             : 
     239       20660 : ScBroadcastAreas::const_iterator ScBroadcastAreaSlot::FindBroadcastArea(
     240             :         const ScRange& rRange ) const
     241             : {
     242       20660 :     aTmpSeekBroadcastArea.UpdateRange( rRange);
     243       20660 :     return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
     244             : }
     245             : 
     246        3800 : bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint)
     247             : {
     248        3800 :     if (aBroadcastAreaTbl.empty())
     249         748 :         return false;
     250        3052 :     bool bInBroadcast = mbInBroadcastIteration;
     251        3052 :     mbInBroadcastIteration = true;
     252        3052 :     bool bIsBroadcasted = false;
     253        3052 :     const ScAddress& rAddress = rHint.GetAddress();
     254       11052 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     255        3052 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     256             :     {
     257        4948 :         if (isMarkedErased( aIter))
     258           0 :             continue;
     259        4948 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     260        4948 :         const ScRange& rAreaRange = pArea->GetRange();
     261        4948 :         if (rAreaRange.In( rAddress))
     262             :         {
     263         752 :             if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
     264             :             {
     265         374 :                 pArea->GetBroadcaster().Broadcast( rHint);
     266         374 :                 bIsBroadcasted = true;
     267             :             }
     268             :         }
     269             :     }
     270        3052 :     mbInBroadcastIteration = bInBroadcast;
     271             :     // A Notify() during broadcast may call EndListeningArea() and thus dispose
     272             :     // an area if it was the last listener, which would invalidate an iterator
     273             :     // pointing to it, hence the real erase is done afterwards.
     274        3052 :     FinallyEraseAreas();
     275        3052 :     return bIsBroadcasted;
     276             : }
     277             : 
     278           0 : bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
     279             :         const ScHint& rHint)
     280             : {
     281           0 :     if (aBroadcastAreaTbl.empty())
     282           0 :         return false;
     283           0 :     bool bInBroadcast = mbInBroadcastIteration;
     284           0 :     mbInBroadcastIteration = true;
     285           0 :     bool bIsBroadcasted = false;
     286           0 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     287           0 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     288             :     {
     289           0 :         if (isMarkedErased( aIter))
     290           0 :             continue;
     291           0 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     292           0 :         const ScRange& rAreaRange = pArea->GetRange();
     293           0 :         if (rAreaRange.Intersects( rRange ))
     294             :         {
     295           0 :             if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
     296             :             {
     297           0 :                 pArea->GetBroadcaster().Broadcast( rHint);
     298           0 :                 bIsBroadcasted = true;
     299             :             }
     300             :         }
     301             :     }
     302           0 :     mbInBroadcastIteration = bInBroadcast;
     303             :     // A Notify() during broadcast may call EndListeningArea() and thus dispose
     304             :     // an area if it was the last listener, which would invalidate an iterator
     305             :     // pointing to it, hence the real erase is done afterwards.
     306           0 :     FinallyEraseAreas();
     307           0 :     return bIsBroadcasted;
     308             : }
     309             : 
     310          56 : void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
     311             : {
     312          56 :     if (aBroadcastAreaTbl.empty())
     313          58 :         return;
     314         278 :     for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     315         224 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     316             :     {
     317          58 :         const ScRange& rAreaRange = (*aIter).mpArea->GetRange();
     318          58 :         if (rRange.In( rAreaRange))
     319             :         {
     320           6 :             ScBroadcastArea* pArea = (*aIter).mpArea;
     321           6 :             aBroadcastAreaTbl.erase( aIter++);  // erase before modifying
     322           6 :             if (!pArea->DecRef())
     323             :             {
     324           6 :                 if (pBASM->IsInBulkBroadcast())
     325           0 :                     pBASM->RemoveBulkArea( pArea);
     326           6 :                 delete pArea;
     327             :             }
     328             :         }
     329             :         else
     330          52 :             ++aIter;
     331             :     }
     332             : }
     333             : 
     334         140 : void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
     335             :         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     336             : {
     337         140 :     if (aBroadcastAreaTbl.empty())
     338         168 :         return;
     339             : 
     340             :     SCCOL nCol1, nCol2, theCol1, theCol2;
     341             :     SCROW nRow1, nRow2, theRow1, theRow2;
     342             :     SCTAB nTab1, nTab2, theTab1, theTab2;
     343         112 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
     344         568 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     345         456 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     346             :     {
     347         116 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     348         116 :         if ( pArea->IsInUpdateChain() )
     349             :         {
     350           0 :             aBroadcastAreaTbl.erase( aIter++);
     351           0 :             pArea->DecRef();
     352             :         }
     353             :         else
     354             :         {
     355         116 :             pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
     356         116 :             if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     357             :                     nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     358         116 :                     theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
     359             :             {
     360          90 :                 aBroadcastAreaTbl.erase( aIter++);
     361          90 :                 pArea->DecRef();
     362          90 :                 if (pBASM->IsInBulkBroadcast())
     363           0 :                     pBASM->RemoveBulkArea( pArea);
     364          90 :                 pArea->SetInUpdateChain( true );
     365          90 :                 ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
     366          90 :                 if ( pUC )
     367           0 :                     pUC->SetUpdateChainNext( pArea );
     368             :                 else    // no tail => no head
     369          90 :                     pBASM->SetUpdateChain( pArea );
     370          90 :                 pBASM->SetEOUpdateChain( pArea );
     371             :             }
     372             :             else
     373          26 :                 ++aIter;
     374             :         }
     375             :     }
     376             : }
     377             : 
     378           0 : void ScBroadcastAreaSlot::UpdateRemoveArea( ScBroadcastArea* pArea )
     379             : {
     380           0 :     ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.find( pArea));
     381           0 :     if (aIter == aBroadcastAreaTbl.end())
     382           0 :         return;
     383           0 :     if ((*aIter).mpArea != pArea)
     384             :         OSL_FAIL( "UpdateRemoveArea: area pointer mismatch");
     385             :     else
     386             :     {
     387           0 :         aBroadcastAreaTbl.erase( aIter);
     388           0 :         pArea->DecRef();
     389             :     }
     390             : }
     391             : 
     392          90 : void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
     393             : {
     394             :     ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
     395          90 :         aBroadcastAreaTbl.insert( pArea);
     396          90 :     if (aPair.second)
     397          88 :         pArea->IncRef();
     398             :     else
     399             :     {
     400             :         // Identical area already exists, add listeners.
     401           2 :         ScBroadcastArea* pTarget = (*(aPair.first)).mpArea;
     402           2 :         if (pArea != pTarget)
     403             :         {
     404           2 :             SvtBroadcaster& rTarget = pTarget->GetBroadcaster();
     405           2 :             SvtBroadcaster::ListenersType& rListeners = pArea->GetBroadcaster().GetAllListeners();
     406           2 :             SvtBroadcaster::ListenersType::iterator it = rListeners.begin(), itEnd = rListeners.end();
     407           2 :             for (; it != itEnd; ++it)
     408             :             {
     409           0 :                 SvtListener& rListener = **it;
     410           0 :                 rListener.StartListening(rTarget);
     411             :             }
     412             :         }
     413             :     }
     414          90 : }
     415             : 
     416         554 : void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator& rIter )
     417             : {
     418         554 :     if (mbInBroadcastIteration)
     419             :     {
     420           4 :         (*rIter).mbErasure = true;      // mark for erasure
     421           4 :         pBASM->PushAreaToBeErased( this, rIter);
     422             :     }
     423             :     else
     424             :     {
     425         550 :         ScBroadcastArea* pArea = (*rIter).mpArea;
     426         550 :         aBroadcastAreaTbl.erase( rIter);
     427         550 :         if (!pArea->DecRef())
     428         550 :             delete pArea;
     429             :     }
     430         554 : }
     431             : 
     432          20 : void ScBroadcastAreaSlot::GetAllListeners(
     433             :     const ScRange& rRange, std::vector<sc::AreaListener>& rListeners, sc::AreaOverlapType eType )
     434             : {
     435         104 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     436          20 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     437             :     {
     438          64 :         if (isMarkedErased( aIter))
     439          14 :             continue;
     440             : 
     441          64 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     442          64 :         const ScRange& rAreaRange = pArea->GetRange();
     443             : 
     444          64 :         switch (eType)
     445             :         {
     446             :             case sc::AreaInside:
     447          14 :                 if (!rRange.In(rAreaRange))
     448             :                     // The range needs to be fully inside specified range.
     449           6 :                     continue;
     450           8 :                 break;
     451             :             case sc::AreaPartialOverlap:
     452          10 :                 if (!rRange.Intersects(rAreaRange) || rRange.In(rAreaRange))
     453             :                     // The range needs to be only partially overlapping.
     454           8 :                     continue;
     455           2 :                 break;
     456             :             case sc::OneRowInsideArea:
     457          40 :                 if (rAreaRange.aStart.Row() != rAreaRange.aEnd.Row() || !rRange.In(rAreaRange))
     458             :                     // The range needs to be one single row and fully inside
     459             :                     // specified range.
     460           0 :                     continue;
     461          40 :                 break;
     462             :             case sc::OneColumnInsideArea:
     463           0 :                 if (rAreaRange.aStart.Col() != rAreaRange.aEnd.Col() || !rRange.In(rAreaRange))
     464             :                     // The range needs to be one single column and fully inside
     465             :                     // specified range.
     466           0 :                     continue;
     467           0 :                 break;
     468             :         }
     469             : 
     470          50 :         SvtBroadcaster::ListenersType& rLst = pArea->GetBroadcaster().GetAllListeners();
     471          50 :         SvtBroadcaster::ListenersType::iterator itLst = rLst.begin(), itLstEnd = rLst.end();
     472         100 :         for (; itLst != itLstEnd; ++itLst)
     473             :         {
     474          50 :             sc::AreaListener aEntry;
     475          50 :             aEntry.maArea = rAreaRange;
     476          50 :             aEntry.mpListener = *itLst;
     477          50 :             rListeners.push_back(aEntry);
     478             :         }
     479             :     }
     480          20 : }
     481             : 
     482        3052 : void ScBroadcastAreaSlot::FinallyEraseAreas()
     483             : {
     484        3052 :     pBASM->FinallyEraseAreas( this);
     485        3052 : }
     486             : 
     487             : // --- ScBroadcastAreaSlotMachine -------------------------------------
     488             : 
     489         446 : ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
     490             : {
     491         446 :     ppSlots = new ScBroadcastAreaSlot* [ nBcaSlots ];
     492         446 :     memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
     493         446 : }
     494             : 
     495         446 : ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
     496             : {
     497    25576316 :     for ( ScBroadcastAreaSlot** pp = ppSlots + nBcaSlots; --pp >= ppSlots; /* nothing */ )
     498             :     {
     499    25575424 :         if (*pp)
     500        2342 :             delete *pp;
     501             :     }
     502         446 :     delete [] ppSlots;
     503         446 : }
     504             : 
     505        2258 : ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
     506             :         ScDocument* pDocument ) :
     507             :     pBCAlways( NULL ),
     508             :     pDoc( pDocument ),
     509             :     pUpdateChain( NULL ),
     510             :     pEOUpdateChain( NULL ),
     511        2258 :     nInBulkBroadcast( 0 )
     512             : {
     513        2258 : }
     514             : 
     515        4424 : ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
     516             : {
     517        7956 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.begin());
     518        5304 :             iTab != aTableSlotsMap.end(); ++iTab)
     519             :     {
     520         440 :         delete (*iTab).second;
     521             :     }
     522        2212 :     delete pBCAlways;
     523             :     // Areas to-be-erased still present is a serious error in handling, but at
     524             :     // this stage there's nothing we can do anymore.
     525             :     SAL_WARN_IF( !maAreasToBeErased.empty(), "sc", "ScBroadcastAreaSlotMachine::dtor: maAreasToBeErased not empty");
     526        2212 : }
     527             : 
     528       72754 : inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
     529             :         const ScAddress& rAddress ) const
     530             : {
     531       72754 :     SCROW nRow = rAddress.Row();
     532       72754 :     SCCOL nCol = rAddress.Col();
     533       72754 :     if ( !ValidRow(nRow) || !ValidCol(nCol) )
     534             :     {
     535             :         OSL_FAIL( "Row/Col invalid, using first slot!" );
     536           0 :         return 0;
     537             :     }
     538       74394 :     for (size_t i=0; i < aSlotDistribution.size(); ++i)
     539             :     {
     540       74394 :         if (nRow < aSlotDistribution[i].nStopRow)
     541             :         {
     542       72754 :             const ScSlotData& rSD = aSlotDistribution[i];
     543      145508 :             return rSD.nCumulated +
     544       72754 :                 (static_cast<SCSIZE>(nRow - rSD.nStartRow)) / rSD.nSlice +
     545       72754 :                 static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * nBcaSlotsRow;
     546             :         }
     547             :     }
     548             :     OSL_FAIL( "No slot found, using last!" );
     549           0 :     return nBcaSlots - 1;
     550             : }
     551             : 
     552       20966 : void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
     553             :         SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak ) const
     554             : {
     555       20966 :     rStart = ComputeSlotOffset( rRange.aStart );
     556       20966 :     rEnd = ComputeSlotOffset( rRange.aEnd );
     557             :     // count of row slots per column minus one
     558             :     rRowBreak = ComputeSlotOffset(
     559       20966 :         ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
     560       20966 : }
     561             : 
     562       46334 : inline void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
     563             :         SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE const & nRowBreak )
     564             : {
     565       46334 :     if ( nOff < nBreak )
     566             :     {
     567       23450 :         ++nOff;
     568       23450 :         ++pp;
     569             :     }
     570             :     else
     571             :     {
     572       22884 :         nStart += nBcaSlotsRow;
     573       22884 :         nOff = nStart;
     574       22884 :         pp = ppSlots + nOff;
     575       22884 :         nBreak = nOff + nRowBreak;
     576             :     }
     577       46334 : }
     578             : 
     579       19772 : void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
     580             :         SvtListener* pListener )
     581             : {
     582       19772 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     583             :     {
     584          58 :         if ( !pBCAlways )
     585          18 :             pBCAlways = new SvtBroadcaster;
     586          58 :         pListener->StartListening( *pBCAlways );
     587             :     }
     588             :     else
     589             :     {
     590       19714 :         bool bDone = false;
     591       78856 :         for (SCTAB nTab = rRange.aStart.Tab();
     592       39428 :                 !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
     593             :         {
     594       19714 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     595       19714 :             if (iTab == aTableSlotsMap.end())
     596             :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
     597         446 :                             nTab, new TableSlots)).first;
     598       19714 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     599             :             SCSIZE nStart, nEnd, nRowBreak;
     600       19714 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     601       19714 :             SCSIZE nOff = nStart;
     602       19714 :             SCSIZE nBreak = nOff + nRowBreak;
     603       19714 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     604       19714 :             ScBroadcastArea* pArea = NULL;
     605       61026 :             while ( !bDone && nOff <= nEnd )
     606             :             {
     607       21598 :                 if ( !*pp )
     608        2342 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
     609       21598 :                 if (!pArea)
     610             :                 {
     611             :                     // If the call to StartListeningArea didn't create the
     612             :                     // ScBroadcastArea, listeners were added to an already
     613             :                     // existing identical area that doesn't need to be inserted
     614             :                     // to slots again.
     615       19714 :                     if (!(*pp)->StartListeningArea( rRange, pListener, pArea))
     616       14894 :                         bDone = true;
     617             :                 }
     618             :                 else
     619        1884 :                     (*pp)->InsertListeningArea( pArea);
     620       21598 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     621             :             }
     622             :         }
     623             :     }
     624       19772 : }
     625             : 
     626       21155 : void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
     627             :         SvtListener* pListener )
     628             : {
     629       21155 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     630             :     {
     631       20209 :         if ( pBCAlways )
     632             :         {
     633         752 :             pListener->EndListening( *pBCAlways);
     634         752 :             if (!pBCAlways->HasListeners())
     635             :             {
     636           2 :                 delete pBCAlways;
     637           2 :                 pBCAlways = NULL;
     638             :             }
     639             :         }
     640             :     }
     641             :     else
     642             :     {
     643         946 :         SCTAB nEndTab = rRange.aEnd.Tab();
     644        5676 :         for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     645        5676 :                 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     646             :         {
     647         946 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     648             :             SCSIZE nStart, nEnd, nRowBreak;
     649         946 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     650         946 :             SCSIZE nOff = nStart;
     651         946 :             SCSIZE nBreak = nOff + nRowBreak;
     652         946 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     653         946 :             ScBroadcastArea* pArea = NULL;
     654         946 :             if (nOff == 0 && nEnd == nBcaSlots-1)
     655             :             {
     656             :                 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     657             :                 // happen for insertion and deletion of sheets.
     658           0 :                 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     659           0 :                 do
     660             :                 {
     661           0 :                     if ( *pp )
     662           0 :                         (*pp)->EndListeningArea( rRange, pListener, pArea );
     663           0 :                 } while (++pp < pStop);
     664             :             }
     665             :             else
     666             :             {
     667        2838 :                 while ( nOff <= nEnd )
     668             :                 {
     669         946 :                     if ( *pp )
     670         946 :                         (*pp)->EndListeningArea( rRange, pListener, pArea );
     671         946 :                     ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     672             :                 }
     673             :             }
     674             :         }
     675             :     }
     676       21155 : }
     677             : 
     678      148034 : bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
     679             : {
     680      148034 :     const ScAddress& rAddress = rHint.GetAddress();
     681      148034 :     if ( rAddress == BCA_BRDCST_ALWAYS )
     682             :     {
     683       33976 :         if ( pBCAlways )
     684             :         {
     685          14 :             pBCAlways->Broadcast( rHint );
     686          14 :             return true;
     687             :         }
     688             :         else
     689       33962 :             return false;
     690             :     }
     691             :     else
     692             :     {
     693      114058 :         TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
     694      114058 :         if (iTab == aTableSlotsMap.end())
     695      104202 :             return false;
     696        9856 :         ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
     697       19712 :                 ComputeSlotOffset( rAddress));
     698        9856 :         if ( pSlot )
     699        3800 :             return pSlot->AreaBroadcast( rHint );
     700             :         else
     701        6056 :             return false;
     702             :     }
     703             : }
     704             : 
     705           0 : bool ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
     706             :         const ScHint& rHint ) const
     707             : {
     708           0 :     bool bBroadcasted = false;
     709           0 :     SCTAB nEndTab = rRange.aEnd.Tab();
     710           0 :     for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     711           0 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     712             :     {
     713           0 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     714             :         SCSIZE nStart, nEnd, nRowBreak;
     715           0 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     716           0 :         SCSIZE nOff = nStart;
     717           0 :         SCSIZE nBreak = nOff + nRowBreak;
     718           0 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     719           0 :         while ( nOff <= nEnd )
     720             :         {
     721           0 :             if ( *pp )
     722           0 :                 bBroadcasted |= (*pp)->AreaBroadcastInRange( rRange, rHint );
     723           0 :             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     724             :         }
     725             :     }
     726           0 :     return bBroadcasted;
     727             : }
     728             : 
     729         322 : void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
     730             :         const ScRange& rRange )
     731             : {
     732         322 :     SCTAB nEndTab = rRange.aEnd.Tab();
     733        1134 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     734        1134 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     735             :     {
     736          56 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     737             :         SCSIZE nStart, nEnd, nRowBreak;
     738          56 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     739          56 :         SCSIZE nOff = nStart;
     740          56 :         SCSIZE nBreak = nOff + nRowBreak;
     741          56 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     742          56 :         if (nOff == 0 && nEnd == nBcaSlots-1)
     743             :         {
     744             :             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     745             :             // happen for insertion and deletion of sheets.
     746           6 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     747      688116 :             do
     748             :             {
     749      344058 :                 if ( *pp )
     750           6 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     751      688122 :             } while (++pp < pStop);
     752             :         }
     753             :         else
     754             :         {
     755       19814 :             while ( nOff <= nEnd )
     756             :             {
     757       19714 :                 if ( *pp )
     758          50 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     759       19714 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     760             :             }
     761             :         }
     762             :     }
     763         322 : }
     764             : 
     765             : // for all affected: remove, chain, update range, insert, and maybe delete
     766         604 : void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
     767             :         UpdateRefMode eUpdateRefMode,
     768             :         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     769             : {
     770             :     // remove affected and put in chain
     771         604 :     SCTAB nEndTab = rRange.aEnd.Tab();
     772        2232 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     773        2232 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     774             :     {
     775         140 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     776             :         SCSIZE nStart, nEnd, nRowBreak;
     777         140 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     778         140 :         SCSIZE nOff = nStart;
     779         140 :         SCSIZE nBreak = nOff + nRowBreak;
     780         140 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     781         140 :         if (nOff == 0 && nEnd == nBcaSlots-1)
     782             :         {
     783             :             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     784             :             // happen for insertion and deletion of sheets.
     785         132 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     786    15138552 :             do
     787             :             {
     788     7569276 :                 if ( *pp )
     789         132 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     790    15138684 :             } while (++pp < pStop);
     791             :         }
     792             :         else
     793             :         {
     794        3856 :             while ( nOff <= nEnd )
     795             :             {
     796        3840 :                 if ( *pp )
     797           8 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     798        3840 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     799             :             }
     800             :         }
     801             :     }
     802             : 
     803             :     // Updating an area's range will modify the hash key, remove areas from all
     804             :     // affected slots. Will be reinserted later with the updated range.
     805         604 :     ScBroadcastArea* pChain = pUpdateChain;
     806        1298 :     while (pChain)
     807             :     {
     808          90 :         ScBroadcastArea* pArea = pChain;
     809          90 :         pChain = pArea->GetUpdateChainNext();
     810          90 :         ScRange aRange( pArea->GetRange());
     811             :         // remove from slots
     812          90 :         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab() && pArea->GetRef(); ++nTab)
     813             :         {
     814           0 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     815           0 :             if (iTab == aTableSlotsMap.end())
     816             :             {
     817             :                 OSL_FAIL( "UpdateBroadcastAreas: Where's the TableSlot?!?");
     818           0 :                 continue;   // for
     819             :             }
     820           0 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     821             :             SCSIZE nStart, nEnd, nRowBreak;
     822           0 :             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
     823           0 :             SCSIZE nOff = nStart;
     824           0 :             SCSIZE nBreak = nOff + nRowBreak;
     825           0 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     826           0 :             while ( nOff <= nEnd && pArea->GetRef() )
     827             :             {
     828           0 :                 if (*pp)
     829           0 :                     (*pp)->UpdateRemoveArea( pArea);
     830           0 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     831             :             }
     832             :         }
     833             : 
     834             :     }
     835             : 
     836             :     // shift sheets
     837         604 :     if (nDz)
     838             :     {
     839         290 :         if (nDz < 0)
     840             :         {
     841         176 :             TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     842         176 :             TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab() - nDz));
     843             :             // Remove sheets, if any, iDel or/and iTab may as well point to end().
     844         358 :             while (iDel != iTab)
     845             :             {
     846           6 :                 delete (*iDel).second;
     847           6 :                 aTableSlotsMap.erase( iDel++);
     848             :             }
     849             :             // shift remaining down
     850         362 :             while (iTab != aTableSlotsMap.end())
     851             :             {
     852          10 :                 SCTAB nTab = (*iTab).first + nDz;
     853          10 :                 aTableSlotsMap[nTab] = (*iTab).second;
     854          10 :                 aTableSlotsMap.erase( iTab++);
     855             :             }
     856             :         }
     857             :         else
     858             :         {
     859         114 :             TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     860         114 :             if (iStop != aTableSlotsMap.end())
     861             :             {
     862           6 :                 bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
     863           6 :                 if (!bStopIsBegin)
     864           2 :                     --iStop;
     865           6 :                 TableSlotsMap::iterator iTab( aTableSlotsMap.end());
     866           6 :                 --iTab;
     867          16 :                 while (iTab != iStop)
     868             :                 {
     869           4 :                     SCTAB nTab = (*iTab).first + nDz;
     870           4 :                     aTableSlotsMap[nTab] = (*iTab).second;
     871           4 :                     aTableSlotsMap.erase( iTab--);
     872             :                 }
     873             :                 // Shift the very first, iTab==iStop in this case.
     874           6 :                 if (bStopIsBegin)
     875             :                 {
     876           4 :                     SCTAB nTab = (*iTab).first + nDz;
     877           4 :                     aTableSlotsMap[nTab] = (*iTab).second;
     878           4 :                     aTableSlotsMap.erase( iStop);
     879             :                 }
     880             :             }
     881             :         }
     882             :     }
     883             : 
     884             :     // work off chain
     885             :     SCCOL nCol1, nCol2, theCol1, theCol2;
     886             :     SCROW nRow1, nRow2, theRow1, theRow2;
     887             :     SCTAB nTab1, nTab2, theTab1, theTab2;
     888         604 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
     889        1298 :     while ( pUpdateChain )
     890             :     {
     891          90 :         ScBroadcastArea* pArea = pUpdateChain;
     892          90 :         ScRange aRange( pArea->GetRange());
     893          90 :         pUpdateChain = pArea->GetUpdateChainNext();
     894             : 
     895             :         // update range
     896          90 :         aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
     897          90 :         if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     898             :                 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     899          90 :                 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
     900             :         {
     901          90 :             aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
     902          90 :             pArea->UpdateRange( aRange );
     903          90 :             pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) );   // for DDE
     904             :         }
     905             : 
     906             :         // insert to slots
     907         180 :         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
     908             :         {
     909          90 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     910          90 :             if (iTab == aTableSlotsMap.end())
     911             :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
     912           0 :                             nTab, new TableSlots)).first;
     913          90 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     914             :             SCSIZE nStart, nEnd, nRowBreak;
     915          90 :             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
     916          90 :             SCSIZE nOff = nStart;
     917          90 :             SCSIZE nBreak = nOff + nRowBreak;
     918          90 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     919         270 :             while ( nOff <= nEnd )
     920             :             {
     921          90 :                 if (!*pp)
     922           0 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
     923          90 :                 (*pp)->UpdateInsert( pArea );
     924          90 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     925             :             }
     926             :         }
     927             : 
     928             :         // unchain
     929          90 :         pArea->SetUpdateChainNext( NULL );
     930          90 :         pArea->SetInUpdateChain( false );
     931             : 
     932             :         // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
     933             :         // already executed in UpdateRemove().
     934          90 :         if (!pArea->GetRef())
     935           2 :             delete pArea;
     936             :     }
     937         604 :     pEOUpdateChain = NULL;
     938         604 : }
     939             : 
     940      104262 : void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
     941             : {
     942      104262 :     ++nInBulkBroadcast;
     943      104262 : }
     944             : 
     945      104262 : void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
     946             : {
     947      104262 :     if (nInBulkBroadcast > 0)
     948             :     {
     949      104262 :         if (--nInBulkBroadcast == 0)
     950       98134 :             ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
     951             :     }
     952      104262 : }
     953             : 
     954         742 : bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
     955             : {
     956         742 :     return aBulkBroadcastAreas.insert( pArea ).second;
     957             : }
     958             : 
     959           0 : size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea* pArea )
     960             : {
     961           0 :     return aBulkBroadcastAreas.erase( pArea );
     962             : }
     963             : 
     964           4 : void ScBroadcastAreaSlotMachine::PushAreaToBeErased( ScBroadcastAreaSlot* pSlot,
     965             :         ScBroadcastAreas::iterator& rIter )
     966             : {
     967           4 :     maAreasToBeErased.push_back( ::std::make_pair( pSlot, rIter));
     968           4 : }
     969             : 
     970        3052 : void ScBroadcastAreaSlotMachine::FinallyEraseAreas( ScBroadcastAreaSlot* pSlot )
     971             : {
     972             :     SAL_WARN_IF( pSlot->IsInBroadcastIteration(), "sc",
     973             :             "ScBroadcastAreaSlotMachine::FinallyEraseAreas: during iteration? NO!");
     974        3052 :     if (pSlot->IsInBroadcastIteration())
     975        3052 :         return;
     976             : 
     977             :     // maAreasToBeErased is a simple vector so erasing an element may
     978             :     // invalidate iterators and would be inefficient anyway. Instead, copy
     979             :     // elements to be preserved (usually none!) to temporary vector and swap.
     980        3052 :     AreasToBeErased aCopy;
     981        9168 :     for (AreasToBeErased::iterator aIt( maAreasToBeErased.begin());
     982        6112 :             aIt != maAreasToBeErased.end(); ++aIt)
     983             :     {
     984           4 :         if ((*aIt).first == pSlot)
     985           4 :             pSlot->EraseArea( (*aIt).second);
     986             :         else
     987           0 :             aCopy.push_back( *aIt);
     988             :     }
     989        3052 :     maAreasToBeErased.swap( aCopy);
     990             : }
     991             : 
     992         112 : std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners(
     993             :     const ScRange& rRange, sc::AreaOverlapType eType )
     994             : {
     995         112 :     std::vector<sc::AreaListener> aRet;
     996             : 
     997         112 :     SCTAB nEndTab = rRange.aEnd.Tab();
     998         396 :     for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     999         396 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
    1000             :     {
    1001          20 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
    1002             :         SCSIZE nStart, nEnd, nRowBreak;
    1003          20 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
    1004          20 :         SCSIZE nOff = nStart;
    1005          20 :         SCSIZE nBreak = nOff + nRowBreak;
    1006          20 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
    1007         186 :         while ( nOff <= nEnd )
    1008             :         {
    1009         146 :             ScBroadcastAreaSlot* p = *pp;
    1010         146 :             if (p)
    1011          20 :                 p->GetAllListeners(rRange, aRet, eType);
    1012         146 :             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
    1013             :         }
    1014             :     }
    1015             : 
    1016         112 :     return aRet;
    1017         228 : }
    1018             : 
    1019             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10