LCOV - code coverage report
Current view: top level - sc/source/core/data - bcaslot.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 347 425 81.6 %
Date: 2012-08-25 Functions: 38 44 86.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 305 580 52.6 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : #include <sfx2/objsh.hxx>
      30                 :            : #include <svl/listener.hxx>
      31                 :            : #include <svl/listeneriter.hxx>
      32                 :            : 
      33                 :            : #include "document.hxx"
      34                 :            : #include "brdcst.hxx"
      35                 :            : #include "bcaslot.hxx"
      36                 :            : #include "scerrors.hxx"
      37                 :            : #include "docoptio.hxx"
      38                 :            : #include "refupdat.hxx"
      39                 :            : #include "table.hxx"
      40                 :            : 
      41                 :            : // Number of slots per dimension
      42                 :            : // must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
      43                 :            : #define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
      44                 :            : #if MAXROWCOUNT_DEFINE == 32000
      45                 :            : #define BCA_SLOTS_ROW 256
      46                 :            : #define BCA_SLICE 125
      47                 :            : #else
      48                 :            : #define BCA_SLICE 128
      49                 :            : #define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / BCA_SLICE)
      50                 :            : #endif
      51                 :            : #define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
      52                 :            : #define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
      53                 :            : // multiple?
      54                 :            : #if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
      55                 :            : #error bad BCA_SLOTS_COL value!
      56                 :            : #endif
      57                 :            : #if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
      58                 :            : #error bad BCA_SLOTS_ROW value!
      59                 :            : #endif
      60                 :            : // size of slot array if linear
      61                 :            : #define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
      62                 :            : // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
      63                 :            : // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
      64                 :            : // anyway, once you reached these values..
      65                 :            : #if BCA_SLOTS_DEFINE > 268435456
      66                 :            : #error BCA_SLOTS_DEFINE DOOMed!
      67                 :            : #endif
      68                 :            : 
      69                 :            : // STATIC DATA -----------------------------------------------------------
      70                 :            : 
      71 [ +  + ][ +  - ]:      12121 : TYPEINIT1( ScHint, SfxSimpleHint );
      72 [ -  + ][ -  + ]:          9 : TYPEINIT1( ScAreaChangedHint, SfxHint );
      73                 :            : 
      74                 :            : struct ScSlotData
      75                 :            : {
      76                 :            :     SCROW  nStartRow;   // first row of this segment
      77                 :            :     SCROW  nStopRow;    // first row of next segment
      78                 :            :     SCSIZE nSlice;      // slice size in this segment
      79                 :            :     SCSIZE nCumulated;  // cumulated slots of previous segments
      80                 :            : 
      81                 :        306 :     ScSlotData( SCROW r1, SCROW r2, SCSIZE s, SCSIZE c ) : nStartRow(r1), nStopRow(r2), nSlice(s), nCumulated(c) {}
      82                 :            : };
      83                 :            : typedef ::std::vector< ScSlotData > ScSlotDistribution;
      84                 :            : #if MAXROWCOUNT_DEFINE <= 65536
      85                 :            : // Linear distribution.
      86                 :            : static ScSlotDistribution aSlotDistribution( ScSlotData( 0, MAXROWCOUNT, BCA_SLOT_ROWS, 0));
      87                 :            : static SCSIZE nBcaSlotsRow = BCA_SLOTS_ROW;
      88                 :            : static SCSIZE nBcaSlots = BCA_SLOTS_DEFINE;
      89                 :            : #else
      90                 :            : // Logarithmic or any other distribution.
      91                 :            : // Upper sheet part usually is more populated and referenced and gets fine
      92                 :            : // grained resolution, larger data in larger hunks.
      93                 :            : // Could be further enhanced by also applying a different distribution of
      94                 :            : // column slots.
      95                 :         51 : static SCSIZE initSlotDistribution( ScSlotDistribution & rSD, SCSIZE & rBSR )
      96                 :            : {
      97                 :         51 :     SCSIZE nSlots = 0;
      98                 :         51 :     SCROW nRow1 = 0;
      99                 :         51 :     SCROW nRow2 = 32*1024;
     100                 :         51 :     SCSIZE nSlice = 128;
     101                 :            :     // Must be sorted by row1,row2!
     102         [ +  + ]:        357 :     while (nRow2 <= MAXROWCOUNT)
     103                 :            :     {
     104         [ +  - ]:        306 :         rSD.push_back( ScSlotData( nRow1, nRow2, nSlice, nSlots));
     105                 :        306 :         nSlots += (nRow2 - nRow1) / nSlice;
     106                 :        306 :         nRow1 = nRow2;
     107                 :        306 :         nRow2 *= 2;
     108                 :        306 :         nSlice *= 2;
     109                 :            :     }
     110                 :         51 :     rBSR = nSlots;
     111                 :         51 :     return nSlots;
     112                 :            : }
     113                 :         51 : static ScSlotDistribution aSlotDistribution;
     114                 :            : static SCSIZE nBcaSlotsRow;
     115                 :         51 : static SCSIZE nBcaSlots = initSlotDistribution( aSlotDistribution, nBcaSlotsRow) * BCA_SLOTS_COL;
     116                 :            : // Ensure that all static variables are initialized with this one call.
     117                 :            : #endif
     118                 :            : 
     119                 :            : 
     120                 :       2857 : ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
     121                 :            :         ScBroadcastAreaSlotMachine* pBASMa ) :
     122                 :            :     aTmpSeekBroadcastArea( ScRange()),
     123                 :            :     pDoc( pDocument ),
     124 [ +  - ][ +  - ]:       2857 :     pBASM( pBASMa )
     125                 :            : {
     126                 :       2857 : }
     127                 :            : 
     128                 :            : 
     129         [ +  - ]:        163 : ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
     130                 :            : {
     131 [ +  - ][ +  + ]:       3928 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     132         [ +  - ]:       3765 :             aIter != aBroadcastAreaTbl.end(); /* none */)
     133                 :            :     {
     134                 :            :         // Prevent hash from accessing dangling pointer in case area is
     135                 :            :         // deleted.
     136         [ +  - ]:       3602 :         ScBroadcastArea* pArea = *aIter;
     137                 :            :         // Erase all so no hash will be accessed upon destruction of the
     138                 :            :         // boost::unordered_map.
     139 [ +  - ][ +  - ]:       3602 :         aBroadcastAreaTbl.erase( aIter++);
     140         [ +  + ]:       3602 :         if (!pArea->DecRef())
     141 [ +  - ][ +  - ]:       3575 :             delete pArea;
     142                 :            :     }
     143                 :        163 : }
     144                 :            : 
     145                 :            : 
     146                 :      13056 : bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
     147                 :            : {
     148         [ -  + ]:      13056 :     if ( pDoc->GetHardRecalcState() )
     149                 :          0 :         return true;
     150         [ -  + ]:      13056 :     if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
     151                 :            :     {   // this is more hypothetical now, check existed for old SV_PTRARR_SORT
     152         [ #  # ]:          0 :         if ( !pDoc->GetHardRecalcState() )
     153                 :            :         {
     154                 :          0 :             SfxObjectShell* pShell = pDoc->GetDocumentShell();
     155                 :            :             OSL_ENSURE( pShell, "Missing DocShell :-/" );
     156                 :            : 
     157         [ #  # ]:          0 :             if ( pShell )
     158         [ #  # ]:          0 :                 pShell->SetError( SCWARN_CORE_HARD_RECALC, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
     159                 :            : 
     160                 :          0 :             pDoc->SetAutoCalc( false );
     161                 :          0 :             pDoc->SetHardRecalcState( true );
     162                 :            :         }
     163                 :          0 :         return true;
     164                 :            :     }
     165                 :      13056 :     return false;
     166                 :            : }
     167                 :            : 
     168                 :            : 
     169                 :      10344 : bool ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
     170                 :            :         SvtListener* pListener, ScBroadcastArea*& rpArea )
     171                 :            : {
     172                 :      10344 :     bool bNewArea = false;
     173                 :            :     OSL_ENSURE(pListener, "StartListeningArea: pListener Null");
     174         [ -  + ]:      10344 :     if (CheckHardRecalcStateCondition())
     175                 :          0 :         return false;
     176         [ +  - ]:      10344 :     if ( !rpArea )
     177                 :            :     {
     178                 :            :         // Even if most times the area doesn't exist yet and immediately trying
     179                 :            :         // to new and insert it would save an attempt to find it, on mass
     180                 :            :         // operations like identical large [HV]LOOKUP() areas the new/delete
     181                 :            :         // would add quite some penalty for all but the first formula cell.
     182         [ +  - ]:      10344 :         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
     183 [ +  - ][ +  + ]:      10344 :         if (aIter != aBroadcastAreaTbl.end())
     184         [ +  - ]:       6682 :             rpArea = *aIter;
     185                 :            :         else
     186                 :            :         {
     187 [ +  - ][ +  - ]:       3662 :             rpArea = new ScBroadcastArea( rRange);
     188 [ +  - ][ +  - ]:       3662 :             if (aBroadcastAreaTbl.insert( rpArea).second)
     189                 :            :             {
     190                 :       3662 :                 rpArea->IncRef();
     191                 :       3662 :                 bNewArea = true;
     192                 :            :             }
     193                 :            :             else
     194                 :            :             {
     195                 :            :                 OSL_FAIL("StartListeningArea: area not found and not inserted in slot?!?");
     196 [ #  # ][ #  # ]:          0 :                 delete rpArea;
     197                 :          0 :                 rpArea = 0;
     198                 :            :             }
     199                 :            :         }
     200         [ +  - ]:      10344 :         if (rpArea)
     201         [ +  - ]:      10344 :             pListener->StartListening( rpArea->GetBroadcaster());
     202                 :            :     }
     203                 :            :     else
     204                 :            :     {
     205         [ #  # ]:          0 :         if (aBroadcastAreaTbl.insert( rpArea).second)
     206                 :          0 :             rpArea->IncRef();
     207                 :            :     }
     208                 :      10344 :     return bNewArea;
     209                 :            : }
     210                 :            : 
     211                 :            : 
     212                 :       2712 : void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea* pArea )
     213                 :            : {
     214                 :            :     OSL_ENSURE( pArea, "InsertListeningArea: pArea NULL");
     215         [ -  + ]:       2712 :     if (CheckHardRecalcStateCondition())
     216                 :       2712 :         return;
     217         [ +  - ]:       2712 :     if (aBroadcastAreaTbl.insert( pArea).second)
     218                 :       2712 :         pArea->IncRef();
     219                 :            : }
     220                 :            : 
     221                 :            : 
     222                 :            : // If rpArea != NULL then no listeners are stopped, only the area is removed
     223                 :            : // and the reference count decremented.
     224                 :        282 : void ScBroadcastAreaSlot::EndListeningArea( const ScRange& rRange,
     225                 :            :         SvtListener* pListener, ScBroadcastArea*& rpArea )
     226                 :            : {
     227                 :            :     OSL_ENSURE(pListener, "EndListeningArea: pListener Null");
     228         [ +  - ]:        282 :     if ( !rpArea )
     229                 :            :     {
     230         [ +  - ]:        282 :         ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
     231 [ +  - ][ +  + ]:        282 :         if (aIter == aBroadcastAreaTbl.end())
     232                 :            :             return;
     233         [ +  - ]:        279 :         rpArea = *aIter;
     234         [ +  - ]:        279 :         pListener->EndListening( rpArea->GetBroadcaster() );
     235         [ +  + ]:        279 :         if ( !rpArea->GetBroadcaster().HasListeners() )
     236                 :            :         {   // if nobody is listening we can dispose it
     237         [ +  - ]:         77 :             aBroadcastAreaTbl.erase( aIter);
     238         [ +  - ]:         77 :             if ( !rpArea->DecRef() )
     239                 :            :             {
     240 [ +  - ][ +  - ]:         77 :                 delete rpArea;
     241                 :        282 :                 rpArea = NULL;
     242                 :            :             }
     243                 :            :         }
     244                 :            :     }
     245                 :            :     else
     246                 :            :     {
     247         [ #  # ]:          0 :         if ( !rpArea->GetBroadcaster().HasListeners() )
     248                 :            :         {
     249         [ #  # ]:          0 :             ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
     250 [ #  # ][ #  # ]:          0 :             if (aIter == aBroadcastAreaTbl.end())
     251                 :            :                 return;
     252                 :            :             OSL_ENSURE( *aIter == rpArea, "EndListeningArea: area pointer mismatch");
     253         [ #  # ]:          0 :             aBroadcastAreaTbl.erase( aIter);
     254         [ #  # ]:          0 :             if ( !rpArea->DecRef() )
     255                 :            :             {
     256 [ #  # ][ #  # ]:          0 :                 delete rpArea;
     257                 :        282 :                 rpArea = NULL;
     258                 :            :             }
     259                 :            :         }
     260                 :            :     }
     261                 :            : }
     262                 :            : 
     263                 :            : 
     264                 :      10626 : ScBroadcastAreas::iterator ScBroadcastAreaSlot::FindBroadcastArea(
     265                 :            :         const ScRange& rRange ) const
     266                 :            : {
     267                 :      10626 :     aTmpSeekBroadcastArea.UpdateRange( rRange);
     268         [ +  - ]:      10626 :     return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
     269                 :            : }
     270                 :            : 
     271                 :            : 
     272                 :       2829 : sal_Bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
     273                 :            : {
     274         [ +  + ]:       2829 :     if (aBroadcastAreaTbl.empty())
     275                 :        837 :         return false;
     276                 :       1992 :     sal_Bool bIsBroadcasted = false;
     277                 :       1992 :     const ScAddress& rAddress = rHint.GetAddress();
     278 [ +  + ][ +  - ]:       6537 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
     279         [ +  - ]:       4545 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     280                 :            :     {
     281         [ +  - ]:       2553 :         ScBroadcastArea* pArea = *aIter;
     282                 :            :         // A Notify() during broadcast may call EndListeningArea() and thus
     283                 :            :         // dispose this area if it was the last listener, which would
     284                 :            :         // invalidate the iterator, hence increment before call.
     285                 :       2553 :         ++aIter;
     286                 :       2553 :         const ScRange& rAreaRange = pArea->GetRange();
     287         [ +  + ]:       2553 :         if (rAreaRange.In( rAddress))
     288                 :            :         {
     289 [ +  + ][ +  - ]:        472 :             if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
         [ +  + ][ +  + ]
     290                 :            :             {
     291         [ +  - ]:        266 :                 pArea->GetBroadcaster().Broadcast( rHint);
     292                 :        266 :                 bIsBroadcasted = sal_True;
     293                 :            :             }
     294                 :            :         }
     295                 :            :     }
     296                 :       2829 :     return bIsBroadcasted;
     297                 :            : }
     298                 :            : 
     299                 :            : 
     300                 :          4 : sal_Bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
     301                 :            :         const ScHint& rHint) const
     302                 :            : {
     303         [ +  + ]:          4 :     if (aBroadcastAreaTbl.empty())
     304                 :          1 :         return false;
     305                 :          3 :     sal_Bool bIsBroadcasted = false;
     306 [ +  - ][ +  + ]:          9 :     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
     307         [ +  - ]:          6 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     308                 :            :     {
     309         [ +  - ]:          3 :         ScBroadcastArea* pArea = *aIter;
     310                 :            :         // A Notify() during broadcast may call EndListeningArea() and thus
     311                 :            :         // dispose this area if it was the last listener, which would
     312                 :            :         // invalidate the iterator, hence increment before call.
     313                 :          3 :         ++aIter;
     314                 :          3 :         const ScRange& rAreaRange = pArea->GetRange();
     315 [ -  + ][ +  - ]:          3 :         if (rAreaRange.Intersects( rRange ))
     316                 :            :         {
     317 [ #  # ][ #  # ]:          0 :             if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
         [ #  # ][ #  # ]
     318                 :            :             {
     319         [ #  # ]:          0 :                 pArea->GetBroadcaster().Broadcast( rHint);
     320                 :          0 :                 bIsBroadcasted = sal_True;
     321                 :            :             }
     322                 :            :         }
     323                 :            :     }
     324                 :          4 :     return bIsBroadcasted;
     325                 :            : }
     326                 :            : 
     327                 :            : 
     328                 :          6 : void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
     329                 :            : {
     330         [ -  + ]:          6 :     if (aBroadcastAreaTbl.empty())
     331                 :          6 :         return;
     332 [ +  - ][ +  + ]:         21 :     for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     333         [ +  - ]:         15 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     334                 :            :     {
     335         [ +  - ]:          9 :         const ScRange& rAreaRange = (*aIter)->GetRange();
     336         [ +  + ]:          9 :         if (rRange.In( rAreaRange))
     337                 :            :         {
     338         [ +  - ]:          3 :             ScBroadcastArea* pArea = *aIter;
     339 [ +  - ][ +  - ]:          3 :             aBroadcastAreaTbl.erase( aIter++);  // erase before modifying
     340         [ +  - ]:          3 :             if (!pArea->DecRef())
     341                 :            :             {
     342         [ -  + ]:          3 :                 if (pBASM->IsInBulkBroadcast())
     343         [ #  # ]:          0 :                     pBASM->RemoveBulkArea( pArea);
     344 [ +  - ][ +  - ]:          3 :                 delete pArea;
     345                 :            :             }
     346                 :            :         }
     347                 :            :         else
     348                 :          6 :             ++aIter;
     349                 :            :     }
     350                 :            : }
     351                 :            : 
     352                 :            : 
     353                 :          6 : void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
     354                 :            :         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     355                 :            : {
     356         [ +  + ]:          6 :     if (aBroadcastAreaTbl.empty())
     357                 :          6 :         return;
     358                 :            : 
     359                 :            :     SCCOL nCol1, nCol2, theCol1, theCol2;
     360                 :            :     SCROW nRow1, nRow2, theRow1, theRow2;
     361                 :            :     SCTAB nTab1, nTab2, theTab1, theTab2;
     362                 :          3 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
     363 [ +  + ][ +  - ]:         15 :     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
     364         [ +  - ]:          9 :             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
     365                 :            :     {
     366         [ +  - ]:          6 :         ScBroadcastArea* pArea = *aIter;
     367         [ -  + ]:          6 :         if ( pArea->IsInUpdateChain() )
     368                 :            :         {
     369 [ #  # ][ #  # ]:          0 :             aBroadcastAreaTbl.erase( aIter++);
     370                 :          0 :             pArea->DecRef();
     371                 :            :         }
     372                 :            :         else
     373                 :            :         {
     374                 :          6 :             pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
     375         [ +  + ]:          6 :             if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     376                 :            :                     nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     377         [ +  - ]:          6 :                     theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
     378                 :            :             {
     379 [ +  - ][ +  - ]:          3 :                 aBroadcastAreaTbl.erase( aIter++);
     380                 :          3 :                 pArea->DecRef();
     381         [ -  + ]:          3 :                 if (pBASM->IsInBulkBroadcast())
     382         [ #  # ]:          0 :                     pBASM->RemoveBulkArea( pArea);
     383                 :          3 :                 pArea->SetInUpdateChain( sal_True );
     384                 :          3 :                 ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
     385         [ +  + ]:          3 :                 if ( pUC )
     386                 :          1 :                     pUC->SetUpdateChainNext( pArea );
     387                 :            :                 else    // no tail => no head
     388                 :          2 :                     pBASM->SetUpdateChain( pArea );
     389                 :          3 :                 pBASM->SetEOUpdateChain( pArea );
     390                 :            :             }
     391                 :            :             else
     392                 :          3 :                 ++aIter;
     393                 :            :         }
     394                 :            :     }
     395                 :            : }
     396                 :            : 
     397                 :            : 
     398                 :          0 : void ScBroadcastAreaSlot::UpdateRemoveArea( ScBroadcastArea* pArea )
     399                 :            : {
     400         [ #  # ]:          0 :     ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.find( pArea));
     401 [ #  # ][ #  # ]:          0 :     if (aIter == aBroadcastAreaTbl.end())
     402                 :          0 :         return;
     403 [ #  # ][ #  # ]:          0 :     if (*aIter != pArea)
     404                 :            :         OSL_FAIL( "UpdateRemoveArea: area pointer mismatch");
     405                 :            :     else
     406                 :            :     {
     407         [ #  # ]:          0 :         aBroadcastAreaTbl.erase( aIter);
     408                 :          0 :         pArea->DecRef();
     409                 :            :     }
     410                 :            : }
     411                 :            : 
     412                 :            : 
     413                 :          3 : void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
     414                 :            : {
     415                 :            :     ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
     416         [ +  - ]:          3 :         aBroadcastAreaTbl.insert( pArea );
     417         [ +  + ]:          3 :     if (aPair.second)
     418                 :          2 :         pArea->IncRef();
     419                 :            :     else
     420                 :            :     {
     421                 :            :         // Identical area already exists, add listeners.
     422         [ +  - ]:          1 :         ScBroadcastArea* pTarget = *(aPair.first);
     423         [ +  - ]:          1 :         if (pArea != pTarget)
     424                 :            :         {
     425                 :          1 :             SvtBroadcaster& rTarget = pTarget->GetBroadcaster();
     426         [ +  - ]:          1 :             SvtListenerIter it( pArea->GetBroadcaster());
     427 [ +  - ][ +  - ]:          2 :             for (SvtListener* pListener = it.GetCurr(); pListener;
                 [ +  + ]
     428                 :            :                     pListener = it.GoNext())
     429                 :            :             {
     430         [ +  - ]:          1 :                 pListener->StartListening( rTarget);
     431         [ +  - ]:          1 :             }
     432                 :            :         }
     433                 :            :     }
     434                 :          3 : }
     435                 :            : 
     436                 :            : 
     437                 :            : // --- ScBroadcastAreaSlotMachine -------------------------------------
     438                 :            : 
     439                 :        145 : ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
     440                 :            : {
     441                 :        145 :     ppSlots = new ScBroadcastAreaSlot* [ nBcaSlots ];
     442                 :        145 :     memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
     443                 :        145 : }
     444                 :            : 
     445                 :            : 
     446                 :        136 : ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
     447                 :            : {
     448         [ +  + ]:    7798920 :     for ( ScBroadcastAreaSlot** pp = ppSlots + nBcaSlots; --pp >= ppSlots; /* nothing */ )
     449                 :            :     {
     450         [ +  + ]:    7798784 :         if (*pp)
     451         [ +  - ]:        163 :             delete *pp;
     452                 :            :     }
     453         [ +  - ]:        136 :     delete [] ppSlots;
     454                 :        136 : }
     455                 :            : 
     456                 :            : 
     457                 :        846 : ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
     458                 :            :         ScDocument* pDocument ) :
     459                 :            :     pBCAlways( NULL ),
     460                 :            :     pDoc( pDocument ),
     461                 :            :     pUpdateChain( NULL ),
     462                 :            :     pEOUpdateChain( NULL ),
     463 [ +  - ][ +  - ]:        846 :     nInBulkBroadcast( 0 )
     464                 :            : {
     465                 :        846 : }
     466                 :            : 
     467                 :            : 
     468                 :        695 : ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
     469                 :            : {
     470         [ +  + ]:       1656 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.begin());
     471                 :        828 :             iTab != aTableSlotsMap.end(); ++iTab)
     472                 :            :     {
     473 [ +  - ][ +  - ]:        133 :         delete (*iTab).second;
     474                 :            :     }
     475 [ +  + ][ +  - ]:        695 :     delete pBCAlways;
     476                 :        695 : }
     477                 :            : 
     478                 :            : 
     479                 :      35022 : inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
     480                 :            :         const ScAddress& rAddress ) const
     481                 :            : {
     482                 :      35022 :     SCROW nRow = rAddress.Row();
     483                 :      35022 :     SCCOL nCol = rAddress.Col();
     484 [ -  + ][ -  + ]:      35022 :     if ( !ValidRow(nRow) || !ValidCol(nCol) )
                 [ +  - ]
     485                 :            :     {
     486                 :            :         OSL_FAIL( "Row/Col invalid, using first slot!" );
     487                 :          0 :         return 0;
     488                 :            :     }
     489         [ +  - ]:      35142 :     for (size_t i=0; i < aSlotDistribution.size(); ++i)
     490                 :            :     {
     491         [ +  + ]:      35142 :         if (nRow < aSlotDistribution[i].nStopRow)
     492                 :            :         {
     493                 :      35022 :             const ScSlotData& rSD = aSlotDistribution[i];
     494                 :            :             return rSD.nCumulated +
     495                 :            :                 (static_cast<SCSIZE>(nRow - rSD.nStartRow)) / rSD.nSlice +
     496                 :      35022 :                 static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * nBcaSlotsRow;
     497                 :            :         }
     498                 :            :     }
     499                 :            :     OSL_FAIL( "No slot found, using last!" );
     500                 :      35022 :     return nBcaSlots - 1;
     501                 :            : }
     502                 :            : 
     503                 :            : 
     504                 :      10645 : void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
     505                 :            :         SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak ) const
     506                 :            : {
     507                 :      10645 :     rStart = ComputeSlotOffset( rRange.aStart );
     508                 :      10645 :     rEnd = ComputeSlotOffset( rRange.aEnd );
     509                 :            :     // count of row slots per column minus one
     510                 :            :     rRowBreak = ComputeSlotOffset(
     511         [ +  - ]:      10645 :         ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
     512                 :      10645 : }
     513                 :            : 
     514                 :            : 
     515                 :      13537 : inline void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
     516                 :            :         SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE const & nRowBreak )
     517                 :            : {
     518         [ +  + ]:      13537 :     if ( nOff < nBreak )
     519                 :            :     {
     520                 :       2712 :         ++nOff;
     521                 :       2712 :         ++pp;
     522                 :            :     }
     523                 :            :     else
     524                 :            :     {
     525                 :      10825 :         nStart += nBcaSlotsRow;
     526                 :      10825 :         nOff = nStart;
     527                 :      10825 :         pp = ppSlots + nOff;
     528                 :      10825 :         nBreak = nOff + nRowBreak;
     529                 :            :     }
     530                 :      13537 : }
     531                 :            : 
     532                 :            : 
     533                 :      10410 : void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
     534                 :            :         SvtListener* pListener )
     535                 :            : {
     536         [ +  + ]:      10410 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     537                 :            :     {
     538         [ +  + ]:         66 :         if ( !pBCAlways )
     539         [ +  - ]:         15 :             pBCAlways = new SvtBroadcaster;
     540                 :         66 :         pListener->StartListening( *pBCAlways );
     541                 :            :     }
     542                 :            :     else
     543                 :            :     {
     544                 :      10344 :         bool bDone = false;
     545   [ +  +  +  + ]:      34694 :         for (SCTAB nTab = rRange.aStart.Tab();
                 [ +  + ]
     546                 :      14006 :                 !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
     547                 :            :         {
     548         [ +  - ]:      10344 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     549         [ +  + ]:      10344 :             if (iTab == aTableSlotsMap.end())
     550                 :            :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
     551 [ +  - ][ +  - ]:        145 :                             nTab, new TableSlots)).first;
                 [ +  - ]
     552                 :      10344 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     553                 :            :             SCSIZE nStart, nEnd, nRowBreak;
     554         [ +  - ]:      10344 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     555                 :      10344 :             SCSIZE nOff = nStart;
     556                 :      10344 :             SCSIZE nBreak = nOff + nRowBreak;
     557                 :      10344 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     558                 :      10344 :             ScBroadcastArea* pArea = NULL;
     559 [ +  + ][ +  + ]:      23400 :             while ( !bDone && nOff <= nEnd )
                 [ +  + ]
     560                 :            :             {
     561         [ +  + ]:      13056 :                 if ( !*pp )
     562 [ +  - ][ +  - ]:       2857 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
     563         [ +  + ]:      13056 :                 if (!pArea)
     564                 :            :                 {
     565                 :            :                     // If the call to StartListeningArea didn't create the
     566                 :            :                     // ScBroadcastArea, listeners were added to an already
     567                 :            :                     // existing identical area that doesn't need to be inserted
     568                 :            :                     // to slots again.
     569 [ +  - ][ +  + ]:      10344 :                     if (!(*pp)->StartListeningArea( rRange, pListener, pArea))
     570                 :       6682 :                         bDone = true;
     571                 :            :                 }
     572                 :            :                 else
     573         [ +  - ]:       2712 :                     (*pp)->InsertListeningArea( pArea);
     574                 :      13056 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     575                 :            :             }
     576                 :            :         }
     577                 :            :     }
     578                 :      10410 : }
     579                 :            : 
     580                 :            : 
     581                 :       2769 : void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
     582                 :            :         SvtListener* pListener )
     583                 :            : {
     584         [ +  + ]:       2769 :     if ( rRange == BCA_LISTEN_ALWAYS  )
     585                 :            :     {
     586         [ +  + ]:       2487 :         if ( pBCAlways )
     587                 :            :         {
     588                 :        711 :             pListener->EndListening( *pBCAlways);
     589         [ -  + ]:        711 :             if (!pBCAlways->HasListeners())
     590                 :            :             {
     591         [ #  # ]:          0 :                 delete pBCAlways;
     592                 :          0 :                 pBCAlways = NULL;
     593                 :            :             }
     594                 :            :         }
     595                 :            :     }
     596                 :            :     else
     597                 :            :     {
     598                 :        282 :         SCTAB nEndTab = rRange.aEnd.Tab();
     599   [ +  +  +  + ]:       1992 :         for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
         [ +  + ][ +  - ]
     600         [ +  - ]:       1428 :                 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     601                 :            :         {
     602                 :        282 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     603                 :            :             SCSIZE nStart, nEnd, nRowBreak;
     604         [ +  - ]:        282 :             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     605                 :        282 :             SCSIZE nOff = nStart;
     606                 :        282 :             SCSIZE nBreak = nOff + nRowBreak;
     607                 :        282 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     608                 :        282 :             ScBroadcastArea* pArea = NULL;
     609 [ +  - ][ -  + ]:        282 :             if (nOff == 0 && nEnd == nBcaSlots-1)
     610                 :            :             {
     611                 :            :                 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     612                 :            :                 // happen for insertion and deletion of sheets.
     613                 :          0 :                 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     614         [ #  # ]:          0 :                 do
     615                 :            :                 {
     616         [ #  # ]:          0 :                     if ( *pp )
     617         [ #  # ]:          0 :                         (*pp)->EndListeningArea( rRange, pListener, pArea );
     618                 :          0 :                 } while (++pp < pStop);
     619                 :            :             }
     620                 :            :             else
     621                 :            :             {
     622         [ +  + ]:        564 :                 while ( nOff <= nEnd )
     623                 :            :                 {
     624         [ +  - ]:        282 :                     if ( *pp )
     625         [ +  - ]:        282 :                         (*pp)->EndListeningArea( rRange, pListener, pArea );
     626                 :        282 :                     ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     627                 :            :                 }
     628                 :            :             }
     629                 :            :         }
     630                 :            :     }
     631                 :       2769 : }
     632                 :            : 
     633                 :            : 
     634                 :      43916 : sal_Bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
     635                 :            : {
     636                 :      43916 :     const ScAddress& rAddress = rHint.GetAddress();
     637         [ +  + ]:      43916 :     if ( rAddress == BCA_BRDCST_ALWAYS )
     638                 :            :     {
     639         [ -  + ]:       9929 :         if ( pBCAlways )
     640                 :            :         {
     641                 :          0 :             pBCAlways->Broadcast( rHint );
     642                 :          0 :             return sal_True;
     643                 :            :         }
     644                 :            :         else
     645                 :       9929 :             return false;
     646                 :            :     }
     647                 :            :     else
     648                 :            :     {
     649         [ +  - ]:      33987 :         TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
     650         [ +  + ]:      33987 :         if (iTab == aTableSlotsMap.end())
     651                 :      30900 :             return false;
     652                 :       3087 :         ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
     653         [ +  - ]:       6174 :                 ComputeSlotOffset( rAddress));
     654         [ +  + ]:       3087 :         if ( pSlot )
     655         [ +  - ]:       2829 :             return pSlot->AreaBroadcast( rHint );
     656                 :            :         else
     657                 :      43916 :             return false;
     658                 :            :     }
     659                 :            : }
     660                 :            : 
     661                 :            : 
     662                 :         13 : sal_Bool ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
     663                 :            :         const ScHint& rHint ) const
     664                 :            : {
     665                 :         13 :     sal_Bool bBroadcasted = false;
     666                 :         13 :     SCTAB nEndTab = rRange.aEnd.Tab();
     667   [ +  +  +  - ]:         55 :     for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
         [ +  + ][ +  - ]
     668         [ +  - ]:         38 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     669                 :            :     {
     670                 :          4 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     671                 :            :         SCSIZE nStart, nEnd, nRowBreak;
     672         [ +  - ]:          4 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     673                 :          4 :         SCSIZE nOff = nStart;
     674                 :          4 :         SCSIZE nBreak = nOff + nRowBreak;
     675                 :          4 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     676         [ +  + ]:          8 :         while ( nOff <= nEnd )
     677                 :            :         {
     678         [ +  - ]:          4 :             if ( *pp )
     679         [ +  - ]:          4 :                 bBroadcasted |= (*pp)->AreaBroadcastInRange( rRange, rHint );
     680                 :          4 :             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     681                 :            :         }
     682                 :            :     }
     683                 :         13 :     return bBroadcasted;
     684                 :            : }
     685                 :            : 
     686                 :            : 
     687                 :        128 : void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
     688                 :            :         const ScRange& rRange )
     689                 :            : {
     690                 :        128 :     SCTAB nEndTab = rRange.aEnd.Tab();
     691   [ +  +  +  - ]:        408 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
         [ +  + ][ +  - ]
     692         [ +  - ]:        274 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     693                 :            :     {
     694                 :          6 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     695                 :            :         SCSIZE nStart, nEnd, nRowBreak;
     696         [ +  - ]:          6 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     697                 :          6 :         SCSIZE nOff = nStart;
     698                 :          6 :         SCSIZE nBreak = nOff + nRowBreak;
     699                 :          6 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     700 [ +  - ][ +  + ]:          6 :         if (nOff == 0 && nEnd == nBcaSlots-1)
     701                 :            :         {
     702                 :            :             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     703                 :            :             // happen for insertion and deletion of sheets.
     704                 :          3 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     705         [ +  + ]:     172029 :             do
     706                 :            :             {
     707         [ +  + ]:     172029 :                 if ( *pp )
     708         [ +  - ]:          3 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     709                 :          3 :             } while (++pp < pStop);
     710                 :            :         }
     711                 :            :         else
     712                 :            :         {
     713         [ +  + ]:        195 :             while ( nOff <= nEnd )
     714                 :            :             {
     715         [ +  + ]:        192 :                 if ( *pp )
     716         [ +  - ]:          3 :                     (*pp)->DelBroadcastAreasInRange( rRange );
     717                 :        192 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     718                 :            :             }
     719                 :            :         }
     720                 :            :     }
     721                 :        128 : }
     722                 :            : 
     723                 :            : 
     724                 :            : // for all affected: remove, chain, update range, insert, and maybe delete
     725                 :        221 : void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
     726                 :            :         UpdateRefMode eUpdateRefMode,
     727                 :            :         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     728                 :            : {
     729                 :            :     // remove affected and put in chain
     730                 :        221 :     SCTAB nEndTab = rRange.aEnd.Tab();
     731   [ +  +  +  - ]:        687 :     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
         [ +  + ][ +  - ]
     732         [ +  - ]:        460 :             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
     733                 :            :     {
     734                 :          6 :         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     735                 :            :         SCSIZE nStart, nEnd, nRowBreak;
     736         [ +  - ]:          6 :         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
     737                 :          6 :         SCSIZE nOff = nStart;
     738                 :          6 :         SCSIZE nBreak = nOff + nRowBreak;
     739                 :          6 :         ScBroadcastAreaSlot** pp = ppSlots + nOff;
     740 [ +  - ][ +  - ]:          6 :         if (nOff == 0 && nEnd == nBcaSlots-1)
     741                 :            :         {
     742                 :            :             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
     743                 :            :             // happen for insertion and deletion of sheets.
     744                 :          6 :             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
     745         [ +  + ]:     344058 :             do
     746                 :            :             {
     747         [ +  + ]:     344058 :                 if ( *pp )
     748         [ +  - ]:          6 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     749                 :          6 :             } while (++pp < pStop);
     750                 :            :         }
     751                 :            :         else
     752                 :            :         {
     753         [ #  # ]:          0 :             while ( nOff <= nEnd )
     754                 :            :             {
     755         [ #  # ]:          0 :                 if ( *pp )
     756         [ #  # ]:          0 :                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
     757                 :          0 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     758                 :            :             }
     759                 :            :         }
     760                 :            :     }
     761                 :            : 
     762                 :            :     // Updating an area's range will modify the hash key, remove areas from all
     763                 :            :     // affected slots. Will be reinserted later with the updated range.
     764                 :        221 :     ScBroadcastArea* pChain = pUpdateChain;
     765         [ +  + ]:        224 :     while (pChain)
     766                 :            :     {
     767                 :          3 :         ScBroadcastArea* pArea = pChain;
     768                 :          3 :         pChain = pArea->GetUpdateChainNext();
     769                 :          3 :         ScRange aRange( pArea->GetRange());
     770                 :            :         // remove from slots
     771 [ +  - ][ -  + ]:          3 :         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab() && pArea->GetRef(); ++nTab)
                 [ -  + ]
     772                 :            :         {
     773         [ #  # ]:          0 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     774         [ #  # ]:          0 :             if (iTab == aTableSlotsMap.end())
     775                 :            :             {
     776                 :            :                 OSL_FAIL( "UpdateBroadcastAreas: Where's the TableSlot?!?");
     777                 :          0 :                 continue;   // for
     778                 :            :             }
     779                 :          0 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     780                 :            :             SCSIZE nStart, nEnd, nRowBreak;
     781         [ #  # ]:          0 :             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
     782                 :          0 :             SCSIZE nOff = nStart;
     783                 :          0 :             SCSIZE nBreak = nOff + nRowBreak;
     784                 :          0 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     785 [ #  # ][ #  # ]:          0 :             while ( nOff <= nEnd && pArea->GetRef() )
                 [ #  # ]
     786                 :            :             {
     787         [ #  # ]:          0 :                 if (*pp)
     788         [ #  # ]:          0 :                     (*pp)->UpdateRemoveArea( pArea);
     789                 :          0 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     790                 :            :             }
     791                 :            :         }
     792                 :            : 
     793                 :            :     }
     794                 :            : 
     795                 :            :     // shift sheets
     796         [ +  + ]:        221 :     if (nDz)
     797                 :            :     {
     798         [ +  + ]:        181 :         if (nDz < 0)
     799                 :            :         {
     800         [ +  - ]:        112 :             TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     801         [ +  - ]:        112 :             TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab() - nDz));
     802                 :            :             // Remove sheets, if any, iDel or/and iTab may as well point to end().
     803         [ +  + ]:        115 :             while (iDel != iTab)
     804                 :            :             {
     805 [ +  - ][ +  - ]:          3 :                 delete (*iDel).second;
     806         [ +  - ]:          3 :                 aTableSlotsMap.erase( iDel++);
     807                 :            :             }
     808                 :            :             // shift remaining down
     809         [ -  + ]:        112 :             while (iTab != aTableSlotsMap.end())
     810                 :            :             {
     811                 :          0 :                 SCTAB nTab = (*iTab).first + nDz;
     812         [ #  # ]:          0 :                 aTableSlotsMap[nTab] = (*iTab).second;
     813         [ #  # ]:          0 :                 aTableSlotsMap.erase( iTab++);
     814                 :            :             }
     815                 :            :         }
     816                 :            :         else
     817                 :            :         {
     818         [ +  - ]:         69 :             TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
     819         [ -  + ]:         69 :             if (iStop != aTableSlotsMap.end())
     820                 :            :             {
     821                 :          0 :                 bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
     822         [ #  # ]:          0 :                 if (!bStopIsBegin)
     823                 :          0 :                     --iStop;
     824                 :          0 :                 TableSlotsMap::iterator iTab( aTableSlotsMap.end());
     825                 :          0 :                 --iTab;
     826         [ #  # ]:          0 :                 while (iTab != iStop)
     827                 :            :                 {
     828                 :          0 :                     SCTAB nTab = (*iTab).first + nDz;
     829         [ #  # ]:          0 :                     aTableSlotsMap[nTab] = (*iTab).second;
     830         [ #  # ]:          0 :                     aTableSlotsMap.erase( iTab--);
     831                 :            :                 }
     832                 :            :                 // Shift the very first, iTab==iStop in this case.
     833         [ #  # ]:          0 :                 if (bStopIsBegin)
     834                 :            :                 {
     835                 :          0 :                     SCTAB nTab = (*iTab).first + nDz;
     836         [ #  # ]:          0 :                     aTableSlotsMap[nTab] = (*iTab).second;
     837         [ #  # ]:         69 :                     aTableSlotsMap.erase( iStop);
     838                 :            :                 }
     839                 :            :             }
     840                 :            :         }
     841                 :            :     }
     842                 :            : 
     843                 :            :     // work off chain
     844                 :            :     SCCOL nCol1, nCol2, theCol1, theCol2;
     845                 :            :     SCROW nRow1, nRow2, theRow1, theRow2;
     846                 :            :     SCTAB nTab1, nTab2, theTab1, theTab2;
     847                 :        221 :     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
     848         [ +  + ]:        224 :     while ( pUpdateChain )
     849                 :            :     {
     850                 :          3 :         ScBroadcastArea* pArea = pUpdateChain;
     851                 :          3 :         ScRange aRange( pArea->GetRange());
     852                 :          3 :         pUpdateChain = pArea->GetUpdateChainNext();
     853                 :            : 
     854                 :            :         // update range
     855                 :          3 :         aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
     856         [ +  - ]:          3 :         if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     857                 :            :                 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     858         [ +  - ]:          3 :                 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
     859                 :            :         {
     860                 :          3 :             aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
     861                 :          3 :             pArea->UpdateRange( aRange );
     862 [ +  - ][ +  - ]:          3 :             pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) );   // for DDE
                 [ +  - ]
     863                 :            :         }
     864                 :            : 
     865                 :            :         // insert to slots
     866         [ +  + ]:          6 :         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
     867                 :            :         {
     868         [ +  - ]:          3 :             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
     869         [ -  + ]:          3 :             if (iTab == aTableSlotsMap.end())
     870                 :            :                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
     871 [ #  # ][ #  # ]:          0 :                             nTab, new TableSlots)).first;
                 [ #  # ]
     872                 :          3 :             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
     873                 :            :             SCSIZE nStart, nEnd, nRowBreak;
     874         [ +  - ]:          3 :             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
     875                 :          3 :             SCSIZE nOff = nStart;
     876                 :          3 :             SCSIZE nBreak = nOff + nRowBreak;
     877                 :          3 :             ScBroadcastAreaSlot** pp = ppSlots + nOff;
     878         [ +  + ]:          6 :             while ( nOff <= nEnd )
     879                 :            :             {
     880         [ -  + ]:          3 :                 if (!*pp)
     881 [ #  # ][ #  # ]:          0 :                     *pp = new ScBroadcastAreaSlot( pDoc, this );
     882         [ +  - ]:          3 :                 (*pp)->UpdateInsert( pArea );
     883                 :          3 :                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
     884                 :            :             }
     885                 :            :         }
     886                 :            : 
     887                 :            :         // unchain
     888                 :          3 :         pArea->SetUpdateChainNext( NULL );
     889                 :          3 :         pArea->SetInUpdateChain( false );
     890                 :            : 
     891                 :            :         // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
     892                 :            :         // already executed in UpdateRemove().
     893         [ +  + ]:          3 :         if (!pArea->GetRef())
     894 [ +  - ][ +  - ]:          3 :             delete pArea;
     895                 :            :     }
     896                 :        221 :     pEOUpdateChain = NULL;
     897                 :        221 : }
     898                 :            : 
     899                 :            : 
     900                 :      42678 : void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
     901                 :            : {
     902                 :      42678 :     ++nInBulkBroadcast;
     903                 :      42678 : }
     904                 :            : 
     905                 :            : 
     906                 :      42678 : void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
     907                 :            : {
     908         [ +  - ]:      42678 :     if (nInBulkBroadcast > 0)
     909                 :            :     {
     910         [ +  + ]:      42678 :         if (--nInBulkBroadcast == 0)
     911 [ +  - ][ +  - ]:      39407 :             ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
                 [ +  - ]
     912                 :            :     }
     913                 :      42678 : }
     914                 :            : 
     915                 :            : 
     916                 :        432 : bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
     917                 :            : {
     918                 :        432 :     return aBulkBroadcastAreas.insert( pArea ).second;
     919                 :            : }
     920                 :            : 
     921                 :            : 
     922                 :          0 : size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea* pArea )
     923                 :            : {
     924                 :          0 :     return aBulkBroadcastAreas.erase( pArea );
     925 [ +  - ][ +  - ]:        153 : }
     926                 :            : 
     927                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10