Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / documen7.cxx
blob7dd9821fea56be7001f491fb648949eec9cca0b9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <vcl/svapp.hxx>
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"
41 #include <tools/shl.hxx>
44 #include "globstr.hrc"
46 extern const ScFormulaCell* pLastFormulaTreeTop; // cellform.cxx Err527 WorkAround
48 // STATIC DATA -----------------------------------------------------------
50 // -----------------------------------------------------------------------
52 void ScDocument::StartListeningArea( const ScRange& rRange,
53 SvtListener* pListener
56 if ( pBASM )
57 pBASM->StartListeningArea( rRange, pListener );
61 void ScDocument::EndListeningArea( const ScRange& rRange,
62 SvtListener* pListener
65 if ( pBASM )
66 pBASM->EndListeningArea( rRange, pListener );
69 void ScDocument::Broadcast( const ScHint& rHint )
71 if ( !pBASM )
72 return ; // Clipboard or Undo
73 if ( !bHardRecalcState )
75 ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
76 bool bIsBroadcasted = false;
77 SvtBroadcaster* pBC = GetBroadcaster(rHint.GetAddress());
78 if ( pBC )
80 pBC->Broadcast( rHint );
81 bIsBroadcasted = true;
83 if ( pBASM->AreaBroadcast( rHint ) || bIsBroadcasted )
84 TrackFormulas( rHint.GetId() );
87 // Repaint fuer bedingte Formate mit relativen Referenzen:
88 for(SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabs.size()); ++nTab)
90 if(!maTabs[nTab])
91 continue;
93 ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
94 if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
95 pCondFormList->SourceChanged( rHint.GetAddress() );
99 if ( rHint.GetAddress() != BCA_BRDCST_ALWAYS )
101 SCTAB nTab = rHint.GetAddress().Tab();
102 if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] && maTabs[nTab]->IsStreamValid())
103 maTabs[nTab]->SetStreamValid(false);
108 void ScDocument::AreaBroadcast( const ScHint& rHint )
110 if ( !pBASM )
111 return ; // Clipboard or Undo
112 if ( !bHardRecalcState )
114 ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
115 if ( pBASM->AreaBroadcast( rHint ) )
116 TrackFormulas( rHint.GetId() );
119 for(SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabs.size()); ++nTab)
121 if(!maTabs[nTab])
122 continue;
124 ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
125 if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
126 pCondFormList->SourceChanged( rHint.GetAddress() );
131 void ScDocument::AreaBroadcastInRange( const ScRange& rRange, const ScHint& rHint )
133 if ( !pBASM )
134 return ; // Clipboard or Undo
135 if ( !bHardRecalcState )
137 ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
138 if ( pBASM->AreaBroadcastInRange( rRange, rHint ) )
139 TrackFormulas( rHint.GetId() );
142 // Repaint for conditional formats containing relative references.
143 //! This is _THE_ bottle neck!
144 TableContainer::iterator itr = maTabs.begin();
145 for(; itr != maTabs.end(); ++itr)
147 if(!*itr)
148 continue;
150 ScConditionalFormatList* pCondFormList = (*itr)->GetCondFormList();
151 if ( pCondFormList )
153 SCCOL nCol1;
154 SCROW nRow1;
155 SCTAB nTab1;
156 SCCOL nCol2;
157 SCROW nRow2;
158 SCTAB nTab2;
159 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
160 ScAddress aAddress( rRange.aStart );
161 for ( SCTAB nTab = nTab1; nTab <= nTab2; ++nTab )
163 aAddress.SetTab( nTab );
164 for ( SCCOL nCol = nCol1; nCol <= nCol2; ++nCol )
166 aAddress.SetCol( nCol );
167 for ( SCROW nRow = nRow1; nRow <= nRow2; ++nRow )
169 aAddress.SetRow( nRow );
170 pCondFormList->SourceChanged( aAddress );
180 void ScDocument::DelBroadcastAreasInRange( const ScRange& rRange )
182 if ( pBASM )
183 pBASM->DelBroadcastAreasInRange( rRange );
186 void ScDocument::StartListeningCell( const ScAddress& rAddress,
187 SvtListener* pListener )
189 OSL_ENSURE(pListener, "StartListeningCell: pListener Null");
190 SCTAB nTab = rAddress.Tab();
191 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
192 maTabs[nTab]->StartListening( rAddress, pListener );
195 void ScDocument::EndListeningCell( const ScAddress& rAddress,
196 SvtListener* pListener )
198 OSL_ENSURE(pListener, "EndListeningCell: pListener Null");
199 SCTAB nTab = rAddress.Tab();
200 if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
201 maTabs[nTab]->EndListening( rAddress, pListener );
204 void ScDocument::StartListeningCell(
205 sc::StartListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
207 ScTable* pTab = FetchTable(rPos.Tab());
208 if (!pTab)
209 return;
211 pTab->StartListening(rCxt, rPos.Col(), rPos.Row(), rListener);
214 void ScDocument::EndListeningCell(
215 sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener )
217 ScTable* pTab = FetchTable(rPos.Tab());
218 if (!pTab)
219 return;
221 pTab->EndListening(rCxt, rPos.Col(), rPos.Row(), rListener);
224 void ScDocument::EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells )
226 if (rCells.empty())
227 return;
229 sc::EndListeningContext aCxt(*this);
230 std::vector<ScFormulaCell*>::iterator it = rCells.begin(), itEnd = rCells.end();
231 for (; it != itEnd; ++it)
232 (*it)->EndListeningTo(aCxt);
234 aCxt.purgeEmptyBroadcasters();
237 void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
239 OSL_ENSURE( pCell, "PutInFormulaTree: pCell Null" );
240 RemoveFromFormulaTree( pCell );
241 // anhaengen
242 if ( pEOFormulaTree )
243 pEOFormulaTree->SetNext( pCell );
244 else
245 pFormulaTree = pCell; // kein Ende, kein Anfang..
246 pCell->SetPrevious( pEOFormulaTree );
247 pCell->SetNext( 0 );
248 pEOFormulaTree = pCell;
249 nFormulaCodeInTree += pCell->GetCode()->GetCodeLen();
253 void ScDocument::RemoveFromFormulaTree( ScFormulaCell* pCell )
255 OSL_ENSURE( pCell, "RemoveFromFormulaTree: pCell Null" );
256 ScFormulaCell* pPrev = pCell->GetPrevious();
257 // wenn die Zelle die erste oder sonstwo ist
258 if ( pPrev || pFormulaTree == pCell )
260 ScFormulaCell* pNext = pCell->GetNext();
261 if ( pPrev )
262 pPrev->SetNext( pNext ); // gibt Vorlaeufer
263 else
264 pFormulaTree = pNext; // ist erste Zelle
265 if ( pNext )
266 pNext->SetPrevious( pPrev ); // gibt Nachfolger
267 else
268 pEOFormulaTree = pPrev; // ist letzte Zelle
269 pCell->SetPrevious( 0 );
270 pCell->SetNext( 0 );
271 sal_uInt16 nRPN = pCell->GetCode()->GetCodeLen();
272 if ( nFormulaCodeInTree >= nRPN )
273 nFormulaCodeInTree -= nRPN;
274 else
276 OSL_FAIL( "RemoveFromFormulaTree: nFormulaCodeInTree < nRPN" );
277 nFormulaCodeInTree = 0;
280 else if ( !pFormulaTree && nFormulaCodeInTree )
282 OSL_FAIL( "!pFormulaTree && nFormulaCodeInTree != 0" );
283 nFormulaCodeInTree = 0;
288 bool ScDocument::IsInFormulaTree( ScFormulaCell* pCell ) const
290 return pCell->GetPrevious() || pFormulaTree == pCell;
294 void ScDocument::CalcFormulaTree( bool bOnlyForced, bool bProgressBar, bool bSetAllDirty )
296 OSL_ENSURE( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
297 // never ever recurse into this, might end up lost in infinity
298 if ( IsCalculatingFormulaTree() )
299 return ;
301 mpFormulaGroupCxt.reset();
302 bCalculatingFormulaTree = true;
304 SetForcedFormulaPending( false );
305 bool bOldIdleEnabled = IsIdleEnabled();
306 EnableIdle(false);
307 bool bOldAutoCalc = GetAutoCalc();
308 //! _nicht_ SetAutoCalc( true ) weil das evtl. CalcFormulaTree( true )
309 //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
310 bAutoCalc = true;
311 if ( bHardRecalcState )
312 CalcAll();
313 else
315 ScFormulaCell* pCell = pFormulaTree;
316 while ( pCell )
318 if ( pCell->GetDirty() )
319 pCell = pCell->GetNext(); // alles klar
320 else
322 if ( pCell->GetCode()->IsRecalcModeAlways() )
324 // pCell wird im SetDirty neu angehaengt!
325 ScFormulaCell* pNext = pCell->GetNext();
326 pCell->SetDirty();
327 // falls pNext==0 und neue abhaengige hinten angehaengt
328 // wurden, so macht das nichts, da die alle bDirty sind
329 pCell = pNext;
331 else
332 { // andere simpel berechnen
333 if( bSetAllDirty )
334 pCell->SetDirtyVar();
335 pCell = pCell->GetNext();
339 bool bProgress = !bOnlyForced && nFormulaCodeInTree && bProgressBar;
340 if ( bProgress )
341 ScProgress::CreateInterpretProgress( this, true );
343 pCell = pFormulaTree;
344 ScFormulaCell* pLastNoGood = 0;
345 while ( pCell )
347 // Interpret setzt bDirty zurueck und callt Remove, auch der referierten!
348 // bei RECALCMODE_ALWAYS bleibt die Zelle
349 if ( bOnlyForced )
351 if ( pCell->GetCode()->IsRecalcModeForced() )
352 pCell->Interpret();
354 else
356 pCell->Interpret();
358 if ( pCell->GetPrevious() || pCell == pFormulaTree )
359 { // (IsInFormulaTree(pCell)) kein Remove gewesen => next
360 pLastNoGood = pCell;
361 pCell = pCell->GetNext();
363 else
365 if ( pFormulaTree )
367 if ( pFormulaTree->GetDirty() && !bOnlyForced )
369 pCell = pFormulaTree;
370 pLastNoGood = 0;
372 else
374 // IsInFormulaTree(pLastNoGood)
375 if ( pLastNoGood && (pLastNoGood->GetPrevious() ||
376 pLastNoGood == pFormulaTree) )
377 pCell = pLastNoGood->GetNext();
378 else
380 pCell = pFormulaTree;
381 while ( pCell && !pCell->GetDirty() )
382 pCell = pCell->GetNext();
383 if ( pCell )
384 pLastNoGood = pCell->GetPrevious();
388 else
389 pCell = 0;
391 if ( ScProgress::IsUserBreak() )
392 pCell = 0;
394 if ( bProgress )
395 ScProgress::DeleteInterpretProgress();
397 bAutoCalc = bOldAutoCalc;
398 EnableIdle(bOldIdleEnabled);
399 bCalculatingFormulaTree = false;
401 mpFormulaGroupCxt.reset();
405 void ScDocument::ClearFormulaTree()
407 ScFormulaCell* pCell;
408 ScFormulaCell* pTree = pFormulaTree;
409 while ( pTree )
411 pCell = pTree;
412 pTree = pCell->GetNext();
413 if ( !pCell->GetCode()->IsRecalcModeAlways() )
414 RemoveFromFormulaTree( pCell );
419 void ScDocument::AppendToFormulaTrack( ScFormulaCell* pCell )
421 OSL_ENSURE( pCell, "AppendToFormulaTrack: pCell Null" );
422 // Zelle kann nicht in beiden Listen gleichzeitig sein
423 RemoveFromFormulaTrack( pCell );
424 RemoveFromFormulaTree( pCell );
425 if ( pEOFormulaTrack )
426 pEOFormulaTrack->SetNextTrack( pCell );
427 else
428 pFormulaTrack = pCell; // kein Ende, kein Anfang..
429 pCell->SetPreviousTrack( pEOFormulaTrack );
430 pCell->SetNextTrack( 0 );
431 pEOFormulaTrack = pCell;
432 ++nFormulaTrackCount;
436 void ScDocument::RemoveFromFormulaTrack( ScFormulaCell* pCell )
438 OSL_ENSURE( pCell, "RemoveFromFormulaTrack: pCell Null" );
439 ScFormulaCell* pPrev = pCell->GetPreviousTrack();
440 // wenn die Zelle die erste oder sonstwo ist
441 if ( pPrev || pFormulaTrack == pCell )
443 ScFormulaCell* pNext = pCell->GetNextTrack();
444 if ( pPrev )
445 pPrev->SetNextTrack( pNext ); // gibt Vorlaeufer
446 else
447 pFormulaTrack = pNext; // ist erste Zelle
448 if ( pNext )
449 pNext->SetPreviousTrack( pPrev ); // gibt Nachfolger
450 else
451 pEOFormulaTrack = pPrev; // ist letzte Zelle
452 pCell->SetPreviousTrack( 0 );
453 pCell->SetNextTrack( 0 );
454 --nFormulaTrackCount;
459 bool ScDocument::IsInFormulaTrack( ScFormulaCell* pCell ) const
461 return pCell->GetPreviousTrack() || pFormulaTrack == pCell;
466 Der erste wird gebroadcastet,
467 die dadurch entstehenden werden durch das Notify an den Track gehaengt.
468 Der nachfolgende broadcastet wieder usw.
469 View stoesst Interpret an.
471 void ScDocument::TrackFormulas( sal_uLong nHintId )
474 if ( pFormulaTrack )
476 // outside the loop, check if any sheet has a "calculate" event script
477 bool bCalcEvent = HasAnySheetEventScript( SC_SHEETEVENT_CALCULATE, true );
478 SvtBroadcaster* pBC;
479 ScFormulaCell* pTrack;
480 ScFormulaCell* pNext;
481 pTrack = pFormulaTrack;
484 pBC = GetBroadcaster(pTrack->aPos);
485 ScHint aHint(nHintId, pTrack->aPos);
486 if (pBC)
487 pBC->Broadcast( aHint );
488 pBASM->AreaBroadcast( aHint );
489 // Repaint fuer bedingte Formate mit relativen Referenzen:
490 TableContainer::iterator itr = maTabs.begin();
491 for(; itr != maTabs.end(); ++itr)
493 if(!*itr)
494 continue;
495 ScConditionalFormatList* pCondFormList = (*itr)->GetCondFormList();
496 if ( pCondFormList )
497 pCondFormList->SourceChanged( pTrack->aPos );
499 // for "calculate" event, keep track of which sheets are affected by tracked formulas
500 if ( bCalcEvent )
501 SetCalcNotification( pTrack->aPos.Tab() );
502 pTrack = pTrack->GetNextTrack();
503 } while ( pTrack );
504 pTrack = pFormulaTrack;
505 bool bHaveForced = false;
508 pNext = pTrack->GetNextTrack();
509 RemoveFromFormulaTrack( pTrack );
510 PutInFormulaTree( pTrack );
511 if ( pTrack->GetCode()->IsRecalcModeForced() )
512 bHaveForced = true;
513 pTrack = pNext;
514 } while ( pTrack );
515 if ( bHaveForced )
517 SetForcedFormulas( true );
518 if ( bAutoCalc && !IsAutoCalcShellDisabled() && !IsInInterpreter()
519 && !IsCalculatingFormulaTree() )
520 CalcFormulaTree( true );
521 else
522 SetForcedFormulaPending( true );
525 OSL_ENSURE( nFormulaTrackCount==0, "TrackFormulas: nFormulaTrackCount!=0" );
529 void ScDocument::StartAllListeners()
531 for ( SCTAB i = 0; i < static_cast<SCTAB>(maTabs.size()); ++i )
532 if ( maTabs[i] )
533 maTabs[i]->StartAllListeners();
536 void ScDocument::UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
537 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
540 bool bExpandRefsOld = IsExpandRefs();
541 if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
542 SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
543 if ( pBASM )
544 pBASM->UpdateBroadcastAreas( eUpdateRefMode, rRange, nDx, nDy, nDz );
545 SetExpandRefs( bExpandRefsOld );
548 void ScDocument::SetAutoCalc( bool bNewAutoCalc )
550 bool bOld = bAutoCalc;
551 bAutoCalc = bNewAutoCalc;
552 if ( !bOld && bNewAutoCalc && bHasForcedFormulas )
554 if ( IsAutoCalcShellDisabled() )
555 SetForcedFormulaPending( true );
556 else if ( !IsInInterpreter() )
557 CalcFormulaTree( true );
563 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */