LibreOffice Module sc (master)  1
formularesult.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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  */
9 
10 #include <formularesult.hxx>
11 #include <scmatrix.hxx>
12 #include <token.hxx>
13 
14 #include <sal/log.hxx>
15 
16 namespace sc {
17 
19 FormulaResultValue::FormulaResultValue( double fValue ) : mfValue(fValue), meType(Value), mnError(FormulaError::NONE) {}
21 FormulaResultValue::FormulaResultValue( FormulaError nErr ) : mfValue(0.0), meType(Error), mnError(nErr) {}
22 
23 }
24 
26  mpToken(nullptr),
27  mbToken(true),
28  mbEmpty(false),
29  mbEmptyDisplayedAsString(false),
30  mbValueCached(false),
31  meMultiline(MULTILINE_UNKNOWN),
32  mnError(FormulaError::NONE) {}
33 
35  mbToken( r.mbToken),
36  mbEmpty( r.mbEmpty),
37  mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
38  mbValueCached( r.mbValueCached),
39  meMultiline( r.meMultiline),
40  mnError( r.mnError)
41 {
42  if (mbToken)
43  {
44  mpToken = r.mpToken;
45  if (mpToken)
46  {
47  // Since matrix dimension and
48  // results are assigned to a matrix
49  // cell formula token we have to
50  // clone that instead of sharing it.
51  const ScMatrixFormulaCellToken* pMatFormula =
53  if (pMatFormula)
54  {
55  mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
56  mpToken->IncRef();
57  }
58  else
60  }
61  }
62  else
63  mfValue = r.mfValue;
64 }
65 
67  mbToken(false),
68  mbEmpty(false),
69  mbEmptyDisplayedAsString(false),
70  mbValueCached(false),
71  meMultiline(MULTILINE_UNKNOWN),
72  mnError(FormulaError::NONE)
73 {
74  SetToken( p);
75 }
76 
78 {
79  if (mbToken && mpToken)
80  mpToken->DecRef();
81 }
82 
84 {
85  mnError = FormulaError::NONE;
86  mbEmpty = false;
89  mbValueCached = false;
90 }
91 
93 {
95  if (!p)
96  {
97  mpToken = p;
98  mbToken = true;
99  }
100  else
101  {
102  switch (p->GetType())
103  {
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;
111  break;
113  mbEmpty = true;
114  mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
115  p->DecRef();
116  mbToken = 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;
128  mbValueCached = true;
129  break;
130  default:
131  mpToken = p;
132  mbToken = true;
133  }
134  }
135 }
136 
138 {
139  Assign( r);
140  return *this;
141 }
142 
144 {
145  if (this == &r)
146  return;
147 
148  // It is important to reset the value-cache flag to that of the source
149  // unconditionally.
151 
152  if (r.mbEmpty)
153  {
154  if (mbToken && mpToken)
155  mpToken->DecRef();
156  mbToken = false;
157  mbEmpty = true;
160  // here r.mfValue will be 0.0 which is ensured in ResolveToken().
161  mfValue = 0.0;
162  }
163  else if (r.mbToken)
164  {
165  // Matrix formula cell token must be cloned, see copy-ctor.
166  const ScMatrixFormulaCellToken* pMatFormula =
168  if (pMatFormula)
169  SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
170  else
171  SetToken( r.mpToken);
172  }
173  else
174  SetDouble( r.mfValue);
175  // If there was an error there will be an error, no matter what Set...()
176  // methods did.
178 }
179 
181 {
182  ResetToDefaults();
183  IncrementTokenRef( p);
184  // Handle a result obtained from the interpreter to be assigned to a matrix
185  // formula cell's ScMatrixFormulaCellToken.
187  if (pMatFormula)
188  {
189  const ScMatrixCellResultToken* pMatResult =
190  (p && p->GetType() == formula::svMatrixCell ?
191  dynamic_cast<const ScMatrixCellResultToken*>(p) : nullptr);
192  if (pMatResult)
193  {
194  const ScMatrixFormulaCellToken* pNewMatFormula =
195  dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
196  if (pNewMatFormula && (pMatFormula->GetMatCols() <= 0 || pMatFormula->GetMatRows() <= 0))
197  {
198  SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
199  pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
200  pNewMatFormula->GetMatRows());
201  }
202  pMatFormula->Assign( *pMatResult);
203  p->DecRef();
204  }
205  else if (p)
206  {
207  // This may be the result of some constant expression like
208  // {="string"} that doesn't result in a matrix but still would
209  // display the result in all cells of this matrix formula.
210  pMatFormula->Assign( *p);
211  p->DecRef();
212  }
213  else
214  {
215  // NULL result? Well, if you say so ...
216  pMatFormula->ResetResult();
217  }
218  }
219  else
220  {
221  if (mbToken && mpToken)
222  mpToken->DecRef();
223  ResolveToken( p);
224  }
225 }
226 
228 {
229  ResetToDefaults();
230  // Handle a result obtained from the interpreter to be assigned to a matrix
231  // formula cell's ScMatrixFormulaCellToken.
233  if (pMatFormula)
234  pMatFormula->SetUpperLeftDouble( f);
235  else
236  {
237  if (mbToken && mpToken)
238  mpToken->DecRef();
239  mfValue = f;
240  mbToken = false;
242  mbValueCached = true;
243  }
244 }
245 
247 {
248  // Order is significant.
249  if (mnError != FormulaError::NONE)
250  return formula::svError;
251  if (mbEmpty)
252  return formula::svEmptyCell;
253  if (!mbToken)
254  return formula::svDouble;
255  if (mpToken)
256  return mpToken->GetType();
257  return formula::svUnknown;
258 }
259 
261 {
262  formula::StackVar sv = GetType();
263  if (sv == formula::svMatrixCell)
264  // don't need to test for mpToken here, GetType() already did it
265  sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
266  return sv;
267 }
268 
270 {
271  if (mbEmpty)
273  switch (GetType())
274  {
276  {
277  // don't need to test for mpToken here, GetType() already did it
278  const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
279  static_cast<const ScMatrixCellResultToken*>(
280  mpToken)->GetUpperLeftToken().get());
281  if (p)
282  return p->IsDisplayedAsString();
283  }
284  break;
286  {
287  const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
288  if (p)
289  return p->IsEmptyDisplayedAsString();
290  }
291  break;
292  default:
293  break;
294  }
295  return false;
296 }
297 
298 namespace {
299 
300 bool isValue( formula::StackVar sv )
301 {
302  return sv == formula::svDouble || sv == formula::svError
303  || sv == formula::svEmptyCell
304  // The initial uninitialized result value is double 0.0, even if the type
305  // is unknown, so the interpreter asking for it gets that double
306  // instead of having to convert a string which may result in #VALUE!
307  // (otherwise the unknown would be neither error nor double nor string)
308  || sv == formula::svUnknown;
309 }
310 
311 bool isString( formula::StackVar sv )
312 {
313  switch (sv)
314  {
315  case formula::svString:
317  return true;
318  default:
319  break;
320  }
321 
322  return false;
323 }
324 
325 }
326 
328 {
330  return true;
331 
332  return isValue(GetCellResultType());
333 }
334 
336 {
337  switch (GetCellResultType())
338  {
339  case formula::svDouble:
341  return true;
342  default:
343  return false;
344  }
345 }
346 
348 {
350  {
352  if (!aStr.isEmpty() && aStr.getString().indexOf('\n') != -1)
353  const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
354  else
355  const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
356  }
357  return meMultiline == MULTILINE_TRUE;
358 }
359 
360 bool ScFormulaResult::GetErrorOrDouble( FormulaError& rErr, double& rVal ) const
361 {
362  if (mbValueCached)
363  {
364  rVal = mfValue;
365  return true;
366  }
367 
368  if (mnError != FormulaError::NONE)
369  {
370  rErr = mnError;
371  return true;
372  }
373 
375  if (sv == formula::svError)
376  {
378  {
379  // don't need to test for mpToken here, GetType() already did it
380  rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
381  GetUpperLeftToken()->GetError();
382  }
383  else if (mpToken)
384  {
385  rErr = mpToken->GetError();
386  }
387  }
388 
389  if (rErr != FormulaError::NONE)
390  return true;
391 
392  if (!isValue(sv))
393  return false;
394 
395  rVal = GetDouble();
396  return true;
397 }
398 
400 {
401  if (mbValueCached)
403 
404  if (mnError != FormulaError::NONE)
406 
408  FormulaError nErr = FormulaError::NONE;
409  if (sv == formula::svError)
410  {
412  {
413  // don't need to test for mpToken here, GetType() already did it
414  nErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
415  GetUpperLeftToken()->GetError();
416  }
417  else if (mpToken)
418  {
419  nErr = mpToken->GetError();
420  }
421  }
422 
423  if (nErr != FormulaError::NONE)
424  return sc::FormulaResultValue(nErr);
425 
426  if (isValue(sv))
428 
429  if (!mbToken)
430  // String result type needs token.
431  return sc::FormulaResultValue();
432 
433  if (isString(sv))
435 
436  // Invalid
437  return sc::FormulaResultValue();
438 }
439 
441 {
442  if (mnError != FormulaError::NONE)
443  return mnError;
445  if (sv == formula::svError)
446  {
448  // don't need to test for mpToken here, GetType() already did it
449  return static_cast<const ScMatrixCellResultToken*>(mpToken)->
450  GetUpperLeftToken()->GetError();
451  if (mpToken)
452  return mpToken->GetError();
453  }
454  return FormulaError::NONE;
455 }
456 
458 {
459  mnError = nErr;
460  if (mnError != FormulaError::NONE)
461  mbValueCached = false;
462 }
463 
465 {
466  if (mbToken)
467  return mpToken;
468  return nullptr;
469 }
470 
472 {
474  // don't need to test for mpToken here, GetType() already did it
475  return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
476  return GetToken();
477 }
478 
480 {
481  if (mbValueCached)
482  return mfValue;
483 
484  if (mbToken)
485  {
486  // Should really not be of type formula::svDouble here.
487  if (mpToken)
488  {
489  switch (mpToken->GetType())
490  {
492  return mpToken->GetDouble();
494  {
495  const ScMatrixCellResultToken* p =
496  static_cast<const ScMatrixCellResultToken*>(mpToken);
498  return p->GetUpperLeftToken()->GetDouble();
499  }
500  break;
501  default:
502  ; // nothing
503  }
504  }
505  // Note that we reach here also for the default ctor and
506  // formula::svUnknown from GetType().
507  return 0.0;
508  }
509  if (mbEmpty)
510  return 0.0;
511  return mfValue;
512 }
513 
515 {
516  if (mbToken && mpToken)
517  {
518  switch (mpToken->GetType())
519  {
520  case formula::svString:
522  return mpToken->GetString();
524  {
525  const ScMatrixCellResultToken* p =
526  static_cast<const ScMatrixCellResultToken*>(mpToken);
528  return p->GetUpperLeftToken()->GetString();
529  }
530  break;
531  default:
532  ; // nothing
533  }
534  }
536 }
537 
539 {
541  return mpToken->GetMatrix();
542  return nullptr;
543 }
544 
545 const OUString& ScFormulaResult::GetHybridFormula() const
546 {
548  {
549  const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
550  if (p)
551  return p->GetFormula();
552  }
553  return EMPTY_OUSTRING;
554 }
555 
557 {
558  ResetToDefaults();
559  if (mbToken && mpToken)
560  {
562  SetDouble(f);
563  else
564  {
565  svl::SharedString aString = GetString();
566  OUString aFormula( GetHybridFormula());
567  mpToken->DecRef();
568  mpToken = new ScHybridCellToken( f, aString, aFormula, false);
569  mpToken->IncRef();
570  }
571  }
572  else
573  {
574  mfValue = f;
575  mbToken = false;
577  mbValueCached = true;
578  }
579 }
580 
582 {
583  // Obtain values before changing anything.
584  double f = GetDouble();
585  OUString aFormula( GetHybridFormula());
586  ResetToDefaults();
587  if (mbToken && mpToken)
588  mpToken->DecRef();
589  mpToken = new ScHybridCellToken( f, rStr, aFormula, false);
590  mpToken->IncRef();
591  mbToken = true;
592 }
593 
595 {
596  // Obtain values before changing anything.
597  double f = GetDouble();
598  OUString aFormula( GetHybridFormula());
600  ResetToDefaults();
601  if (mbToken && mpToken)
602  mpToken->DecRef();
603  // XXX NOTE: we can't use mbEmpty and mbEmptyDisplayedAsString here because
604  // GetType() intentionally returns svEmptyCell if mbEmpty==true. So stick
605  // it into the ScHybridCellToken.
606  mpToken = new ScHybridCellToken( f, aStr, aFormula, true);
607  mpToken->IncRef();
608  mbToken = true;
609 }
610 
611 void ScFormulaResult::SetHybridFormula( const OUString & rFormula )
612 {
613  // Obtain values before changing anything.
614  double f = GetDouble();
616  ResetToDefaults();
617  if (mbToken && mpToken)
618  mpToken->DecRef();
619  mpToken = new ScHybridCellToken( f, aStr, rFormula, false);
620  mpToken->IncRef();
621  mbToken = true;
622 }
623 
624 void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL )
625 {
626  ResetToDefaults();
627  if (mbToken && mpToken)
628  mpToken->DecRef();
629  mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
630  mpToken->IncRef();
631  mbToken = true;
632 }
633 
635 {
636  return (GetType() == formula::svMatrixCell ?
637  dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : nullptr);
638 }
639 
641 {
642  return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
643 }
644 
645 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void IncrementTokenRef(const formula::FormulaToken *&rp)
void SetHybridFormula(const OUString &rFormula)
Should only be used by import filters, best in the order SetHybridDouble(), SetHybridString()/SetHybr...
::boost::intrusive_ptr< const FormulaToken > FormulaConstTokenRef
formula::StackVar GetUpperLeftType() const
Definition: token.hxx:313
virtual svl::SharedString GetString() const
OUString getString() const
formula::FormulaConstTokenRef GetCellResultToken() const
Return upper left token if formula::svMatrixCell, else return GetToken().
#define EMPTY_OUSTRING
Definition: global.hxx:215
formula::StackVar GetType() const
Return type of result, including formula::svError, formula::svEmptyCell, formula::svDouble and formul...
static SharedString getEmptyString()
static const Multiline MULTILINE_UNKNOWN
svl::SharedString GetString() const
Return string if type formula::svString or formula::svHybridCell or formula::svMatrixCell and upper l...
void SetMatrix(SCCOL nCols, SCROW nRows, const ScConstMatrixRef &pMat, const formula::FormulaToken *pUL)
static const Multiline MULTILINE_TRUE
svl::SharedString maString
Definition: scmatrix.cxx:3348
const OUString & GetHybridFormula() const
Return formula string if type formula::svHybridCell, else empty string.
virtual double GetDouble() const
void IncRef() const
void Assign(const ScMatrixCellResultToken &r)
Assign matrix result, keep matrix formula dimension.
Definition: token.cxx:1042
void SetResultError(FormulaError nErr)
Set error code, don't touch token or double.
Stores the matrix result at the formula cell, additionally the range the matrix formula occupies...
Definition: token.hxx:325
void SetHybridEmptyDisplayedAsString()
Should only be used by import filters, best in the order SetHybridDouble(), SetHybridFormula(), SetHybridEmptyDisplayedAsString() must be last.
NONE
Value
Transports the result from the interpreter to the formula cell.
Definition: token.hxx:295
virtual const ScMatrix * GetMatrix() const
bool IsMultiline() const
Determines whether or not the result is a string containing more than one paragraph.
Store a variable formula cell result, balancing between runtime performance and memory consumption...
bool IsEmptyDisplayedAsString() const
If type is formula::svEmptyCell (including matrix upper left) and should be displayed as empty string...
void SetMatColsRows(SCCOL nC, SCROW nR)
Definition: token.hxx:338
SCROW GetMatRows() const
Definition: token.hxx:349
void SetToken(const formula::FormulaToken *p)
Sets a direct double if token type is formula::svDouble, or mbEmpty if formula::svEmptyCell, else token.
virtual FormulaError GetError() const
bool IsValue() const
Test for cell result type formula::svDouble, including upper left if formula::svMatrixCell.
static const Multiline MULTILINE_FALSE
bool isEmpty() const
const formula::FormulaConstTokenRef & GetUpperLeftToken() const
Definition: token.hxx:319
const formula::FormulaToken * mpToken
bool GetErrorOrDouble(FormulaError &rErr, double &rVal) const
sal_Int16 SCCOL
Definition: types.hxx:22
ScFormulaResult & operator=(const ScFormulaResult &r)
Well, guess what ...
Error
ScConstMatrixRef GetMatrix() const
Return matrix if type formula::svMatrixCell and ScMatrix present, else NULL.
FormulaError mnError
FormulaError
ScMatrixFormulaCellToken * GetMatrixFormulaCellTokenNonConst()
Get the ScMatrixFormulaCellToken* if token is of that type, else NULL.
void ResetResult()
Reset matrix and upper left, keep matrix formula dimension.
Definition: token.cxx:1097
void Assign(const ScFormulaResult &r)
Assignment as in operator=() but without return.
sal_Int32 SCROW
Definition: types.hxx:18
bool IsValueNoError() const
Multiline meMultiline
SCCOL GetMatCols() const
Definition: token.hxx:348
ScFormulaResult()
Effectively type svUnknown.
void SetHybridDouble(double f)
Should only be used by import filters, best in the order SetHybridDouble(), SetHybridString(), or only SetHybridFormula() for formula string to be compiled later.
void ResetToDefaults()
Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults prior to assigning other types...
::boost::intrusive_ptr< const ScMatrix > ScConstMatrixRef
Definition: types.hxx:27
void SetUpperLeftDouble(double f)
Modify xUpperLeft if formula::svDouble, or create new formula::FormulaDoubleToken if not set yet...
Definition: token.cxx:1073
bool IsDisplayedAsString() const
Definition: token.hxx:287
void * p
void DecRef() const
formula::StackVar GetCellResultType() const
If type is formula::svMatrixCell return the type of upper left element, else GetType() ...
double GetDouble() const
Return value if type formula::svDouble or formula::svHybridCell or formula::svMatrixCell and upper le...
#define SAL_WARN(area, stream)
const ScMatrixFormulaCellToken * GetMatrixFormulaCellToken() const
Get the const ScMatrixFormulaCellToken* if token is of that type, else NULL.
void(* f)(TrueTypeTable *)
formula::FormulaConstTokenRef GetToken() const
May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! ...
void ResolveToken(const formula::FormulaToken *p)
If token is of formula::svError set error code and decrement RefCount.
void SetHybridString(const svl::SharedString &rStr)
Should only be used by import filters, best in the order SetHybridDouble(), SetHybridString()/SetHybr...
StackVar GetType() const
RedlineType meType
aStr
bool mbEmptyDisplayedAsString
void SetDouble(double f)
Set direct double.
const OUString & GetFormula() const
Definition: token.hxx:390
FormulaError GetResultError() const
Get error code if set or GetCellResultType() is formula::svError or svUnknown, else 0...
sc::FormulaResultValue GetResult() const
bool IsEmptyDisplayedAsString() const
Definition: token.hxx:391