Update ooo320-m1
[ooovba.git] / sc / source / core / data / bcaslot.cxx
blob29f54e8dc23c427214cb071640e11d5df072edc6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bcaslot.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 #include <sfx2/objsh.hxx>
37 #include <svtools/listener.hxx>
38 #include <svtools/listeneriter.hxx>
40 #include "document.hxx"
41 #include "brdcst.hxx"
42 #include "bcaslot.hxx"
43 #include "scerrors.hxx"
44 #include "docoptio.hxx"
45 #include "refupdat.hxx"
46 #include "table.hxx"
48 // Number of slots per dimension
49 // must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
50 #define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
51 #if MAXROWCOUNT_DEFINE == 32000
52 #define BCA_SLOTS_ROW 256
53 #else
54 #define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / 128)
55 #endif
56 #define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
57 #define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
58 // multiple?
59 #if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
60 #error bad BCA_SLOTS_COL value!
61 #endif
62 #if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
63 #error bad BCA_SLOTS_ROW value!
64 #endif
65 // size of slot array
66 #define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
67 // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
68 // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
69 // anyway, once you reached these values..
70 #if BCA_SLOTS_DEFINE > 268435456
71 #error BCA_SLOTS_DEFINE DOOMed!
72 #endif
73 // type safe constant
74 const SCSIZE BCA_SLOTS = BCA_SLOTS_DEFINE;
76 // STATIC DATA -----------------------------------------------------------
78 TYPEINIT1( ScHint, SfxSimpleHint );
79 TYPEINIT1( ScAreaChangedHint, SfxHint );
82 ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
83 ScBroadcastAreaSlotMachine* pBASMa ) :
84 aTmpSeekBroadcastArea( ScRange()),
85 pDoc( pDocument ),
86 pBASM( pBASMa )
91 ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
93 for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
94 aIter != aBroadcastAreaTbl.end(); ++aIter)
96 if (!(*aIter)->DecRef())
97 delete *aIter;
102 bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
104 if ( pDoc->GetHardRecalcState() )
105 return true;
106 if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
107 { // this is more hypothetical now, check existed for old SV_PTRARR_SORT
108 if ( !pDoc->GetHardRecalcState() )
110 pDoc->SetHardRecalcState( 1 );
112 SfxObjectShell* pShell = pDoc->GetDocumentShell();
113 DBG_ASSERT( pShell, "Missing DocShell :-/" );
115 if ( pShell )
116 pShell->SetError( SCWARN_CORE_HARD_RECALC, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) );
118 pDoc->SetAutoCalc( FALSE );
119 pDoc->SetHardRecalcState( 2 );
121 return true;
123 return false;
127 bool ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
128 SvtListener* pListener, ScBroadcastArea*& rpArea )
130 bool bNewArea = false;
131 DBG_ASSERT(pListener, "StartListeningArea: pListener Null");
132 if (CheckHardRecalcStateCondition())
133 return false;
134 if ( !rpArea )
136 // Even if most times the area doesn't exist yet and immediately trying
137 // to new and insert it would save an attempt to find it, on mass
138 // operations like identical large [HV]LOOKUP() areas the new/delete
139 // would add quite some penalty for all but the first formula cell.
140 ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
141 if (aIter != aBroadcastAreaTbl.end())
142 rpArea = *aIter;
143 else
145 rpArea = new ScBroadcastArea( rRange);
146 if (aBroadcastAreaTbl.insert( rpArea).second)
148 rpArea->IncRef();
149 bNewArea = true;
151 else
153 DBG_ERRORFILE("StartListeningArea: area not found and not inserted in slot?!?");
154 delete rpArea;
155 rpArea = 0;
158 if (rpArea)
159 pListener->StartListening( rpArea->GetBroadcaster());
161 else
163 if (aBroadcastAreaTbl.insert( rpArea).second)
164 rpArea->IncRef();
166 return bNewArea;
170 void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea* pArea )
172 DBG_ASSERT( pArea, "InsertListeningArea: pArea NULL");
173 if (CheckHardRecalcStateCondition())
174 return;
175 if (aBroadcastAreaTbl.insert( pArea).second)
176 pArea->IncRef();
180 // If rpArea != NULL then no listeners are stopped, only the area is removed
181 // and the reference count decremented.
182 void ScBroadcastAreaSlot::EndListeningArea( const ScRange& rRange,
183 SvtListener* pListener, ScBroadcastArea*& rpArea )
185 DBG_ASSERT(pListener, "EndListeningArea: pListener Null");
186 if ( !rpArea )
188 ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
189 if (aIter == aBroadcastAreaTbl.end())
190 return;
191 rpArea = *aIter;
192 pListener->EndListening( rpArea->GetBroadcaster() );
193 if ( !rpArea->GetBroadcaster().HasListeners() )
194 { // if nobody is listening we can dispose it
195 aBroadcastAreaTbl.erase( aIter);
196 if ( !rpArea->DecRef() )
198 delete rpArea;
199 rpArea = NULL;
203 else
205 if ( !rpArea->GetBroadcaster().HasListeners() )
207 ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
208 if (aIter == aBroadcastAreaTbl.end())
209 return;
210 DBG_ASSERT( *aIter == rpArea, "EndListeningArea: area pointer mismatch");
211 aBroadcastAreaTbl.erase( aIter);
212 if ( !rpArea->DecRef() )
214 delete rpArea;
215 rpArea = NULL;
222 ScBroadcastAreas::iterator ScBroadcastAreaSlot::FindBroadcastArea(
223 const ScRange& rRange ) const
225 aTmpSeekBroadcastArea.UpdateRange( rRange);
226 return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
230 BOOL ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
232 if (aBroadcastAreaTbl.empty())
233 return FALSE;
234 BOOL bIsBroadcasted = FALSE;
235 const ScAddress& rAddress = rHint.GetAddress();
236 for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
237 aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
239 ScBroadcastArea* pArea = *aIter;
240 // A Notify() during broadcast may call EndListeningArea() and thus
241 // dispose this area if it was the last listener, which would
242 // invalidate the iterator, hence increment before call.
243 ++aIter;
244 const ScRange& rAreaRange = pArea->GetRange();
245 if (rAreaRange.In( rAddress))
247 if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
249 pArea->GetBroadcaster().Broadcast( rHint);
250 bIsBroadcasted = TRUE;
254 return bIsBroadcasted;
258 BOOL ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
259 const ScHint& rHint) const
261 if (aBroadcastAreaTbl.empty())
262 return FALSE;
263 BOOL bIsBroadcasted = FALSE;
264 for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
265 aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
267 ScBroadcastArea* pArea = *aIter;
268 // A Notify() during broadcast may call EndListeningArea() and thus
269 // dispose this area if it was the last listener, which would
270 // invalidate the iterator, hence increment before call.
271 ++aIter;
272 const ScRange& rAreaRange = pArea->GetRange();
273 if (rAreaRange.Intersects( rRange ))
275 if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
277 pArea->GetBroadcaster().Broadcast( rHint);
278 bIsBroadcasted = TRUE;
282 return bIsBroadcasted;
286 void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
288 if (aBroadcastAreaTbl.empty())
289 return;
290 for (ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
291 aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
293 const ScRange& rAreaRange = (*aIter)->GetRange();
294 if (rRange.In( rAreaRange))
296 ScBroadcastArea* pArea = *aIter;
297 aBroadcastAreaTbl.erase( aIter++); // erase before modifying
298 if (!pArea->DecRef())
300 if (pBASM->IsInBulkBroadcast())
301 pBASM->RemoveBulkArea( pArea);
302 delete pArea;
305 else
306 ++aIter;
311 void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
312 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
314 if (aBroadcastAreaTbl.empty())
315 return;
317 SCCOL nCol1, nCol2, theCol1, theCol2;
318 SCROW nRow1, nRow2, theRow1, theRow2;
319 SCTAB nTab1, nTab2, theTab1, theTab2;
320 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
321 for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
322 aIter != aBroadcastAreaTbl.end(); /* increment in body */ )
324 ScBroadcastArea* pArea = *aIter;
325 if ( pArea->IsInUpdateChain() )
327 aBroadcastAreaTbl.erase( aIter++);
328 pArea->DecRef();
330 else
332 pArea->GetRange().GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
333 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
334 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
335 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
337 aBroadcastAreaTbl.erase( aIter++);
338 pArea->DecRef();
339 if (pBASM->IsInBulkBroadcast())
340 pBASM->RemoveBulkArea( pArea);
341 pArea->SetInUpdateChain( TRUE );
342 ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
343 if ( pUC )
344 pUC->SetUpdateChainNext( pArea );
345 else // no tail => no head
346 pBASM->SetUpdateChain( pArea );
347 pBASM->SetEOUpdateChain( pArea );
349 else
350 ++aIter;
356 void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
358 ::std::pair< ScBroadcastAreas::iterator, bool > aPair =
359 aBroadcastAreaTbl.insert( pArea );
360 if (aPair.second)
361 pArea->IncRef();
362 else
364 // Identical area already exists, add listeners.
365 ScBroadcastArea* pTarget = *(aPair.first);
366 if (pArea != pTarget)
368 SvtBroadcaster& rTarget = pTarget->GetBroadcaster();
369 SvtListenerIter it( pArea->GetBroadcaster());
370 for (SvtListener* pListener = it.GetCurr(); pListener;
371 pListener = it.GoNext())
373 pListener->StartListening( rTarget);
380 // --- ScBroadcastAreaSlotMachine -------------------------------------
382 ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
384 ppSlots = new ScBroadcastAreaSlot* [ BCA_SLOTS ];
385 memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * BCA_SLOTS );
389 ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
391 for ( ScBroadcastAreaSlot** pp = ppSlots + BCA_SLOTS; --pp >= ppSlots; /* nothing */ )
393 if (*pp)
394 delete *pp;
396 delete [] ppSlots;
400 ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
401 ScDocument* pDocument ) :
402 pBCAlways( NULL ),
403 pDoc( pDocument ),
404 pUpdateChain( NULL ),
405 pEOUpdateChain( NULL ),
406 nInBulkBroadcast( 0 )
408 for (TableSlotsMap::iterator iTab( aTableSlotsMap.begin());
409 iTab != aTableSlotsMap.end(); ++iTab)
411 delete (*iTab).second;
416 ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
418 delete pBCAlways;
422 inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
423 const ScAddress& rAddress ) const
425 SCROW nRow = rAddress.Row();
426 SCCOL nCol = rAddress.Col();
427 if ( !ValidRow(nRow) || !ValidCol(nCol) )
429 DBG_ASSERT( FALSE, "Row/Col ungueltig!" );
430 return 0;
432 else
433 return
434 static_cast<SCSIZE>(nRow) / BCA_SLOT_ROWS +
435 static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * BCA_SLOTS_ROW;
439 void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
440 SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak ) const
442 rStart = ComputeSlotOffset( rRange.aStart );
443 rEnd = ComputeSlotOffset( rRange.aEnd );
444 // count of row slots per column minus one
445 rRowBreak = ComputeSlotOffset(
446 ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
450 void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
451 SvtListener* pListener )
453 if ( rRange == BCA_LISTEN_ALWAYS )
455 if ( !pBCAlways )
456 pBCAlways = new SvtBroadcaster;
457 pListener->StartListening( *pBCAlways );
459 else
461 bool bDone = false;
462 for (SCTAB nTab = rRange.aStart.Tab();
463 !bDone && nTab <= rRange.aEnd.Tab(); ++nTab)
465 TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
466 if (iTab == aTableSlotsMap.end())
467 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
468 nTab, new TableSlots)).first;
469 ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
470 SCSIZE nStart, nEnd, nRowBreak;
471 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
472 SCSIZE nOff = nStart;
473 SCSIZE nBreak = nOff + nRowBreak;
474 ScBroadcastAreaSlot** pp = ppSlots + nOff;
475 ScBroadcastArea* pArea = NULL;
476 while ( !bDone && nOff <= nEnd )
478 if ( !*pp )
479 *pp = new ScBroadcastAreaSlot( pDoc, this );
480 if (!pArea)
482 // If the call to StartListeningArea didn't create the
483 // ScBroadcastArea, listeners were added to an already
484 // existing identical area that doesn't need to be inserted
485 // to slots again.
486 if (!(*pp)->StartListeningArea( rRange, pListener, pArea))
487 bDone = true;
489 else
490 (*pp)->InsertListeningArea( pArea);
491 if ( nOff < nBreak )
493 ++nOff;
494 ++pp;
496 else
498 nStart += BCA_SLOTS_ROW;
499 nOff = nStart;
500 pp = ppSlots + nOff;
501 nBreak = nOff + nRowBreak;
509 void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
510 SvtListener* pListener )
512 if ( rRange == BCA_LISTEN_ALWAYS )
514 DBG_ASSERT( pBCAlways, "ScBroadcastAreaSlotMachine::EndListeningArea: BCA_LISTEN_ALWAYS but none established");
515 if ( pBCAlways )
517 pListener->EndListening( *pBCAlways);
518 if (!pBCAlways->HasListeners())
520 delete pBCAlways;
521 pBCAlways = NULL;
525 else
527 SCTAB nEndTab = rRange.aEnd.Tab();
528 for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
529 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
531 ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
532 SCSIZE nStart, nEnd, nRowBreak;
533 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
534 SCSIZE nOff = nStart;
535 SCSIZE nBreak = nOff + nRowBreak;
536 ScBroadcastAreaSlot** pp = ppSlots + nOff;
537 ScBroadcastArea* pArea = NULL;
538 if (nOff == 0 && nEnd == BCA_SLOTS-1)
540 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
541 // happen for insertion and deletion of sheets.
542 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
545 if ( *pp )
546 (*pp)->EndListeningArea( rRange, pListener, pArea );
547 } while (++pp < pStop);
549 else
551 while ( nOff <= nEnd )
553 if ( *pp )
554 (*pp)->EndListeningArea( rRange, pListener, pArea );
555 if ( nOff < nBreak )
557 ++nOff;
558 ++pp;
560 else
562 nStart += BCA_SLOTS_ROW;
563 nOff = nStart;
564 pp = ppSlots + nOff;
565 nBreak = nOff + nRowBreak;
574 BOOL ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
576 const ScAddress& rAddress = rHint.GetAddress();
577 if ( rAddress == BCA_BRDCST_ALWAYS )
579 if ( pBCAlways )
581 pBCAlways->Broadcast( rHint );
582 return TRUE;
584 else
585 return FALSE;
587 else
589 TableSlotsMap::const_iterator iTab( aTableSlotsMap.find( rAddress.Tab()));
590 if (iTab == aTableSlotsMap.end())
591 return FALSE;
592 ScBroadcastAreaSlot* pSlot = (*iTab).second->getAreaSlot(
593 ComputeSlotOffset( rAddress));
594 if ( pSlot )
595 return pSlot->AreaBroadcast( rHint );
596 else
597 return FALSE;
602 BOOL ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
603 const ScHint& rHint ) const
605 BOOL bBroadcasted = FALSE;
606 SCTAB nEndTab = rRange.aEnd.Tab();
607 for (TableSlotsMap::const_iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
608 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
610 ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
611 SCSIZE nStart, nEnd, nRowBreak;
612 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
613 SCSIZE nOff = nStart;
614 SCSIZE nBreak = nOff + nRowBreak;
615 ScBroadcastAreaSlot** pp = ppSlots + nOff;
616 while ( nOff <= nEnd )
618 if ( *pp )
619 bBroadcasted |= (*pp)->AreaBroadcastInRange( rRange, rHint );
620 if ( nOff < nBreak )
622 ++nOff;
623 ++pp;
625 else
627 nStart += BCA_SLOTS_ROW;
628 nOff = nStart;
629 pp = ppSlots + nOff;
630 nBreak = nOff + nRowBreak;
634 return bBroadcasted;
638 void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
639 const ScRange& rRange )
641 SCTAB nEndTab = rRange.aEnd.Tab();
642 for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
643 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
645 ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
646 SCSIZE nStart, nEnd, nRowBreak;
647 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
648 SCSIZE nOff = nStart;
649 SCSIZE nBreak = nOff + nRowBreak;
650 ScBroadcastAreaSlot** pp = ppSlots + nOff;
651 if (nOff == 0 && nEnd == BCA_SLOTS-1)
653 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
654 // happen for insertion and deletion of sheets.
655 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
658 if ( *pp )
659 (*pp)->DelBroadcastAreasInRange( rRange );
660 } while (++pp < pStop);
662 else
664 while ( nOff <= nEnd )
666 if ( *pp )
667 (*pp)->DelBroadcastAreasInRange( rRange );
668 if ( nOff < nBreak )
670 ++nOff;
671 ++pp;
673 else
675 nStart += BCA_SLOTS_ROW;
676 nOff = nStart;
677 pp = ppSlots + nOff;
678 nBreak = nOff + nRowBreak;
686 // for all affected: remove, chain, update range, insert, and maybe delete
687 void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
688 UpdateRefMode eUpdateRefMode,
689 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
691 // remove affected and put in chain
692 SCTAB nEndTab = rRange.aEnd.Tab();
693 for (TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
694 iTab != aTableSlotsMap.end() && (*iTab).first <= nEndTab; ++iTab)
696 ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
697 SCSIZE nStart, nEnd, nRowBreak;
698 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
699 SCSIZE nOff = nStart;
700 SCSIZE nBreak = nOff + nRowBreak;
701 ScBroadcastAreaSlot** pp = ppSlots + nOff;
702 if (nOff == 0 && nEnd == BCA_SLOTS-1)
704 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
705 // happen for insertion and deletion of sheets.
706 ScBroadcastAreaSlot** const pStop = ppSlots + nEnd;
709 if ( *pp )
710 (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
711 } while (++pp < pStop);
713 else
715 while ( nOff <= nEnd )
717 if ( *pp )
718 (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
719 if ( nOff < nBreak )
721 ++nOff;
722 ++pp;
724 else
726 nStart += BCA_SLOTS_ROW;
727 nOff = nStart;
728 pp = ppSlots + nOff;
729 nBreak = nOff + nRowBreak;
735 // shift sheets
736 if (nDz)
738 if (nDz < 0)
740 TableSlotsMap::iterator iDel( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
741 TableSlotsMap::iterator iTab( aTableSlotsMap.lower_bound( rRange.aStart.Tab() - nDz));
742 // Remove sheets, if any, iDel or/and iTab may as well point to end().
743 while (iDel != iTab)
745 delete (*iDel).second;
746 aTableSlotsMap.erase( iDel++);
748 // shift remaining down
749 while (iTab != aTableSlotsMap.end())
751 SCTAB nTab = (*iTab).first + nDz;
752 aTableSlotsMap[nTab] = (*iTab).second;
753 aTableSlotsMap.erase( iTab++);
756 else
758 TableSlotsMap::iterator iStop( aTableSlotsMap.lower_bound( rRange.aStart.Tab()));
759 if (iStop != aTableSlotsMap.end())
761 bool bStopIsBegin = (iStop == aTableSlotsMap.begin());
762 if (!bStopIsBegin)
763 --iStop;
764 TableSlotsMap::iterator iTab( aTableSlotsMap.end());
765 --iTab;
766 while (iTab != iStop)
768 SCTAB nTab = (*iTab).first + nDz;
769 aTableSlotsMap[nTab] = (*iTab).second;
770 aTableSlotsMap.erase( iTab--);
772 // Shift the very first, iTab==iStop in this case.
773 if (bStopIsBegin)
775 SCTAB nTab = (*iTab).first + nDz;
776 aTableSlotsMap[nTab] = (*iTab).second;
777 aTableSlotsMap.erase( iStop);
783 // work off chain
784 SCCOL nCol1, nCol2, theCol1, theCol2;
785 SCROW nRow1, nRow2, theRow1, theRow2;
786 SCTAB nTab1, nTab2, theTab1, theTab2;
787 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
788 while ( pUpdateChain )
790 ScBroadcastArea* pArea = pUpdateChain;
791 ScRange aRange( pArea->GetRange());
792 pUpdateChain = pArea->GetUpdateChainNext();
794 // update range
795 aRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2);
796 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
797 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
798 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ))
800 aRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
801 pArea->UpdateRange( aRange );
802 pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) ); // for DDE
805 // insert to slots
806 for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
808 TableSlotsMap::iterator iTab( aTableSlotsMap.find( nTab));
809 if (iTab == aTableSlotsMap.end())
810 iTab = aTableSlotsMap.insert( TableSlotsMap::value_type(
811 nTab, new TableSlots)).first;
812 ScBroadcastAreaSlot** ppSlots = (*iTab).second->getSlots();
813 SCSIZE nStart, nEnd, nRowBreak;
814 ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
815 SCSIZE nOff = nStart;
816 SCSIZE nBreak = nOff + nRowBreak;
817 ScBroadcastAreaSlot** pp = ppSlots + nOff;
818 while ( nOff <= nEnd )
820 if (!*pp)
821 *pp = new ScBroadcastAreaSlot( pDoc, this );
822 (*pp)->UpdateInsert( pArea );
823 if ( nOff < nBreak )
825 ++nOff;
826 ++pp;
828 else
830 nStart += BCA_SLOTS_ROW;
831 nOff = nStart;
832 pp = ppSlots + nOff;
833 nBreak = nOff + nRowBreak;
838 // unchain
839 pArea->SetUpdateChainNext( NULL );
840 pArea->SetInUpdateChain( FALSE );
842 // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
843 // already executed in UpdateRemove().
844 if (!pArea->GetRef())
845 delete pArea;
847 pEOUpdateChain = NULL;
851 void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
853 ++nInBulkBroadcast;
857 void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
859 if (nInBulkBroadcast > 0)
861 if (--nInBulkBroadcast == 0)
862 ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
867 bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
869 return aBulkBroadcastAreas.insert( pArea ).second;
873 size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea* pArea )
875 return aBulkBroadcastAreas.erase( pArea );