update ooo310-m15
[ooovba.git] / sc / source / core / data / bcaslot.cxx
blob6fe8b4828ca8189fdc48d040a65a103ef067a927
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>
39 #include "document.hxx"
40 #include "brdcst.hxx"
41 #include "bcaslot.hxx"
42 #include "scerrors.hxx"
43 #include "docoptio.hxx"
44 #include "refupdat.hxx"
45 #include "table.hxx"
47 // Number of slots per dimension
48 // must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
49 #define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
50 #if MAXROWCOUNT_DEFINE == 32000
51 #define BCA_SLOTS_ROW 256
52 #else
53 #define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / 128)
54 #endif
55 #define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
56 #define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
57 // multiple?
58 #if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
59 #error bad BCA_SLOTS_COL value!
60 #endif
61 #if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
62 #error bad BCA_SLOTS_ROW value!
63 #endif
64 // size of slot array
65 #define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
66 // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
67 // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
68 // anyway, once you reached these values..
69 #if BCA_SLOTS_DEFINE > 268435456
70 #error BCA_SLOTS_DEFINE DOOMed!
71 #endif
72 // type safe constant
73 const SCSIZE BCA_SLOTS = BCA_SLOTS_DEFINE;
75 // STATIC DATA -----------------------------------------------------------
77 TYPEINIT1( ScHint, SfxSimpleHint );
78 TYPEINIT1( ScAreaChangedHint, SfxHint );
81 ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
82 ScBroadcastAreaSlotMachine* pBASMa ) :
83 aTmpSeekBroadcastArea( ScRange()),
84 pDoc( pDocument ),
85 pBASM( pBASMa )
90 ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
92 for ( ScBroadcastAreas::iterator aIter = aBroadcastAreaTbl.begin();
93 aIter != aBroadcastAreaTbl.end(); ++aIter)
95 if (!(*aIter)->DecRef())
96 delete *aIter;
101 // Only here new ScBroadcastArea objects are created, prevention of dupes.
102 // If rpArea != NULL then no listeners are startet, only the area is inserted
103 // and the reference count increased.
104 void ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
105 SvtListener* pListener, ScBroadcastArea*& rpArea
108 DBG_ASSERT(pListener, "StartListeningArea: pListener Null");
109 if ( pDoc->GetHardRecalcState() )
110 return;
111 if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
112 { // this is more hypothetical now, check existed for old SV_PTRARR_SORT
113 if ( !pDoc->GetHardRecalcState() )
115 pDoc->SetHardRecalcState( 1 );
117 SfxObjectShell* pShell = pDoc->GetDocumentShell();
118 DBG_ASSERT( pShell, "Missing DocShell :-/" );
120 if ( pShell )
121 pShell->SetError( SCWARN_CORE_HARD_RECALC );
123 pDoc->SetAutoCalc( FALSE );
124 pDoc->SetHardRecalcState( 2 );
126 return;
128 if ( !rpArea )
130 rpArea = new ScBroadcastArea( rRange );
131 // Most times the area doesn't exist yet, immediately trying to insert
132 // it saves an attempt to find it.
133 if (aBroadcastAreaTbl.insert( rpArea).second)
134 rpArea->IncRef();
135 else
137 delete rpArea;
138 ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
139 if (aIter != aBroadcastAreaTbl.end())
140 rpArea = *aIter;
141 else
143 DBG_ERRORFILE("BroadcastArea not inserted and not found?!?");
144 rpArea = 0;
147 if (rpArea)
148 pListener->StartListening( rpArea->GetBroadcaster() );
150 else
152 aBroadcastAreaTbl.insert( rpArea );
153 rpArea->IncRef();
158 // If rpArea != NULL then no listeners are stopped, only the area is removed
159 // and the reference count decreased.
160 void ScBroadcastAreaSlot::EndListeningArea( const ScRange& rRange,
161 SvtListener* pListener, ScBroadcastArea*& rpArea
164 DBG_ASSERT(pListener, "EndListeningArea: pListener Null");
165 if ( !rpArea )
167 ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
168 if (aIter == aBroadcastAreaTbl.end())
169 return;
170 rpArea = *aIter;
171 pListener->EndListening( rpArea->GetBroadcaster() );
172 if ( !rpArea->GetBroadcaster().HasListeners() )
173 { // if nobody is listening we can dispose it
174 aBroadcastAreaTbl.erase( aIter);
175 if ( !rpArea->DecRef() )
177 delete rpArea;
178 rpArea = NULL;
182 else
184 if ( !rpArea->GetBroadcaster().HasListeners() )
186 ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
187 if (aIter == aBroadcastAreaTbl.end())
188 return;
189 aBroadcastAreaTbl.erase( aIter);
190 if ( !rpArea->DecRef() )
192 delete rpArea;
193 rpArea = NULL;
200 ScBroadcastAreas::iterator ScBroadcastAreaSlot::FindBroadcastArea(
201 const ScRange& rRange ) const
203 aTmpSeekBroadcastArea.UpdateRange( rRange);
204 return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
208 BOOL ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
210 if (aBroadcastAreaTbl.empty())
211 return FALSE;
212 BOOL bIsBroadcasted = FALSE;
213 const ScAddress& rAddress = rHint.GetAddress();
214 // Unfortunately we can't search for the first matching entry.
215 ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
216 while (aIter != aBroadcastAreaTbl.end())
218 ScBroadcastArea* pArea = *aIter;
219 // A Notify() during broadcast may call EndListeningArea() and thus
220 // dispose this area if it was the last listener, which would
221 // invalidate the iterator, hence increment before call.
222 ++aIter;
223 const ScRange& rAreaRange = pArea->GetRange();
224 if (rAreaRange.In( rAddress))
226 if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
228 pArea->GetBroadcaster().Broadcast( rHint);
229 bIsBroadcasted = TRUE;
232 else if (rAddress < rAreaRange.aStart)
233 break; // while loop, only ranges greater than rAddress follow
235 return bIsBroadcasted;
239 BOOL ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
240 const ScHint& rHint) const
242 if (aBroadcastAreaTbl.empty())
243 return FALSE;
244 BOOL bIsBroadcasted = FALSE;
245 // Unfortunately we can't search for the first matching entry.
246 ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
247 while (aIter != aBroadcastAreaTbl.end())
249 ScBroadcastArea* pArea = *aIter;
250 // A Notify() during broadcast may call EndListeningArea() and thus
251 // dispose this area if it was the last listener, which would
252 // invalidate the iterator, hence increment before call.
253 ++aIter;
254 const ScRange& rAreaRange = pArea->GetRange();
255 if (rAreaRange.Intersects( rRange ))
257 if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
259 pArea->GetBroadcaster().Broadcast( rHint);
260 bIsBroadcasted = TRUE;
263 else if (rRange.aEnd < rAreaRange.aStart)
264 break; // while loop, only ranges greater than end address follow
266 return bIsBroadcasted;
270 void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
272 if (aBroadcastAreaTbl.empty())
273 return;
274 // Searching for areas bound completely within rRange, so it's fine to
275 // exclude all upper left corners smaller than the upper left corner of
276 // rRange and get a lower bound.
277 aTmpSeekBroadcastArea.UpdateRange( ScRange( rRange.aStart));
278 // Search for lower bound, inclusive, not less than.
279 ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.lower_bound(
280 &aTmpSeekBroadcastArea));
281 for ( ; aIter != aBroadcastAreaTbl.end(); )
283 const ScRange& rAreaRange = (*aIter)->GetRange();
284 if (rRange.In( rAreaRange))
286 ScBroadcastArea* pArea = *aIter;
287 if (!pArea->DecRef())
289 if (pBASM->IsInBulkBroadcast())
290 pBASM->RemoveBulkArea( pArea);
291 delete pArea;
293 ScBroadcastAreas::iterator aDel( aIter);
294 ++aIter;
295 aBroadcastAreaTbl.erase( aDel);
297 else if (rRange.aEnd < rAreaRange.aStart)
298 break; // for loop, only ranges greater than end address follow
299 else
300 ++aIter;
305 void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
306 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
309 if (aBroadcastAreaTbl.empty())
310 return;
312 SCCOL nCol1, nCol2, theCol1, theCol2;
313 SCROW nRow1, nRow2, theRow1, theRow2;
314 SCTAB nTab1, nTab2, theTab1, theTab2;
315 nCol1 = rRange.aStart.Col();
316 nRow1 = rRange.aStart.Row();
317 nTab1 = rRange.aStart.Tab();
318 nCol2 = rRange.aEnd.Col();
319 nRow2 = rRange.aEnd.Row();
320 nTab2 = rRange.aEnd.Tab();
321 for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
322 aIter != aBroadcastAreaTbl.end(); )
324 ScBroadcastArea* pArea = *aIter;
325 ScBroadcastAreas::iterator aDel( aIter);
326 ++aIter;
327 if ( pArea->IsInUpdateChain() )
329 aBroadcastAreaTbl.erase( aDel);
330 pArea->DecRef();
332 else
334 const ScAddress& rAdr1 = pArea->GetStart();
335 theCol1 = rAdr1.Col();
336 theRow1 = rAdr1.Row();
337 theTab1 = rAdr1.Tab();
338 const ScAddress& rAdr2 = pArea->GetEnd();
339 theCol2 = rAdr2.Col();
340 theRow2 = rAdr2.Row();
341 theTab2 = rAdr2.Tab();
342 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
343 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
344 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 )
347 aBroadcastAreaTbl.erase( aDel);
348 pArea->DecRef();
349 if (pBASM->IsInBulkBroadcast())
350 pBASM->RemoveBulkArea( pArea);
351 pArea->SetInUpdateChain( TRUE );
352 ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
353 if ( pUC )
354 pUC->SetUpdateChainNext( pArea );
355 else // no tail => no head
356 pBASM->SetUpdateChain( pArea );
357 pBASM->SetEOUpdateChain( pArea );
364 void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
366 aBroadcastAreaTbl.insert( pArea );
367 pArea->IncRef();
371 // --- ScBroadcastAreaSlotMachine -------------------------------------
373 ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
374 ScDocument* pDocument ) :
375 pBCAlways( NULL ),
376 pDoc( pDocument ),
377 pUpdateChain( NULL ),
378 pEOUpdateChain( NULL ),
379 nInBulkBroadcast( 0 )
381 ppSlots = new ScBroadcastAreaSlot* [ BCA_SLOTS ];
382 memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * BCA_SLOTS );
386 ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
388 for ( ScBroadcastAreaSlot** pp = ppSlots + BCA_SLOTS; --pp >= ppSlots; )
390 if ( *pp )
391 delete *pp;
393 delete[] ppSlots;
395 delete pBCAlways;
399 inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
400 const ScAddress& rAddress ) const
402 SCROW nRow = rAddress.Row();
403 SCCOL nCol = rAddress.Col();
404 if ( !ValidRow(nRow) || !ValidCol(nCol) )
406 DBG_ASSERT( FALSE, "Row/Col ungueltig!" );
407 return 0;
409 else
410 return
411 static_cast<SCSIZE>(nRow) / BCA_SLOT_ROWS +
412 static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * BCA_SLOTS_ROW;
416 void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
417 SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak
418 ) const
420 rStart = ComputeSlotOffset( rRange.aStart );
421 rEnd = ComputeSlotOffset( rRange.aEnd );
422 // count of row slots per column minus one
423 rRowBreak = ComputeSlotOffset(
424 ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
428 void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
429 SvtListener* pListener
432 if ( rRange == BCA_LISTEN_ALWAYS )
434 if ( !pBCAlways )
435 pBCAlways = new SvtBroadcaster;
436 pListener->StartListening( *pBCAlways );
438 else
440 SCSIZE nStart, nEnd, nRowBreak;
441 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
442 SCSIZE nOff = nStart;
443 SCSIZE nBreak = nOff + nRowBreak;
444 ScBroadcastAreaSlot** pp = ppSlots + nOff;
445 ScBroadcastArea* pArea = NULL;
446 while ( nOff <= nEnd )
448 if ( !*pp )
449 *pp = new ScBroadcastAreaSlot( pDoc, this );
450 // the first call creates the ScBroadcastArea
451 (*pp)->StartListeningArea( rRange, pListener, pArea );
452 if ( nOff < nBreak )
454 ++nOff;
455 ++pp;
457 else
459 nStart += BCA_SLOTS_ROW;
460 nOff = nStart;
461 pp = ppSlots + nOff;
462 nBreak = nOff + nRowBreak;
469 void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
470 SvtListener* pListener
473 if ( rRange == BCA_LISTEN_ALWAYS )
475 DBG_ASSERT( pBCAlways, "ScBroadcastAreaSlotMachine::EndListeningArea: BCA_LISTEN_ALWAYS but none established");
476 if ( pBCAlways )
478 pListener->EndListening( *pBCAlways);
479 if (!pBCAlways->HasListeners())
481 delete pBCAlways;
482 pBCAlways = NULL;
486 else
488 SCSIZE nStart, nEnd, nRowBreak;
489 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
490 SCSIZE nOff = nStart;
491 SCSIZE nBreak = nOff + nRowBreak;
492 ScBroadcastAreaSlot** pp = ppSlots + nOff;
493 ScBroadcastArea* pArea = NULL;
494 while ( nOff <= nEnd )
496 if ( *pp )
497 (*pp)->EndListeningArea( rRange, pListener, pArea );
498 if ( nOff < nBreak )
500 ++nOff;
501 ++pp;
503 else
505 nStart += BCA_SLOTS_ROW;
506 nOff = nStart;
507 pp = ppSlots + nOff;
508 nBreak = nOff + nRowBreak;
515 BOOL ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
517 const ScAddress& rAddress = rHint.GetAddress();
518 if ( rAddress == BCA_BRDCST_ALWAYS )
520 if ( pBCAlways )
522 pBCAlways->Broadcast( rHint );
523 return TRUE;
525 else
526 return FALSE;
528 else
530 ScBroadcastAreaSlot* pSlot = ppSlots[ ComputeSlotOffset( rAddress ) ];
531 if ( pSlot )
532 return pSlot->AreaBroadcast( rHint );
533 else
534 return FALSE;
539 BOOL ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
540 const ScHint& rHint ) const
542 BOOL bBroadcasted = FALSE;
543 SCSIZE nStart, nEnd, nRowBreak;
544 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
545 SCSIZE nOff = nStart;
546 SCSIZE nBreak = nOff + nRowBreak;
547 ScBroadcastAreaSlot** pp = ppSlots + nOff;
548 while ( nOff <= nEnd )
550 if ( *pp )
551 bBroadcasted |= (*pp)->AreaBroadcastInRange( rRange, rHint );
552 if ( nOff < nBreak )
554 ++nOff;
555 ++pp;
557 else
559 nStart += BCA_SLOTS_ROW;
560 nOff = nStart;
561 pp = ppSlots + nOff;
562 nBreak = nOff + nRowBreak;
565 return bBroadcasted;
569 void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
570 const ScRange& rRange
573 SCSIZE nStart, nEnd, nRowBreak;
574 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
575 SCSIZE nOff = nStart;
576 SCSIZE nBreak = nOff + nRowBreak;
577 ScBroadcastAreaSlot** pp = ppSlots + nOff;
578 while ( nOff <= nEnd )
580 if ( *pp )
581 (*pp)->DelBroadcastAreasInRange( rRange );
582 if ( nOff < nBreak )
584 ++nOff;
585 ++pp;
587 else
589 nStart += BCA_SLOTS_ROW;
590 nOff = nStart;
591 pp = ppSlots + nOff;
592 nBreak = nOff + nRowBreak;
598 // for all affected: remove, chain, update range, insert
599 void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
600 UpdateRefMode eUpdateRefMode,
601 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
604 SCSIZE nStart, nEnd, nRowBreak;
605 // remove affected and put in chain
606 ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
607 SCSIZE nOff = nStart;
608 SCSIZE nBreak = nOff + nRowBreak;
609 ScBroadcastAreaSlot** pp = ppSlots + nOff;
610 while ( nOff <= nEnd )
612 if ( *pp )
613 (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
614 if ( nOff < nBreak )
616 ++nOff;
617 ++pp;
619 else
621 nStart += BCA_SLOTS_ROW;
622 nOff = nStart;
623 pp = ppSlots + nOff;
624 nBreak = nOff + nRowBreak;
627 // work off chain
628 SCCOL nCol1, nCol2, theCol1, theCol2;
629 SCROW nRow1, nRow2, theRow1, theRow2;
630 SCTAB nTab1, nTab2, theTab1, theTab2;
631 nCol1 = rRange.aStart.Col();
632 nRow1 = rRange.aStart.Row();
633 nTab1 = rRange.aStart.Tab();
634 nCol2 = rRange.aEnd.Col();
635 nRow2 = rRange.aEnd.Row();
636 nTab2 = rRange.aEnd.Tab();
637 while ( pUpdateChain )
639 ScAddress aAdr;
640 ScRange aRange;
641 ScBroadcastArea* pArea = pUpdateChain;
642 pUpdateChain = pArea->GetUpdateChainNext();
644 // update range
645 aAdr = pArea->GetStart();
646 theCol1 = aAdr.Col();
647 theRow1 = aAdr.Row();
648 theTab1 = aAdr.Tab();
649 aAdr = pArea->GetEnd();
650 theCol2 = aAdr.Col();
651 theRow2 = aAdr.Row();
652 theTab2 = aAdr.Tab();
653 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
654 nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
655 theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 )
658 aRange = ScRange( ScAddress( theCol1,theRow1,theTab1 ),
659 ScAddress( theCol2,theRow2,theTab2 ) );
660 pArea->UpdateRange( aRange );
661 pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) ); // for DDE
664 // insert in slot
665 ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
666 nOff = nStart;
667 nBreak = nOff + nRowBreak;
668 pp = ppSlots + nOff;
669 while ( nOff <= nEnd )
671 if ( *pp )
672 (*pp)->UpdateInsert( pArea );
673 if ( nOff < nBreak )
675 ++nOff;
676 ++pp;
678 else
680 nStart += BCA_SLOTS_ROW;
681 nOff = nStart;
682 pp = ppSlots + nOff;
683 nBreak = nOff + nRowBreak;
687 // unchain
688 pArea->SetUpdateChainNext( NULL );
689 pArea->SetInUpdateChain( FALSE );
691 pEOUpdateChain = NULL;
695 void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
697 ++nInBulkBroadcast;
701 void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
703 if (nInBulkBroadcast > 0)
705 if (--nInBulkBroadcast == 0)
706 ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
711 bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
713 return aBulkBroadcastAreas.insert( pArea ).second;
717 size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea* pArea )
719 return aBulkBroadcastAreas.erase( pArea );