LCOV - code coverage report
Current view: top level - sc/source/core/data - bcaslot.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 503 582 86.4 %
Date: 2015-06-13 12:38:46 Functions: 43 45 95.6 %
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             : #include <bulkdatahint.hxx>
      31             : 
      32             : #if DEBUG_AREA_BROADCASTER
      33             : #include <formulacell.hxx>
      34             : #include <grouparealistener.hxx>
      35             : #endif
      36             : 
      37             : // Number of slots per dimension
      38             : // must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
      39             : #define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
      40             : #if MAXROWCOUNT_DEFINE == 32000
      41             : #define BCA_SLOTS_ROW 256
      42             : #define BCA_SLICE 125
      43             : #else
      44             : #define BCA_SLICE 128
      45             : #define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / BCA_SLICE)
      46             : #endif
      47             : #define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
      48             : #define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
      49             : // multiple?
      50             : #if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
      51             : #error bad BCA_SLOTS_COL value!
      52             : #endif
      53             : #if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
      54             : #error bad BCA_SLOTS_ROW value!
      55             : #endif
      56             : // size of slot array if linear
      57             : #define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
      58             : // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
      59             : // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
      60             : // anyway, once you reached these values..
      61             : #if BCA_SLOTS_DEFINE > 268435456
      62             : #error BCA_SLOTS_DEFINE DOOMed!
      63             : #endif
      64             : 
      65             : // STATIC DATA -----------------------------------------------------------
      66             : 
      67             : namespace sc {
      68             : 
      69           2 : bool AreaListener::SortByArea::operator ()( const AreaListener& rLeft, const AreaListener& rRight ) const
      70             : {
      71           2 :     if (rLeft.maArea.aStart.Tab() != rRight.maArea.aStart.Tab())
      72           0 :         return rLeft.maArea.aStart.Tab() < rRight.maArea.aStart.Tab();
      73             : 
      74           2 :     if (rLeft.maArea.aStart.Col() != rRight.maArea.aStart.Col())
      75           0 :         return rLeft.maArea.aStart.Col() < rRight.maArea.aStart.Col();
      76             : 
      77           2 :     if (rLeft.maArea.aStart.Row() != rRight.maArea.aStart.Row())
      78           2 :         return rLeft.maArea.aStart.Row() < rRight.maArea.aStart.Row();
      79             : 
      80           0 :     if (rLeft.maArea.aEnd.Tab() != rRight.maArea.aEnd.Tab())
      81           0 :         return rLeft.maArea.aEnd.Tab() < rRight.maArea.aEnd.Tab();
      82             : 
      83           0 :     if (rLeft.maArea.aEnd.Col() != rRight.maArea.aEnd.Col())
      84           0 :         return rLeft.maArea.aEnd.Col() < rRight.maArea.aEnd.Col();
      85             : 
      86           0 :     return rLeft.maArea.aEnd.Row() < rRight.maArea.aEnd.Row();
      87             : }
      88             : 
      89             : }
      90             : 
      91             : struct ScSlotData
      92             : {
      93             :     SCROW  nStartRow;   // first row of this segment
      94             :     SCROW  nStopRow;    // first row of next segment
      95             :     SCSIZE nSlice;      // slice size in this segment
      96             :     SCSIZE nCumulated;  // cumulated slots of previous segments
      97             : 
      98         312 :     ScSlotData( SCROW r1, SCROW r2, SCSIZE s, SCSIZE c ) : nStartRow(r1), nStopRow(r2), nSlice(s), nCumulated(c) {}
      99             : };
     100             : typedef ::std::vector< ScSlotData > ScSlotDistribution;
     101             : #if MAXROWCOUNT_DEFINE <= 65536
     102             : // Linear distribution.
     103             : static ScSlotDistribution aSlotDistribution( ScSlotData( 0, MAXROWCOUNT, BCA_SLOT_ROWS, 0));
     104             : static SCSIZE nBcaSlotsRow = BCA_SLOTS_ROW;
     105             : static SCSIZE nBcaSlots = BCA_SLOTS_DEFINE;
     106             : #else
     107             : // Logarithmic or any other distribution.
     108             : // Upper sheet part usually is more populated and referenced and gets fine
     109             : // grained resolution, larger data in larger hunks.
     110             : // Could be further enhanced by also applying a different distribution of
     111             : // column slots.
     112          52 : static SCSIZE initSlotDistribution( ScSlotDistribution & rSD, SCSIZE & rBSR )
     113             : {
     114          52 :     SCSIZE nSlots = 0;
     115          52 :     SCROW nRow1 = 0;
     116          52 :     SCROW nRow2 = 32*1024;
     117          52 :     SCSIZE nSlice = 128;
     118             :     // Must be sorted by row1,row2!
     119         416 :     while (nRow2 <= MAXROWCOUNT)
     120             :     {
     121         312 :         rSD.push_back( ScSlotData( nRow1, nRow2, nSlice, nSlots));
     122         312 :         nSlots += (nRow2 - nRow1) / nSlice;
     123         312 :         nRow1 = nRow2;
     124         312 :         nRow2 *= 2;
     125         312 :         nSlice *= 2;
     126             :     }
     127          52 :     rBSR = nSlots;
     128          52 :     return nSlots;
     129             : }
     130          52 : static ScSlotDistribution aSlotDistribution;
     131             : static SCSIZE nBcaSlotsRow;
     132          52 : static SCSIZE nBcaSlots = initSlotDistribution( aSlotDistribution, nBcaSlotsRow) * BCA_SLOTS_COL;
     133             : // Ensure that all static variables are initialized with this one call.
     134             : #endif
     135             : 
     136        3788 : ScBroadcastArea::ScBroadcastArea( const ScRange& rRange ) :
     137             :     pUpdateChainNext(NULL),
     138             :     aRange(rRange),
     139             :     nRefCount(0),
     140             :     mbInUpdateChain(false),
     141        3788 :     mbGroupListening(false) {}
     142             : 
     143        1549 : ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
     144             :         ScBroadcastAreaSlotMachine* pBASMa ) :
     145             :     aTmpSeekBroadcastArea( ScRange()),
     146             :     pDoc( pDocument ),
     147             :     pBASM( pBASMa ),
     148             :     mbInBroadcastIteration( false),
     149        1549 :     mbHasErasedArea(false)
     150             : {
     151        1549 : }
     152             : 
     153        3080 : ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
     154             : {
     155       10740 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     156        9200 :             aIter != aBroadcastAreaTbl.end(); /* none */)
     157             :     {
     158             :         // Prevent hash from accessing dangling pointer in case area is
     159             :         // deleted.
     160        3060 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     161             :         // Erase all so no hash will be accessed upon destruction of the
     162             :         // unordered_map.
     163        3060 :         aBroadcastAreaTbl.erase( aIter++);
     164        3060 :         if (!pArea->DecRef())
     165        1820 :             delete pArea;
     166             :     }
     167        1540 : }
     168             : 
     169        8097 : bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
     170             : {
     171        8097 :     if ( pDoc->GetHardRecalcState() )
     172           4 :         return true;
     173        8093 :     if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
     174             :     {   // this is more hypothetical now, check existed for old SV_PTRARR_SORT
     175           0 :         if ( !pDoc->GetHardRecalcState() )
     176             :         {
     177           0 :             SfxObjectShell* pShell = pDoc->GetDocumentShell();
     178             :             OSL_ENSURE( pShell, "Missing DocShell :-/" );
     179             : 
     180           0 :             if ( pShell )
     181           0 :                 pShell->SetError( SCWARN_CORE_HARD_RECALC, OUString( OSL_LOG_PREFIX ) );
     182             : 
     183           0 :             pDoc->SetAutoCalc( false );
     184           0 :             pDoc->SetHardRecalcState( true );
     185             :         }
     186           0 :         return true;
     187             :     }
     188        8093 :     return false;
     189             : }
     190             : 
     191        6852 : bool ScBroadcastAreaSlot::StartListeningArea(
     192             :     const ScRange& rRange, bool bGroupListening, SvtListener* pListener, ScBroadcastArea*& rpArea )
     193             : {
     194        6852 :     bool bNewArea = false;
     195             :     OSL_ENSURE(pListener, "StartListeningArea: pListener Null");
     196        6852 :     if (CheckHardRecalcStateCondition())
     197           4 :         return false;
     198        6848 :     if ( !rpArea )
     199             :     {
     200             :         // Even if most times the area doesn't exist yet and immediately trying
     201             :         // to new and insert it would save an attempt to find it, on mass
     202             :         // operations like identical large [HV]LOOKUP() areas the new/delete
     203             :         // would add quite some penalty for all but the first formula cell.
     204        6848 :         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange, bGroupListening));
     205        6848 :         if (aIter != aBroadcastAreaTbl.end())
     206        4609 :             rpArea = (*aIter).mpArea;
     207             :         else
     208             :         {
     209        2239 :             rpArea = new ScBroadcastArea( rRange);
     210        2239 :             rpArea->SetGroupListening(bGroupListening);
     211        2239 :             if (aBroadcastAreaTbl.insert( rpArea).second)
     212             :             {
     213        2239 :                 rpArea->IncRef();
     214        2239 :                 bNewArea = true;
     215             :             }
     216             :             else
     217             :             {
     218             :                 OSL_FAIL("StartListeningArea: area not found and not inserted in slot?!?");
     219           0 :                 delete rpArea;
     220           0 :                 rpArea = 0;
     221             :             }
     222             :         }
     223        6848 :         if (rpArea)
     224        6848 :             pListener->StartListening( rpArea->GetBroadcaster());
     225             :     }
     226             :     else
     227             :     {
     228           0 :         if (aBroadcastAreaTbl.insert( rpArea).second)
     229           0 :             rpArea->IncRef();
     230             :     }
     231        6848 :     return bNewArea;
     232             : }
     233             : 
     234        1245 : void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea* pArea )
     235             : {
     236             :     OSL_ENSURE( pArea, "InsertListeningArea: pArea NULL");
     237        1245 :     if (CheckHardRecalcStateCondition())
     238        1245 :         return;
     239        1245 :     if (aBroadcastAreaTbl.insert( pArea).second)
     240        1245 :         pArea->IncRef();
     241             : }
     242             : 
     243             : // If rpArea != NULL then no listeners are stopped, only the area is removed
     244             : // and the reference count decremented.
     245         606 : void ScBroadcastAreaSlot::EndListeningArea(
     246             :     const ScRange& rRange, bool bGroupListening, SvtListener* pListener, ScBroadcastArea*& rpArea )
     247             : {
     248             :     OSL_ENSURE(pListener, "EndListeningArea: pListener Null");
     249         606 :     if ( !rpArea )
     250             :     {
     251         606 :         ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange, bGroupListening));
     252         606 :         if (aIter == aBroadcastAreaTbl.end() || isMarkedErased( aIter))
     253          43 :             return;
     254         563 :         rpArea = (*aIter).mpArea;
     255         563 :         pListener->EndListening( rpArea->GetBroadcaster() );
     256         563 :         if ( !rpArea->GetBroadcaster().HasListeners() )
     257             :         {   // if nobody is listening we can dispose it
     258         337 :             if (rpArea->GetRef() == 1)
     259         337 :                 rpArea = NULL;      // will be deleted by erase
     260         337 :             EraseArea( aIter);
     261             :         }
     262             :     }
     263             :     else
     264             :     {
     265           0 :         if (rpArea && !rpArea->GetBroadcaster().HasListeners())
     266             :         {
     267           0 :             ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange, bGroupListening));
     268           0 :             if (aIter == aBroadcastAreaTbl.end() || isMarkedErased( aIter))
     269           0 :                 return;
     270             :             OSL_ENSURE( (*aIter).mpArea == rpArea, "EndListeningArea: area pointer mismatch");
     271           0 :             if (rpArea->GetRef() == 1)
     272           0 :                 rpArea = NULL;      // will be deleted by erase
     273           0 :             EraseArea( aIter);
     274             :         }
     275             :     }
     276             : }
     277             : 
     278        7454 : ScBroadcastAreas::iterator ScBroadcastAreaSlot::FindBroadcastArea(
     279             :         const ScRange& rRange, bool bGroupListening )
     280             : {
     281        7454 :     aTmpSeekBroadcastArea.UpdateRange( rRange);
     282        7454 :     aTmpSeekBroadcastArea.SetGroupListening(bGroupListening);
     283        7454 :     return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
     284             : }
     285             : 
     286             : namespace {
     287             : 
     288          32 : void broadcastRangeByCell( SvtBroadcaster& rBC, const ScRange& rRange, sal_uLong nHint )
     289             : {
     290          32 :     ScHint aHint(nHint, ScAddress());
     291          32 :     ScAddress& rPos = aHint.GetAddress();
     292          64 :     for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
     293             :     {
     294          32 :         rPos.SetTab(nTab);
     295          82 :         for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
     296             :         {
     297          50 :             rPos.SetCol(nCol);
     298         132 :             for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
     299             :             {
     300          82 :                 rPos.SetRow(nRow);
     301          82 :                 rBC.Broadcast(aHint);
     302             :             }
     303             :         }
     304          32 :     }
     305          32 : }
     306             : 
     307             : }
     308             : 
     309          34 : bool ScBroadcastAreaSlot::AreaBroadcast( const ScRange& rRange, sal_uLong nHint )
     310             : {
     311          34 :     if (aBroadcastAreaTbl.empty())
     312           3 :         return false;
     313             : 
     314          31 :     bool bInBroadcast = mbInBroadcastIteration;
     315          31 :     mbInBroadcastIteration = true;
     316          31 :     bool bIsBroadcasted = false;
     317             : 
     318          31 :     mbHasErasedArea = false;
     319             : 
     320         132 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     321          31 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     322             :     {
     323          70 :         if (mbHasErasedArea && isMarkedErased( aIter))
     324          13 :             continue;
     325             : 
     326          70 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     327          70 :         const ScRange& rAreaRange = pArea->GetRange();
     328             : 
     329             :         // Take the intersection of the area range and the broadcast range.
     330          70 :         ScRange aIntersection = rAreaRange.Intersection(rRange);
     331          70 :         if (!aIntersection.IsValid())
     332          13 :             continue;
     333             : 
     334          57 :         if (pArea->IsGroupListening())
     335             :         {
     336           5 :             if (pBASM->IsInBulkBroadcast())
     337             :             {
     338           5 :                 pBASM->InsertBulkGroupArea(pArea, aIntersection);
     339             :             }
     340             :             else
     341             :             {
     342           0 :                 broadcastRangeByCell(pArea->GetBroadcaster(), aIntersection, nHint);
     343           0 :                 bIsBroadcasted = true;
     344             :             }
     345             :         }
     346          52 :         else if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
     347             :         {
     348          32 :             broadcastRangeByCell(pArea->GetBroadcaster(), aIntersection, nHint);
     349          32 :             bIsBroadcasted = true;
     350             :         }
     351             :     }
     352             : 
     353          31 :     mbInBroadcastIteration = bInBroadcast;
     354             : 
     355             :     // A Notify() during broadcast may call EndListeningArea() and thus dispose
     356             :     // an area if it was the last listener, which would invalidate an iterator
     357             :     // pointing to it, hence the real erase is done afterwards.
     358          31 :     FinallyEraseAreas();
     359             : 
     360          31 :     return bIsBroadcasted;
     361             : }
     362             : 
     363        2329 : bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint)
     364             : {
     365        2329 :     if (aBroadcastAreaTbl.empty())
     366         414 :         return false;
     367             : 
     368        1915 :     bool bInBroadcast = mbInBroadcastIteration;
     369        1915 :     mbInBroadcastIteration = true;
     370        1915 :     bool bIsBroadcasted = false;
     371             : 
     372        1915 :     mbHasErasedArea = false;
     373             : 
     374        1915 :     const ScAddress& rAddress = rHint.GetAddress();
     375        8935 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     376        1915 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     377             :     {
     378        5105 :         if (mbHasErasedArea && isMarkedErased( aIter))
     379           0 :             continue;
     380             : 
     381        5105 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     382        5105 :         const ScRange& rAreaRange = pArea->GetRange();
     383        5105 :         if (rAreaRange.In( rAddress))
     384             :         {
     385         535 :             if (pArea->IsGroupListening())
     386             :             {
     387          53 :                 if (pBASM->IsInBulkBroadcast())
     388             :                 {
     389          53 :                     pBASM->InsertBulkGroupArea(pArea, rAddress);
     390             :                 }
     391             :                 else
     392             :                 {
     393           0 :                     pArea->GetBroadcaster().Broadcast( rHint);
     394           0 :                     bIsBroadcasted = true;
     395             :                 }
     396             :             }
     397         482 :             else if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
     398             :             {
     399         310 :                 pArea->GetBroadcaster().Broadcast( rHint);
     400         310 :                 bIsBroadcasted = true;
     401             :             }
     402             :         }
     403             :     }
     404             : 
     405        1915 :     mbInBroadcastIteration = bInBroadcast;
     406             : 
     407             :     // A Notify() during broadcast may call EndListeningArea() and thus dispose
     408             :     // an area if it was the last listener, which would invalidate an iterator
     409             :     // pointing to it, hence the real erase is done afterwards.
     410        1915 :     FinallyEraseAreas();
     411             : 
     412        1915 :     return bIsBroadcasted;
     413             : }
     414             : 
     415          41 : void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
     416             : {
     417          41 :     if (aBroadcastAreaTbl.empty())
     418          42 :         return;
     419         222 :     for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     420         182 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     421             :     {
     422          51 :         const ScRange& rAreaRange = (*aIter).mpArea->GetRange();
     423          51 :         if (rRange.In( rAreaRange))
     424             :         {
     425          10 :             ScBroadcastArea* pArea = (*aIter).mpArea;
     426          10 :             aBroadcastAreaTbl.erase( aIter++);  // erase before modifying
     427          10 :             if (!pArea->DecRef())
     428             :             {
     429          10 :                 if (pBASM->IsInBulkBroadcast())
     430           0 :                     pBASM->RemoveBulkArea( pArea);
     431          10 :                 delete pArea;
     432             :             }
     433             :         }
     434             :         else
     435          41 :             ++aIter;
     436             :     }
     437             : }
     438             : 
     439         102 : void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
     440             :         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     441             : {
     442         102 :     if (aBroadcastAreaTbl.empty())
     443         144 :         return;
     444             : 
     445             :     SCCOL nCol1, nCol2, theCol1, theCol2;
     446             :     SCROW nRow1, nRow2, theRow1, theRow2;
     447             :     SCTAB nTab1, nTab2, theTab1, theTab2;
     448          60 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
     449         306 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     450         246 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     451             :     {
     452          63 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     453          63 :         if ( pArea->IsInUpdateChain() )
     454             :         {
     455           0 :             aBroadcastAreaTbl.erase( aIter++);
     456           0 :             pArea->DecRef();
     457             :         }
     458             :         else
     459             :         {
     460          63 :             pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
     461          63 :             if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     462             :                     nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     463          63 :                     theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
     464             :             {
     465          49 :                 aBroadcastAreaTbl.erase( aIter++);
     466          49 :                 pArea->DecRef();
     467          49 :                 if (pBASM->IsInBulkBroadcast())
     468           0 :                     pBASM->RemoveBulkArea( pArea);
     469          49 :                 pArea->SetInUpdateChain( true );
     470          49 :                 ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
     471          49 :                 if ( pUC )
     472           0 :                     pUC->SetUpdateChainNext( pArea );
     473             :                 else    // no tail => no head
     474          49 :                     pBASM->SetUpdateChain( pArea );
     475          49 :                 pBASM->SetEOUpdateChain( pArea );
     476             :             }
     477             :             else
     478          14 :                 ++aIter;
     479             :         }
     480             :     }
     481             : }
     482             : 
     483           0 : void ScBroadcastAreaSlot::UpdateRemoveArea( ScBroadcastArea* pArea )
     484             : {
     485           0 :     ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.find( pArea));
     486           0 :     if (aIter == aBroadcastAreaTbl.end())
     487           0 :         return;
     488           0 :     if ((*aIter).mpArea != pArea)
     489             :         OSL_FAIL( "UpdateRemoveArea: area pointer mismatch");
     490             :     else
     491             :     {
     492           0 :         aBroadcastAreaTbl.erase( aIter);
     493           0 :         pArea->DecRef();
     494             :     }
     495             : }
     496             : 
     497          49 : void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
     498             : {
     499             :     ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
     500          49 :         aBroadcastAreaTbl.insert( pArea);
     501          49 :     if (aPair.second)
     502          48 :         pArea->IncRef();
     503             :     else
     504             :     {
     505             :         // Identical area already exists, add listeners.
     506           1 :         ScBroadcastArea* pTarget = (*(aPair.first)).mpArea;
     507           1 :         if (pArea != pTarget)
     508             :         {
     509           1 :             SvtBroadcaster& rTarget = pTarget->GetBroadcaster();
     510           1 :             SvtBroadcaster::ListenersType& rListeners = pArea->GetBroadcaster().GetAllListeners();
     511           1 :             SvtBroadcaster::ListenersType::iterator it = rListeners.begin(), itEnd = rListeners.end();
     512           1 :             for (; it != itEnd; ++it)
     513             :             {
     514           0 :                 SvtListener& rListener = **it;
     515           0 :                 rListener.StartListening(rTarget);
     516             :             }
     517             :         }
     518             :     }
     519          49 : }
     520             : 
     521         339 : void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator& rIter )
     522             : {
     523         339 :     if (mbInBroadcastIteration)
     524             :     {
     525           2 :         (*rIter).mbErasure = true;      // mark for erasure
     526           2 :         mbHasErasedArea = true; // at least one area is marked for erasure.
     527           2 :         pBASM->PushAreaToBeErased( this, rIter);
     528             :     }
     529             :     else
     530             :     {
     531         337 :         ScBroadcastArea* pArea = (*rIter).mpArea;
     532         337 :         aBroadcastAreaTbl.erase( rIter);
     533         337 :         if (!pArea->DecRef())
     534         337 :             delete pArea;
     535             :     }
     536         339 : }
     537             : 
     538          21 : void ScBroadcastAreaSlot::GetAllListeners(
     539             :     const ScRange& rRange, std::vector<sc::AreaListener>& rListeners,
     540             :     sc::AreaOverlapType eType, sc::ListenerGroupType eGroup )
     541             : {
     542          68 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
     543          21 :             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
     544             :     {
     545          26 :         if (isMarkedErased( aIter))
     546           7 :             continue;
     547             : 
     548          26 :         ScBroadcastArea* pArea = (*aIter).mpArea;
     549          26 :         const ScRange& rAreaRange = pArea->GetRange();
     550          26 :         switch (eGroup)
     551             :         {
     552             :             case sc::ListenerSingle:
     553           0 :                 if (pArea->IsGroupListening())
     554           0 :                     continue;
     555           0 :             break;
     556             :             case sc::ListenerGroup:
     557           4 :                 if (!pArea->IsGroupListening())
     558           0 :                     continue;
     559           4 :             break;
     560             :             case sc::ListenerBoth:
     561             :             default:
     562             :                 ;
     563             :         }
     564             : 
     565          26 :         switch (eType)
     566             :         {
     567             :             case sc::AreaInside:
     568          17 :                 if (!rRange.In(rAreaRange))
     569             :                     // The range needs to be fully inside specified range.
     570           3 :                     continue;
     571          14 :                 break;
     572             :             case sc::AreaPartialOverlap:
     573           5 :                 if (!rRange.Intersects(rAreaRange) || rRange.In(rAreaRange))
     574             :                     // The range needs to be only partially overlapping.
     575           4 :                     continue;
     576           1 :                 break;
     577             :             case sc::AreaInsideOrOverlap:
     578           4 :                 if (!rRange.Intersects(rAreaRange))
     579             :                     // The range needs to be partially overlapping or fully inside.
     580           0 :                     continue;
     581           4 :                 break;
     582             :             case sc::OneRowInsideArea:
     583           0 :                 if (rAreaRange.aStart.Row() != rAreaRange.aEnd.Row() || !rRange.In(rAreaRange))
     584             :                     // The range needs to be one single row and fully inside
     585             :                     // specified range.
     586           0 :                     continue;
     587           0 :                 break;
     588             :             case sc::OneColumnInsideArea:
     589           0 :                 if (rAreaRange.aStart.Col() != rAreaRange.aEnd.Col() || !rRange.In(rAreaRange))
     590             :                     // The range needs to be one single column and fully inside
     591             :                     // specified range.
     592           0 :                     continue;
     593           0 :                 break;
     594             :         }
     595             : 
     596          19 :         SvtBroadcaster::ListenersType& rLst = pArea->GetBroadcaster().GetAllListeners();
     597          19 :         SvtBroadcaster::ListenersType::iterator itLst = rLst.begin(), itLstEnd = rLst.end();
     598          37 :         for (; itLst != itLstEnd; ++itLst)
     599             :         {
     600          18 :             sc::AreaListener aEntry;
     601          18 :             aEntry.maArea = rAreaRange;
     602          18 :             aEntry.mbGroupListening = pArea->IsGroupListening();
     603          18 :             aEntry.mpListener = *itLst;
     604          18 :             rListeners.push_back(aEntry);
     605             :         }
     606             :     }
     607          21 : }
     608             : 
     609             : #if DEBUG_AREA_BROADCASTER
     610             : void ScBroadcastAreaSlot::Dump() const
     611             : {
     612             :     ScBroadcastAreas::const_iterator it = aBroadcastAreaTbl.begin(), itEnd = aBroadcastAreaTbl.end();
     613             :     for (; it != itEnd; ++it)
     614             :     {
     615             :         const ScBroadcastAreaEntry& rEntry = *it;
     616             :         const ScBroadcastArea* pArea = rEntry.mpArea;
     617             :         const SvtBroadcaster& rBC = pArea->GetBroadcaster();
     618             :         const SvtBroadcaster::ListenersType& rListeners = rBC.GetAllListeners();
     619             :         size_t n = rListeners.size();
     620             : 
     621             :         cout << "  * range: " << rtl::OUStringToOString(pArea->GetRange().Format(SCA_VALID|SCA_TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr()
     622             :             << ", group: " << pArea->IsGroupListening()
     623             :             << ", listener count: " << n << endl;
     624             : 
     625             :         for (size_t i = 0; i < n; ++i)
     626             :         {
     627             :             const ScFormulaCell* pFC = dynamic_cast<const ScFormulaCell*>(rListeners[i]);
     628             :             if (pFC)
     629             :             {
     630             :                 cout << "    * listener: formula cell: "
     631             :                      << rtl::OUStringToOString(pFC->aPos.Format(SCA_VALID|SCA_TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr()
     632             :                      << endl;
     633             :                 continue;
     634             :             }
     635             : 
     636             :             const sc::FormulaGroupAreaListener* pFGListener = dynamic_cast<const sc::FormulaGroupAreaListener*>(rListeners[i]);
     637             :             if (pFGListener)
     638             :             {
     639             :                 cout << "    * listener: formula group: (pos: "
     640             :                      << rtl::OUStringToOString(pFGListener->getTopCellPos().Format(SCA_VALID | SCA_TAB_3D, pDoc), RTL_TEXTENCODING_UTF8).getStr()
     641             :                      << ", length: " << pFGListener->getGroupLength()
     642             :                      << ")" << endl;
     643             :                 continue;
     644             :             }
     645             : 
     646             :             cout << "    * listener: unknown" << endl;
     647             :         }
     648             :     }
     649             : }
     650             : #endif
     651             : 
     652        1946 : void ScBroadcastAreaSlot::FinallyEraseAreas()
     653             : {
     654        1946 :     pBASM->FinallyEraseAreas( this);
     655        1946 : }
     656             : 
     657             : // --- ScBroadcastAreaSlotMachine -------------------------------------
     658             : 
     659         304 : ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
     660             : {
     661         304 :     ppSlots = new ScBroadcastAreaSlot* [ nBcaSlots ];
     662         304 :     memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
     663         304 : }
     664             : 
     665         298 : ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
     666             : {
     667    17089108 :     for ( ScBroadcastAreaSlot** pp = ppSlots + nBcaSlots; --pp >= ppSlots; /* nothing */ )
     668             :     {
     669    17088512 :         if (*pp)
     670        1540 :             delete *pp;
     671             :     }
     672         298 :     delete [] ppSlots;
     673         298 : }
     674             : 
     675        1325 : ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
     676             :         ScDocument* pDocument ) :
     677             :     pBCAlways( NULL ),
     678             :     pDoc( pDocument ),
     679             :     pUpdateChain( NULL ),
     680             :     pEOUpdateChain( NULL ),
     681        1325 :     nInBulkBroadcast( 0 )
     682             : {
     683        1325 : }
     684             : 
     685        2588 : ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
     686             : {
     687        4743 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.begin());
     688        3162 :             iTab != aTableSlotsMap.end(); ++iTab)
     689             :     {
     690         287 :         delete (*iTab).second;
     691             :     }
     692        1294 :     delete pBCAlways;
     693             :     // Areas to-be-erased still present is a serious error in handling, but at
     694             :     // this stage there's nothing we can do anymore.
     695             :     SAL_WARN_IF( !maAreasToBeErased.empty(), "sc", "ScBroadcastAreaSlotMachine::dtor: maAreasToBeErased not empty");
     696        1294 : }
     697             : 
     698       28492 : inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
     699             :         const ScAddress& rAddress )
     700             : {
     701       28492 :     SCROW nRow = rAddress.Row();
     702       28492 :     SCCOL nCol = rAddress.Col();
     703       28492 :     if ( !ValidRow(nRow) || !ValidCol(nCol) )
     704             :     {
     705             :         OSL_FAIL( "Row/Col invalid, using first slot!" );
     706           0 :         return 0;
     707             :     }
     708       29784 :     for (size_t i=0; i < aSlotDistribution.size(); ++i)
     709             :     {
     710       29784 :         if (nRow < aSlotDistribution[i].nStopRow)
     711             :         {
     712       28492 :             const ScSlotData& rSD = aSlotDistribution[i];
     713       56984 :             return rSD.nCumulated +
     714       28492 :                 (static_cast<SCSIZE>(nRow - rSD.nStartRow)) / rSD.nSlice +
     715       28492 :                 static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * nBcaSlotsRow;
     716             :         }
     717             :     }
     718             :     OSL_FAIL( "No slot found, using last!" );
     719           0 :     return nBcaSlots - 1;
     720             : }
     721             : 
     722        7705 : void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
     723             :         SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak )
     724             : {
     725        7705 :     rStart = ComputeSlotOffset( rRange.aStart );
     726        7705 :     rEnd = ComputeSlotOffset( rRange.aEnd );
     727             :     // count of row slots per column minus one
     728             :     rRowBreak = ComputeSlotOffset(
     729        7705 :         ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
     730        7705 : }
     731             : 
     732      250102 : inline void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
     733             :         SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE const & nRowBreak )
     734             : {
     735      250102 :     if ( nOff < nBreak )
     736             :     {
     737      241098 :         ++nOff;
     738      241098 :         ++pp;
     739             :     }
     740             :     else
     741             :     {
     742        9004 :         nStart += nBcaSlotsRow;
     743        9004 :         nOff = nStart;
     744        9004 :         pp = ppSlots + nOff;
     745        9004 :         nBreak = nOff + nRowBreak;
     746             :     }
     747      250102 : }
     748             : 
     749        6839 : void ScBroadcastAreaSlotMachine::StartListeningArea(
     750             :     const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
     751             : {
     752        6839 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     753             :     {
     754          31 :         if ( !pBCAlways )
     755          10 :             pBCAlways = new SvtBroadcaster;
     756          31 :         pListener->StartListening( *pBCAlways );
     757             :     }
     758             :     else
     759             :     {
     760        6808 :         bool bDone = false;
     761       27320 :         for (SCTAB nTab = rRange.aStart.Tab();
     762       13660 :                 !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
     763             :         {
     764        6852 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     765        6852 :             if (iTab == aTableSlotsMap.end())
     766             :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
     767         304 :                             nTab, new TableSlots)).first;
     768        6852 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     769             :             SCSIZE nStart, nEnd, nRowBreak;
     770        6852 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     771        6852 :             SCSIZE nOff = nStart;
     772        6852 :             SCSIZE nBreak = nOff + nRowBreak;
     773        6852 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     774        6852 :             ScBroadcastArea* pArea = NULL;
     775       21801 :             while ( !bDone && nOff <= nEnd )
     776             :             {
     777        8097 :                 if ( !*pp )
     778        1549 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
     779        8097 :                 if (!pArea)
     780             :                 {
     781             :                     // If the call to StartListeningArea didn't create the
     782             :                     // ScBroadcastArea, listeners were added to an already
     783             :                     // existing identical area that doesn't need to be inserted
     784             :                     // to slots again.
     785        6852 :                     if (!(*pp)->StartListeningArea( rRange, bGroupListening, pListener, pArea))
     786        4613 :                         bDone = true;
     787             :                 }
     788             :                 else
     789        1245 :                     (*pp)->InsertListeningArea( pArea);
     790        8097 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     791             :             }
     792             :         }
     793             :     }
     794        6839 : }
     795             : 
     796       12293 : void ScBroadcastAreaSlotMachine::EndListeningArea(
     797             :     const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
     798             : {
     799       12293 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     800             :     {
     801       11737 :         if ( pBCAlways )
     802             :         {
     803        1431 :             pListener->EndListening( *pBCAlways);
     804        1431 :             if (!pBCAlways->HasListeners())
     805             :             {
     806           1 :                 delete pBCAlways;
     807           1 :                 pBCAlways = NULL;
     808             :             }
     809             :         }
     810             :     }
     811             :     else
     812             :     {
     813         556 :         SCTAB nEndTab = rRange.aEnd.Tab();
     814        3486 :         for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     815        3486 :                 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     816             :         {
     817         606 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     818             :             SCSIZE nStart, nEnd, nRowBreak;
     819         606 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     820         606 :             SCSIZE nOff = nStart;
     821         606 :             SCSIZE nBreak = nOff + nRowBreak;
     822         606 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     823         606 :             ScBroadcastArea* pArea = NULL;
     824         606 :             if (nOff == 0 && nEnd == nBcaSlots-1)
     825             :             {
     826             :                 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     827             :                 // happen for insertion and deletion of sheets.
     828           0 :                 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     829           0 :                 do
     830             :                 {
     831           0 :                     if ( *pp )
     832           0 :                         (*pp)->EndListeningArea( rRange, bGroupListening, pListener, pArea);
     833           0 :                 } while (++pp < pStop);
     834             :             }
     835             :             else
     836             :             {
     837        1818 :                 while ( nOff <= nEnd )
     838             :                 {
     839         606 :                     if ( *pp )
     840         606 :                         (*pp)->EndListeningArea( rRange, bGroupListening, pListener, pArea);
     841         606 :                     ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     842             :                 }
     843             :             }
     844             :         }
     845             :     }
     846       12293 : }
     847             : 
     848         197 : bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScRange& rRange, sal_uLong nHint )
     849             : {
     850         197 :     bool bBroadcasted = false;
     851         197 :     SCTAB nEndTab = rRange.aEnd.Tab();
     852         693 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     853         693 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     854             :     {
     855          34 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     856             :         SCSIZE nStart, nEnd, nRowBreak;
     857          34 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     858          34 :         SCSIZE nOff = nStart;
     859          34 :         SCSIZE nBreak = nOff + nRowBreak;
     860          34 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     861         102 :         while ( nOff <= nEnd )
     862             :         {
     863          34 :             if ( *pp )
     864          34 :                 bBroadcasted |= (*pp)->AreaBroadcast( rRange, nHint );
     865          34 :             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     866             :         }
     867             :     }
     868         197 :     return bBroadcasted;
     869             : }
     870             : 
     871       73074 : bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
     872             : {
     873       73074 :     const ScAddress& rAddress = rHint.GetAddress();
     874       73074 :     if ( rAddress == BCA_BRDCST_ALWAYS )
     875             :     {
     876       15729 :         if ( pBCAlways )
     877             :         {
     878           8 :             pBCAlways->Broadcast( rHint );
     879           8 :             return true;
     880             :         }
     881             :         else
     882       15721 :             return false;
     883             :     }
     884             :     else
     885             :     {
     886       57345 :         TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
     887       57345 :         if (iTab == aTableSlotsMap.end())
     888       51968 :             return false;
     889        5377 :         ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
     890       10754 :                 ComputeSlotOffset( rAddress));
     891        5377 :         if ( pSlot )
     892        2329 :             return pSlot->AreaBroadcast( rHint );
     893             :         else
     894        3048 :             return false;
     895             :     }
     896             : }
     897             : 
     898         180 : void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
     899             :         const ScRange& rRange )
     900             : {
     901         180 :     SCTAB nEndTab = rRange.aEnd.Tab();
     902         663 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     903         663 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     904             :     {
     905          41 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     906             :         SCSIZE nStart, nEnd, nRowBreak;
     907          41 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     908          41 :         SCSIZE nOff = nStart;
     909          41 :         SCSIZE nBreak = nOff + nRowBreak;
     910          41 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     911          41 :         if (nOff == 0 && nEnd == nBcaSlots-1)
     912             :         {
     913             :             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     914             :             // happen for insertion and deletion of sheets.
     915          14 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     916     1605604 :             do
     917             :             {
     918      802802 :                 if ( *pp )
     919          14 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     920     1605618 :             } while (++pp < pStop);
     921             :         }
     922             :         else
     923             :         {
     924       10039 :             while ( nOff <= nEnd )
     925             :             {
     926        9985 :                 if ( *pp )
     927          27 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     928        9985 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     929             :             }
     930             :         }
     931             :     }
     932         180 : }
     933             : 
     934             : // for all affected: remove, chain, update range, insert, and maybe delete
     935         330 : void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
     936             :         UpdateRefMode eUpdateRefMode,
     937             :         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     938             : {
     939             :     // remove affected and put in chain
     940         330 :     SCTAB nEndTab = rRange.aEnd.Tab();
     941        1296 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     942        1296 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     943             :     {
     944         102 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     945             :         SCSIZE nStart, nEnd, nRowBreak;
     946         102 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     947         102 :         SCSIZE nOff = nStart;
     948         102 :         SCSIZE nBreak = nOff + nRowBreak;
     949         102 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     950         102 :         if (nOff == 0 && nEnd == nBcaSlots-1)
     951             :         {
     952             :             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     953             :             // happen for insertion and deletion of sheets.
     954          98 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     955    11239228 :             do
     956             :             {
     957     5619614 :                 if ( *pp )
     958          98 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     959    11239326 :             } while (++pp < pStop);
     960             :         }
     961             :         else
     962             :         {
     963        1928 :             while ( nOff <= nEnd )
     964             :             {
     965        1920 :                 if ( *pp )
     966           4 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     967        1920 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     968             :             }
     969             :         }
     970             :     }
     971             : 
     972             :     // Updating an area's range will modify the hash key, remove areas from all
     973             :     // affected slots. Will be reinserted later with the updated range.
     974         330 :     ScBroadcastArea* pChain = pUpdateChain;
     975         709 :     while (pChain)
     976             :     {
     977          49 :         ScBroadcastArea* pArea = pChain;
     978          49 :         pChain = pArea->GetUpdateChainNext();
     979          49 :         ScRange aRange( pArea->GetRange());
     980             :         // remove from slots
     981          49 :         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab() && pArea->GetRef(); ++nTab)
     982             :         {
     983           0 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     984           0 :             if (iTab == aTableSlotsMap.end())
     985             :             {
     986             :                 OSL_FAIL( "UpdateBroadcastAreas: Where's the TableSlot?!?");
     987           0 :                 continue;   // for
     988             :             }
     989           0 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     990             :             SCSIZE nStart, nEnd, nRowBreak;
     991           0 :             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
     992           0 :             SCSIZE nOff = nStart;
     993           0 :             SCSIZE nBreak = nOff + nRowBreak;
     994           0 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     995           0 :             while ( nOff <= nEnd && pArea->GetRef() )
     996             :             {
     997           0 :                 if (*pp)
     998           0 :                     (*pp)->UpdateRemoveArea( pArea);
     999           0 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
    1000             :             }
    1001             :         }
    1002             : 
    1003             :     }
    1004             : 
    1005             :     // shift sheets
    1006         330 :     if (nDz)
    1007             :     {
    1008         162 :         if (nDz < 0)
    1009             :         {
    1010         100 :             TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
    1011         100 :             TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab() - nDz));
    1012             :             // Remove sheets, if any, iDel or/and iTab may as well point to end().
    1013         211 :             while (iDel != iTab)
    1014             :             {
    1015          11 :                 delete (*iDel).second;
    1016          11 :                 aTableSlotsMap.erase( iDel++);
    1017             :             }
    1018             :             // shift remaining down
    1019         219 :             while (iTab != aTableSlotsMap.end())
    1020             :             {
    1021          19 :                 SCTAB nTab = (*iTab).first + nDz;
    1022          19 :                 aTableSlotsMap[nTab] = (*iTab).second;
    1023          19 :                 aTableSlotsMap.erase( iTab++);
    1024             :             }
    1025             :         }
    1026             :         else
    1027             :         {
    1028          62 :             TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
    1029          62 :             if (iStop != aTableSlotsMap.end())
    1030             :             {
    1031           8 :                 bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
    1032           8 :                 if (!bStopIsBegin)
    1033           2 :                     --iStop;
    1034           8 :                 TableSlotsMap::iterator iTab( aTableSlotsMap.end());
    1035           8 :                 --iTab;
    1036          26 :                 while (iTab != iStop)
    1037             :                 {
    1038          10 :                     SCTAB nTab = (*iTab).first + nDz;
    1039          10 :                     aTableSlotsMap[nTab] = (*iTab).second;
    1040          10 :                     aTableSlotsMap.erase( iTab--);
    1041             :                 }
    1042             :                 // Shift the very first, iTab==iStop in this case.
    1043           8 :                 if (bStopIsBegin)
    1044             :                 {
    1045           6 :                     SCTAB nTab = (*iTab).first + nDz;
    1046           6 :                     aTableSlotsMap[nTab] = (*iTab).second;
    1047           6 :                     aTableSlotsMap.erase( iStop);
    1048             :                 }
    1049             :             }
    1050             :         }
    1051             :     }
    1052             : 
    1053             :     // work off chain
    1054             :     SCCOL nCol1, nCol2, theCol1, theCol2;
    1055             :     SCROW nRow1, nRow2, theRow1, theRow2;
    1056             :     SCTAB nTab1, nTab2, theTab1, theTab2;
    1057         330 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    1058         709 :     while ( pUpdateChain )
    1059             :     {
    1060          49 :         ScBroadcastArea* pArea = pUpdateChain;
    1061          49 :         ScRange aRange( pArea->GetRange());
    1062          49 :         pUpdateChain = pArea->GetUpdateChainNext();
    1063             : 
    1064             :         // update range
    1065          49 :         aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
    1066          49 :         if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
    1067             :                 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
    1068          49 :                 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
    1069             :         {
    1070          49 :             aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
    1071          49 :             pArea->UpdateRange( aRange );
    1072          49 :             pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) );   // for DDE
    1073             :         }
    1074             : 
    1075             :         // insert to slots
    1076          98 :         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
    1077             :         {
    1078          49 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
    1079          49 :             if (iTab == aTableSlotsMap.end())
    1080             :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
    1081           0 :                             nTab, new TableSlots)).first;
    1082          49 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
    1083             :             SCSIZE nStart, nEnd, nRowBreak;
    1084          49 :             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
    1085          49 :             SCSIZE nOff = nStart;
    1086          49 :             SCSIZE nBreak = nOff + nRowBreak;
    1087          49 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
    1088         147 :             while ( nOff <= nEnd )
    1089             :             {
    1090          49 :                 if (!*pp)
    1091           0 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
    1092          49 :                 (*pp)->UpdateInsert( pArea );
    1093          49 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
    1094             :             }
    1095             :         }
    1096             : 
    1097             :         // unchain
    1098          49 :         pArea->SetUpdateChainNext( NULL );
    1099          49 :         pArea->SetInUpdateChain( false );
    1100             : 
    1101             :         // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
    1102             :         // already executed in UpdateRemove().
    1103          49 :         if (!pArea->GetRef())
    1104           1 :             delete pArea;
    1105             :     }
    1106         330 :     pEOUpdateChain = NULL;
    1107         330 : }
    1108             : 
    1109       50923 : void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
    1110             : {
    1111       50923 :     ++nInBulkBroadcast;
    1112       50923 : }
    1113             : 
    1114       50923 : void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
    1115             : {
    1116       50923 :     if (nInBulkBroadcast > 0)
    1117             :     {
    1118       50923 :         if (--nInBulkBroadcast == 0)
    1119             :         {
    1120       48286 :             ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
    1121       48286 :             BulkBroadcastGroupAreas();
    1122             :         }
    1123             :     }
    1124       50923 : }
    1125             : 
    1126         402 : bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
    1127             : {
    1128         402 :     return aBulkBroadcastAreas.insert( pArea ).second;
    1129             : }
    1130             : 
    1131          58 : void ScBroadcastAreaSlotMachine::InsertBulkGroupArea( ScBroadcastArea* pArea, const ScRange& rRange )
    1132             : {
    1133          58 :     BulkGroupAreasType::iterator it = maBulkGroupAreas.lower_bound(pArea);
    1134          58 :     if (it == maBulkGroupAreas.end() || maBulkGroupAreas.key_comp()(pArea, it->first))
    1135             :     {
    1136             :         // Insert a new one.
    1137          14 :         it = maBulkGroupAreas.insert(it, pArea, new sc::ColumnSpanSet(false));
    1138             :     }
    1139             : 
    1140          58 :     sc::ColumnSpanSet* pSet = it->second;
    1141             :     assert(pSet);
    1142          58 :     pSet->set(rRange, true);
    1143          58 : }
    1144             : 
    1145       48286 : void ScBroadcastAreaSlotMachine::BulkBroadcastGroupAreas()
    1146             : {
    1147       48286 :     if (maBulkGroupAreas.empty())
    1148       96560 :         return;
    1149             : 
    1150          12 :     sc::BulkDataHint aHint(*pDoc, NULL);
    1151             : 
    1152          12 :     bool bBroadcasted = false;
    1153          12 :     BulkGroupAreasType::iterator it = maBulkGroupAreas.begin(), itEnd = maBulkGroupAreas.end();
    1154          26 :     for (; it != itEnd; ++it)
    1155             :     {
    1156          14 :         ScBroadcastArea* pArea = it->first;
    1157          14 :         const sc::ColumnSpanSet* pSpans = it->second;
    1158             :         assert(pArea);
    1159             :         assert(pSpans);
    1160          14 :         aHint.setSpans(pSpans);
    1161          14 :         pArea->GetBroadcaster().Broadcast(aHint);
    1162          14 :         bBroadcasted = true;
    1163             :     }
    1164             : 
    1165          12 :     maBulkGroupAreas.clear();
    1166          12 :     if (bBroadcasted)
    1167          12 :         pDoc->TrackFormulas();
    1168             : }
    1169             : 
    1170           0 : size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea* pArea )
    1171             : {
    1172           0 :     return aBulkBroadcastAreas.erase( pArea );
    1173             : }
    1174             : 
    1175           2 : void ScBroadcastAreaSlotMachine::PushAreaToBeErased( ScBroadcastAreaSlot* pSlot,
    1176             :         ScBroadcastAreas::iterator& rIter )
    1177             : {
    1178           2 :     maAreasToBeErased.push_back( ::std::make_pair( pSlot, rIter));
    1179           2 : }
    1180             : 
    1181        1946 : void ScBroadcastAreaSlotMachine::FinallyEraseAreas( ScBroadcastAreaSlot* pSlot )
    1182             : {
    1183             :     SAL_WARN_IF( pSlot->IsInBroadcastIteration(), "sc",
    1184             :             "ScBroadcastAreaSlotMachine::FinallyEraseAreas: during iteration? NO!");
    1185        1946 :     if (pSlot->IsInBroadcastIteration())
    1186        1946 :         return;
    1187             : 
    1188             :     // maAreasToBeErased is a simple vector so erasing an element may
    1189             :     // invalidate iterators and would be inefficient anyway. Instead, copy
    1190             :     // elements to be preserved (usually none!) to temporary vector and swap.
    1191        1946 :     AreasToBeErased aCopy;
    1192        5844 :     for (AreasToBeErased::iterator aIt( maAreasToBeErased.begin());
    1193        3896 :             aIt != maAreasToBeErased.end(); ++aIt)
    1194             :     {
    1195           2 :         if ((*aIt).first == pSlot)
    1196           2 :             pSlot->EraseArea( (*aIt).second);
    1197             :         else
    1198           0 :             aCopy.push_back( *aIt);
    1199             :     }
    1200        1946 :     maAreasToBeErased.swap( aCopy);
    1201             : }
    1202             : 
    1203          76 : std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners(
    1204             :     const ScRange& rRange, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup )
    1205             : {
    1206          76 :     std::vector<sc::AreaListener> aRet;
    1207             : 
    1208          76 :     SCTAB nEndTab = rRange.aEnd.Tab();
    1209         291 :     for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
    1210         291 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
    1211             :     {
    1212          21 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
    1213             :         SCSIZE nStart, nEnd, nRowBreak;
    1214          21 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
    1215          21 :         SCSIZE nOff = nStart;
    1216          21 :         SCSIZE nBreak = nOff + nRowBreak;
    1217          21 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
    1218      229453 :         while ( nOff <= nEnd )
    1219             :         {
    1220      229411 :             ScBroadcastAreaSlot* p = *pp;
    1221      229411 :             if (p)
    1222          21 :                 p->GetAllListeners(rRange, aRet, eType, eGroup);
    1223      229411 :             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
    1224             :         }
    1225             :     }
    1226             : 
    1227          76 :     return aRet;
    1228         156 : }
    1229             : 
    1230             : #if DEBUG_AREA_BROADCASTER
    1231             : void ScBroadcastAreaSlotMachine::Dump() const
    1232             : {
    1233             :     cout << "slot distribution count: " << nBcaSlots << endl;
    1234             :     TableSlotsMap::const_iterator it = aTableSlotsMap.begin(), itEnd = aTableSlotsMap.end();
    1235             :     for (; it != itEnd; ++it)
    1236             :     {
    1237             :         cout << "-- sheet (index: " << it->first << ")" << endl;
    1238             : 
    1239             :         TableSlots* pTabSlots = it->second;
    1240             :         assert(pTabSlots);
    1241             :         ScBroadcastAreaSlot** ppSlots = pTabSlots->getSlots();
    1242             :         for (SCSIZE i = 0; i < nBcaSlots; ++i)
    1243             :         {
    1244             :             const ScBroadcastAreaSlot* pSlot = ppSlots[i];
    1245             :             if (pSlot)
    1246             :             {
    1247             :                 cout << "* slot " << i << endl;
    1248             :                 pSlot->Dump();
    1249             :             }
    1250             :         }
    1251             :     }
    1252             : }
    1253             : #endif
    1254             : 
    1255             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11