update dev300-m57
[ooovba.git] / sc / source / core / data / documen7.cxx
blob172b49db5242cc958a5f15814befbe3fea55f021
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: documen7.cxx,v $
10 * $Revision: 1.12 $
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"
34 // INCLUDE ---------------------------------------------------------------
36 #include <vcl/svapp.hxx>
38 #if defined( WNT ) && defined( erBEEP )
39 #include <svwin.h>
40 #define erBEEPER() Beep( 666, 66 )
41 #else
42 #define erBEEPER()
43 #endif
45 #include "document.hxx"
46 #include "brdcst.hxx"
47 #include "bcaslot.hxx"
48 #include "cell.hxx"
49 #include "formula/errorcodes.hxx" // errCircularReference
50 #include "scerrors.hxx"
51 #include "docoptio.hxx"
52 #include "refupdat.hxx"
53 #include "table.hxx"
54 #include "progress.hxx"
55 #include "scmod.hxx" // SC_MOD
56 #include "inputopt.hxx" // GetExpandRefs
57 #include "conditio.hxx"
58 #include <tools/shl.hxx>
61 #include "globstr.hrc"
62 #include <algorithm>
63 #include <vector>
66 #include <com/sun/star/document/XVbaEventsHelper.hpp>
67 #include <com/sun/star/document/VbaEventId.hpp>
69 using namespace com::sun::star;
70 using namespace com::sun::star::document::VbaEventId;
71 extern const ScFormulaCell* pLastFormulaTreeTop; // cellform.cxx Err527 WorkAround
73 // STATIC DATA -----------------------------------------------------------
75 #ifdef erDEBUG
76 ULONG erCountBCAInserts = 0;
77 ULONG erCountBCAFinds = 0;
78 #endif
80 // -----------------------------------------------------------------------
82 void ScDocument::StartListeningArea( const ScRange& rRange,
83 SvtListener* pListener
86 if ( pBASM )
87 pBASM->StartListeningArea( rRange, pListener );
91 void ScDocument::EndListeningArea( const ScRange& rRange,
92 SvtListener* pListener
95 if ( pBASM )
96 pBASM->EndListeningArea( rRange, pListener );
100 void ScDocument::Broadcast( ULONG nHint, const ScAddress& rAddr,
101 ScBaseCell* pCell
104 if ( !pBASM )
105 return ; // Clipboard or Undo
106 ScHint aHint( nHint, rAddr, pCell );
107 Broadcast( aHint );
111 void ScDocument::Broadcast( const ScHint& rHint )
113 if ( !pBASM )
114 return ; // Clipboard or Undo
115 if ( !nHardRecalcState )
117 ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
118 BOOL bIsBroadcasted = FALSE;
119 ScBaseCell* pCell = rHint.GetCell();
120 if ( pCell )
122 SvtBroadcaster* pBC = pCell->GetBroadcaster();
123 if ( pBC )
125 pBC->Broadcast( rHint );
126 bIsBroadcasted = TRUE;
129 if ( pBASM->AreaBroadcast( rHint ) || bIsBroadcasted )
130 TrackFormulas( rHint.GetId() );
133 // Repaint fuer bedingte Formate mit relativen Referenzen:
134 if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
135 pCondFormList->SourceChanged( rHint.GetAddress() );
139 void ScDocument::AreaBroadcast( const ScHint& rHint )
141 if ( !pBASM )
142 return ; // Clipboard or Undo
143 if ( !nHardRecalcState )
145 ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
146 if ( pBASM->AreaBroadcast( rHint ) )
147 TrackFormulas( rHint.GetId() );
150 // Repaint fuer bedingte Formate mit relativen Referenzen:
151 if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
152 pCondFormList->SourceChanged( rHint.GetAddress() );
156 void ScDocument::AreaBroadcastInRange( const ScRange& rRange, const ScHint& rHint )
158 if ( !pBASM )
159 return ; // Clipboard or Undo
160 if ( !nHardRecalcState )
162 ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
163 if ( pBASM->AreaBroadcastInRange( rRange, rHint ) )
164 TrackFormulas( rHint.GetId() );
167 // Repaint for conditional formats containing relative references.
168 //! This is _THE_ bottle neck!
169 if ( pCondFormList )
171 SCCOL nCol;
172 SCROW nRow;
173 SCTAB nTab;
174 SCCOL nCol1;
175 SCROW nRow1;
176 SCTAB nTab1;
177 SCCOL nCol2;
178 SCROW nRow2;
179 SCTAB nTab2;
180 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
181 ScAddress aAddress( rRange.aStart );
182 for ( nTab = nTab1; nTab <= nTab2; ++nTab )
184 aAddress.SetTab( nTab );
185 for ( nCol = nCol1; nCol <= nCol2; ++nCol )
187 aAddress.SetCol( nCol );
188 for ( nRow = nRow1; nRow <= nRow2; ++nRow )
190 aAddress.SetRow( nRow );
191 pCondFormList->SourceChanged( aAddress );
199 void ScDocument::DelBroadcastAreasInRange( const ScRange& rRange )
201 if ( pBASM )
202 pBASM->DelBroadcastAreasInRange( rRange );
205 void ScDocument::StartListeningCell( const ScAddress& rAddress,
206 SvtListener* pListener )
208 DBG_ASSERT(pListener, "StartListeningCell: pListener Null");
209 SCTAB nTab = rAddress.Tab();
210 if (pTab[nTab])
211 pTab[nTab]->StartListening( rAddress, pListener );
214 void ScDocument::EndListeningCell( const ScAddress& rAddress,
215 SvtListener* pListener )
217 DBG_ASSERT(pListener, "EndListeningCell: pListener Null");
218 SCTAB nTab = rAddress.Tab();
219 if (pTab[nTab])
220 pTab[nTab]->EndListening( rAddress, pListener );
224 void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
226 DBG_ASSERT( pCell, "PutInFormulaTree: pCell Null" );
227 RemoveFromFormulaTree( pCell );
228 // anhaengen
229 if ( pEOFormulaTree )
230 pEOFormulaTree->SetNext( pCell );
231 else
232 pFormulaTree = pCell; // kein Ende, kein Anfang..
233 pCell->SetPrevious( pEOFormulaTree );
234 pCell->SetNext( 0 );
235 pEOFormulaTree = pCell;
236 nFormulaCodeInTree += pCell->GetCode()->GetCodeLen();
240 void ScDocument::RemoveFromFormulaTree( ScFormulaCell* pCell )
242 DBG_ASSERT( pCell, "RemoveFromFormulaTree: pCell Null" );
243 ScFormulaCell* pPrev = pCell->GetPrevious();
244 // wenn die Zelle die erste oder sonstwo ist
245 if ( pPrev || pFormulaTree == pCell )
247 ScFormulaCell* pNext = pCell->GetNext();
248 if ( pPrev )
249 pPrev->SetNext( pNext ); // gibt Vorlaeufer
250 else
251 pFormulaTree = pNext; // ist erste Zelle
252 if ( pNext )
253 pNext->SetPrevious( pPrev ); // gibt Nachfolger
254 else
255 pEOFormulaTree = pPrev; // ist letzte Zelle
256 pCell->SetPrevious( 0 );
257 pCell->SetNext( 0 );
258 USHORT nRPN = pCell->GetCode()->GetCodeLen();
259 if ( nFormulaCodeInTree >= nRPN )
260 nFormulaCodeInTree -= nRPN;
261 else
263 DBG_ERRORFILE( "RemoveFromFormulaTree: nFormulaCodeInTree < nRPN" );
264 nFormulaCodeInTree = 0;
267 else if ( !pFormulaTree && nFormulaCodeInTree )
269 DBG_ERRORFILE( "!pFormulaTree && nFormulaCodeInTree != 0" );
270 nFormulaCodeInTree = 0;
275 BOOL ScDocument::IsInFormulaTree( ScFormulaCell* pCell ) const
277 return pCell->GetPrevious() || pFormulaTree == pCell;
281 void ScDocument::CalcFormulaTree( BOOL bOnlyForced, BOOL bNoProgress )
283 DBG_ASSERT( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
284 // never ever recurse into this, might end up lost in infinity
285 if ( IsCalculatingFormulaTree() )
286 return ;
287 bCalculatingFormulaTree = TRUE;
289 SetForcedFormulaPending( FALSE );
290 BOOL bOldIdleDisabled = IsIdleDisabled();
291 DisableIdle( TRUE );
292 BOOL bOldAutoCalc = GetAutoCalc();
293 //! _nicht_ SetAutoCalc( TRUE ) weil das evtl. CalcFormulaTree( TRUE )
294 //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
295 bAutoCalc = TRUE;
296 if ( nHardRecalcState )
297 CalcAll();
298 else
300 ScFormulaCell* pCell = pFormulaTree;
301 while ( pCell )
303 if ( pCell->GetDirty() )
304 pCell = pCell->GetNext(); // alles klar
305 else
307 if ( pCell->GetCode()->IsRecalcModeAlways() )
309 // pCell wird im SetDirty neu angehaengt!
310 ScFormulaCell* pNext = pCell->GetNext();
311 pCell->SetDirty();
312 // falls pNext==0 und neue abhaengige hinten angehaengt
313 // wurden, so macht das nichts, da die alle bDirty sind
314 pCell = pNext;
316 else
317 { // andere simpel berechnen
318 pCell->SetDirtyVar();
319 pCell = pCell->GetNext();
323 BOOL bProgress = !bOnlyForced && nFormulaCodeInTree && !bNoProgress;
324 if ( bProgress )
325 ScProgress::CreateInterpretProgress( this, TRUE );
327 pCell = pFormulaTree;
328 ScFormulaCell* pLastNoGood = 0;
329 while ( pCell )
331 // Interpret setzt bDirty zurueck und callt Remove, auch der referierten!
332 // bei RECALCMODE_ALWAYS bleibt die Zelle
333 if ( bOnlyForced )
335 if ( pCell->GetCode()->IsRecalcModeForced() )
336 pCell->Interpret();
338 else
340 pCell->Interpret();
342 if ( pCell->GetPrevious() || pCell == pFormulaTree )
343 { // (IsInFormulaTree(pCell)) kein Remove gewesen => next
344 pLastNoGood = pCell;
345 pCell = pCell->GetNext();
347 else
349 if ( pFormulaTree )
351 if ( pFormulaTree->GetDirty() && !bOnlyForced )
353 pCell = pFormulaTree;
354 pLastNoGood = 0;
356 else
358 // IsInFormulaTree(pLastNoGood)
359 if ( pLastNoGood && (pLastNoGood->GetPrevious() ||
360 pLastNoGood == pFormulaTree) )
361 pCell = pLastNoGood->GetNext();
362 else
364 pCell = pFormulaTree;
365 while ( pCell && !pCell->GetDirty() )
366 pCell = pCell->GetNext();
367 if ( pCell )
368 pLastNoGood = pCell->GetPrevious();
372 else
373 pCell = 0;
375 if ( ScProgress::IsUserBreak() )
376 pCell = 0;
378 if ( bProgress )
379 ScProgress::DeleteInterpretProgress();
381 bAutoCalc = bOldAutoCalc;
382 DisableIdle( bOldIdleDisabled );
383 bCalculatingFormulaTree = FALSE;
387 void ScDocument::ClearFormulaTree()
389 ScFormulaCell* pCell;
390 ScFormulaCell* pTree = pFormulaTree;
391 while ( pTree )
393 pCell = pTree;
394 pTree = pCell->GetNext();
395 if ( !pCell->GetCode()->IsRecalcModeAlways() )
396 RemoveFromFormulaTree( pCell );
401 void ScDocument::AppendToFormulaTrack( ScFormulaCell* pCell )
403 DBG_ASSERT( pCell, "AppendToFormulaTrack: pCell Null" );
404 // Zelle kann nicht in beiden Listen gleichzeitig sein
405 RemoveFromFormulaTrack( pCell );
406 RemoveFromFormulaTree( pCell );
407 if ( pEOFormulaTrack )
408 pEOFormulaTrack->SetNextTrack( pCell );
409 else
410 pFormulaTrack = pCell; // kein Ende, kein Anfang..
411 pCell->SetPreviousTrack( pEOFormulaTrack );
412 pCell->SetNextTrack( 0 );
413 pEOFormulaTrack = pCell;
414 ++nFormulaTrackCount;
418 void ScDocument::RemoveFromFormulaTrack( ScFormulaCell* pCell )
420 DBG_ASSERT( pCell, "RemoveFromFormulaTrack: pCell Null" );
421 ScFormulaCell* pPrev = pCell->GetPreviousTrack();
422 // wenn die Zelle die erste oder sonstwo ist
423 if ( pPrev || pFormulaTrack == pCell )
425 ScFormulaCell* pNext = pCell->GetNextTrack();
426 if ( pPrev )
427 pPrev->SetNextTrack( pNext ); // gibt Vorlaeufer
428 else
429 pFormulaTrack = pNext; // ist erste Zelle
430 if ( pNext )
431 pNext->SetPreviousTrack( pPrev ); // gibt Nachfolger
432 else
433 pEOFormulaTrack = pPrev; // ist letzte Zelle
434 pCell->SetPreviousTrack( 0 );
435 pCell->SetNextTrack( 0 );
436 --nFormulaTrackCount;
441 BOOL ScDocument::IsInFormulaTrack( ScFormulaCell* pCell ) const
443 return pCell->GetPreviousTrack() || pFormulaTrack == pCell;
448 Der erste wird gebroadcastet,
449 die dadurch entstehenden werden durch das Notify an den Track gehaengt.
450 Der nachfolgende broadcastet wieder usw.
451 View stoesst Interpret an.
453 void ScDocument::TrackFormulas( ULONG nHintId )
456 if ( pFormulaTrack )
458 erBEEPER();
459 SvtBroadcaster* pBC;
460 ScFormulaCell* pTrack;
461 ScFormulaCell* pNext;
462 pTrack = pFormulaTrack;
465 ScHint aHint( nHintId, pTrack->aPos, pTrack );
466 if ( ( pBC = pTrack->GetBroadcaster() ) != NULL )
467 pBC->Broadcast( aHint );
468 pBASM->AreaBroadcast( aHint );
469 // Repaint fuer bedingte Formate mit relativen Referenzen:
470 if ( pCondFormList )
471 pCondFormList->SourceChanged( pTrack->aPos );
472 pTrack = pTrack->GetNextTrack();
473 } while ( pTrack );
474 pTrack = pFormulaTrack;
475 BOOL bHaveForced = FALSE;
478 pNext = pTrack->GetNextTrack();
479 RemoveFromFormulaTrack( pTrack );
480 PutInFormulaTree( pTrack );
481 if ( pTrack->GetCode()->IsRecalcModeForced() )
482 bHaveForced = TRUE;
483 pTrack = pNext;
484 } while ( pTrack );
485 if ( bHaveForced )
487 SetForcedFormulas( TRUE );
488 if ( bAutoCalc && !IsAutoCalcShellDisabled() && !IsInInterpreter()
489 && !IsCalculatingFormulaTree() )
490 CalcFormulaTree( TRUE );
491 else
492 SetForcedFormulaPending( TRUE );
495 DBG_ASSERT( nFormulaTrackCount==0, "TrackFormulas: nFormulaTrackCount!=0" );
499 void ScDocument::StartAllListeners()
501 for ( SCTAB i = 0; i <= MAXTAB; ++i )
502 if ( pTab[i] )
503 pTab[i]->StartAllListeners();
506 void ScDocument::UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
507 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
510 BOOL bExpandRefsOld = IsExpandRefs();
511 if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
512 SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
513 if ( pBASM )
514 pBASM->UpdateBroadcastAreas( eUpdateRefMode, rRange, nDx, nDy, nDz );
515 SetExpandRefs( bExpandRefsOld );
518 void ScDocument::SetAutoCalc( BOOL bNewAutoCalc )
520 BOOL bOld = bAutoCalc;
521 bAutoCalc = bNewAutoCalc;
522 if ( !bOld && bNewAutoCalc && bHasForcedFormulas )
524 if ( IsAutoCalcShellDisabled() )
525 SetForcedFormulaPending( TRUE );
526 else if ( !IsInInterpreter() )
527 CalcFormulaTree( TRUE );
531 BOOL ScDocument::FireCalculateEvent( SCTAB nTab )
533 BOOL bSuccess = FALSE;
534 ::std::vector<SCTAB>::iterator iter;
535 iter = ::std::find( maTabs.begin(), maTabs.end(), nTab );
536 if( iter != maTabs.end() )
538 // make sure fire worksheet calculate event only once for each sheet
539 // regardless of how many formula cells are calculated.
540 maTabs.erase(iter);
542 uno::Reference< document::XVbaEventsHelper > xVbaEventsHelper ( GetVbaEventsHelper(), uno::UNO_QUERY );
543 if( xVbaEventsHelper.is() )
545 uno::Sequence< uno::Any > aArgs(1);
546 aArgs[0] <<= nTab;
547 bSuccess = xVbaEventsHelper->ProcessCompatibleVbaEvent( VBAEVENT_WORKSHEET_CALCULATE, aArgs );
550 return bSuccess;
553 void ScDocument::AddCalculateTable( SCTAB nTab )
555 ::std::vector<SCTAB>::iterator iter;
556 iter = ::std::find( maTabs.begin(), maTabs.end(), nTab );
557 if( iter == maTabs.end() )
559 maTabs.push_back( nTab );