xref: /aoo41x/main/sc/source/core/data/bcaslot.cxx (revision 6d3b264b)
1b3f79822SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3b3f79822SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4b3f79822SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5b3f79822SAndrew Rist  * distributed with this work for additional information
6b3f79822SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7b3f79822SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8b3f79822SAndrew Rist  * "License"); you may not use this file except in compliance
9b3f79822SAndrew Rist  * with the License.  You may obtain a copy of the License at
10b3f79822SAndrew Rist  *
11b3f79822SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12b3f79822SAndrew Rist  *
13b3f79822SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14b3f79822SAndrew Rist  * software distributed under the License is distributed on an
15b3f79822SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16b3f79822SAndrew Rist  * KIND, either express or implied.  See the License for the
17b3f79822SAndrew Rist  * specific language governing permissions and limitations
18b3f79822SAndrew Rist  * under the License.
19b3f79822SAndrew Rist  *
20b3f79822SAndrew Rist  *************************************************************/
21b3f79822SAndrew Rist 
22b3f79822SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sc.hxx"
26cdf0e10cSrcweir 
2757de19abSOliver-Rainer Wittmann #include <boost/mem_fn.hpp>
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <sfx2/objsh.hxx>
30cdf0e10cSrcweir #include <svl/listener.hxx>
31cdf0e10cSrcweir #include <svl/listeneriter.hxx>
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include "document.hxx"
34cdf0e10cSrcweir #include "brdcst.hxx"
35cdf0e10cSrcweir #include "bcaslot.hxx"
36cdf0e10cSrcweir #include "scerrors.hxx"
37cdf0e10cSrcweir #include "docoptio.hxx"
38cdf0e10cSrcweir #include "refupdat.hxx"
39cdf0e10cSrcweir #include "table.hxx"
40cdf0e10cSrcweir 
41cdf0e10cSrcweir // Number of slots per dimension
42cdf0e10cSrcweir // must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
43cdf0e10cSrcweir #define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
44cdf0e10cSrcweir #if MAXROWCOUNT_DEFINE == 32000
45cdf0e10cSrcweir #define BCA_SLOTS_ROW 256
46cdf0e10cSrcweir #define BCA_SLICE 125
47cdf0e10cSrcweir #else
48cdf0e10cSrcweir #define BCA_SLICE 128
49cdf0e10cSrcweir #define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / BCA_SLICE)
50cdf0e10cSrcweir #endif
51cdf0e10cSrcweir #define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
52cdf0e10cSrcweir #define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
53cdf0e10cSrcweir // multiple?
54cdf0e10cSrcweir #if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
55cdf0e10cSrcweir #error bad BCA_SLOTS_COL value!
56cdf0e10cSrcweir #endif
57cdf0e10cSrcweir #if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
58cdf0e10cSrcweir #error bad BCA_SLOTS_ROW value!
59cdf0e10cSrcweir #endif
60cdf0e10cSrcweir // size of slot array if linear
61cdf0e10cSrcweir #define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
62cdf0e10cSrcweir // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
63cdf0e10cSrcweir // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
64cdf0e10cSrcweir // anyway, once you reached these values..
65cdf0e10cSrcweir #if BCA_SLOTS_DEFINE > 268435456
66cdf0e10cSrcweir #error BCA_SLOTS_DEFINE DOOMed!
67cdf0e10cSrcweir #endif
68cdf0e10cSrcweir 
69cdf0e10cSrcweir // STATIC DATA -----------------------------------------------------------
70cdf0e10cSrcweir 
71cdf0e10cSrcweir TYPEINIT1( ScHint, SfxSimpleHint );
72cdf0e10cSrcweir TYPEINIT1( ScAreaChangedHint, SfxHint );
73cdf0e10cSrcweir 
74cdf0e10cSrcweir struct ScSlotData
75cdf0e10cSrcweir {
76cdf0e10cSrcweir     SCROW  nStartRow;   // first row of this segment
77cdf0e10cSrcweir     SCROW  nStopRow;    // first row of next segment
78cdf0e10cSrcweir     SCSIZE nSlice;      // slice size in this segment
79cdf0e10cSrcweir     SCSIZE nCumulated;  // cumulated slots of previous segments
80cdf0e10cSrcweir 
ScSlotDataScSlotData81cdf0e10cSrcweir     ScSlotData( SCROW r1, SCROW r2, SCSIZE s, SCSIZE c ) : nStartRow(r1), nStopRow(r2), nSlice(s), nCumulated(c) {}
82cdf0e10cSrcweir };
83cdf0e10cSrcweir typedef ::std::vector< ScSlotData > ScSlotDistribution;
84cdf0e10cSrcweir #if MAXROWCOUNT_DEFINE <= 65536
85cdf0e10cSrcweir // Linear distribution.
86cdf0e10cSrcweir static ScSlotDistribution aSlotDistribution( ScSlotData( 0, MAXROWCOUNT, BCA_SLOT_ROWS, 0));
87cdf0e10cSrcweir static SCSIZE nBcaSlotsRow = BCA_SLOTS_ROW;
88cdf0e10cSrcweir static SCSIZE nBcaSlots = BCA_SLOTS_DEFINE;
89cdf0e10cSrcweir #else
90cdf0e10cSrcweir // Logarithmic or any other distribution.
91cdf0e10cSrcweir // Upper sheet part usually is more populated and referenced and gets fine
92cdf0e10cSrcweir // grained resolution, larger data in larger hunks.
93cdf0e10cSrcweir // Could be further enhanced by also applying a different distribution of
94cdf0e10cSrcweir // column slots.
initSlotDistribution(ScSlotDistribution & rSD,SCSIZE & rBSR)95cdf0e10cSrcweir static SCSIZE initSlotDistribution( ScSlotDistribution & rSD, SCSIZE & rBSR )
96cdf0e10cSrcweir {
97cdf0e10cSrcweir     SCSIZE nSlots = 0;
98cdf0e10cSrcweir     SCROW nRow1 = 0;
99cdf0e10cSrcweir     SCROW nRow2 = 32*1024;
100cdf0e10cSrcweir     SCSIZE nSlice = 128;
101cdf0e10cSrcweir     // Must be sorted by row1,row2!
102cdf0e10cSrcweir     while (nRow2 <= MAXROWCOUNT)
103cdf0e10cSrcweir     {
104cdf0e10cSrcweir         //fprintf( stderr, "r1,r2,slice,cum: %7zu, %7zu, %7zu, %7zu\n", (size_t)nRow1, (size_t)nRow2, (size_t)nSlice, (size_t)nSlots);
105cdf0e10cSrcweir         // {0,32k,128,0;32k,64k,256,0+256;64k,128k,512,0+256+128;128k,256k,1024,0+256+128+128;256k,512k,2048,...;512k,1M,4096,...}
106cdf0e10cSrcweir         rSD.push_back( ScSlotData( nRow1, nRow2, nSlice, nSlots));
107cdf0e10cSrcweir         nSlots += (nRow2 - nRow1) / nSlice;
108cdf0e10cSrcweir         nRow1 = nRow2;
109cdf0e10cSrcweir         nRow2 *= 2;
110cdf0e10cSrcweir         nSlice *= 2;
111cdf0e10cSrcweir     }
112cdf0e10cSrcweir     //fprintf( stderr, "Slices: %zu, slots per sheet: %zu, memory per referenced sheet: %zu\n", (size_t) nSlots, (size_t) nSlots * BCA_SLOTS_COL, (size_t) nSlots * BCA_SLOTS_COL * sizeof(void*));
113cdf0e10cSrcweir     rBSR = nSlots;
114cdf0e10cSrcweir     return nSlots;
115cdf0e10cSrcweir }
116cdf0e10cSrcweir static ScSlotDistribution aSlotDistribution;
117cdf0e10cSrcweir static SCSIZE nBcaSlotsRow;
118cdf0e10cSrcweir static SCSIZE nBcaSlots = initSlotDistribution( aSlotDistribution, nBcaSlotsRow) * BCA_SLOTS_COL;
119cdf0e10cSrcweir // Ensure that all static variables are initialized with this one call.
120cdf0e10cSrcweir #endif
121cdf0e10cSrcweir 
122cdf0e10cSrcweir 
ScBroadcastAreaSlot(ScDocument * pDocument,ScBroadcastAreaSlotMachine * pBASMa)123cdf0e10cSrcweir ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
124cdf0e10cSrcweir         ScBroadcastAreaSlotMachine* pBASMa ) :
125cdf0e10cSrcweir     aTmpSeekBroadcastArea( ScRange()),
126cdf0e10cSrcweir     pDoc( pDocument ),
127cdf0e10cSrcweir     pBASM( pBASMa )
128cdf0e10cSrcweir {
129cdf0e10cSrcweir }
130cdf0e10cSrcweir 
131cdf0e10cSrcweir 
~ScBroadcastAreaSlot()132cdf0e10cSrcweir ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
133cdf0e10cSrcweir {
134cdf0e10cSrcweir     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
135cdf0e10cSrcweir             aIter != aBroadcastAreaTbl.end(); /* none */)
136cdf0e10cSrcweir     {
137cdf0e10cSrcweir         // Prevent hash from accessing dangling pointer in case area is
138cdf0e10cSrcweir         // deleted.
139cdf0e10cSrcweir         ScBroadcastArea* pArea = *aIter;
140cdf0e10cSrcweir         // Erase all so no hash will be accessed upon destruction of the
141cdf0e10cSrcweir         // hash_set.
142cdf0e10cSrcweir         aBroadcastAreaTbl.erase( aIter++);
143cdf0e10cSrcweir         if (!pArea->DecRef())
144cdf0e10cSrcweir             delete pArea;
145cdf0e10cSrcweir     }
146cdf0e10cSrcweir }
147cdf0e10cSrcweir 
148cdf0e10cSrcweir 
CheckHardRecalcStateCondition() const149cdf0e10cSrcweir bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
150cdf0e10cSrcweir {
151cdf0e10cSrcweir     if ( pDoc->GetHardRecalcState() )
152cdf0e10cSrcweir         return true;
153cdf0e10cSrcweir     if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
154cdf0e10cSrcweir     {   // this is more hypothetical now, check existed for old SV_PTRARR_SORT
155cdf0e10cSrcweir         if ( !pDoc->GetHardRecalcState() )
156cdf0e10cSrcweir         {
157cdf0e10cSrcweir             pDoc->SetHardRecalcState( 1 );
158cdf0e10cSrcweir 
159cdf0e10cSrcweir             SfxObjectShell* pShell = pDoc->GetDocumentShell();
160cdf0e10cSrcweir             DBG_ASSERT( pShell, "Missing DocShell :-/" );
161cdf0e10cSrcweir 
162cdf0e10cSrcweir 			if ( pShell )
163cdf0e10cSrcweir 				pShell->SetError( SCWARN_CORE_HARD_RECALC, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
164cdf0e10cSrcweir 
165cdf0e10cSrcweir             pDoc->SetAutoCalc( sal_False );
166cdf0e10cSrcweir             pDoc->SetHardRecalcState( 2 );
167cdf0e10cSrcweir         }
168cdf0e10cSrcweir         return true;
169cdf0e10cSrcweir     }
170cdf0e10cSrcweir     return false;
171cdf0e10cSrcweir }
172cdf0e10cSrcweir 
173cdf0e10cSrcweir 
StartListeningArea(const ScRange & rRange,SvtListener * pListener,ScBroadcastArea * & rpArea)174cdf0e10cSrcweir bool ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
175cdf0e10cSrcweir         SvtListener* pListener, ScBroadcastArea*& rpArea )
176cdf0e10cSrcweir {
177cdf0e10cSrcweir     bool bNewArea = false;
178cdf0e10cSrcweir     DBG_ASSERT(pListener, "StartListeningArea: pListener Null");
179cdf0e10cSrcweir     if (CheckHardRecalcStateCondition())
180cdf0e10cSrcweir         return false;
181cdf0e10cSrcweir     if ( !rpArea )
182cdf0e10cSrcweir     {
183cdf0e10cSrcweir         // Even if most times the area doesn't exist yet and immediately trying
184cdf0e10cSrcweir         // to new and insert it would save an attempt to find it, on mass
185cdf0e10cSrcweir         // operations like identical large [HV]LOOKUP() areas the new/delete
186cdf0e10cSrcweir         // would add quite some penalty for all but the first formula cell.
187cdf0e10cSrcweir         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
188cdf0e10cSrcweir         if (aIter != aBroadcastAreaTbl.end())
189cdf0e10cSrcweir             rpArea = *aIter;
190cdf0e10cSrcweir         else
191cdf0e10cSrcweir         {
192cdf0e10cSrcweir             rpArea = new ScBroadcastArea( rRange);
193cdf0e10cSrcweir             if (aBroadcastAreaTbl.insert( rpArea).second)
194cdf0e10cSrcweir             {
195cdf0e10cSrcweir                 rpArea->IncRef();
196cdf0e10cSrcweir                 bNewArea = true;
197cdf0e10cSrcweir             }
198cdf0e10cSrcweir             else
199cdf0e10cSrcweir             {
200cdf0e10cSrcweir                 DBG_ERRORFILE("StartListeningArea: area not found and not inserted in slot?!?");
201cdf0e10cSrcweir                 delete rpArea;
202cdf0e10cSrcweir                 rpArea = 0;
203cdf0e10cSrcweir             }
204cdf0e10cSrcweir         }
205cdf0e10cSrcweir         if (rpArea)
206cdf0e10cSrcweir             pListener->StartListening( rpArea->GetBroadcaster());
207cdf0e10cSrcweir     }
208cdf0e10cSrcweir     else
209cdf0e10cSrcweir     {
210cdf0e10cSrcweir         if (aBroadcastAreaTbl.insert( rpArea).second)
211cdf0e10cSrcweir             rpArea->IncRef();
212cdf0e10cSrcweir     }
213cdf0e10cSrcweir     return bNewArea;
214cdf0e10cSrcweir }
215cdf0e10cSrcweir 
216cdf0e10cSrcweir 
InsertListeningArea(ScBroadcastArea * pArea)217cdf0e10cSrcweir void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea* pArea )
218cdf0e10cSrcweir {
219cdf0e10cSrcweir     DBG_ASSERT( pArea, "InsertListeningArea: pArea NULL");
220cdf0e10cSrcweir     if (CheckHardRecalcStateCondition())
221cdf0e10cSrcweir         return;
222cdf0e10cSrcweir     if (aBroadcastAreaTbl.insert( pArea).second)
223cdf0e10cSrcweir         pArea->IncRef();
224cdf0e10cSrcweir }
225cdf0e10cSrcweir 
226cdf0e10cSrcweir 
227cdf0e10cSrcweir // If rpArea != NULL then no listeners are stopped, only the area is removed
228cdf0e10cSrcweir // and the reference count decremented.
EndListeningArea(const ScRange & rRange,SvtListener * pListener,ScBroadcastArea * & rpArea)229cdf0e10cSrcweir void ScBroadcastAreaSlot::EndListeningArea( const ScRange& rRange,
230cdf0e10cSrcweir         SvtListener* pListener, ScBroadcastArea*& rpArea )
231cdf0e10cSrcweir {
232cdf0e10cSrcweir     DBG_ASSERT(pListener, "EndListeningArea: pListener Null");
233cdf0e10cSrcweir     if ( !rpArea )
234cdf0e10cSrcweir     {
235*6d3b264bSHerbert Dürr         ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
236cdf0e10cSrcweir         if (aIter == aBroadcastAreaTbl.end())
237cdf0e10cSrcweir             return;
238cdf0e10cSrcweir         rpArea = *aIter;
239cdf0e10cSrcweir         pListener->EndListening( rpArea->GetBroadcaster() );
240cdf0e10cSrcweir         if ( !rpArea->GetBroadcaster().HasListeners() )
241cdf0e10cSrcweir         {   // if nobody is listening we can dispose it
242cdf0e10cSrcweir             aBroadcastAreaTbl.erase( aIter);
243cdf0e10cSrcweir             if ( !rpArea->DecRef() )
244cdf0e10cSrcweir             {
245cdf0e10cSrcweir                 delete rpArea;
246cdf0e10cSrcweir                 rpArea = NULL;
247cdf0e10cSrcweir             }
248cdf0e10cSrcweir         }
249cdf0e10cSrcweir     }
250cdf0e10cSrcweir     else
251cdf0e10cSrcweir     {
252cdf0e10cSrcweir         if ( !rpArea->GetBroadcaster().HasListeners() )
253cdf0e10cSrcweir         {
254*6d3b264bSHerbert Dürr             ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
255cdf0e10cSrcweir             if (aIter == aBroadcastAreaTbl.end())
256cdf0e10cSrcweir                 return;
257cdf0e10cSrcweir             DBG_ASSERT( *aIter == rpArea, "EndListeningArea: area pointer mismatch");
258cdf0e10cSrcweir             aBroadcastAreaTbl.erase( aIter);
259cdf0e10cSrcweir             if ( !rpArea->DecRef() )
260cdf0e10cSrcweir             {
261cdf0e10cSrcweir                 delete rpArea;
262cdf0e10cSrcweir                 rpArea = NULL;
263cdf0e10cSrcweir             }
264cdf0e10cSrcweir         }
265cdf0e10cSrcweir     }
266cdf0e10cSrcweir }
267cdf0e10cSrcweir 
268cdf0e10cSrcweir 
FindBroadcastArea(const ScRange & rRange) const269*6d3b264bSHerbert Dürr ScBroadcastAreas::const_iterator ScBroadcastAreaSlot::FindBroadcastArea(
270cdf0e10cSrcweir         const ScRange& rRange ) const
271cdf0e10cSrcweir {
272cdf0e10cSrcweir     aTmpSeekBroadcastArea.UpdateRange( rRange);
273cdf0e10cSrcweir     return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
274cdf0e10cSrcweir }
275cdf0e10cSrcweir 
276cdf0e10cSrcweir 
AreaBroadcast(const ScHint & rHint) const277cdf0e10cSrcweir sal_Bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
278cdf0e10cSrcweir {
279cdf0e10cSrcweir     if (aBroadcastAreaTbl.empty())
280cdf0e10cSrcweir         return sal_False;
281cdf0e10cSrcweir     sal_Bool bIsBroadcasted = sal_False;
28257de19abSOliver-Rainer Wittmann 
28357de19abSOliver-Rainer Wittmann     // issue 118012
28457de19abSOliver-Rainer Wittmann     // do not iterate on <aBoardcastAreaTbl> as its reveals that its iterators
28557de19abSOliver-Rainer Wittmann     // are destroyed during notification.
28657de19abSOliver-Rainer Wittmann     std::vector< ScBroadcastArea* > aCopyForIteration( aBroadcastAreaTbl.begin(), aBroadcastAreaTbl.end() );
28757de19abSOliver-Rainer Wittmann     std::for_each( aCopyForIteration.begin(), aCopyForIteration.end(), boost::mem_fn( &ScBroadcastArea::IncRef ) );
28857de19abSOliver-Rainer Wittmann 
289cdf0e10cSrcweir     const ScAddress& rAddress = rHint.GetAddress();
29057de19abSOliver-Rainer Wittmann     const std::vector< ScBroadcastArea* >::const_iterator aEnd( aCopyForIteration.end() );
29157de19abSOliver-Rainer Wittmann     std::vector< ScBroadcastArea* >::const_iterator aIter;
29257de19abSOliver-Rainer Wittmann     for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
293cdf0e10cSrcweir     {
294cdf0e10cSrcweir         ScBroadcastArea* pArea = *aIter;
29557de19abSOliver-Rainer Wittmann         // check, if copied item has been already removed from <aBroadcastAreaTbl>
29657de19abSOliver-Rainer Wittmann         if ( aBroadcastAreaTbl.find( pArea ) == aBroadcastAreaTbl.end() )
29757de19abSOliver-Rainer Wittmann         {
29857de19abSOliver-Rainer Wittmann             continue;
29957de19abSOliver-Rainer Wittmann         }
30057de19abSOliver-Rainer Wittmann 
301cdf0e10cSrcweir         const ScRange& rAreaRange = pArea->GetRange();
302cdf0e10cSrcweir         if (rAreaRange.In( rAddress))
303cdf0e10cSrcweir         {
304cdf0e10cSrcweir             if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
305cdf0e10cSrcweir             {
306cdf0e10cSrcweir                 pArea->GetBroadcaster().Broadcast( rHint);
307cdf0e10cSrcweir                 bIsBroadcasted = sal_True;
308cdf0e10cSrcweir             }
309cdf0e10cSrcweir         }
310cdf0e10cSrcweir     }
31157de19abSOliver-Rainer Wittmann 
31257de19abSOliver-Rainer Wittmann     // delete no longer referenced <ScBroadcastArea> instances
31357de19abSOliver-Rainer Wittmann     for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
31457de19abSOliver-Rainer Wittmann     {
31557de19abSOliver-Rainer Wittmann         ScBroadcastArea* pArea = *aIter;
31657de19abSOliver-Rainer Wittmann         if ( !pArea->DecRef() )
31757de19abSOliver-Rainer Wittmann         {
31857de19abSOliver-Rainer Wittmann             delete pArea;
31957de19abSOliver-Rainer Wittmann         }
32057de19abSOliver-Rainer Wittmann     }
32157de19abSOliver-Rainer Wittmann 
322cdf0e10cSrcweir     return bIsBroadcasted;
323cdf0e10cSrcweir }
324cdf0e10cSrcweir 
325cdf0e10cSrcweir 
AreaBroadcastInRange(const ScRange & rRange,const ScHint & rHint) const326cdf0e10cSrcweir sal_Bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
327cdf0e10cSrcweir         const ScHint& rHint) const
328cdf0e10cSrcweir {
329cdf0e10cSrcweir     if (aBroadcastAreaTbl.empty())
330cdf0e10cSrcweir         return sal_False;
331cdf0e10cSrcweir     sal_Bool bIsBroadcasted = sal_False;
33257de19abSOliver-Rainer Wittmann 
33357de19abSOliver-Rainer Wittmann     // issue 118012
33457de19abSOliver-Rainer Wittmann     // do not iterate on <aBoardcastAreaTbl> as its reveals that its iterators
33557de19abSOliver-Rainer Wittmann     // are destroyed during notification.
33657de19abSOliver-Rainer Wittmann     std::vector< ScBroadcastArea* > aCopyForIteration( aBroadcastAreaTbl.begin(), aBroadcastAreaTbl.end() );
33757de19abSOliver-Rainer Wittmann     std::for_each( aCopyForIteration.begin(), aCopyForIteration.end(), boost::mem_fn( &ScBroadcastArea::IncRef ) );
33857de19abSOliver-Rainer Wittmann 
33957de19abSOliver-Rainer Wittmann     const std::vector< ScBroadcastArea* >::const_iterator aEnd( aCopyForIteration.end() );
34057de19abSOliver-Rainer Wittmann     std::vector< ScBroadcastArea* >::const_iterator aIter;
34157de19abSOliver-Rainer Wittmann     for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
342cdf0e10cSrcweir     {
343cdf0e10cSrcweir         ScBroadcastArea* pArea = *aIter;
34457de19abSOliver-Rainer Wittmann         // check, if copied item has been already removed from <aBroadcastAreaTbl>
34557de19abSOliver-Rainer Wittmann         if ( aBroadcastAreaTbl.find( pArea ) == aBroadcastAreaTbl.end() )
34657de19abSOliver-Rainer Wittmann         {
34757de19abSOliver-Rainer Wittmann             continue;
34857de19abSOliver-Rainer Wittmann         }
34957de19abSOliver-Rainer Wittmann 
350cdf0e10cSrcweir         const ScRange& rAreaRange = pArea->GetRange();
351cdf0e10cSrcweir         if (rAreaRange.Intersects( rRange ))
352cdf0e10cSrcweir         {
353cdf0e10cSrcweir             if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
354cdf0e10cSrcweir             {
355cdf0e10cSrcweir                 pArea->GetBroadcaster().Broadcast( rHint);
356cdf0e10cSrcweir                 bIsBroadcasted = sal_True;
357cdf0e10cSrcweir             }
358cdf0e10cSrcweir         }
359cdf0e10cSrcweir     }
36057de19abSOliver-Rainer Wittmann 
36157de19abSOliver-Rainer Wittmann     // delete no longer referenced <ScBroadcastArea> instances
36257de19abSOliver-Rainer Wittmann     for ( aIter = aCopyForIteration.begin(); aIter != aEnd; ++aIter )
36357de19abSOliver-Rainer Wittmann     {
36457de19abSOliver-Rainer Wittmann         ScBroadcastArea* pArea = *aIter;
36557de19abSOliver-Rainer Wittmann         if ( !pArea->DecRef() )
36657de19abSOliver-Rainer Wittmann         {
36757de19abSOliver-Rainer Wittmann             delete pArea;
36857de19abSOliver-Rainer Wittmann         }
36957de19abSOliver-Rainer Wittmann     }
37057de19abSOliver-Rainer Wittmann 
371cdf0e10cSrcweir     return bIsBroadcasted;
372cdf0e10cSrcweir }
373cdf0e10cSrcweir 
374cdf0e10cSrcweir 
DelBroadcastAreasInRange(const ScRange & rRange)375cdf0e10cSrcweir void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
376cdf0e10cSrcweir {
377cdf0e10cSrcweir     if (aBroadcastAreaTbl.empty())
378cdf0e10cSrcweir         return;
379cdf0e10cSrcweir     for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
380cdf0e10cSrcweir             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
381cdf0e10cSrcweir     {
382cdf0e10cSrcweir         const ScRange& rAreaRange = (*aIter)->GetRange();
383cdf0e10cSrcweir         if (rRange.In( rAreaRange))
384cdf0e10cSrcweir         {
385cdf0e10cSrcweir             ScBroadcastArea* pArea = *aIter;
386cdf0e10cSrcweir             aBroadcastAreaTbl.erase( aIter++);  // erase before modifying
387cdf0e10cSrcweir             if (!pArea->DecRef())
388cdf0e10cSrcweir             {
389cdf0e10cSrcweir                 if (pBASM->IsInBulkBroadcast())
390cdf0e10cSrcweir                     pBASM->RemoveBulkArea( pArea);
391cdf0e10cSrcweir                 delete pArea;
392cdf0e10cSrcweir             }
393cdf0e10cSrcweir         }
394cdf0e10cSrcweir         else
395cdf0e10cSrcweir             ++aIter;
396cdf0e10cSrcweir     }
397cdf0e10cSrcweir }
398cdf0e10cSrcweir 
399cdf0e10cSrcweir 
UpdateRemove(UpdateRefMode eUpdateRefMode,const ScRange & rRange,SCsCOL nDx,SCsROW nDy,SCsTAB nDz)400cdf0e10cSrcweir void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
401cdf0e10cSrcweir         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
402cdf0e10cSrcweir {
403cdf0e10cSrcweir     if (aBroadcastAreaTbl.empty())
404cdf0e10cSrcweir         return;
405cdf0e10cSrcweir 
406cdf0e10cSrcweir     SCCOL nCol1, nCol2, theCol1, theCol2;
407cdf0e10cSrcweir     SCROW nRow1, nRow2, theRow1, theRow2;
408cdf0e10cSrcweir     SCTAB nTab1, nTab2, theTab1, theTab2;
409cdf0e10cSrcweir     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
410cdf0e10cSrcweir     for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
411cdf0e10cSrcweir             aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
412cdf0e10cSrcweir     {
413cdf0e10cSrcweir         ScBroadcastArea* pArea = *aIter;
414cdf0e10cSrcweir         if ( pArea->IsInUpdateChain() )
415cdf0e10cSrcweir         {
416cdf0e10cSrcweir             aBroadcastAreaTbl.erase( aIter++);
417cdf0e10cSrcweir             pArea->DecRef();
418cdf0e10cSrcweir         }
419cdf0e10cSrcweir         else
420cdf0e10cSrcweir         {
421cdf0e10cSrcweir             pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
422cdf0e10cSrcweir             if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
423cdf0e10cSrcweir                     nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
424cdf0e10cSrcweir                     theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
425cdf0e10cSrcweir             {
426cdf0e10cSrcweir                 aBroadcastAreaTbl.erase( aIter++);
427cdf0e10cSrcweir                 pArea->DecRef();
428cdf0e10cSrcweir                 if (pBASM->IsInBulkBroadcast())
429cdf0e10cSrcweir                     pBASM->RemoveBulkArea( pArea);
430cdf0e10cSrcweir                 pArea->SetInUpdateChain( sal_True );
431cdf0e10cSrcweir                 ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
432cdf0e10cSrcweir                 if ( pUC )
433cdf0e10cSrcweir                     pUC->SetUpdateChainNext( pArea );
434cdf0e10cSrcweir                 else    // no tail => no head
435cdf0e10cSrcweir                     pBASM->SetUpdateChain( pArea );
436cdf0e10cSrcweir                 pBASM->SetEOUpdateChain( pArea );
437cdf0e10cSrcweir             }
438cdf0e10cSrcweir             else
439cdf0e10cSrcweir                 ++aIter;
440cdf0e10cSrcweir         }
441cdf0e10cSrcweir     }
442cdf0e10cSrcweir }
443cdf0e10cSrcweir 
444cdf0e10cSrcweir 
UpdateRemoveArea(ScBroadcastArea * pArea)445cdf0e10cSrcweir void ScBroadcastAreaSlot::UpdateRemoveArea( ScBroadcastArea* pArea )
446cdf0e10cSrcweir {
447cdf0e10cSrcweir     ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.find( pArea));
448cdf0e10cSrcweir     if (aIter == aBroadcastAreaTbl.end())
449cdf0e10cSrcweir         return;
450cdf0e10cSrcweir     if (*aIter != pArea)
451cdf0e10cSrcweir         DBG_ERRORFILE( "UpdateRemoveArea: area pointer mismatch");
452cdf0e10cSrcweir     else
453cdf0e10cSrcweir     {
454cdf0e10cSrcweir         aBroadcastAreaTbl.erase( aIter);
455cdf0e10cSrcweir         pArea->DecRef();
456cdf0e10cSrcweir     }
457cdf0e10cSrcweir }
458cdf0e10cSrcweir 
459cdf0e10cSrcweir 
UpdateInsert(ScBroadcastArea * pArea)460cdf0e10cSrcweir void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
461cdf0e10cSrcweir {
462cdf0e10cSrcweir     ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
463cdf0e10cSrcweir         aBroadcastAreaTbl.insert( pArea );
464cdf0e10cSrcweir     if (aPair.second)
465cdf0e10cSrcweir         pArea->IncRef();
466cdf0e10cSrcweir     else
467cdf0e10cSrcweir     {
468cdf0e10cSrcweir         // Identical area already exists, add listeners.
469cdf0e10cSrcweir         ScBroadcastArea* pTarget = *(aPair.first);
470cdf0e10cSrcweir         if (pArea != pTarget)
471cdf0e10cSrcweir         {
472cdf0e10cSrcweir             SvtBroadcaster& rTarget = pTarget->GetBroadcaster();
473cdf0e10cSrcweir             SvtListenerIter it( pArea->GetBroadcaster());
474cdf0e10cSrcweir             for (SvtListener* pListener = it.GetCurr(); pListener;
475cdf0e10cSrcweir                     pListener = it.GoNext())
476cdf0e10cSrcweir             {
477cdf0e10cSrcweir                 pListener->StartListening( rTarget);
478cdf0e10cSrcweir             }
479cdf0e10cSrcweir         }
480cdf0e10cSrcweir     }
481cdf0e10cSrcweir }
482cdf0e10cSrcweir 
483cdf0e10cSrcweir 
484cdf0e10cSrcweir // --- ScBroadcastAreaSlotMachine -------------------------------------
485cdf0e10cSrcweir 
TableSlots()486cdf0e10cSrcweir ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
487cdf0e10cSrcweir {
488cdf0e10cSrcweir     ppSlots = new ScBroadcastAreaSlot* [ nBcaSlots ];
489cdf0e10cSrcweir     memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * nBcaSlots );
490cdf0e10cSrcweir }
491cdf0e10cSrcweir 
492cdf0e10cSrcweir 
~TableSlots()493cdf0e10cSrcweir ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
494cdf0e10cSrcweir {
495cdf0e10cSrcweir     for ( ScBroadcastAreaSlot** pp = ppSlots + nBcaSlots; --pp >= ppSlots; /* nothing */ )
496cdf0e10cSrcweir     {
497cdf0e10cSrcweir         if (*pp)
498cdf0e10cSrcweir             delete *pp;
499cdf0e10cSrcweir     }
500cdf0e10cSrcweir     delete [] ppSlots;
501cdf0e10cSrcweir }
502cdf0e10cSrcweir 
503cdf0e10cSrcweir 
ScBroadcastAreaSlotMachine(ScDocument * pDocument)504cdf0e10cSrcweir ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
505cdf0e10cSrcweir         ScDocument* pDocument ) :
506cdf0e10cSrcweir     pBCAlways( NULL ),
507cdf0e10cSrcweir     pDoc( pDocument ),
508cdf0e10cSrcweir     pUpdateChain( NULL ),
509cdf0e10cSrcweir     pEOUpdateChain( NULL ),
510cdf0e10cSrcweir     nInBulkBroadcast( 0 )
511cdf0e10cSrcweir {
512cdf0e10cSrcweir }
513cdf0e10cSrcweir 
514cdf0e10cSrcweir 
~ScBroadcastAreaSlotMachine()515cdf0e10cSrcweir ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
516cdf0e10cSrcweir {
517cdf0e10cSrcweir     for (TableSlotsMap::iterator iTab( aTableSlotsMap.begin());
518cdf0e10cSrcweir             iTab != aTableSlotsMap.end(); ++iTab)
519cdf0e10cSrcweir     {
520cdf0e10cSrcweir         delete (*iTab).second;
521cdf0e10cSrcweir     }
522cdf0e10cSrcweir     delete pBCAlways;
523cdf0e10cSrcweir }
524cdf0e10cSrcweir 
525cdf0e10cSrcweir 
ComputeSlotOffset(const ScAddress & rAddress) const526cdf0e10cSrcweir inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
527cdf0e10cSrcweir         const ScAddress& rAddress ) const
528cdf0e10cSrcweir {
529cdf0e10cSrcweir     SCROW nRow = rAddress.Row();
530cdf0e10cSrcweir     SCCOL nCol = rAddress.Col();
531cdf0e10cSrcweir     if ( !ValidRow(nRow) || !ValidCol(nCol) )
532cdf0e10cSrcweir     {
533cdf0e10cSrcweir         DBG_ERRORFILE( "Row/Col invalid, using first slot!" );
534cdf0e10cSrcweir         return 0;
535cdf0e10cSrcweir     }
536cdf0e10cSrcweir     for (size_t i=0; i < aSlotDistribution.size(); ++i)
537cdf0e10cSrcweir     {
538cdf0e10cSrcweir         if (nRow < aSlotDistribution[i].nStopRow)
539cdf0e10cSrcweir         {
540cdf0e10cSrcweir             const ScSlotData& rSD = aSlotDistribution[i];
541cdf0e10cSrcweir             return rSD.nCumulated +
542cdf0e10cSrcweir                 (static_cast<SCSIZE>(nRow - rSD.nStartRow)) / rSD.nSlice +
543cdf0e10cSrcweir                 static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * nBcaSlotsRow;
544cdf0e10cSrcweir         }
545cdf0e10cSrcweir     }
546cdf0e10cSrcweir     DBG_ERRORFILE( "No slot found, using last!" );
547cdf0e10cSrcweir     return nBcaSlots - 1;
548cdf0e10cSrcweir }
549cdf0e10cSrcweir 
550cdf0e10cSrcweir 
ComputeAreaPoints(const ScRange & rRange,SCSIZE & rStart,SCSIZE & rEnd,SCSIZE & rRowBreak) const551cdf0e10cSrcweir void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
552cdf0e10cSrcweir         SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak ) const
553cdf0e10cSrcweir {
554cdf0e10cSrcweir     rStart = ComputeSlotOffset( rRange.aStart );
555cdf0e10cSrcweir     rEnd = ComputeSlotOffset( rRange.aEnd );
556cdf0e10cSrcweir     // count of row slots per column minus one
557cdf0e10cSrcweir     rRowBreak = ComputeSlotOffset(
558cdf0e10cSrcweir         ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
559cdf0e10cSrcweir }
560cdf0e10cSrcweir 
561cdf0e10cSrcweir 
ComputeNextSlot(SCSIZE & nOff,SCSIZE & nBreak,ScBroadcastAreaSlot ** & pp,SCSIZE & nStart,ScBroadcastAreaSlot ** const & ppSlots,SCSIZE const & nRowBreak)562cdf0e10cSrcweir inline void ComputeNextSlot( SCSIZE & nOff, SCSIZE & nBreak, ScBroadcastAreaSlot** & pp,
563cdf0e10cSrcweir         SCSIZE & nStart, ScBroadcastAreaSlot** const & ppSlots, SCSIZE const & nRowBreak )
564cdf0e10cSrcweir {
565cdf0e10cSrcweir     if ( nOff < nBreak )
566cdf0e10cSrcweir     {
567cdf0e10cSrcweir         ++nOff;
568cdf0e10cSrcweir         ++pp;
569cdf0e10cSrcweir     }
570cdf0e10cSrcweir     else
571cdf0e10cSrcweir     {
572cdf0e10cSrcweir         nStart += nBcaSlotsRow;
573cdf0e10cSrcweir         nOff = nStart;
574cdf0e10cSrcweir         pp = ppSlots + nOff;
575cdf0e10cSrcweir         nBreak = nOff + nRowBreak;
576cdf0e10cSrcweir     }
577cdf0e10cSrcweir }
578cdf0e10cSrcweir 
579cdf0e10cSrcweir 
StartListeningArea(const ScRange & rRange,SvtListener * pListener)580cdf0e10cSrcweir void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
581cdf0e10cSrcweir         SvtListener* pListener )
582cdf0e10cSrcweir {
583cdf0e10cSrcweir     //fprintf( stderr, "StartListeningArea (c,r,t): %d, %d, %d, %d, %d, %d\n", (int)rRange.aStart.Col(), (int)rRange.aStart.Row(), (int)rRange.aStart.Tab(), (int)rRange.aEnd.Col(), (int)rRange.aEnd.Row(), (int)rRange.aEnd.Tab());
584cdf0e10cSrcweir     if ( rRange == BCA_LISTEN_ALWAYS  )
585cdf0e10cSrcweir     {
586cdf0e10cSrcweir         if ( !pBCAlways )
587cdf0e10cSrcweir             pBCAlways = new SvtBroadcaster;
588cdf0e10cSrcweir         pListener->StartListening( *pBCAlways );
589cdf0e10cSrcweir     }
590cdf0e10cSrcweir     else
591cdf0e10cSrcweir     {
592cdf0e10cSrcweir         bool bDone = false;
593cdf0e10cSrcweir         for (SCTAB nTab = rRange.aStart.Tab();
594cdf0e10cSrcweir                 !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
595cdf0e10cSrcweir         {
596cdf0e10cSrcweir             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
597cdf0e10cSrcweir             if (iTab == aTableSlotsMap.end())
598cdf0e10cSrcweir                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
599cdf0e10cSrcweir                             nTab, new TableSlots)).first;
600cdf0e10cSrcweir             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
601cdf0e10cSrcweir             SCSIZE nStart, nEnd, nRowBreak;
602cdf0e10cSrcweir             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
603cdf0e10cSrcweir             SCSIZE nOff = nStart;
604cdf0e10cSrcweir             SCSIZE nBreak = nOff + nRowBreak;
605cdf0e10cSrcweir             ScBroadcastAreaSlot** pp = ppSlots + nOff;
606cdf0e10cSrcweir             ScBroadcastArea* pArea = NULL;
607cdf0e10cSrcweir             while ( !bDone && nOff <= nEnd )
608cdf0e10cSrcweir             {
609cdf0e10cSrcweir                 if ( !*pp )
610cdf0e10cSrcweir                     *pp = new ScBroadcastAreaSlot( pDoc, this );
611cdf0e10cSrcweir                 if (!pArea)
612cdf0e10cSrcweir                 {
613cdf0e10cSrcweir                     // If the call to StartListeningArea didn't create the
614cdf0e10cSrcweir                     // ScBroadcastArea, listeners were added to an already
615cdf0e10cSrcweir                     // existing identical area that doesn't need to be inserted
616cdf0e10cSrcweir                     // to slots again.
617cdf0e10cSrcweir                     if (!(*pp)->StartListeningArea( rRange, pListener, pArea))
618cdf0e10cSrcweir                         bDone = true;
619cdf0e10cSrcweir                 }
620cdf0e10cSrcweir                 else
621cdf0e10cSrcweir                     (*pp)->InsertListeningArea( pArea);
622cdf0e10cSrcweir                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
623cdf0e10cSrcweir             }
624cdf0e10cSrcweir         }
625cdf0e10cSrcweir     }
626cdf0e10cSrcweir }
627cdf0e10cSrcweir 
628cdf0e10cSrcweir 
EndListeningArea(const ScRange & rRange,SvtListener * pListener)629cdf0e10cSrcweir void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
630cdf0e10cSrcweir         SvtListener* pListener )
631cdf0e10cSrcweir {
632cdf0e10cSrcweir     //fprintf( stderr, "EndListeningArea (c,r,t): %d, %d, %d, %d, %d, %d\n", (int)rRange.aStart.Col(), (int)rRange.aStart.Row(), (int)rRange.aStart.Tab(), (int)rRange.aEnd.Col(), (int)rRange.aEnd.Row(), (int)rRange.aEnd.Tab());
633cdf0e10cSrcweir     if ( rRange == BCA_LISTEN_ALWAYS  )
634cdf0e10cSrcweir     {
635cdf0e10cSrcweir         DBG_ASSERT( pBCAlways, "ScBroadcastAreaSlotMachine::EndListeningArea: BCA_LISTEN_ALWAYS but none established");
636cdf0e10cSrcweir         if ( pBCAlways )
637cdf0e10cSrcweir         {
638cdf0e10cSrcweir             pListener->EndListening( *pBCAlways);
639cdf0e10cSrcweir             if (!pBCAlways->HasListeners())
640cdf0e10cSrcweir             {
641cdf0e10cSrcweir                 delete pBCAlways;
642cdf0e10cSrcweir                 pBCAlways = NULL;
643cdf0e10cSrcweir             }
644cdf0e10cSrcweir         }
645cdf0e10cSrcweir     }
646cdf0e10cSrcweir     else
647cdf0e10cSrcweir     {
648cdf0e10cSrcweir         SCTAB nEndTab = rRange.aEnd.Tab();
649cdf0e10cSrcweir         for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
650cdf0e10cSrcweir                 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
651cdf0e10cSrcweir         {
652cdf0e10cSrcweir             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
653cdf0e10cSrcweir             SCSIZE nStart, nEnd, nRowBreak;
654cdf0e10cSrcweir             ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
655cdf0e10cSrcweir             SCSIZE nOff = nStart;
656cdf0e10cSrcweir             SCSIZE nBreak = nOff + nRowBreak;
657cdf0e10cSrcweir             ScBroadcastAreaSlot** pp = ppSlots + nOff;
658cdf0e10cSrcweir             ScBroadcastArea* pArea = NULL;
659cdf0e10cSrcweir             if (nOff == 0 && nEnd == nBcaSlots-1)
660cdf0e10cSrcweir             {
661cdf0e10cSrcweir                 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
662cdf0e10cSrcweir                 // happen for insertion and deletion of sheets.
663cdf0e10cSrcweir                 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
664cdf0e10cSrcweir                 do
665cdf0e10cSrcweir                 {
666cdf0e10cSrcweir                     if ( *pp )
667cdf0e10cSrcweir                         (*pp)->EndListeningArea( rRange, pListener, pArea );
668cdf0e10cSrcweir                 } while (++pp < pStop);
669cdf0e10cSrcweir             }
670cdf0e10cSrcweir             else
671cdf0e10cSrcweir             {
672cdf0e10cSrcweir                 while ( nOff <= nEnd )
673cdf0e10cSrcweir                 {
674cdf0e10cSrcweir                     if ( *pp )
675cdf0e10cSrcweir                         (*pp)->EndListeningArea( rRange, pListener, pArea );
676cdf0e10cSrcweir                     ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
677cdf0e10cSrcweir                 }
678cdf0e10cSrcweir             }
679cdf0e10cSrcweir         }
680cdf0e10cSrcweir     }
681cdf0e10cSrcweir }
682cdf0e10cSrcweir 
683cdf0e10cSrcweir 
AreaBroadcast(const ScHint & rHint) const684cdf0e10cSrcweir sal_Bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
685cdf0e10cSrcweir {
686cdf0e10cSrcweir     const ScAddress& rAddress = rHint.GetAddress();
687cdf0e10cSrcweir     if ( rAddress == BCA_BRDCST_ALWAYS )
688cdf0e10cSrcweir     {
689cdf0e10cSrcweir         if ( pBCAlways )
690cdf0e10cSrcweir         {
691cdf0e10cSrcweir             pBCAlways->Broadcast( rHint );
692cdf0e10cSrcweir             return sal_True;
693cdf0e10cSrcweir         }
694cdf0e10cSrcweir         else
695cdf0e10cSrcweir             return sal_False;
696cdf0e10cSrcweir     }
697cdf0e10cSrcweir     else
698cdf0e10cSrcweir     {
699cdf0e10cSrcweir         TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
700cdf0e10cSrcweir         if (iTab == aTableSlotsMap.end())
701cdf0e10cSrcweir             return sal_False;
702cdf0e10cSrcweir         ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
703cdf0e10cSrcweir                 ComputeSlotOffset( rAddress));
704cdf0e10cSrcweir         if ( pSlot )
705cdf0e10cSrcweir             return pSlot->AreaBroadcast( rHint );
706cdf0e10cSrcweir         else
707cdf0e10cSrcweir             return sal_False;
708cdf0e10cSrcweir     }
709cdf0e10cSrcweir }
710cdf0e10cSrcweir 
711cdf0e10cSrcweir 
AreaBroadcastInRange(const ScRange & rRange,const ScHint & rHint) const712cdf0e10cSrcweir sal_Bool ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
713cdf0e10cSrcweir         const ScHint& rHint ) const
714cdf0e10cSrcweir {
715cdf0e10cSrcweir     sal_Bool bBroadcasted = sal_False;
716cdf0e10cSrcweir     SCTAB nEndTab = rRange.aEnd.Tab();
717cdf0e10cSrcweir     for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
718cdf0e10cSrcweir             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
719cdf0e10cSrcweir     {
720cdf0e10cSrcweir         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
721cdf0e10cSrcweir         SCSIZE nStart, nEnd, nRowBreak;
722cdf0e10cSrcweir         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
723cdf0e10cSrcweir         SCSIZE nOff = nStart;
724cdf0e10cSrcweir         SCSIZE nBreak = nOff + nRowBreak;
725cdf0e10cSrcweir         ScBroadcastAreaSlot** pp = ppSlots + nOff;
726cdf0e10cSrcweir         while ( nOff <= nEnd )
727cdf0e10cSrcweir         {
728cdf0e10cSrcweir             if ( *pp )
729cdf0e10cSrcweir                 bBroadcasted |= (*pp)->AreaBroadcastInRange( rRange, rHint );
730cdf0e10cSrcweir             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
731cdf0e10cSrcweir         }
732cdf0e10cSrcweir     }
733cdf0e10cSrcweir     return bBroadcasted;
734cdf0e10cSrcweir }
735cdf0e10cSrcweir 
736cdf0e10cSrcweir 
DelBroadcastAreasInRange(const ScRange & rRange)737cdf0e10cSrcweir void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
738cdf0e10cSrcweir         const ScRange& rRange )
739cdf0e10cSrcweir {
740cdf0e10cSrcweir     SCTAB nEndTab = rRange.aEnd.Tab();
741cdf0e10cSrcweir     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
742cdf0e10cSrcweir             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
743cdf0e10cSrcweir     {
744cdf0e10cSrcweir         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
745cdf0e10cSrcweir         SCSIZE nStart, nEnd, nRowBreak;
746cdf0e10cSrcweir         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
747cdf0e10cSrcweir         SCSIZE nOff = nStart;
748cdf0e10cSrcweir         SCSIZE nBreak = nOff + nRowBreak;
749cdf0e10cSrcweir         ScBroadcastAreaSlot** pp = ppSlots + nOff;
750cdf0e10cSrcweir         if (nOff == 0 && nEnd == nBcaSlots-1)
751cdf0e10cSrcweir         {
752cdf0e10cSrcweir             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
753cdf0e10cSrcweir             // happen for insertion and deletion of sheets.
754cdf0e10cSrcweir             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
755cdf0e10cSrcweir             do
756cdf0e10cSrcweir             {
757cdf0e10cSrcweir                 if ( *pp )
758cdf0e10cSrcweir                     (*pp)->DelBroadcastAreasInRange( rRange );
759cdf0e10cSrcweir             } while (++pp < pStop);
760cdf0e10cSrcweir         }
761cdf0e10cSrcweir         else
762cdf0e10cSrcweir         {
763cdf0e10cSrcweir             while ( nOff <= nEnd )
764cdf0e10cSrcweir             {
765cdf0e10cSrcweir                 if ( *pp )
766cdf0e10cSrcweir                     (*pp)->DelBroadcastAreasInRange( rRange );
767cdf0e10cSrcweir                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
768cdf0e10cSrcweir             }
769cdf0e10cSrcweir         }
770cdf0e10cSrcweir     }
771cdf0e10cSrcweir }
772cdf0e10cSrcweir 
773cdf0e10cSrcweir 
774cdf0e10cSrcweir // for all affected: remove, chain, update range, insert, and maybe delete
UpdateBroadcastAreas(UpdateRefMode eUpdateRefMode,const ScRange & rRange,SCsCOL nDx,SCsROW nDy,SCsTAB nDz)775cdf0e10cSrcweir void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
776cdf0e10cSrcweir         UpdateRefMode eUpdateRefMode,
777cdf0e10cSrcweir         const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
778cdf0e10cSrcweir {
779cdf0e10cSrcweir     // remove affected and put in chain
780cdf0e10cSrcweir     SCTAB nEndTab = rRange.aEnd.Tab();
781cdf0e10cSrcweir     for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
782cdf0e10cSrcweir             iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
783cdf0e10cSrcweir     {
784cdf0e10cSrcweir         ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
785cdf0e10cSrcweir         SCSIZE nStart, nEnd, nRowBreak;
786cdf0e10cSrcweir         ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
787cdf0e10cSrcweir         SCSIZE nOff = nStart;
788cdf0e10cSrcweir         SCSIZE nBreak = nOff + nRowBreak;
789cdf0e10cSrcweir         ScBroadcastAreaSlot** pp = ppSlots + nOff;
790cdf0e10cSrcweir         if (nOff == 0 && nEnd == nBcaSlots-1)
791cdf0e10cSrcweir         {
792cdf0e10cSrcweir             // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
793cdf0e10cSrcweir             // happen for insertion and deletion of sheets.
794cdf0e10cSrcweir             ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
795cdf0e10cSrcweir             do
796cdf0e10cSrcweir             {
797cdf0e10cSrcweir                 if ( *pp )
798cdf0e10cSrcweir                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
799cdf0e10cSrcweir             } while (++pp < pStop);
800cdf0e10cSrcweir         }
801cdf0e10cSrcweir         else
802cdf0e10cSrcweir         {
803cdf0e10cSrcweir             while ( nOff <= nEnd )
804cdf0e10cSrcweir             {
805cdf0e10cSrcweir                 if ( *pp )
806cdf0e10cSrcweir                     (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
807cdf0e10cSrcweir                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
808cdf0e10cSrcweir             }
809cdf0e10cSrcweir         }
810cdf0e10cSrcweir     }
811cdf0e10cSrcweir 
812cdf0e10cSrcweir     // Updating an area's range will modify the hash key, remove areas from all
813cdf0e10cSrcweir     // affected slots. Will be reinserted later with the updated range.
814cdf0e10cSrcweir     ScBroadcastArea* pChain = pUpdateChain;
815cdf0e10cSrcweir     while (pChain)
816cdf0e10cSrcweir     {
817cdf0e10cSrcweir         ScBroadcastArea* pArea = pChain;
818cdf0e10cSrcweir         pChain = pArea->GetUpdateChainNext();
819cdf0e10cSrcweir         ScRange aRange( pArea->GetRange());
820cdf0e10cSrcweir         // remove from slots
821cdf0e10cSrcweir         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab() && pArea->GetRef(); ++nTab)
822cdf0e10cSrcweir         {
823cdf0e10cSrcweir             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
824cdf0e10cSrcweir             if (iTab == aTableSlotsMap.end())
825cdf0e10cSrcweir             {
826cdf0e10cSrcweir                 DBG_ERRORFILE( "UpdateBroadcastAreas: Where's the TableSlot?!?");
827cdf0e10cSrcweir                 continue;   // for
828cdf0e10cSrcweir             }
829cdf0e10cSrcweir             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
830cdf0e10cSrcweir             SCSIZE nStart, nEnd, nRowBreak;
831cdf0e10cSrcweir             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
832cdf0e10cSrcweir             SCSIZE nOff = nStart;
833cdf0e10cSrcweir             SCSIZE nBreak = nOff + nRowBreak;
834cdf0e10cSrcweir             ScBroadcastAreaSlot** pp = ppSlots + nOff;
835cdf0e10cSrcweir             while ( nOff <= nEnd && pArea->GetRef() )
836cdf0e10cSrcweir             {
837cdf0e10cSrcweir                 if (*pp)
838cdf0e10cSrcweir                     (*pp)->UpdateRemoveArea( pArea);
839cdf0e10cSrcweir                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
840cdf0e10cSrcweir             }
841cdf0e10cSrcweir         }
842cdf0e10cSrcweir 
843cdf0e10cSrcweir     }
844cdf0e10cSrcweir 
845cdf0e10cSrcweir     // shift sheets
846cdf0e10cSrcweir     if (nDz)
847cdf0e10cSrcweir     {
848cdf0e10cSrcweir         if (nDz < 0)
849cdf0e10cSrcweir         {
850cdf0e10cSrcweir             TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
851cdf0e10cSrcweir             TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab() - nDz));
852cdf0e10cSrcweir             // Remove sheets, if any, iDel or/and iTab may as well point to end().
853cdf0e10cSrcweir             while (iDel != iTab)
854cdf0e10cSrcweir             {
855cdf0e10cSrcweir                 delete (*iDel).second;
856cdf0e10cSrcweir                 aTableSlotsMap.erase( iDel++);
857cdf0e10cSrcweir             }
858cdf0e10cSrcweir             // shift remaining down
859cdf0e10cSrcweir             while (iTab != aTableSlotsMap.end())
860cdf0e10cSrcweir             {
861cdf0e10cSrcweir                 SCTAB nTab = (*iTab).first + nDz;
862cdf0e10cSrcweir                 aTableSlotsMap[nTab] = (*iTab).second;
863cdf0e10cSrcweir                 aTableSlotsMap.erase( iTab++);
864cdf0e10cSrcweir             }
865cdf0e10cSrcweir         }
866cdf0e10cSrcweir         else
867cdf0e10cSrcweir         {
868cdf0e10cSrcweir             TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
869cdf0e10cSrcweir             if (iStop != aTableSlotsMap.end())
870cdf0e10cSrcweir             {
871cdf0e10cSrcweir                 bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
872cdf0e10cSrcweir                 if (!bStopIsBegin)
873cdf0e10cSrcweir                     --iStop;
874cdf0e10cSrcweir                 TableSlotsMap::iterator iTab( aTableSlotsMap.end());
875cdf0e10cSrcweir                 --iTab;
876cdf0e10cSrcweir                 while (iTab != iStop)
877cdf0e10cSrcweir                 {
878cdf0e10cSrcweir                     SCTAB nTab = (*iTab).first + nDz;
879cdf0e10cSrcweir                     aTableSlotsMap[nTab] = (*iTab).second;
880cdf0e10cSrcweir                     aTableSlotsMap.erase( iTab--);
881cdf0e10cSrcweir                 }
882cdf0e10cSrcweir                 // Shift the very first, iTab==iStop in this case.
883cdf0e10cSrcweir                 if (bStopIsBegin)
884cdf0e10cSrcweir                 {
885cdf0e10cSrcweir                     SCTAB nTab = (*iTab).first + nDz;
886cdf0e10cSrcweir                     aTableSlotsMap[nTab] = (*iTab).second;
887cdf0e10cSrcweir                     aTableSlotsMap.erase( iStop);
888cdf0e10cSrcweir                 }
889cdf0e10cSrcweir             }
890cdf0e10cSrcweir         }
891cdf0e10cSrcweir     }
892cdf0e10cSrcweir 
893cdf0e10cSrcweir     // work off chain
894cdf0e10cSrcweir     SCCOL nCol1, nCol2, theCol1, theCol2;
895cdf0e10cSrcweir     SCROW nRow1, nRow2, theRow1, theRow2;
896cdf0e10cSrcweir     SCTAB nTab1, nTab2, theTab1, theTab2;
897cdf0e10cSrcweir     rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
898cdf0e10cSrcweir     while ( pUpdateChain )
899cdf0e10cSrcweir     {
900cdf0e10cSrcweir         ScBroadcastArea* pArea = pUpdateChain;
901cdf0e10cSrcweir         ScRange aRange( pArea->GetRange());
902cdf0e10cSrcweir         pUpdateChain = pArea->GetUpdateChainNext();
903cdf0e10cSrcweir 
904cdf0e10cSrcweir         // update range
905cdf0e10cSrcweir         aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
906cdf0e10cSrcweir         if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
907cdf0e10cSrcweir                 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
908cdf0e10cSrcweir                 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
909cdf0e10cSrcweir         {
910cdf0e10cSrcweir             aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
911cdf0e10cSrcweir             pArea->UpdateRange( aRange );
912cdf0e10cSrcweir             pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) );   // for DDE
913cdf0e10cSrcweir         }
914cdf0e10cSrcweir 
915cdf0e10cSrcweir         // insert to slots
916cdf0e10cSrcweir         for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
917cdf0e10cSrcweir         {
918cdf0e10cSrcweir             TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
919cdf0e10cSrcweir             if (iTab == aTableSlotsMap.end())
920cdf0e10cSrcweir                 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
921cdf0e10cSrcweir                             nTab, new TableSlots)).first;
922cdf0e10cSrcweir             ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
923cdf0e10cSrcweir             SCSIZE nStart, nEnd, nRowBreak;
924cdf0e10cSrcweir             ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
925cdf0e10cSrcweir             SCSIZE nOff = nStart;
926cdf0e10cSrcweir             SCSIZE nBreak = nOff + nRowBreak;
927cdf0e10cSrcweir             ScBroadcastAreaSlot** pp = ppSlots + nOff;
928cdf0e10cSrcweir             while ( nOff <= nEnd )
929cdf0e10cSrcweir             {
930cdf0e10cSrcweir                 if (!*pp)
931cdf0e10cSrcweir                     *pp = new ScBroadcastAreaSlot( pDoc, this );
932cdf0e10cSrcweir                 (*pp)->UpdateInsert( pArea );
933cdf0e10cSrcweir                 ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
934cdf0e10cSrcweir             }
935cdf0e10cSrcweir         }
936cdf0e10cSrcweir 
937cdf0e10cSrcweir         // unchain
938cdf0e10cSrcweir         pArea->SetUpdateChainNext( NULL );
939cdf0e10cSrcweir         pArea->SetInUpdateChain( sal_False );
940cdf0e10cSrcweir 
941cdf0e10cSrcweir         // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
942cdf0e10cSrcweir         // already executed in UpdateRemove().
943cdf0e10cSrcweir         if (!pArea->GetRef())
944cdf0e10cSrcweir             delete pArea;
945cdf0e10cSrcweir     }
946cdf0e10cSrcweir     pEOUpdateChain = NULL;
947cdf0e10cSrcweir }
948cdf0e10cSrcweir 
949cdf0e10cSrcweir 
EnterBulkBroadcast()950cdf0e10cSrcweir void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
951cdf0e10cSrcweir {
952cdf0e10cSrcweir     ++nInBulkBroadcast;
953cdf0e10cSrcweir }
954cdf0e10cSrcweir 
955cdf0e10cSrcweir 
LeaveBulkBroadcast()956cdf0e10cSrcweir void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
957cdf0e10cSrcweir {
958cdf0e10cSrcweir     if (nInBulkBroadcast > 0)
959cdf0e10cSrcweir     {
960cdf0e10cSrcweir         if (--nInBulkBroadcast == 0)
961cdf0e10cSrcweir             ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
962cdf0e10cSrcweir     }
963cdf0e10cSrcweir }
964cdf0e10cSrcweir 
965cdf0e10cSrcweir 
InsertBulkArea(const ScBroadcastArea * pArea)966cdf0e10cSrcweir bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
967cdf0e10cSrcweir {
968cdf0e10cSrcweir     return aBulkBroadcastAreas.insert( pArea ).second;
969cdf0e10cSrcweir }
970cdf0e10cSrcweir 
971cdf0e10cSrcweir 
RemoveBulkArea(const ScBroadcastArea * pArea)972cdf0e10cSrcweir size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea* pArea )
973cdf0e10cSrcweir {
974cdf0e10cSrcweir     return aBulkBroadcastAreas.erase( pArea );
975cdf0e10cSrcweir }
976