/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #ifndef SC_CELL_HXX #define SC_CELL_HXX #include #include #include #include #include "global.hxx" #include "rangenam.hxx" #include "formula/grammar.hxx" #include "tokenarray.hxx" #include "formularesult.hxx" #include #include #include "scdllapi.h" #include #define USE_MEMPOOL #define TEXTWIDTH_DIRTY 0xffff // in addition to SCRIPTTYPE_... flags from scripttypeitem.hxx: // set (in nScriptType) if type has not been determined yet #define SC_SCRIPTTYPE_UNKNOWN 0x08 class ScDocument; class EditTextObject; class ScMatrix; class SvtBroadcaster; class ScCodeArray; class ScProgress; class ScPostIt; // ============================================================================ /** Default cell clone flags: do not start listening, do not adjust 3D refs to old position, clone note captions of cell notes. */ const int SC_CLONECELL_DEFAULT = 0x0000; /** If set, cloned formula cells will start to listen to the document. */ const int SC_CLONECELL_STARTLISTENING = 0x0001; /** If set, relative 3D references of cloned formula cells will be adjusted to old position (used while swapping cells for sorting a cell range). */ const int SC_CLONECELL_ADJUST3DREL = 0x0002; /** If set, the caption object of a cell note will not be cloned (used while copying cells to undo document, where captions are handled in drawing undo). */ const int SC_CLONECELL_NOCAPTION = 0x0004; // ============================================================================ class SC_DLLPUBLIC ScBaseCell { protected: ~ScBaseCell(); // nicht virtuell -> darf nicht direkt aufgerufen werden public: explicit ScBaseCell( CellType eNewType ); /** Base copy constructor. Does NOT clone cell note or broadcaster! */ ScBaseCell( const ScBaseCell& rCell ); /** Returns a clone of this cell at the same position, cell note and broadcaster will not be cloned. */ ScBaseCell* CloneWithoutNote( ScDocument& rDestDoc, int nCloneFlags = SC_CLONECELL_DEFAULT ) const; /** Returns a clone of this cell for the passed document position, cell note and broadcaster will not be cloned. */ ScBaseCell* CloneWithoutNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags = SC_CLONECELL_DEFAULT ) const; /** Returns a clone of this cell, clones cell note and caption object too (unless SC_CLONECELL_NOCAPTION flag is set). Broadcaster will not be cloned. */ ScBaseCell* CloneWithNote( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags = SC_CLONECELL_DEFAULT ) const; /** Due to the fact that ScBaseCell does not have a vtable, this function deletes the cell by calling the appropriate d'tor of the derived class. */ void Delete(); inline CellType GetCellType() const { return (CellType)eCellType; } /** Returns true, if the cell is empty (neither value nor formula nor cell note). Returns false for formula cells returning nothing, use HasEmptyData() for that. */ bool IsBlank( bool bIgnoreNotes = false ) const; // fuer Idle-Berechnung inline sal_uInt16 GetTextWidth() const { return nTextWidth; } inline void SetTextWidth( sal_uInt16 nNew ) { nTextWidth = nNew; } inline sal_uInt8 GetScriptType() const { return nScriptType; } inline void SetScriptType( sal_uInt8 nNew ) { nScriptType = nNew; } /** Returns true, if the cell contains a note. */ inline bool HasNote() const { return mpNote != 0; } /** Returns the pointer to a cell note object (read-only). */ inline const ScPostIt* GetNote() const { return mpNote; } /** Returns the pointer to a cell note object. */ inline ScPostIt* GetNote() { return mpNote; } /** Takes ownership of the passed cell note object. */ void TakeNote( ScPostIt* pNote ); /** Returns and forgets the own cell note object. Caller takes ownership! */ ScPostIt* ReleaseNote(); /** Deletes the own cell note object. */ void DeleteNote(); /** Returns true, if the cell contains a broadcaster. */ inline bool HasBroadcaster() const { return mpBroadcaster != 0; } /** Returns the pointer to the cell broadcaster. */ inline SvtBroadcaster* GetBroadcaster() const { return mpBroadcaster; } /** Takes ownership of the passed cell broadcaster. */ void TakeBroadcaster( SvtBroadcaster* pBroadcaster ); /** Returns and forgets the own cell broadcaster. Caller takes ownership! */ SvtBroadcaster* ReleaseBroadcaster(); /** Deletes the own cell broadcaster. */ void DeleteBroadcaster(); // String- oder EditCell static ScBaseCell* CreateTextCell( const String& rString, ScDocument* ); // nOnlyNames may be one or more of SC_LISTENING_NAMES_* void StartListeningTo( ScDocument* pDoc ); void EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() ); /** Error code if ScFormulaCell, else 0. */ sal_uInt16 GetErrorCode() const; /** ScFormulaCell with formula::svEmptyCell result, or ScNoteCell (may have been created due to reference to empty cell). */ sal_Bool HasEmptyData() const; sal_Bool HasValueData() const; sal_Bool HasStringData() const; String GetStringData() const; // nur echte Strings static sal_Bool CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 ); private: ScBaseCell& operator=( const ScBaseCell& ); private: ScPostIt* mpNote; /// The cell note. Cell takes ownership! SvtBroadcaster* mpBroadcaster; /// Broadcaster for changed values. Cell takes ownership! protected: sal_uInt16 nTextWidth; sal_uInt8 eCellType; // enum CellType - sal_uInt8 spart Speicher sal_uInt8 nScriptType; }; // ============================================================================ class SC_DLLPUBLIC ScNoteCell : public ScBaseCell { public: #ifdef USE_MEMPOOL DECL_FIXEDMEMPOOL_NEWDEL( ScNoteCell ) #endif /** Cell takes ownership of the passed broadcaster. */ explicit ScNoteCell( SvtBroadcaster* pBC = 0 ); /** Cell takes ownership of the passed note and broadcaster. */ explicit ScNoteCell( ScPostIt* pNote, SvtBroadcaster* pBC = 0 ); #ifdef DBG_UTIL ~ScNoteCell(); #endif private: ScNoteCell( const ScNoteCell& ); }; // ============================================================================ class SC_DLLPUBLIC ScValueCell : public ScBaseCell { public: #ifdef USE_MEMPOOL DECL_FIXEDMEMPOOL_NEWDEL( ScValueCell ) #endif ScValueCell(); explicit ScValueCell( double fValue ); #ifdef DBG_UTIL ~ScValueCell(); #endif inline void SetValue( double fValue ) { mfValue = fValue; } inline double GetValue() const { return mfValue; } private: double mfValue; }; // ============================================================================ class SC_DLLPUBLIC ScStringCell : public ScBaseCell { public: #ifdef USE_MEMPOOL DECL_FIXEDMEMPOOL_NEWDEL( ScStringCell ) #endif ScStringCell(); explicit ScStringCell( const String& rString ); #ifdef DBG_UTIL ~ScStringCell(); #endif inline void SetString( const String& rString ) { maString = rString; } inline void GetString( String& rString ) const { rString = maString; } inline const String& GetString() const { return maString; } private: String maString; }; // ============================================================================ class SC_DLLPUBLIC ScEditCell : public ScBaseCell { private: EditTextObject* pData; String* pString; // fuer schnelleren Zugriff von Formeln ScDocument* pDoc; // fuer EditEngine Zugriff mit Pool void SetTextObject( const EditTextObject* pObject, const SfxItemPool* pFromPool ); // not implemented ScEditCell( const ScEditCell& ); public: #ifdef USE_MEMPOOL DECL_FIXEDMEMPOOL_NEWDEL( ScEditCell ) #endif ~ScEditCell(); // wegen pData immer! ScEditCell( const EditTextObject* pObject, ScDocument*, const SfxItemPool* pFromPool /* = NULL */ ); ScEditCell( const ScEditCell& rCell, ScDocument& rDoc ); // fuer Zeilenumbrueche ScEditCell( const String& rString, ScDocument* ); void SetData( const EditTextObject* pObject, const SfxItemPool* pFromPool /* = NULL */ ); void GetData( const EditTextObject*& rpObject ) const; void GetString( String& rString ) const; const EditTextObject* GetData() const { return pData; } }; // ============================================================================ 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; 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 sal_Bool bDirty : 1; // Must be (re)calculated sal_Bool bChanged : 1; // Whether something changed regarding display/representation sal_Bool bRunning : 1; // Already interpreting right now sal_Bool bCompile : 1; // Must be (re)compiled sal_Bool bSubTotal : 1; // Cell is part of or contains a SubTotal sal_Bool bIsIterCell : 1; // Cell is part of a circular reference sal_Bool bInChangeTrack : 1; // Cell is in ChangeTrack sal_Bool bTableOpDirty : 1; // Dirty flag for TableOp sal_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(); ScFormulaCell(); /** 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 String& 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 ); void GetFormula( String& 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(); inline void SetDirtyVar() { bDirty = sal_True; } // If setting entire document dirty after load, no broadcasts but still append to FormulaTree. void SetDirtyAfterLoad(); inline void ResetTableOpDirtyVar() { bTableOpDirty = sal_False; } void SetTableOpDirty(); sal_Bool IsDirtyOrInTableOpDirty() const; sal_Bool GetDirty() const { return bDirty; } sal_Bool NeedsListening() const { return bNeedListening; } void SetNeedsListening( sal_Bool bVar ) { bNeedListening = bVar; } void Compile(const String& rFormula, sal_Bool bNoListening = sal_False, const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ); void CompileTokenArray( sal_Bool bNoListening = sal_False ); void CompileXML( ScProgress& rProgress ); // compile temporary string tokens void CalcAfterLoad(); bool MarkUsedExternalReferences(); void Interpret(); inline sal_Bool IsIterCell() const { return bIsIterCell; } inline sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; } sal_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; sal_Bool HasRelNameReference() const; sal_Bool HasColRowName() const; void 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); void UpdateInsertTabAbs(SCTAB nTable); sal_Bool UpdateDeleteTab(SCTAB nTable, sal_Bool bIsMove = sal_False); void UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo); void UpdateRenameTab(SCTAB nTable, const String& rName); sal_Bool TestTabRefAbs(SCTAB nTable); void UpdateCompile( sal_Bool bForceIfNameInUse = sal_False ); sal_Bool IsRangeNameInUse(sal_uInt16 nIndex) const; void FindRangeNamesInUse(std::set& rIndexes) const; void ReplaceRangeNamesInUse( const ScRangeData::IndexMap& rMap ); sal_Bool IsSubTotal() const { return bSubTotal; } sal_Bool IsChanged() const { return bChanged; } void ResetChanged() { bChanged = sal_False; } sal_Bool IsEmpty(); // formula::svEmptyCell result // display as empty string if formula::svEmptyCell result sal_Bool IsEmptyDisplayedAsString(); sal_Bool IsValue(); // also sal_True if formula::svEmptyCell double GetValue(); double GetValueAlways(); // ignore errors void GetString( String& rString ); const ScMatrix* GetMatrix(); sal_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; } sal_Bool IsRunning() const { return bRunning; } void SetRunning( sal_Bool bVal ) { bRunning = bVal; } void CompileDBFormula(); void CompileDBFormula( sal_Bool bCreateFormulaString ); void CompileNameFormula( sal_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( sal_Bool bVal ) { bCompile = bVal; } ScDocument* GetDocument() const { return pDocument; } void SetMatColsRows( SCCOL nCols, SCROW nRows ); void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const; // ob Zelle im ChangeTrack und nicht im echten Dokument ist void SetInChangeTrack( sal_Bool bVal ) { bInChangeTrack = bVal; } sal_Bool IsInChangeTrack() const { return bInChangeTrack; } // Zu Typ und Format das entsprechende Standardformat. // Bei Format "Standard" evtl. das in die Formelzelle // uebernommene Format. 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 String& 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 String& r, const formula::FormulaGrammar::Grammar eGrammar ) { aResult.SetHybridFormula( r); eTempGrammar = eGrammar; } void SetErrCode( sal_uInt16 n ); inline sal_Bool IsHyperLinkCell() const { return pCode && pCode->IsHyperLink(); } EditTextObject* CreateURLObject() ; void GetURLResult( String& rURL, String& rCellText ); /** Determines whether or not the result string contains more than one paragraph */ bool IsMultilineResult(); }; // Iterator fuer Referenzen in einer Formelzelle class ScDetectiveRefIter { private: ScTokenArray* pCode; ScAddress aPos; public: ScDetectiveRefIter( ScFormulaCell* pCell ); sal_Bool GetNextRef( ScRange& rRange ); }; // ============================================================================ inline double GetValueFromCell( const ScBaseCell * pCell ) { switch (pCell->GetCellType()) { case CELLTYPE_VALUE: return ((ScValueCell*)pCell)->GetValue(); case CELLTYPE_FORMULA: { if (((ScFormulaCell*)pCell)->IsValue()) return ((ScFormulaCell*)pCell)->GetValue(); else return 0.0; } default: return 0.0; } } // ============================================================================ inline String GetStringFromCell( const ScBaseCell * pCell, sal_uLong nFormat, SvNumberFormatter* pFormatter ) { if (pCell->GetCellType() != CELLTYPE_NOTE) { String strResult; Color* pColor = NULL; ScCellFormat::GetString( const_cast(pCell), nFormat, strResult, &pColor, *(pFormatter) ); return strResult; } else return String(); } #endif