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