diff options
Diffstat (limited to 'sc/source/core/data/cell.cxx')
-rw-r--r-- | sc/source/core/data/cell.cxx | 1459 |
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: */ |