1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: documen7.cxx,v $
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 )
40 #define erBEEPER() Beep( 666, 66 )
45 #include "document.hxx"
47 #include "bcaslot.hxx"
49 #include "formula/errorcodes.hxx" // errCircularReference
50 #include "scerrors.hxx"
51 #include "docoptio.hxx"
52 #include "refupdat.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"
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 -----------------------------------------------------------
76 ULONG erCountBCAInserts
= 0;
77 ULONG erCountBCAFinds
= 0;
80 // -----------------------------------------------------------------------
82 void ScDocument::StartListeningArea( const ScRange
& rRange
,
83 SvtListener
* pListener
87 pBASM
->StartListeningArea( rRange
, pListener
);
91 void ScDocument::EndListeningArea( const ScRange
& rRange
,
92 SvtListener
* pListener
96 pBASM
->EndListeningArea( rRange
, pListener
);
100 void ScDocument::Broadcast( ULONG nHint
, const ScAddress
& rAddr
,
105 return ; // Clipboard or Undo
106 ScHint
aHint( nHint
, rAddr
, pCell
);
111 void ScDocument::Broadcast( const ScHint
& rHint
)
114 return ; // Clipboard or Undo
115 if ( !nHardRecalcState
)
117 ScBulkBroadcast
aBulkBroadcast( pBASM
); // scoped bulk broadcast
118 BOOL bIsBroadcasted
= FALSE
;
119 ScBaseCell
* pCell
= rHint
.GetCell();
122 SvtBroadcaster
* pBC
= pCell
->GetBroadcaster();
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
)
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
)
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!
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
)
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();
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();
220 pTab
[nTab
]->EndListening( rAddress
, pListener
);
224 void ScDocument::PutInFormulaTree( ScFormulaCell
* pCell
)
226 DBG_ASSERT( pCell
, "PutInFormulaTree: pCell Null" );
227 RemoveFromFormulaTree( pCell
);
229 if ( pEOFormulaTree
)
230 pEOFormulaTree
->SetNext( pCell
);
232 pFormulaTree
= pCell
; // kein Ende, kein Anfang..
233 pCell
->SetPrevious( pEOFormulaTree
);
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();
249 pPrev
->SetNext( pNext
); // gibt Vorlaeufer
251 pFormulaTree
= pNext
; // ist erste Zelle
253 pNext
->SetPrevious( pPrev
); // gibt Nachfolger
255 pEOFormulaTree
= pPrev
; // ist letzte Zelle
256 pCell
->SetPrevious( 0 );
258 USHORT nRPN
= pCell
->GetCode()->GetCodeLen();
259 if ( nFormulaCodeInTree
>= nRPN
)
260 nFormulaCodeInTree
-= nRPN
;
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() )
287 bCalculatingFormulaTree
= TRUE
;
289 SetForcedFormulaPending( FALSE
);
290 BOOL bOldIdleDisabled
= IsIdleDisabled();
292 BOOL bOldAutoCalc
= GetAutoCalc();
293 //! _nicht_ SetAutoCalc( TRUE ) weil das evtl. CalcFormulaTree( TRUE )
294 //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
296 if ( nHardRecalcState
)
300 ScFormulaCell
* pCell
= pFormulaTree
;
303 if ( pCell
->GetDirty() )
304 pCell
= pCell
->GetNext(); // alles klar
307 if ( pCell
->GetCode()->IsRecalcModeAlways() )
309 // pCell wird im SetDirty neu angehaengt!
310 ScFormulaCell
* pNext
= pCell
->GetNext();
312 // falls pNext==0 und neue abhaengige hinten angehaengt
313 // wurden, so macht das nichts, da die alle bDirty sind
317 { // andere simpel berechnen
318 pCell
->SetDirtyVar();
319 pCell
= pCell
->GetNext();
323 BOOL bProgress
= !bOnlyForced
&& nFormulaCodeInTree
&& !bNoProgress
;
325 ScProgress::CreateInterpretProgress( this, TRUE
);
327 pCell
= pFormulaTree
;
328 ScFormulaCell
* pLastNoGood
= 0;
331 // Interpret setzt bDirty zurueck und callt Remove, auch der referierten!
332 // bei RECALCMODE_ALWAYS bleibt die Zelle
335 if ( pCell
->GetCode()->IsRecalcModeForced() )
342 if ( pCell
->GetPrevious() || pCell
== pFormulaTree
)
343 { // (IsInFormulaTree(pCell)) kein Remove gewesen => next
345 pCell
= pCell
->GetNext();
351 if ( pFormulaTree
->GetDirty() && !bOnlyForced
)
353 pCell
= pFormulaTree
;
358 // IsInFormulaTree(pLastNoGood)
359 if ( pLastNoGood
&& (pLastNoGood
->GetPrevious() ||
360 pLastNoGood
== pFormulaTree
) )
361 pCell
= pLastNoGood
->GetNext();
364 pCell
= pFormulaTree
;
365 while ( pCell
&& !pCell
->GetDirty() )
366 pCell
= pCell
->GetNext();
368 pLastNoGood
= pCell
->GetPrevious();
375 if ( ScProgress::IsUserBreak() )
379 ScProgress::DeleteInterpretProgress();
381 bAutoCalc
= bOldAutoCalc
;
382 DisableIdle( bOldIdleDisabled
);
383 bCalculatingFormulaTree
= FALSE
;
387 void ScDocument::ClearFormulaTree()
389 ScFormulaCell
* pCell
;
390 ScFormulaCell
* pTree
= pFormulaTree
;
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
);
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();
427 pPrev
->SetNextTrack( pNext
); // gibt Vorlaeufer
429 pFormulaTrack
= pNext
; // ist erste Zelle
431 pNext
->SetPreviousTrack( pPrev
); // gibt Nachfolger
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
)
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:
471 pCondFormList
->SourceChanged( pTrack
->aPos
);
472 pTrack
= pTrack
->GetNextTrack();
474 pTrack
= pFormulaTrack
;
475 BOOL bHaveForced
= FALSE
;
478 pNext
= pTrack
->GetNextTrack();
479 RemoveFromFormulaTrack( pTrack
);
480 PutInFormulaTree( pTrack
);
481 if ( pTrack
->GetCode()->IsRecalcModeForced() )
487 SetForcedFormulas( TRUE
);
488 if ( bAutoCalc
&& !IsAutoCalcShellDisabled() && !IsInInterpreter()
489 && !IsCalculatingFormulaTree() )
490 CalcFormulaTree( TRUE
);
492 SetForcedFormulaPending( TRUE
);
495 DBG_ASSERT( nFormulaTrackCount
==0, "TrackFormulas: nFormulaTrackCount!=0" );
499 void ScDocument::StartAllListeners()
501 for ( SCTAB i
= 0; i
<= MAXTAB
; ++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() );
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.
542 uno::Reference
< document::XVbaEventsHelper
> xVbaEventsHelper ( GetVbaEventsHelper(), uno::UNO_QUERY
);
543 if( xVbaEventsHelper
.is() )
545 uno::Sequence
< uno::Any
> aArgs(1);
547 bSuccess
= xVbaEventsHelper
->ProcessCompatibleVbaEvent( VBAEVENT_WORKSHEET_CALCULATE
, aArgs
);
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
);