From 428b0aeceecbccb7558a246eda090ececd28d7c5 Mon Sep 17 00:00:00 2001 From: Kohei Yoshida Date: Thu, 28 Mar 2013 15:20:14 -0400 Subject: Move ScFormulaCell into its own header source files: formulacell.?xx. Change-Id: I65f2cb12c06784b5bcf6c6a2fad773825b6c409c --- sc/Library_sc.mk | 1 + sc/inc/cell.hxx | 278 -- sc/inc/formulacell.hxx | 305 ++ sc/qa/unit/subsequent_filters-test.cxx | 2 +- sc/qa/unit/ucalc.cxx | 2 +- sc/source/core/data/attarray.cxx | 2 +- sc/source/core/data/autonamecache.cxx | 2 +- sc/source/core/data/cell.cxx | 1459 +-------- sc/source/core/data/cell2.cxx | 1749 +---------- sc/source/core/data/cellvalue.cxx | 1 + sc/source/core/data/colorscale.cxx | 2 +- sc/source/core/data/column.cxx | 1 + sc/source/core/data/column2.cxx | 1 + sc/source/core/data/column3.cxx | 10 +- sc/source/core/data/conditio.cxx | 2 +- sc/source/core/data/dociter.cxx | 1 + sc/source/core/data/documen2.cxx | 1 + sc/source/core/data/documen3.cxx | 1 + sc/source/core/data/documen4.cxx | 1 + sc/source/core/data/documen7.cxx | 1 + sc/source/core/data/document.cxx | 1 + sc/source/core/data/dpfilteredcache.cxx | 2 +- sc/source/core/data/dpitemdata.cxx | 2 +- sc/source/core/data/dpshttab.cxx | 2 +- sc/source/core/data/dptabsrc.cxx | 2 +- sc/source/core/data/fillinfo.cxx | 2 +- sc/source/core/data/formulacell.cxx | 3208 ++++++++++++++++++++ sc/source/core/data/formulaiter.cxx | 2 +- sc/source/core/data/postit.cxx | 2 +- sc/source/core/data/table1.cxx | 2 +- sc/source/core/data/table2.cxx | 2 +- sc/source/core/data/table3.cxx | 2 +- sc/source/core/data/table4.cxx | 2 +- sc/source/core/data/table5.cxx | 2 +- sc/source/core/data/table6.cxx | 2 +- sc/source/core/data/validat.cxx | 2 +- sc/source/core/tool/cellform.cxx | 2 +- sc/source/core/tool/chartarr.cxx | 2 +- sc/source/core/tool/chgtrack.cxx | 2 +- sc/source/core/tool/compiler.cxx | 2 +- sc/source/core/tool/consoli.cxx | 2 +- sc/source/core/tool/detfunc.cxx | 2 +- sc/source/core/tool/doubleref.cxx | 2 +- sc/source/core/tool/interpr1.cxx | 2 +- sc/source/core/tool/interpr2.cxx | 2 +- sc/source/core/tool/interpr3.cxx | 2 +- sc/source/core/tool/interpr4.cxx | 2 +- sc/source/core/tool/interpr5.cxx | 2 +- sc/source/core/tool/rangeseq.cxx | 2 +- sc/source/filter/dif/difexp.cxx | 2 +- sc/source/filter/excel/excdoc.cxx | 2 +- sc/source/filter/excel/excform.cxx | 2 +- sc/source/filter/excel/excform8.cxx | 2 +- sc/source/filter/excel/excimp8.cxx | 2 +- sc/source/filter/excel/excrecds.cxx | 2 +- sc/source/filter/excel/impop.cxx | 2 +- sc/source/filter/excel/xehelper.cxx | 2 +- sc/source/filter/excel/xelink.cxx | 2 +- sc/source/filter/excel/xestream.cxx | 2 +- sc/source/filter/excel/xetable.cxx | 2 +- sc/source/filter/excel/xicontent.cxx | 2 +- sc/source/filter/excel/xilink.cxx | 2 +- sc/source/filter/excel/xipivot.cxx | 2 +- sc/source/filter/excel/xistyle.cxx | 2 +- sc/source/filter/html/htmlexp.cxx | 2 +- sc/source/filter/lotus/lotimpop.cxx | 2 +- sc/source/filter/lotus/op.cxx | 2 +- sc/source/filter/oox/formulabuffer.cxx | 2 +- sc/source/filter/oox/sheetdatabuffer.cxx | 2 +- sc/source/filter/orcus/interface.cxx | 2 +- sc/source/filter/qpro/biff.cxx | 2 +- sc/source/filter/qpro/qpro.cxx | 2 +- sc/source/filter/qpro/qprostyle.cxx | 2 +- sc/source/filter/starcalc/scflt.cxx | 2 +- sc/source/filter/xcl97/XclExpChangeTrack.cxx | 2 +- sc/source/filter/xcl97/XclImpChangeTrack.cxx | 2 +- sc/source/filter/xcl97/xcl97rec.cxx | 2 +- .../filter/xml/XMLChangeTrackingExportHelper.cxx | 2 +- .../filter/xml/XMLChangeTrackingImportHelper.cxx | 2 +- sc/source/filter/xml/XMLTrackedChangesContext.cxx | 2 +- sc/source/filter/xml/xmlcelli.cxx | 2 +- sc/source/filter/xml/xmlexprt.cxx | 2 +- sc/source/ui/Accessibility/AccessibleCellBase.cxx | 2 +- sc/source/ui/app/inputhdl.cxx | 2 +- sc/source/ui/app/transobj.cxx | 2 +- sc/source/ui/collab/sendfunc.cxx | 2 +- sc/source/ui/docshell/docfunc.cxx | 2 +- sc/source/ui/docshell/docsh.cxx | 2 +- sc/source/ui/docshell/docsh3.cxx | 2 +- sc/source/ui/docshell/docsh8.cxx | 2 +- sc/source/ui/docshell/externalrefmgr.cxx | 2 +- sc/source/ui/docshell/impex.cxx | 2 +- sc/source/ui/docshell/macromgr.cxx | 2 +- sc/source/ui/docshell/tablink.cxx | 2 +- sc/source/ui/formdlg/dwfunctr.cxx | 2 +- sc/source/ui/formdlg/formula.cxx | 2 +- sc/source/ui/miscdlgs/anyrefdg.cxx | 2 +- sc/source/ui/miscdlgs/optsolver.cxx | 2 +- sc/source/ui/navipi/content.cxx | 2 +- sc/source/ui/undo/undoblk3.cxx | 2 +- sc/source/ui/undo/undocell.cxx | 2 +- sc/source/ui/unoobj/cellsuno.cxx | 2 +- sc/source/ui/unoobj/chart2uno.cxx | 2 +- sc/source/ui/unoobj/docuno.cxx | 2 +- sc/source/ui/unoobj/funcuno.cxx | 2 +- sc/source/ui/unoobj/textuno.cxx | 2 +- sc/source/ui/view/cellsh.cxx | 2 +- sc/source/ui/view/dbfunc3.cxx | 2 +- sc/source/ui/view/gridwin.cxx | 2 +- sc/source/ui/view/output.cxx | 2 +- sc/source/ui/view/output2.cxx | 2 +- sc/source/ui/view/printfun.cxx | 2 +- sc/source/ui/view/spelleng.cxx | 2 +- sc/source/ui/view/tabview4.cxx | 2 +- sc/source/ui/view/tabvwsh3.cxx | 2 +- sc/source/ui/view/tabvwsh5.cxx | 2 +- sc/source/ui/view/tabvwsha.cxx | 2 +- sc/source/ui/view/tabvwshc.cxx | 2 +- sc/source/ui/view/viewfun2.cxx | 2 +- sc/source/ui/view/viewfun4.cxx | 2 +- sc/source/ui/view/viewfun6.cxx | 2 +- sc/source/ui/view/viewfunc.cxx | 2 +- 122 files changed, 3635 insertions(+), 3596 deletions(-) create mode 100644 sc/inc/formulacell.hxx create mode 100644 sc/source/core/data/formulacell.cxx (limited to 'sc') diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 46ab33020904..8d89830bdd93 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -143,6 +143,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/data/drawpage \ sc/source/core/data/drwlayer \ sc/source/core/data/fillinfo \ + sc/source/core/data/formulacell \ sc/source/core/data/formulaiter \ sc/source/core/data/funcdesc \ sc/source/core/data/global \ diff --git a/sc/inc/cell.hxx b/sc/inc/cell.hxx index 7395713e5c21..217cfab38647 100644 --- a/sc/inc/cell.hxx +++ b/sc/inc/cell.hxx @@ -300,284 +300,6 @@ private: ::std::vector maArray; }; -struct ScSimilarFormulaDelta; - -struct SC_DLLPUBLIC ScFormulaCellGroup -{ - sal_Int32 mnRefCount; - ScSimilarFormulaDelta *mpDelta; // difference between items in column - sal_Int32 mnStart; // Start offset of that cell - sal_Int32 mnLength; // How many of these do we have ? - - ScFormulaCellGroup(); - ~ScFormulaCellGroup(); - - bool IsCompatible( ScSimilarFormulaDelta *pDelta ); -}; -inline void intrusive_ptr_add_ref(ScFormulaCellGroup *p) -{ - p->mnRefCount++; -} -inline void intrusive_ptr_release(ScFormulaCellGroup *p) -{ - if( --p->mnRefCount == 0 ) - delete p; -} - -typedef ::boost::intrusive_ptr ScFormulaCellGroupRef; - -enum ScMatrixMode { - MM_NONE = 0, // No matrix formula - MM_FORMULA = 1, // Upper left matrix formula cell - MM_REFERENCE = 2, // Remaining cells, via ocMatRef reference token - MM_FAKE = 3 // Interpret "as-if" matrix formula (legacy) -}; - -class SC_DLLPUBLIC ScFormulaCell : public ScBaseCell, public SvtListener -{ -private: - ScFormulaResult aResult; - formula::FormulaGrammar::Grammar eTempGrammar; // used between string (creation) and (re)compilation - ScTokenArray* pCode; // The (new) token array - ScDocument* pDocument; - ScFormulaCell* pPrevious; - ScFormulaCell* pNext; - ScFormulaCell* pPreviousTrack; - ScFormulaCell* pNextTrack; - ScFormulaCellGroupRef xGroup; // re-factoring hack - group of formulae we're part of. - sal_uLong nFormatIndex; // Number format set by calculation - short nFormatType; // Number format type set by calculation - sal_uInt16 nSeenInIteration; // Iteration cycle in which the cell was last encountered - sal_uInt8 cMatrixFlag; // One of ScMatrixMode - bool bDirty : 1; // Must be (re)calculated - bool bChanged : 1; // Whether something changed regarding display/representation - bool bRunning : 1; // Already interpreting right now - bool bCompile : 1; // Must be (re)compiled - bool bSubTotal : 1; // Cell is part of or contains a SubTotal - bool bIsIterCell : 1; // Cell is part of a circular reference - bool bInChangeTrack : 1; // Cell is in ChangeTrack - bool bTableOpDirty : 1; // Dirty flag for TableOp - bool bNeedListening : 1; // Listeners need to be re-established after UpdateReference - - enum ScInterpretTailParameter - { - SCITP_NORMAL, - SCITP_FROM_ITERATION, - SCITP_CLOSE_ITERATION_CIRCLE - }; - void InterpretTail( ScInterpretTailParameter ); - - ScFormulaCell( const ScFormulaCell& ); - -public: - -#ifdef USE_MEMPOOL - DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell ) -#endif - - ScAddress aPos; - - ~ScFormulaCell(); - - using ScBaseCell::Clone; - - ScFormulaCell* Clone() const; - - /** Empty formula cell, or with a preconstructed token array. */ - ScFormulaCell( ScDocument*, const ScAddress&, const ScTokenArray* = NULL, - const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT, - sal_uInt8 = MM_NONE ); - - /** With formula string and grammar to compile with. - formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that - also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefor uses the address - convention associated with rPos::nTab by default. */ - ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, - const rtl::OUString& rFormula, - const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT, - sal_uInt8 cMatInd = MM_NONE ); - - ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags = SC_CLONECELL_DEFAULT ); - - size_t GetHash() const; - - ScFormulaVectorState GetVectorState() const; - - void GetFormula( rtl::OUString& rFormula, - const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const; - void GetFormula( rtl::OUStringBuffer& rBuffer, - const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const; - - void SetDirty( bool bDirtyFlag=true ); - void SetDirtyVar(); - // If setting entire document dirty after load, no broadcasts but still append to FormulaTree. - void SetDirtyAfterLoad(); - inline void ResetTableOpDirtyVar() { bTableOpDirty = false; } - void SetTableOpDirty(); - bool IsDirtyOrInTableOpDirty() const; - bool GetDirty() const { return bDirty; } - void ResetDirty() { bDirty = false; } - bool NeedsListening() const { return bNeedListening; } - void SetNeedsListening( bool bVar ) { bNeedListening = bVar; } - void Compile(const rtl::OUString& rFormula, - bool bNoListening = false, - const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ); - void CompileTokenArray( bool bNoListening = false ); - void CompileXML( ScProgress& rProgress ); // compile temporary string tokens - void CalcAfterLoad(); - bool MarkUsedExternalReferences(); - void Interpret(); - inline bool IsIterCell() const { return bIsIterCell; } - inline sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; } - - bool HasOneReference( ScRange& r ) const; - /* Checks if the formula contains reference list that can be - expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The - reference list is not required to be sorted (i.e. A3;A1;A2 is - still recognized as A1:A3), but no overlapping is allowed. - If one reference is recognized, the rRange is filled. - - It is similar to HasOneReference(), but more general. - */ - bool HasRefListExpressibleAsOneReference(ScRange& rRange) const; - bool HasRelNameReference() const; - bool HasColRowName() const; - - bool UpdateReference(UpdateRefMode eUpdateRefMode, - const ScRange& r, - SCsCOL nDx, SCsROW nDy, SCsTAB nDz, - ScDocument* pUndoDoc = NULL, - const ScAddress* pUndoCellPos = NULL ); - - void TransposeReference(); - void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, - ScDocument* pUndoDoc ); - - void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ); - - void UpdateInsertTab(SCTAB nTable, SCTAB nNewSheets = 1); - void UpdateInsertTabAbs(SCTAB nTable); - bool UpdateDeleteTab(SCTAB nTable, bool bIsMove = false, SCTAB nSheets = 1); - void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo); - void UpdateRenameTab(SCTAB nTable, const rtl::OUString& rName); - bool TestTabRefAbs(SCTAB nTable); - void UpdateCompile( bool bForceIfNameInUse = false ); - void FindRangeNamesInUse(std::set& rIndexes) const; - bool IsSubTotal() const { return bSubTotal; } - bool IsChanged() const; - void ResetChanged(); - bool IsEmpty(); // formula::svEmptyCell result - // display as empty string if formula::svEmptyCell result - bool IsEmptyDisplayedAsString(); - bool IsValue(); // also true if formula::svEmptyCell - bool IsHybridValueCell(); // for cells after import to deal with inherited number formats - double GetValue(); - double GetValueAlways(); // ignore errors - rtl::OUString GetString(); - const ScMatrix* GetMatrix(); - bool GetMatrixOrigin( ScAddress& rPos ) const; - void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows ); - sal_uInt16 GetMatrixEdge( ScAddress& rOrgPos ); - sal_uInt16 GetErrCode(); // interpret first if necessary - sal_uInt16 GetRawError(); // don't interpret, just return code or result error - short GetFormatType() const { return nFormatType; } - sal_uLong GetFormatIndex() const { return nFormatIndex; } - void GetFormatInfo( short& nType, sal_uLong& nIndex ) const - { nType = nFormatType; nIndex = nFormatIndex; } - sal_uInt8 GetMatrixFlag() const { return cMatrixFlag; } - ScTokenArray* GetCode() const { return pCode; } - - bool IsRunning() const { return bRunning; } - void SetRunning( bool bVal ) { bRunning = bVal; } - void CompileDBFormula(); - void CompileDBFormula( bool bCreateFormulaString ); - void CompileNameFormula( bool bCreateFormulaString ); - void CompileColRowNameFormula(); - ScFormulaCell* GetPrevious() const { return pPrevious; } - ScFormulaCell* GetNext() const { return pNext; } - void SetPrevious( ScFormulaCell* pF ) { pPrevious = pF; } - void SetNext( ScFormulaCell* pF ) { pNext = pF; } - ScFormulaCell* GetPreviousTrack() const { return pPreviousTrack; } - ScFormulaCell* GetNextTrack() const { return pNextTrack; } - void SetPreviousTrack( ScFormulaCell* pF ) { pPreviousTrack = pF; } - void SetNextTrack( ScFormulaCell* pF ) { pNextTrack = pF; } - - virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint); - void SetCompile( bool bVal ) { bCompile = bVal; } - ScDocument* GetDocument() const { return pDocument; } - void SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag=true ); - void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const; - - // cell belongs to ChangeTrack and not to the real document - void SetInChangeTrack( bool bVal ) { bInChangeTrack = bVal; } - bool IsInChangeTrack() const { return bInChangeTrack; } - - // standard format for type and format - // for format "Standard" possibly the format used in the formula cell - sal_uLong GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const; - - // For import filters! - void AddRecalcMode( formula::ScRecalcMode ); - /** For import only: set a double result. */ - void SetHybridDouble( double n ) { aResult.SetHybridDouble( n); } - /** For import only: set a string result. - If for whatever reason you have to use both, SetHybridDouble() and - SetHybridString() or SetHybridFormula(), use SetHybridDouble() first - for performance reasons.*/ - void SetHybridString( const rtl::OUString& r ) - { aResult.SetHybridString( r); } - /** For import only: set a temporary formula string to be compiled later. - If for whatever reason you have to use both, SetHybridDouble() and - SetHybridString() or SetHybridFormula(), use SetHybridDouble() first - for performance reasons.*/ - void SetHybridFormula( const rtl::OUString& r, - const formula::FormulaGrammar::Grammar eGrammar ) - { aResult.SetHybridFormula( r); eTempGrammar = eGrammar; } - - /** - * For import only: use for formula cells that return a number - * formatted as some kind of string - */ - void SetHybridValueString( double nVal, const OUString& r ) - { aResult.SetHybridValueString( nVal, r ); } - - void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL ) - { - aResult.SetMatrix(nCols, nRows, pMat, pUL); - } - - /** For import only: set a double result. - Use this instead of SetHybridDouble() if there is no (temporary) - formula string because the formula is present as a token array, as it - is the case for binary Excel import. - */ - void SetResultDouble( double n ) { aResult.SetDouble( n); } - - void SetErrCode( sal_uInt16 n ); - inline bool IsHyperLinkCell() const { return pCode && pCode->IsHyperLink(); } - EditTextObject* CreateURLObject(); - void GetURLResult( rtl::OUString& rURL, rtl::OUString& rCellText ); - - /** Determines whether or not the result string contains more than one paragraph */ - bool IsMultilineResult(); - - void MaybeInterpret(); - - // Temporary formula cell grouping API - ScFormulaCellGroupRef GetCellGroup() - { return xGroup; } - void SetCellGroup( const ScFormulaCellGroupRef &xRef ) - { xGroup = xRef; } - ScSimilarFormulaDelta *BuildDeltaTo( ScFormulaCell *pOther ); - void ReleaseDelta( ScSimilarFormulaDelta *pDelta ); - bool InterpretFormulaGroup(); - - // nOnlyNames may be one or more of SC_LISTENING_NAMES_* - void StartListeningTo( ScDocument* pDoc ); - void EndListeningTo( - ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() ); -}; - #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx new file mode 100644 index 000000000000..8bdcbc04d225 --- /dev/null +++ b/sc/inc/formulacell.hxx @@ -0,0 +1,305 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef SC_FORMULACELL_HXX +#define SC_FORMULACELL_HXX + +#include "cell.hxx" + +struct ScSimilarFormulaDelta; + +struct SC_DLLPUBLIC ScFormulaCellGroup +{ + sal_Int32 mnRefCount; + ScSimilarFormulaDelta *mpDelta; // difference between items in column + sal_Int32 mnStart; // Start offset of that cell + sal_Int32 mnLength; // How many of these do we have ? + + ScFormulaCellGroup(); + ~ScFormulaCellGroup(); + + bool IsCompatible( ScSimilarFormulaDelta *pDelta ); +}; +inline void intrusive_ptr_add_ref(ScFormulaCellGroup *p) +{ + p->mnRefCount++; +} +inline void intrusive_ptr_release(ScFormulaCellGroup *p) +{ + if( --p->mnRefCount == 0 ) + delete p; +} + +typedef ::boost::intrusive_ptr ScFormulaCellGroupRef; + +enum ScMatrixMode { + MM_NONE = 0, // No matrix formula + MM_FORMULA = 1, // Upper left matrix formula cell + MM_REFERENCE = 2, // Remaining cells, via ocMatRef reference token + MM_FAKE = 3 // Interpret "as-if" matrix formula (legacy) +}; + +class SC_DLLPUBLIC ScFormulaCell : public ScBaseCell, public SvtListener +{ +private: + ScFormulaResult aResult; + formula::FormulaGrammar::Grammar eTempGrammar; // used between string (creation) and (re)compilation + ScTokenArray* pCode; // The (new) token array + ScDocument* pDocument; + ScFormulaCell* pPrevious; + ScFormulaCell* pNext; + ScFormulaCell* pPreviousTrack; + ScFormulaCell* pNextTrack; + ScFormulaCellGroupRef xGroup; // re-factoring hack - group of formulae we're part of. + sal_uLong nFormatIndex; // Number format set by calculation + short nFormatType; // Number format type set by calculation + sal_uInt16 nSeenInIteration; // Iteration cycle in which the cell was last encountered + sal_uInt8 cMatrixFlag; // One of ScMatrixMode + bool bDirty : 1; // Must be (re)calculated + bool bChanged : 1; // Whether something changed regarding display/representation + bool bRunning : 1; // Already interpreting right now + bool bCompile : 1; // Must be (re)compiled + bool bSubTotal : 1; // Cell is part of or contains a SubTotal + bool bIsIterCell : 1; // Cell is part of a circular reference + bool bInChangeTrack : 1; // Cell is in ChangeTrack + bool bTableOpDirty : 1; // Dirty flag for TableOp + bool bNeedListening : 1; // Listeners need to be re-established after UpdateReference + + enum ScInterpretTailParameter + { + SCITP_NORMAL, + SCITP_FROM_ITERATION, + SCITP_CLOSE_ITERATION_CIRCLE + }; + void InterpretTail( ScInterpretTailParameter ); + + ScFormulaCell( const ScFormulaCell& ); + +public: + +#ifdef USE_MEMPOOL + DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell ) +#endif + + ScAddress aPos; + + ~ScFormulaCell(); + + using ScBaseCell::Clone; + + ScFormulaCell* Clone() const; + + /** Empty formula cell, or with a preconstructed token array. */ + ScFormulaCell( ScDocument*, const ScAddress&, const ScTokenArray* = NULL, + const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT, + sal_uInt8 = MM_NONE ); + + /** With formula string and grammar to compile with. + formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that + also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefor uses the address + convention associated with rPos::nTab by default. */ + ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, + const rtl::OUString& rFormula, + const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT, + sal_uInt8 cMatInd = MM_NONE ); + + ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags = SC_CLONECELL_DEFAULT ); + + size_t GetHash() const; + + ScFormulaVectorState GetVectorState() const; + + void GetFormula( rtl::OUString& rFormula, + const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const; + void GetFormula( rtl::OUStringBuffer& rBuffer, + const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const; + + void SetDirty( bool bDirtyFlag=true ); + void SetDirtyVar(); + // If setting entire document dirty after load, no broadcasts but still append to FormulaTree. + void SetDirtyAfterLoad(); + inline void ResetTableOpDirtyVar() { bTableOpDirty = false; } + void SetTableOpDirty(); + bool IsDirtyOrInTableOpDirty() const; + bool GetDirty() const { return bDirty; } + void ResetDirty() { bDirty = false; } + bool NeedsListening() const { return bNeedListening; } + void SetNeedsListening( bool bVar ) { bNeedListening = bVar; } + void Compile(const rtl::OUString& rFormula, + bool bNoListening = false, + const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ); + void CompileTokenArray( bool bNoListening = false ); + void CompileXML( ScProgress& rProgress ); // compile temporary string tokens + void CalcAfterLoad(); + bool MarkUsedExternalReferences(); + void Interpret(); + inline bool IsIterCell() const { return bIsIterCell; } + inline sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; } + + bool HasOneReference( ScRange& r ) const; + /* Checks if the formula contains reference list that can be + expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The + reference list is not required to be sorted (i.e. A3;A1;A2 is + still recognized as A1:A3), but no overlapping is allowed. + If one reference is recognized, the rRange is filled. + + It is similar to HasOneReference(), but more general. + */ + bool HasRefListExpressibleAsOneReference(ScRange& rRange) const; + bool HasRelNameReference() const; + bool HasColRowName() const; + + bool UpdateReference(UpdateRefMode eUpdateRefMode, + const ScRange& r, + SCsCOL nDx, SCsROW nDy, SCsTAB nDz, + ScDocument* pUndoDoc = NULL, + const ScAddress* pUndoCellPos = NULL ); + + void TransposeReference(); + void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, + ScDocument* pUndoDoc ); + + void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ); + + void UpdateInsertTab(SCTAB nTable, SCTAB nNewSheets = 1); + void UpdateInsertTabAbs(SCTAB nTable); + bool UpdateDeleteTab(SCTAB nTable, bool bIsMove = false, SCTAB nSheets = 1); + void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo); + void UpdateRenameTab(SCTAB nTable, const rtl::OUString& rName); + bool TestTabRefAbs(SCTAB nTable); + void UpdateCompile( bool bForceIfNameInUse = false ); + void FindRangeNamesInUse(std::set& rIndexes) const; + bool IsSubTotal() const { return bSubTotal; } + bool IsChanged() const; + void ResetChanged(); + bool IsEmpty(); // formula::svEmptyCell result + // display as empty string if formula::svEmptyCell result + bool IsEmptyDisplayedAsString(); + bool IsValue(); // also true if formula::svEmptyCell + bool IsHybridValueCell(); // for cells after import to deal with inherited number formats + double GetValue(); + double GetValueAlways(); // ignore errors + rtl::OUString GetString(); + const ScMatrix* GetMatrix(); + bool GetMatrixOrigin( ScAddress& rPos ) const; + void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows ); + sal_uInt16 GetMatrixEdge( ScAddress& rOrgPos ); + sal_uInt16 GetErrCode(); // interpret first if necessary + sal_uInt16 GetRawError(); // don't interpret, just return code or result error + short GetFormatType() const { return nFormatType; } + sal_uLong GetFormatIndex() const { return nFormatIndex; } + void GetFormatInfo( short& nType, sal_uLong& nIndex ) const + { nType = nFormatType; nIndex = nFormatIndex; } + sal_uInt8 GetMatrixFlag() const { return cMatrixFlag; } + ScTokenArray* GetCode() const { return pCode; } + + bool IsRunning() const { return bRunning; } + void SetRunning( bool bVal ) { bRunning = bVal; } + void CompileDBFormula(); + void CompileDBFormula( bool bCreateFormulaString ); + void CompileNameFormula( bool bCreateFormulaString ); + void CompileColRowNameFormula(); + ScFormulaCell* GetPrevious() const { return pPrevious; } + ScFormulaCell* GetNext() const { return pNext; } + void SetPrevious( ScFormulaCell* pF ) { pPrevious = pF; } + void SetNext( ScFormulaCell* pF ) { pNext = pF; } + ScFormulaCell* GetPreviousTrack() const { return pPreviousTrack; } + ScFormulaCell* GetNextTrack() const { return pNextTrack; } + void SetPreviousTrack( ScFormulaCell* pF ) { pPreviousTrack = pF; } + void SetNextTrack( ScFormulaCell* pF ) { pNextTrack = pF; } + + virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint); + void SetCompile( bool bVal ) { bCompile = bVal; } + ScDocument* GetDocument() const { return pDocument; } + void SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag=true ); + void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const; + + // cell belongs to ChangeTrack and not to the real document + void SetInChangeTrack( bool bVal ) { bInChangeTrack = bVal; } + bool IsInChangeTrack() const { return bInChangeTrack; } + + // standard format for type and format + // for format "Standard" possibly the format used in the formula cell + sal_uLong GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const; + + // For import filters! + void AddRecalcMode( formula::ScRecalcMode ); + /** For import only: set a double result. */ + void SetHybridDouble( double n ) { aResult.SetHybridDouble( n); } + /** For import only: set a string result. + If for whatever reason you have to use both, SetHybridDouble() and + SetHybridString() or SetHybridFormula(), use SetHybridDouble() first + for performance reasons.*/ + void SetHybridString( const rtl::OUString& r ) + { aResult.SetHybridString( r); } + /** For import only: set a temporary formula string to be compiled later. + If for whatever reason you have to use both, SetHybridDouble() and + SetHybridString() or SetHybridFormula(), use SetHybridDouble() first + for performance reasons.*/ + void SetHybridFormula( const rtl::OUString& r, + const formula::FormulaGrammar::Grammar eGrammar ) + { aResult.SetHybridFormula( r); eTempGrammar = eGrammar; } + + /** + * For import only: use for formula cells that return a number + * formatted as some kind of string + */ + void SetHybridValueString( double nVal, const OUString& r ) + { aResult.SetHybridValueString( nVal, r ); } + + void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL ) + { + aResult.SetMatrix(nCols, nRows, pMat, pUL); + } + + /** For import only: set a double result. + Use this instead of SetHybridDouble() if there is no (temporary) + formula string because the formula is present as a token array, as it + is the case for binary Excel import. + */ + void SetResultDouble( double n ) { aResult.SetDouble( n); } + + void SetErrCode( sal_uInt16 n ); + inline bool IsHyperLinkCell() const { return pCode && pCode->IsHyperLink(); } + EditTextObject* CreateURLObject(); + void GetURLResult( rtl::OUString& rURL, rtl::OUString& rCellText ); + + /** Determines whether or not the result string contains more than one paragraph */ + bool IsMultilineResult(); + + void MaybeInterpret(); + + // Temporary formula cell grouping API + ScFormulaCellGroupRef GetCellGroup() + { return xGroup; } + void SetCellGroup( const ScFormulaCellGroupRef &xRef ) + { xGroup = xRef; } + ScSimilarFormulaDelta *BuildDeltaTo( ScFormulaCell *pOther ); + void ReleaseDelta( ScSimilarFormulaDelta *pDelta ); + bool InterpretFormulaGroup(); + + // nOnlyNames may be one or more of SC_LISTENING_NAMES_* + void StartListeningTo( ScDocument* pDoc ); + void EndListeningTo( + ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/qa/unit/subsequent_filters-test.cxx b/sc/qa/unit/subsequent_filters-test.cxx index 130be28a49ec..a00b518591c0 100644 --- a/sc/qa/unit/subsequent_filters-test.cxx +++ b/sc/qa/unit/subsequent_filters-test.cxx @@ -50,7 +50,7 @@ #include #include #include "validat.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "drwlayer.hxx" #include "userdat.hxx" #include "dpobject.hxx" diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 6d4895632e7a..6416340fdc15 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -33,7 +33,7 @@ #include #include "scdll.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "stringutil.hxx" #include "scmatrix.hxx" diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx index 29522130e0f1..d52bcc69a258 100644 --- a/sc/source/core/data/attarray.cxx +++ b/sc/source/core/data/attarray.cxx @@ -40,7 +40,7 @@ #include "rechead.hxx" #include "globstr.hrc" #include "segmenttree.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "cellvalue.hxx" #include "editutil.hxx" #include diff --git a/sc/source/core/data/autonamecache.cxx b/sc/source/core/data/autonamecache.cxx index 6629c510555c..1dca11e62afe 100644 --- a/sc/source/core/data/autonamecache.cxx +++ b/sc/source/core/data/autonamecache.cxx @@ -22,7 +22,7 @@ #include "autonamecache.hxx" #include "dociter.hxx" #include "queryparam.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "cellvalue.hxx" #include "editutil.hxx" #include "document.hxx" 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 #include -#include - -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(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(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(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(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(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: */ diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx index b443d658c087..9d8b1b9de07d 100644 --- a/sc/source/core/data/cell2.cxx +++ b/sc/source/core/data/cell2.cxx @@ -17,34 +17,14 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include -#include - -#include -#include -#include -#include -#include -#include "editeng/fieldupdater.hxx" - #include "cell.hxx" -#include "compiler.hxx" -#include "formula/errorcodes.hxx" + #include "document.hxx" -#include "rangenam.hxx" -#include "rechead.hxx" -#include "refupdat.hxx" -#include "scmatrix.hxx" #include "editutil.hxx" -#include "chgtrack.hxx" -#include "externalrefmgr.hxx" -#include "scitems.hxx" -#include "patattr.hxx" -#include -#include - -using namespace formula; +#include "editeng/editobj.hxx" +#include "editeng/editstat.hxx" +#include "editeng/fieldupdater.hxx" // STATIC DATA ----------------------------------------------------------- @@ -260,1725 +240,4 @@ SCROW ScEditDataArray::Item::GetRow() const return mnRow; } -// ============================================================================ - -namespace -{ - -using std::deque; - -typedef SCCOLROW(*DimensionSelector)(const ScSingleRefData&); - - -static SCCOLROW lcl_GetCol(const ScSingleRefData& rData) -{ - return rData.nCol; -} - - -static SCCOLROW lcl_GetRow(const ScSingleRefData& rData) -{ - return rData.nRow; -} - - -static SCCOLROW lcl_GetTab(const ScSingleRefData& rData) -{ - return rData.nTab; -} - - -/** Check if both references span the same range in selected dimension. - */ -static bool -lcl_checkRangeDimension( - const SingleDoubleRefProvider& rRef1, - const SingleDoubleRefProvider& rRef2, - const DimensionSelector aWhich) -{ - return - aWhich(rRef1.Ref1) == aWhich(rRef2.Ref1) - && aWhich(rRef1.Ref2) == aWhich(rRef2.Ref2); -} - - -static bool -lcl_checkRangeDimensions( - const SingleDoubleRefProvider& rRef1, - const SingleDoubleRefProvider& rRef2, - bool& bCol, bool& bRow, bool& bTab) -{ - const bool bSameCols(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetCol)); - const bool bSameRows(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetRow)); - const bool bSameTabs(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetTab)); - - // Test if exactly two dimensions are equal - if (!(bSameCols ^ bSameRows ^ bSameTabs) - && (bSameCols || bSameRows || bSameTabs)) - { - bCol = !bSameCols; - bRow = !bSameRows; - bTab = !bSameTabs; - return true; - } - return false; -} - - -/** Check if references in given reference list can possibly - form a range. To do that, two of their dimensions must be the same. - */ -static bool -lcl_checkRangeDimensions( - const deque::const_iterator aBegin, - const deque::const_iterator aEnd, - bool& bCol, bool& bRow, bool& bTab) -{ - deque::const_iterator aCur(aBegin); - ++aCur; - const SingleDoubleRefProvider aRef(**aBegin); - bool bOk(false); - { - const SingleDoubleRefProvider aRefCur(**aCur); - bOk = lcl_checkRangeDimensions(aRef, aRefCur, bCol, bRow, bTab); - } - while (bOk && aCur != aEnd) - { - const SingleDoubleRefProvider aRefCur(**aCur); - bool bColTmp(false); - bool bRowTmp(false); - bool bTabTmp(false); - bOk = lcl_checkRangeDimensions(aRef, aRefCur, bColTmp, bRowTmp, bTabTmp); - bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp); - ++aCur; - } - - if (bOk && aCur == aEnd) - { - return true; - } - return false; -} - - -bool -lcl_lessReferenceBy( - const ScToken* const pRef1, const ScToken* const pRef2, - const DimensionSelector aWhich) -{ - const SingleDoubleRefProvider rRef1(*pRef1); - const SingleDoubleRefProvider rRef2(*pRef2); - return aWhich(rRef1.Ref1) < aWhich(rRef2.Ref1); -} - - -/** Returns true if range denoted by token pRef2 starts immediately after - range denoted by token pRef1. Dimension, in which the comparison takes - place, is given by aWhich. - */ -bool -lcl_isImmediatelyFollowing( - const ScToken* const pRef1, const ScToken* const pRef2, - const DimensionSelector aWhich) -{ - const SingleDoubleRefProvider rRef1(*pRef1); - const SingleDoubleRefProvider rRef2(*pRef2); - return aWhich(rRef2.Ref1) - aWhich(rRef1.Ref2) == 1; -} - - -static bool -lcl_checkIfAdjacent( - const deque& rReferences, - const DimensionSelector aWhich) -{ - typedef deque::const_iterator Iter; - Iter aBegin(rReferences.begin()); - Iter aEnd(rReferences.end()); - Iter aBegin1(aBegin); - ++aBegin1, --aEnd; - return std::equal( - aBegin, aEnd, aBegin1, - boost::bind(lcl_isImmediatelyFollowing, _1, _2, aWhich)); -} - - -static void -lcl_fillRangeFromRefList( - const deque& rReferences, ScRange& rRange) -{ - const ScSingleRefData aStart( - SingleDoubleRefProvider(*rReferences.front()).Ref1); - rRange.aStart.Set(aStart.nCol, aStart.nRow, aStart.nTab); - const ScSingleRefData aEnd( - SingleDoubleRefProvider(*rReferences.back()).Ref2); - rRange.aEnd.Set(aEnd.nCol, aEnd.nRow, aEnd.nTab); -} - - -static bool -lcl_refListFormsOneRange( - const ScAddress& aPos, deque& rReferences, - ScRange& rRange) -{ - std::for_each( - rReferences.begin(), rReferences.end(), - bind(&ScToken::CalcAbsIfRel, _1, aPos)) - ; - if (rReferences.size() == 1) { - lcl_fillRangeFromRefList(rReferences, rRange); - return true; - } - - bool bCell(false); - bool bRow(false); - bool bTab(false); - if (lcl_checkRangeDimensions(rReferences.begin(), rReferences.end(), - bCell, bRow, bTab)) - { - DimensionSelector aWhich; - if (bCell) - { - aWhich = lcl_GetCol; - } - else if (bRow) - { - aWhich = lcl_GetRow; - } - else if (bTab) - { - aWhich = lcl_GetTab; - } - else - { - OSL_FAIL( "lcl_checkRangeDimensions shouldn't allow that!"); - aWhich = lcl_GetRow; // initialize to avoid warning - } - // Sort the references by start of range - std::sort(rReferences.begin(), rReferences.end(), - boost::bind(lcl_lessReferenceBy, _1, _2, aWhich)); - if (lcl_checkIfAdjacent(rReferences, aWhich)) - { - lcl_fillRangeFromRefList(rReferences, rRange); - return true; - } - } - return false; -} - - -bool lcl_isReference(const FormulaToken& rToken) -{ - return - rToken.GetType() == svSingleRef || - rToken.GetType() == svDoubleRef; -} - -} - -bool ScFormulaCell::IsEmpty() -{ - MaybeInterpret(); - return aResult.GetCellResultType() == formula::svEmptyCell; -} - -bool ScFormulaCell::IsEmptyDisplayedAsString() -{ - MaybeInterpret(); - return aResult.IsEmptyDisplayedAsString(); -} - -bool ScFormulaCell::IsValue() -{ - MaybeInterpret(); - return aResult.IsValue(); -} - -bool ScFormulaCell::IsHybridValueCell() -{ - return aResult.GetType() == formula::svHybridValueCell; -} - -double ScFormulaCell::GetValue() -{ - MaybeInterpret(); - if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) && - !aResult.GetResultError()) - return aResult.GetDouble(); - return 0.0; -} - -double ScFormulaCell::GetValueAlways() -{ - // for goal seek: return result value even if error code is set - MaybeInterpret(); - return aResult.GetDouble(); -} - -rtl::OUString ScFormulaCell::GetString() -{ - MaybeInterpret(); - if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) && - !aResult.GetResultError()) - return aResult.GetString(); - return rtl::OUString(); -} - -const ScMatrix* ScFormulaCell::GetMatrix() -{ - if ( pDocument->GetAutoCalc() ) - { - if( IsDirtyOrInTableOpDirty() - // Was stored !bDirty but an accompanying matrix cell was bDirty? - || (!bDirty && cMatrixFlag == MM_FORMULA && !aResult.GetMatrix())) - Interpret(); - } - return aResult.GetMatrix().get(); -} - -bool ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const -{ - switch ( cMatrixFlag ) - { - case MM_FORMULA : - rPos = aPos; - return true; - case MM_REFERENCE : - { - pCode->Reset(); - ScToken* t = static_cast(pCode->GetNextReferenceRPN()); - if( t ) - { - ScSingleRefData& rRef = t->GetSingleRef(); - rRef.CalcAbsIfRel( aPos ); - if ( rRef.Valid() ) - { - rPos.Set( rRef.nCol, rRef.nRow, rRef.nTab ); - return true; - } - } - } - break; - } - return false; -} - - -/* - Edge-Values: - - 8 - 4 16 - 2 - - inside: 1 - outside: 0 - (reserved: open: 32) - */ - -sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos ) -{ - switch ( cMatrixFlag ) - { - case MM_FORMULA : - case MM_REFERENCE : - { - static SCCOL nC; - static SCROW nR; - ScAddress aOrg; - if ( !GetMatrixOrigin( aOrg ) ) - return 0; // bad luck.. - if ( aOrg != rOrgPos ) - { // First time or a different matrix than last time. - rOrgPos = aOrg; - ScFormulaCell* pFCell; - if ( cMatrixFlag == MM_REFERENCE ) - pFCell = pDocument->GetFormulaCell(aOrg); - else - pFCell = this; // this MM_FORMULA - // There's only one this, don't compare pFCell==this. - if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA - && pFCell->cMatrixFlag == MM_FORMULA ) - { - pFCell->GetMatColsRows( nC, nR ); - if ( nC == 0 || nR == 0 ) - { - // No ScMatrixFormulaCellToken available yet, calculate new. - nC = 1; - nR = 1; - ScAddress aTmpOrg; - ScFormulaCell* pCell; - ScAddress aAdr( aOrg ); - aAdr.IncCol(); - bool bCont = true; - do - { - pCell = pDocument->GetFormulaCell(aAdr); - if (pCell && pCell->cMatrixFlag == MM_REFERENCE && - pCell->GetMatrixOrigin(aTmpOrg) && aTmpOrg == aOrg) - { - nC++; - aAdr.IncCol(); - } - else - bCont = false; - } while ( bCont ); - aAdr = aOrg; - aAdr.IncRow(); - bCont = true; - do - { - pCell = pDocument->GetFormulaCell(aAdr); - if (pCell && pCell->cMatrixFlag == MM_REFERENCE && - pCell->GetMatrixOrigin(aTmpOrg) && aTmpOrg == aOrg) - { - nR++; - aAdr.IncRow(); - } - else - bCont = false; - } while ( bCont ); - pFCell->SetMatColsRows( nC, nR ); - } - } - else - { -#if OSL_DEBUG_LEVEL > 0 - rtl::OUString aTmp; - rtl::OStringBuffer aMsg(RTL_CONSTASCII_STRINGPARAM( - "broken Matrix, no MatFormula at origin, Pos: ")); - aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); - aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_ASCII_US)); - aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatOrg: ")); - aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); - aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_ASCII_US)); - OSL_FAIL(aMsg.getStr()); -#endif - return 0; // bad luck ... - } - } - // here we are, healthy and clean, somewhere in between - SCsCOL dC = aPos.Col() - aOrg.Col(); - SCsROW dR = aPos.Row() - aOrg.Row(); - sal_uInt16 nEdges = 0; - if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR ) - { - if ( dC == 0 ) - nEdges |= 4; // left edge - if ( dC+1 == nC ) - nEdges |= 16; // right edge - if ( dR == 0 ) - nEdges |= 8; // top edge - if ( dR+1 == nR ) - nEdges |= 2; // bottom edge - if ( !nEdges ) - nEdges = 1; // inside - } -#if OSL_DEBUG_LEVEL > 0 - else - { - rtl::OUString aTmp; - rtl::OStringBuffer aMsg( "broken Matrix, Pos: " ); - aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); - aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8 )); - aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatOrg: ")); - aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); - aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8 )); - aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatCols: ")); - aMsg.append(static_cast( nC )); - aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatRows: ")); - aMsg.append(static_cast( nR )); - aMsg.append(RTL_CONSTASCII_STRINGPARAM(", DiffCols: ")); - aMsg.append(static_cast( dC )); - aMsg.append(RTL_CONSTASCII_STRINGPARAM(", DiffRows: ")); - aMsg.append(static_cast( dR )); - OSL_FAIL( aMsg.makeStringAndClear().getStr()); - } -#endif - return nEdges; -// break; - } - default: - return 0; - } -} - -sal_uInt16 ScFormulaCell::GetErrCode() -{ - MaybeInterpret(); - - /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors - * and not also abused for signaling other error conditions we could bail - * out even before attempting to interpret broken code. */ - sal_uInt16 nErr = pCode->GetCodeError(); - if (nErr) - return nErr; - return aResult.GetResultError(); -} - -sal_uInt16 ScFormulaCell::GetRawError() -{ - sal_uInt16 nErr = pCode->GetCodeError(); - if (nErr) - return nErr; - return aResult.GetResultError(); -} - -bool ScFormulaCell::HasOneReference( ScRange& r ) const -{ - pCode->Reset(); - ScToken* p = static_cast(pCode->GetNextReferenceRPN()); - if( p && !pCode->GetNextReferenceRPN() ) // only one! - { - p->CalcAbsIfRel( aPos ); - SingleDoubleRefProvider aProv( *p ); - r.aStart.Set( aProv.Ref1.nCol, - aProv.Ref1.nRow, - aProv.Ref1.nTab ); - r.aEnd.Set( aProv.Ref2.nCol, - aProv.Ref2.nRow, - aProv.Ref2.nTab ); - return true; - } - else - return false; -} - -bool -ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const -{ - /* If there appears just one reference in the formula, it's the same - as HasOneReference(). If there are more of them, they can denote - one range if they are (sole) arguments of one function. - Union of these references must form one range and their - intersection must be empty set. - */ - - // Detect the simple case of exactly one reference in advance without all - // overhead. - // #i107741# Doing so actually makes outlines using SUBTOTAL(x;reference) - // work again, where the function does not have only references. - if (HasOneReference( rRange)) - return true; - - pCode->Reset(); - // Get first reference, if any - ScToken* const pFirstReference( - dynamic_cast(pCode->GetNextReferenceRPN())); - if (pFirstReference) - { - // Collect all consecutive references, starting by the one - // already found - std::deque aReferences; - aReferences.push_back(pFirstReference); - FormulaToken* pToken(pCode->NextRPN()); - FormulaToken* pFunction(0); - while (pToken) - { - if (lcl_isReference(*pToken)) - { - aReferences.push_back(dynamic_cast(pToken)); - pToken = pCode->NextRPN(); - } - else - { - if (pToken->IsFunction()) - { - pFunction = pToken; - } - break; - } - } - if (pFunction && !pCode->GetNextReferenceRPN() - && (pFunction->GetParamCount() == aReferences.size())) - { - return lcl_refListFormsOneRange(aPos, aReferences, rRange); - } - } - return false; -} - -bool ScFormulaCell::HasRelNameReference() const -{ - pCode->Reset(); - ScToken* t; - while ( ( t = static_cast(pCode->GetNextReferenceRPN()) ) != NULL ) - { - if ( t->GetSingleRef().IsRelName() || - (t->GetType() == formula::svDoubleRef && - t->GetDoubleRef().Ref2.IsRelName()) ) - return true; - } - return false; -} - -bool ScFormulaCell::HasColRowName() const -{ - pCode->Reset(); - return (pCode->GetNextColRowName() != NULL); -} - -bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode, - const ScRange& r, - SCsCOL nDx, SCsROW nDy, SCsTAB nDz, - ScDocument* pUndoDoc, const ScAddress* pUndoCellPos ) -{ - bool bCellStateChanged = false; - - SCCOL nCol1 = r.aStart.Col(); - SCROW nRow1 = r.aStart.Row(); - SCCOL nCol = aPos.Col(); - SCROW nRow = aPos.Row(); - SCTAB nTab = aPos.Tab(); - ScAddress aUndoPos( aPos ); // position for undo cell in pUndoDoc - if ( pUndoCellPos ) - aUndoPos = *pUndoCellPos; - ScAddress aOldPos( aPos ); -// bool bPosChanged = false; // if this cell was moved - bool bIsInsert = (eUpdateRefMode == URM_INSDEL && - nDx >= 0 && nDy >= 0 && nDz >= 0); - if (eUpdateRefMode == URM_INSDEL && r.In( aPos )) - { - aPos.Move(nDx, nDy, nDz); - bCellStateChanged = aPos != aOldPos; - } - else if ( r.In( aPos ) ) - { - aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz ); - } - - bool bHasRefs = false; - bool bHasColRowNames = false; - bool bOnRefMove = false; - if ( !pDocument->IsClipOrUndo() ) - { - pCode->Reset(); - bHasRefs = (pCode->GetNextReferenceRPN() != NULL); - if ( !bHasRefs || eUpdateRefMode == URM_COPY ) - { - pCode->Reset(); - bHasColRowNames = (pCode->GetNextColRowName() != NULL); - bHasRefs = bHasRefs || bHasColRowNames; - } - bOnRefMove = pCode->IsRecalcModeOnRefMove(); - } - if( bHasRefs || bOnRefMove ) - { - ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL; - ScRangeData* pRangeData; - bool bValChanged = false; - bool bRangeModified = false; // any range, not only shared formula - bool bRefSizeChanged = false; - if ( bHasRefs ) - { - ScCompiler aComp(pDocument, aPos, *pCode); - aComp.SetGrammar(pDocument->GetGrammar()); - pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, r, - nDx, nDy, nDz, - bValChanged, bRefSizeChanged); - bRangeModified = aComp.HasModifiedRange(); - } - else - { - bValChanged = false; - pRangeData = NULL; - bRangeModified = false; - bRefSizeChanged = false; - } - - bCellStateChanged |= bValChanged; - - if ( bOnRefMove ) - bOnRefMove = (bValChanged || (aPos != aOldPos)); - // Cell may reference itself, e.g. ocColumn, ocRow without parameter - - bool bColRowNameCompile, bHasRelName, bNewListening, bInDeleteUndo; - if ( bHasRefs ) - { - // Upon Insert ColRowNames have to be recompiled in case the - // insertion occurs right in front of the range. - bColRowNameCompile = - (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0)); - if ( bColRowNameCompile ) - { - bColRowNameCompile = false; - ScToken* t; - ScRangePairList* pColList = pDocument->GetColNameRanges(); - ScRangePairList* pRowList = pDocument->GetRowNameRanges(); - pCode->Reset(); - while ( !bColRowNameCompile && (t = static_cast(pCode->GetNextColRowName())) != NULL ) - { - ScSingleRefData& rRef = t->GetSingleRef(); - if ( nDy > 0 && rRef.IsColRel() ) - { // ColName - rRef.CalcAbsIfRel( aPos ); - ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab ); - ScRangePair* pR = pColList->Find( aAdr ); - if ( pR ) - { // defined - if ( pR->GetRange(1).aStart.Row() == nRow1 ) - bColRowNameCompile = true; - } - else - { // on the fly - if ( rRef.nRow + 1 == nRow1 ) - bColRowNameCompile = true; - } - } - if ( nDx > 0 && rRef.IsRowRel() ) - { // RowName - rRef.CalcAbsIfRel( aPos ); - ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab ); - ScRangePair* pR = pRowList->Find( aAdr ); - if ( pR ) - { // defined - if ( pR->GetRange(1).aStart.Col() == nCol1 ) - bColRowNameCompile = true; - } - else - { // on the fly - if ( rRef.nCol + 1 == nCol1 ) - bColRowNameCompile = true; - } - } - } - } - else if ( eUpdateRefMode == URM_MOVE ) - { // Recomplie for Move/D&D when ColRowName was moved or this Cell - // points to one and was moved. - bColRowNameCompile = bCompile; // Possibly from Copy ctor - if ( !bColRowNameCompile ) - { - bool bMoved = (aPos != aOldPos); - pCode->Reset(); - ScToken* t = static_cast(pCode->GetNextColRowName()); - if ( t && bMoved ) - bColRowNameCompile = true; - while ( t && !bColRowNameCompile ) - { - ScSingleRefData& rRef = t->GetSingleRef(); - rRef.CalcAbsIfRel( aPos ); - if ( rRef.Valid() ) - { - ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab ); - if ( r.In( aAdr ) ) - bColRowNameCompile = true; - } - t = static_cast(pCode->GetNextColRowName()); - } - } - } - else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged ) - { - bColRowNameCompile = true; - } - ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack(); - if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() ) - bInDeleteUndo = true; - else - bInDeleteUndo = false; - // RelNameRefs are always moved - bHasRelName = HasRelNameReference(); - // Reference changed and new listening needed? - // Except in Insert/Delete without specialties. - bNewListening = (bRangeModified || pRangeData || bColRowNameCompile - || (bValChanged && (eUpdateRefMode != URM_INSDEL || - bInDeleteUndo || bRefSizeChanged)) || - (bHasRelName && eUpdateRefMode != URM_COPY)) - // #i36299# Don't duplicate action during cut&paste / drag&drop - // on a cell in the range moved, start/end listeners is done - // via ScDocument::DeleteArea() and ScDocument::CopyFromClip(). - && !(eUpdateRefMode == URM_MOVE && - pDocument->IsInsertingFromOtherDoc() && r.In(aPos)); - if ( bNewListening ) - EndListeningTo( pDocument, pOld, aOldPos ); - } - else - { - bColRowNameCompile = bHasRelName = bNewListening = bInDeleteUndo = - false; - } - - bool bNeedDirty = false; - // NeedDirty for changes except for Copy and Move/Insert without RelNames - if ( bRangeModified || pRangeData || bColRowNameCompile || - (bValChanged && eUpdateRefMode != URM_COPY && - (eUpdateRefMode != URM_MOVE || bHasRelName) && - (!bIsInsert || bHasRelName || bInDeleteUndo || - bRefSizeChanged)) || bOnRefMove) - bNeedDirty = true; - else - bNeedDirty = false; - if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove)) - { - // Copy the cell to aUndoPos, which is its current position in the document, - // so this works when UpdateReference is called before moving the cells - // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference - // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed). - - // If there is already a formula cell in the undo document, don't overwrite it, - // the first (oldest) is the important cell. - if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA ) - { - ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos, - pOld, eTempGrammar, cMatrixFlag ); - pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!) - pUndoDoc->PutCell( aUndoPos, pFCell ); - } - } - bValChanged = false; - if ( pRangeData ) - { // Replace shared formula with own formula - pDocument->RemoveFromFormulaTree( this ); // update formula count - delete pCode; - pCode = pRangeData->GetCode()->Clone(); - // #i18937# #i110008# call MoveRelWrap, but with the old position - ScCompiler::MoveRelWrap(*pCode, pDocument, aOldPos, pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); - ScCompiler aComp2(pDocument, aPos, *pCode); - aComp2.SetGrammar(pDocument->GetGrammar()); - aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r, - nDx, nDy, nDz ); - bValChanged = true; - bNeedDirty = true; - } - if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 ) - { - CompileTokenArray( bNewListening ); // no Listening - bNeedDirty = true; - } - if ( !bInDeleteUndo ) - { // In ChangeTrack Delete-Reject listeners are established in - // InsertCol/InsertRow - if ( bNewListening ) - { - if ( eUpdateRefMode == URM_INSDEL ) - { - // Inserts/Deletes re-establish listeners after all - // UpdateReference calls. - // All replaced shared formula listeners have to be - // established after an Insert or Delete. Do nothing here. - SetNeedsListening( true); - } - else - StartListeningTo( pDocument ); - } - } - if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) ) - { // Cut off references, invalid or similar? - bool bOldAutoCalc = pDocument->GetAutoCalc(); - // No Interpret in SubMinimalRecalc because of eventual wrong reference - pDocument->SetAutoCalc( false ); - SetDirty(); - pDocument->SetAutoCalc( bOldAutoCalc ); - } - - delete pOld; - } - return bCellStateChanged; -} - -void ScFormulaCell::UpdateInsertTab(SCTAB nTable, SCTAB nNewSheets) -{ - bool bPosChanged = ( aPos.Tab() >= nTable ? true : false ); - pCode->Reset(); - if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() ) - { - EndListeningTo( pDocument ); - // IncTab _after_ EndListeningTo and _before_ Compiler UpdateInsertTab! - if ( bPosChanged ) - aPos.IncTab(nNewSheets); - ScRangeData* pRangeData; - ScCompiler aComp(pDocument, aPos, *pCode); - aComp.SetGrammar(pDocument->GetGrammar()); - pRangeData = aComp.UpdateInsertTab( nTable, false, nNewSheets ); - if (pRangeData) // Exchange Shared Formula with real Formula - { - bool bRefChanged; - pDocument->RemoveFromFormulaTree( this ); // update formula count - delete pCode; - pCode = new ScTokenArray( *pRangeData->GetCode() ); - ScCompiler aComp2(pDocument, aPos, *pCode); - aComp2.SetGrammar(pDocument->GetGrammar()); - aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); - aComp2.UpdateInsertTab( nTable, false, nNewSheets ); - // If the shared formula contained a named range/formula containing - // an absolute reference to a sheet, those have to be readjusted. - aComp2.UpdateDeleteTab( nTable, false, true, bRefChanged, nNewSheets ); - bCompile = true; - } - // no StartListeningTo because pTab[nTab] does not exsist! - } - else if ( bPosChanged ) - aPos.IncTab(); -} - -bool ScFormulaCell::UpdateDeleteTab(SCTAB nTable, bool bIsMove, SCTAB nSheets) -{ - bool bRefChanged = false; - bool bPosChanged = ( aPos.Tab() >= nTable + nSheets ? true : false ); - pCode->Reset(); - if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() ) - { - EndListeningTo( pDocument ); - // IncTab _after_ EndListeningTo und _before_ Compiler UpdateDeleteTab! - if ( bPosChanged ) - aPos.IncTab(-1*nSheets); - ScRangeData* pRangeData; - ScCompiler aComp(pDocument, aPos, *pCode); - aComp.SetGrammar(pDocument->GetGrammar()); - pRangeData = aComp.UpdateDeleteTab(nTable, bIsMove, false, bRefChanged, nSheets); - if (pRangeData) // Exchange Shared Formula with real Formula - { - pDocument->RemoveFromFormulaTree( this ); // update formula count - delete pCode; - pCode = pRangeData->GetCode()->Clone(); - ScCompiler aComp2(pDocument, aPos, *pCode); - aComp2.SetGrammar(pDocument->GetGrammar()); - aComp2.CompileTokenArray(); - aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); - aComp2.UpdateDeleteTab( nTable, false, false, bRefChanged, nSheets ); - // If the shared formula contained a named range/formula containing - // an absolute reference to a sheet, those have to be readjusted. - aComp2.UpdateInsertTab( nTable,true, nSheets ); - // bRefChanged could have been reset at the last UpdateDeleteTab - bRefChanged = true; - bCompile = true; - } - // no StartListeningTo because pTab[nTab] not yet correct! - } - else if ( bPosChanged ) - aPos.IncTab(-1*nSheets); - - return bRefChanged; -} - -void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo ) -{ - pCode->Reset(); - if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() ) - { - EndListeningTo( pDocument ); - // SetTab _after_ EndListeningTo und _before_ Compiler UpdateMoveTab ! - aPos.SetTab( nTabNo ); - ScRangeData* pRangeData; - ScCompiler aComp(pDocument, aPos, *pCode); - aComp.SetGrammar(pDocument->GetGrammar()); - pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, false ); - if (pRangeData) // Exchange Shared Formula with real Formula - { - pDocument->RemoveFromFormulaTree( this ); // update formula count - delete pCode; - pCode = pRangeData->GetCode()->Clone(); - ScCompiler aComp2(pDocument, aPos, *pCode); - aComp2.SetGrammar(pDocument->GetGrammar()); - aComp2.CompileTokenArray(); - aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); - aComp2.UpdateMoveTab( nOldPos, nNewPos, true ); - bCompile = true; - } - // no StartListeningTo because pTab[nTab] not yet correct! - } - else - aPos.SetTab( nTabNo ); -} - -void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable) -{ - if( !pDocument->IsClipOrUndo() ) - { - pCode->Reset(); - ScToken* p = static_cast(pCode->GetNextReferenceRPN()); - while( p ) - { - ScSingleRefData& rRef1 = p->GetSingleRef(); - if( !rRef1.IsTabRel() && (SCsTAB) nTable <= rRef1.nTab ) - rRef1.nTab++; - if( p->GetType() == formula::svDoubleRef ) - { - ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2; - if( !rRef2.IsTabRel() && (SCsTAB) nTable <= rRef2.nTab ) - rRef2.nTab++; - } - p = static_cast(pCode->GetNextReferenceRPN()); - } - } -} - -bool ScFormulaCell::TestTabRefAbs(SCTAB nTable) -{ - bool bRet = false; - if( !pDocument->IsClipOrUndo() ) - { - pCode->Reset(); - ScToken* p = static_cast(pCode->GetNextReferenceRPN()); - while( p ) - { - ScSingleRefData& rRef1 = p->GetSingleRef(); - if( !rRef1.IsTabRel() ) - { - if( (SCsTAB) nTable != rRef1.nTab ) - bRet = true; - else if (nTable != aPos.Tab()) - rRef1.nTab = aPos.Tab(); - } - if( p->GetType() == formula::svDoubleRef ) - { - ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2; - if( !rRef2.IsTabRel() ) - { - if( (SCsTAB) nTable != rRef2.nTab ) - bRet = true; - else if (nTable != aPos.Tab()) - rRef2.nTab = aPos.Tab(); - } - } - p = static_cast(pCode->GetNextReferenceRPN()); - } - } - return bRet; -} - -void ScFormulaCell::UpdateCompile( bool bForceIfNameInUse ) -{ - if ( bForceIfNameInUse && !bCompile ) - bCompile = pCode->HasNameOrColRowName(); - if ( bCompile ) - pCode->SetCodeError( 0 ); // make sure it will really be compiled - CompileTokenArray(); -} - -// Reference transposition is only called in Clipboard Document -void ScFormulaCell::TransposeReference() -{ - bool bFound = false; - pCode->Reset(); - ScToken* t; - while ( ( t = static_cast(pCode->GetNextReference()) ) != NULL ) - { - ScSingleRefData& rRef1 = t->GetSingleRef(); - if ( rRef1.IsColRel() && rRef1.IsRowRel() ) - { - bool bDouble = (t->GetType() == formula::svDoubleRef); - ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1); - if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) ) - { - sal_Int16 nTemp; - - nTemp = rRef1.nRelCol; - rRef1.nRelCol = static_cast(rRef1.nRelRow); - rRef1.nRelRow = static_cast(nTemp); - - if ( bDouble ) - { - nTemp = rRef2.nRelCol; - rRef2.nRelCol = static_cast(rRef2.nRelRow); - rRef2.nRelRow = static_cast(nTemp); - } - - bFound = true; - } - } - } - - if (bFound) - bCompile = true; -} - -void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, - ScDocument* pUndoDoc ) -{ - EndListeningTo( pDocument ); - - ScAddress aOldPos = aPos; - bool bPosChanged = false; // Whether this cell has been moved - - ScRange aDestRange( rDest, ScAddress( - static_cast(rDest.Col() + rSource.aEnd.Row() - rSource.aStart.Row()), - static_cast(rDest.Row() + rSource.aEnd.Col() - rSource.aStart.Col()), - rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) ); - if ( aDestRange.In( aOldPos ) ) - { - // Count back Positions - SCsCOL nRelPosX = aOldPos.Col(); - SCsROW nRelPosY = aOldPos.Row(); - SCsTAB nRelPosZ = aOldPos.Tab(); - ScRefUpdate::DoTranspose( nRelPosX, nRelPosY, nRelPosZ, pDocument, aDestRange, rSource.aStart ); - aOldPos.Set( nRelPosX, nRelPosY, nRelPosZ ); - bPosChanged = true; - } - - ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL; - bool bRefChanged = false; - ScToken* t; - - ScRangeData* pShared = NULL; - pCode->Reset(); - while( (t = static_cast(pCode->GetNextReferenceOrName())) != NULL ) - { - if( t->GetOpCode() == ocName ) - { - ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() ); - if (pName) - { - if (pName->IsModified()) - bRefChanged = true; - if (pName->HasType(RT_SHAREDMOD)) - pShared = pName; - } - } - else if( t->GetType() != svIndex ) - { - t->CalcAbsIfRel( aOldPos ); - bool bMod; - { // Own scope for SingleDoubleRefModifier dtor if SingleRef - SingleDoubleRefModifier aMod( *t ); - ScComplexRefData& rRef = aMod.Ref(); - bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource, - rDest, rRef ) != UR_NOTHING || bPosChanged); - } - if ( bMod ) - { - t->CalcRelFromAbs( aPos ); - bRefChanged = true; - } - } - } - - if (pShared) // Exchange Shared Formula with real Formula - { - pDocument->RemoveFromFormulaTree( this ); // update formula count - delete pCode; - pCode = new ScTokenArray( *pShared->GetCode() ); - bRefChanged = true; - pCode->Reset(); - while( (t = static_cast(pCode->GetNextReference())) != NULL ) - { - if( t->GetType() != svIndex ) - { - t->CalcAbsIfRel( aOldPos ); - bool bMod; - { // Own scope for SingleDoubleRefModifier dtor if SingleRef - SingleDoubleRefModifier aMod( *t ); - ScComplexRefData& rRef = aMod.Ref(); - bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource, - rDest, rRef ) != UR_NOTHING || bPosChanged); - } - if ( bMod ) - t->CalcRelFromAbs( aPos ); - } - } - } - - if (bRefChanged) - { - if (pUndoDoc) - { - ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aPos, pOld, - eTempGrammar, cMatrixFlag); - pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!) - pUndoDoc->SetFormulaCell(aPos, pFCell); - } - - bCompile = true; - CompileTokenArray(); // also call StartListeningTo - SetDirty(); - } - else - StartListeningTo( pDocument ); // Listener as previous - - delete pOld; -} - -void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) -{ - EndListeningTo( pDocument ); - - bool bRefChanged = false; - ScToken* t; - ScRangeData* pShared = NULL; - - pCode->Reset(); - while( (t = static_cast(pCode->GetNextReferenceOrName())) != NULL ) - { - if( t->GetOpCode() == ocName ) - { - ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() ); - if (pName) - { - if (pName->IsModified()) - bRefChanged = true; - if (pName->HasType(RT_SHAREDMOD)) - pShared = pName; - } - } - else if( t->GetType() != svIndex ) - { - t->CalcAbsIfRel( aPos ); - bool bMod; - { // Own scope for SingleDoubleRefModifier dtor if SingleRef - SingleDoubleRefModifier aMod( *t ); - ScComplexRefData& rRef = aMod.Ref(); - bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, - rRef ) != UR_NOTHING); - } - if ( bMod ) - { - t->CalcRelFromAbs( aPos ); - bRefChanged = true; - } - } - } - - if (pShared) // Exchange Shared Formula with real Formula - { - pDocument->RemoveFromFormulaTree( this ); // Update formula count - delete pCode; - pCode = new ScTokenArray( *pShared->GetCode() ); - bRefChanged = true; - pCode->Reset(); - while( (t = static_cast(pCode->GetNextReference())) != NULL ) - { - if( t->GetType() != svIndex ) - { - t->CalcAbsIfRel( aPos ); - bool bMod; - { // Own scope for SingleDoubleRefModifier dtor if SingleRef - SingleDoubleRefModifier aMod( *t ); - ScComplexRefData& rRef = aMod.Ref(); - bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, - rRef ) != UR_NOTHING); - } - if ( bMod ) - t->CalcRelFromAbs( aPos ); - } - } - } - - if (bRefChanged) - { - bCompile = true; - CompileTokenArray(); // Also call StartListeningTo - SetDirty(); - } - else - StartListeningTo( pDocument ); // Listener as previous -} - -static void lcl_FindRangeNamesInUse(std::set& rIndexes, ScTokenArray* pCode, ScRangeName* pNames) -{ - for (FormulaToken* p = pCode->First(); p; p = pCode->Next()) - { - if (p->GetOpCode() == ocName) - { - sal_uInt16 nTokenIndex = p->GetIndex(); - rIndexes.insert( nTokenIndex ); - - ScRangeData* pSubName = pNames->findByIndex(p->GetIndex()); - if (pSubName) - lcl_FindRangeNamesInUse(rIndexes, pSubName->GetCode(), pNames); - } - } -} - -void ScFormulaCell::FindRangeNamesInUse(std::set& rIndexes) const -{ - lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() ); -} - -bool ScFormulaCell::IsChanged() const -{ - return bChanged; -} - -void ScFormulaCell::ResetChanged() -{ - bChanged = false; -} - -void ScFormulaCell::CompileDBFormula() -{ - for( FormulaToken* p = pCode->First(); p; p = pCode->Next() ) - { - if ( p->GetOpCode() == ocDBArea - || (p->GetOpCode() == ocName && p->GetIndex() >= SC_START_INDEX_DB_COLL) ) - { - bCompile = true; - CompileTokenArray(); - SetDirty(); - break; - } - } -} - -void ScFormulaCell::CompileDBFormula( bool bCreateFormulaString ) -{ - // Two phases must be called after each other - // 1. Formula String with old generated names - // 2. Formula String with new generated names - if ( bCreateFormulaString ) - { - bool bRecompile = false; - pCode->Reset(); - for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() ) - { - switch ( p->GetOpCode() ) - { - case ocBad: // DB Area eventually goes bad - case ocColRowName: // in case of the same names - case ocDBArea: // DB Area - bRecompile = true; - break; - case ocName: - if ( p->GetIndex() >= SC_START_INDEX_DB_COLL ) - bRecompile = true; // DB Area - break; - default: - ; // nothing - } - } - if ( bRecompile ) - { - rtl::OUString aFormula; - GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); - if ( GetMatrixFlag() != MM_NONE && !aFormula.isEmpty() ) - { - if ( aFormula[ aFormula.getLength()-1 ] == '}' ) - aFormula = aFormula.copy( 0, aFormula.getLength()-1 ); - if ( aFormula[0] == '{' ) - aFormula = aFormula.copy( 1 ); - } - EndListeningTo( pDocument ); - pDocument->RemoveFromFormulaTree( this ); - pCode->Clear(); - SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); - } - } - else if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() ) - { - Compile( aResult.GetHybridFormula(), false, eTempGrammar ); - aResult.SetToken( NULL); - SetDirty(); - } -} - -void ScFormulaCell::CompileNameFormula( bool bCreateFormulaString ) -{ - // Two phases must be called after each other - // 1. Formula String with old generated names - // 2. Formula String with new generated names - if ( bCreateFormulaString ) - { - bool bRecompile = false; - pCode->Reset(); - for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() ) - { - switch ( p->GetOpCode() ) - { - case ocBad: // in case RangeName goes bad - case ocColRowName: // in case the names are the same - bRecompile = true; - break; - default: - if ( p->GetType() == svIndex ) - bRecompile = true; // RangeName - } - } - if ( bRecompile ) - { - rtl::OUString aFormula; - GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); - if ( GetMatrixFlag() != MM_NONE && !aFormula.isEmpty() ) - { - if ( aFormula[ aFormula.getLength()-1 ] == '}' ) - aFormula = aFormula.copy( 0, aFormula.getLength()-1 ); - if ( aFormula[0] == '{' ) - aFormula = aFormula.copy( 1 ); - } - EndListeningTo( pDocument ); - pDocument->RemoveFromFormulaTree( this ); - pCode->Clear(); - SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); - } - } - else if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() ) - { - Compile( aResult.GetHybridFormula(), false, eTempGrammar ); - aResult.SetToken( NULL); - SetDirty(); - } -} - -void ScFormulaCell::CompileColRowNameFormula() -{ - pCode->Reset(); - for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() ) - { - if ( p->GetOpCode() == ocColRowName ) - { - bCompile = true; - CompileTokenArray(); - SetDirty(); - break; - } - } -} - -// we really want to be a lot more descriptive than this -struct ScSimilarFormulaDelta : std::vector< size_t > -{ - bool IsCompatible( ScSimilarFormulaDelta *pDelta ) - { - if ( size() != pDelta->size() ) - return false; - for ( size_t i = 0; i < size(); i++ ) - { - if ( (*this)[ i ] != (*pDelta)[ i ] ) - return false; - } - return true; - } - - void push_delta( const ScSingleRefData& a, const ScSingleRefData& b ) - { - push_back( b.nCol - a.nCol ); - push_back( b.nRow - a.nRow ); - push_back( b.nTab - a.nTab ); - } - - /// if the vector is zero then nothing changes down the column. - bool IsInvariant() const - { - for ( size_t i = 0; i < size(); i++ ) - { - if ( (*this)[ i ] != 0 ) - return false; - } - return true; - } -}; - -bool ScFormulaCellGroup::IsCompatible( ScSimilarFormulaDelta *pDelta ) -{ - return pDelta && mpDelta && mpDelta->IsCompatible( pDelta ); -} - -/// compare formulae tokens and build a series of deltas describing -/// the difference - ie. the result, when added to this -/// formulae should produce pOther -ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell ) -{ - // no Matrix formulae yet. - if ( GetMatrixFlag() != MM_NONE ) - return NULL; - - // are these formule at all similar ? - if ( GetHash() != pOtherCell->GetHash() ) - return NULL; - - FormulaToken **pThis = pCode->GetCode(); - sal_uInt16 pThisLen = pCode->GetCodeLen(); - FormulaToken **pOther = pOtherCell->pCode->GetCode(); - sal_uInt16 pOtherLen = pOtherCell->pCode->GetCodeLen(); - - if ( !pThis || !pOther ) - { -// fprintf( stderr, "Error: no compiled code for cells !" ); - return NULL; - } - - if ( pThisLen != pOtherLen ) - return NULL; - - // check we are basically the same function - for ( sal_uInt16 i = 0; i < pThisLen; i++ ) - { - if ( pThis[ i ]->GetType() != pOther[ i ]->GetType() || - pThis[ i ]->GetOpCode() != pOther[ i ]->GetOpCode() || - pThis[ i ]->GetParamCount() != pOther[ i ]->GetParamCount() ) - { -// fprintf( stderr, "Incompatible type, op-code or param counts\n" ); - return NULL; - } - switch( pThis[ i ]->GetType() ) - { - case formula::svMatrix: - case formula::svExternalSingleRef: - case formula::svExternalDoubleRef: -// fprintf( stderr, "Ignoring matrix and external references for now\n" ); - return NULL; - default: - break; - } - } - - ScSimilarFormulaDelta *pDelta = new ScSimilarFormulaDelta(); - - for ( sal_uInt16 i = 0; i < pThisLen; i++ ) - { - ScToken *pThisTok = static_cast< ScToken * >( pThis[ i ] ); - ScToken *pOtherTok = static_cast< ScToken * >( pOther[ i ] ); - - if ( pThis[i]->GetType() == formula::svSingleRef || - pThis[i]->GetType() == formula::svDoubleRef ) - { - const ScSingleRefData& aThisRef = pThisTok->GetSingleRef(); - const ScSingleRefData& aOtherRef = pOtherTok->GetSingleRef(); - pDelta->push_delta( aThisRef, aOtherRef ); - } - if ( pThis[i]->GetType() == formula::svDoubleRef ) - { - const ScSingleRefData& aThisRef2 = pThisTok->GetSingleRef2(); - const ScSingleRefData& aOtherRef2 = pOtherTok->GetSingleRef2(); - pDelta->push_delta( aThisRef2, aOtherRef2 ); - } - } - - return pDelta; -} - -/// To avoid exposing impl. details of ScSimilarFormulaDelta publicly -void ScFormulaCell::ReleaseDelta( ScSimilarFormulaDelta *pDelta ) -{ - delete pDelta; -} - -bool ScFormulaCell::InterpretFormulaGroup() -{ - // Re-build formulae groups if necessary - ideally this is done at - // import / insert / delete etc. and is integral to the data structures - pDocument->RebuildFormulaGroups(); - - if( !xGroup.get() ) - return false; - -// fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() ); - - if ( xGroup->mpDelta->IsInvariant() ) - { -// fprintf( stderr, "struck gold - completely invariant for %d items !\n", -// (int)xGroup->mnLength ); - - // calculate ourselves: - InterpretTail( SCITP_NORMAL ); - for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ ) - { - ScAddress aTmpPos = aPos; - aTmpPos.SetRow(xGroup->mnStart + i); - ScFormulaCell* pCell = pDocument->GetFormulaCell(aTmpPos); - assert( pCell != NULL ); - - // FIXME: this set of horrors is unclear to me ... certainly - // the above GetCell is profoundly nasty & slow ... - - // Ensure the cell truly has a result: - pCell->aResult = aResult; - pCell->ResetDirty(); - - // FIXME: there is a view / refresh missing here it appears. - } - return true; - } - else - { - // scan the formula ... - // have a document method: "Get2DRangeAsDoublesArray" that does the - // column-based heavy lifting call it for each absolute range from the - // first cell pos in the formula group. - // - // Project single references to ranges by adding their vector * xGroup->mnLength - // - // TODO: - // elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>) - // produces a diagonal 'column' that serves no useful purpose for us. - // these should be very rare. Should elide in GetDeltas anyway and - // assert here. - // - // Having built our input data ... - // Throw it, and the formula over to some 'OpenCLCalculage' hook - // - // on return - release references on these double buffers - // - // transfer the result to the formula cells (as above) - // store the doubles in the columns' maDoubles array for - // dependent formulae - // - // TODO: - // need to abort/fail when we get errors returned and fallback to - // stock interpreting [ I guess ], unless we can use NaN etc. to - // signal errors. - - return false; - } -} - -void ScFormulaCell::StartListeningTo( ScDocument* pDoc ) -{ - if (pDoc->IsClipOrUndo() || pDoc->GetNoListening() || IsInChangeTrack()) - return; - - pDoc->SetDetectiveDirty(true); // It has changed something - - ScTokenArray* pArr = GetCode(); - if( pArr->IsRecalcModeAlways() ) - { - pDoc->StartListeningArea(BCA_LISTEN_ALWAYS, this); - SetNeedsListening( false); - return; - } - - pArr->Reset(); - ScToken* t; - while ( ( t = static_cast(pArr->GetNextReferenceRPN()) ) != NULL ) - { - StackVar eType = t->GetType(); - ScSingleRefData& rRef1 = t->GetSingleRef(); - ScSingleRefData& rRef2 = (eType == svDoubleRef ? - t->GetDoubleRef().Ref2 : rRef1); - switch( eType ) - { - case svSingleRef: - rRef1.CalcAbsIfRel(aPos); - if ( rRef1.Valid() ) - { - pDoc->StartListeningCell( - ScAddress( rRef1.nCol, - rRef1.nRow, - rRef1.nTab ), this ); - } - break; - case svDoubleRef: - t->CalcAbsIfRel(aPos); - if ( rRef1.Valid() && rRef2.Valid() ) - { - if ( t->GetOpCode() == ocColRowNameAuto ) - { // automagically - if ( rRef1.IsColRel() ) - { // ColName - pDoc->StartListeningArea( ScRange ( - rRef1.nCol, - rRef1.nRow, - rRef1.nTab, - rRef2.nCol, - MAXROW, - rRef2.nTab ), this ); - } - else - { // RowName - pDoc->StartListeningArea( ScRange ( - rRef1.nCol, - rRef1.nRow, - rRef1.nTab, - MAXCOL, - rRef2.nRow, - rRef2.nTab ), this ); - } - } - else - { - pDoc->StartListeningArea( ScRange ( - rRef1.nCol, - rRef1.nRow, - rRef1.nTab, - rRef2.nCol, - rRef2.nRow, - rRef2.nTab ), this ); - } - } - break; - default: - ; // nothing - } - } - SetNeedsListening( false); -} - -// pArr gesetzt -> Referenzen von anderer Zelle nehmen -// Then aPos must also be commited - -void ScFormulaCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr, - ScAddress aCellPos ) -{ - if (pDoc->IsClipOrUndo() || IsInChangeTrack()) - return; - - pDoc->SetDetectiveDirty(true); // It has changed something - - if ( GetCode()->IsRecalcModeAlways() ) - { - pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, this ); - return; - } - - if (!pArr) - { - pArr = GetCode(); - aCellPos = aPos; - } - pArr->Reset(); - ScToken* t; - while ( ( t = static_cast(pArr->GetNextReferenceRPN()) ) != NULL ) - { - StackVar eType = t->GetType(); - ScSingleRefData& rRef1 = t->GetSingleRef(); - ScSingleRefData& rRef2 = (eType == svDoubleRef ? - t->GetDoubleRef().Ref2 : rRef1); - switch( eType ) - { - case svSingleRef: - rRef1.CalcAbsIfRel( aCellPos ); - if ( rRef1.Valid() ) - { - pDoc->EndListeningCell( - ScAddress( rRef1.nCol, - rRef1.nRow, - rRef1.nTab ), this ); - } - break; - case svDoubleRef: - t->CalcAbsIfRel( aCellPos ); - if ( rRef1.Valid() && rRef2.Valid() ) - { - if ( t->GetOpCode() == ocColRowNameAuto ) - { // automagically - if ( rRef1.IsColRel() ) - { // ColName - pDoc->EndListeningArea( ScRange ( - rRef1.nCol, - rRef1.nRow, - rRef1.nTab, - rRef2.nCol, - MAXROW, - rRef2.nTab ), this ); - } - else - { // RowName - pDoc->EndListeningArea( ScRange ( - rRef1.nCol, - rRef1.nRow, - rRef1.nTab, - MAXCOL, - rRef2.nRow, - rRef2.nTab ), this ); - } - } - else - { - pDoc->EndListeningArea( ScRange ( - rRef1.nCol, - rRef1.nRow, - rRef1.nTab, - rRef2.nCol, - rRef2.nRow, - rRef2.nTab ), this ); - } - } - break; - default: - ; // nothing - } - } -} - -// ============================================================================ - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx index 7ef5bda45a84..c287f10e1fb5 100644 --- a/sc/source/core/data/cellvalue.cxx +++ b/sc/source/core/data/cellvalue.cxx @@ -10,6 +10,7 @@ #include "cellvalue.hxx" #include "document.hxx" #include "cell.hxx" +#include "formulacell.hxx" #include "editeng/editobj.hxx" #include "editeng/editstat.hxx" #include "stringutil.hxx" diff --git a/sc/source/core/data/colorscale.cxx b/sc/source/core/data/colorscale.cxx index f7d3493e83c5..c9aa3cbc86ae 100644 --- a/sc/source/core/data/colorscale.cxx +++ b/sc/source/core/data/colorscale.cxx @@ -28,7 +28,7 @@ #include "colorscale.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "fillinfo.hxx" #include "iconsets.hrc" #include "scresid.hxx" diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 1712fbe04b1c..c04619210baf 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -20,6 +20,7 @@ #include "column.hxx" #include "scitems.hxx" #include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "docpool.hxx" #include "attarray.hxx" diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index e4a9931a256f..2e878e28b280 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -37,6 +37,7 @@ #include "column.hxx" #include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "docpool.hxx" #include "attarray.hxx" diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 9bd0ee9400f8..bd7586e963d1 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -29,6 +29,7 @@ #include "scitems.hxx" #include "column.hxx" #include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "attarray.hxx" #include "patattr.hxx" @@ -2089,15 +2090,6 @@ xub_StrLen ScColumn::GetMaxNumberStringLen( return nStringLen; } - -ScFormulaCellGroup::ScFormulaCellGroup() -{ -} - -ScFormulaCellGroup::~ScFormulaCellGroup() -{ -} - // Very[!] slow way to look for and merge contiguous runs // of similar formulae into a formulagroup void ScColumn::RebuildFormulaGroups() diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx index 0ce3088eddb1..237c7f08da68 100644 --- a/sc/source/core/data/conditio.cxx +++ b/sc/source/core/data/conditio.cxx @@ -27,7 +27,7 @@ #include #include "conditio.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "hints.hxx" #include "compiler.hxx" diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index 187551893717..553c38f2aa5d 100644 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -26,6 +26,7 @@ #include "table.hxx" #include "column.hxx" #include "cell.hxx" +#include "formulacell.hxx" #include "attarray.hxx" #include "patattr.hxx" #include "docoptio.hxx" diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 90cc920dbd32..bc6174018dfe 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -85,6 +85,7 @@ #include "clipparam.hxx" #include "macromgr.hxx" #include "cell.hxx" +#include "formulacell.hxx" using namespace com::sun::star; diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index 3196b2e446d3..07bc970136dd 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -69,6 +69,7 @@ #include "sheetevents.hxx" #include "colorscale.hxx" #include "queryentry.hxx" +#include "formulacell.hxx" #include "globalnames.hxx" #include diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx index 27fd9fa7a8ff..6dfad050c071 100644 --- a/sc/source/core/data/documen4.cxx +++ b/sc/source/core/data/documen4.cxx @@ -42,6 +42,7 @@ #include "colorscale.hxx" #include "attrib.hxx" #include "cell.hxx" +#include "formulacell.hxx" using namespace formula; diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx index 96ebc365279d..85c3cf9061c1 100644 --- a/sc/source/core/data/documen7.cxx +++ b/sc/source/core/data/documen7.cxx @@ -23,6 +23,7 @@ #include "brdcst.hxx" #include "bcaslot.hxx" #include "cell.hxx" +#include "formulacell.hxx" #include "formula/errorcodes.hxx" // errCircularReference #include "scerrors.hxx" #include "docoptio.hxx" diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 9aa8e6a3bfae..81ca67618e2d 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -89,6 +89,7 @@ #include "editutil.hxx" #include "stringutil.hxx" #include "formulaiter.hxx" +#include "formulacell.hxx" #include #include diff --git a/sc/source/core/data/dpfilteredcache.cxx b/sc/source/core/data/dpfilteredcache.cxx index 0df77891f40e..64381e07ea78 100644 --- a/sc/source/core/data/dpfilteredcache.cxx +++ b/sc/source/core/data/dpfilteredcache.cxx @@ -20,7 +20,7 @@ #include "dpfilteredcache.hxx" #include "document.hxx" #include "address.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "dptabdat.hxx" #include "dptabsrc.hxx" #include "dpobject.hxx" diff --git a/sc/source/core/data/dpitemdata.cxx b/sc/source/core/data/dpitemdata.cxx index 4c04106f20eb..a2d7bb74fb1e 100644 --- a/sc/source/core/data/dpitemdata.cxx +++ b/sc/source/core/data/dpitemdata.cxx @@ -21,7 +21,7 @@ #include "document.hxx" #include "dpobject.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "globstr.hrc" #include "dptabdat.hxx" #include "rtl/math.hxx" diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx index ccf4659cdf94..f1cf22735dcd 100644 --- a/sc/source/core/data/dpshttab.cxx +++ b/sc/source/core/data/dpshttab.cxx @@ -22,7 +22,7 @@ #include "dpshttab.hxx" #include "dptabres.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "dpfilteredcache.hxx" #include "dpobject.hxx" #include "globstr.hrc" diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx index 20ff80b3a391..91dcacc363e2 100644 --- a/sc/source/core/data/dptabsrc.cxx +++ b/sc/source/core/data/dptabsrc.cxx @@ -34,7 +34,7 @@ #include "document.hxx" #include "docpool.hxx" #include "patattr.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "dptabres.hxx" #include "dptabdat.hxx" diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx index 5a04751839af..1e37c6deaa9e 100644 --- a/sc/source/core/data/fillinfo.cxx +++ b/sc/source/core/data/fillinfo.cxx @@ -27,7 +27,7 @@ #include "fillinfo.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "table.hxx" #include "attrib.hxx" #include "attarray.hxx" diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx new file mode 100644 index 000000000000..00912d2f51e7 --- /dev/null +++ b/sc/source/core/data/formulacell.cxx @@ -0,0 +1,3208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "formulacell.hxx" + +#include "compiler.hxx" +#include "document.hxx" +#include "globalnames.hxx" +#include "cellvalue.hxx" +#include "interpre.hxx" +#include "macromgr.hxx" +#include "refupdat.hxx" +#include "recursionhelper.hxx" +#include "docoptio.hxx" +#include "rangenam.hxx" +#include "dbdata.hxx" +#include "progress.hxx" +#include "scmatrix.hxx" +#include "rechead.hxx" +#include "scitems.hxx" +#include "validat.hxx" +#include "editutil.hxx" +#include "chgtrack.hxx" + +#include "formula/errorcodes.hxx" +#include "svl/intitem.hxx" + +#include + +using namespace formula; + +#ifdef USE_MEMPOOL +IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell ) +#endif + +namespace { + +// 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; + +using std::deque; + +typedef SCCOLROW(*DimensionSelector)(const ScSingleRefData&); + + +static SCCOLROW lcl_GetCol(const ScSingleRefData& rData) +{ + return rData.nCol; +} + + +static SCCOLROW lcl_GetRow(const ScSingleRefData& rData) +{ + return rData.nRow; +} + + +static SCCOLROW lcl_GetTab(const ScSingleRefData& rData) +{ + return rData.nTab; +} + + +/** Check if both references span the same range in selected dimension. + */ +static bool +lcl_checkRangeDimension( + const SingleDoubleRefProvider& rRef1, + const SingleDoubleRefProvider& rRef2, + const DimensionSelector aWhich) +{ + return + aWhich(rRef1.Ref1) == aWhich(rRef2.Ref1) + && aWhich(rRef1.Ref2) == aWhich(rRef2.Ref2); +} + + +static bool +lcl_checkRangeDimensions( + const SingleDoubleRefProvider& rRef1, + const SingleDoubleRefProvider& rRef2, + bool& bCol, bool& bRow, bool& bTab) +{ + const bool bSameCols(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetCol)); + const bool bSameRows(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetRow)); + const bool bSameTabs(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetTab)); + + // Test if exactly two dimensions are equal + if (!(bSameCols ^ bSameRows ^ bSameTabs) + && (bSameCols || bSameRows || bSameTabs)) + { + bCol = !bSameCols; + bRow = !bSameRows; + bTab = !bSameTabs; + return true; + } + return false; +} + + +/** Check if references in given reference list can possibly + form a range. To do that, two of their dimensions must be the same. + */ +static bool +lcl_checkRangeDimensions( + const deque::const_iterator aBegin, + const deque::const_iterator aEnd, + bool& bCol, bool& bRow, bool& bTab) +{ + deque::const_iterator aCur(aBegin); + ++aCur; + const SingleDoubleRefProvider aRef(**aBegin); + bool bOk(false); + { + const SingleDoubleRefProvider aRefCur(**aCur); + bOk = lcl_checkRangeDimensions(aRef, aRefCur, bCol, bRow, bTab); + } + while (bOk && aCur != aEnd) + { + const SingleDoubleRefProvider aRefCur(**aCur); + bool bColTmp(false); + bool bRowTmp(false); + bool bTabTmp(false); + bOk = lcl_checkRangeDimensions(aRef, aRefCur, bColTmp, bRowTmp, bTabTmp); + bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp); + ++aCur; + } + + if (bOk && aCur == aEnd) + { + return true; + } + return false; +} + + +bool +lcl_lessReferenceBy( + const ScToken* const pRef1, const ScToken* const pRef2, + const DimensionSelector aWhich) +{ + const SingleDoubleRefProvider rRef1(*pRef1); + const SingleDoubleRefProvider rRef2(*pRef2); + return aWhich(rRef1.Ref1) < aWhich(rRef2.Ref1); +} + + +/** Returns true if range denoted by token pRef2 starts immediately after + range denoted by token pRef1. Dimension, in which the comparison takes + place, is given by aWhich. + */ +bool +lcl_isImmediatelyFollowing( + const ScToken* const pRef1, const ScToken* const pRef2, + const DimensionSelector aWhich) +{ + const SingleDoubleRefProvider rRef1(*pRef1); + const SingleDoubleRefProvider rRef2(*pRef2); + return aWhich(rRef2.Ref1) - aWhich(rRef1.Ref2) == 1; +} + + +static bool +lcl_checkIfAdjacent( + const deque& rReferences, + const DimensionSelector aWhich) +{ + typedef deque::const_iterator Iter; + Iter aBegin(rReferences.begin()); + Iter aEnd(rReferences.end()); + Iter aBegin1(aBegin); + ++aBegin1, --aEnd; + return std::equal( + aBegin, aEnd, aBegin1, + boost::bind(lcl_isImmediatelyFollowing, _1, _2, aWhich)); +} + + +static void +lcl_fillRangeFromRefList( + const deque& rReferences, ScRange& rRange) +{ + const ScSingleRefData aStart( + SingleDoubleRefProvider(*rReferences.front()).Ref1); + rRange.aStart.Set(aStart.nCol, aStart.nRow, aStart.nTab); + const ScSingleRefData aEnd( + SingleDoubleRefProvider(*rReferences.back()).Ref2); + rRange.aEnd.Set(aEnd.nCol, aEnd.nRow, aEnd.nTab); +} + + +static bool +lcl_refListFormsOneRange( + const ScAddress& aPos, deque& rReferences, + ScRange& rRange) +{ + std::for_each( + rReferences.begin(), rReferences.end(), + bind(&ScToken::CalcAbsIfRel, _1, aPos)) + ; + if (rReferences.size() == 1) { + lcl_fillRangeFromRefList(rReferences, rRange); + return true; + } + + bool bCell(false); + bool bRow(false); + bool bTab(false); + if (lcl_checkRangeDimensions(rReferences.begin(), rReferences.end(), + bCell, bRow, bTab)) + { + DimensionSelector aWhich; + if (bCell) + { + aWhich = lcl_GetCol; + } + else if (bRow) + { + aWhich = lcl_GetRow; + } + else if (bTab) + { + aWhich = lcl_GetTab; + } + else + { + OSL_FAIL( "lcl_checkRangeDimensions shouldn't allow that!"); + aWhich = lcl_GetRow; // initialize to avoid warning + } + // Sort the references by start of range + std::sort(rReferences.begin(), rReferences.end(), + boost::bind(lcl_lessReferenceBy, _1, _2, aWhich)); + if (lcl_checkIfAdjacent(rReferences, aWhich)) + { + lcl_fillRangeFromRefList(rReferences, rRange); + return true; + } + } + return false; +} + + +bool lcl_isReference(const FormulaToken& rToken) +{ + return + rToken.GetType() == svSingleRef || + rToken.GetType() == svDoubleRef; +} + +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(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()); +} + +} + +ScFormulaCellGroup::ScFormulaCellGroup() +{ +} + +ScFormulaCellGroup::~ScFormulaCellGroup() +{ +} + +// ============================================================================ + +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(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(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(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(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 ); +} + +bool ScFormulaCell::IsEmpty() +{ + MaybeInterpret(); + return aResult.GetCellResultType() == formula::svEmptyCell; +} + +bool ScFormulaCell::IsEmptyDisplayedAsString() +{ + MaybeInterpret(); + return aResult.IsEmptyDisplayedAsString(); +} + +bool ScFormulaCell::IsValue() +{ + MaybeInterpret(); + return aResult.IsValue(); +} + +bool ScFormulaCell::IsHybridValueCell() +{ + return aResult.GetType() == formula::svHybridValueCell; +} + +double ScFormulaCell::GetValue() +{ + MaybeInterpret(); + if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) && + !aResult.GetResultError()) + return aResult.GetDouble(); + return 0.0; +} + +double ScFormulaCell::GetValueAlways() +{ + // for goal seek: return result value even if error code is set + MaybeInterpret(); + return aResult.GetDouble(); +} + +rtl::OUString ScFormulaCell::GetString() +{ + MaybeInterpret(); + if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) && + !aResult.GetResultError()) + return aResult.GetString(); + return rtl::OUString(); +} + +const ScMatrix* ScFormulaCell::GetMatrix() +{ + if ( pDocument->GetAutoCalc() ) + { + if( IsDirtyOrInTableOpDirty() + // Was stored !bDirty but an accompanying matrix cell was bDirty? + || (!bDirty && cMatrixFlag == MM_FORMULA && !aResult.GetMatrix())) + Interpret(); + } + return aResult.GetMatrix().get(); +} + +bool ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const +{ + switch ( cMatrixFlag ) + { + case MM_FORMULA : + rPos = aPos; + return true; + case MM_REFERENCE : + { + pCode->Reset(); + ScToken* t = static_cast(pCode->GetNextReferenceRPN()); + if( t ) + { + ScSingleRefData& rRef = t->GetSingleRef(); + rRef.CalcAbsIfRel( aPos ); + if ( rRef.Valid() ) + { + rPos.Set( rRef.nCol, rRef.nRow, rRef.nTab ); + return true; + } + } + } + break; + } + return false; +} + + +/* + Edge-Values: + + 8 + 4 16 + 2 + + inside: 1 + outside: 0 + (reserved: open: 32) + */ + +sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos ) +{ + switch ( cMatrixFlag ) + { + case MM_FORMULA : + case MM_REFERENCE : + { + static SCCOL nC; + static SCROW nR; + ScAddress aOrg; + if ( !GetMatrixOrigin( aOrg ) ) + return 0; // bad luck.. + if ( aOrg != rOrgPos ) + { // First time or a different matrix than last time. + rOrgPos = aOrg; + ScFormulaCell* pFCell; + if ( cMatrixFlag == MM_REFERENCE ) + pFCell = pDocument->GetFormulaCell(aOrg); + else + pFCell = this; // this MM_FORMULA + // There's only one this, don't compare pFCell==this. + if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA + && pFCell->cMatrixFlag == MM_FORMULA ) + { + pFCell->GetMatColsRows( nC, nR ); + if ( nC == 0 || nR == 0 ) + { + // No ScMatrixFormulaCellToken available yet, calculate new. + nC = 1; + nR = 1; + ScAddress aTmpOrg; + ScFormulaCell* pCell; + ScAddress aAdr( aOrg ); + aAdr.IncCol(); + bool bCont = true; + do + { + pCell = pDocument->GetFormulaCell(aAdr); + if (pCell && pCell->cMatrixFlag == MM_REFERENCE && + pCell->GetMatrixOrigin(aTmpOrg) && aTmpOrg == aOrg) + { + nC++; + aAdr.IncCol(); + } + else + bCont = false; + } while ( bCont ); + aAdr = aOrg; + aAdr.IncRow(); + bCont = true; + do + { + pCell = pDocument->GetFormulaCell(aAdr); + if (pCell && pCell->cMatrixFlag == MM_REFERENCE && + pCell->GetMatrixOrigin(aTmpOrg) && aTmpOrg == aOrg) + { + nR++; + aAdr.IncRow(); + } + else + bCont = false; + } while ( bCont ); + pFCell->SetMatColsRows( nC, nR ); + } + } + else + { +#if OSL_DEBUG_LEVEL > 0 + rtl::OUString aTmp; + rtl::OStringBuffer aMsg(RTL_CONSTASCII_STRINGPARAM( + "broken Matrix, no MatFormula at origin, Pos: ")); + aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); + aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_ASCII_US)); + aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatOrg: ")); + aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); + aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_ASCII_US)); + OSL_FAIL(aMsg.getStr()); +#endif + return 0; // bad luck ... + } + } + // here we are, healthy and clean, somewhere in between + SCsCOL dC = aPos.Col() - aOrg.Col(); + SCsROW dR = aPos.Row() - aOrg.Row(); + sal_uInt16 nEdges = 0; + if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR ) + { + if ( dC == 0 ) + nEdges |= 4; // left edge + if ( dC+1 == nC ) + nEdges |= 16; // right edge + if ( dR == 0 ) + nEdges |= 8; // top edge + if ( dR+1 == nR ) + nEdges |= 2; // bottom edge + if ( !nEdges ) + nEdges = 1; // inside + } +#if OSL_DEBUG_LEVEL > 0 + else + { + rtl::OUString aTmp; + rtl::OStringBuffer aMsg( "broken Matrix, Pos: " ); + aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); + aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8 )); + aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatOrg: ")); + aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument ); + aMsg.append(rtl::OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8 )); + aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatCols: ")); + aMsg.append(static_cast( nC )); + aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatRows: ")); + aMsg.append(static_cast( nR )); + aMsg.append(RTL_CONSTASCII_STRINGPARAM(", DiffCols: ")); + aMsg.append(static_cast( dC )); + aMsg.append(RTL_CONSTASCII_STRINGPARAM(", DiffRows: ")); + aMsg.append(static_cast( dR )); + OSL_FAIL( aMsg.makeStringAndClear().getStr()); + } +#endif + return nEdges; +// break; + } + default: + return 0; + } +} + +sal_uInt16 ScFormulaCell::GetErrCode() +{ + MaybeInterpret(); + + /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors + * and not also abused for signaling other error conditions we could bail + * out even before attempting to interpret broken code. */ + sal_uInt16 nErr = pCode->GetCodeError(); + if (nErr) + return nErr; + return aResult.GetResultError(); +} + +sal_uInt16 ScFormulaCell::GetRawError() +{ + sal_uInt16 nErr = pCode->GetCodeError(); + if (nErr) + return nErr; + return aResult.GetResultError(); +} + +bool ScFormulaCell::HasOneReference( ScRange& r ) const +{ + pCode->Reset(); + ScToken* p = static_cast(pCode->GetNextReferenceRPN()); + if( p && !pCode->GetNextReferenceRPN() ) // only one! + { + p->CalcAbsIfRel( aPos ); + SingleDoubleRefProvider aProv( *p ); + r.aStart.Set( aProv.Ref1.nCol, + aProv.Ref1.nRow, + aProv.Ref1.nTab ); + r.aEnd.Set( aProv.Ref2.nCol, + aProv.Ref2.nRow, + aProv.Ref2.nTab ); + return true; + } + else + return false; +} + +bool +ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const +{ + /* If there appears just one reference in the formula, it's the same + as HasOneReference(). If there are more of them, they can denote + one range if they are (sole) arguments of one function. + Union of these references must form one range and their + intersection must be empty set. + */ + + // Detect the simple case of exactly one reference in advance without all + // overhead. + // #i107741# Doing so actually makes outlines using SUBTOTAL(x;reference) + // work again, where the function does not have only references. + if (HasOneReference( rRange)) + return true; + + pCode->Reset(); + // Get first reference, if any + ScToken* const pFirstReference( + dynamic_cast(pCode->GetNextReferenceRPN())); + if (pFirstReference) + { + // Collect all consecutive references, starting by the one + // already found + std::deque aReferences; + aReferences.push_back(pFirstReference); + FormulaToken* pToken(pCode->NextRPN()); + FormulaToken* pFunction(0); + while (pToken) + { + if (lcl_isReference(*pToken)) + { + aReferences.push_back(dynamic_cast(pToken)); + pToken = pCode->NextRPN(); + } + else + { + if (pToken->IsFunction()) + { + pFunction = pToken; + } + break; + } + } + if (pFunction && !pCode->GetNextReferenceRPN() + && (pFunction->GetParamCount() == aReferences.size())) + { + return lcl_refListFormsOneRange(aPos, aReferences, rRange); + } + } + return false; +} + +bool ScFormulaCell::HasRelNameReference() const +{ + pCode->Reset(); + ScToken* t; + while ( ( t = static_cast(pCode->GetNextReferenceRPN()) ) != NULL ) + { + if ( t->GetSingleRef().IsRelName() || + (t->GetType() == formula::svDoubleRef && + t->GetDoubleRef().Ref2.IsRelName()) ) + return true; + } + return false; +} + +bool ScFormulaCell::HasColRowName() const +{ + pCode->Reset(); + return (pCode->GetNextColRowName() != NULL); +} + +bool ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode, + const ScRange& r, + SCsCOL nDx, SCsROW nDy, SCsTAB nDz, + ScDocument* pUndoDoc, const ScAddress* pUndoCellPos ) +{ + bool bCellStateChanged = false; + + SCCOL nCol1 = r.aStart.Col(); + SCROW nRow1 = r.aStart.Row(); + SCCOL nCol = aPos.Col(); + SCROW nRow = aPos.Row(); + SCTAB nTab = aPos.Tab(); + ScAddress aUndoPos( aPos ); // position for undo cell in pUndoDoc + if ( pUndoCellPos ) + aUndoPos = *pUndoCellPos; + ScAddress aOldPos( aPos ); +// bool bPosChanged = false; // if this cell was moved + bool bIsInsert = (eUpdateRefMode == URM_INSDEL && + nDx >= 0 && nDy >= 0 && nDz >= 0); + if (eUpdateRefMode == URM_INSDEL && r.In( aPos )) + { + aPos.Move(nDx, nDy, nDz); + bCellStateChanged = aPos != aOldPos; + } + else if ( r.In( aPos ) ) + { + aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz ); + } + + bool bHasRefs = false; + bool bHasColRowNames = false; + bool bOnRefMove = false; + if ( !pDocument->IsClipOrUndo() ) + { + pCode->Reset(); + bHasRefs = (pCode->GetNextReferenceRPN() != NULL); + if ( !bHasRefs || eUpdateRefMode == URM_COPY ) + { + pCode->Reset(); + bHasColRowNames = (pCode->GetNextColRowName() != NULL); + bHasRefs = bHasRefs || bHasColRowNames; + } + bOnRefMove = pCode->IsRecalcModeOnRefMove(); + } + if( bHasRefs || bOnRefMove ) + { + ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL; + ScRangeData* pRangeData; + bool bValChanged = false; + bool bRangeModified = false; // any range, not only shared formula + bool bRefSizeChanged = false; + if ( bHasRefs ) + { + ScCompiler aComp(pDocument, aPos, *pCode); + aComp.SetGrammar(pDocument->GetGrammar()); + pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, r, + nDx, nDy, nDz, + bValChanged, bRefSizeChanged); + bRangeModified = aComp.HasModifiedRange(); + } + else + { + bValChanged = false; + pRangeData = NULL; + bRangeModified = false; + bRefSizeChanged = false; + } + + bCellStateChanged |= bValChanged; + + if ( bOnRefMove ) + bOnRefMove = (bValChanged || (aPos != aOldPos)); + // Cell may reference itself, e.g. ocColumn, ocRow without parameter + + bool bColRowNameCompile, bHasRelName, bNewListening, bInDeleteUndo; + if ( bHasRefs ) + { + // Upon Insert ColRowNames have to be recompiled in case the + // insertion occurs right in front of the range. + bColRowNameCompile = + (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0)); + if ( bColRowNameCompile ) + { + bColRowNameCompile = false; + ScToken* t; + ScRangePairList* pColList = pDocument->GetColNameRanges(); + ScRangePairList* pRowList = pDocument->GetRowNameRanges(); + pCode->Reset(); + while ( !bColRowNameCompile && (t = static_cast(pCode->GetNextColRowName())) != NULL ) + { + ScSingleRefData& rRef = t->GetSingleRef(); + if ( nDy > 0 && rRef.IsColRel() ) + { // ColName + rRef.CalcAbsIfRel( aPos ); + ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab ); + ScRangePair* pR = pColList->Find( aAdr ); + if ( pR ) + { // defined + if ( pR->GetRange(1).aStart.Row() == nRow1 ) + bColRowNameCompile = true; + } + else + { // on the fly + if ( rRef.nRow + 1 == nRow1 ) + bColRowNameCompile = true; + } + } + if ( nDx > 0 && rRef.IsRowRel() ) + { // RowName + rRef.CalcAbsIfRel( aPos ); + ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab ); + ScRangePair* pR = pRowList->Find( aAdr ); + if ( pR ) + { // defined + if ( pR->GetRange(1).aStart.Col() == nCol1 ) + bColRowNameCompile = true; + } + else + { // on the fly + if ( rRef.nCol + 1 == nCol1 ) + bColRowNameCompile = true; + } + } + } + } + else if ( eUpdateRefMode == URM_MOVE ) + { // Recomplie for Move/D&D when ColRowName was moved or this Cell + // points to one and was moved. + bColRowNameCompile = bCompile; // Possibly from Copy ctor + if ( !bColRowNameCompile ) + { + bool bMoved = (aPos != aOldPos); + pCode->Reset(); + ScToken* t = static_cast(pCode->GetNextColRowName()); + if ( t && bMoved ) + bColRowNameCompile = true; + while ( t && !bColRowNameCompile ) + { + ScSingleRefData& rRef = t->GetSingleRef(); + rRef.CalcAbsIfRel( aPos ); + if ( rRef.Valid() ) + { + ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab ); + if ( r.In( aAdr ) ) + bColRowNameCompile = true; + } + t = static_cast(pCode->GetNextColRowName()); + } + } + } + else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged ) + { + bColRowNameCompile = true; + } + ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack(); + if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() ) + bInDeleteUndo = true; + else + bInDeleteUndo = false; + // RelNameRefs are always moved + bHasRelName = HasRelNameReference(); + // Reference changed and new listening needed? + // Except in Insert/Delete without specialties. + bNewListening = (bRangeModified || pRangeData || bColRowNameCompile + || (bValChanged && (eUpdateRefMode != URM_INSDEL || + bInDeleteUndo || bRefSizeChanged)) || + (bHasRelName && eUpdateRefMode != URM_COPY)) + // #i36299# Don't duplicate action during cut&paste / drag&drop + // on a cell in the range moved, start/end listeners is done + // via ScDocument::DeleteArea() and ScDocument::CopyFromClip(). + && !(eUpdateRefMode == URM_MOVE && + pDocument->IsInsertingFromOtherDoc() && r.In(aPos)); + if ( bNewListening ) + EndListeningTo( pDocument, pOld, aOldPos ); + } + else + { + bColRowNameCompile = bHasRelName = bNewListening = bInDeleteUndo = + false; + } + + bool bNeedDirty = false; + // NeedDirty for changes except for Copy and Move/Insert without RelNames + if ( bRangeModified || pRangeData || bColRowNameCompile || + (bValChanged && eUpdateRefMode != URM_COPY && + (eUpdateRefMode != URM_MOVE || bHasRelName) && + (!bIsInsert || bHasRelName || bInDeleteUndo || + bRefSizeChanged)) || bOnRefMove) + bNeedDirty = true; + else + bNeedDirty = false; + if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove)) + { + // Copy the cell to aUndoPos, which is its current position in the document, + // so this works when UpdateReference is called before moving the cells + // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference + // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed). + + // If there is already a formula cell in the undo document, don't overwrite it, + // the first (oldest) is the important cell. + if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA ) + { + ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos, + pOld, eTempGrammar, cMatrixFlag ); + pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!) + pUndoDoc->PutCell( aUndoPos, pFCell ); + } + } + bValChanged = false; + if ( pRangeData ) + { // Replace shared formula with own formula + pDocument->RemoveFromFormulaTree( this ); // update formula count + delete pCode; + pCode = pRangeData->GetCode()->Clone(); + // #i18937# #i110008# call MoveRelWrap, but with the old position + ScCompiler::MoveRelWrap(*pCode, pDocument, aOldPos, pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); + ScCompiler aComp2(pDocument, aPos, *pCode); + aComp2.SetGrammar(pDocument->GetGrammar()); + aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r, + nDx, nDy, nDz ); + bValChanged = true; + bNeedDirty = true; + } + if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 ) + { + CompileTokenArray( bNewListening ); // no Listening + bNeedDirty = true; + } + if ( !bInDeleteUndo ) + { // In ChangeTrack Delete-Reject listeners are established in + // InsertCol/InsertRow + if ( bNewListening ) + { + if ( eUpdateRefMode == URM_INSDEL ) + { + // Inserts/Deletes re-establish listeners after all + // UpdateReference calls. + // All replaced shared formula listeners have to be + // established after an Insert or Delete. Do nothing here. + SetNeedsListening( true); + } + else + StartListeningTo( pDocument ); + } + } + if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) ) + { // Cut off references, invalid or similar? + bool bOldAutoCalc = pDocument->GetAutoCalc(); + // No Interpret in SubMinimalRecalc because of eventual wrong reference + pDocument->SetAutoCalc( false ); + SetDirty(); + pDocument->SetAutoCalc( bOldAutoCalc ); + } + + delete pOld; + } + return bCellStateChanged; +} + +void ScFormulaCell::UpdateInsertTab(SCTAB nTable, SCTAB nNewSheets) +{ + bool bPosChanged = ( aPos.Tab() >= nTable ? true : false ); + pCode->Reset(); + if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() ) + { + EndListeningTo( pDocument ); + // IncTab _after_ EndListeningTo and _before_ Compiler UpdateInsertTab! + if ( bPosChanged ) + aPos.IncTab(nNewSheets); + ScRangeData* pRangeData; + ScCompiler aComp(pDocument, aPos, *pCode); + aComp.SetGrammar(pDocument->GetGrammar()); + pRangeData = aComp.UpdateInsertTab( nTable, false, nNewSheets ); + if (pRangeData) // Exchange Shared Formula with real Formula + { + bool bRefChanged; + pDocument->RemoveFromFormulaTree( this ); // update formula count + delete pCode; + pCode = new ScTokenArray( *pRangeData->GetCode() ); + ScCompiler aComp2(pDocument, aPos, *pCode); + aComp2.SetGrammar(pDocument->GetGrammar()); + aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); + aComp2.UpdateInsertTab( nTable, false, nNewSheets ); + // If the shared formula contained a named range/formula containing + // an absolute reference to a sheet, those have to be readjusted. + aComp2.UpdateDeleteTab( nTable, false, true, bRefChanged, nNewSheets ); + bCompile = true; + } + // no StartListeningTo because pTab[nTab] does not exsist! + } + else if ( bPosChanged ) + aPos.IncTab(); +} + +bool ScFormulaCell::UpdateDeleteTab(SCTAB nTable, bool bIsMove, SCTAB nSheets) +{ + bool bRefChanged = false; + bool bPosChanged = ( aPos.Tab() >= nTable + nSheets ? true : false ); + pCode->Reset(); + if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() ) + { + EndListeningTo( pDocument ); + // IncTab _after_ EndListeningTo und _before_ Compiler UpdateDeleteTab! + if ( bPosChanged ) + aPos.IncTab(-1*nSheets); + ScRangeData* pRangeData; + ScCompiler aComp(pDocument, aPos, *pCode); + aComp.SetGrammar(pDocument->GetGrammar()); + pRangeData = aComp.UpdateDeleteTab(nTable, bIsMove, false, bRefChanged, nSheets); + if (pRangeData) // Exchange Shared Formula with real Formula + { + pDocument->RemoveFromFormulaTree( this ); // update formula count + delete pCode; + pCode = pRangeData->GetCode()->Clone(); + ScCompiler aComp2(pDocument, aPos, *pCode); + aComp2.SetGrammar(pDocument->GetGrammar()); + aComp2.CompileTokenArray(); + aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); + aComp2.UpdateDeleteTab( nTable, false, false, bRefChanged, nSheets ); + // If the shared formula contained a named range/formula containing + // an absolute reference to a sheet, those have to be readjusted. + aComp2.UpdateInsertTab( nTable,true, nSheets ); + // bRefChanged could have been reset at the last UpdateDeleteTab + bRefChanged = true; + bCompile = true; + } + // no StartListeningTo because pTab[nTab] not yet correct! + } + else if ( bPosChanged ) + aPos.IncTab(-1*nSheets); + + return bRefChanged; +} + +void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo ) +{ + pCode->Reset(); + if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() ) + { + EndListeningTo( pDocument ); + // SetTab _after_ EndListeningTo und _before_ Compiler UpdateMoveTab ! + aPos.SetTab( nTabNo ); + ScRangeData* pRangeData; + ScCompiler aComp(pDocument, aPos, *pCode); + aComp.SetGrammar(pDocument->GetGrammar()); + pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, false ); + if (pRangeData) // Exchange Shared Formula with real Formula + { + pDocument->RemoveFromFormulaTree( this ); // update formula count + delete pCode; + pCode = pRangeData->GetCode()->Clone(); + ScCompiler aComp2(pDocument, aPos, *pCode); + aComp2.SetGrammar(pDocument->GetGrammar()); + aComp2.CompileTokenArray(); + aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); + aComp2.UpdateMoveTab( nOldPos, nNewPos, true ); + bCompile = true; + } + // no StartListeningTo because pTab[nTab] not yet correct! + } + else + aPos.SetTab( nTabNo ); +} + +void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable) +{ + if( !pDocument->IsClipOrUndo() ) + { + pCode->Reset(); + ScToken* p = static_cast(pCode->GetNextReferenceRPN()); + while( p ) + { + ScSingleRefData& rRef1 = p->GetSingleRef(); + if( !rRef1.IsTabRel() && (SCsTAB) nTable <= rRef1.nTab ) + rRef1.nTab++; + if( p->GetType() == formula::svDoubleRef ) + { + ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2; + if( !rRef2.IsTabRel() && (SCsTAB) nTable <= rRef2.nTab ) + rRef2.nTab++; + } + p = static_cast(pCode->GetNextReferenceRPN()); + } + } +} + +bool ScFormulaCell::TestTabRefAbs(SCTAB nTable) +{ + bool bRet = false; + if( !pDocument->IsClipOrUndo() ) + { + pCode->Reset(); + ScToken* p = static_cast(pCode->GetNextReferenceRPN()); + while( p ) + { + ScSingleRefData& rRef1 = p->GetSingleRef(); + if( !rRef1.IsTabRel() ) + { + if( (SCsTAB) nTable != rRef1.nTab ) + bRet = true; + else if (nTable != aPos.Tab()) + rRef1.nTab = aPos.Tab(); + } + if( p->GetType() == formula::svDoubleRef ) + { + ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2; + if( !rRef2.IsTabRel() ) + { + if( (SCsTAB) nTable != rRef2.nTab ) + bRet = true; + else if (nTable != aPos.Tab()) + rRef2.nTab = aPos.Tab(); + } + } + p = static_cast(pCode->GetNextReferenceRPN()); + } + } + return bRet; +} + +void ScFormulaCell::UpdateCompile( bool bForceIfNameInUse ) +{ + if ( bForceIfNameInUse && !bCompile ) + bCompile = pCode->HasNameOrColRowName(); + if ( bCompile ) + pCode->SetCodeError( 0 ); // make sure it will really be compiled + CompileTokenArray(); +} + +// Reference transposition is only called in Clipboard Document +void ScFormulaCell::TransposeReference() +{ + bool bFound = false; + pCode->Reset(); + ScToken* t; + while ( ( t = static_cast(pCode->GetNextReference()) ) != NULL ) + { + ScSingleRefData& rRef1 = t->GetSingleRef(); + if ( rRef1.IsColRel() && rRef1.IsRowRel() ) + { + bool bDouble = (t->GetType() == formula::svDoubleRef); + ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1); + if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) ) + { + sal_Int16 nTemp; + + nTemp = rRef1.nRelCol; + rRef1.nRelCol = static_cast(rRef1.nRelRow); + rRef1.nRelRow = static_cast(nTemp); + + if ( bDouble ) + { + nTemp = rRef2.nRelCol; + rRef2.nRelCol = static_cast(rRef2.nRelRow); + rRef2.nRelRow = static_cast(nTemp); + } + + bFound = true; + } + } + } + + if (bFound) + bCompile = true; +} + +void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, + ScDocument* pUndoDoc ) +{ + EndListeningTo( pDocument ); + + ScAddress aOldPos = aPos; + bool bPosChanged = false; // Whether this cell has been moved + + ScRange aDestRange( rDest, ScAddress( + static_cast(rDest.Col() + rSource.aEnd.Row() - rSource.aStart.Row()), + static_cast(rDest.Row() + rSource.aEnd.Col() - rSource.aStart.Col()), + rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) ); + if ( aDestRange.In( aOldPos ) ) + { + // Count back Positions + SCsCOL nRelPosX = aOldPos.Col(); + SCsROW nRelPosY = aOldPos.Row(); + SCsTAB nRelPosZ = aOldPos.Tab(); + ScRefUpdate::DoTranspose( nRelPosX, nRelPosY, nRelPosZ, pDocument, aDestRange, rSource.aStart ); + aOldPos.Set( nRelPosX, nRelPosY, nRelPosZ ); + bPosChanged = true; + } + + ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL; + bool bRefChanged = false; + ScToken* t; + + ScRangeData* pShared = NULL; + pCode->Reset(); + while( (t = static_cast(pCode->GetNextReferenceOrName())) != NULL ) + { + if( t->GetOpCode() == ocName ) + { + ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() ); + if (pName) + { + if (pName->IsModified()) + bRefChanged = true; + if (pName->HasType(RT_SHAREDMOD)) + pShared = pName; + } + } + else if( t->GetType() != svIndex ) + { + t->CalcAbsIfRel( aOldPos ); + bool bMod; + { // Own scope for SingleDoubleRefModifier dtor if SingleRef + SingleDoubleRefModifier aMod( *t ); + ScComplexRefData& rRef = aMod.Ref(); + bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource, + rDest, rRef ) != UR_NOTHING || bPosChanged); + } + if ( bMod ) + { + t->CalcRelFromAbs( aPos ); + bRefChanged = true; + } + } + } + + if (pShared) // Exchange Shared Formula with real Formula + { + pDocument->RemoveFromFormulaTree( this ); // update formula count + delete pCode; + pCode = new ScTokenArray( *pShared->GetCode() ); + bRefChanged = true; + pCode->Reset(); + while( (t = static_cast(pCode->GetNextReference())) != NULL ) + { + if( t->GetType() != svIndex ) + { + t->CalcAbsIfRel( aOldPos ); + bool bMod; + { // Own scope for SingleDoubleRefModifier dtor if SingleRef + SingleDoubleRefModifier aMod( *t ); + ScComplexRefData& rRef = aMod.Ref(); + bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource, + rDest, rRef ) != UR_NOTHING || bPosChanged); + } + if ( bMod ) + t->CalcRelFromAbs( aPos ); + } + } + } + + if (bRefChanged) + { + if (pUndoDoc) + { + ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aPos, pOld, + eTempGrammar, cMatrixFlag); + pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!) + pUndoDoc->SetFormulaCell(aPos, pFCell); + } + + bCompile = true; + CompileTokenArray(); // also call StartListeningTo + SetDirty(); + } + else + StartListeningTo( pDocument ); // Listener as previous + + delete pOld; +} + +void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) +{ + EndListeningTo( pDocument ); + + bool bRefChanged = false; + ScToken* t; + ScRangeData* pShared = NULL; + + pCode->Reset(); + while( (t = static_cast(pCode->GetNextReferenceOrName())) != NULL ) + { + if( t->GetOpCode() == ocName ) + { + ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() ); + if (pName) + { + if (pName->IsModified()) + bRefChanged = true; + if (pName->HasType(RT_SHAREDMOD)) + pShared = pName; + } + } + else if( t->GetType() != svIndex ) + { + t->CalcAbsIfRel( aPos ); + bool bMod; + { // Own scope for SingleDoubleRefModifier dtor if SingleRef + SingleDoubleRefModifier aMod( *t ); + ScComplexRefData& rRef = aMod.Ref(); + bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, + rRef ) != UR_NOTHING); + } + if ( bMod ) + { + t->CalcRelFromAbs( aPos ); + bRefChanged = true; + } + } + } + + if (pShared) // Exchange Shared Formula with real Formula + { + pDocument->RemoveFromFormulaTree( this ); // Update formula count + delete pCode; + pCode = new ScTokenArray( *pShared->GetCode() ); + bRefChanged = true; + pCode->Reset(); + while( (t = static_cast(pCode->GetNextReference())) != NULL ) + { + if( t->GetType() != svIndex ) + { + t->CalcAbsIfRel( aPos ); + bool bMod; + { // Own scope for SingleDoubleRefModifier dtor if SingleRef + SingleDoubleRefModifier aMod( *t ); + ScComplexRefData& rRef = aMod.Ref(); + bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY, + rRef ) != UR_NOTHING); + } + if ( bMod ) + t->CalcRelFromAbs( aPos ); + } + } + } + + if (bRefChanged) + { + bCompile = true; + CompileTokenArray(); // Also call StartListeningTo + SetDirty(); + } + else + StartListeningTo( pDocument ); // Listener as previous +} + +static void lcl_FindRangeNamesInUse(std::set& rIndexes, ScTokenArray* pCode, ScRangeName* pNames) +{ + for (FormulaToken* p = pCode->First(); p; p = pCode->Next()) + { + if (p->GetOpCode() == ocName) + { + sal_uInt16 nTokenIndex = p->GetIndex(); + rIndexes.insert( nTokenIndex ); + + ScRangeData* pSubName = pNames->findByIndex(p->GetIndex()); + if (pSubName) + lcl_FindRangeNamesInUse(rIndexes, pSubName->GetCode(), pNames); + } + } +} + +void ScFormulaCell::FindRangeNamesInUse(std::set& rIndexes) const +{ + lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() ); +} + +bool ScFormulaCell::IsChanged() const +{ + return bChanged; +} + +void ScFormulaCell::ResetChanged() +{ + bChanged = false; +} + +void ScFormulaCell::CompileDBFormula() +{ + for( FormulaToken* p = pCode->First(); p; p = pCode->Next() ) + { + if ( p->GetOpCode() == ocDBArea + || (p->GetOpCode() == ocName && p->GetIndex() >= SC_START_INDEX_DB_COLL) ) + { + bCompile = true; + CompileTokenArray(); + SetDirty(); + break; + } + } +} + +void ScFormulaCell::CompileDBFormula( bool bCreateFormulaString ) +{ + // Two phases must be called after each other + // 1. Formula String with old generated names + // 2. Formula String with new generated names + if ( bCreateFormulaString ) + { + bool bRecompile = false; + pCode->Reset(); + for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() ) + { + switch ( p->GetOpCode() ) + { + case ocBad: // DB Area eventually goes bad + case ocColRowName: // in case of the same names + case ocDBArea: // DB Area + bRecompile = true; + break; + case ocName: + if ( p->GetIndex() >= SC_START_INDEX_DB_COLL ) + bRecompile = true; // DB Area + break; + default: + ; // nothing + } + } + if ( bRecompile ) + { + rtl::OUString aFormula; + GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); + if ( GetMatrixFlag() != MM_NONE && !aFormula.isEmpty() ) + { + if ( aFormula[ aFormula.getLength()-1 ] == '}' ) + aFormula = aFormula.copy( 0, aFormula.getLength()-1 ); + if ( aFormula[0] == '{' ) + aFormula = aFormula.copy( 1 ); + } + EndListeningTo( pDocument ); + pDocument->RemoveFromFormulaTree( this ); + pCode->Clear(); + SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); + } + } + else if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() ) + { + Compile( aResult.GetHybridFormula(), false, eTempGrammar ); + aResult.SetToken( NULL); + SetDirty(); + } +} + +void ScFormulaCell::CompileNameFormula( bool bCreateFormulaString ) +{ + // Two phases must be called after each other + // 1. Formula String with old generated names + // 2. Formula String with new generated names + if ( bCreateFormulaString ) + { + bool bRecompile = false; + pCode->Reset(); + for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() ) + { + switch ( p->GetOpCode() ) + { + case ocBad: // in case RangeName goes bad + case ocColRowName: // in case the names are the same + bRecompile = true; + break; + default: + if ( p->GetType() == svIndex ) + bRecompile = true; // RangeName + } + } + if ( bRecompile ) + { + rtl::OUString aFormula; + GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); + if ( GetMatrixFlag() != MM_NONE && !aFormula.isEmpty() ) + { + if ( aFormula[ aFormula.getLength()-1 ] == '}' ) + aFormula = aFormula.copy( 0, aFormula.getLength()-1 ); + if ( aFormula[0] == '{' ) + aFormula = aFormula.copy( 1 ); + } + EndListeningTo( pDocument ); + pDocument->RemoveFromFormulaTree( this ); + pCode->Clear(); + SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE); + } + } + else if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() ) + { + Compile( aResult.GetHybridFormula(), false, eTempGrammar ); + aResult.SetToken( NULL); + SetDirty(); + } +} + +void ScFormulaCell::CompileColRowNameFormula() +{ + pCode->Reset(); + for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() ) + { + if ( p->GetOpCode() == ocColRowName ) + { + bCompile = true; + CompileTokenArray(); + SetDirty(); + break; + } + } +} + +// we really want to be a lot more descriptive than this +struct ScSimilarFormulaDelta : std::vector< size_t > +{ + bool IsCompatible( ScSimilarFormulaDelta *pDelta ) + { + if ( size() != pDelta->size() ) + return false; + for ( size_t i = 0; i < size(); i++ ) + { + if ( (*this)[ i ] != (*pDelta)[ i ] ) + return false; + } + return true; + } + + void push_delta( const ScSingleRefData& a, const ScSingleRefData& b ) + { + push_back( b.nCol - a.nCol ); + push_back( b.nRow - a.nRow ); + push_back( b.nTab - a.nTab ); + } + + /// if the vector is zero then nothing changes down the column. + bool IsInvariant() const + { + for ( size_t i = 0; i < size(); i++ ) + { + if ( (*this)[ i ] != 0 ) + return false; + } + return true; + } +}; + +bool ScFormulaCellGroup::IsCompatible( ScSimilarFormulaDelta *pDelta ) +{ + return pDelta && mpDelta && mpDelta->IsCompatible( pDelta ); +} + +/// compare formulae tokens and build a series of deltas describing +/// the difference - ie. the result, when added to this +/// formulae should produce pOther +ScSimilarFormulaDelta *ScFormulaCell::BuildDeltaTo( ScFormulaCell *pOtherCell ) +{ + // no Matrix formulae yet. + if ( GetMatrixFlag() != MM_NONE ) + return NULL; + + // are these formule at all similar ? + if ( GetHash() != pOtherCell->GetHash() ) + return NULL; + + FormulaToken **pThis = pCode->GetCode(); + sal_uInt16 pThisLen = pCode->GetCodeLen(); + FormulaToken **pOther = pOtherCell->pCode->GetCode(); + sal_uInt16 pOtherLen = pOtherCell->pCode->GetCodeLen(); + + if ( !pThis || !pOther ) + { +// fprintf( stderr, "Error: no compiled code for cells !" ); + return NULL; + } + + if ( pThisLen != pOtherLen ) + return NULL; + + // check we are basically the same function + for ( sal_uInt16 i = 0; i < pThisLen; i++ ) + { + if ( pThis[ i ]->GetType() != pOther[ i ]->GetType() || + pThis[ i ]->GetOpCode() != pOther[ i ]->GetOpCode() || + pThis[ i ]->GetParamCount() != pOther[ i ]->GetParamCount() ) + { +// fprintf( stderr, "Incompatible type, op-code or param counts\n" ); + return NULL; + } + switch( pThis[ i ]->GetType() ) + { + case formula::svMatrix: + case formula::svExternalSingleRef: + case formula::svExternalDoubleRef: +// fprintf( stderr, "Ignoring matrix and external references for now\n" ); + return NULL; + default: + break; + } + } + + ScSimilarFormulaDelta *pDelta = new ScSimilarFormulaDelta(); + + for ( sal_uInt16 i = 0; i < pThisLen; i++ ) + { + ScToken *pThisTok = static_cast< ScToken * >( pThis[ i ] ); + ScToken *pOtherTok = static_cast< ScToken * >( pOther[ i ] ); + + if ( pThis[i]->GetType() == formula::svSingleRef || + pThis[i]->GetType() == formula::svDoubleRef ) + { + const ScSingleRefData& aThisRef = pThisTok->GetSingleRef(); + const ScSingleRefData& aOtherRef = pOtherTok->GetSingleRef(); + pDelta->push_delta( aThisRef, aOtherRef ); + } + if ( pThis[i]->GetType() == formula::svDoubleRef ) + { + const ScSingleRefData& aThisRef2 = pThisTok->GetSingleRef2(); + const ScSingleRefData& aOtherRef2 = pOtherTok->GetSingleRef2(); + pDelta->push_delta( aThisRef2, aOtherRef2 ); + } + } + + return pDelta; +} + +/// To avoid exposing impl. details of ScSimilarFormulaDelta publicly +void ScFormulaCell::ReleaseDelta( ScSimilarFormulaDelta *pDelta ) +{ + delete pDelta; +} + +bool ScFormulaCell::InterpretFormulaGroup() +{ + // Re-build formulae groups if necessary - ideally this is done at + // import / insert / delete etc. and is integral to the data structures + pDocument->RebuildFormulaGroups(); + + if( !xGroup.get() ) + return false; + +// fprintf( stderr, "Interpret cell %d, %d\n", (int)aPos.Col(), (int)aPos.Row() ); + + if ( xGroup->mpDelta->IsInvariant() ) + { +// fprintf( stderr, "struck gold - completely invariant for %d items !\n", +// (int)xGroup->mnLength ); + + // calculate ourselves: + InterpretTail( SCITP_NORMAL ); + for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ ) + { + ScAddress aTmpPos = aPos; + aTmpPos.SetRow(xGroup->mnStart + i); + ScFormulaCell* pCell = pDocument->GetFormulaCell(aTmpPos); + assert( pCell != NULL ); + + // FIXME: this set of horrors is unclear to me ... certainly + // the above GetCell is profoundly nasty & slow ... + + // Ensure the cell truly has a result: + pCell->aResult = aResult; + pCell->ResetDirty(); + + // FIXME: there is a view / refresh missing here it appears. + } + return true; + } + else + { + // scan the formula ... + // have a document method: "Get2DRangeAsDoublesArray" that does the + // column-based heavy lifting call it for each absolute range from the + // first cell pos in the formula group. + // + // Project single references to ranges by adding their vector * xGroup->mnLength + // + // TODO: + // elide multiple dimensional movement in vectors eg. =SUM(A1<1,1>) + // produces a diagonal 'column' that serves no useful purpose for us. + // these should be very rare. Should elide in GetDeltas anyway and + // assert here. + // + // Having built our input data ... + // Throw it, and the formula over to some 'OpenCLCalculage' hook + // + // on return - release references on these double buffers + // + // transfer the result to the formula cells (as above) + // store the doubles in the columns' maDoubles array for + // dependent formulae + // + // TODO: + // need to abort/fail when we get errors returned and fallback to + // stock interpreting [ I guess ], unless we can use NaN etc. to + // signal errors. + + return false; + } +} + +void ScFormulaCell::StartListeningTo( ScDocument* pDoc ) +{ + if (pDoc->IsClipOrUndo() || pDoc->GetNoListening() || IsInChangeTrack()) + return; + + pDoc->SetDetectiveDirty(true); // It has changed something + + ScTokenArray* pArr = GetCode(); + if( pArr->IsRecalcModeAlways() ) + { + pDoc->StartListeningArea(BCA_LISTEN_ALWAYS, this); + SetNeedsListening( false); + return; + } + + pArr->Reset(); + ScToken* t; + while ( ( t = static_cast(pArr->GetNextReferenceRPN()) ) != NULL ) + { + StackVar eType = t->GetType(); + ScSingleRefData& rRef1 = t->GetSingleRef(); + ScSingleRefData& rRef2 = (eType == svDoubleRef ? + t->GetDoubleRef().Ref2 : rRef1); + switch( eType ) + { + case svSingleRef: + rRef1.CalcAbsIfRel(aPos); + if ( rRef1.Valid() ) + { + pDoc->StartListeningCell( + ScAddress( rRef1.nCol, + rRef1.nRow, + rRef1.nTab ), this ); + } + break; + case svDoubleRef: + t->CalcAbsIfRel(aPos); + if ( rRef1.Valid() && rRef2.Valid() ) + { + if ( t->GetOpCode() == ocColRowNameAuto ) + { // automagically + if ( rRef1.IsColRel() ) + { // ColName + pDoc->StartListeningArea( ScRange ( + rRef1.nCol, + rRef1.nRow, + rRef1.nTab, + rRef2.nCol, + MAXROW, + rRef2.nTab ), this ); + } + else + { // RowName + pDoc->StartListeningArea( ScRange ( + rRef1.nCol, + rRef1.nRow, + rRef1.nTab, + MAXCOL, + rRef2.nRow, + rRef2.nTab ), this ); + } + } + else + { + pDoc->StartListeningArea( ScRange ( + rRef1.nCol, + rRef1.nRow, + rRef1.nTab, + rRef2.nCol, + rRef2.nRow, + rRef2.nTab ), this ); + } + } + break; + default: + ; // nothing + } + } + SetNeedsListening( false); +} + +// pArr gesetzt -> Referenzen von anderer Zelle nehmen +// Then aPos must also be commited + +void ScFormulaCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr, + ScAddress aCellPos ) +{ + if (pDoc->IsClipOrUndo() || IsInChangeTrack()) + return; + + pDoc->SetDetectiveDirty(true); // It has changed something + + if ( GetCode()->IsRecalcModeAlways() ) + { + pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, this ); + return; + } + + if (!pArr) + { + pArr = GetCode(); + aCellPos = aPos; + } + pArr->Reset(); + ScToken* t; + while ( ( t = static_cast(pArr->GetNextReferenceRPN()) ) != NULL ) + { + StackVar eType = t->GetType(); + ScSingleRefData& rRef1 = t->GetSingleRef(); + ScSingleRefData& rRef2 = (eType == svDoubleRef ? + t->GetDoubleRef().Ref2 : rRef1); + switch( eType ) + { + case svSingleRef: + rRef1.CalcAbsIfRel( aCellPos ); + if ( rRef1.Valid() ) + { + pDoc->EndListeningCell( + ScAddress( rRef1.nCol, + rRef1.nRow, + rRef1.nTab ), this ); + } + break; + case svDoubleRef: + t->CalcAbsIfRel( aCellPos ); + if ( rRef1.Valid() && rRef2.Valid() ) + { + if ( t->GetOpCode() == ocColRowNameAuto ) + { // automagically + if ( rRef1.IsColRel() ) + { // ColName + pDoc->EndListeningArea( ScRange ( + rRef1.nCol, + rRef1.nRow, + rRef1.nTab, + rRef2.nCol, + MAXROW, + rRef2.nTab ), this ); + } + else + { // RowName + pDoc->EndListeningArea( ScRange ( + rRef1.nCol, + rRef1.nRow, + rRef1.nTab, + MAXCOL, + rRef2.nRow, + rRef2.nTab ), this ); + } + } + else + { + pDoc->EndListeningArea( ScRange ( + rRef1.nCol, + rRef1.nRow, + rRef1.nTab, + rRef2.nCol, + rRef2.nRow, + rRef2.nTab ), this ); + } + } + break; + default: + ; // nothing + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/formulaiter.cxx b/sc/source/core/data/formulaiter.cxx index 4a28acf2156d..29c2bb83f5b5 100644 --- a/sc/source/core/data/formulaiter.cxx +++ b/sc/source/core/data/formulaiter.cxx @@ -19,7 +19,7 @@ #include "formulaiter.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "formula/token.hxx" using namespace formula; diff --git a/sc/source/core/data/postit.cxx b/sc/source/core/data/postit.cxx index 00ec727240c8..ea885b31dd26 100644 --- a/sc/source/core/data/postit.cxx +++ b/sc/source/core/data/postit.cxx @@ -41,7 +41,7 @@ #include "document.hxx" #include "docpool.hxx" #include "patattr.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "drwlayer.hxx" #include "userdat.hxx" #include "detfunc.hxx" diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 12ab3d383f62..2044014f838b 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -25,7 +25,7 @@ #include "attrib.hxx" #include "patattr.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "table.hxx" #include "document.hxx" #include "drwlayer.hxx" diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 9c95be5efcf2..85b494629a76 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -29,7 +29,7 @@ #include "table.hxx" #include "patattr.hxx" #include "docpool.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "drwlayer.hxx" #include "olinetab.hxx" diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index a16d945d0d0f..5468ecb89394 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -31,7 +31,7 @@ #include "table.hxx" #include "scitems.hxx" #include "attrib.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "globstr.hrc" #include "global.hxx" diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index b467745b8a24..ea82e75f9bd3 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -44,7 +44,7 @@ #include "attrib.hxx" #include "patattr.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "table.hxx" #include "globstr.hrc" #include "global.hxx" diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx index 86e6b4fed71a..7e3fd7f57214 100644 --- a/sc/source/core/data/table5.cxx +++ b/sc/source/core/data/table5.cxx @@ -21,7 +21,7 @@ #include "attrib.hxx" #include "patattr.hxx" #include "docpool.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "table.hxx" #include "column.hxx" #include "document.hxx" diff --git a/sc/source/core/data/table6.cxx b/sc/source/core/data/table6.cxx index 6df2249d89a4..0354e09d8264 100644 --- a/sc/source/core/data/table6.cxx +++ b/sc/source/core/data/table6.cxx @@ -24,7 +24,7 @@ #include #include "table.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "stlpool.hxx" #include "markdata.hxx" diff --git a/sc/source/core/data/validat.cxx b/sc/source/core/data/validat.cxx index cff7da794831..16267bfd7a4f 100644 --- a/sc/source/core/data/validat.cxx +++ b/sc/source/core/data/validat.cxx @@ -33,7 +33,7 @@ #include "validat.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "patattr.hxx" #include "rechead.hxx" #include "globstr.hrc" diff --git a/sc/source/core/tool/cellform.cxx b/sc/source/core/tool/cellform.cxx index 1ddfaaa4645c..cb7ce81996e6 100644 --- a/sc/source/core/tool/cellform.cxx +++ b/sc/source/core/tool/cellform.cxx @@ -22,7 +22,7 @@ #include #include "cellform.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "cellvalue.hxx" #include "formula/errorcodes.hxx" diff --git a/sc/source/core/tool/chartarr.cxx b/sc/source/core/tool/chartarr.cxx index 34f4605810a6..26716c1a8e65 100644 --- a/sc/source/core/tool/chartarr.cxx +++ b/sc/source/core/tool/chartarr.cxx @@ -26,7 +26,7 @@ #include "document.hxx" #include "rechead.hxx" #include "globstr.hrc" -#include "cell.hxx" +#include "formulacell.hxx" #include "docoptio.hxx" #include diff --git a/sc/source/core/tool/chgtrack.cxx b/sc/source/core/tool/chgtrack.cxx index b5ce9c917cdb..3c41eb65bb99 100644 --- a/sc/source/core/tool/chgtrack.cxx +++ b/sc/source/core/tool/chgtrack.cxx @@ -18,7 +18,7 @@ */ #include "chgtrack.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "dociter.hxx" #include "global.hxx" diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index b8bf5dde27c4..7cee7f6d5449 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -51,7 +51,7 @@ #include "scresid.hxx" #include "sc.hrc" #include "globstr.hrc" -#include "cell.hxx" +#include "formulacell.hxx" #include "dociter.hxx" #include "docoptio.hxx" #include diff --git a/sc/source/core/tool/consoli.cxx b/sc/source/core/tool/consoli.cxx index 2d0e129f50aa..a27be8529abc 100644 --- a/sc/source/core/tool/consoli.cxx +++ b/sc/source/core/tool/consoli.cxx @@ -23,7 +23,7 @@ #include "globstr.hrc" #include "subtotal.hxx" #include "formula/errorcodes.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include #include diff --git a/sc/source/core/tool/detfunc.cxx b/sc/source/core/tool/detfunc.cxx index cd75cddcc3a5..517a892363b0 100644 --- a/sc/source/core/tool/detfunc.cxx +++ b/sc/source/core/tool/detfunc.cxx @@ -58,7 +58,7 @@ #include "drwlayer.hxx" #include "userdat.hxx" #include "validat.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "docpool.hxx" #include "patattr.hxx" #include "attrib.hxx" diff --git a/sc/source/core/tool/doubleref.cxx b/sc/source/core/tool/doubleref.cxx index 522853d74320..aa07053f52b9 100644 --- a/sc/source/core/tool/doubleref.cxx +++ b/sc/source/core/tool/doubleref.cxx @@ -18,7 +18,7 @@ */ #include "doubleref.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "global.hxx" #include "document.hxx" #include "queryparam.hxx" diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index f0bfbe59c73d..1d9e857fcc88 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -38,7 +38,7 @@ #include "global.hxx" #include "document.hxx" #include "dociter.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scmatrix.hxx" #include "docoptio.hxx" #include "globstr.hrc" diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx index c7496b503027..7768a08cce91 100644 --- a/sc/source/core/tool/interpr2.cxx +++ b/sc/source/core/tool/interpr2.cxx @@ -32,7 +32,7 @@ #include "ddelink.hxx" #include "scmatrix.hxx" #include "compiler.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "dociter.hxx" #include "docoptio.hxx" diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx index 3fadc45b22a4..9fa7763ea00d 100644 --- a/sc/source/core/tool/interpr3.cxx +++ b/sc/source/core/tool/interpr3.cxx @@ -25,7 +25,7 @@ #include "interpre.hxx" #include "global.hxx" #include "compiler.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "dociter.hxx" #include "scmatrix.hxx" diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index fe05654bf2fe..83d02f16060b 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -41,7 +41,7 @@ #include "interpre.hxx" #include "global.hxx" #include "dbdata.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "callform.hxx" #include "addincol.hxx" #include "document.hxx" diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx index 7dc9b57a5305..fc904a4d5648 100644 --- a/sc/source/core/tool/interpr5.cxx +++ b/sc/source/core/tool/interpr5.cxx @@ -29,7 +29,7 @@ #include "interpre.hxx" #include "global.hxx" #include "compiler.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "dociter.hxx" #include "scmatrix.hxx" diff --git a/sc/source/core/tool/rangeseq.cxx b/sc/source/core/tool/rangeseq.cxx index 9e08c896749e..957548121f43 100644 --- a/sc/source/core/tool/rangeseq.cxx +++ b/sc/source/core/tool/rangeseq.cxx @@ -27,7 +27,7 @@ #include "document.hxx" #include "dociter.hxx" #include "scmatrix.hxx" -#include "cell.hxx" +#include "formulacell.hxx" using namespace com::sun::star; diff --git a/sc/source/filter/dif/difexp.cxx b/sc/source/filter/dif/difexp.cxx index d55a02a0cc29..a4c225699f25 100644 --- a/sc/source/filter/dif/difexp.cxx +++ b/sc/source/filter/dif/difexp.cxx @@ -24,7 +24,7 @@ #include "dif.hxx" #include "filter.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "globstr.hrc" #include "global.hxx" #include "progress.hxx" diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx index 9598d5b651cb..5ac3c6063d29 100644 --- a/sc/source/filter/excel/excdoc.cxx +++ b/sc/source/filter/excel/excdoc.cxx @@ -31,7 +31,7 @@ #include #include -#include "cell.hxx" +#include "formulacell.hxx" #include "dociter.hxx" #include "document.hxx" #include "rangenam.hxx" diff --git a/sc/source/filter/excel/excform.cxx b/sc/source/filter/excel/excform.cxx index 155fad900f1d..6aa95aebbd30 100644 --- a/sc/source/filter/excel/excform.cxx +++ b/sc/source/filter/excel/excform.cxx @@ -20,7 +20,7 @@ #include "excform.hxx" #include -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "rangenam.hxx" #include "global.hxx" diff --git a/sc/source/filter/excel/excform8.cxx b/sc/source/filter/excel/excform8.cxx index ab8e950a57c1..5007456fcd36 100644 --- a/sc/source/filter/excel/excform8.cxx +++ b/sc/source/filter/excel/excform8.cxx @@ -19,7 +19,7 @@ #include "excform.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "rangenam.hxx" #include "xltracer.hxx" diff --git a/sc/source/filter/excel/excimp8.cxx b/sc/source/filter/excel/excimp8.cxx index 68ceed5238aa..59f93976b2e7 100644 --- a/sc/source/filter/excel/excimp8.cxx +++ b/sc/source/filter/excel/excimp8.cxx @@ -64,7 +64,7 @@ #include -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "patattr.hxx" #include "docpool.hxx" diff --git a/sc/source/filter/excel/excrecds.cxx b/sc/source/filter/excel/excrecds.cxx index 495465879ac8..d788b2dfe914 100644 --- a/sc/source/filter/excel/excrecds.cxx +++ b/sc/source/filter/excel/excrecds.cxx @@ -56,7 +56,7 @@ #include "globstr.hrc" #include "docpool.hxx" #include "patattr.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "scextopt.hxx" #include "attrib.hxx" diff --git a/sc/source/filter/excel/impop.cxx b/sc/source/filter/excel/impop.cxx index 152f03c45afc..b7ac26ce9d07 100644 --- a/sc/source/filter/excel/impop.cxx +++ b/sc/source/filter/excel/impop.cxx @@ -39,7 +39,7 @@ #include "tools/urlobj.hxx" #include "docuno.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "rangenam.hxx" #include "compiler.hxx" diff --git a/sc/source/filter/excel/xehelper.cxx b/sc/source/filter/excel/xehelper.cxx index ab53c4911ace..27821544c5c2 100644 --- a/sc/source/filter/excel/xehelper.cxx +++ b/sc/source/filter/excel/xehelper.cxx @@ -37,7 +37,7 @@ #include "document.hxx" #include "docpool.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "editutil.hxx" #include "patattr.hxx" #include "xestyle.hxx" diff --git a/sc/source/filter/excel/xelink.cxx b/sc/source/filter/excel/xelink.cxx index 5f06be08f7bc..027a123b47ac 100644 --- a/sc/source/filter/excel/xelink.cxx +++ b/sc/source/filter/excel/xelink.cxx @@ -23,7 +23,7 @@ #include #include #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scextopt.hxx" #include "externalrefmgr.hxx" diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 0198db842c4f..0f541b516baf 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -37,7 +37,7 @@ #include "xcl97rec.hxx" #include "rangelst.hxx" #include "compiler.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include <../../ui/inc/docsh.hxx> #include <../../ui/inc/viewdata.hxx> diff --git a/sc/source/filter/excel/xetable.cxx b/sc/source/filter/excel/xetable.cxx index 06e70bb6af36..2366e7093c79 100644 --- a/sc/source/filter/excel/xetable.cxx +++ b/sc/source/filter/excel/xetable.cxx @@ -26,7 +26,7 @@ #include "document.hxx" #include "dociter.hxx" #include "olinetab.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "patattr.hxx" #include "attrib.hxx" #include "xehelper.hxx" diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx index ecee9c8b16ab..542a3fe7b7f7 100644 --- a/sc/source/filter/excel/xicontent.cxx +++ b/sc/source/filter/excel/xicontent.cxx @@ -39,7 +39,7 @@ #include "stringutil.hxx" #include "document.hxx" #include "editutil.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "validat.hxx" #include "patattr.hxx" #include "docpool.hxx" diff --git a/sc/source/filter/excel/xilink.cxx b/sc/source/filter/excel/xilink.cxx index 15c80a5bf1b0..6b4d2c3aece2 100644 --- a/sc/source/filter/excel/xilink.cxx +++ b/sc/source/filter/excel/xilink.cxx @@ -19,7 +19,7 @@ #include "xilink.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scextopt.hxx" #include "tablink.hxx" #include "xistream.hxx" diff --git a/sc/source/filter/excel/xipivot.cxx b/sc/source/filter/excel/xipivot.cxx index 95a73b6a081b..8ba8d0e69d73 100644 --- a/sc/source/filter/excel/xipivot.cxx +++ b/sc/source/filter/excel/xipivot.cxx @@ -30,7 +30,7 @@ #include #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "dpsave.hxx" #include "dpdimsave.hxx" #include "dpobject.hxx" diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx index 55e0087c1266..8dfbad4da192 100644 --- a/sc/source/filter/excel/xistyle.cxx +++ b/sc/source/filter/excel/xistyle.cxx @@ -48,7 +48,7 @@ #include "attrib.hxx" #include "stlpool.hxx" #include "stlsheet.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "globstr.hrc" #include "attarray.hxx" #include "xltracer.hxx" diff --git a/sc/source/filter/html/htmlexp.cxx b/sc/source/filter/html/htmlexp.cxx index 5853f7a6bc83..826797db1523 100644 --- a/sc/source/filter/html/htmlexp.cxx +++ b/sc/source/filter/html/htmlexp.cxx @@ -57,7 +57,7 @@ #include "patattr.hxx" #include "stlpool.hxx" #include "scresid.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "cellform.hxx" #include "docoptio.hxx" #include "editutil.hxx" diff --git a/sc/source/filter/lotus/lotimpop.cxx b/sc/source/filter/lotus/lotimpop.cxx index 19fe9acbaf35..f5d39a074f90 100644 --- a/sc/source/filter/lotus/lotimpop.cxx +++ b/sc/source/filter/lotus/lotimpop.cxx @@ -23,7 +23,7 @@ #include "attrib.hxx" #include "document.hxx" #include "rangenam.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "patattr.hxx" #include "docpool.hxx" #include "compiler.hxx" diff --git a/sc/source/filter/lotus/op.cxx b/sc/source/filter/lotus/op.cxx index 5ed25643f682..152b1f01eddf 100644 --- a/sc/source/filter/lotus/op.cxx +++ b/sc/source/filter/lotus/op.cxx @@ -35,7 +35,7 @@ #include #include -#include "cell.hxx" +#include "formulacell.hxx" #include "rangenam.hxx" #include "document.hxx" #include "postit.hxx" diff --git a/sc/source/filter/oox/formulabuffer.cxx b/sc/source/filter/oox/formulabuffer.cxx index 59b922104710..59286f5c30bc 100644 --- a/sc/source/filter/oox/formulabuffer.cxx +++ b/sc/source/filter/oox/formulabuffer.cxx @@ -14,7 +14,7 @@ #include #include #include -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "convuno.hxx" diff --git a/sc/source/filter/oox/sheetdatabuffer.cxx b/sc/source/filter/oox/sheetdatabuffer.cxx index 1e804fff1768..9877fde12887 100644 --- a/sc/source/filter/oox/sheetdatabuffer.cxx +++ b/sc/source/filter/oox/sheetdatabuffer.cxx @@ -49,7 +49,7 @@ #include "rangelst.hxx" #include "document.hxx" #include "scitems.hxx" -#include "cell.hxx" +#include "formulacell.hxx" namespace oox { namespace xls { diff --git a/sc/source/filter/orcus/interface.cxx b/sc/source/filter/orcus/interface.cxx index a8588a5276c1..2aed6286d250 100644 --- a/sc/source/filter/orcus/interface.cxx +++ b/sc/source/filter/orcus/interface.cxx @@ -10,7 +10,7 @@ #include "orcusinterface.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "rangenam.hxx" #include "tokenarray.hxx" #include diff --git a/sc/source/filter/qpro/biff.cxx b/sc/source/filter/qpro/biff.cxx index 53eaba3969f3..350afa763717 100644 --- a/sc/source/filter/qpro/biff.cxx +++ b/sc/source/filter/qpro/biff.cxx @@ -28,7 +28,7 @@ #include "patattr.hxx" #include "filter.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "biff.hxx" ScBiffReader::ScBiffReader( SfxMedium & rMedium ) : diff --git a/sc/source/filter/qpro/qpro.cxx b/sc/source/filter/qpro/qpro.cxx index 231f1e0752ae..1247ecccb598 100644 --- a/sc/source/filter/qpro/qpro.cxx +++ b/sc/source/filter/qpro/qpro.cxx @@ -32,7 +32,7 @@ #include "patattr.hxx" #include "filter.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "biff.hxx" #include diff --git a/sc/source/filter/qpro/qprostyle.cxx b/sc/source/filter/qpro/qprostyle.cxx index 11ee06768e62..be0a7cf23e81 100644 --- a/sc/source/filter/qpro/qprostyle.cxx +++ b/sc/source/filter/qpro/qprostyle.cxx @@ -42,7 +42,7 @@ #include "patattr.hxx" #include "filter.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" ScQProStyle::ScQProStyle() { diff --git a/sc/source/filter/starcalc/scflt.cxx b/sc/source/filter/starcalc/scflt.cxx index 445962dc8f0a..b7c514b9e023 100644 --- a/sc/source/filter/starcalc/scflt.cxx +++ b/sc/source/filter/starcalc/scflt.cxx @@ -57,7 +57,7 @@ #include "stlpool.hxx" #include "filter.hxx" #include "scflt.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scfobj.hxx" #include "docoptio.hxx" #include "viewopti.hxx" diff --git a/sc/source/filter/xcl97/XclExpChangeTrack.cxx b/sc/source/filter/xcl97/XclExpChangeTrack.cxx index e3a8758c7b05..f23dfe21fea5 100644 --- a/sc/source/filter/xcl97/XclExpChangeTrack.cxx +++ b/sc/source/filter/xcl97/XclExpChangeTrack.cxx @@ -25,7 +25,7 @@ #include #include "XclExpChangeTrack.hxx" #include "xeformula.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "xcl97rec.hxx" #include "document.hxx" #include "editutil.hxx" diff --git a/sc/source/filter/xcl97/XclImpChangeTrack.cxx b/sc/source/filter/xcl97/XclImpChangeTrack.cxx index 6046dd37f70c..9ce4e2ab19c3 100644 --- a/sc/source/filter/xcl97/XclImpChangeTrack.cxx +++ b/sc/source/filter/xcl97/XclImpChangeTrack.cxx @@ -22,7 +22,7 @@ #include #include #include "chgviset.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "chgtrack.hxx" #include "xihelper.hxx" #include "xilink.hxx" diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx index e3f8bafc7995..60b169086391 100644 --- a/sc/source/filter/xcl97/xcl97rec.cxx +++ b/sc/source/filter/xcl97/xcl97rec.cxx @@ -32,7 +32,7 @@ #include #include #include -#include "cell.hxx" +#include "formulacell.hxx" #include "drwlayer.hxx" #include "xcl97rec.hxx" diff --git a/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx b/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx index 223aeeda2e85..08e60c4f1aa7 100644 --- a/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx +++ b/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx @@ -23,7 +23,7 @@ #include "document.hxx" #include "chgtrack.hxx" #include "chgviset.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "textuno.hxx" #include "rangeutl.hxx" #include "cellvalue.hxx" diff --git a/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx b/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx index 5fb6334ac7a4..c38b9cf3282c 100644 --- a/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx +++ b/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx @@ -19,7 +19,7 @@ #include "XMLChangeTrackingImportHelper.hxx" #include "XMLConverter.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "document.hxx" #include "chgviset.hxx" #include "rangeutl.hxx" diff --git a/sc/source/filter/xml/XMLTrackedChangesContext.cxx b/sc/source/filter/xml/XMLTrackedChangesContext.cxx index be46fb7cb8c3..b7834d6d84c1 100644 --- a/sc/source/filter/xml/XMLTrackedChangesContext.cxx +++ b/sc/source/filter/xml/XMLTrackedChangesContext.cxx @@ -22,7 +22,7 @@ #include "xmlimprt.hxx" #include "xmlconti.hxx" #include "XMLConverter.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "textuno.hxx" #include "editutil.hxx" #include "document.hxx" diff --git a/sc/source/filter/xml/xmlcelli.cxx b/sc/source/filter/xml/xmlcelli.cxx index c57a951857bf..6a53ea124922 100644 --- a/sc/source/filter/xml/xmlcelli.cxx +++ b/sc/source/filter/xml/xmlcelli.cxx @@ -46,7 +46,7 @@ #include "XMLConverter.hxx" #include "scerrors.hxx" #include "editutil.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "editattributemap.hxx" #include "stringutil.hxx" diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index 48b53cd6a1fb..358172ab951b 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -26,7 +26,7 @@ #include "document.hxx" #include "olinetab.hxx" #include "cellsuno.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "rangenam.hxx" #include "XMLTableMasterPageExport.hxx" #include "drwlayer.hxx" diff --git a/sc/source/ui/Accessibility/AccessibleCellBase.cxx b/sc/source/ui/Accessibility/AccessibleCellBase.cxx index d6491d44c40c..7481e654030e 100644 --- a/sc/source/ui/Accessibility/AccessibleCellBase.cxx +++ b/sc/source/ui/Accessibility/AccessibleCellBase.cxx @@ -24,7 +24,7 @@ #include "document.hxx" #include "docfunc.hxx" #include "docsh.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scresid.hxx" #include "sc.hrc" #include "unonames.hxx" diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx index f34b346b2ff7..4bd0c0115d44 100644 --- a/sc/source/ui/app/inputhdl.cxx +++ b/sc/source/ui/app/inputhdl.cxx @@ -69,7 +69,7 @@ #include "userlist.hxx" #include "rfindlst.hxx" #include "inputopt.hxx" -#include "cell.hxx" // fuer Formel-Preview +#include "formulacell.hxx" // fuer Formel-Preview #include "compiler.hxx" // fuer Formel-Preview #include "editable.hxx" #include "funcdesc.hxx" diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx index 275d50b5e1c7..721b4b2f95e6 100644 --- a/sc/source/ui/app/transobj.cxx +++ b/sc/source/ui/app/transobj.cxx @@ -41,7 +41,7 @@ #include "viewopti.hxx" #include "editutil.hxx" #include "impex.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "printfun.hxx" #include "docfunc.hxx" #include "scmod.hxx" diff --git a/sc/source/ui/collab/sendfunc.cxx b/sc/source/ui/collab/sendfunc.cxx index 3e45a8c3ad7c..75233cfe218b 100644 --- a/sc/source/ui/collab/sendfunc.cxx +++ b/sc/source/ui/collab/sendfunc.cxx @@ -28,7 +28,7 @@ #include "sendfunc.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "docsh.hxx" #include "docfunc.hxx" #include "sccollaboration.hxx" diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index f131c780a0f5..09e571c870a8 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -41,7 +41,7 @@ #include "attrib.hxx" #include "dociter.hxx" #include "autoform.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "cellmergeoption.hxx" #include "detdata.hxx" #include "detfunc.hxx" diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx index 0bd4dabd3f9f..45bb6ae53e26 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -63,7 +63,7 @@ #include "scabstdlg.hxx" #include -#include "cell.hxx" +#include "formulacell.hxx" #include "column.hxx" #include "postit.hxx" #include "global.hxx" diff --git a/sc/source/ui/docshell/docsh3.cxx b/sc/source/ui/docshell/docsh3.cxx index cb4e6e6dd6ed..361de67402fa 100644 --- a/sc/source/ui/docshell/docsh3.cxx +++ b/sc/source/ui/docshell/docsh3.cxx @@ -50,7 +50,7 @@ #include "pntlock.hxx" #include "chgtrack.hxx" #include "docfunc.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "chgviset.hxx" #include "progress.hxx" #include "redcom.hxx" diff --git a/sc/source/ui/docshell/docsh8.cxx b/sc/source/ui/docshell/docsh8.cxx index 36811e739642..cd9871d0b328 100644 --- a/sc/source/ui/docshell/docsh8.cxx +++ b/sc/source/ui/docshell/docsh8.cxx @@ -58,7 +58,7 @@ #include "docsh.hxx" #include "filter.hxx" #include "progress.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "column.hxx" #include "editutil.hxx" #include "cellform.hxx" diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx index 6c6a0595fb75..2134e119793d 100644 --- a/sc/source/ui/docshell/externalrefmgr.cxx +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -26,7 +26,7 @@ #include "docsh.hxx" #include "scextopt.hxx" #include "rangenam.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "viewdata.hxx" #include "tabvwsh.hxx" #include "sc.hrc" diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx index 5c525dc0dbd1..a08787bc8509 100644 --- a/sc/source/ui/docshell/impex.cxx +++ b/sc/source/ui/docshell/impex.cxx @@ -34,7 +34,7 @@ #include "tabvwsh.hxx" #include "filter.hxx" #include "asciiopt.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "column.hxx" #include "docoptio.hxx" #include "progress.hxx" diff --git a/sc/source/ui/docshell/macromgr.cxx b/sc/source/ui/docshell/macromgr.cxx index d4efd763a931..6eaa7d871fde 100644 --- a/sc/source/ui/docshell/macromgr.cxx +++ b/sc/source/ui/docshell/macromgr.cxx @@ -23,7 +23,7 @@ #include "basic/basmgr.hxx" #include "cppuhelper/implbase1.hxx" #include "sfx2/objsh.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include #include diff --git a/sc/source/ui/docshell/tablink.cxx b/sc/source/ui/docshell/tablink.cxx index 628a15f2152e..4de384acc760 100644 --- a/sc/source/ui/docshell/tablink.cxx +++ b/sc/source/ui/docshell/tablink.cxx @@ -41,7 +41,7 @@ #include "hints.hxx" #include "dociter.hxx" #include "formula/opcode.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "formulaiter.hxx" using ::rtl::OUString; diff --git a/sc/source/ui/formdlg/dwfunctr.cxx b/sc/source/ui/formdlg/dwfunctr.cxx index 13776b6ec488..423b78d45397 100644 --- a/sc/source/ui/formdlg/dwfunctr.cxx +++ b/sc/source/ui/formdlg/dwfunctr.cxx @@ -30,7 +30,7 @@ #include "scresid.hxx" #include "reffact.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scmod.hxx" #include "inputhdl.hxx" #include "tabvwsh.hxx" diff --git a/sc/source/ui/formdlg/formula.cxx b/sc/source/ui/formdlg/formula.cxx index 6e4b846e498e..4f359f625dd0 100644 --- a/sc/source/ui/formdlg/formula.cxx +++ b/sc/source/ui/formdlg/formula.cxx @@ -39,7 +39,7 @@ #include "scresid.hxx" #include "reffact.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scmod.hxx" #include "inputhdl.hxx" #include "tabvwsh.hxx" diff --git a/sc/source/ui/miscdlgs/anyrefdg.cxx b/sc/source/ui/miscdlgs/anyrefdg.cxx index 80e0975431c3..52f0c3ae1807 100644 --- a/sc/source/ui/miscdlgs/anyrefdg.cxx +++ b/sc/source/ui/miscdlgs/anyrefdg.cxx @@ -37,7 +37,7 @@ #include "docsh.hxx" #include "rfindlst.hxx" #include "compiler.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "global.hxx" #include "inputopt.hxx" #include "rangeutl.hxx" diff --git a/sc/source/ui/miscdlgs/optsolver.cxx b/sc/source/ui/miscdlgs/optsolver.cxx index c9f7a796273e..386f6a5cf09a 100644 --- a/sc/source/ui/miscdlgs/optsolver.cxx +++ b/sc/source/ui/miscdlgs/optsolver.cxx @@ -29,7 +29,7 @@ #include "reffact.hxx" #include "docsh.hxx" #include "docfunc.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "rangeutl.hxx" #include "scresid.hxx" #include "convuno.hxx" diff --git a/sc/source/ui/navipi/content.cxx b/sc/source/ui/navipi/content.cxx index 9799b70d55c6..e8c28fb88dda 100644 --- a/sc/source/ui/navipi/content.cxx +++ b/sc/source/ui/navipi/content.cxx @@ -46,7 +46,7 @@ #include "transobj.hxx" #include "drwtrans.hxx" #include "lnktrans.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "dociter.hxx" #include "scresid.hxx" #include "globstr.hrc" diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx index 23a3a4d674af..317cab43df32 100644 --- a/sc/source/ui/undo/undoblk3.cxx +++ b/sc/source/ui/undo/undoblk3.cxx @@ -44,7 +44,7 @@ #include "undoutil.hxx" #include "chgtrack.hxx" #include "dociter.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "paramisc.hxx" #include "postit.hxx" #include "docuno.hxx" diff --git a/sc/source/ui/undo/undocell.cxx b/sc/source/ui/undo/undocell.cxx index a1f0f9e74a01..40ca1da9c02b 100644 --- a/sc/source/ui/undo/undocell.cxx +++ b/sc/source/ui/undo/undocell.cxx @@ -31,7 +31,7 @@ #include "tabvwsh.hxx" #include "globstr.hrc" #include "global.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "target.hxx" #include "undoolk.hxx" #include "detdata.hxx" diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index 502a1ea451c5..5a9e6b28542d 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -87,7 +87,7 @@ #include "dbdocfun.hxx" #include "olinefun.hxx" #include "hints.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "column.hxx" #include "undocell.hxx" #include "undotab.hxx" diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx index dc02354a0e75..e32ad531b22c 100644 --- a/sc/source/ui/unoobj/chart2uno.cxx +++ b/sc/source/ui/unoobj/chart2uno.cxx @@ -21,7 +21,7 @@ #include "chart2uno.hxx" #include "miscuno.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "chartpos.hxx" #include "unonames.hxx" #include "globstr.hrc" diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx index b0e20cfeaf5a..34a0de491604 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -76,7 +76,7 @@ #include "docfunc.hxx" #include "postit.hxx" #include "dociter.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "drwlayer.hxx" #include "rangeutl.hxx" #include "markdata.hxx" diff --git a/sc/source/ui/unoobj/funcuno.cxx b/sc/source/ui/unoobj/funcuno.cxx index 40fa41c17a41..8594c631ddd3 100644 --- a/sc/source/ui/unoobj/funcuno.cxx +++ b/sc/source/ui/unoobj/funcuno.cxx @@ -31,7 +31,7 @@ #include "callform.hxx" #include "addincol.hxx" #include "rangeseq.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "docoptio.hxx" #include "optuno.hxx" #include diff --git a/sc/source/ui/unoobj/textuno.cxx b/sc/source/ui/unoobj/textuno.cxx index c5c31e20aa47..29e61fdd8f8b 100644 --- a/sc/source/ui/unoobj/textuno.cxx +++ b/sc/source/ui/unoobj/textuno.cxx @@ -43,7 +43,7 @@ #include "cellsuno.hxx" #include "hints.hxx" #include "patattr.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "docfunc.hxx" #include "scmod.hxx" diff --git a/sc/source/ui/view/cellsh.cxx b/sc/source/ui/view/cellsh.cxx index bed44c39a146..e1258f460e45 100644 --- a/sc/source/ui/view/cellsh.cxx +++ b/sc/source/ui/view/cellsh.cxx @@ -43,7 +43,7 @@ #include "scresid.hxx" #include "tabvwsh.hxx" #include "impex.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scmod.hxx" #include "globstr.hrc" #include "transobj.hxx" diff --git a/sc/source/ui/view/dbfunc3.cxx b/sc/source/ui/view/dbfunc3.cxx index b159103dd231..a0d9baa098c3 100644 --- a/sc/source/ui/view/dbfunc3.cxx +++ b/sc/source/ui/view/dbfunc3.cxx @@ -61,7 +61,7 @@ #include "docpool.hxx" #include "patattr.hxx" #include "unonames.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "userlist.hxx" #include "queryentry.hxx" #include "markdata.hxx" diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 9daf85939485..4f5774c2b9ce 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -81,7 +81,7 @@ #include "uiitems.hxx" // Filter-Dialog - auslagern !!! #include "filtdlg.hxx" #include "impex.hxx" // Sylk-ID fuer CB -#include "cell.hxx" // fuer Edit-Felder +#include "formulacell.hxx" // fuer Edit-Felder #include "patattr.hxx" #include "notemark.hxx" #include "rfindlst.hxx" diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx index 19f3a6e69680..fa5fd662f9f5 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -45,7 +45,7 @@ #include "output.hxx" #include "document.hxx" #include "drwlayer.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "attrib.hxx" #include "patattr.hxx" #include "docpool.hxx" diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx index 4ecb1fc040af..c1bf7ebc5c3b 100644 --- a/sc/source/ui/view/output2.cxx +++ b/sc/source/ui/view/output2.cxx @@ -45,7 +45,7 @@ #include "output.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "attrib.hxx" #include "patattr.hxx" #include "cellform.hxx" diff --git a/sc/source/ui/view/printfun.cxx b/sc/source/ui/view/printfun.cxx index e054a4a6a3b0..6214fa22f0b4 100644 --- a/sc/source/ui/view/printfun.cxx +++ b/sc/source/ui/view/printfun.cxx @@ -55,7 +55,7 @@ #include "patattr.hxx" #include "docpool.hxx" #include "dociter.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "drawutil.hxx" #include "globstr.hrc" #include "scresid.hxx" diff --git a/sc/source/ui/view/spelleng.cxx b/sc/source/ui/view/spelleng.cxx index 61bc765545be..d66fc09ca8ac 100644 --- a/sc/source/ui/view/spelleng.cxx +++ b/sc/source/ui/view/spelleng.cxx @@ -36,7 +36,7 @@ #include "spelldialog.hxx" #include "tabvwsh.hxx" #include "docsh.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "patattr.hxx" #include "waitoff.hxx" #include "globstr.hrc" diff --git a/sc/source/ui/view/tabview4.cxx b/sc/source/ui/view/tabview4.cxx index 900e03de91a7..33d7cec19bb4 100644 --- a/sc/source/ui/view/tabview4.cxx +++ b/sc/source/ui/view/tabview4.cxx @@ -26,7 +26,7 @@ #include "scmod.hxx" #include "gridwin.hxx" #include "globstr.hrc" -#include "cell.hxx" +#include "formulacell.hxx" #include "dociter.hxx" extern sal_uInt16 nScFillModeMouseModifier; // global.cxx diff --git a/sc/source/ui/view/tabvwsh3.cxx b/sc/source/ui/view/tabvwsh3.cxx index a0a4c3fe9666..da817a124d7d 100644 --- a/sc/source/ui/view/tabvwsh3.cxx +++ b/sc/source/ui/view/tabvwsh3.cxx @@ -47,7 +47,7 @@ #include "rangeutl.hxx" #include "reffact.hxx" #include "uiitems.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "inputhdl.hxx" #include "autoform.hxx" #include "autofmt.hxx" diff --git a/sc/source/ui/view/tabvwsh5.cxx b/sc/source/ui/view/tabvwsh5.cxx index 4787b6151a51..79e506434997 100644 --- a/sc/source/ui/view/tabvwsh5.cxx +++ b/sc/source/ui/view/tabvwsh5.cxx @@ -31,7 +31,7 @@ #include "global.hxx" #include "docsh.hxx" #include "document.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "globstr.hrc" #include "scmod.hxx" #include "uiitems.hxx" diff --git a/sc/source/ui/view/tabvwsha.cxx b/sc/source/ui/view/tabvwsha.cxx index a6e624e6857b..45e2c38920e0 100644 --- a/sc/source/ui/view/tabvwsha.cxx +++ b/sc/source/ui/view/tabvwsha.cxx @@ -35,7 +35,7 @@ #include "attrib.hxx" #include "patattr.hxx" #include "document.hxx" -#include "cell.hxx" // Input Status Edit-Zellen +#include "formulacell.hxx" // Input Status Edit-Zellen #include "globstr.hrc" #include "scmod.hxx" #include "inputhdl.hxx" diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx index 857294ad4796..3652415e2290 100644 --- a/sc/source/ui/view/tabvwshc.cxx +++ b/sc/source/ui/view/tabvwshc.cxx @@ -46,7 +46,7 @@ #include "rangeutl.hxx" #include "crnrdlg.hxx" #include "formula.hxx" -#include "cell.hxx" // Input Status Edit-Zellen +#include "formulacell.hxx" // Input Status Edit-Zellen #include "acredlin.hxx" #include "highred.hxx" #include "simpref.hxx" diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx index 72407dc1ceff..7f15a3fc56fe 100644 --- a/sc/source/ui/view/viewfun2.cxx +++ b/sc/source/ui/view/viewfun2.cxx @@ -49,7 +49,7 @@ #include "attrib.hxx" #include "autoform.hxx" -#include "cell.hxx" // EnterAutoSum +#include "formulacell.hxx" // EnterAutoSum #include "cellmergeoption.hxx" #include "compiler.hxx" #include "docfunc.hxx" diff --git a/sc/source/ui/view/viewfun4.cxx b/sc/source/ui/view/viewfun4.cxx index 84a4202c4764..b73110582998 100644 --- a/sc/source/ui/view/viewfun4.cxx +++ b/sc/source/ui/view/viewfun4.cxx @@ -52,7 +52,7 @@ #include "global.hxx" #include "undoblk.hxx" #include "undocell.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scmod.hxx" #include "spelleng.hxx" #include "patattr.hxx" diff --git a/sc/source/ui/view/viewfun6.cxx b/sc/source/ui/view/viewfun6.cxx index 7a4a4ab58e04..ad04cb7b77ef 100644 --- a/sc/source/ui/view/viewfun6.cxx +++ b/sc/source/ui/view/viewfun6.cxx @@ -40,7 +40,7 @@ #include "fusel.hxx" #include "reftokenhelper.hxx" #include "externalrefmgr.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "markdata.hxx" #include "drawview.hxx" diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index 065373cbf0be..5316300c7c30 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -59,7 +59,7 @@ #include "global.hxx" #include "stlsheet.hxx" #include "editutil.hxx" -#include "cell.hxx" +#include "formulacell.hxx" #include "scresid.hxx" #include "inputhdl.hxx" #include "scmod.hxx" -- cgit v1.2.3