/* -*- 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/.
*/
ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
mbToken( r.mbToken),
mbEmpty( r.mbEmpty),
mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
mbValueCached( r.mbValueCached),
meMultiline( r.meMultiline),
mnError( r.mnError)
{ 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;
mbNoneRefCnt = mbToken && mpToken && mpToken->GetRefCntPolicy() == formula::RefCntPolicy::None;
}
void ScFormulaResult::Assign( const ScFormulaResult & r )
{ if (this == &r) return;
// It is important to reset the value-cache flag to that of the source // unconditionally.
mbValueCached = r.mbValueCached;
if (r.mbEmpty)
{ if (mbToken && mpToken)
mpToken->DecRef();
mbToken = false;
mbNoneRefCnt = false;
mbEmpty = true;
mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
meMultiline = r.meMultiline; // here r.mfValue will be 0.0 which is ensured in ResolveToken().
mfValue = 0.0;
} elseif (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.
SetResultError(r.mnError);
}
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) : nullptr); if (pMatResult)
{ const ScMatrixFormulaCellToken* pNewMatFormula = dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult); if (pNewMatFormula && (pMatFormula->GetMatCols() <= 0 || pMatFormula->GetMatRows() <= 0))
{
SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
pNewMatFormula->GetMatRows());
}
pMatFormula->Assign( *pMatResult);
p->DecRef();
} elseif (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);
}
}
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;
mbNoneRefCnt = false;
meMultiline = MULTILINE_FALSE;
mbValueCached = true;
}
}
formula::StackVar ScFormulaResult::GetType() const
{ // Order is significant. if (mnError != FormulaError::NONE) return formula::svError; if (mbEmpty) return formula::svEmptyCell; if (!mbToken) return formula::svDouble; if (mpToken) return mpToken->GetType(); return formula::svUnknown;
}
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;
}
bool ScFormulaResult::IsEmptyDisplayedAsString() const
{ if (mbEmpty) return mbEmptyDisplayedAsString; switch (GetType())
{ case 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().get()); if (p) return p->IsDisplayedAsString();
} break; case formula::svHybridCell:
{ const ScHybridCellToken* p = static_cast<const ScHybridCellToken*>(mpToken); return p->IsEmptyDisplayedAsString();
} break; default: break;
} returnfalse;
}
namespace {
bool isValue( formula::StackVar sv )
{ return sv == formula::svDouble || sv == formula::svError
|| sv == formula::svEmptyCell // The initial uninitialized result value is double 0.0, even if the type // is unknown, so the interpreter asking for it gets that double // instead of having to convert a string which may result in #VALUE! // (otherwise the unknown would be neither error nor double nor string)
|| sv == formula::svUnknown;
}
bool isString( formula::StackVar sv )
{ switch (sv)
{ case formula::svString: case formula::svHybridCell: returntrue; default: break;
}
returnfalse;
}
}
bool ScFormulaResult::IsValue() const
{ if (IsEmptyDisplayedAsString()) returntrue;
return isValue(GetCellResultType());
}
bool ScFormulaResult::IsValueNoError() const
{ switch (GetCellResultType())
{ case formula::svDouble: case formula::svEmptyCell: returntrue; default: returnfalse;
}
}
if (mnError != FormulaError::NONE)
{
rErr = mnError; returntrue;
}
formula::StackVar sv = GetCellResultType(); if (sv == formula::svError)
{ if (GetType() == formula::svMatrixCell)
{ // don't need to test for mpToken here, GetType() already did it
rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
GetUpperLeftToken()->GetError();
} elseif (mpToken)
{
rErr = mpToken->GetError();
}
}
if (rErr != FormulaError::NONE) returntrue;
if (!isValue(sv)) returnfalse;
rVal = GetDouble(); returntrue;
}
sc::FormulaResultValue ScFormulaResult::GetResult() const
{ if (mbValueCached) return sc::FormulaResultValue(mfValue);
if (mnError != FormulaError::NONE) return sc::FormulaResultValue(mnError);
formula::StackVar sv = GetCellResultType();
FormulaError nErr = FormulaError::NONE; if (sv == formula::svError)
{ if (GetType() == formula::svMatrixCell)
{ // don't need to test for mpToken here, GetType() already did it
nErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
GetUpperLeftToken()->GetError();
} elseif (mpToken)
{
nErr = mpToken->GetError();
}
}
if (nErr != FormulaError::NONE) return sc::FormulaResultValue(nErr);
if (isValue(sv)) return sc::FormulaResultValue(GetDouble());
if (!mbToken) // String result type needs token. return sc::FormulaResultValue();
if (isString(sv)) return sc::FormulaResultValue(GetString(), IsMultiline());
// Invalid return sc::FormulaResultValue();
}
FormulaError ScFormulaResult::GetResultError() const
{ if (mnError != FormulaError::NONE) 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 returnstatic_cast<const ScMatrixCellResultToken*>(mpToken)->
GetUpperLeftToken()->GetError(); if (mpToken) return mpToken->GetError();
} return FormulaError::NONE;
}
formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
{ if (GetType() == formula::svMatrixCell) // don't need to test for mpToken here, GetType() already did it returnstatic_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken(); return GetToken();
}
double ScFormulaResult::GetDouble() const
{ if (mbValueCached) return mfValue;
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
}
} // Note that we reach here also for the default ctor and // formula::svUnknown from GetType(). return 0.0;
} if (mbEmpty) return 0.0; return mfValue;
}
const svl::SharedString & 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 svl::SharedString::getEmptyString();
}
void ScFormulaResult::SetHybridEmptyDisplayedAsString()
{ // Obtain values before changing anything. double f = GetDouble();
OUString aFormula( GetHybridFormula());
svl::SharedString aStr = GetString();
ResetToDefaults(); if (mbToken && mpToken)
mpToken->DecRef(); // XXX NOTE: we can't use mbEmpty and mbEmptyDisplayedAsString here because // GetType() intentionally returns svEmptyCell if mbEmpty==true. So stick // it into the ScHybridCellToken.
mpToken = new ScHybridCellToken( f, aStr, aFormula, true);
mpToken->IncRef();
mbToken = true;
mbNoneRefCnt = false;
}
// If a token from the original tokens, supplied to a parallel group calculation // while RefCounting was disabled for those tokens, ends up as a FormulaResult // token, then fix up the ref count now void ScFormulaResult::HandleStuffAfterParallelCalculation()
{ if (mbNoneRefCnt)
{
assert(mbToken && mpToken && mpToken->GetRefCntPolicy() != formula::RefCntPolicy::None);
mpToken->IncRef();
mbNoneRefCnt = false;
} // If ScInterpreter::CreateFormulaDoubleToken tokens make it into a result if (mbToken && mpToken)
{ // I don't see any evidence that this can happen, but assert if it arises
assert(mpToken->GetRefCntPolicy() == formula::RefCntPolicy::ThreadSafe); const_cast<formula::FormulaToken*>(mpToken)->SetRefCntPolicy(formula::RefCntPolicy::ThreadSafe);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.