1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <formularesult.hxx>
11 #include <scmatrix.hxx>
14 #include <sal/log.hxx>
19 FormulaResultValue::FormulaResultValue() : mfValue(0.0), meType(Invalid
), mnError(FormulaError::NONE
) {}
20 FormulaResultValue::FormulaResultValue( double fValue
) : mfValue(fValue
), meType(Value
), mnError(FormulaError::NONE
) {}
21 FormulaResultValue::FormulaResultValue( svl::SharedString aStr
, bool bMultiLine
) : mfValue(0.0), maString(std::move(aStr
)), mbMultiLine(bMultiLine
), meType(String
), mnError(FormulaError::NONE
) {}
22 FormulaResultValue::FormulaResultValue( FormulaError nErr
) : mfValue(0.0), meType(Error
), mnError(nErr
) {}
26 ScFormulaResult::ScFormulaResult() :
31 mbEmptyDisplayedAsString(false),
33 meMultiline(MULTILINE_UNKNOWN
),
34 mnError(FormulaError::NONE
) {}
36 ScFormulaResult::ScFormulaResult( const ScFormulaResult
& r
) :
39 mbEmptyDisplayedAsString( r
.mbEmptyDisplayedAsString
),
40 mbValueCached( r
.mbValueCached
),
41 meMultiline( r
.meMultiline
),
49 // Since matrix dimension and
50 // results are assigned to a matrix
51 // cell formula token we have to
52 // clone that instead of sharing it.
53 const ScMatrixFormulaCellToken
* pMatFormula
=
54 r
.GetMatrixFormulaCellToken();
56 mpToken
= new ScMatrixFormulaCellToken( *pMatFormula
);
62 mbNoneRefCnt
= mbToken
&& mpToken
&& mpToken
->GetRefCntPolicy() == formula::RefCntPolicy::None
;
65 ScFormulaResult::ScFormulaResult( const formula::FormulaToken
* p
) :
69 mbEmptyDisplayedAsString(false),
71 meMultiline(MULTILINE_UNKNOWN
),
72 mnError(FormulaError::NONE
)
77 ScFormulaResult::~ScFormulaResult()
79 if (mbToken
&& mpToken
)
83 void ScFormulaResult::ResetToDefaults()
85 mnError
= FormulaError::NONE
;
87 mbEmptyDisplayedAsString
= false;
88 meMultiline
= MULTILINE_UNKNOWN
;
89 mbValueCached
= false;
92 void ScFormulaResult::ResolveToken( const formula::FormulaToken
* p
)
102 switch (p
->GetType())
104 case formula::svError
:
105 mnError
= p
->GetError();
108 // set in case mnError is 0 now, which shouldn't happen but ...
110 meMultiline
= MULTILINE_FALSE
;
112 case formula::svEmptyCell
:
114 mbEmptyDisplayedAsString
= static_cast<const ScEmptyCellToken
*>(p
)->IsDisplayedAsString();
117 meMultiline
= MULTILINE_FALSE
;
118 // Take advantage of fast double result return for empty result token.
119 // by setting mfValue to 0 and turning on mbValueCached flag.
121 mbValueCached
= true;
123 case formula::svDouble
:
124 mfValue
= p
->GetDouble();
127 meMultiline
= MULTILINE_FALSE
;
128 mbValueCached
= true;
135 mbNoneRefCnt
= mbToken
&& mpToken
&& mpToken
->GetRefCntPolicy() == formula::RefCntPolicy::None
;
138 ScFormulaResult
& ScFormulaResult::operator=( const ScFormulaResult
& r
)
144 void ScFormulaResult::Assign( const ScFormulaResult
& r
)
149 // It is important to reset the value-cache flag to that of the source
151 mbValueCached
= r
.mbValueCached
;
155 if (mbToken
&& mpToken
)
158 mbNoneRefCnt
= false;
160 mbEmptyDisplayedAsString
= r
.mbEmptyDisplayedAsString
;
161 meMultiline
= r
.meMultiline
;
162 // here r.mfValue will be 0.0 which is ensured in ResolveToken().
167 // Matrix formula cell token must be cloned, see copy-ctor.
168 const ScMatrixFormulaCellToken
* pMatFormula
=
169 r
.GetMatrixFormulaCellToken();
171 SetToken( new ScMatrixFormulaCellToken( *pMatFormula
));
173 SetToken( r
.mpToken
);
176 SetDouble( r
.mfValue
);
177 // If there was an error there will be an error, no matter what Set...()
179 SetResultError(r
.mnError
);
182 void ScFormulaResult::SetToken( const formula::FormulaToken
* p
)
187 // Handle a result obtained from the interpreter to be assigned to a matrix
188 // formula cell's ScMatrixFormulaCellToken.
189 ScMatrixFormulaCellToken
* pMatFormula
= GetMatrixFormulaCellTokenNonConst();
192 const ScMatrixCellResultToken
* pMatResult
=
193 (p
&& p
->GetType() == formula::svMatrixCell
?
194 dynamic_cast<const ScMatrixCellResultToken
*>(p
) : nullptr);
197 const ScMatrixFormulaCellToken
* pNewMatFormula
=
198 dynamic_cast<const ScMatrixFormulaCellToken
*>(pMatResult
);
199 if (pNewMatFormula
&& (pMatFormula
->GetMatCols() <= 0 || pMatFormula
->GetMatRows() <= 0))
201 SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
202 pMatFormula
->SetMatColsRows( pNewMatFormula
->GetMatCols(),
203 pNewMatFormula
->GetMatRows());
205 pMatFormula
->Assign( *pMatResult
);
210 // This may be the result of some constant expression like
211 // {="string"} that doesn't result in a matrix but still would
212 // display the result in all cells of this matrix formula.
213 pMatFormula
->Assign( *p
);
218 // NULL result? Well, if you say so ...
219 pMatFormula
->ResetResult();
224 if (mbToken
&& mpToken
)
230 void ScFormulaResult::SetDouble( double f
)
233 // Handle a result obtained from the interpreter to be assigned to a matrix
234 // formula cell's ScMatrixFormulaCellToken.
235 ScMatrixFormulaCellToken
* pMatFormula
= GetMatrixFormulaCellTokenNonConst();
237 pMatFormula
->SetUpperLeftDouble( f
);
240 if (mbToken
&& mpToken
)
244 mbNoneRefCnt
= false;
245 meMultiline
= MULTILINE_FALSE
;
246 mbValueCached
= true;
250 formula::StackVar
ScFormulaResult::GetType() const
252 // Order is significant.
253 if (mnError
!= FormulaError::NONE
)
254 return formula::svError
;
256 return formula::svEmptyCell
;
258 return formula::svDouble
;
260 return mpToken
->GetType();
261 return formula::svUnknown
;
264 formula::StackVar
ScFormulaResult::GetCellResultType() const
266 formula::StackVar sv
= GetType();
267 if (sv
== formula::svMatrixCell
)
268 // don't need to test for mpToken here, GetType() already did it
269 sv
= static_cast<const ScMatrixCellResultToken
*>(mpToken
)->GetUpperLeftType();
273 bool ScFormulaResult::IsEmptyDisplayedAsString() const
276 return mbEmptyDisplayedAsString
;
279 case formula::svMatrixCell
:
281 // don't need to test for mpToken here, GetType() already did it
282 const ScEmptyCellToken
* p
= dynamic_cast<const ScEmptyCellToken
*>(
283 static_cast<const ScMatrixCellResultToken
*>(
284 mpToken
)->GetUpperLeftToken().get());
286 return p
->IsDisplayedAsString();
289 case formula::svHybridCell
:
291 const ScHybridCellToken
* p
= static_cast<const ScHybridCellToken
*>(mpToken
);
292 return p
->IsEmptyDisplayedAsString();
303 bool isValue( formula::StackVar sv
)
305 return sv
== formula::svDouble
|| sv
== formula::svError
306 || sv
== formula::svEmptyCell
307 // The initial uninitialized result value is double 0.0, even if the type
308 // is unknown, so the interpreter asking for it gets that double
309 // instead of having to convert a string which may result in #VALUE!
310 // (otherwise the unknown would be neither error nor double nor string)
311 || sv
== formula::svUnknown
;
314 bool isString( formula::StackVar sv
)
318 case formula::svString
:
319 case formula::svHybridCell
:
330 bool ScFormulaResult::IsValue() const
332 if (IsEmptyDisplayedAsString())
335 return isValue(GetCellResultType());
338 bool ScFormulaResult::IsValueNoError() const
340 switch (GetCellResultType())
342 case formula::svDouble
:
343 case formula::svEmptyCell
:
350 bool ScFormulaResult::IsMultiline() const
352 if (meMultiline
== MULTILINE_UNKNOWN
)
354 svl::SharedString aStr
= GetString();
355 if (!aStr
.isEmpty() && aStr
.getString().indexOf('\n') != -1)
356 const_cast<ScFormulaResult
*>(this)->meMultiline
= MULTILINE_TRUE
;
358 const_cast<ScFormulaResult
*>(this)->meMultiline
= MULTILINE_FALSE
;
360 return meMultiline
== MULTILINE_TRUE
;
363 bool ScFormulaResult::GetErrorOrDouble( FormulaError
& rErr
, double& rVal
) const
371 if (mnError
!= FormulaError::NONE
)
377 formula::StackVar sv
= GetCellResultType();
378 if (sv
== formula::svError
)
380 if (GetType() == formula::svMatrixCell
)
382 // don't need to test for mpToken here, GetType() already did it
383 rErr
= static_cast<const ScMatrixCellResultToken
*>(mpToken
)->
384 GetUpperLeftToken()->GetError();
388 rErr
= mpToken
->GetError();
392 if (rErr
!= FormulaError::NONE
)
402 sc::FormulaResultValue
ScFormulaResult::GetResult() const
405 return sc::FormulaResultValue(mfValue
);
407 if (mnError
!= FormulaError::NONE
)
408 return sc::FormulaResultValue(mnError
);
410 formula::StackVar sv
= GetCellResultType();
411 FormulaError nErr
= FormulaError::NONE
;
412 if (sv
== formula::svError
)
414 if (GetType() == formula::svMatrixCell
)
416 // don't need to test for mpToken here, GetType() already did it
417 nErr
= static_cast<const ScMatrixCellResultToken
*>(mpToken
)->
418 GetUpperLeftToken()->GetError();
422 nErr
= mpToken
->GetError();
426 if (nErr
!= FormulaError::NONE
)
427 return sc::FormulaResultValue(nErr
);
430 return sc::FormulaResultValue(GetDouble());
433 // String result type needs token.
434 return sc::FormulaResultValue();
437 return sc::FormulaResultValue(GetString(), IsMultiline());
440 return sc::FormulaResultValue();
443 FormulaError
ScFormulaResult::GetResultError() const
445 if (mnError
!= FormulaError::NONE
)
447 formula::StackVar sv
= GetCellResultType();
448 if (sv
== formula::svError
)
450 if (GetType() == formula::svMatrixCell
)
451 // don't need to test for mpToken here, GetType() already did it
452 return static_cast<const ScMatrixCellResultToken
*>(mpToken
)->
453 GetUpperLeftToken()->GetError();
455 return mpToken
->GetError();
457 return FormulaError::NONE
;
460 void ScFormulaResult::SetResultError( FormulaError nErr
)
463 if (mnError
!= FormulaError::NONE
)
464 mbValueCached
= false;
467 formula::FormulaConstTokenRef
ScFormulaResult::GetToken() const
474 formula::FormulaConstTokenRef
ScFormulaResult::GetCellResultToken() const
476 if (GetType() == formula::svMatrixCell
)
477 // don't need to test for mpToken here, GetType() already did it
478 return static_cast<const ScMatrixCellResultToken
*>(mpToken
)->GetUpperLeftToken();
482 double ScFormulaResult::GetDouble() const
489 // Should really not be of type formula::svDouble here.
492 switch (mpToken
->GetType())
494 case formula::svHybridCell
:
495 return mpToken
->GetDouble();
496 case formula::svMatrixCell
:
498 const ScMatrixCellResultToken
* p
=
499 static_cast<const ScMatrixCellResultToken
*>(mpToken
);
500 if (p
->GetUpperLeftType() == formula::svDouble
)
501 return p
->GetUpperLeftToken()->GetDouble();
508 // Note that we reach here also for the default ctor and
509 // formula::svUnknown from GetType().
517 const svl::SharedString
& ScFormulaResult::GetString() const
519 if (mbToken
&& mpToken
)
521 switch (mpToken
->GetType())
523 case formula::svString
:
524 case formula::svHybridCell
:
525 return mpToken
->GetString();
526 case formula::svMatrixCell
:
528 const ScMatrixCellResultToken
* p
=
529 static_cast<const ScMatrixCellResultToken
*>(mpToken
);
530 if (p
->GetUpperLeftType() == formula::svString
)
531 return p
->GetUpperLeftToken()->GetString();
538 return svl::SharedString::getEmptyString();
541 ScConstMatrixRef
ScFormulaResult::GetMatrix() const
543 if (GetType() == formula::svMatrixCell
)
544 return mpToken
->GetMatrix();
548 OUString
ScFormulaResult::GetHybridFormula() const
550 if (GetType() == formula::svHybridCell
)
552 const ScHybridCellToken
* p
= static_cast<const ScHybridCellToken
*>(mpToken
);
553 return p
->GetFormula();
558 void ScFormulaResult::SetHybridDouble( double f
)
561 if (mbToken
&& mpToken
)
563 if(GetType() == formula::svMatrixCell
)
567 svl::SharedString aString
= GetString();
568 OUString
aFormula( GetHybridFormula());
570 mpToken
= new ScHybridCellToken( f
, aString
, aFormula
, false);
572 mbNoneRefCnt
= false;
579 mbNoneRefCnt
= false;
580 meMultiline
= MULTILINE_FALSE
;
581 mbValueCached
= true;
585 void ScFormulaResult::SetHybridString( const svl::SharedString
& rStr
)
587 // Obtain values before changing anything.
588 double f
= GetDouble();
589 OUString
aFormula( GetHybridFormula());
591 if (mbToken
&& mpToken
)
593 mpToken
= new ScHybridCellToken( f
, rStr
, aFormula
, false);
596 mbNoneRefCnt
= false;
599 void ScFormulaResult::SetHybridEmptyDisplayedAsString()
601 // Obtain values before changing anything.
602 double f
= GetDouble();
603 OUString
aFormula( GetHybridFormula());
604 svl::SharedString aStr
= GetString();
606 if (mbToken
&& mpToken
)
608 // XXX NOTE: we can't use mbEmpty and mbEmptyDisplayedAsString here because
609 // GetType() intentionally returns svEmptyCell if mbEmpty==true. So stick
610 // it into the ScHybridCellToken.
611 mpToken
= new ScHybridCellToken( f
, aStr
, aFormula
, true);
614 mbNoneRefCnt
= false;
617 void ScFormulaResult::SetHybridFormula( const OUString
& rFormula
)
619 // Obtain values before changing anything.
620 double f
= GetDouble();
621 svl::SharedString aStr
= GetString();
623 if (mbToken
&& mpToken
)
625 mpToken
= new ScHybridCellToken( f
, aStr
, rFormula
, false);
628 mbNoneRefCnt
= false;
631 void ScFormulaResult::SetMatrix( SCCOL nCols
, SCROW nRows
, const ScConstMatrixRef
& pMat
, const formula::FormulaToken
* pUL
)
634 if (mbToken
&& mpToken
)
636 mpToken
= new ScMatrixFormulaCellToken(nCols
, nRows
, pMat
, pUL
);
639 mbNoneRefCnt
= false;
642 const ScMatrixFormulaCellToken
* ScFormulaResult::GetMatrixFormulaCellToken() const
644 return (GetType() == formula::svMatrixCell
?
645 static_cast<const ScMatrixFormulaCellToken
*>(mpToken
) : nullptr);
648 ScMatrixFormulaCellToken
* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
650 return const_cast<ScMatrixFormulaCellToken
*>( GetMatrixFormulaCellToken());
653 // If a token from the original tokens, supplied to a parallel group calculation
654 // while RefCounting was disabled for those tokens, ends up as a FormulaResult
655 // token, then fix up the ref count now
656 void ScFormulaResult::HandleStuffAfterParallelCalculation()
660 assert(mbToken
&& mpToken
&& mpToken
->GetRefCntPolicy() != formula::RefCntPolicy::None
);
662 mbNoneRefCnt
= false;
664 // If ScInterpreter::CreateFormulaDoubleToken tokens make it into a result
665 if (mbToken
&& mpToken
)
667 // I don't see any evidence that this can happen, but assert if it arises
668 assert(mpToken
->GetRefCntPolicy() == formula::RefCntPolicy::ThreadSafe
);
669 const_cast<formula::FormulaToken
*>(mpToken
)->SetRefCntPolicy(formula::RefCntPolicy::ThreadSafe
);
673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */