Update ooo320-m1
[ooovba.git] / sc / source / core / data / documen7.cxx
blob31fc961940cb32eb659096f91ec9627d6c0771e4
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() );
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 )
148 if ( !pBASM )
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 )
165 if ( !pBASM )
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!
176 if ( pCondFormList )
178 SCCOL nCol;
179 SCROW nRow;
180 SCTAB nTab;
181 SCCOL nCol1;
182 SCROW nRow1;
183 SCTAB nTab1;
184 SCCOL nCol2;
185 SCROW nRow2;
186 SCTAB nTab2;
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 )
208 if ( pBASM )
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();
217 if (pTab[nTab])
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();
226 if (pTab[nTab])
227 pTab[nTab]->EndListening( rAddress, pListener );
231 void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
233 DBG_ASSERT( pCell, "PutInFormulaTree: pCell Null" );
234 RemoveFromFormulaTree( pCell );
235 // anhaengen
236 if ( pEOFormulaTree )
237 pEOFormulaTree->SetNext( pCell );
238 else
239 pFormulaTree = pCell; // kein Ende, kein Anfang..
240 pCell->SetPrevious( pEOFormulaTree );
241 pCell->SetNext( 0 );
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();
255 if ( pPrev )
256 pPrev->SetNext( pNext ); // gibt Vorlaeufer
257 else
258 pFormulaTree = pNext; // ist erste Zelle
259 if ( pNext )
260 pNext->SetPrevious( pPrev ); // gibt Nachfolger
261 else
262 pEOFormulaTree = pPrev; // ist letzte Zelle
263 pCell->SetPrevious( 0 );
264 pCell->SetNext( 0 );
265 USHORT nRPN = pCell->GetCode()->GetCodeLen();
266 if ( nFormulaCodeInTree >= nRPN )
267 nFormulaCodeInTree -= nRPN;
268 else
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() )
293 return ;
294 bCalculatingFormulaTree = TRUE;
296 SetForcedFormulaPending( FALSE );
297 BOOL bOldIdleDisabled = IsIdleDisabled();
298 DisableIdle( TRUE );
299 BOOL bOldAutoCalc = GetAutoCalc();
300 //! _nicht_ SetAutoCalc( TRUE ) weil das evtl. CalcFormulaTree( TRUE )
301 //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
302 bAutoCalc = TRUE;
303 if ( nHardRecalcState )
304 CalcAll();
305 else
307 ScFormulaCell* pCell = pFormulaTree;
308 while ( pCell )
310 if ( pCell->GetDirty() )
311 pCell = pCell->GetNext(); // alles klar
312 else
314 if ( pCell->GetCode()->IsRecalcModeAlways() )
316 // pCell wird im SetDirty neu angehaengt!
317 ScFormulaCell* pNext = pCell->GetNext();
318 pCell->SetDirty();
319 // falls pNext==0 und neue abhaengige hinten angehaengt
320 // wurden, so macht das nichts, da die alle bDirty sind
321 pCell = pNext;
323 else
324 { // andere simpel berechnen
325 pCell->SetDirtyVar();
326 pCell = pCell->GetNext();
330 BOOL bProgress = !bOnlyForced && nFormulaCodeInTree && !bNoProgress;
331 if ( bProgress )
332 ScProgress::CreateInterpretProgress( this, TRUE );
334 pCell = pFormulaTree;
335 ScFormulaCell* pLastNoGood = 0;
336 while ( pCell )
338 // Interpret setzt bDirty zurueck und callt Remove, auch der referierten!
339 // bei RECALCMODE_ALWAYS bleibt die Zelle
340 if ( bOnlyForced )
342 if ( pCell->GetCode()->IsRecalcModeForced() )
343 pCell->Interpret();
345 else
347 pCell->Interpret();
349 if ( pCell->GetPrevious() || pCell == pFormulaTree )
350 { // (IsInFormulaTree(pCell)) kein Remove gewesen => next
351 pLastNoGood = pCell;
352 pCell = pCell->GetNext();
354 else
356 if ( pFormulaTree )
358 if ( pFormulaTree->GetDirty() && !bOnlyForced )
360 pCell = pFormulaTree;
361 pLastNoGood = 0;
363 else
365 // IsInFormulaTree(pLastNoGood)
366 if ( pLastNoGood && (pLastNoGood->GetPrevious() ||
367 pLastNoGood == pFormulaTree) )
368 pCell = pLastNoGood->GetNext();
369 else
371 pCell = pFormulaTree;
372 while ( pCell && !pCell->GetDirty() )
373 pCell = pCell->GetNext();
374 if ( pCell )
375 pLastNoGood = pCell->GetPrevious();
379 else
380 pCell = 0;
382 if ( ScProgress::IsUserBreak() )
383 pCell = 0;
385 if ( bProgress )
386 ScProgress::DeleteInterpretProgress();
388 bAutoCalc = bOldAutoCalc;
389 DisableIdle( bOldIdleDisabled );
390 bCalculatingFormulaTree = FALSE;
394 void ScDocument::ClearFormulaTree()
396 ScFormulaCell* pCell;
397 ScFormulaCell* pTree = pFormulaTree;
398 while ( pTree )
400 pCell = pTree;
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 );
416 else
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();
433 if ( pPrev )
434 pPrev->SetNextTrack( pNext ); // gibt Vorlaeufer
435 else
436 pFormulaTrack = pNext; // ist erste Zelle
437 if ( pNext )
438 pNext->SetPreviousTrack( pPrev ); // gibt Nachfolger
439 else
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 )
463 if ( pFormulaTrack )
465 erBEEPER();
466 SvtBroadcaster* pBC;
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:
477 if ( pCondFormList )
478 pCondFormList->SourceChanged( pTrack->aPos );
479 pTrack = pTrack->GetNextTrack();
480 } while ( pTrack );
481 pTrack = pFormulaTrack;
482 BOOL bHaveForced = FALSE;
485 pNext = pTrack->GetNextTrack();
486 RemoveFromFormulaTrack( pTrack );
487 PutInFormulaTree( pTrack );
488 if ( pTrack->GetCode()->IsRecalcModeForced() )
489 bHaveForced = TRUE;
490 pTrack = pNext;
491 } while ( pTrack );
492 if ( bHaveForced )
494 SetForcedFormulas( TRUE );
495 if ( bAutoCalc && !IsAutoCalcShellDisabled() && !IsInInterpreter()
496 && !IsCalculatingFormulaTree() )
497 CalcFormulaTree( TRUE );
498 else
499 SetForcedFormulaPending( TRUE );
502 DBG_ASSERT( nFormulaTrackCount==0, "TrackFormulas: nFormulaTrackCount!=0" );
506 void ScDocument::StartAllListeners()
508 for ( SCTAB i = 0; i <= MAXTAB; ++i )
509 if ( pTab[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() );
520 if ( pBASM )
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.
547 maTabs.erase(iter);
549 uno::Reference< document::XVbaEventsHelper > xVbaEventsHelper ( GetVbaEventsHelper(), uno::UNO_QUERY );
550 if( xVbaEventsHelper.is() )
552 uno::Sequence< uno::Any > aArgs(1);
553 aArgs[0] <<= nTab;
554 bSuccess = xVbaEventsHelper->ProcessCompatibleVbaEvent( VBAEVENT_WORKSHEET_CALCULATE, aArgs );
557 return bSuccess;
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 );