LCOV - code coverage report
Current view: top level - sc/source/core/data - bcaslot.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 495 0.0 %
Date: 2014-04-14 Functions: 0 50 0.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           0 : 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           0 :     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           0 : static SCSIZE initSlotDistribution( ScSlotDistribution & rSD, SCSIZE & rBSR )
      86             : {
      87           0 :     SCSIZE nSlots = 0;
      88           0 :     SCROW nRow1 = 0;
      89           0 :     SCROW nRow2 = 32*1024;
      90           0 :     SCSIZE nSlice = 128;
      91             :     // Must be sorted by row1,row2!
      92           0 :     while (nRow2 <= MAXROWCOUNT)
      93             :     {
      94           0 :         rSD.push_back( ScSlotData( nRow1, nRow2, nSlice, nSlots));
      95           0 :         nSlots += (nRow2 - nRow1) / nSlice;
      96           0 :         nRow1 = nRow2;
      97           0 :         nRow2 *= 2;
      98           0 :         nSlice *= 2;
      99             :     }
     100           0 :     rBSR = nSlots;
     101           0 :     return nSlots;
     102             : }
     103           0 : static ScSlotDistribution aSlotDistribution;
     104             : static SCSIZE nBcaSlotsRow;
     105           0 : 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           0 : ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
     111             :         ScBroadcastAreaSlotMachine* pBASMa ) :
     112             :     aTmpSeekBroadcastArea( ScRange()),
     113             :     pDoc( pDocument ),
     114             :     pBASM( pBASMa ),
     115           0 :     mbInBroadcastIteration( false)
     116             : {
     117           0 : }
     118             : 
     119             : 
     120           0 : ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
     121             : {
     122           0 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     123           0 :             aIter != aBroadcastAreaTbl.end(); /* none */)
     124             :     {
     125             :         // Prevent hash from accessing dangling pointer in case area is
     126             :         // deleted.
     127           0 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     128             :         // Erase all so no hash will be accessed upon destruction of the
     129             :         // boost::unordered_map.
     130           0 :         aBroadcastAreaTbl.erase( aIter++);
     131           0 :         if (!pArea->DecRef())
     132           0 :             delete pArea;
     133             :     }
     134           0 : }
     135             : 
     136             : 
     137           0 : bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
     138             : {
     139           0 :     if ( pDoc->GetHardRecalcState() )
     140           0 :         return true;
     141           0 :     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           0 :     return false;
     157             : }
     158             : 
     159             : 
     160           0 : bool ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
     161             :         SvtListener* pListener, ScBroadcastArea*& rpArea )
     162             : {
     163           0 :     bool bNewArea = false;
     164             :     OSL_ENSURE(pListener, "StartListeningArea: pListener Null");
     165           0 :     if (CheckHardRecalcStateCondition())
     166           0 :         return false;
     167           0 :     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           0 :         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
     174           0 :         if (aIter != aBroadcastAreaTbl.end())
     175           0 :             rpArea = (*aIter).mpArea;
     176             :         else
     177             :         {
     178           0 :             rpArea = new ScBroadcastArea( rRange);
     179           0 :             if (aBroadcastAreaTbl.insert( rpArea).second)
     180             :             {
     181           0 :                 rpArea->IncRef();
     182           0 :                 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           0 :         if (rpArea)
     192           0 :             pListener->StartListening( rpArea->GetBroadcaster());
     193             :     }
     194             :     else
     195             :     {
     196           0 :         if (aBroadcastAreaTbl.insert( rpArea).second)
     197           0 :             rpArea->IncRef();
     198             :     }
     199           0 :     return bNewArea;
     200             : }
     201             : 
     202             : 
     203           0 : void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea* pArea )
     204             : {
     205             :     OSL_ENSURE( pArea, "InsertListeningArea: pArea NULL");
     206           0 :     if (CheckHardRecalcStateCondition())
     207           0 :         return;
     208           0 :     if (aBroadcastAreaTbl.insert( pArea).second)
     209           0 :         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           0 : void ScBroadcastAreaSlot::EndListeningArea( const ScRange& rRange,
     216             :         SvtListener* pListener, ScBroadcastArea*& rpArea )
     217             : {
     218             :     OSL_ENSURE(pListener, "EndListeningArea: pListener Null");
     219           0 :     if ( !rpArea )
     220             :     {
     221           0 :         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
     222           0 :         if (aIter == aBroadcastAreaTbl.end() || isMarkedErased( aIter))
     223           0 :             return;
     224           0 :         rpArea = (*aIter).mpArea;
     225           0 :         pListener->EndListening( rpArea->GetBroadcaster() );
     226           0 :         if ( !rpArea->GetBroadcaster().HasListeners() )
     227             :         {   // if nobody is listening we can dispose it
     228           0 :             if (rpArea->GetRef() == 1)
     229           0 :                 rpArea = NULL;      // will be deleted by erase
     230           0 :             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           0 : ScBroadcastAreas::const_iterator ScBroadcastAreaSlot::FindBroadcastArea(
     250             :         const ScRange& rRange ) const
     251             : {
     252           0 :     aTmpSeekBroadcastArea.UpdateRange( rRange);
     253           0 :     return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
     254             : }
     255             : 
     256             : 
     257           0 : bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint)
     258             : {
     259           0 :     if (aBroadcastAreaTbl.empty())
     260           0 :         return false;
     261           0 :     bool bInBroadcast = mbInBroadcastIteration;
     262           0 :     mbInBroadcastIteration = true;
     263           0 :     bool bIsBroadcasted = false;
     264           0 :     const ScAddress& rAddress = rHint.GetAddress();
     265           0 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     266           0 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     267             :     {
     268           0 :         if (isMarkedErased( aIter))
     269           0 :             continue;
     270           0 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     271           0 :         const ScRange& rAreaRange = pArea->GetRange();
     272           0 :         if (rAreaRange.In( rAddress))
     273             :         {
     274           0 :             if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
     275             :             {
     276           0 :                 pArea->GetBroadcaster().Broadcast( rHint);
     277           0 :                 bIsBroadcasted = true;
     278             :             }
     279             :         }
     280             :     }
     281           0 :     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           0 :     FinallyEraseAreas();
     286           0 :     return bIsBroadcasted;
     287             : }
     288             : 
     289             : 
     290           0 : bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
     291             :         const ScHint& rHint)
     292             : {
     293           0 :     if (aBroadcastAreaTbl.empty())
     294           0 :         return false;
     295           0 :     bool bInBroadcast = mbInBroadcastIteration;
     296           0 :     mbInBroadcastIteration = true;
     297           0 :     bool bIsBroadcasted = false;
     298           0 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     299           0 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     300             :     {
     301           0 :         if (isMarkedErased( aIter))
     302           0 :             continue;
     303           0 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     304           0 :         const ScRange& rAreaRange = pArea->GetRange();
     305           0 :         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           0 :     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           0 :     FinallyEraseAreas();
     319           0 :     return bIsBroadcasted;
     320             : }
     321             : 
     322             : 
     323           0 : void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
     324             : {
     325           0 :     if (aBroadcastAreaTbl.empty())
     326           0 :         return;
     327           0 :     for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     328           0 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     329             :     {
     330           0 :         const ScRange& rAreaRange = (*aIter).mpArea->GetRange();
     331           0 :         if (rRange.In( rAreaRange))
     332             :         {
     333           0 :             ScBroadcastArea* pArea = (*aIter).mpArea;
     334           0 :             aBroadcastAreaTbl.erase( aIter++);  // erase before modifying
     335           0 :             if (!pArea->DecRef())
     336             :             {
     337           0 :                 if (pBASM->IsInBulkBroadcast())
     338           0 :                     pBASM->RemoveBulkArea( pArea);
     339           0 :                 delete pArea;
     340             :             }
     341             :         }
     342             :         else
     343           0 :             ++aIter;
     344             :     }
     345             : }
     346             : 
     347             : 
     348           0 : void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
     349             :         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     350             : {
     351           0 :     if (aBroadcastAreaTbl.empty())
     352           0 :         return;
     353             : 
     354             :     SCCOL nCol1, nCol2, theCol1, theCol2;
     355             :     SCROW nRow1, nRow2, theRow1, theRow2;
     356             :     SCTAB nTab1, nTab2, theTab1, theTab2;
     357           0 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
     358           0 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     359           0 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     360             :     {
     361           0 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     362           0 :         if ( pArea->IsInUpdateChain() )
     363             :         {
     364           0 :             aBroadcastAreaTbl.erase( aIter++);
     365           0 :             pArea->DecRef();
     366             :         }
     367             :         else
     368             :         {
     369           0 :             pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
     370           0 :             if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     371             :                     nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     372           0 :                     theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
     373             :             {
     374           0 :                 aBroadcastAreaTbl.erase( aIter++);
     375           0 :                 pArea->DecRef();
     376           0 :                 if (pBASM->IsInBulkBroadcast())
     377           0 :                     pBASM->RemoveBulkArea( pArea);
     378           0 :                 pArea->SetInUpdateChain( true );
     379           0 :                 ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
     380           0 :                 if ( pUC )
     381           0 :                     pUC->SetUpdateChainNext( pArea );
     382             :                 else    // no tail => no head
     383           0 :                     pBASM->SetUpdateChain( pArea );
     384           0 :                 pBASM->SetEOUpdateChain( pArea );
     385             :             }
     386             :             else
     387           0 :                 ++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           0 : void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
     409             : {
     410             :     ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
     411           0 :         aBroadcastAreaTbl.insert( pArea);
     412           0 :     if (aPair.second)
     413           0 :         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           0 : }
     431             : 
     432             : 
     433           0 : void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator& rIter )
     434             : {
     435           0 :     if (mbInBroadcastIteration)
     436             :     {
     437           0 :         (*rIter).mbErasure = true;      // mark for erasure
     438           0 :         pBASM->PushAreaToBeErased( this, rIter);
     439             :     }
     440             :     else
     441             :     {
     442           0 :         ScBroadcastArea* pArea = (*rIter).mpArea;
     443           0 :         aBroadcastAreaTbl.erase( rIter);
     444           0 :         if (!pArea->DecRef())
     445           0 :             delete pArea;
     446             :     }
     447           0 : }
     448             : 
     449           0 : void ScBroadcastAreaSlot::GetAllListeners( const ScRange& rRange, std::vector<sc::AreaListener>& rListeners )
     450             : {
     451           0 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     452           0 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     453             :     {
     454           0 :         if (isMarkedErased( aIter))
     455           0 :             continue;
     456             : 
     457           0 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     458           0 :         const ScRange& rAreaRange = pArea->GetRange();
     459           0 :         if (!rRange.In(rAreaRange))
     460           0 :             continue;
     461             : 
     462           0 :         SvtBroadcaster::ListenersType& rLst = pArea->GetBroadcaster().GetAllListeners();
     463           0 :         SvtBroadcaster::ListenersType::iterator itLst = rLst.begin(), itLstEnd = rLst.end();
     464           0 :         for (; itLst != itLstEnd; ++itLst)
     465             :         {
     466           0 :             sc::AreaListener aEntry;
     467           0 :             aEntry.maArea = rAreaRange;
     468           0 :             aEntry.mpListener = *itLst;
     469           0 :             rListeners.push_back(aEntry);
     470             :         }
     471             :     }
     472           0 : }
     473             : 
     474           0 : void ScBroadcastAreaSlot::FinallyEraseAreas()
     475             : {
     476           0 :     pBASM->FinallyEraseAreas( this);
     477           0 : }
     478             : 
     479             : 
     480             : // --- ScBroadcastAreaSlotMachine -------------------------------------
     481             : 
     482           0 : ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
     483             : {
     484           0 :     ppSlots = new ScBroadcastAreaSlot* [ nBcaSlots ];
     485           0 :     memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
     486           0 : }
     487             : 
     488             : 
     489           0 : ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
     490             : {
     491           0 :     for ( ScBroadcastAreaSlot** pp = ppSlots + nBcaSlots; --pp >= ppSlots; /* nothing */ )
     492             :     {
     493           0 :         if (*pp)
     494           0 :             delete *pp;
     495             :     }
     496           0 :     delete [] ppSlots;
     497           0 : }
     498             : 
     499             : 
     500           0 : ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
     501             :         ScDocument* pDocument ) :
     502             :     pBCAlways( NULL ),
     503             :     pDoc( pDocument ),
     504             :     pUpdateChain( NULL ),
     505             :     pEOUpdateChain( NULL ),
     506           0 :     nInBulkBroadcast( 0 )
     507             : {
     508           0 : }
     509             : 
     510             : 
     511           0 : ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
     512             : {
     513           0 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.begin());
     514           0 :             iTab != aTableSlotsMap.end(); ++iTab)
     515             :     {
     516           0 :         delete (*iTab).second;
     517             :     }
     518           0 :     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           0 : }
     523             : 
     524             : 
     525           0 : inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
     526             :         const ScAddress& rAddress ) const
     527             : {
     528           0 :     SCROW nRow = rAddress.Row();
     529           0 :     SCCOL nCol = rAddress.Col();
     530           0 :     if ( !ValidRow(nRow) || !ValidCol(nCol) )
     531             :     {
     532             :         OSL_FAIL( "Row/Col invalid, using first slot!" );
     533           0 :         return 0;
     534             :     }
     535           0 :     for (size_t i=0; i < aSlotDistribution.size(); ++i)
     536             :     {
     537           0 :         if (nRow < aSlotDistribution[i].nStopRow)
     538             :         {
     539           0 :             const ScSlotData& rSD = aSlotDistribution[i];
     540           0 :             return rSD.nCumulated +
     541           0 :                 (static_cast<SCSIZE>(nRow - rSD.nStartRow)) / rSD.nSlice +
     542           0 :                 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           0 : void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
     551             :         SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak ) const
     552             : {
     553           0 :     rStart = ComputeSlotOffset( rRange.aStart );
     554           0 :     rEnd = ComputeSlotOffset( rRange.aEnd );
     555             :     // count of row slots per column minus one
     556             :     rRowBreak = ComputeSlotOffset(
     557           0 :         ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
     558           0 : }
     559             : 
     560             : 
     561           0 : inline void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
     562             :         SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE const & nRowBreak )
     563             : {
     564           0 :     if ( nOff < nBreak )
     565             :     {
     566           0 :         ++nOff;
     567           0 :         ++pp;
     568             :     }
     569             :     else
     570             :     {
     571           0 :         nStart += nBcaSlotsRow;
     572           0 :         nOff = nStart;
     573           0 :         pp = ppSlots + nOff;
     574           0 :         nBreak = nOff + nRowBreak;
     575             :     }
     576           0 : }
     577             : 
     578             : 
     579           0 : void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
     580             :         SvtListener* pListener )
     581             : {
     582           0 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     583             :     {
     584           0 :         if ( !pBCAlways )
     585           0 :             pBCAlways = new SvtBroadcaster;
     586           0 :         pListener->StartListening( *pBCAlways );
     587             :     }
     588             :     else
     589             :     {
     590           0 :         bool bDone = false;
     591           0 :         for (SCTAB nTab = rRange.aStart.Tab();
     592           0 :                 !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
     593             :         {
     594           0 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     595           0 :             if (iTab == aTableSlotsMap.end())
     596             :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
     597           0 :                             nTab, new TableSlots)).first;
     598           0 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     599             :             SCSIZE nStart, nEnd, nRowBreak;
     600           0 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     601           0 :             SCSIZE nOff = nStart;
     602           0 :             SCSIZE nBreak = nOff + nRowBreak;
     603           0 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     604           0 :             ScBroadcastArea* pArea = NULL;
     605           0 :             while ( !bDone && nOff <= nEnd )
     606             :             {
     607           0 :                 if ( !*pp )
     608           0 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
     609           0 :                 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           0 :                     if (!(*pp)->StartListeningArea( rRange, pListener, pArea))
     616           0 :                         bDone = true;
     617             :                 }
     618             :                 else
     619           0 :                     (*pp)->InsertListeningArea( pArea);
     620           0 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     621             :             }
     622             :         }
     623             :     }
     624           0 : }
     625             : 
     626             : 
     627           0 : void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
     628             :         SvtListener* pListener )
     629             : {
     630           0 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     631             :     {
     632           0 :         if ( pBCAlways )
     633             :         {
     634           0 :             pListener->EndListening( *pBCAlways);
     635           0 :             if (!pBCAlways->HasListeners())
     636             :             {
     637           0 :                 delete pBCAlways;
     638           0 :                 pBCAlways = NULL;
     639             :             }
     640             :         }
     641             :     }
     642             :     else
     643             :     {
     644           0 :         SCTAB nEndTab = rRange.aEnd.Tab();
     645           0 :         for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     646           0 :                 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     647             :         {
     648           0 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     649             :             SCSIZE nStart, nEnd, nRowBreak;
     650           0 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     651           0 :             SCSIZE nOff = nStart;
     652           0 :             SCSIZE nBreak = nOff + nRowBreak;
     653           0 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     654           0 :             ScBroadcastArea* pArea = NULL;
     655           0 :             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           0 :                 while ( nOff <= nEnd )
     669             :                 {
     670           0 :                     if ( *pp )
     671           0 :                         (*pp)->EndListeningArea( rRange, pListener, pArea );
     672           0 :                     ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     673             :                 }
     674             :             }
     675             :         }
     676             :     }
     677           0 : }
     678             : 
     679             : 
     680           0 : bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
     681             : {
     682           0 :     const ScAddress& rAddress = rHint.GetAddress();
     683           0 :     if ( rAddress == BCA_BRDCST_ALWAYS )
     684             :     {
     685           0 :         if ( pBCAlways )
     686             :         {
     687           0 :             pBCAlways->Broadcast( rHint );
     688           0 :             return true;
     689             :         }
     690             :         else
     691           0 :             return false;
     692             :     }
     693             :     else
     694             :     {
     695           0 :         TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
     696           0 :         if (iTab == aTableSlotsMap.end())
     697           0 :             return false;
     698           0 :         ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
     699           0 :                 ComputeSlotOffset( rAddress));
     700           0 :         if ( pSlot )
     701           0 :             return pSlot->AreaBroadcast( rHint );
     702             :         else
     703           0 :             return false;
     704             :     }
     705             : }
     706             : 
     707             : 
     708           0 : bool ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
     709             :         const ScHint& rHint ) const
     710             : {
     711           0 :     bool bBroadcasted = false;
     712           0 :     SCTAB nEndTab = rRange.aEnd.Tab();
     713           0 :     for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     714           0 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     715             :     {
     716           0 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     717             :         SCSIZE nStart, nEnd, nRowBreak;
     718           0 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     719           0 :         SCSIZE nOff = nStart;
     720           0 :         SCSIZE nBreak = nOff + nRowBreak;
     721           0 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     722           0 :         while ( nOff <= nEnd )
     723             :         {
     724           0 :             if ( *pp )
     725           0 :                 bBroadcasted |= (*pp)->AreaBroadcastInRange( rRange, rHint );
     726           0 :             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     727             :         }
     728             :     }
     729           0 :     return bBroadcasted;
     730             : }
     731             : 
     732             : 
     733           0 : void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
     734             :         const ScRange& rRange )
     735             : {
     736           0 :     SCTAB nEndTab = rRange.aEnd.Tab();
     737           0 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     738           0 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     739             :     {
     740           0 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     741             :         SCSIZE nStart, nEnd, nRowBreak;
     742           0 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     743           0 :         SCSIZE nOff = nStart;
     744           0 :         SCSIZE nBreak = nOff + nRowBreak;
     745           0 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     746           0 :         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           0 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     751           0 :             do
     752             :             {
     753           0 :                 if ( *pp )
     754           0 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     755           0 :             } while (++pp < pStop);
     756             :         }
     757             :         else
     758             :         {
     759           0 :             while ( nOff <= nEnd )
     760             :             {
     761           0 :                 if ( *pp )
     762           0 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     763           0 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     764             :             }
     765             :         }
     766             :     }
     767           0 : }
     768             : 
     769             : 
     770             : // for all affected: remove, chain, update range, insert, and maybe delete
     771           0 : 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           0 :     SCTAB nEndTab = rRange.aEnd.Tab();
     777           0 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     778           0 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     779             :     {
     780           0 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     781             :         SCSIZE nStart, nEnd, nRowBreak;
     782           0 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     783           0 :         SCSIZE nOff = nStart;
     784           0 :         SCSIZE nBreak = nOff + nRowBreak;
     785           0 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     786           0 :         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           0 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     791           0 :             do
     792             :             {
     793           0 :                 if ( *pp )
     794           0 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     795           0 :             } while (++pp < pStop);
     796             :         }
     797             :         else
     798             :         {
     799           0 :             while ( nOff <= nEnd )
     800             :             {
     801           0 :                 if ( *pp )
     802           0 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     803           0 :                 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           0 :     ScBroadcastArea* pChain = pUpdateChain;
     811           0 :     while (pChain)
     812             :     {
     813           0 :         ScBroadcastArea* pArea = pChain;
     814           0 :         pChain = pArea->GetUpdateChainNext();
     815           0 :         ScRange aRange( pArea->GetRange());
     816             :         // remove from slots
     817           0 :         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           0 :     if (nDz)
     843             :     {
     844           0 :         if (nDz < 0)
     845             :         {
     846           0 :             TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     847           0 :             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           0 :             while (iDel != iTab)
     850             :             {
     851           0 :                 delete (*iDel).second;
     852           0 :                 aTableSlotsMap.erase( iDel++);
     853             :             }
     854             :             // shift remaining down
     855           0 :             while (iTab != aTableSlotsMap.end())
     856             :             {
     857           0 :                 SCTAB nTab = (*iTab).first + nDz;
     858           0 :                 aTableSlotsMap[nTab] = (*iTab).second;
     859           0 :                 aTableSlotsMap.erase( iTab++);
     860             :             }
     861             :         }
     862             :         else
     863             :         {
     864           0 :             TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     865           0 :             if (iStop != aTableSlotsMap.end())
     866             :             {
     867           0 :                 bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
     868           0 :                 if (!bStopIsBegin)
     869           0 :                     --iStop;
     870           0 :                 TableSlotsMap::iterator iTab( aTableSlotsMap.end());
     871           0 :                 --iTab;
     872           0 :                 while (iTab != iStop)
     873             :                 {
     874           0 :                     SCTAB nTab = (*iTab).first + nDz;
     875           0 :                     aTableSlotsMap[nTab] = (*iTab).second;
     876           0 :                     aTableSlotsMap.erase( iTab--);
     877             :                 }
     878             :                 // Shift the very first, iTab==iStop in this case.
     879           0 :                 if (bStopIsBegin)
     880             :                 {
     881           0 :                     SCTAB nTab = (*iTab).first + nDz;
     882           0 :                     aTableSlotsMap[nTab] = (*iTab).second;
     883           0 :                     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           0 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
     894           0 :     while ( pUpdateChain )
     895             :     {
     896           0 :         ScBroadcastArea* pArea = pUpdateChain;
     897           0 :         ScRange aRange( pArea->GetRange());
     898           0 :         pUpdateChain = pArea->GetUpdateChainNext();
     899             : 
     900             :         // update range
     901           0 :         aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
     902           0 :         if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     903             :                 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     904           0 :                 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
     905             :         {
     906           0 :             aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
     907           0 :             pArea->UpdateRange( aRange );
     908           0 :             pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) );   // for DDE
     909             :         }
     910             : 
     911             :         // insert to slots
     912           0 :         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
     913             :         {
     914           0 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     915           0 :             if (iTab == aTableSlotsMap.end())
     916             :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
     917           0 :                             nTab, new TableSlots)).first;
     918           0 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     919             :             SCSIZE nStart, nEnd, nRowBreak;
     920           0 :             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
     921           0 :             SCSIZE nOff = nStart;
     922           0 :             SCSIZE nBreak = nOff + nRowBreak;
     923           0 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     924           0 :             while ( nOff <= nEnd )
     925             :             {
     926           0 :                 if (!*pp)
     927           0 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
     928           0 :                 (*pp)->UpdateInsert( pArea );
     929           0 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     930             :             }
     931             :         }
     932             : 
     933             :         // unchain
     934           0 :         pArea->SetUpdateChainNext( NULL );
     935           0 :         pArea->SetInUpdateChain( false );
     936             : 
     937             :         // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
     938             :         // already executed in UpdateRemove().
     939           0 :         if (!pArea->GetRef())
     940           0 :             delete pArea;
     941             :     }
     942           0 :     pEOUpdateChain = NULL;
     943           0 : }
     944             : 
     945             : 
     946           0 : void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
     947             : {
     948           0 :     ++nInBulkBroadcast;
     949           0 : }
     950             : 
     951             : 
     952           0 : void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
     953             : {
     954           0 :     if (nInBulkBroadcast > 0)
     955             :     {
     956           0 :         if (--nInBulkBroadcast == 0)
     957           0 :             ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
     958             :     }
     959           0 : }
     960             : 
     961             : 
     962           0 : bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
     963             : {
     964           0 :     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           0 : void ScBroadcastAreaSlotMachine::PushAreaToBeErased( ScBroadcastAreaSlot* pSlot,
     975             :         ScBroadcastAreas::iterator& rIter )
     976             : {
     977           0 :     maAreasToBeErased.push_back( ::std::make_pair( pSlot, rIter));
     978           0 : }
     979             : 
     980             : 
     981           0 : void ScBroadcastAreaSlotMachine::FinallyEraseAreas( ScBroadcastAreaSlot* pSlot )
     982             : {
     983             :     SAL_WARN_IF( pSlot->IsInBroadcastIteration(), "sc",
     984             :             "ScBroadcastAreaSlotMachine::FinallyEraseAreas: during iteration? NO!");
     985           0 :     if (pSlot->IsInBroadcastIteration())
     986           0 :         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           0 :     AreasToBeErased aCopy;
     992           0 :     for (AreasToBeErased::iterator aIt( maAreasToBeErased.begin());
     993           0 :             aIt != maAreasToBeErased.end(); ++aIt)
     994             :     {
     995           0 :         if ((*aIt).first == pSlot)
     996           0 :             pSlot->EraseArea( (*aIt).second);
     997             :         else
     998           0 :             aCopy.push_back( *aIt);
     999             :     }
    1000           0 :     maAreasToBeErased.swap( aCopy);
    1001             : }
    1002             : 
    1003           0 : std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners( const ScRange& rRange )
    1004             : {
    1005           0 :     std::vector<sc::AreaListener> aRet;
    1006             : 
    1007           0 :     SCTAB nEndTab = rRange.aEnd.Tab();
    1008           0 :     for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
    1009           0 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
    1010             :     {
    1011           0 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
    1012             :         SCSIZE nStart, nEnd, nRowBreak;
    1013           0 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
    1014           0 :         SCSIZE nOff = nStart;
    1015           0 :         SCSIZE nBreak = nOff + nRowBreak;
    1016           0 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
    1017           0 :         while ( nOff <= nEnd )
    1018             :         {
    1019           0 :             ScBroadcastAreaSlot* p = *pp;
    1020           0 :             p->GetAllListeners(rRange, aRet);
    1021           0 :             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
    1022             :         }
    1023             :     }
    1024             : 
    1025           0 :     return aRet;
    1026           0 : }
    1027             : 
    1028             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10