tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / tool / formularesult.cxx
blobe326da7f2121268961a4a69a72e3976c3c10d417
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <formularesult.hxx>
11 #include <scmatrix.hxx>
12 #include <token.hxx>
14 #include <sal/log.hxx>
15 #include <utility>
17 namespace sc {
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() :
27 mpToken(nullptr),
28 mbToken(true),
29 mbNoneRefCnt(false),
30 mbEmpty(false),
31 mbEmptyDisplayedAsString(false),
32 mbValueCached(false),
33 meMultiline(MULTILINE_UNKNOWN),
34 mnError(FormulaError::NONE) {}
36 ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
37 mbToken( r.mbToken),
38 mbEmpty( r.mbEmpty),
39 mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
40 mbValueCached( r.mbValueCached),
41 meMultiline( r.meMultiline),
42 mnError( r.mnError)
44 if (mbToken)
46 mpToken = r.mpToken;
47 if (mpToken)
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();
55 if (pMatFormula)
56 mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
57 mpToken->IncRef();
60 else
61 mfValue = r.mfValue;
62 mbNoneRefCnt = mbToken && mpToken && mpToken->GetRefCntPolicy() == formula::RefCntPolicy::None;
65 ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
66 mbToken(false),
67 mbNoneRefCnt(false),
68 mbEmpty(false),
69 mbEmptyDisplayedAsString(false),
70 mbValueCached(false),
71 meMultiline(MULTILINE_UNKNOWN),
72 mnError(FormulaError::NONE)
74 SetToken( p);
77 ScFormulaResult::~ScFormulaResult()
79 if (mbToken && mpToken)
80 mpToken->DecRef();
83 void ScFormulaResult::ResetToDefaults()
85 mnError = FormulaError::NONE;
86 mbEmpty = false;
87 mbEmptyDisplayedAsString = false;
88 meMultiline = MULTILINE_UNKNOWN;
89 mbValueCached = false;
92 void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
94 ResetToDefaults();
95 if (!p)
97 mpToken = p;
98 mbToken = true;
100 else
102 switch (p->GetType())
104 case formula::svError:
105 mnError = p->GetError();
106 p->DecRef();
107 mbToken = false;
108 // set in case mnError is 0 now, which shouldn't happen but ...
109 mfValue = 0.0;
110 meMultiline = MULTILINE_FALSE;
111 break;
112 case formula::svEmptyCell:
113 mbEmpty = true;
114 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
115 p->DecRef();
116 mbToken = false;
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.
120 mfValue = 0.0;
121 mbValueCached = true;
122 break;
123 case formula::svDouble:
124 mfValue = p->GetDouble();
125 p->DecRef();
126 mbToken = false;
127 meMultiline = MULTILINE_FALSE;
128 mbValueCached = true;
129 break;
130 default:
131 mpToken = p;
132 mbToken = true;
135 mbNoneRefCnt = mbToken && mpToken && mpToken->GetRefCntPolicy() == formula::RefCntPolicy::None;
138 ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
140 Assign( r);
141 return *this;
144 void ScFormulaResult::Assign( const ScFormulaResult & r )
146 if (this == &r)
147 return;
149 // It is important to reset the value-cache flag to that of the source
150 // unconditionally.
151 mbValueCached = r.mbValueCached;
153 if (r.mbEmpty)
155 if (mbToken && mpToken)
156 mpToken->DecRef();
157 mbToken = false;
158 mbNoneRefCnt = false;
159 mbEmpty = true;
160 mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
161 meMultiline = r.meMultiline;
162 // here r.mfValue will be 0.0 which is ensured in ResolveToken().
163 mfValue = 0.0;
165 else if (r.mbToken)
167 // Matrix formula cell token must be cloned, see copy-ctor.
168 const ScMatrixFormulaCellToken* pMatFormula =
169 r.GetMatrixFormulaCellToken();
170 if (pMatFormula)
171 SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
172 else
173 SetToken( r.mpToken);
175 else
176 SetDouble( r.mfValue);
177 // If there was an error there will be an error, no matter what Set...()
178 // methods did.
179 SetResultError(r.mnError);
182 void ScFormulaResult::SetToken( const formula::FormulaToken* p )
184 ResetToDefaults();
185 if (p)
186 p->IncRef();
187 // Handle a result obtained from the interpreter to be assigned to a matrix
188 // formula cell's ScMatrixFormulaCellToken.
189 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
190 if (pMatFormula)
192 const ScMatrixCellResultToken* pMatResult =
193 (p && p->GetType() == formula::svMatrixCell ?
194 dynamic_cast<const ScMatrixCellResultToken*>(p) : nullptr);
195 if (pMatResult)
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);
206 p->DecRef();
208 else if (p)
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);
214 p->DecRef();
216 else
218 // NULL result? Well, if you say so ...
219 pMatFormula->ResetResult();
222 else
224 if (mbToken && mpToken)
225 mpToken->DecRef();
226 ResolveToken( p);
230 void ScFormulaResult::SetDouble( double f )
232 ResetToDefaults();
233 // Handle a result obtained from the interpreter to be assigned to a matrix
234 // formula cell's ScMatrixFormulaCellToken.
235 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
236 if (pMatFormula)
237 pMatFormula->SetUpperLeftDouble( f);
238 else
240 if (mbToken && mpToken)
241 mpToken->DecRef();
242 mfValue = f;
243 mbToken = false;
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;
255 if (mbEmpty)
256 return formula::svEmptyCell;
257 if (!mbToken)
258 return formula::svDouble;
259 if (mpToken)
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();
270 return sv;
273 bool ScFormulaResult::IsEmptyDisplayedAsString() const
275 if (mbEmpty)
276 return mbEmptyDisplayedAsString;
277 switch (GetType())
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());
285 if (p)
286 return p->IsDisplayedAsString();
288 break;
289 case formula::svHybridCell:
291 const ScHybridCellToken* p = static_cast<const ScHybridCellToken*>(mpToken);
292 return p->IsEmptyDisplayedAsString();
294 break;
295 default:
296 break;
298 return false;
301 namespace {
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 )
316 switch (sv)
318 case formula::svString:
319 case formula::svHybridCell:
320 return true;
321 default:
322 break;
325 return false;
330 bool ScFormulaResult::IsValue() const
332 if (IsEmptyDisplayedAsString())
333 return true;
335 return isValue(GetCellResultType());
338 bool ScFormulaResult::IsValueNoError() const
340 switch (GetCellResultType())
342 case formula::svDouble:
343 case formula::svEmptyCell:
344 return true;
345 default:
346 return false;
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;
357 else
358 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
360 return meMultiline == MULTILINE_TRUE;
363 bool ScFormulaResult::GetErrorOrDouble( FormulaError& rErr, double& rVal ) const
365 if (mbValueCached)
367 rVal = mfValue;
368 return true;
371 if (mnError != FormulaError::NONE)
373 rErr = mnError;
374 return true;
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();
386 else if (mpToken)
388 rErr = mpToken->GetError();
392 if (rErr != FormulaError::NONE)
393 return true;
395 if (!isValue(sv))
396 return false;
398 rVal = GetDouble();
399 return true;
402 sc::FormulaResultValue ScFormulaResult::GetResult() const
404 if (mbValueCached)
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();
420 else if (mpToken)
422 nErr = mpToken->GetError();
426 if (nErr != FormulaError::NONE)
427 return sc::FormulaResultValue(nErr);
429 if (isValue(sv))
430 return sc::FormulaResultValue(GetDouble());
432 if (!mbToken)
433 // String result type needs token.
434 return sc::FormulaResultValue();
436 if (isString(sv))
437 return sc::FormulaResultValue(GetString(), IsMultiline());
439 // Invalid
440 return sc::FormulaResultValue();
443 FormulaError ScFormulaResult::GetResultError() const
445 if (mnError != FormulaError::NONE)
446 return mnError;
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();
454 if (mpToken)
455 return mpToken->GetError();
457 return FormulaError::NONE;
460 void ScFormulaResult::SetResultError( FormulaError nErr )
462 mnError = nErr;
463 if (mnError != FormulaError::NONE)
464 mbValueCached = false;
467 formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
469 if (mbToken)
470 return mpToken;
471 return nullptr;
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();
479 return GetToken();
482 double ScFormulaResult::GetDouble() const
484 if (mbValueCached)
485 return mfValue;
487 if (mbToken)
489 // Should really not be of type formula::svDouble here.
490 if (mpToken)
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();
503 break;
504 default:
505 ; // nothing
508 // Note that we reach here also for the default ctor and
509 // formula::svUnknown from GetType().
510 return 0.0;
512 if (mbEmpty)
513 return 0.0;
514 return mfValue;
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();
533 break;
534 default:
535 ; // nothing
538 return svl::SharedString::getEmptyString();
541 ScConstMatrixRef ScFormulaResult::GetMatrix() const
543 if (GetType() == formula::svMatrixCell)
544 return mpToken->GetMatrix();
545 return nullptr;
548 OUString ScFormulaResult::GetHybridFormula() const
550 if (GetType() == formula::svHybridCell)
552 const ScHybridCellToken* p = static_cast<const ScHybridCellToken*>(mpToken);
553 return p->GetFormula();
555 return OUString();
558 void ScFormulaResult::SetHybridDouble( double f )
560 ResetToDefaults();
561 if (mbToken && mpToken)
563 if(GetType() == formula::svMatrixCell)
564 SetDouble(f);
565 else
567 svl::SharedString aString = GetString();
568 OUString aFormula( GetHybridFormula());
569 mpToken->DecRef();
570 mpToken = new ScHybridCellToken( f, aString, aFormula, false);
571 mpToken->IncRef();
572 mbNoneRefCnt = false;
575 else
577 mfValue = f;
578 mbToken = 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());
590 ResetToDefaults();
591 if (mbToken && mpToken)
592 mpToken->DecRef();
593 mpToken = new ScHybridCellToken( f, rStr, aFormula, false);
594 mpToken->IncRef();
595 mbToken = true;
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();
605 ResetToDefaults();
606 if (mbToken && mpToken)
607 mpToken->DecRef();
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);
612 mpToken->IncRef();
613 mbToken = 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();
622 ResetToDefaults();
623 if (mbToken && mpToken)
624 mpToken->DecRef();
625 mpToken = new ScHybridCellToken( f, aStr, rFormula, false);
626 mpToken->IncRef();
627 mbToken = true;
628 mbNoneRefCnt = false;
631 void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL )
633 ResetToDefaults();
634 if (mbToken && mpToken)
635 mpToken->DecRef();
636 mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
637 mpToken->IncRef();
638 mbToken = true;
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()
658 if (mbNoneRefCnt)
660 assert(mbToken && mpToken && mpToken->GetRefCntPolicy() != formula::RefCntPolicy::None);
661 mpToken->IncRef();
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: */