1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/objsh.hxx>
21 #include <svl/listener.hxx>
23 #include "document.hxx"
25 #include "bcaslot.hxx"
26 #include "scerrors.hxx"
27 #include "docoptio.hxx"
28 #include "refupdat.hxx"
31 // Number of slots per dimension
32 // must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
33 #define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
34 #if MAXROWCOUNT_DEFINE == 32000
35 #define BCA_SLOTS_ROW 256
39 #define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / BCA_SLICE)
41 #define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
42 #define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
44 #if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
45 #error bad BCA_SLOTS_COL value!
47 #if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
48 #error bad BCA_SLOTS_ROW value!
50 // size of slot array if linear
51 #define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
52 // Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
53 // sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
54 // anyway, once you reached these values..
55 #if BCA_SLOTS_DEFINE > 268435456
56 #error BCA_SLOTS_DEFINE DOOMed!
59 // STATIC DATA -----------------------------------------------------------
61 TYPEINIT1( ScHint
, SfxSimpleHint
);
62 TYPEINIT1( ScAreaChangedHint
, SfxHint
);
66 SCROW nStartRow
; // first row of this segment
67 SCROW nStopRow
; // first row of next segment
68 SCSIZE nSlice
; // slice size in this segment
69 SCSIZE nCumulated
; // cumulated slots of previous segments
71 ScSlotData( SCROW r1
, SCROW r2
, SCSIZE s
, SCSIZE c
) : nStartRow(r1
), nStopRow(r2
), nSlice(s
), nCumulated(c
) {}
73 typedef ::std::vector
< ScSlotData
> ScSlotDistribution
;
74 #if MAXROWCOUNT_DEFINE <= 65536
75 // Linear distribution.
76 static ScSlotDistribution
aSlotDistribution( ScSlotData( 0, MAXROWCOUNT
, BCA_SLOT_ROWS
, 0));
77 static SCSIZE nBcaSlotsRow
= BCA_SLOTS_ROW
;
78 static SCSIZE nBcaSlots
= BCA_SLOTS_DEFINE
;
80 // Logarithmic or any other distribution.
81 // Upper sheet part usually is more populated and referenced and gets fine
82 // grained resolution, larger data in larger hunks.
83 // Could be further enhanced by also applying a different distribution of
85 static SCSIZE
initSlotDistribution( ScSlotDistribution
& rSD
, SCSIZE
& rBSR
)
89 SCROW nRow2
= 32*1024;
91 // Must be sorted by row1,row2!
92 while (nRow2
<= MAXROWCOUNT
)
94 rSD
.push_back( ScSlotData( nRow1
, nRow2
, nSlice
, nSlots
));
95 nSlots
+= (nRow2
- nRow1
) / nSlice
;
103 static ScSlotDistribution aSlotDistribution
;
104 static SCSIZE nBcaSlotsRow
;
105 static SCSIZE nBcaSlots
= initSlotDistribution( aSlotDistribution
, nBcaSlotsRow
) * BCA_SLOTS_COL
;
106 // Ensure that all static variables are initialized with this one call.
110 ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument
* pDocument
,
111 ScBroadcastAreaSlotMachine
* pBASMa
) :
112 aTmpSeekBroadcastArea( ScRange()),
115 mbInBroadcastIteration( false)
120 ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
122 for ( ScBroadcastAreas::iterator
aIter( aBroadcastAreaTbl
.begin());
123 aIter
!= aBroadcastAreaTbl
.end(); /* none */)
125 // Prevent hash from accessing dangling pointer in case area is
127 ScBroadcastArea
* pArea
= (*aIter
).mpArea
;
128 // Erase all so no hash will be accessed upon destruction of the
129 // boost::unordered_map.
130 aBroadcastAreaTbl
.erase( aIter
++);
131 if (!pArea
->DecRef())
137 bool ScBroadcastAreaSlot::CheckHardRecalcStateCondition() const
139 if ( pDoc
->GetHardRecalcState() )
141 if (aBroadcastAreaTbl
.size() >= aBroadcastAreaTbl
.max_size())
142 { // this is more hypothetical now, check existed for old SV_PTRARR_SORT
143 if ( !pDoc
->GetHardRecalcState() )
145 SfxObjectShell
* pShell
= pDoc
->GetDocumentShell();
146 OSL_ENSURE( pShell
, "Missing DocShell :-/" );
149 pShell
->SetError( SCWARN_CORE_HARD_RECALC
, OUString( OSL_LOG_PREFIX
) );
151 pDoc
->SetAutoCalc( false );
152 pDoc
->SetHardRecalcState( true );
160 bool ScBroadcastAreaSlot::StartListeningArea( const ScRange
& rRange
,
161 SvtListener
* pListener
, ScBroadcastArea
*& rpArea
)
163 bool bNewArea
= false;
164 OSL_ENSURE(pListener
, "StartListeningArea: pListener Null");
165 if (CheckHardRecalcStateCondition())
169 // Even if most times the area doesn't exist yet and immediately trying
170 // to new and insert it would save an attempt to find it, on mass
171 // operations like identical large [HV]LOOKUP() areas the new/delete
172 // would add quite some penalty for all but the first formula cell.
173 ScBroadcastAreas::const_iterator
aIter( FindBroadcastArea( rRange
));
174 if (aIter
!= aBroadcastAreaTbl
.end())
175 rpArea
= (*aIter
).mpArea
;
178 rpArea
= new ScBroadcastArea( rRange
);
179 if (aBroadcastAreaTbl
.insert( rpArea
).second
)
186 OSL_FAIL("StartListeningArea: area not found and not inserted in slot?!?");
192 pListener
->StartListening( rpArea
->GetBroadcaster());
196 if (aBroadcastAreaTbl
.insert( rpArea
).second
)
203 void ScBroadcastAreaSlot::InsertListeningArea( ScBroadcastArea
* pArea
)
205 OSL_ENSURE( pArea
, "InsertListeningArea: pArea NULL");
206 if (CheckHardRecalcStateCondition())
208 if (aBroadcastAreaTbl
.insert( pArea
).second
)
213 // If rpArea != NULL then no listeners are stopped, only the area is removed
214 // and the reference count decremented.
215 void ScBroadcastAreaSlot::EndListeningArea( const ScRange
& rRange
,
216 SvtListener
* pListener
, ScBroadcastArea
*& rpArea
)
218 OSL_ENSURE(pListener
, "EndListeningArea: pListener Null");
221 ScBroadcastAreas::const_iterator
aIter( FindBroadcastArea( rRange
));
222 if (aIter
== aBroadcastAreaTbl
.end() || isMarkedErased( aIter
))
224 rpArea
= (*aIter
).mpArea
;
225 pListener
->EndListening( rpArea
->GetBroadcaster() );
226 if ( !rpArea
->GetBroadcaster().HasListeners() )
227 { // if nobody is listening we can dispose it
228 if (rpArea
->GetRef() == 1)
229 rpArea
= NULL
; // will be deleted by erase
235 if ( !rpArea
->GetBroadcaster().HasListeners() )
237 ScBroadcastAreas::const_iterator
aIter( FindBroadcastArea( rRange
));
238 if (aIter
== aBroadcastAreaTbl
.end() || isMarkedErased( aIter
))
240 OSL_ENSURE( (*aIter
).mpArea
== rpArea
, "EndListeningArea: area pointer mismatch");
241 if (rpArea
->GetRef() == 1)
242 rpArea
= NULL
; // will be deleted by erase
249 ScBroadcastAreas::const_iterator
ScBroadcastAreaSlot::FindBroadcastArea(
250 const ScRange
& rRange
) const
252 aTmpSeekBroadcastArea
.UpdateRange( rRange
);
253 return aBroadcastAreaTbl
.find( &aTmpSeekBroadcastArea
);
257 bool ScBroadcastAreaSlot::AreaBroadcast( const ScHint
& rHint
)
259 if (aBroadcastAreaTbl
.empty())
261 bool bInBroadcast
= mbInBroadcastIteration
;
262 mbInBroadcastIteration
= true;
263 bool bIsBroadcasted
= false;
264 const ScAddress
& rAddress
= rHint
.GetAddress();
265 for (ScBroadcastAreas::const_iterator
aIter( aBroadcastAreaTbl
.begin()),
266 aIterEnd( aBroadcastAreaTbl
.end()); aIter
!= aIterEnd
; ++aIter
)
268 if (isMarkedErased( aIter
))
270 ScBroadcastArea
* pArea
= (*aIter
).mpArea
;
271 const ScRange
& rAreaRange
= pArea
->GetRange();
272 if (rAreaRange
.In( rAddress
))
274 if (!pBASM
->IsInBulkBroadcast() || pBASM
->InsertBulkArea( pArea
))
276 pArea
->GetBroadcaster().Broadcast( rHint
);
277 bIsBroadcasted
= true;
281 mbInBroadcastIteration
= bInBroadcast
;
282 // A Notify() during broadcast may call EndListeningArea() and thus dispose
283 // an area if it was the last listener, which would invalidate an iterator
284 // pointing to it, hence the real erase is done afterwards.
286 return bIsBroadcasted
;
290 bool ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange
& rRange
,
293 if (aBroadcastAreaTbl
.empty())
295 bool bInBroadcast
= mbInBroadcastIteration
;
296 mbInBroadcastIteration
= true;
297 bool bIsBroadcasted
= false;
298 for (ScBroadcastAreas::const_iterator
aIter( aBroadcastAreaTbl
.begin()),
299 aIterEnd( aBroadcastAreaTbl
.end()); aIter
!= aIterEnd
; ++aIter
)
301 if (isMarkedErased( aIter
))
303 ScBroadcastArea
* pArea
= (*aIter
).mpArea
;
304 const ScRange
& rAreaRange
= pArea
->GetRange();
305 if (rAreaRange
.Intersects( rRange
))
307 if (!pBASM
->IsInBulkBroadcast() || pBASM
->InsertBulkArea( pArea
))
309 pArea
->GetBroadcaster().Broadcast( rHint
);
310 bIsBroadcasted
= true;
314 mbInBroadcastIteration
= bInBroadcast
;
315 // A Notify() during broadcast may call EndListeningArea() and thus dispose
316 // an area if it was the last listener, which would invalidate an iterator
317 // pointing to it, hence the real erase is done afterwards.
319 return bIsBroadcasted
;
323 void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange
& rRange
)
325 if (aBroadcastAreaTbl
.empty())
327 for (ScBroadcastAreas::iterator
aIter( aBroadcastAreaTbl
.begin());
328 aIter
!= aBroadcastAreaTbl
.end(); /* increment in body */ )
330 const ScRange
& rAreaRange
= (*aIter
).mpArea
->GetRange();
331 if (rRange
.In( rAreaRange
))
333 ScBroadcastArea
* pArea
= (*aIter
).mpArea
;
334 aBroadcastAreaTbl
.erase( aIter
++); // erase before modifying
335 if (!pArea
->DecRef())
337 if (pBASM
->IsInBulkBroadcast())
338 pBASM
->RemoveBulkArea( pArea
);
348 void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode
,
349 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
351 if (aBroadcastAreaTbl
.empty())
354 SCCOL nCol1
, nCol2
, theCol1
, theCol2
;
355 SCROW nRow1
, nRow2
, theRow1
, theRow2
;
356 SCTAB nTab1
, nTab2
, theTab1
, theTab2
;
357 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
358 for ( ScBroadcastAreas::iterator
aIter( aBroadcastAreaTbl
.begin());
359 aIter
!= aBroadcastAreaTbl
.end(); /* increment in body */ )
361 ScBroadcastArea
* pArea
= (*aIter
).mpArea
;
362 if ( pArea
->IsInUpdateChain() )
364 aBroadcastAreaTbl
.erase( aIter
++);
369 pArea
->GetRange().GetVars( theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
);
370 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
371 nCol1
,nRow1
,nTab1
, nCol2
,nRow2
,nTab2
, nDx
,nDy
,nDz
,
372 theCol1
,theRow1
,theTab1
, theCol2
,theRow2
,theTab2
))
374 aBroadcastAreaTbl
.erase( aIter
++);
376 if (pBASM
->IsInBulkBroadcast())
377 pBASM
->RemoveBulkArea( pArea
);
378 pArea
->SetInUpdateChain( true );
379 ScBroadcastArea
* pUC
= pBASM
->GetEOUpdateChain();
381 pUC
->SetUpdateChainNext( pArea
);
382 else // no tail => no head
383 pBASM
->SetUpdateChain( pArea
);
384 pBASM
->SetEOUpdateChain( pArea
);
393 void ScBroadcastAreaSlot::UpdateRemoveArea( ScBroadcastArea
* pArea
)
395 ScBroadcastAreas::iterator
aIter( aBroadcastAreaTbl
.find( pArea
));
396 if (aIter
== aBroadcastAreaTbl
.end())
398 if ((*aIter
).mpArea
!= pArea
)
399 OSL_FAIL( "UpdateRemoveArea: area pointer mismatch");
402 aBroadcastAreaTbl
.erase( aIter
);
408 void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea
* pArea
)
410 ::std::pair
< ScBroadcastAreas::iterator
, bool > aPair
=
411 aBroadcastAreaTbl
.insert( pArea
);
416 // Identical area already exists, add listeners.
417 ScBroadcastArea
* pTarget
= (*(aPair
.first
)).mpArea
;
418 if (pArea
!= pTarget
)
420 SvtBroadcaster
& rTarget
= pTarget
->GetBroadcaster();
421 SvtBroadcaster::ListenersType
& rListeners
= pArea
->GetBroadcaster().GetAllListeners();
422 SvtBroadcaster::ListenersType::iterator it
= rListeners
.begin(), itEnd
= rListeners
.end();
423 for (; it
!= itEnd
; ++it
)
425 SvtListener
& rListener
= **it
;
426 rListener
.StartListening(rTarget
);
433 void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator
& rIter
)
435 if (mbInBroadcastIteration
)
437 (*rIter
).mbErasure
= true; // mark for erasure
438 pBASM
->PushAreaToBeErased( this, rIter
);
442 ScBroadcastArea
* pArea
= (*rIter
).mpArea
;
443 aBroadcastAreaTbl
.erase( rIter
);
444 if (!pArea
->DecRef())
450 void ScBroadcastAreaSlot::FinallyEraseAreas()
452 pBASM
->FinallyEraseAreas( this);
456 // --- ScBroadcastAreaSlotMachine -------------------------------------
458 ScBroadcastAreaSlotMachine::TableSlots::TableSlots()
460 ppSlots
= new ScBroadcastAreaSlot
* [ nBcaSlots
];
461 memset( ppSlots
, 0 , sizeof( ScBroadcastAreaSlot
* ) * nBcaSlots
);
465 ScBroadcastAreaSlotMachine::TableSlots::~TableSlots()
467 for ( ScBroadcastAreaSlot
** pp
= ppSlots
+ nBcaSlots
; --pp
>= ppSlots
; /* nothing */ )
476 ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
477 ScDocument
* pDocument
) :
480 pUpdateChain( NULL
),
481 pEOUpdateChain( NULL
),
482 nInBulkBroadcast( 0 )
487 ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
489 for (TableSlotsMap::iterator
iTab( aTableSlotsMap
.begin());
490 iTab
!= aTableSlotsMap
.end(); ++iTab
)
492 delete (*iTab
).second
;
495 // Areas to-be-erased still present is a serious error in handling, but at
496 // this stage there's nothing we can do anymore.
497 SAL_WARN_IF( !maAreasToBeErased
.empty(), "sc", "ScBroadcastAreaSlotMachine::dtor: maAreasToBeErased not empty");
501 inline SCSIZE
ScBroadcastAreaSlotMachine::ComputeSlotOffset(
502 const ScAddress
& rAddress
) const
504 SCROW nRow
= rAddress
.Row();
505 SCCOL nCol
= rAddress
.Col();
506 if ( !ValidRow(nRow
) || !ValidCol(nCol
) )
508 OSL_FAIL( "Row/Col invalid, using first slot!" );
511 for (size_t i
=0; i
< aSlotDistribution
.size(); ++i
)
513 if (nRow
< aSlotDistribution
[i
].nStopRow
)
515 const ScSlotData
& rSD
= aSlotDistribution
[i
];
516 return rSD
.nCumulated
+
517 (static_cast<SCSIZE
>(nRow
- rSD
.nStartRow
)) / rSD
.nSlice
+
518 static_cast<SCSIZE
>(nCol
) / BCA_SLOT_COLS
* nBcaSlotsRow
;
521 OSL_FAIL( "No slot found, using last!" );
522 return nBcaSlots
- 1;
526 void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange
& rRange
,
527 SCSIZE
& rStart
, SCSIZE
& rEnd
, SCSIZE
& rRowBreak
) const
529 rStart
= ComputeSlotOffset( rRange
.aStart
);
530 rEnd
= ComputeSlotOffset( rRange
.aEnd
);
531 // count of row slots per column minus one
532 rRowBreak
= ComputeSlotOffset(
533 ScAddress( rRange
.aStart
.Col(), rRange
.aEnd
.Row(), 0 ) ) - rStart
;
537 inline void ComputeNextSlot( SCSIZE
& nOff
, SCSIZE
& nBreak
, ScBroadcastAreaSlot
** & pp
,
538 SCSIZE
& nStart
, ScBroadcastAreaSlot
** const & ppSlots
, SCSIZE
const & nRowBreak
)
547 nStart
+= nBcaSlotsRow
;
550 nBreak
= nOff
+ nRowBreak
;
555 void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange
& rRange
,
556 SvtListener
* pListener
)
558 if ( rRange
== BCA_LISTEN_ALWAYS
)
561 pBCAlways
= new SvtBroadcaster
;
562 pListener
->StartListening( *pBCAlways
);
567 for (SCTAB nTab
= rRange
.aStart
.Tab();
568 !bDone
&& nTab
<= rRange
.aEnd
.Tab(); ++nTab
)
570 TableSlotsMap::iterator
iTab( aTableSlotsMap
.find( nTab
));
571 if (iTab
== aTableSlotsMap
.end())
572 iTab
= aTableSlotsMap
.insert( TableSlotsMap::value_type(
573 nTab
, new TableSlots
)).first
;
574 ScBroadcastAreaSlot
** ppSlots
= (*iTab
).second
->getSlots();
575 SCSIZE nStart
, nEnd
, nRowBreak
;
576 ComputeAreaPoints( rRange
, nStart
, nEnd
, nRowBreak
);
577 SCSIZE nOff
= nStart
;
578 SCSIZE nBreak
= nOff
+ nRowBreak
;
579 ScBroadcastAreaSlot
** pp
= ppSlots
+ nOff
;
580 ScBroadcastArea
* pArea
= NULL
;
581 while ( !bDone
&& nOff
<= nEnd
)
584 *pp
= new ScBroadcastAreaSlot( pDoc
, this );
587 // If the call to StartListeningArea didn't create the
588 // ScBroadcastArea, listeners were added to an already
589 // existing identical area that doesn't need to be inserted
591 if (!(*pp
)->StartListeningArea( rRange
, pListener
, pArea
))
595 (*pp
)->InsertListeningArea( pArea
);
596 ComputeNextSlot( nOff
, nBreak
, pp
, nStart
, ppSlots
, nRowBreak
);
603 void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange
& rRange
,
604 SvtListener
* pListener
)
606 if ( rRange
== BCA_LISTEN_ALWAYS
)
610 pListener
->EndListening( *pBCAlways
);
611 if (!pBCAlways
->HasListeners())
620 SCTAB nEndTab
= rRange
.aEnd
.Tab();
621 for (TableSlotsMap::iterator
iTab( aTableSlotsMap
.lower_bound( rRange
.aStart
.Tab()));
622 iTab
!= aTableSlotsMap
.end() && (*iTab
).first
<= nEndTab
; ++iTab
)
624 ScBroadcastAreaSlot
** ppSlots
= (*iTab
).second
->getSlots();
625 SCSIZE nStart
, nEnd
, nRowBreak
;
626 ComputeAreaPoints( rRange
, nStart
, nEnd
, nRowBreak
);
627 SCSIZE nOff
= nStart
;
628 SCSIZE nBreak
= nOff
+ nRowBreak
;
629 ScBroadcastAreaSlot
** pp
= ppSlots
+ nOff
;
630 ScBroadcastArea
* pArea
= NULL
;
631 if (nOff
== 0 && nEnd
== nBcaSlots
-1)
633 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
634 // happen for insertion and deletion of sheets.
635 ScBroadcastAreaSlot
** const pStop
= ppSlots
+ nEnd
;
639 (*pp
)->EndListeningArea( rRange
, pListener
, pArea
);
640 } while (++pp
< pStop
);
644 while ( nOff
<= nEnd
)
647 (*pp
)->EndListeningArea( rRange
, pListener
, pArea
);
648 ComputeNextSlot( nOff
, nBreak
, pp
, nStart
, ppSlots
, nRowBreak
);
656 bool ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint
& rHint
) const
658 const ScAddress
& rAddress
= rHint
.GetAddress();
659 if ( rAddress
== BCA_BRDCST_ALWAYS
)
663 pBCAlways
->Broadcast( rHint
);
671 TableSlotsMap::const_iterator
iTab( aTableSlotsMap
.find( rAddress
.Tab()));
672 if (iTab
== aTableSlotsMap
.end())
674 ScBroadcastAreaSlot
* pSlot
= (*iTab
).second
->getAreaSlot(
675 ComputeSlotOffset( rAddress
));
677 return pSlot
->AreaBroadcast( rHint
);
684 bool ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange
& rRange
,
685 const ScHint
& rHint
) const
687 bool bBroadcasted
= false;
688 SCTAB nEndTab
= rRange
.aEnd
.Tab();
689 for (TableSlotsMap::const_iterator
iTab( aTableSlotsMap
.lower_bound( rRange
.aStart
.Tab()));
690 iTab
!= aTableSlotsMap
.end() && (*iTab
).first
<= nEndTab
; ++iTab
)
692 ScBroadcastAreaSlot
** ppSlots
= (*iTab
).second
->getSlots();
693 SCSIZE nStart
, nEnd
, nRowBreak
;
694 ComputeAreaPoints( rRange
, nStart
, nEnd
, nRowBreak
);
695 SCSIZE nOff
= nStart
;
696 SCSIZE nBreak
= nOff
+ nRowBreak
;
697 ScBroadcastAreaSlot
** pp
= ppSlots
+ nOff
;
698 while ( nOff
<= nEnd
)
701 bBroadcasted
|= (*pp
)->AreaBroadcastInRange( rRange
, rHint
);
702 ComputeNextSlot( nOff
, nBreak
, pp
, nStart
, ppSlots
, nRowBreak
);
709 void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
710 const ScRange
& rRange
)
712 SCTAB nEndTab
= rRange
.aEnd
.Tab();
713 for (TableSlotsMap::iterator
iTab( aTableSlotsMap
.lower_bound( rRange
.aStart
.Tab()));
714 iTab
!= aTableSlotsMap
.end() && (*iTab
).first
<= nEndTab
; ++iTab
)
716 ScBroadcastAreaSlot
** ppSlots
= (*iTab
).second
->getSlots();
717 SCSIZE nStart
, nEnd
, nRowBreak
;
718 ComputeAreaPoints( rRange
, nStart
, nEnd
, nRowBreak
);
719 SCSIZE nOff
= nStart
;
720 SCSIZE nBreak
= nOff
+ nRowBreak
;
721 ScBroadcastAreaSlot
** pp
= ppSlots
+ nOff
;
722 if (nOff
== 0 && nEnd
== nBcaSlots
-1)
724 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
725 // happen for insertion and deletion of sheets.
726 ScBroadcastAreaSlot
** const pStop
= ppSlots
+ nEnd
;
730 (*pp
)->DelBroadcastAreasInRange( rRange
);
731 } while (++pp
< pStop
);
735 while ( nOff
<= nEnd
)
738 (*pp
)->DelBroadcastAreasInRange( rRange
);
739 ComputeNextSlot( nOff
, nBreak
, pp
, nStart
, ppSlots
, nRowBreak
);
746 // for all affected: remove, chain, update range, insert, and maybe delete
747 void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
748 UpdateRefMode eUpdateRefMode
,
749 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
751 // remove affected and put in chain
752 SCTAB nEndTab
= rRange
.aEnd
.Tab();
753 for (TableSlotsMap::iterator
iTab( aTableSlotsMap
.lower_bound( rRange
.aStart
.Tab()));
754 iTab
!= aTableSlotsMap
.end() && (*iTab
).first
<= nEndTab
; ++iTab
)
756 ScBroadcastAreaSlot
** ppSlots
= (*iTab
).second
->getSlots();
757 SCSIZE nStart
, nEnd
, nRowBreak
;
758 ComputeAreaPoints( rRange
, nStart
, nEnd
, nRowBreak
);
759 SCSIZE nOff
= nStart
;
760 SCSIZE nBreak
= nOff
+ nRowBreak
;
761 ScBroadcastAreaSlot
** pp
= ppSlots
+ nOff
;
762 if (nOff
== 0 && nEnd
== nBcaSlots
-1)
764 // Slightly optimized for 0,0,MAXCOL,MAXROW calls as they
765 // happen for insertion and deletion of sheets.
766 ScBroadcastAreaSlot
** const pStop
= ppSlots
+ nEnd
;
770 (*pp
)->UpdateRemove( eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
);
771 } while (++pp
< pStop
);
775 while ( nOff
<= nEnd
)
778 (*pp
)->UpdateRemove( eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
);
779 ComputeNextSlot( nOff
, nBreak
, pp
, nStart
, ppSlots
, nRowBreak
);
784 // Updating an area's range will modify the hash key, remove areas from all
785 // affected slots. Will be reinserted later with the updated range.
786 ScBroadcastArea
* pChain
= pUpdateChain
;
789 ScBroadcastArea
* pArea
= pChain
;
790 pChain
= pArea
->GetUpdateChainNext();
791 ScRange
aRange( pArea
->GetRange());
793 for (SCTAB nTab
= aRange
.aStart
.Tab(); nTab
<= aRange
.aEnd
.Tab() && pArea
->GetRef(); ++nTab
)
795 TableSlotsMap::iterator
iTab( aTableSlotsMap
.find( nTab
));
796 if (iTab
== aTableSlotsMap
.end())
798 OSL_FAIL( "UpdateBroadcastAreas: Where's the TableSlot?!?");
801 ScBroadcastAreaSlot
** ppSlots
= (*iTab
).second
->getSlots();
802 SCSIZE nStart
, nEnd
, nRowBreak
;
803 ComputeAreaPoints( aRange
, nStart
, nEnd
, nRowBreak
);
804 SCSIZE nOff
= nStart
;
805 SCSIZE nBreak
= nOff
+ nRowBreak
;
806 ScBroadcastAreaSlot
** pp
= ppSlots
+ nOff
;
807 while ( nOff
<= nEnd
&& pArea
->GetRef() )
810 (*pp
)->UpdateRemoveArea( pArea
);
811 ComputeNextSlot( nOff
, nBreak
, pp
, nStart
, ppSlots
, nRowBreak
);
822 TableSlotsMap::iterator
iDel( aTableSlotsMap
.lower_bound( rRange
.aStart
.Tab()));
823 TableSlotsMap::iterator
iTab( aTableSlotsMap
.lower_bound( rRange
.aStart
.Tab() - nDz
));
824 // Remove sheets, if any, iDel or/and iTab may as well point to end().
827 delete (*iDel
).second
;
828 aTableSlotsMap
.erase( iDel
++);
830 // shift remaining down
831 while (iTab
!= aTableSlotsMap
.end())
833 SCTAB nTab
= (*iTab
).first
+ nDz
;
834 aTableSlotsMap
[nTab
] = (*iTab
).second
;
835 aTableSlotsMap
.erase( iTab
++);
840 TableSlotsMap::iterator
iStop( aTableSlotsMap
.lower_bound( rRange
.aStart
.Tab()));
841 if (iStop
!= aTableSlotsMap
.end())
843 bool bStopIsBegin
= (iStop
== aTableSlotsMap
.begin());
846 TableSlotsMap::iterator
iTab( aTableSlotsMap
.end());
848 while (iTab
!= iStop
)
850 SCTAB nTab
= (*iTab
).first
+ nDz
;
851 aTableSlotsMap
[nTab
] = (*iTab
).second
;
852 aTableSlotsMap
.erase( iTab
--);
854 // Shift the very first, iTab==iStop in this case.
857 SCTAB nTab
= (*iTab
).first
+ nDz
;
858 aTableSlotsMap
[nTab
] = (*iTab
).second
;
859 aTableSlotsMap
.erase( iStop
);
866 SCCOL nCol1
, nCol2
, theCol1
, theCol2
;
867 SCROW nRow1
, nRow2
, theRow1
, theRow2
;
868 SCTAB nTab1
, nTab2
, theTab1
, theTab2
;
869 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
870 while ( pUpdateChain
)
872 ScBroadcastArea
* pArea
= pUpdateChain
;
873 ScRange
aRange( pArea
->GetRange());
874 pUpdateChain
= pArea
->GetUpdateChainNext();
877 aRange
.GetVars( theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
);
878 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
879 nCol1
,nRow1
,nTab1
, nCol2
,nRow2
,nTab2
, nDx
,nDy
,nDz
,
880 theCol1
,theRow1
,theTab1
, theCol2
,theRow2
,theTab2
))
882 aRange
= ScRange( theCol1
,theRow1
,theTab1
, theCol2
,theRow2
,theTab2
);
883 pArea
->UpdateRange( aRange
);
884 pArea
->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange
) ); // for DDE
888 for (SCTAB nTab
= aRange
.aStart
.Tab(); nTab
<= aRange
.aEnd
.Tab(); ++nTab
)
890 TableSlotsMap::iterator
iTab( aTableSlotsMap
.find( nTab
));
891 if (iTab
== aTableSlotsMap
.end())
892 iTab
= aTableSlotsMap
.insert( TableSlotsMap::value_type(
893 nTab
, new TableSlots
)).first
;
894 ScBroadcastAreaSlot
** ppSlots
= (*iTab
).second
->getSlots();
895 SCSIZE nStart
, nEnd
, nRowBreak
;
896 ComputeAreaPoints( aRange
, nStart
, nEnd
, nRowBreak
);
897 SCSIZE nOff
= nStart
;
898 SCSIZE nBreak
= nOff
+ nRowBreak
;
899 ScBroadcastAreaSlot
** pp
= ppSlots
+ nOff
;
900 while ( nOff
<= nEnd
)
903 *pp
= new ScBroadcastAreaSlot( pDoc
, this );
904 (*pp
)->UpdateInsert( pArea
);
905 ComputeNextSlot( nOff
, nBreak
, pp
, nStart
, ppSlots
, nRowBreak
);
910 pArea
->SetUpdateChainNext( NULL
);
911 pArea
->SetInUpdateChain( false );
913 // Delete if not inserted to any slot. RemoveBulkArea(pArea) was
914 // already executed in UpdateRemove().
915 if (!pArea
->GetRef())
918 pEOUpdateChain
= NULL
;
922 void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
928 void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
930 if (nInBulkBroadcast
> 0)
932 if (--nInBulkBroadcast
== 0)
933 ScBroadcastAreasBulk().swap( aBulkBroadcastAreas
);
938 bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea
* pArea
)
940 return aBulkBroadcastAreas
.insert( pArea
).second
;
944 size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea
* pArea
)
946 return aBulkBroadcastAreas
.erase( pArea
);
950 void ScBroadcastAreaSlotMachine::PushAreaToBeErased( ScBroadcastAreaSlot
* pSlot
,
951 ScBroadcastAreas::iterator
& rIter
)
953 maAreasToBeErased
.push_back( ::std::make_pair( pSlot
, rIter
));
957 void ScBroadcastAreaSlotMachine::FinallyEraseAreas( ScBroadcastAreaSlot
* pSlot
)
959 SAL_WARN_IF( pSlot
->IsInBroadcastIteration(), "sc",
960 "ScBroadcastAreaSlotMachine::FinallyEraseAreas: during iteration? NO!");
961 if (pSlot
->IsInBroadcastIteration())
964 // maAreasToBeErased is a simple vector so erasing an element may
965 // invalidate iterators and would be inefficient anyway. Instead, copy
966 // elements to be preserved (usually none!) to temporary vector and swap.
967 AreasToBeErased aCopy
;
968 for (AreasToBeErased::iterator
aIt( maAreasToBeErased
.begin());
969 aIt
!= maAreasToBeErased
.end(); ++aIt
)
971 if ((*aIt
).first
== pSlot
)
972 pSlot
->EraseArea( (*aIt
).second
);
974 aCopy
.push_back( *aIt
);
976 maAreasToBeErased
.swap( aCopy
);
979 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */