summaryrefslogtreecommitdiff
path: root/sc/source/core/data/cell.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/cell.cxx')
-rw-r--r--sc/source/core/data/cell.cxx1459
1 files changed, 1 insertions, 1458 deletions
diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx
index 66032a8471d8..aa6e2a215ba1 100644
--- a/sc/source/core/data/cell.cxx
+++ b/sc/source/core/data/cell.cxx
@@ -19,45 +19,15 @@
#include "cell.hxx"
-#include "scitems.hxx"
-#include "attrib.hxx"
-#include "compiler.hxx"
-#include "interpre.hxx"
#include "document.hxx"
-#include "docoptio.hxx"
-#include "rechead.hxx"
-#include "rangenam.hxx"
-#include "brdcst.hxx"
-#include "ddelink.hxx"
-#include "validat.hxx"
-#include "progress.hxx"
-#include "editutil.hxx"
-#include "recursionhelper.hxx"
-#include "externalrefmgr.hxx"
-#include "macromgr.hxx"
-#include "dbdata.hxx"
-#include "globalnames.hxx"
-#include "cellvalue.hxx"
+#include "formulacell.hxx"
-#include <svl/intitem.hxx>
#include <svl/broadcast.hxx>
-#include <svl/zforlist.hxx>
-
-using namespace formula;
-// More or less arbitrary, of course all recursions must fit into available
-// stack space (which is what on all systems we don't know yet?). Choosing a
-// lower value may be better than trying a much higher value that also isn't
-// sufficient but temporarily leads to high memory consumption. On the other
-// hand, if the value fits all recursions, execution is quicker as no resumes
-// are necessary. Could be made a configurable option.
-// Allow for a year's calendar (366).
-const sal_uInt16 MAXRECURSION = 400;
// STATIC DATA -----------------------------------------------------------
#ifdef USE_MEMPOOL
IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell )
-IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell )
IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell )
#endif
@@ -104,108 +74,6 @@ ScBaseCell* lclCloneCell( const ScBaseCell& rSrcCell, ScDocument& rDestDoc, cons
return 0;
}
-void adjustRangeName(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& aNewPos, const ScAddress& aOldPos)
-{
- bool bOldGlobal = pToken->IsGlobal();
- SCTAB aOldTab = aOldPos.Tab();
- rtl::OUString aRangeName;
- int nOldIndex = pToken->GetIndex();
- ScRangeData* pOldRangeData = NULL;
-
- //search the name of the RangeName
- if (!bOldGlobal)
- {
- pOldRangeData = pOldDoc->GetRangeName(aOldTab)->findByIndex(nOldIndex);
- if (!pOldRangeData)
- return; //might be an error in the formula array
- aRangeName = pOldRangeData->GetUpperName();
- }
- else
- {
- pOldRangeData = pOldDoc->GetRangeName()->findByIndex(nOldIndex);
- if (!pOldRangeData)
- return; //might be an error in the formula array
- aRangeName = pOldRangeData->GetUpperName();
- }
-
- //find corresponding range name in new document
- //first search for local range name then global range names
- SCTAB aNewTab = aNewPos.Tab();
- ScRangeName* pRangeName = rNewDoc.GetRangeName(aNewTab);
- ScRangeData* pRangeData = NULL;
- bool bNewGlobal = false;
- //search local range names
- if (pRangeName)
- {
- pRangeData = pRangeName->findByUpperName(aRangeName);
- }
- //search global range names
- if (!pRangeData)
- {
- bNewGlobal = true;
- pRangeName = rNewDoc.GetRangeName();
- if (pRangeName)
- pRangeData = pRangeName->findByUpperName(aRangeName);
- }
- //if no range name was found copy it
- if (!pRangeData)
- {
- bNewGlobal = bOldGlobal;
- pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc);
- ScTokenArray* pRangeNameToken = pRangeData->GetCode();
- if (rNewDoc.GetPool() != const_cast<ScDocument*>(pOldDoc)->GetPool())
- {
- pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(), true);
- pRangeNameToken->AdjustAbsoluteRefs(pOldDoc, aOldPos, aNewPos, false, true);
- }
-
- bool bInserted;
- if (bNewGlobal)
- bInserted = rNewDoc.GetRangeName()->insert(pRangeData);
- else
- bInserted = rNewDoc.GetRangeName(aNewTab)->insert(pRangeData);
- if (!bInserted)
- {
- //if this happened we have a real problem
- pRangeData = NULL;
- pToken->SetIndex(0);
- OSL_FAIL("inserting the range name should not fail");
- return;
- }
- }
- sal_Int32 nIndex = pRangeData->GetIndex();
- pToken->SetIndex(nIndex);
- pToken->SetGlobal(bNewGlobal);
-}
-
-void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc)
-{
- ScDBCollection* pOldDBCollection = pOldDoc->GetDBCollection();
- if (!pOldDBCollection)
- return;//strange error case, don't do anything
- ScDBCollection::NamedDBs& aOldNamedDBs = pOldDBCollection->getNamedDBs();
- ScDBData* pDBData = aOldNamedDBs.findByIndex(pToken->GetIndex());
- if (!pDBData)
- return; //invalid index
- rtl::OUString aDBName = pDBData->GetUpperName();
-
- //search in new document
- ScDBCollection* pNewDBCollection = rNewDoc.GetDBCollection();
- if (!pNewDBCollection)
- {
- pNewDBCollection = new ScDBCollection(&rNewDoc);
- rNewDoc.SetDBCollection(pNewDBCollection);
- }
- ScDBCollection::NamedDBs& aNewNamedDBs = pNewDBCollection->getNamedDBs();
- ScDBData* pNewDBData = aNewNamedDBs.findByUpperName(aDBName);
- if (!pNewDBData)
- {
- pNewDBData = new ScDBData(*pDBData);
- aNewNamedDBs.insert(pNewDBData);
- }
- pToken->SetIndex(pNewDBData->GetIndex());
-}
-
} // namespace
ScBaseCell* ScBaseCell::Clone( ScDocument& rDestDoc, int nCloneFlags ) const
@@ -388,1329 +256,4 @@ ScStringCell::~ScStringCell()
}
#endif
-// ============================================================================
-
-//
-// ScFormulaCell
-//
-
-ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
- const rtl::OUString& rFormula,
- const FormulaGrammar::Grammar eGrammar,
- sal_uInt8 cMatInd ) :
- ScBaseCell( CELLTYPE_FORMULA ),
- eTempGrammar( eGrammar),
- pCode( NULL ),
- pDocument( pDoc ),
- pPrevious(0),
- pNext(0),
- pPreviousTrack(0),
- pNextTrack(0),
- nFormatIndex(0),
- nFormatType( NUMBERFORMAT_NUMBER ),
- nSeenInIteration(0),
- cMatrixFlag ( cMatInd ),
- bDirty( true ), // -> Because of the use of the Auto Pilot Function was: cMatInd != 0
- bChanged( false ),
- bRunning( false ),
- bCompile( false ),
- bSubTotal( false ),
- bIsIterCell( false ),
- bInChangeTrack( false ),
- bTableOpDirty( false ),
- bNeedListening( false ),
- aPos( rPos )
-{
- Compile( rFormula, true, eGrammar ); // bNoListening, Insert does that
- if (!pCode)
- // We need to have a non-NULL token array instance at all times.
- pCode = new ScTokenArray;
-}
-
-// Used by import filters
-
-ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
- const ScTokenArray* pArr,
- const FormulaGrammar::Grammar eGrammar, sal_uInt8 cInd ) :
- ScBaseCell( CELLTYPE_FORMULA ),
- eTempGrammar( eGrammar),
- pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ),
- pDocument( pDoc ),
- pPrevious(0),
- pNext(0),
- pPreviousTrack(0),
- pNextTrack(0),
- nFormatIndex(0),
- nFormatType( NUMBERFORMAT_NUMBER ),
- nSeenInIteration(0),
- cMatrixFlag ( cInd ),
- bDirty( NULL != pArr ), // -> Because of the use of the Auto Pilot Function was: cInd != 0
- bChanged( false ),
- bRunning( false ),
- bCompile( false ),
- bSubTotal( false ),
- bIsIterCell( false ),
- bInChangeTrack( false ),
- bTableOpDirty( false ),
- bNeedListening( false ),
- aPos( rPos )
-{
- // UPN-Array generation
- if( pCode->GetLen() && !pCode->GetCodeError() && !pCode->GetCodeLen() )
- {
- ScCompiler aComp( pDocument, aPos, *pCode);
- aComp.SetGrammar(eTempGrammar);
- bSubTotal = aComp.CompileTokenArray();
- nFormatType = aComp.GetNumFormatType();
- }
- else
- {
- pCode->Reset();
- if ( pCode->GetNextOpCodeRPN( ocSubTotal ) )
- bSubTotal = true;
- }
-
- if (bSubTotal)
- pDocument->AddSubTotalCell(this);
-}
-
-ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) :
- ScBaseCell( rCell ),
- SvtListener(),
- aResult( rCell.aResult ),
- eTempGrammar( rCell.eTempGrammar),
- pDocument( &rDoc ),
- pPrevious(0),
- pNext(0),
- pPreviousTrack(0),
- pNextTrack(0),
- nFormatIndex( &rDoc == rCell.pDocument ? rCell.nFormatIndex : 0 ),
- nFormatType( rCell.nFormatType ),
- nSeenInIteration(0),
- cMatrixFlag ( rCell.cMatrixFlag ),
- bDirty( rCell.bDirty ),
- bChanged( rCell.bChanged ),
- bRunning( false ),
- bCompile( rCell.bCompile ),
- bSubTotal( rCell.bSubTotal ),
- bIsIterCell( false ),
- bInChangeTrack( false ),
- bTableOpDirty( false ),
- bNeedListening( false ),
- aPos( rPos )
-{
- pCode = rCell.pCode->Clone();
-
- // set back any errors and recompile
- // not in the Clipboard - it must keep the received error flag
- // Special Length=0: as bad cells are generated, then they are also retained
- if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() )
- {
- pCode->SetCodeError( 0 );
- bCompile = true;
- }
- //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
- bool bCompileLater = false;
- bool bClipMode = rCell.pDocument->IsClipboard();
-
- //update ScNameTokens
- if (!pDocument->IsClipOrUndo() || rDoc.IsUndo())
- {
- if (!pDocument->IsClipboardSource() || aPos.Tab() != rCell.aPos.Tab())
- {
- ScToken* pToken = NULL;
- while((pToken = static_cast<ScToken*>(pCode->GetNextName()))!= NULL)
- {
- OpCode eOpCode = pToken->GetOpCode();
- if (eOpCode == ocName)
- adjustRangeName(pToken, rDoc, rCell.pDocument, aPos, rCell.aPos);
- else if (eOpCode == ocDBArea)
- adjustDBRange(pToken, rDoc, rCell.pDocument);
- }
- }
-
- bool bCopyBetweenDocs = pDocument->GetPool() != rCell.pDocument->GetPool();
- if (bCopyBetweenDocs && !(nCloneFlags & SC_CLONECELL_NOMAKEABS_EXTERNAL))
- {
- pCode->ReadjustAbsolute3DReferences( rCell.pDocument, &rDoc, rCell.aPos);
- }
-
- pCode->AdjustAbsoluteRefs( rCell.pDocument, rCell.aPos, aPos, false, bCopyBetweenDocs );
- }
-
- if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL )
- pCode->ReadjustRelative3DReferences( rCell.aPos, aPos );
-
- if( !bCompile )
- { // Name references with references and ColRowNames
- pCode->Reset();
- ScToken* t;
- while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
- {
- if ( t->IsExternalRef() )
- {
- // External name, cell, and area references.
- bCompile = true;
- }
- else if ( t->GetType() == svIndex )
- {
- ScRangeData* pRangeData = rDoc.GetRangeName()->findByIndex( t->GetIndex() );
- if( pRangeData )
- {
- if( pRangeData->HasReferences() )
- bCompile = true;
- }
- else
- bCompile = true; // invalid reference!
- }
- else if ( t->GetOpCode() == ocColRowName )
- {
- bCompile = true; // new lookup needed
- bCompileLater = bClipMode;
- }
- }
- }
- if( bCompile )
- {
- if ( !bCompileLater && bClipMode )
- {
- // Merging ranges needs the actual positions after UpdateReference.
- // ColRowNames need new lookup after positions are adjusted.
- bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName);
- }
- if ( !bCompileLater )
- {
- // bNoListening, not at all if in Clipboard/Undo,
- // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
- CompileTokenArray( true );
- }
- }
-
- if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
- StartListeningTo( &rDoc );
-
- if (bSubTotal)
- pDocument->AddSubTotalCell(this);
-}
-
-ScFormulaCell::~ScFormulaCell()
-{
- pDocument->RemoveFromFormulaTree( this );
- pDocument->RemoveSubTotalCell(this);
- if (pCode->HasOpCode(ocMacro))
- pDocument->GetMacroManager()->RemoveDependentCell(this);
-
- if (pDocument->HasExternalRefManager())
- pDocument->GetExternalRefManager()->removeRefCell(this);
-
- delete pCode;
-#if OSL_DEBUG_LEVEL > 0
- eCellType = CELLTYPE_DESTROYED;
-#endif
-}
-
-ScFormulaCell* ScFormulaCell::Clone() const
-{
- return new ScFormulaCell(*this, *pDocument, aPos);
-}
-
-size_t ScFormulaCell::GetHash() const
-{
- return pCode->GetHash();
-}
-
-ScFormulaVectorState ScFormulaCell::GetVectorState() const
-{
- return pCode->GetVectorState();
-}
-
-void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer,
- const FormulaGrammar::Grammar eGrammar ) const
-{
- if( pCode->GetCodeError() && !pCode->GetLen() )
- {
- rBuffer = rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError()));
- return;
- }
- else if( cMatrixFlag == MM_REFERENCE )
- {
- // Reference to another cell that contains a matrix formula.
- pCode->Reset();
- ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
- if( p )
- {
- /* FIXME: original GetFormula() code obtained
- * pCell only if (!this->IsInChangeTrack()),
- * GetEnglishFormula() omitted that test.
- * Can we live without in all cases? */
- ScFormulaCell* pCell = NULL;
- ScSingleRefData& rRef = p->GetSingleRef();
- rRef.CalcAbsIfRel( aPos );
- if ( rRef.Valid() )
- pCell = pDocument->GetFormulaCell(
- ScAddress(rRef.nCol, rRef.nRow, rRef.nTab));
-
- if (pCell)
- {
- pCell->GetFormula( rBuffer, eGrammar);
- return;
- }
- else
- {
- ScCompiler aComp( pDocument, aPos, *pCode);
- aComp.SetGrammar(eGrammar);
- aComp.CreateStringFromTokenArray( rBuffer );
- }
- }
- else
- {
- OSL_FAIL("ScFormulaCell::GetFormula: not a matrix");
- }
- }
- else
- {
- ScCompiler aComp( pDocument, aPos, *pCode);
- aComp.SetGrammar(eGrammar);
- aComp.CreateStringFromTokenArray( rBuffer );
- }
-
- sal_Unicode ch('=');
- rBuffer.insert( 0, &ch, 1 );
- if( cMatrixFlag )
- {
- sal_Unicode ch2('{');
- rBuffer.insert( 0, &ch2, 1);
- rBuffer.append( sal_Unicode('}'));
- }
-}
-
-void ScFormulaCell::GetFormula( rtl::OUString& rFormula, const FormulaGrammar::Grammar eGrammar ) const
-{
- rtl::OUStringBuffer rBuffer( rFormula );
- GetFormula( rBuffer, eGrammar );
- rFormula = rBuffer.makeStringAndClear();
-}
-
-void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
-{
- MaybeInterpret();
-
- const ScMatrix* pMat = NULL;
- if (!pCode->GetCodeError() && aResult.GetType() == svMatrixCell &&
- ((pMat = static_cast<const ScToken*>(aResult.GetToken().get())->GetMatrix()) != 0))
- pMat->GetDimensions( rCols, rRows );
- else
- {
- rCols = 0;
- rRows = 0;
- }
-}
-
-void ScFormulaCell::Compile( const rtl::OUString& rFormula, bool bNoListening,
- const FormulaGrammar::Grammar eGrammar )
-{
- if ( pDocument->IsClipOrUndo() )
- return;
- bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
- if ( bWasInFormulaTree )
- pDocument->RemoveFromFormulaTree( this );
- // pCode may not deleted for queries, but must be empty
- if ( pCode )
- pCode->Clear();
- ScTokenArray* pCodeOld = pCode;
- ScCompiler aComp( pDocument, aPos);
- aComp.SetGrammar(eGrammar);
- pCode = aComp.CompileString( rFormula );
- if ( pCodeOld )
- delete pCodeOld;
- if( !pCode->GetCodeError() )
- {
- if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() && rFormula == aResult.GetHybridFormula() )
- { // not recursive CompileTokenArray/Compile/CompileTokenArray
- if ( rFormula[0] == '=' )
- pCode->AddBad( rFormula.copy(1) );
- else
- pCode->AddBad( rFormula );
- }
- bCompile = true;
- CompileTokenArray( bNoListening );
- }
- else
- {
- bChanged = true;
- pDocument->SetTextWidth(aPos, TEXTWIDTH_DIRTY);
- pDocument->SetScriptType(aPos, SC_SCRIPTTYPE_UNKNOWN);
- }
- if ( bWasInFormulaTree )
- pDocument->PutInFormulaTree( this );
-}
-
-
-void ScFormulaCell::CompileTokenArray( bool bNoListening )
-{
- // Not already compiled?
- if( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
- Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar);
- else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() )
- {
- // RPN length may get changed
- bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
- if ( bWasInFormulaTree )
- pDocument->RemoveFromFormulaTree( this );
-
- // Loading from within filter? No listening yet!
- if( pDocument->IsInsertingFromOtherDoc() )
- bNoListening = true;
-
- if( !bNoListening && pCode->GetCodeLen() )
- EndListeningTo( pDocument );
- ScCompiler aComp(pDocument, aPos, *pCode);
- aComp.SetGrammar(pDocument->GetGrammar());
- bSubTotal = aComp.CompileTokenArray();
- if( !pCode->GetCodeError() )
- {
- nFormatType = aComp.GetNumFormatType();
- nFormatIndex = 0;
- bChanged = true;
- aResult.SetToken( NULL);
- bCompile = false;
- if ( !bNoListening )
- StartListeningTo( pDocument );
- }
- if ( bWasInFormulaTree )
- pDocument->PutInFormulaTree( this );
-
- if (bSubTotal)
- pDocument->AddSubTotalCell(this);
- }
-}
-
-
-void ScFormulaCell::CompileXML( ScProgress& rProgress )
-{
- if ( cMatrixFlag == MM_REFERENCE )
- { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula
- // just establish listeners
- StartListeningTo( pDocument );
- return ;
- }
-
- ScCompiler aComp( pDocument, aPos, *pCode);
- aComp.SetGrammar(eTempGrammar);
- rtl::OUString aFormula, aFormulaNmsp;
- aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp );
- pDocument->DecXMLImportedFormulaCount( aFormula.getLength() );
- rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() );
- // pCode may not deleted for queries, but must be empty
- if ( pCode )
- pCode->Clear();
- ScTokenArray* pCodeOld = pCode;
- pCode = aComp.CompileString( aFormula, aFormulaNmsp );
- delete pCodeOld;
- if( !pCode->GetCodeError() )
- {
- if ( !pCode->GetLen() )
- {
- if ( aFormula[0] == '=' )
- pCode->AddBad( aFormula.copy( 1 ) );
- else
- pCode->AddBad( aFormula );
- }
- bSubTotal = aComp.CompileTokenArray();
- if( !pCode->GetCodeError() )
- {
- nFormatType = aComp.GetNumFormatType();
- nFormatIndex = 0;
- bChanged = true;
- bCompile = false;
- StartListeningTo( pDocument );
- }
-
- if (bSubTotal)
- pDocument->AddSubTotalCell(this);
- }
- else
- {
- bChanged = true;
- pDocument->SetTextWidth(aPos, TEXTWIDTH_DIRTY);
- pDocument->SetScriptType(aPos, SC_SCRIPTTYPE_UNKNOWN);
- }
-
- // Same as in Load: after loading, it must be known if ocMacro is in any formula
- // (for macro warning, CompileXML is called at the end of loading XML file)
- if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) )
- pDocument->SetHasMacroFunc( true );
-
- //volatile cells must be added here for import
- if( pCode->IsRecalcModeAlways() || pCode->IsRecalcModeForced() ||
- pCode->IsRecalcModeOnLoad() || pCode->IsRecalcModeOnLoadOnce() )
- {
- // During load, only those cells that are marked explicitly dirty get
- // recalculated. So we need to set it dirty here.
- SetDirtyVar();
- pDocument->PutInFormulaTree(this);
- }
-}
-
-
-void ScFormulaCell::CalcAfterLoad()
-{
- bool bNewCompiled = false;
- // If a Calc 1.0-doc is read, we have a result, but no token array
- if( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
- {
- Compile( aResult.GetHybridFormula(), true, eTempGrammar);
- aResult.SetToken( NULL);
- bDirty = true;
- bNewCompiled = true;
- }
- // The UPN array is not created when a Calc 3.0-Doc has been read as the Range Names exist until now.
- if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() )
- {
- ScCompiler aComp(pDocument, aPos, *pCode);
- aComp.SetGrammar(pDocument->GetGrammar());
- bSubTotal = aComp.CompileTokenArray();
- nFormatType = aComp.GetNumFormatType();
- nFormatIndex = 0;
- bDirty = true;
- bCompile = false;
- bNewCompiled = true;
-
- if (bSubTotal)
- pDocument->AddSubTotalCell(this);
- }
-
- // On OS/2 with broken FPU exception, we can somehow store /0 without Err503. Later on in
- // the BLC Lib NumberFormatter crashes when doing a fabs (NAN) (# 32739 #).
- // We iron this out here for all systems, such that we also have an Err503 here.
- if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
- {
- OSL_FAIL("Formula cell INFINITY!!! Where does this document come from?");
- aResult.SetResultError( errIllegalFPOperation );
- bDirty = true;
- }
-
- // DoubleRefs for binary operators were always a Matrix before version v5.0.
- // Now this is only the case when when in an array formula, otherwise it's an implicit intersection
- if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF &&
- GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() )
- {
- cMatrixFlag = MM_FORMULA;
- SetMatColsRows( 1, 1);
- }
-
- // Do the cells need to be calculated? After Load cells can contain an error code, and then start
- // the listener and Recalculate (if needed) if not RECALCMODE_NORMAL
- if( !bNewCompiled || !pCode->GetCodeError() )
- {
- StartListeningTo( pDocument );
- if( !pCode->IsRecalcModeNormal() )
- bDirty = true;
- }
- if ( pCode->IsRecalcModeAlways() )
- { // random(), today(), now() always stay in the FormulaTree, so that they are calculated
- // for each F9
- bDirty = true;
- }
- // No SetDirty yet, as no all Listeners are known yet (only in SetDirtyAfterLoad)
-}
-
-
-bool ScFormulaCell::MarkUsedExternalReferences()
-{
- return pCode && pDocument->MarkUsedExternalReferences( *pCode);
-}
-
-
-void ScFormulaCell::Interpret()
-{
- if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn())
- return; // no double/triple processing
-
- //! HACK:
- // If the call originates from a Reschedule in DdeLink update, leave dirty
- // Better: Do a Dde Link Update without Reschedule or do it completely asynchronously!
- if ( pDocument->IsInDdeLinkUpdate() )
- return;
-
- if (bRunning)
- {
- if (!pDocument->GetDocOptions().IsIter())
- {
- aResult.SetResultError( errCircularReference );
- return;
- }
-
- if (aResult.GetResultError() == errCircularReference)
- aResult.SetResultError( 0 );
-
- // Start or add to iteration list.
- if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
- !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell)
- pDocument->GetRecursionHelper().SetInIterationReturn( true);
-
- return;
- }
- // no multiple interprets for GetErrCode, IsValue, GetValue and
- // different entry point recursions. Would also lead to premature
- // convergence in iterations.
- if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration ==
- pDocument->GetRecursionHelper().GetIteration())
- return ;
-
- ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
- bool bOldRunning = bRunning;
- if (rRecursionHelper.GetRecursionCount() > MAXRECURSION)
- {
- bRunning = true;
- rRecursionHelper.SetInRecursionReturn( true);
- }
- else
- {
- if ( ! InterpretFormulaGroup() )
- InterpretTail( SCITP_NORMAL);
- }
-
- // While leaving a recursion or iteration stack, insert its cells to the
- // recursion list in reverse order.
- if (rRecursionHelper.IsInReturn())
- {
- if (rRecursionHelper.GetRecursionCount() > 0 ||
- !rRecursionHelper.IsDoingRecursion())
- rRecursionHelper.Insert( this, bOldRunning, aResult);
- bool bIterationFromRecursion = false;
- bool bResumeIteration = false;
- do
- {
- if ((rRecursionHelper.IsInIterationReturn() &&
- rRecursionHelper.GetRecursionCount() == 0 &&
- !rRecursionHelper.IsDoingIteration()) ||
- bIterationFromRecursion || bResumeIteration)
- {
- ScFormulaCell* pIterCell = this; // scope for debug convenience
- bool & rDone = rRecursionHelper.GetConvergingReference();
- rDone = false;
- if (!bIterationFromRecursion && bResumeIteration)
- {
- bResumeIteration = false;
- // Resuming iteration expands the range.
- ScFormulaRecursionList::const_iterator aOldStart(
- rRecursionHelper.GetLastIterationStart());
- rRecursionHelper.ResumeIteration();
- // Mark new cells being in iteration.
- for (ScFormulaRecursionList::const_iterator aIter(
- rRecursionHelper.GetIterationStart()); aIter !=
- aOldStart; ++aIter)
- {
- pIterCell = (*aIter).pCell;
- pIterCell->bIsIterCell = true;
- }
- // Mark older cells dirty again, in case they converted
- // without accounting for all remaining cells in the circle
- // that weren't touched so far, e.g. conditional. Restore
- // backuped result.
- sal_uInt16 nIteration = rRecursionHelper.GetIteration();
- for (ScFormulaRecursionList::const_iterator aIter(
- aOldStart); aIter !=
- rRecursionHelper.GetIterationEnd(); ++aIter)
- {
- pIterCell = (*aIter).pCell;
- if (pIterCell->nSeenInIteration == nIteration)
- {
- if (!pIterCell->bDirty || aIter == aOldStart)
- {
- pIterCell->aResult = (*aIter).aPreviousResult;
- }
- --pIterCell->nSeenInIteration;
- }
- pIterCell->bDirty = true;
- }
- }
- else
- {
- bResumeIteration = false;
- // Close circle once.
- rRecursionHelper.GetList().back().pCell->InterpretTail(
- SCITP_CLOSE_ITERATION_CIRCLE);
- // Start at 1, init things.
- rRecursionHelper.StartIteration();
- // Mark all cells being in iteration.
- for (ScFormulaRecursionList::const_iterator aIter(
- rRecursionHelper.GetIterationStart()); aIter !=
- rRecursionHelper.GetIterationEnd(); ++aIter)
- {
- pIterCell = (*aIter).pCell;
- pIterCell->bIsIterCell = true;
- }
- }
- bIterationFromRecursion = false;
- sal_uInt16 nIterMax = pDocument->GetDocOptions().GetIterCount();
- for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone;
- rRecursionHelper.IncIteration())
- {
- rDone = true;
- for ( ScFormulaRecursionList::iterator aIter(
- rRecursionHelper.GetIterationStart()); aIter !=
- rRecursionHelper.GetIterationEnd() &&
- !rRecursionHelper.IsInReturn(); ++aIter)
- {
- pIterCell = (*aIter).pCell;
- if (pIterCell->IsDirtyOrInTableOpDirty() &&
- rRecursionHelper.GetIteration() !=
- pIterCell->GetSeenInIteration())
- {
- (*aIter).aPreviousResult = pIterCell->aResult;
- pIterCell->InterpretTail( SCITP_FROM_ITERATION);
- }
- rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
- }
- if (rRecursionHelper.IsInReturn())
- {
- bResumeIteration = true;
- break; // for
- // Don't increment iteration.
- }
- }
- if (!bResumeIteration)
- {
- if (rDone)
- {
- for (ScFormulaRecursionList::const_iterator aIter(
- rRecursionHelper.GetIterationStart());
- aIter != rRecursionHelper.GetIterationEnd();
- ++aIter)
- {
- pIterCell = (*aIter).pCell;
- pIterCell->bIsIterCell = false;
- pIterCell->nSeenInIteration = 0;
- pIterCell->bRunning = (*aIter).bOldRunning;
- }
- }
- else
- {
- for (ScFormulaRecursionList::const_iterator aIter(
- rRecursionHelper.GetIterationStart());
- aIter != rRecursionHelper.GetIterationEnd();
- ++aIter)
- {
- pIterCell = (*aIter).pCell;
- pIterCell->bIsIterCell = false;
- pIterCell->nSeenInIteration = 0;
- pIterCell->bRunning = (*aIter).bOldRunning;
- // If one cell didn't converge, all cells of this
- // circular dependency don't, no matter whether
- // single cells did.
- pIterCell->bDirty = false;
- pIterCell->bTableOpDirty = false;
- pIterCell->aResult.SetResultError( errNoConvergence);
- pIterCell->bChanged = true;
- pDocument->SetTextWidth(pIterCell->aPos, TEXTWIDTH_DIRTY);
- pDocument->SetScriptType(pIterCell->aPos, SC_SCRIPTTYPE_UNKNOWN);
- }
- }
- // End this iteration and remove entries.
- rRecursionHelper.EndIteration();
- bResumeIteration = rRecursionHelper.IsDoingIteration();
- }
- }
- if (rRecursionHelper.IsInRecursionReturn() &&
- rRecursionHelper.GetRecursionCount() == 0 &&
- !rRecursionHelper.IsDoingRecursion())
- {
- bIterationFromRecursion = false;
- // Iterate over cells known so far, start with the last cell
- // encountered, inserting new cells if another recursion limit
- // is reached. Repeat until solved.
- rRecursionHelper.SetDoingRecursion( true);
- do
- {
- rRecursionHelper.SetInRecursionReturn( false);
- for (ScFormulaRecursionList::const_iterator aIter(
- rRecursionHelper.GetIterationStart());
- !rRecursionHelper.IsInReturn() && aIter !=
- rRecursionHelper.GetIterationEnd(); ++aIter)
- {
- ScFormulaCell* pCell = (*aIter).pCell;
- if (pCell->IsDirtyOrInTableOpDirty())
- {
- pCell->InterpretTail( SCITP_NORMAL);
- if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
- pCell->bRunning = (*aIter).bOldRunning;
- }
- }
- } while (rRecursionHelper.IsInRecursionReturn());
- rRecursionHelper.SetDoingRecursion( false);
- if (rRecursionHelper.IsInIterationReturn())
- {
- if (!bResumeIteration)
- bIterationFromRecursion = true;
- }
- else if (bResumeIteration ||
- rRecursionHelper.IsDoingIteration())
- rRecursionHelper.GetList().erase(
- rRecursionHelper.GetIterationStart(),
- rRecursionHelper.GetLastIterationStart());
- else
- rRecursionHelper.Clear();
- }
- } while (bIterationFromRecursion || bResumeIteration);
- }
-}
-
-void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
-{
- class RecursionCounter
- {
- ScRecursionHelper& rRec;
- bool bStackedInIteration;
- public:
- RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r)
- {
- bStackedInIteration = rRec.IsDoingIteration();
- if (bStackedInIteration)
- rRec.GetRecursionInIterationStack().push( p);
- rRec.IncRecursionCount();
- }
- ~RecursionCounter()
- {
- rRec.DecRecursionCount();
- if (bStackedInIteration)
- rRec.GetRecursionInIterationStack().pop();
- }
- } aRecursionCounter( pDocument->GetRecursionHelper(), this);
- nSeenInIteration = pDocument->GetRecursionHelper().GetIteration();
- if( !pCode->GetCodeLen() && !pCode->GetCodeError() )
- {
- // #i11719# no UPN and no error and no token code but result string present
- // => interpretation of this cell during name-compilation and unknown names
- // => can't exchange underlying code array in CompileTokenArray() /
- // Compile() because interpreter's token iterator would crash or pCode
- // would be deleted twice if this cell was interpreted during
- // compilation.
- // This should only be a temporary condition and, since we set an
- // error, if ran into it again we'd bump into the dirty-clearing
- // condition further down.
- if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
- {
- pCode->SetCodeError( errNoCode );
- // This is worth an assertion; if encountered in daily work
- // documents we might need another solution. Or just confirm correctness.
- OSL_FAIL( "ScFormulaCell::Interpret: no UPN, no error, no token, but hybrid formula string" );
- return;
- }
- CompileTokenArray();
- }
-
- if( pCode->GetCodeLen() && pDocument )
- {
- class StackCleaner
- {
- ScDocument* pDoc;
- ScInterpreter* pInt;
- public:
- StackCleaner( ScDocument* pD, ScInterpreter* pI )
- : pDoc(pD), pInt(pI)
- {}
- ~StackCleaner()
- {
- delete pInt;
- pDoc->DecInterpretLevel();
- }
- };
- pDocument->IncInterpretLevel();
- ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode );
- StackCleaner aStackCleaner( pDocument, p);
- sal_uInt16 nOldErrCode = aResult.GetResultError();
- if ( nSeenInIteration == 0 )
- { // Only the first time
- // With bChanged=false, if a newly compiled cell has a result of
- // 0.0, no change is detected and the cell will not be repainted.
- // bChanged = false;
- aResult.SetResultError( 0 );
- }
-
- switch ( aResult.GetResultError() )
- {
- case errCircularReference : // will be determined again if so
- aResult.SetResultError( 0 );
- break;
- }
-
- bool bOldRunning = bRunning;
- bRunning = true;
- p->Interpret();
- if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE)
- {
- if (nSeenInIteration > 0)
- --nSeenInIteration; // retry when iteration is resumed
- return;
- }
- bRunning = bOldRunning;
-
- // #i102616# For single-sheet saving consider only content changes, not format type,
- // because format type isn't set on loading (might be changed later)
- bool bContentChanged = false;
-
- // Do not create a HyperLink() cell if the formula results in an error.
- if( p->GetError() && pCode->IsHyperLink())
- pCode->SetHyperLink(false);
-
- if( p->GetError() && p->GetError() != errCircularReference)
- {
- bDirty = false;
- bTableOpDirty = false;
- bChanged = true;
- }
- if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty())
- {
- bool bIsValue = aResult.IsValue(); // the previous type
- // Did it converge?
- if ((bIsValue && p->GetResultType() == svDouble && fabs(
- p->GetNumResult() - aResult.GetDouble()) <=
- pDocument->GetDocOptions().GetIterEps()) ||
- (!bIsValue && p->GetResultType() == svString &&
- p->GetStringResult() == aResult.GetString()))
- {
- // A convergence in the first iteration doesn't necessarily
- // mean that it's done, it may be as not all related cells
- // of a circle changed their values yet. If the set really
- // converges it will do so also during the next iteration. This
- // fixes situations like of #i44115#. If this wasn't wanted an
- // initial "uncalculated" value would be needed for all cells
- // of a circular dependency => graph needed before calculation.
- if (nSeenInIteration > 1 ||
- pDocument->GetDocOptions().GetIterCount() == 1)
- {
- bDirty = false;
- bTableOpDirty = false;
- }
- }
- }
-
- // New error code?
- if( p->GetError() != nOldErrCode )
- {
- bChanged = true;
- // bContentChanged only has to be set if the file content would be changed
- if ( aResult.GetCellResultType() != svUnknown )
- bContentChanged = true;
- }
- // Different number format?
- if( nFormatType != p->GetRetFormatType() )
- {
- nFormatType = p->GetRetFormatType();
- bChanged = true;
- }
- if( nFormatIndex != p->GetRetFormatIndex() )
- {
- nFormatIndex = p->GetRetFormatIndex();
- bChanged = true;
- }
-
- // In case of changes just obtain the result, no temporary and
- // comparison needed anymore.
- if (bChanged)
- {
- // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving
- // Also handle special cases of initial results after loading.
- if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
- {
- ScFormulaResult aNewResult( p->GetResultToken().get());
- StackVar eOld = aResult.GetCellResultType();
- StackVar eNew = aNewResult.GetCellResultType();
- if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) )
- {
- // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0
- // -> no change
- }
- else
- {
- if ( eOld == svHybridCell || eOld == svHybridValueCell ) // string result from SetFormulaResultString?
- eOld = svString; // ScHybridCellToken has a valid GetString method
-
- // #i106045# use approxEqual to compare with stored value
- bContentChanged = (eOld != eNew ||
- (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) ||
- (eNew == svString && aResult.GetString() != aNewResult.GetString()));
- }
- }
-
- aResult.SetToken( p->GetResultToken().get() );
- }
- else
- {
- ScFormulaResult aNewResult( p->GetResultToken().get());
- StackVar eOld = aResult.GetCellResultType();
- StackVar eNew = aNewResult.GetCellResultType();
- bChanged = (eOld != eNew ||
- (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
- (eNew == svString && aResult.GetString() != aNewResult.GetString()));
-
- // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged)
- if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
- {
- if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) ||
- ( (eOld == svHybridCell || eOld == svHybridValueCell) && eNew == svString && aResult.GetString() == aNewResult.GetString() ) ||
- ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) )
- {
- // no change, see above
- }
- else
- bContentChanged = true;
- }
-
- aResult.Assign( aNewResult);
- }
-
- // Precision as shown?
- if ( aResult.IsValue() && !p->GetError()
- && pDocument->GetDocOptions().IsCalcAsShown()
- && nFormatType != NUMBERFORMAT_DATE
- && nFormatType != NUMBERFORMAT_TIME
- && nFormatType != NUMBERFORMAT_DATETIME )
- {
- sal_uLong nFormat = pDocument->GetNumberFormat( aPos );
- if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
- nFormat = nFormatIndex;
- if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
- nFormat = ScGlobal::GetStandardFormat(
- *pDocument->GetFormatTable(), nFormat, nFormatType );
- aResult.SetDouble( pDocument->RoundValueAsShown(
- aResult.GetDouble(), nFormat));
- }
- if (eTailParam == SCITP_NORMAL)
- {
- bDirty = false;
- bTableOpDirty = false;
- }
- if( aResult.GetMatrix() )
- {
- // If the formula wasn't entered as a matrix formula, live on with
- // the upper left corner and let reference counting delete the matrix.
- if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() )
- aResult.SetToken( aResult.GetCellResultToken().get());
- }
- if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
- {
- // Coded double error may occur via filter import.
- sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble());
- aResult.SetResultError( nErr);
- bChanged = bContentChanged = true;
- }
- if( bChanged )
- {
- pDocument->SetTextWidth(aPos, TEXTWIDTH_DIRTY);
- pDocument->SetScriptType(aPos, SC_SCRIPTTYPE_UNKNOWN);
- }
- if (bContentChanged && pDocument->IsStreamValid(aPos.Tab()))
- {
- // pass bIgnoreLock=true, because even if called from pending row height update,
- // a changed result must still reset the stream flag
- pDocument->SetStreamValid(aPos.Tab(), false, true);
- }
- if ( !pCode->IsRecalcModeAlways() )
- pDocument->RemoveFromFormulaTree( this );
-
- // FORCED cells also immediately tested for validity (start macro possibly)
-
- if ( pCode->IsRecalcModeForced() )
- {
- sal_uLong nValidation = ((const SfxUInt32Item*) pDocument->GetAttr(
- aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue();
- if ( nValidation )
- {
- const ScValidationData* pData = pDocument->GetValidationEntry( nValidation );
- ScRefCellValue aTmpCell(this);
- if ( pData && !pData->IsDataValid(aTmpCell, aPos))
- pData->DoCalcError( this );
- }
- }
-
- // Reschedule slows the whole thing down considerably, thus only execute on percent change
- ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
- pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE );
-
- switch (p->GetVolatileType())
- {
- case ScInterpreter::VOLATILE:
- // Volatile via built-in volatile functions. No actions needed.
- break;
- case ScInterpreter::VOLATILE_MACRO:
- // The formula contains a volatile macro.
- pCode->SetExclusiveRecalcModeAlways();
- pDocument->PutInFormulaTree(this);
- StartListeningTo(pDocument);
- break;
- case ScInterpreter::NOT_VOLATILE:
- if (pCode->IsRecalcModeAlways())
- {
- // The formula was previously volatile, but no more.
- EndListeningTo(pDocument);
- pCode->SetExclusiveRecalcModeNormal();
- }
- else
- {
- // non-volatile formula. End listening to the area in case
- // it's listening due to macro module change.
- pDocument->EndListeningArea(BCA_LISTEN_ALWAYS, this);
- }
- pDocument->RemoveFromFormulaTree(this);
- break;
- default:
- ;
- }
- }
- else
- {
- // Cells with compiler errors should not be marked dirty forever
- OSL_ENSURE( pCode->GetCodeError(), "no UPN-Code und no errors ?!?!" );
- bDirty = false;
- bTableOpDirty = false;
- }
-}
-
-
-void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag )
-{
- ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst();
- if (pMat)
- pMat->SetMatColsRows( nCols, nRows );
- else if (nCols || nRows)
- {
- aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows));
- // Setting the new token actually forces an empty result at this top
- // left cell, so have that recalculated.
- SetDirty( bDirtyFlag );
- }
-}
-
-
-void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const
-{
- const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken();
- if (pMat)
- pMat->GetMatColsRows( nCols, nRows);
- else
- {
- nCols = 0;
- nRows = 0;
- }
-}
-
-
-sal_uLong ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const
-{
- if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
- return nFormatIndex;
- //! not ScFormulaCell::IsValue(), that could reinterpret the formula again.
- if ( aResult.IsValue() )
- return ScGlobal::GetStandardFormat( aResult.GetDouble(), rFormatter, nFormat, nFormatType );
- else
- return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType );
-}
-
-
-void ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
-{
- if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
- {
- const ScHint* p = PTR_CAST( ScHint, &rHint );
- sal_uLong nHint = (p ? p->GetId() : 0);
- if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY))
- {
- bool bForceTrack = false;
- if ( nHint & SC_HINT_TABLEOPDIRTY )
- {
- bForceTrack = !bTableOpDirty;
- if ( !bTableOpDirty )
- {
- pDocument->AddTableOpFormulaCell( this );
- bTableOpDirty = true;
- }
- }
- else
- {
- bForceTrack = !bDirty;
- SetDirtyVar();
- }
- // Don't remove from FormulaTree to put in FormulaTrack to
- // put in FormulaTree again and again, only if necessary.
- // Any other means except RECALCMODE_ALWAYS by which a cell could
- // be in FormulaTree if it would notify other cells through
- // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
- // Yes. The new TableOpDirty made it necessary to have a
- // forced mode where formulas may still be in FormulaTree from
- // TableOpDirty but have to notify dependents for normal dirty.
- if ( (bForceTrack || !pDocument->IsInFormulaTree( this )
- || pCode->IsRecalcModeAlways())
- && !pDocument->IsInFormulaTrack( this ) )
- pDocument->AppendToFormulaTrack( this );
- }
- }
-}
-
-void ScFormulaCell::SetDirty( bool bDirtyFlag )
-{
- if ( !IsInChangeTrack() )
- {
- if ( pDocument->GetHardRecalcState() )
- SetDirtyVar();
- else
- {
- // Multiple Formulas avoid tracking in Load and Copy compileAll
- // by Scenario and Copy Block From Clip.
- // If unconditional required Formula tracking is set before SetDirty
- // bDirty = false, eg in CompileTokenArray
- if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
- {
- if( bDirtyFlag )
- SetDirtyVar();
- pDocument->AppendToFormulaTrack( this );
- pDocument->TrackFormulas();
- }
- }
-
- if (pDocument->IsStreamValid(aPos.Tab()))
- pDocument->SetStreamValid(aPos.Tab(), false);
- }
-}
-
-void ScFormulaCell::SetDirtyVar()
-{
- bDirty = true;
- // mark the sheet of this cell to be calculated
- //#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() );
-}
-
-void ScFormulaCell::SetDirtyAfterLoad()
-{
- bDirty = true;
- if ( !pDocument->GetHardRecalcState() )
- pDocument->PutInFormulaTree( this );
-}
-
-void ScFormulaCell::SetTableOpDirty()
-{
- if ( !IsInChangeTrack() )
- {
- if ( pDocument->GetHardRecalcState() )
- bTableOpDirty = true;
- else
- {
- if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
- {
- if ( !bTableOpDirty )
- {
- pDocument->AddTableOpFormulaCell( this );
- bTableOpDirty = true;
- }
- pDocument->AppendToFormulaTrack( this );
- pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
- }
- }
- }
-}
-
-
-bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
-{
- return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
-}
-
-
-void ScFormulaCell::SetErrCode( sal_uInt16 n )
-{
- /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
- * used whether it is solely for transport of a simple result error and get
- * rid of that abuse. */
- pCode->SetCodeError( n );
- // Hard set errors are transported as result type value per convention,
- // e.g. via clipboard. ScFormulaResult::IsValue() and
- // ScFormulaResult::GetDouble() handle that.
- aResult.SetResultError( n );
-}
-
-void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
-{
- if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
- bDirty = true;
- if ( nBits & RECALCMODE_ONLOAD_ONCE )
- { // OnLoadOnce nur zum Dirty setzen nach Filter-Import
- nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
- }
- pCode->AddRecalcMode( nBits );
-}
-
-// Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
-void ScFormulaCell::GetURLResult( rtl::OUString& rURL, rtl::OUString& rCellText )
-{
- rtl::OUString aCellString;
-
- Color* pColor;
-
- // Cell Text uses the Cell format while the URL uses
- // the default format for the type.
- sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos );
- SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
-
- if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
- nCellFormat = GetStandardFormat( *pFormatter,nCellFormat );
-
- sal_uLong nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER);
-
- if ( IsValue() )
- {
- double fValue = GetValue();
- pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
- }
- else
- {
- aCellString = GetString();
- pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
- }
- ScConstMatrixRef xMat( aResult.GetMatrix());
- if (xMat)
- {
- // determine if the matrix result is a string or value.
- if (!xMat->IsValue(0, 1))
- rURL = xMat->GetString(0, 1);
- else
- pFormatter->GetOutputString(
- xMat->GetDouble(0, 1), nURLFormat, rURL, &pColor);
- }
-
- if(rURL.isEmpty())
- {
- if(IsValue())
- pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
- else
- pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
- }
-}
-
-bool ScFormulaCell::IsMultilineResult()
-{
- if (!IsValue())
- return aResult.IsMultiline();
- return false;
-}
-
-void ScFormulaCell::MaybeInterpret()
-{
- if (!IsDirtyOrInTableOpDirty())
- return;
-
- if (pDocument->GetAutoCalc() || (cMatrixFlag != MM_NONE))
- Interpret();
-}
-
-EditTextObject* ScFormulaCell::CreateURLObject()
-{
- rtl::OUString aCellText;
- rtl::OUString aURL;
- GetURLResult( aURL, aCellText );
-
- return ScEditUtil::CreateURLObjectFromURL( *pDocument, aURL, aCellText );
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */