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

Generated by: LCOV version 1.10