summaryrefslogtreecommitdiff
path: root/sc/source/core/data/documen7.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/documen7.cxx')
-rw-r--r--sc/source/core/data/documen7.cxx528
1 files changed, 528 insertions, 0 deletions
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
new file mode 100644
index 000000000000..ad2ec90379df
--- /dev/null
+++ b/sc/source/core/data/documen7.cxx
@@ -0,0 +1,528 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <vcl/svapp.hxx>
+
+#if defined( WNT ) && defined( erBEEP )
+#include <svwin.h>
+#define erBEEPER() Beep( 666, 66 )
+#else
+#define erBEEPER()
+#endif
+
+#include "document.hxx"
+#include "brdcst.hxx"
+#include "bcaslot.hxx"
+#include "cell.hxx"
+#include "formula/errorcodes.hxx" // errCircularReference
+#include "scerrors.hxx"
+#include "docoptio.hxx"
+#include "refupdat.hxx"
+#include "table.hxx"
+#include "progress.hxx"
+#include "scmod.hxx" // SC_MOD
+#include "inputopt.hxx" // GetExpandRefs
+#include "conditio.hxx"
+#include <tools/shl.hxx>
+
+
+#include "globstr.hrc"
+
+extern const ScFormulaCell* pLastFormulaTreeTop; // cellform.cxx Err527 WorkAround
+
+// STATIC DATA -----------------------------------------------------------
+
+#ifdef erDEBUG
+ULONG erCountBCAInserts = 0;
+ULONG erCountBCAFinds = 0;
+#endif
+
+// -----------------------------------------------------------------------
+
+void ScDocument::StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener
+ )
+{
+ if ( pBASM )
+ pBASM->StartListeningArea( rRange, pListener );
+}
+
+
+void ScDocument::EndListeningArea( const ScRange& rRange,
+ SvtListener* pListener
+ )
+{
+ if ( pBASM )
+ pBASM->EndListeningArea( rRange, pListener );
+}
+
+
+void ScDocument::Broadcast( ULONG nHint, const ScAddress& rAddr,
+ ScBaseCell* pCell
+ )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ ScHint aHint( nHint, rAddr, pCell );
+ Broadcast( aHint );
+}
+
+
+void ScDocument::Broadcast( const ScHint& rHint )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ if ( !nHardRecalcState )
+ {
+ ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
+ BOOL bIsBroadcasted = FALSE;
+ ScBaseCell* pCell = rHint.GetCell();
+ if ( pCell )
+ {
+ SvtBroadcaster* pBC = pCell->GetBroadcaster();
+ if ( pBC )
+ {
+ pBC->Broadcast( rHint );
+ bIsBroadcasted = TRUE;
+ }
+ }
+ if ( pBASM->AreaBroadcast( rHint ) || bIsBroadcasted )
+ TrackFormulas( rHint.GetId() );
+ }
+
+ // Repaint fuer bedingte Formate mit relativen Referenzen:
+ if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
+ pCondFormList->SourceChanged( rHint.GetAddress() );
+
+ if ( rHint.GetAddress() != BCA_BRDCST_ALWAYS )
+ {
+ SCTAB nTab = rHint.GetAddress().Tab();
+ if (pTab[nTab] && pTab[nTab]->IsStreamValid())
+ pTab[nTab]->SetStreamValid(FALSE);
+ }
+}
+
+
+void ScDocument::AreaBroadcast( const ScHint& rHint )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ if ( !nHardRecalcState )
+ {
+ ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
+ if ( pBASM->AreaBroadcast( rHint ) )
+ TrackFormulas( rHint.GetId() );
+ }
+
+ // Repaint fuer bedingte Formate mit relativen Referenzen:
+ if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
+ pCondFormList->SourceChanged( rHint.GetAddress() );
+}
+
+
+void ScDocument::AreaBroadcastInRange( const ScRange& rRange, const ScHint& rHint )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ if ( !nHardRecalcState )
+ {
+ ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
+ if ( pBASM->AreaBroadcastInRange( rRange, rHint ) )
+ TrackFormulas( rHint.GetId() );
+ }
+
+ // Repaint for conditional formats containing relative references.
+ //! This is _THE_ bottle neck!
+ if ( pCondFormList )
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ ScAddress aAddress( rRange.aStart );
+ for ( nTab = nTab1; nTab <= nTab2; ++nTab )
+ {
+ aAddress.SetTab( nTab );
+ for ( nCol = nCol1; nCol <= nCol2; ++nCol )
+ {
+ aAddress.SetCol( nCol );
+ for ( nRow = nRow1; nRow <= nRow2; ++nRow )
+ {
+ aAddress.SetRow( nRow );
+ pCondFormList->SourceChanged( aAddress );
+ }
+ }
+ }
+ }
+}
+
+
+void ScDocument::DelBroadcastAreasInRange( const ScRange& rRange )
+{
+ if ( pBASM )
+ pBASM->DelBroadcastAreasInRange( rRange );
+}
+
+void ScDocument::StartListeningCell( const ScAddress& rAddress,
+ SvtListener* pListener )
+{
+ DBG_ASSERT(pListener, "StartListeningCell: pListener Null");
+ SCTAB nTab = rAddress.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->StartListening( rAddress, pListener );
+}
+
+void ScDocument::EndListeningCell( const ScAddress& rAddress,
+ SvtListener* pListener )
+{
+ DBG_ASSERT(pListener, "EndListeningCell: pListener Null");
+ SCTAB nTab = rAddress.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->EndListening( rAddress, pListener );
+}
+
+
+void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "PutInFormulaTree: pCell Null" );
+ RemoveFromFormulaTree( pCell );
+ // anhaengen
+ if ( pEOFormulaTree )
+ pEOFormulaTree->SetNext( pCell );
+ else
+ pFormulaTree = pCell; // kein Ende, kein Anfang..
+ pCell->SetPrevious( pEOFormulaTree );
+ pCell->SetNext( 0 );
+ pEOFormulaTree = pCell;
+ nFormulaCodeInTree += pCell->GetCode()->GetCodeLen();
+}
+
+
+void ScDocument::RemoveFromFormulaTree( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "RemoveFromFormulaTree: pCell Null" );
+ ScFormulaCell* pPrev = pCell->GetPrevious();
+ // wenn die Zelle die erste oder sonstwo ist
+ if ( pPrev || pFormulaTree == pCell )
+ {
+ ScFormulaCell* pNext = pCell->GetNext();
+ if ( pPrev )
+ pPrev->SetNext( pNext ); // gibt Vorlaeufer
+ else
+ pFormulaTree = pNext; // ist erste Zelle
+ if ( pNext )
+ pNext->SetPrevious( pPrev ); // gibt Nachfolger
+ else
+ pEOFormulaTree = pPrev; // ist letzte Zelle
+ pCell->SetPrevious( 0 );
+ pCell->SetNext( 0 );
+ USHORT nRPN = pCell->GetCode()->GetCodeLen();
+ if ( nFormulaCodeInTree >= nRPN )
+ nFormulaCodeInTree -= nRPN;
+ else
+ {
+ DBG_ERRORFILE( "RemoveFromFormulaTree: nFormulaCodeInTree < nRPN" );
+ nFormulaCodeInTree = 0;
+ }
+ }
+ else if ( !pFormulaTree && nFormulaCodeInTree )
+ {
+ DBG_ERRORFILE( "!pFormulaTree && nFormulaCodeInTree != 0" );
+ nFormulaCodeInTree = 0;
+ }
+}
+
+
+BOOL ScDocument::IsInFormulaTree( ScFormulaCell* pCell ) const
+{
+ return pCell->GetPrevious() || pFormulaTree == pCell;
+}
+
+
+void ScDocument::CalcFormulaTree( BOOL bOnlyForced, BOOL bNoProgress )
+{
+ DBG_ASSERT( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
+ // never ever recurse into this, might end up lost in infinity
+ if ( IsCalculatingFormulaTree() )
+ return ;
+ bCalculatingFormulaTree = TRUE;
+
+ SetForcedFormulaPending( FALSE );
+ BOOL bOldIdleDisabled = IsIdleDisabled();
+ DisableIdle( TRUE );
+ BOOL bOldAutoCalc = GetAutoCalc();
+ //! _nicht_ SetAutoCalc( TRUE ) weil das evtl. CalcFormulaTree( TRUE )
+ //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
+ bAutoCalc = TRUE;
+ if ( nHardRecalcState )
+ CalcAll();
+ else
+ {
+ ScFormulaCell* pCell = pFormulaTree;
+ while ( pCell )
+ {
+ if ( pCell->GetDirty() )
+ pCell = pCell->GetNext(); // alles klar
+ else
+ {
+ if ( pCell->GetCode()->IsRecalcModeAlways() )
+ {
+ // pCell wird im SetDirty neu angehaengt!
+ ScFormulaCell* pNext = pCell->GetNext();
+ pCell->SetDirty();
+ // falls pNext==0 und neue abhaengige hinten angehaengt
+ // wurden, so macht das nichts, da die alle bDirty sind
+ pCell = pNext;
+ }
+ else
+ { // andere simpel berechnen
+ pCell->SetDirtyVar();
+ pCell = pCell->GetNext();
+ }
+ }
+ }
+ BOOL bProgress = !bOnlyForced && nFormulaCodeInTree && !bNoProgress;
+ if ( bProgress )
+ ScProgress::CreateInterpretProgress( this, TRUE );
+
+ pCell = pFormulaTree;
+ ScFormulaCell* pLastNoGood = 0;
+ while ( pCell )
+ {
+ // Interpret setzt bDirty zurueck und callt Remove, auch der referierten!
+ // bei RECALCMODE_ALWAYS bleibt die Zelle
+ if ( bOnlyForced )
+ {
+ if ( pCell->GetCode()->IsRecalcModeForced() )
+ pCell->Interpret();
+ }
+ else
+ {
+ pCell->Interpret();
+ }
+ if ( pCell->GetPrevious() || pCell == pFormulaTree )
+ { // (IsInFormulaTree(pCell)) kein Remove gewesen => next
+ pLastNoGood = pCell;
+ pCell = pCell->GetNext();
+ }
+ else
+ {
+ if ( pFormulaTree )
+ {
+ if ( pFormulaTree->GetDirty() && !bOnlyForced )
+ {
+ pCell = pFormulaTree;
+ pLastNoGood = 0;
+ }
+ else
+ {
+ // IsInFormulaTree(pLastNoGood)
+ if ( pLastNoGood && (pLastNoGood->GetPrevious() ||
+ pLastNoGood == pFormulaTree) )
+ pCell = pLastNoGood->GetNext();
+ else
+ {
+ pCell = pFormulaTree;
+ while ( pCell && !pCell->GetDirty() )
+ pCell = pCell->GetNext();
+ if ( pCell )
+ pLastNoGood = pCell->GetPrevious();
+ }
+ }
+ }
+ else
+ pCell = 0;
+ }
+ if ( ScProgress::IsUserBreak() )
+ pCell = 0;
+ }
+ if ( bProgress )
+ ScProgress::DeleteInterpretProgress();
+ }
+ bAutoCalc = bOldAutoCalc;
+ DisableIdle( bOldIdleDisabled );
+ bCalculatingFormulaTree = FALSE;
+}
+
+
+void ScDocument::ClearFormulaTree()
+{
+ ScFormulaCell* pCell;
+ ScFormulaCell* pTree = pFormulaTree;
+ while ( pTree )
+ {
+ pCell = pTree;
+ pTree = pCell->GetNext();
+ if ( !pCell->GetCode()->IsRecalcModeAlways() )
+ RemoveFromFormulaTree( pCell );
+ }
+}
+
+
+void ScDocument::AppendToFormulaTrack( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "AppendToFormulaTrack: pCell Null" );
+ // Zelle kann nicht in beiden Listen gleichzeitig sein
+ RemoveFromFormulaTrack( pCell );
+ RemoveFromFormulaTree( pCell );
+ if ( pEOFormulaTrack )
+ pEOFormulaTrack->SetNextTrack( pCell );
+ else
+ pFormulaTrack = pCell; // kein Ende, kein Anfang..
+ pCell->SetPreviousTrack( pEOFormulaTrack );
+ pCell->SetNextTrack( 0 );
+ pEOFormulaTrack = pCell;
+ ++nFormulaTrackCount;
+}
+
+
+void ScDocument::RemoveFromFormulaTrack( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "RemoveFromFormulaTrack: pCell Null" );
+ ScFormulaCell* pPrev = pCell->GetPreviousTrack();
+ // wenn die Zelle die erste oder sonstwo ist
+ if ( pPrev || pFormulaTrack == pCell )
+ {
+ ScFormulaCell* pNext = pCell->GetNextTrack();
+ if ( pPrev )
+ pPrev->SetNextTrack( pNext ); // gibt Vorlaeufer
+ else
+ pFormulaTrack = pNext; // ist erste Zelle
+ if ( pNext )
+ pNext->SetPreviousTrack( pPrev ); // gibt Nachfolger
+ else
+ pEOFormulaTrack = pPrev; // ist letzte Zelle
+ pCell->SetPreviousTrack( 0 );
+ pCell->SetNextTrack( 0 );
+ --nFormulaTrackCount;
+ }
+}
+
+
+BOOL ScDocument::IsInFormulaTrack( ScFormulaCell* pCell ) const
+{
+ return pCell->GetPreviousTrack() || pFormulaTrack == pCell;
+}
+
+
+/*
+ Der erste wird gebroadcastet,
+ die dadurch entstehenden werden durch das Notify an den Track gehaengt.
+ Der nachfolgende broadcastet wieder usw.
+ View stoesst Interpret an.
+ */
+void ScDocument::TrackFormulas( ULONG nHintId )
+{
+
+ if ( pFormulaTrack )
+ {
+ erBEEPER();
+ SvtBroadcaster* pBC;
+ ScFormulaCell* pTrack;
+ ScFormulaCell* pNext;
+ pTrack = pFormulaTrack;
+ do
+ {
+ ScHint aHint( nHintId, pTrack->aPos, pTrack );
+ if ( ( pBC = pTrack->GetBroadcaster() ) != NULL )
+ pBC->Broadcast( aHint );
+ pBASM->AreaBroadcast( aHint );
+ // Repaint fuer bedingte Formate mit relativen Referenzen:
+ if ( pCondFormList )
+ pCondFormList->SourceChanged( pTrack->aPos );
+ pTrack = pTrack->GetNextTrack();
+ } while ( pTrack );
+ pTrack = pFormulaTrack;
+ BOOL bHaveForced = FALSE;
+ do
+ {
+ pNext = pTrack->GetNextTrack();
+ RemoveFromFormulaTrack( pTrack );
+ PutInFormulaTree( pTrack );
+ if ( pTrack->GetCode()->IsRecalcModeForced() )
+ bHaveForced = TRUE;
+ pTrack = pNext;
+ } while ( pTrack );
+ if ( bHaveForced )
+ {
+ SetForcedFormulas( TRUE );
+ if ( bAutoCalc && !IsAutoCalcShellDisabled() && !IsInInterpreter()
+ && !IsCalculatingFormulaTree() )
+ CalcFormulaTree( TRUE );
+ else
+ SetForcedFormulaPending( TRUE );
+ }
+ }
+ DBG_ASSERT( nFormulaTrackCount==0, "TrackFormulas: nFormulaTrackCount!=0" );
+}
+
+
+void ScDocument::StartAllListeners()
+{
+ for ( SCTAB i = 0; i <= MAXTAB; ++i )
+ if ( pTab[i] )
+ pTab[i]->StartAllListeners();
+}
+
+void ScDocument::UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
+ )
+{
+ BOOL bExpandRefsOld = IsExpandRefs();
+ if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
+ SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
+ if ( pBASM )
+ pBASM->UpdateBroadcastAreas( eUpdateRefMode, rRange, nDx, nDy, nDz );
+ SetExpandRefs( bExpandRefsOld );
+}
+
+void ScDocument::SetAutoCalc( BOOL bNewAutoCalc )
+{
+ BOOL bOld = bAutoCalc;
+ bAutoCalc = bNewAutoCalc;
+ if ( !bOld && bNewAutoCalc && bHasForcedFormulas )
+ {
+ if ( IsAutoCalcShellDisabled() )
+ SetForcedFormulaPending( TRUE );
+ else if ( !IsInInterpreter() )
+ CalcFormulaTree( TRUE );
+ }
+}
+
+
+