summaryrefslogtreecommitdiff
path: root/sc/inc/formularesult.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/inc/formularesult.hxx')
-rw-r--r--sc/inc/formularesult.hxx618
1 files changed, 618 insertions, 0 deletions
diff --git a/sc/inc/formularesult.hxx b/sc/inc/formularesult.hxx
new file mode 100644
index 000000000000..c8f50a92cd0b
--- /dev/null
+++ b/sc/inc/formularesult.hxx
@@ -0,0 +1,618 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: formularesult.hxx,v $
+ * $Revision: 1.3 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_FORMULARESULT_HXX
+#define SC_FORMULARESULT_HXX
+
+#include "token.hxx"
+
+
+/** Store a variable formula cell result, balancing between runtime performance
+ and memory consumption. */
+class ScFormulaResult
+{
+ typedef unsigned char Multiline;
+ static const Multiline MULTILINE_UNKNOWN = 0;
+ static const Multiline MULTILINE_FALSE = 1;
+ static const Multiline MULTILINE_TRUE = 2;
+
+ union
+ {
+ double mfValue; // double result direct for performance and memory consumption
+ const formula::FormulaToken* mpToken; // if not, result token obtained from interpreter
+ };
+ USHORT mnError; // error code
+ bool mbToken :1; // whether content of union is a token
+ bool mbEmpty :1; // empty cell result
+ bool mbEmptyDisplayedAsString :1; // only if mbEmpty
+ Multiline meMultiline :2; // result is multiline
+
+ /** Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults
+ prior to assigning other types */
+ inline void ResetToDefaults();
+
+ /** If token is of formula::svError set error code and decrement RefCount.
+ If token is of formula::svEmptyCell set mbEmpty and mbEmptyAsString and
+ decrement RefCount.
+ If token is of formula::svDouble set mfValue and decrement RefCount.
+ Else assign token to mpToken. NULL is valid => svUnknown.
+ Other member variables are set accordingly.
+ @precondition: Token MUST had been IncRef'ed prior to this call!
+ @precondition: An already existing different mpToken MUST had been
+ DecRef'ed prior to this call, p will be assigned to mpToken if not
+ resolved.
+ ATTENTION! Token may get deleted in this call! */
+ inline void ResolveToken( const formula::FormulaToken * p );
+
+public:
+ /** Effectively type svUnknown. */
+ ScFormulaResult()
+ : mpToken(NULL), mnError(0), mbToken(true),
+ mbEmpty(false), mbEmptyDisplayedAsString(false),
+ meMultiline(MULTILINE_UNKNOWN) {}
+
+ ScFormulaResult( const ScFormulaResult & r )
+ : mnError( r.mnError), mbToken( r.mbToken),
+ mbEmpty( r.mbEmpty),
+ mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
+ meMultiline( r.meMultiline)
+ {
+ if (mbToken)
+ {
+ mpToken = r.mpToken;
+ if (mpToken)
+ {
+ // Since matrix dimension and
+ // results are assigned to a matrix
+ // cell formula token we have to
+ // clone that instead of sharing it.
+ const ScMatrixFormulaCellToken* pMatFormula =
+ r.GetMatrixFormulaCellToken();
+ if (pMatFormula)
+ mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
+ mpToken->IncRef();
+ }
+ }
+ else
+ mfValue = r.mfValue;
+ }
+
+ /** Same comments as for SetToken() apply! */
+ explicit ScFormulaResult( const formula::FormulaToken* p )
+ : mnError(0), mbToken(false),
+ mbEmpty(false), mbEmptyDisplayedAsString(false),
+ meMultiline(MULTILINE_UNKNOWN)
+ {
+ SetToken( p);
+ }
+
+ ~ScFormulaResult()
+ {
+ if (mbToken && mpToken)
+ mpToken->DecRef();
+ }
+
+ /** Well, guess what ... */
+ inline ScFormulaResult & operator=( const ScFormulaResult & r );
+
+ /** Assignment as in operator=() but without return */
+ inline void Assign( const ScFormulaResult & r );
+
+ /** Sets a direct double if token type is formula::svDouble, or mbEmpty if
+ formula::svEmptyCell, else token. If p is NULL, that is set as well, effectively
+ resulting in GetType()==svUnknown. If the already existing result is
+ ScMatrixFormulaCellToken, the upper left ist set to token.
+
+ ATTENTION! formula::FormulaToken had to be allocated using 'new' and if of type
+ formula::svDouble and no RefCount was set may not be used after this call
+ because it was deleted after decrement! */
+ inline void SetToken( const formula::FormulaToken* p );
+
+ /** May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
+ inline formula::FormulaConstTokenRef GetToken() const;
+
+ /** Return upper left token if formula::svMatrixCell, else return GetToken().
+ May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
+ inline formula::FormulaConstTokenRef GetCellResultToken() const;
+
+ /** Return type of result, including formula::svError, formula::svEmptyCell, formula::svDouble and
+ formula::svMatrixCell. */
+ inline formula::StackVar GetType() const;
+
+ /** If type is formula::svMatrixCell return the type of upper left element, else
+ GetType() */
+ inline formula::StackVar GetCellResultType() const;
+
+ /** If type is formula::svEmptyCell (including matrix upper left) and should be
+ displayed as empty string */
+ inline bool IsEmptyDisplayedAsString() const;
+
+ /** Test for cell result type formula::svDouble, including upper left if
+ formula::svMatrixCell. Also included is formula::svError for legacy, because previously
+ an error result was treated like a numeric value at some places in
+ ScFormulaCell. Also included is formula::svEmptyCell as a reference to an empty
+ cell usually is treated as numeric 0. Use GetCellResultType() for
+ details instead. */
+ inline bool IsValue() const;
+
+ /** Determines whether or not the result is a string containing more than
+ one paragraph */
+ inline bool IsMultiline() const;
+
+ /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
+ else 0. */
+ inline USHORT GetResultError() const;
+
+ /** Set error code, don't touch token or double. */
+ inline void SetResultError( USHORT nErr );
+
+ /** Set direct double. Shouldn't be used externally except in
+ ScFormulaCell for rounded CalcAsShown or SetErrCode(). If
+ ScMatrixFormulaCellToken the token isn't replaced but upper left result
+ is modified instead, but only if it was of type formula::svDouble before or not
+ set at all. */
+ inline void SetDouble( double f );
+
+ /** Return value if type formula::svDouble or formula::svHybridCell or formula::svMatrixCell and upper
+ left formula::svDouble, else 0.0 */
+ inline double GetDouble() const;
+
+ /** Return string if type formula::svString or formula::svHybridCell or formula::svMatrixCell and
+ upper left formula::svString, else empty string. */
+ inline const String & GetString() const;
+
+ /** Return matrix if type formula::svMatrixCell and ScMatrix present, else NULL. */
+ inline ScConstMatrixRef GetMatrix() const;
+
+ /** Return formula string if type formula::svHybridCell, else empty string. */
+ inline const String & GetHybridFormula() const;
+
+ /** Should only be used by import filters, best in the order
+ SetHybridDouble(), SetHybridString(), or only SetHybridString() for
+ formula string to be compiled later. */
+ inline void SetHybridDouble( double f );
+
+ /** Should only be used by import filters, best in the order
+ SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
+ SetHybridFormula() for formula string to be compiled later. */
+ inline void SetHybridString( const String & rStr );
+
+ /** Should only be used by import filters, best in the order
+ SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
+ SetHybridFormula() for formula string to be compiled later. */
+ inline void SetHybridFormula( const String & rFormula );
+
+ /** Get the const ScMatrixFormulaCellToken* if token is of that type, else
+ NULL. */
+ inline const ScMatrixFormulaCellToken* GetMatrixFormulaCellToken() const;
+
+ /** Get the ScMatrixFormulaCellToken* if token is of that type, else NULL.
+ Shouldn't be used externally except by ScFormulaCell::SetMatColsRows(). */
+ inline ScMatrixFormulaCellToken* GetMatrixFormulaCellTokenNonConst();
+};
+
+
+inline void ScFormulaResult::ResetToDefaults()
+{
+ mnError = 0;
+ mbEmpty = false;
+ mbEmptyDisplayedAsString = false;
+ meMultiline = MULTILINE_UNKNOWN;
+}
+
+
+inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
+{
+ ResetToDefaults();
+ if (!p)
+ {
+ mpToken = p;
+ mbToken = true;
+ }
+ else
+ {
+ switch (p->GetType())
+ {
+ case formula::svError:
+ mnError = p->GetError();
+ p->DecRef();
+ mbToken = false;
+ // set in case mnError is 0 now, which shouldn't happen but ...
+ mfValue = 0.0;
+ meMultiline = MULTILINE_FALSE;
+ break;
+ case formula::svEmptyCell:
+ mbEmpty = true;
+ mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
+ p->DecRef();
+ mbToken = false;
+ meMultiline = MULTILINE_FALSE;
+ break;
+ case formula::svDouble:
+ mfValue = p->GetDouble();
+ p->DecRef();
+ mbToken = false;
+ meMultiline = MULTILINE_FALSE;
+ break;
+ default:
+ mpToken = p;
+ mbToken = true;
+ }
+ }
+}
+
+
+inline ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
+{
+ Assign( r);
+ return *this;
+}
+
+
+inline void ScFormulaResult::Assign( const ScFormulaResult & r )
+{
+ if (this == &r)
+ return;
+ if (r.mbEmpty)
+ {
+ if (mbToken && mpToken)
+ mpToken->DecRef();
+ mbToken = false;
+ mbEmpty = true;
+ mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
+ meMultiline = r.meMultiline;
+ }
+ else if (r.mbToken)
+ {
+ // Matrix formula cell token must be cloned, see copy-ctor.
+ const ScMatrixFormulaCellToken* pMatFormula =
+ r.GetMatrixFormulaCellToken();
+ if (pMatFormula)
+ SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
+ else
+ SetToken( r.mpToken);
+ }
+ else
+ SetDouble( r.mfValue);
+ // If there was an error there will be an error, no matter what Set...()
+ // methods did.
+ mnError = r.mnError;
+}
+
+
+inline void ScFormulaResult::SetToken( const formula::FormulaToken* p )
+{
+ ResetToDefaults();
+ if (p)
+ p->IncRef();
+ // Handle a result obtained from the interpreter to be assigned to a matrix
+ // formula cell's ScMatrixFormulaCellToken.
+ ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
+ if (pMatFormula)
+ {
+ const ScMatrixCellResultToken* pMatResult =
+ (p && p->GetType() == formula::svMatrixCell ?
+ dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
+ if (pMatResult)
+ {
+ const ScMatrixFormulaCellToken* pNewMatFormula =
+ dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
+ if (pNewMatFormula)
+ {
+ DBG_ERRORFILE( "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
+ pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
+ pNewMatFormula->GetMatRows());
+ }
+ pMatFormula->Assign( *pMatResult);
+ p->DecRef();
+ }
+ else if (p)
+ {
+ // This may be the result of some constant expression like
+ // {="string"} that doesn't result in a matrix but still would
+ // display the result in all cells of this matrix formula.
+ pMatFormula->Assign( *p);
+ p->DecRef();
+ }
+ else
+ {
+ // NULL result? Well, if you say so ...
+ pMatFormula->ResetResult();
+ }
+ }
+ else
+ {
+ if (mbToken && mpToken)
+ mpToken->DecRef();
+ ResolveToken( p);
+ }
+}
+
+
+inline void ScFormulaResult::SetDouble( double f )
+{
+ ResetToDefaults();
+ // Handle a result obtained from the interpreter to be assigned to a matrix
+ // formula cell's ScMatrixFormulaCellToken.
+ ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
+ if (pMatFormula)
+ pMatFormula->SetUpperLeftDouble( f);
+ else
+ {
+ if (mbToken && mpToken)
+ mpToken->DecRef();
+ mfValue = f;
+ mbToken = false;
+ meMultiline = MULTILINE_FALSE;
+ }
+}
+
+
+inline formula::StackVar ScFormulaResult::GetType() const
+{
+ // Order is significant.
+ if (mnError)
+ return formula::svError;
+ if (mbEmpty)
+ return formula::svEmptyCell;
+ if (!mbToken)
+ return formula::svDouble;
+ if (mpToken)
+ return mpToken->GetType();
+ return formula::svUnknown;
+}
+
+
+inline formula::StackVar ScFormulaResult::GetCellResultType() const
+{
+ formula::StackVar sv = GetType();
+ if (sv == formula::svMatrixCell)
+ // don't need to test for mpToken here, GetType() already did it
+ sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
+ return sv;
+}
+
+
+inline bool ScFormulaResult::IsEmptyDisplayedAsString() const
+{
+ if (mbEmpty)
+ return mbEmptyDisplayedAsString;
+ if (GetType() == formula::svMatrixCell)
+ {
+ // don't need to test for mpToken here, GetType() already did it
+ const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
+ static_cast<const ScMatrixCellResultToken*>(
+ mpToken)->GetUpperLeftToken().operator->());
+ if (p)
+ return p->IsDisplayedAsString();
+ }
+ return false;
+}
+
+
+inline bool ScFormulaResult::IsValue() const
+{
+ formula::StackVar sv = GetCellResultType();
+ return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell;
+}
+
+inline bool ScFormulaResult::IsMultiline() const
+{
+ if (meMultiline == MULTILINE_UNKNOWN)
+ {
+ const String& rStr = GetString();
+ if (rStr.Len() && rStr.Search( _LF ) != STRING_NOTFOUND)
+ const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
+ else
+ const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
+ }
+ return meMultiline == MULTILINE_TRUE;
+}
+
+
+inline USHORT ScFormulaResult::GetResultError() const
+{
+ if (mnError)
+ return mnError;
+ formula::StackVar sv = GetCellResultType();
+ if (sv == formula::svError)
+ {
+ if (GetType() == formula::svMatrixCell)
+ // don't need to test for mpToken here, GetType() already did it
+ return static_cast<const ScMatrixCellResultToken*>(mpToken)->
+ GetUpperLeftToken()->GetError();
+ if (mpToken)
+ return mpToken->GetError();
+ }
+ return 0;
+}
+
+
+inline void ScFormulaResult::SetResultError( USHORT nErr )
+{
+ mnError = nErr;
+}
+
+
+inline formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
+{
+ if (mbToken)
+ return mpToken;
+ return NULL;
+}
+
+
+inline formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
+{
+ if (GetType() == formula::svMatrixCell)
+ // don't need to test for mpToken here, GetType() already did it
+ return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
+ return GetToken();
+}
+
+
+inline double ScFormulaResult::GetDouble() const
+{
+ if (mbToken)
+ {
+ // Should really not be of type formula::svDouble here.
+ if (mpToken)
+ {
+ switch (mpToken->GetType())
+ {
+ case formula::svHybridCell:
+ return mpToken->GetDouble();
+ case formula::svMatrixCell:
+ {
+ const ScMatrixCellResultToken* p =
+ static_cast<const ScMatrixCellResultToken*>(mpToken);
+ if (p->GetUpperLeftType() == formula::svDouble)
+ return p->GetUpperLeftToken()->GetDouble();
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ return 0.0;
+ }
+ if (mbEmpty)
+ return 0.0;
+ return mfValue;
+}
+
+
+inline const String & ScFormulaResult::GetString() const
+{
+ if (mbToken && mpToken)
+ {
+ switch (mpToken->GetType())
+ {
+ case formula::svString:
+ case formula::svHybridCell:
+ return mpToken->GetString();
+ case formula::svMatrixCell:
+ {
+ const ScMatrixCellResultToken* p =
+ static_cast<const ScMatrixCellResultToken*>(mpToken);
+ if (p->GetUpperLeftType() == formula::svString)
+ return p->GetUpperLeftToken()->GetString();
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ return EMPTY_STRING;
+}
+
+
+inline ScConstMatrixRef ScFormulaResult::GetMatrix() const
+{
+ if (GetType() == formula::svMatrixCell)
+ return static_cast<const ScToken*>(mpToken)->GetMatrix();
+ return NULL;
+}
+
+
+inline const String & ScFormulaResult::GetHybridFormula() const
+{
+ if (GetType() == formula::svHybridCell)
+ {
+ const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
+ if (p)
+ return p->GetFormula();
+ }
+ return EMPTY_STRING;
+}
+
+
+inline void ScFormulaResult::SetHybridDouble( double f )
+{
+ ResetToDefaults();
+ if (mbToken && mpToken)
+ {
+ String aString( GetString());
+ String aFormula( GetHybridFormula());
+ mpToken->DecRef();
+ mpToken = new ScHybridCellToken( f, aString, aFormula);
+ mpToken->IncRef();
+ }
+ else
+ {
+ mfValue = f;
+ mbToken = false;
+ meMultiline = MULTILINE_FALSE;
+ }
+}
+
+
+inline void ScFormulaResult::SetHybridString( const String & rStr )
+{
+ // Obtain values before changing anything.
+ double f = GetDouble();
+ String aFormula( GetHybridFormula());
+ ResetToDefaults();
+ if (mbToken && mpToken)
+ mpToken->DecRef();
+ mpToken = new ScHybridCellToken( f, rStr, aFormula);
+ mpToken->IncRef();
+ mbToken = true;
+}
+
+
+inline void ScFormulaResult::SetHybridFormula( const String & rFormula )
+{
+ // Obtain values before changing anything.
+ double f = GetDouble();
+ String aStr( GetString());
+ ResetToDefaults();
+ if (mbToken && mpToken)
+ mpToken->DecRef();
+ mpToken = new ScHybridCellToken( f, aStr, rFormula);
+ mpToken->IncRef();
+ mbToken = true;
+}
+
+
+inline const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
+{
+ return (GetType() == formula::svMatrixCell ?
+ dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
+}
+
+
+inline ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
+{
+ return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
+}
+
+
+#endif // SC_FORMULARESULT_HXX