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 <vcl/svapp.hxx>
21 :
22 : #include "document.hxx"
23 : #include "brdcst.hxx"
24 : #include "bcaslot.hxx"
25 : #include "formulacell.hxx"
26 : #include <formula/errorcodes.hxx>
27 : #include "scerrors.hxx"
28 : #include "docoptio.hxx"
29 : #include "refupdat.hxx"
30 : #include "table.hxx"
31 : #include "progress.hxx"
32 : #include "scmod.hxx"
33 : #include "inputopt.hxx"
34 : #include "conditio.hxx"
35 : #include "colorscale.hxx"
36 : #include "sheetevents.hxx"
37 : #include "tokenarray.hxx"
38 : #include "listenercontext.hxx"
39 : #include "formulagroup.hxx"
40 : #include <refhint.hxx>
41 :
42 : #include "globstr.hrc"
43 :
44 : extern const ScFormulaCell* pLastFormulaTreeTop; // cellform.cxx Err527 WorkAround
45 :
46 : // STATIC DATA -----------------------------------------------------------
47 :
48 6835 : void ScDocument::StartListeningArea(
49 : const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
50 : {
51 6835 : if ( pBASM )
52 6835 : pBASM->StartListeningArea(rRange, bGroupListening, pListener);
53 6835 : }
54 :
55 12289 : void ScDocument::EndListeningArea( const ScRange& rRange, bool bGroupListening, SvtListener* pListener )
56 : {
57 12289 : if ( pBASM )
58 12289 : pBASM->EndListeningArea(rRange, bGroupListening, pListener);
59 12289 : }
60 :
61 49354 : void ScDocument::Broadcast( const ScHint& rHint )
62 : {
63 49354 : if ( !pBASM )
64 50073 : return ; // Clipboard or Undo
65 48635 : if ( !bHardRecalcState )
66 : {
67 48471 : ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
68 48471 : bool bIsBroadcasted = false;
69 48471 : SvtBroadcaster* pBC = GetBroadcaster(rHint.GetAddress());
70 48471 : if ( pBC )
71 : {
72 324 : pBC->Broadcast( rHint );
73 324 : bIsBroadcasted = true;
74 : }
75 48471 : if ( pBASM->AreaBroadcast( rHint ) || bIsBroadcasted )
76 466 : TrackFormulas( rHint.GetId() );
77 : }
78 :
79 : // Repaint for conditional formats with relative references:
80 134069 : for(SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabs.size()); ++nTab)
81 : {
82 85434 : if(!maTabs[nTab])
83 0 : continue;
84 :
85 85434 : ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
86 85434 : if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
87 49183 : pCondFormList->SourceChanged( rHint.GetAddress() );
88 :
89 : }
90 :
91 48635 : if ( rHint.GetAddress() != BCA_BRDCST_ALWAYS )
92 : {
93 32742 : SCTAB nTab = rHint.GetAddress().Tab();
94 32742 : if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsStreamValid())
95 13 : maTabs[nTab]->SetStreamValid(false);
96 : }
97 : }
98 :
99 197 : void ScDocument::BroadcastCells( const ScRange& rRange, sal_uLong nHint, bool bBroadcastSingleBroadcasters )
100 : {
101 197 : ClearFormulaContext();
102 :
103 197 : if (!pBASM)
104 197 : return; // Clipboard or Undo
105 :
106 197 : SCTAB nTab1 = rRange.aStart.Tab();
107 197 : SCTAB nTab2 = rRange.aEnd.Tab();
108 197 : SCROW nRow1 = rRange.aStart.Row();
109 197 : SCROW nRow2 = rRange.aEnd.Row();
110 197 : SCCOL nCol1 = rRange.aStart.Col();
111 197 : SCCOL nCol2 = rRange.aEnd.Col();
112 :
113 197 : if (!bHardRecalcState)
114 : {
115 197 : ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
116 197 : bool bIsBroadcasted = false;
117 :
118 197 : if (bBroadcastSingleBroadcasters)
119 : {
120 144 : ScHint aHint(nHint, ScAddress());
121 :
122 288 : for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
123 : {
124 144 : ScTable* pTab = FetchTable(nTab);
125 144 : if (!pTab)
126 0 : continue;
127 :
128 144 : bIsBroadcasted |= pTab->BroadcastBroadcasters( nCol1, nRow1, nCol2, nRow2, aHint);
129 144 : }
130 : }
131 :
132 197 : if (pBASM->AreaBroadcast(rRange, nHint) || bIsBroadcasted)
133 41 : TrackFormulas(nHint);
134 : }
135 :
136 : // Repaint for conditional formats with relative references:
137 394 : for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
138 : {
139 197 : ScTable* pTab = FetchTable(nTab);
140 197 : if (!pTab)
141 0 : continue;
142 :
143 197 : ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
144 197 : if (pCondFormList)
145 : {
146 197 : ScAddress aAddress( 0, 0, nTab);
147 773 : for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
148 : {
149 576 : aAddress.SetRow(nRow);
150 1665 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
151 : {
152 1089 : aAddress.SetCol(nCol);
153 1089 : pCondFormList->SourceChanged(aAddress);
154 : }
155 : }
156 : }
157 : }
158 :
159 394 : for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
160 : {
161 197 : ScTable* pTab = FetchTable(nTab);
162 197 : if (pTab)
163 197 : pTab->SetStreamValid(false);
164 : }
165 :
166 197 : BroadcastUno(SfxSimpleHint(SC_HINT_DATACHANGED));
167 : }
168 :
169 : namespace {
170 :
171 : class RefMovedNotifier : std::unary_function<SvtListener*, void>
172 : {
173 : const sc::RefMovedHint& mrHint;
174 : public:
175 6 : RefMovedNotifier( const sc::RefMovedHint& rHint ) : mrHint(rHint) {}
176 :
177 10 : void operator() ( SvtListener* p )
178 : {
179 10 : p->Notify(mrHint);
180 10 : }
181 : };
182 :
183 : }
184 :
185 6 : void ScDocument::BroadcastRefMoved( const sc::RefMovedHint& rHint )
186 : {
187 6 : if (!pBASM)
188 : // clipboard or undo document.
189 6 : return;
190 :
191 6 : const ScRange& rSrcRange = rHint.getRange(); // old range
192 6 : const ScAddress& rDelta = rHint.getDelta();
193 :
194 : // Get all area listeners that listens on the old range, and end their listening.
195 6 : std::vector<sc::AreaListener> aAreaListeners = pBASM->GetAllListeners(rSrcRange, sc::AreaInside);
196 : {
197 6 : std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
198 10 : for (; it != itEnd; ++it)
199 : {
200 4 : pBASM->EndListeningArea(it->maArea, it->mbGroupListening, it->mpListener);
201 4 : it->mpListener->Notify(rHint); // Adjust the references.
202 : }
203 : }
204 :
205 : // Collect all listeners listening into the range.
206 12 : std::vector<SvtListener*> aListeners;
207 12 : for (SCTAB nTab = rSrcRange.aStart.Tab(); nTab <= rSrcRange.aEnd.Tab(); ++nTab)
208 : {
209 6 : ScTable* pTab = FetchTable(nTab);
210 6 : if (!pTab)
211 0 : continue;
212 :
213 : pTab->CollectListeners(
214 : aListeners,
215 6 : rSrcRange.aStart.Col(), rSrcRange.aStart.Row(),
216 12 : rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row());
217 : }
218 :
219 : // Remove any duplicate listener entries. We must ensure that we notify
220 : // each unique listener only once.
221 6 : std::sort(aListeners.begin(), aListeners.end());
222 6 : aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
223 :
224 : // Notify the listeners.
225 6 : std::for_each(aListeners.begin(), aListeners.end(), RefMovedNotifier(rHint));
226 :
227 12 : for (SCTAB nTab = rSrcRange.aStart.Tab(); nTab <= rSrcRange.aEnd.Tab(); ++nTab)
228 : {
229 6 : ScTable* pTab = FetchTable(nTab);
230 6 : if (!pTab)
231 0 : continue;
232 :
233 6 : SCTAB nDestTab = nTab + rDelta.Tab();
234 6 : ScTable* pDestTab = FetchTable(nDestTab);
235 6 : if (!pDestTab)
236 0 : continue;
237 :
238 : // Move the listeners from the old location to the new.
239 : pTab->TransferListeners(
240 6 : *pDestTab, rSrcRange.aStart.Col(), rSrcRange.aStart.Row(),
241 12 : rSrcRange.aEnd.Col(), rSrcRange.aEnd.Row(), rDelta.Col(), rDelta.Row());
242 : }
243 :
244 : // Re-start area listeners on the new range.
245 : {
246 6 : std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
247 10 : for (; it != itEnd; ++it)
248 : {
249 4 : ScRange aNewRange = it->maArea;
250 4 : aNewRange.Move(rDelta.Col(), rDelta.Row(), rDelta.Tab());
251 4 : pBASM->StartListeningArea(aNewRange, it->mbGroupListening, it->mpListener);
252 : }
253 6 : }
254 : }
255 :
256 13 : void ScDocument::AreaBroadcast( const ScHint& rHint )
257 : {
258 13 : if ( !pBASM )
259 13 : return ; // Clipboard or Undo
260 13 : if ( !bHardRecalcState )
261 : {
262 13 : ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
263 13 : if ( pBASM->AreaBroadcast( rHint ) )
264 0 : TrackFormulas( rHint.GetId() );
265 : }
266 :
267 29 : for(SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabs.size()); ++nTab)
268 : {
269 16 : if(!maTabs[nTab])
270 0 : continue;
271 :
272 16 : ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
273 16 : if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
274 16 : pCondFormList->SourceChanged( rHint.GetAddress() );
275 : }
276 : }
277 :
278 180 : void ScDocument::DelBroadcastAreasInRange( const ScRange& rRange )
279 : {
280 180 : if ( pBASM )
281 180 : pBASM->DelBroadcastAreasInRange( rRange );
282 180 : }
283 :
284 1059 : void ScDocument::StartListeningCell( const ScAddress& rAddress,
285 : SvtListener* pListener )
286 : {
287 : OSL_ENSURE(pListener, "StartListeningCell: pListener Null");
288 1059 : SCTAB nTab = rAddress.Tab();
289 1059 : if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
290 1059 : maTabs[nTab]->StartListening( rAddress, pListener );
291 1059 : }
292 :
293 783 : void ScDocument::EndListeningCell( const ScAddress& rAddress,
294 : SvtListener* pListener )
295 : {
296 : OSL_ENSURE(pListener, "EndListeningCell: pListener Null");
297 783 : SCTAB nTab = rAddress.Tab();
298 783 : if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
299 775 : maTabs[nTab]->EndListening( rAddress, pListener );
300 783 : }
301 :
302 13711 : void ScDocument::StartListeningCell(
303 : sc::StartListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
304 : {
305 13711 : ScTable* pTab = FetchTable(rPos.Tab());
306 13711 : if (!pTab)
307 13778 : return;
308 :
309 13644 : pTab->StartListening(rCxt, rPos.Col(), rPos.Row(), rListener);
310 : }
311 :
312 595 : void ScDocument::EndListeningCell(
313 : sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
314 : {
315 595 : ScTable* pTab = FetchTable(rPos.Tab());
316 595 : if (!pTab)
317 595 : return;
318 :
319 595 : pTab->EndListening(rCxt, rPos.Col(), rPos.Row(), rListener);
320 : }
321 :
322 4495 : void ScDocument::EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells )
323 : {
324 4495 : if (rCells.empty())
325 8869 : return;
326 :
327 121 : sc::EndListeningContext aCxt(*this);
328 121 : std::vector<ScFormulaCell*>::iterator it = rCells.begin(), itEnd = rCells.end();
329 457 : for (; it != itEnd; ++it)
330 336 : (*it)->EndListeningTo(aCxt);
331 :
332 121 : aCxt.purgeEmptyBroadcasters();
333 : }
334 :
335 28764 : void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
336 : {
337 : OSL_ENSURE( pCell, "PutInFormulaTree: pCell Null" );
338 28764 : RemoveFromFormulaTree( pCell );
339 : // append
340 28764 : if ( pEOFormulaTree )
341 28038 : pEOFormulaTree->SetNext( pCell );
342 : else
343 726 : pFormulaTree = pCell; // No end, no beginning..
344 28764 : pCell->SetPrevious( pEOFormulaTree );
345 28764 : pCell->SetNext( 0 );
346 28764 : pEOFormulaTree = pCell;
347 28764 : nFormulaCodeInTree += pCell->GetCode()->GetCodeLen();
348 28764 : }
349 :
350 87497 : void ScDocument::RemoveFromFormulaTree( ScFormulaCell* pCell )
351 : {
352 : OSL_ENSURE( pCell, "RemoveFromFormulaTree: pCell Null" );
353 87497 : ScFormulaCell* pPrev = pCell->GetPrevious();
354 : assert(pPrev != pCell); // pointing to itself?!?
355 : // if the cell is first or somewhere in chain
356 87497 : if ( pPrev || pFormulaTree == pCell )
357 : {
358 28754 : ScFormulaCell* pNext = pCell->GetNext();
359 : assert(pNext != pCell); // pointing to itself?!?
360 28754 : if ( pPrev )
361 : {
362 : assert(pFormulaTree != pCell); // if this cell is also head something's wrong
363 4268 : pPrev->SetNext( pNext ); // predecessor exists, set successor
364 : }
365 : else
366 : {
367 24486 : pFormulaTree = pNext; // this cell was first cell
368 : }
369 28754 : if ( pNext )
370 : {
371 : assert(pEOFormulaTree != pCell); // if this cell is also tail something's wrong
372 27712 : pNext->SetPrevious( pPrev ); // successor exists, set predecessor
373 : }
374 : else
375 : {
376 1042 : pEOFormulaTree = pPrev; // this cell was last cell
377 : }
378 28754 : pCell->SetPrevious( 0 );
379 28754 : pCell->SetNext( 0 );
380 28754 : sal_uInt16 nRPN = pCell->GetCode()->GetCodeLen();
381 28754 : if ( nFormulaCodeInTree >= nRPN )
382 28754 : nFormulaCodeInTree -= nRPN;
383 : else
384 : {
385 : OSL_FAIL( "RemoveFromFormulaTree: nFormulaCodeInTree < nRPN" );
386 0 : nFormulaCodeInTree = 0;
387 28754 : }
388 : }
389 58743 : else if ( !pFormulaTree && nFormulaCodeInTree )
390 : {
391 : OSL_FAIL( "!pFormulaTree && nFormulaCodeInTree != 0" );
392 0 : nFormulaCodeInTree = 0;
393 : }
394 87497 : }
395 :
396 70254 : bool ScDocument::IsInFormulaTree( ScFormulaCell* pCell ) const
397 : {
398 70254 : return pCell->GetPrevious() || pFormulaTree == pCell;
399 : }
400 :
401 155 : void ScDocument::CalcFormulaTree( bool bOnlyForced, bool bProgressBar, bool bSetAllDirty )
402 : {
403 : OSL_ENSURE( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
404 : // never ever recurse into this, might end up lost in infinity
405 155 : if ( IsCalculatingFormulaTree() )
406 155 : return ;
407 :
408 155 : mpFormulaGroupCxt.reset();
409 155 : bCalculatingFormulaTree = true;
410 :
411 155 : SetForcedFormulaPending( false );
412 155 : bool bOldIdleEnabled = IsIdleEnabled();
413 155 : EnableIdle(false);
414 155 : bool bOldAutoCalc = GetAutoCalc();
415 : //ATTENTION: _not_ SetAutoCalc( true ) because this might call CalcFormulaTree( true )
416 : //ATTENTION: if it was disabled before and bHasForcedFormulas is set
417 155 : bAutoCalc = true;
418 155 : if ( bHardRecalcState )
419 0 : CalcAll();
420 : else
421 : {
422 155 : ScFormulaCell* pCell = pFormulaTree;
423 1080 : while ( pCell )
424 : {
425 770 : if ( pCell->GetDirty() )
426 770 : pCell = pCell->GetNext(); // all clear
427 : else
428 : {
429 0 : if ( pCell->GetCode()->IsRecalcModeAlways() )
430 : {
431 : // pCell is set to Dirty again!
432 0 : ScFormulaCell* pNext = pCell->GetNext();
433 0 : pCell->SetDirty();
434 : // if pNext==0 and new dependencies were appended at the end,
435 : // this does not matter since they all are bDirty
436 0 : pCell = pNext;
437 : }
438 : else
439 : { // calculate the other single
440 0 : if( bSetAllDirty )
441 0 : pCell->SetDirtyVar();
442 0 : pCell = pCell->GetNext();
443 : }
444 : }
445 : }
446 155 : bool bProgress = !bOnlyForced && nFormulaCodeInTree && bProgressBar;
447 155 : if ( bProgress )
448 8 : ScProgress::CreateInterpretProgress( this, true );
449 :
450 155 : pCell = pFormulaTree;
451 155 : ScFormulaCell* pLastNoGood = 0;
452 567 : while ( pCell )
453 : {
454 : // Interpret resets bDirty and calls Remove, also the referenced!
455 : // the Cell remains when ScRecalcMode::ALWAYS.
456 257 : if ( bOnlyForced )
457 : {
458 0 : if ( pCell->GetCode()->IsRecalcModeForced() )
459 0 : pCell->Interpret();
460 : }
461 : else
462 : {
463 257 : pCell->Interpret();
464 : }
465 257 : if ( pCell->GetPrevious() || pCell == pFormulaTree )
466 : { // (IsInFormulaTree(pCell)) no Remove was called => next
467 2 : pLastNoGood = pCell;
468 2 : pCell = pCell->GetNext();
469 : }
470 : else
471 : {
472 255 : if ( pFormulaTree )
473 : {
474 244 : if ( pFormulaTree->GetDirty() && !bOnlyForced )
475 : {
476 244 : pCell = pFormulaTree;
477 244 : pLastNoGood = 0;
478 : }
479 : else
480 : {
481 : // IsInFormulaTree(pLastNoGood)
482 0 : if ( pLastNoGood && (pLastNoGood->GetPrevious() ||
483 0 : pLastNoGood == pFormulaTree) )
484 0 : pCell = pLastNoGood->GetNext();
485 : else
486 : {
487 0 : pCell = pFormulaTree;
488 0 : while ( pCell && !pCell->GetDirty() )
489 0 : pCell = pCell->GetNext();
490 0 : if ( pCell )
491 0 : pLastNoGood = pCell->GetPrevious();
492 : }
493 : }
494 : }
495 : else
496 11 : pCell = 0;
497 : }
498 257 : if ( ScProgress::IsUserBreak() )
499 0 : pCell = 0;
500 : }
501 155 : if ( bProgress )
502 8 : ScProgress::DeleteInterpretProgress();
503 : }
504 155 : bAutoCalc = bOldAutoCalc;
505 155 : EnableIdle(bOldIdleEnabled);
506 155 : bCalculatingFormulaTree = false;
507 :
508 155 : mpFormulaGroupCxt.reset();
509 : }
510 :
511 349 : void ScDocument::ClearFormulaTree()
512 : {
513 : ScFormulaCell* pCell;
514 349 : ScFormulaCell* pTree = pFormulaTree;
515 891 : while ( pTree )
516 : {
517 193 : pCell = pTree;
518 193 : pTree = pCell->GetNext();
519 193 : if ( !pCell->GetCode()->IsRecalcModeAlways() )
520 155 : RemoveFromFormulaTree( pCell );
521 : }
522 349 : }
523 :
524 24613 : void ScDocument::AppendToFormulaTrack( ScFormulaCell* pCell )
525 : {
526 : OSL_ENSURE( pCell, "AppendToFormulaTrack: pCell Null" );
527 : // The cell can not be in both lists at the same time
528 24613 : RemoveFromFormulaTrack( pCell );
529 24613 : RemoveFromFormulaTree( pCell );
530 24613 : if ( pEOFormulaTrack )
531 6087 : pEOFormulaTrack->SetNextTrack( pCell );
532 : else
533 18526 : pFormulaTrack = pCell; // No end, no beginning..
534 24613 : pCell->SetPreviousTrack( pEOFormulaTrack );
535 24613 : pCell->SetNextTrack( 0 );
536 24613 : pEOFormulaTrack = pCell;
537 24613 : ++nFormulaTrackCount;
538 24613 : }
539 :
540 59446 : void ScDocument::RemoveFromFormulaTrack( ScFormulaCell* pCell )
541 : {
542 : OSL_ENSURE( pCell, "RemoveFromFormulaTrack: pCell Null" );
543 59446 : ScFormulaCell* pPrev = pCell->GetPreviousTrack();
544 : assert(pPrev != pCell); // pointing to itself?!?
545 : // if the cell is first or somewhere in chain
546 59446 : if ( pPrev || pFormulaTrack == pCell )
547 : {
548 24613 : ScFormulaCell* pNext = pCell->GetNextTrack();
549 : assert(pNext != pCell); // pointing to itself?!?
550 24613 : if ( pPrev )
551 : {
552 : assert(pFormulaTrack != pCell); // if this cell is also head something's wrong
553 12 : pPrev->SetNextTrack( pNext ); // predecessor exists, set successor
554 : }
555 : else
556 : {
557 24601 : pFormulaTrack = pNext; // this cell was first cell
558 : }
559 24613 : if ( pNext )
560 : {
561 : assert(pEOFormulaTrack != pCell); // if this cell is also tail something's wrong
562 6076 : pNext->SetPreviousTrack( pPrev ); // successor exists, set predecessor
563 : }
564 : else
565 : {
566 18537 : pEOFormulaTrack = pPrev; // this cell was last cell
567 : }
568 24613 : pCell->SetPreviousTrack( 0 );
569 24613 : pCell->SetNextTrack( 0 );
570 24613 : --nFormulaTrackCount;
571 : }
572 59446 : }
573 :
574 6579 : bool ScDocument::IsInFormulaTrack( ScFormulaCell* pCell ) const
575 : {
576 6579 : return pCell->GetPreviousTrack() || pFormulaTrack == pCell;
577 : }
578 :
579 : /*
580 : The first is broadcasted,
581 : the ones that are created through this are appended to the Track by Notify.
582 : The next is broadcasted again, and so on.
583 : View initiates Interpret.
584 : */
585 18945 : void ScDocument::TrackFormulas( sal_uLong nHintId )
586 : {
587 :
588 18945 : if ( pFormulaTrack )
589 : {
590 : // outside the loop, check if any sheet has a "calculate" event script
591 18525 : bool bCalcEvent = HasAnySheetEventScript( SC_SHEETEVENT_CALCULATE, true );
592 : ScFormulaCell* pTrack;
593 : ScFormulaCell* pNext;
594 18525 : pTrack = pFormulaTrack;
595 24590 : do
596 : {
597 24590 : SvtBroadcaster* pBC = GetBroadcaster(pTrack->aPos);
598 24590 : ScHint aHint(nHintId, pTrack->aPos);
599 24590 : if (pBC)
600 488 : pBC->Broadcast( aHint );
601 24590 : pBASM->AreaBroadcast( aHint );
602 : // Repaint for conditional formats with relative references:
603 24590 : TableContainer::iterator itr = maTabs.begin();
604 53281 : for(; itr != maTabs.end(); ++itr)
605 : {
606 28691 : if(!*itr)
607 0 : continue;
608 28691 : ScConditionalFormatList* pCondFormList = (*itr)->GetCondFormList();
609 28691 : if ( pCondFormList )
610 28691 : pCondFormList->SourceChanged( pTrack->aPos );
611 : }
612 : // for "calculate" event, keep track of which sheets are affected by tracked formulas
613 24590 : if ( bCalcEvent )
614 0 : SetCalcNotification( pTrack->aPos.Tab() );
615 24590 : pTrack = pTrack->GetNextTrack();
616 : } while ( pTrack );
617 18525 : pTrack = pFormulaTrack;
618 18525 : bool bHaveForced = false;
619 24590 : do
620 : {
621 24590 : pNext = pTrack->GetNextTrack();
622 24590 : RemoveFromFormulaTrack( pTrack );
623 24590 : PutInFormulaTree( pTrack );
624 24590 : if ( pTrack->GetCode()->IsRecalcModeForced() )
625 0 : bHaveForced = true;
626 24590 : pTrack = pNext;
627 : } while ( pTrack );
628 18525 : if ( bHaveForced )
629 : {
630 0 : SetForcedFormulas( true );
631 0 : if ( bAutoCalc && !IsAutoCalcShellDisabled() && !IsInInterpreter()
632 0 : && !IsCalculatingFormulaTree() )
633 0 : CalcFormulaTree( true );
634 : else
635 0 : SetForcedFormulaPending( true );
636 : }
637 : }
638 : OSL_ENSURE( nFormulaTrackCount==0, "TrackFormulas: nFormulaTrackCount!=0" );
639 18945 : }
640 :
641 380 : void ScDocument::StartAllListeners()
642 : {
643 380 : sc::StartListeningContext aCxt(*this);
644 1105 : for ( SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i )
645 725 : if ( maTabs[i] )
646 1105 : maTabs[i]->StartListeners(aCxt, true);
647 380 : }
648 :
649 330 : void ScDocument::UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
650 : const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
651 : )
652 : {
653 330 : bool bExpandRefsOld = IsExpandRefs();
654 330 : if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
655 153 : SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
656 330 : if ( pBASM )
657 330 : pBASM->UpdateBroadcastAreas( eUpdateRefMode, rRange, nDx, nDy, nDz );
658 330 : SetExpandRefs( bExpandRefsOld );
659 330 : }
660 :
661 3529523 : void ScDocument::SetAutoCalc( bool bNewAutoCalc )
662 : {
663 3529523 : bool bOld = bAutoCalc;
664 3529523 : bAutoCalc = bNewAutoCalc;
665 3529523 : if ( !bOld && bNewAutoCalc && bHasForcedFormulas )
666 : {
667 0 : if ( IsAutoCalcShellDisabled() )
668 0 : SetForcedFormulaPending( true );
669 0 : else if ( !IsInInterpreter() )
670 0 : CalcFormulaTree( true );
671 : }
672 3529679 : }
673 :
674 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|