blob: 961e563fd857b3d13db168a63774dd4ac84f0237 [file] [log] [blame]
/**************************************************************
*
* 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 <stddef.h>
#include <set>
#include <tools/mempool.hxx>
#include <svl/listener.hxx>
#include "global.hxx"
#include "rangenam.hxx"
#include "formula/grammar.hxx"
#include "tokenarray.hxx"
#include "formularesult.hxx"
#include <rtl/ustrbuf.hxx>
#include <unotools/fontcvt.hxx>
#include "scdllapi.h"
#include <cellform.hxx>
#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
ScToken* pValidRefToken; // i120962, get the valid reference token if the cell was applied a reference formula
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<sal_uInt16>& 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();
ScToken* GetValidRefToken() { return pValidRefToken; } // i120962
};
// 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<ScBaseCell*>(pCell), nFormat, strResult, &pColor, *(pFormatter) );
return strResult;
}
else
return String();
}
#endif