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