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() );
137 if ( rHint
.GetAddress() != BCA_BRDCST_ALWAYS
)
139 SCTAB nTab
= rHint
.GetAddress().Tab();
140 if (pTab
[nTab
] && pTab
[nTab
]->IsStreamValid())
141 pTab
[nTab
]->SetStreamValid(FALSE
);
146 void ScDocument::AreaBroadcast( const ScHint
& rHint
)
149 return ; // Clipboard or Undo
150 if ( !nHardRecalcState
)
152 ScBulkBroadcast
aBulkBroadcast( pBASM
); // scoped bulk broadcast
153 if ( pBASM
->AreaBroadcast( rHint
) )
154 TrackFormulas( rHint
.GetId() );
157 // Repaint fuer bedingte Formate mit relativen Referenzen:
158 if ( pCondFormList
&& rHint
.GetAddress() != BCA_BRDCST_ALWAYS
)
159 pCondFormList
->SourceChanged( rHint
.GetAddress() );
163 void ScDocument::AreaBroadcastInRange( const ScRange
& rRange
, const ScHint
& rHint
)
166 return ; // Clipboard or Undo
167 if ( !nHardRecalcState
)
169 ScBulkBroadcast
aBulkBroadcast( pBASM
); // scoped bulk broadcast
170 if ( pBASM
->AreaBroadcastInRange( rRange
, rHint
) )
171 TrackFormulas( rHint
.GetId() );
174 // Repaint for conditional formats containing relative references.
175 //! This is _THE_ bottle neck!
187 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
188 ScAddress
aAddress( rRange
.aStart
);
189 for ( nTab
= nTab1
; nTab
<= nTab2
; ++nTab
)
191 aAddress
.SetTab( nTab
);
192 for ( nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
194 aAddress
.SetCol( nCol
);
195 for ( nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
197 aAddress
.SetRow( nRow
);
198 pCondFormList
->SourceChanged( aAddress
);
206 void ScDocument::DelBroadcastAreasInRange( const ScRange
& rRange
)
209 pBASM
->DelBroadcastAreasInRange( rRange
);
212 void ScDocument::StartListeningCell( const ScAddress
& rAddress
,
213 SvtListener
* pListener
)
215 DBG_ASSERT(pListener
, "StartListeningCell: pListener Null");
216 SCTAB nTab
= rAddress
.Tab();
218 pTab
[nTab
]->StartListening( rAddress
, pListener
);
221 void ScDocument::EndListeningCell( const ScAddress
& rAddress
,
222 SvtListener
* pListener
)
224 DBG_ASSERT(pListener
, "EndListeningCell: pListener Null");
225 SCTAB nTab
= rAddress
.Tab();
227 pTab
[nTab
]->EndListening( rAddress
, pListener
);
231 void ScDocument::PutInFormulaTree( ScFormulaCell
* pCell
)
233 DBG_ASSERT( pCell
, "PutInFormulaTree: pCell Null" );
234 RemoveFromFormulaTree( pCell
);
236 if ( pEOFormulaTree
)
237 pEOFormulaTree
->SetNext( pCell
);
239 pFormulaTree
= pCell
; // kein Ende, kein Anfang..
240 pCell
->SetPrevious( pEOFormulaTree
);
242 pEOFormulaTree
= pCell
;
243 nFormulaCodeInTree
+= pCell
->GetCode()->GetCodeLen();
247 void ScDocument::RemoveFromFormulaTree( ScFormulaCell
* pCell
)
249 DBG_ASSERT( pCell
, "RemoveFromFormulaTree: pCell Null" );
250 ScFormulaCell
* pPrev
= pCell
->GetPrevious();
251 // wenn die Zelle die erste oder sonstwo ist
252 if ( pPrev
|| pFormulaTree
== pCell
)
254 ScFormulaCell
* pNext
= pCell
->GetNext();
256 pPrev
->SetNext( pNext
); // gibt Vorlaeufer
258 pFormulaTree
= pNext
; // ist erste Zelle
260 pNext
->SetPrevious( pPrev
); // gibt Nachfolger
262 pEOFormulaTree
= pPrev
; // ist letzte Zelle
263 pCell
->SetPrevious( 0 );
265 USHORT nRPN
= pCell
->GetCode()->GetCodeLen();
266 if ( nFormulaCodeInTree
>= nRPN
)
267 nFormulaCodeInTree
-= nRPN
;
270 DBG_ERRORFILE( "RemoveFromFormulaTree: nFormulaCodeInTree < nRPN" );
271 nFormulaCodeInTree
= 0;
274 else if ( !pFormulaTree
&& nFormulaCodeInTree
)
276 DBG_ERRORFILE( "!pFormulaTree && nFormulaCodeInTree != 0" );
277 nFormulaCodeInTree
= 0;
282 BOOL
ScDocument::IsInFormulaTree( ScFormulaCell
* pCell
) const
284 return pCell
->GetPrevious() || pFormulaTree
== pCell
;
288 void ScDocument::CalcFormulaTree( BOOL bOnlyForced
, BOOL bNoProgress
)
290 DBG_ASSERT( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
291 // never ever recurse into this, might end up lost in infinity
292 if ( IsCalculatingFormulaTree() )
294 bCalculatingFormulaTree
= TRUE
;
296 SetForcedFormulaPending( FALSE
);
297 BOOL bOldIdleDisabled
= IsIdleDisabled();
299 BOOL bOldAutoCalc
= GetAutoCalc();
300 //! _nicht_ SetAutoCalc( TRUE ) weil das evtl. CalcFormulaTree( TRUE )
301 //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
303 if ( nHardRecalcState
)
307 ScFormulaCell
* pCell
= pFormulaTree
;
310 if ( pCell
->GetDirty() )
311 pCell
= pCell
->GetNext(); // alles klar
314 if ( pCell
->GetCode()->IsRecalcModeAlways() )
316 // pCell wird im SetDirty neu angehaengt!
317 ScFormulaCell
* pNext
= pCell
->GetNext();
319 // falls pNext==0 und neue abhaengige hinten angehaengt
320 // wurden, so macht das nichts, da die alle bDirty sind
324 { // andere simpel berechnen
325 pCell
->SetDirtyVar();
326 pCell
= pCell
->GetNext();
330 BOOL bProgress
= !bOnlyForced
&& nFormulaCodeInTree
&& !bNoProgress
;
332 ScProgress::CreateInterpretProgress( this, TRUE
);
334 pCell
= pFormulaTree
;
335 ScFormulaCell
* pLastNoGood
= 0;
338 // Interpret setzt bDirty zurueck und callt Remove, auch der referierten!
339 // bei RECALCMODE_ALWAYS bleibt die Zelle
342 if ( pCell
->GetCode()->IsRecalcModeForced() )
349 if ( pCell
->GetPrevious() || pCell
== pFormulaTree
)
350 { // (IsInFormulaTree(pCell)) kein Remove gewesen => next
352 pCell
= pCell
->GetNext();
358 if ( pFormulaTree
->GetDirty() && !bOnlyForced
)
360 pCell
= pFormulaTree
;
365 // IsInFormulaTree(pLastNoGood)
366 if ( pLastNoGood
&& (pLastNoGood
->GetPrevious() ||
367 pLastNoGood
== pFormulaTree
) )
368 pCell
= pLastNoGood
->GetNext();
371 pCell
= pFormulaTree
;
372 while ( pCell
&& !pCell
->GetDirty() )
373 pCell
= pCell
->GetNext();
375 pLastNoGood
= pCell
->GetPrevious();
382 if ( ScProgress::IsUserBreak() )
386 ScProgress::DeleteInterpretProgress();
388 bAutoCalc
= bOldAutoCalc
;
389 DisableIdle( bOldIdleDisabled
);
390 bCalculatingFormulaTree
= FALSE
;
394 void ScDocument::ClearFormulaTree()
396 ScFormulaCell
* pCell
;
397 ScFormulaCell
* pTree
= pFormulaTree
;
401 pTree
= pCell
->GetNext();
402 if ( !pCell
->GetCode()->IsRecalcModeAlways() )
403 RemoveFromFormulaTree( pCell
);
408 void ScDocument::AppendToFormulaTrack( ScFormulaCell
* pCell
)
410 DBG_ASSERT( pCell
, "AppendToFormulaTrack: pCell Null" );
411 // Zelle kann nicht in beiden Listen gleichzeitig sein
412 RemoveFromFormulaTrack( pCell
);
413 RemoveFromFormulaTree( pCell
);
414 if ( pEOFormulaTrack
)
415 pEOFormulaTrack
->SetNextTrack( pCell
);
417 pFormulaTrack
= pCell
; // kein Ende, kein Anfang..
418 pCell
->SetPreviousTrack( pEOFormulaTrack
);
419 pCell
->SetNextTrack( 0 );
420 pEOFormulaTrack
= pCell
;
421 ++nFormulaTrackCount
;
425 void ScDocument::RemoveFromFormulaTrack( ScFormulaCell
* pCell
)
427 DBG_ASSERT( pCell
, "RemoveFromFormulaTrack: pCell Null" );
428 ScFormulaCell
* pPrev
= pCell
->GetPreviousTrack();
429 // wenn die Zelle die erste oder sonstwo ist
430 if ( pPrev
|| pFormulaTrack
== pCell
)
432 ScFormulaCell
* pNext
= pCell
->GetNextTrack();
434 pPrev
->SetNextTrack( pNext
); // gibt Vorlaeufer
436 pFormulaTrack
= pNext
; // ist erste Zelle
438 pNext
->SetPreviousTrack( pPrev
); // gibt Nachfolger
440 pEOFormulaTrack
= pPrev
; // ist letzte Zelle
441 pCell
->SetPreviousTrack( 0 );
442 pCell
->SetNextTrack( 0 );
443 --nFormulaTrackCount
;
448 BOOL
ScDocument::IsInFormulaTrack( ScFormulaCell
* pCell
) const
450 return pCell
->GetPreviousTrack() || pFormulaTrack
== pCell
;
455 Der erste wird gebroadcastet,
456 die dadurch entstehenden werden durch das Notify an den Track gehaengt.
457 Der nachfolgende broadcastet wieder usw.
458 View stoesst Interpret an.
460 void ScDocument::TrackFormulas( ULONG nHintId
)
467 ScFormulaCell
* pTrack
;
468 ScFormulaCell
* pNext
;
469 pTrack
= pFormulaTrack
;
472 ScHint
aHint( nHintId
, pTrack
->aPos
, pTrack
);
473 if ( ( pBC
= pTrack
->GetBroadcaster() ) != NULL
)
474 pBC
->Broadcast( aHint
);
475 pBASM
->AreaBroadcast( aHint
);
476 // Repaint fuer bedingte Formate mit relativen Referenzen:
478 pCondFormList
->SourceChanged( pTrack
->aPos
);
479 pTrack
= pTrack
->GetNextTrack();
481 pTrack
= pFormulaTrack
;
482 BOOL bHaveForced
= FALSE
;
485 pNext
= pTrack
->GetNextTrack();
486 RemoveFromFormulaTrack( pTrack
);
487 PutInFormulaTree( pTrack
);
488 if ( pTrack
->GetCode()->IsRecalcModeForced() )
494 SetForcedFormulas( TRUE
);
495 if ( bAutoCalc
&& !IsAutoCalcShellDisabled() && !IsInInterpreter()
496 && !IsCalculatingFormulaTree() )
497 CalcFormulaTree( TRUE
);
499 SetForcedFormulaPending( TRUE
);
502 DBG_ASSERT( nFormulaTrackCount
==0, "TrackFormulas: nFormulaTrackCount!=0" );
506 void ScDocument::StartAllListeners()
508 for ( SCTAB i
= 0; i
<= MAXTAB
; ++i
)
510 pTab
[i
]->StartAllListeners();
513 void ScDocument::UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode
,
514 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
517 BOOL bExpandRefsOld
= IsExpandRefs();
518 if ( eUpdateRefMode
== URM_INSDEL
&& (nDx
> 0 || nDy
> 0 || nDz
> 0) )
519 SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
521 pBASM
->UpdateBroadcastAreas( eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
);
522 SetExpandRefs( bExpandRefsOld
);
525 void ScDocument::SetAutoCalc( BOOL bNewAutoCalc
)
527 BOOL bOld
= bAutoCalc
;
528 bAutoCalc
= bNewAutoCalc
;
529 if ( !bOld
&& bNewAutoCalc
&& bHasForcedFormulas
)
531 if ( IsAutoCalcShellDisabled() )
532 SetForcedFormulaPending( TRUE
);
533 else if ( !IsInInterpreter() )
534 CalcFormulaTree( TRUE
);
538 BOOL
ScDocument::FireCalculateEvent( SCTAB nTab
)
540 BOOL bSuccess
= FALSE
;
541 ::std::vector
<SCTAB
>::iterator iter
;
542 iter
= ::std::find( maTabs
.begin(), maTabs
.end(), nTab
);
543 if( iter
!= maTabs
.end() )
545 // make sure fire worksheet calculate event only once for each sheet
546 // regardless of how many formula cells are calculated.
549 uno::Reference
< document::XVbaEventsHelper
> xVbaEventsHelper ( GetVbaEventsHelper(), uno::UNO_QUERY
);
550 if( xVbaEventsHelper
.is() )
552 uno::Sequence
< uno::Any
> aArgs(1);
554 bSuccess
= xVbaEventsHelper
->ProcessCompatibleVbaEvent( VBAEVENT_WORKSHEET_CALCULATE
, aArgs
);
560 void ScDocument::AddCalculateTable( SCTAB nTab
)
562 ::std::vector
<SCTAB
>::iterator iter
;
563 iter
= ::std::find( maTabs
.begin(), maTabs
.end(), nTab
);
564 if( iter
== maTabs
.end() )
566 maTabs
.push_back( nTab
);