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 = static_cast<const ScHybridCellToken*>(mpToken);
288  return p->IsEmptyDisplayedAsString();
289  }
290  break;
291  default:
292  break;
293  }
294  return false;
295 }
296 
297 namespace {
298 
299 bool isValue( formula::StackVar sv )
300 {
301  return sv == formula::svDouble || sv == formula::svError
302  || sv == formula::svEmptyCell
303  // The initial uninitialized result value is double 0.0, even if the type
304  // is unknown, so the interpreter asking for it gets that double
305  // instead of having to convert a string which may result in #VALUE!
306  // (otherwise the unknown would be neither error nor double nor string)
307  || sv == formula::svUnknown;
308 }
309 
310 bool isString( formula::StackVar sv )
311 {
312  switch (sv)
313  {
314  case formula::svString:
316  return true;
317  default:
318  break;
319  }
320 
321  return false;
322 }
323 
324 }
325 
327 {
329  return true;
330 
331  return isValue(GetCellResultType());
332 }
333 
335 {
336  switch (GetCellResultType())
337  {
338  case formula::svDouble:
340  return true;
341  default:
342  return false;
343  }
344 }
345 
347 {
349  {
351  if (!aStr.isEmpty() && aStr.getString().indexOf('\n') != -1)
352  const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
353  else
354  const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
355  }
356  return meMultiline == MULTILINE_TRUE;
357 }
358 
359 bool ScFormulaResult::GetErrorOrDouble( FormulaError& rErr, double& rVal ) const
360 {
361  if (mbValueCached)
362  {
363  rVal = mfValue;
364  return true;
365  }
366 
367  if (mnError != FormulaError::NONE)
368  {
369  rErr = mnError;
370  return true;
371  }
372 
374  if (sv == formula::svError)
375  {
377  {
378  // don't need to test for mpToken here, GetType() already did it
379  rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
380  GetUpperLeftToken()->GetError();
381  }
382  else if (mpToken)
383  {
384  rErr = mpToken->GetError();
385  }
386  }
387 
388  if (rErr != FormulaError::NONE)
389  return true;
390 
391  if (!isValue(sv))
392  return false;
393 
394  rVal = GetDouble();
395  return true;
396 }
397 
399 {
400  if (mbValueCached)
402 
403  if (mnError != FormulaError::NONE)
405 
407  FormulaError nErr = FormulaError::NONE;
408  if (sv == formula::svError)
409  {
411  {
412  // don't need to test for mpToken here, GetType() already did it
413  nErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
414  GetUpperLeftToken()->GetError();
415  }
416  else if (mpToken)
417  {
418  nErr = mpToken->GetError();
419  }
420  }
421 
422  if (nErr != FormulaError::NONE)
423  return sc::FormulaResultValue(nErr);
424 
425  if (isValue(sv))
427 
428  if (!mbToken)
429  // String result type needs token.
430  return sc::FormulaResultValue();
431 
432  if (isString(sv))
434 
435  // Invalid
436  return sc::FormulaResultValue();
437 }
438 
440 {
441  if (mnError != FormulaError::NONE)
442  return mnError;
444  if (sv == formula::svError)
445  {
447  // don't need to test for mpToken here, GetType() already did it
448  return static_cast<const ScMatrixCellResultToken*>(mpToken)->
449  GetUpperLeftToken()->GetError();
450  if (mpToken)
451  return mpToken->GetError();
452  }
453  return FormulaError::NONE;
454 }
455 
457 {
458  mnError = nErr;
459  if (mnError != FormulaError::NONE)
460  mbValueCached = false;
461 }
462 
464 {
465  if (mbToken)
466  return mpToken;
467  return nullptr;
468 }
469 
471 {
473  // don't need to test for mpToken here, GetType() already did it
474  return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
475  return GetToken();
476 }
477 
479 {
480  if (mbValueCached)
481  return mfValue;
482 
483  if (mbToken)
484  {
485  // Should really not be of type formula::svDouble here.
486  if (mpToken)
487  {
488  switch (mpToken->GetType())
489  {
491  return mpToken->GetDouble();
493  {
494  const ScMatrixCellResultToken* p =
495  static_cast<const ScMatrixCellResultToken*>(mpToken);
497  return p->GetUpperLeftToken()->GetDouble();
498  }
499  break;
500  default:
501  ; // nothing
502  }
503  }
504  // Note that we reach here also for the default ctor and
505  // formula::svUnknown from GetType().
506  return 0.0;
507  }
508  if (mbEmpty)
509  return 0.0;
510  return mfValue;
511 }
512 
514 {
515  if (mbToken && mpToken)
516  {
517  switch (mpToken->GetType())
518  {
519  case formula::svString:
521  return mpToken->GetString();
523  {
524  const ScMatrixCellResultToken* p =
525  static_cast<const ScMatrixCellResultToken*>(mpToken);
527  return p->GetUpperLeftToken()->GetString();
528  }
529  break;
530  default:
531  ; // nothing
532  }
533  }
535 }
536 
538 {
540  return mpToken->GetMatrix();
541  return nullptr;
542 }
543 
544 const OUString& ScFormulaResult::GetHybridFormula() const
545 {
547  {
548  const ScHybridCellToken* p = static_cast<const ScHybridCellToken*>(mpToken);
549  return p->GetFormula();
550  }
551  return EMPTY_OUSTRING;
552 }
553 
555 {
556  ResetToDefaults();
557  if (mbToken && mpToken)
558  {
560  SetDouble(f);
561  else
562  {
563  svl::SharedString aString = GetString();
564  OUString aFormula( GetHybridFormula());
565  mpToken->DecRef();
566  mpToken = new ScHybridCellToken( f, aString, aFormula, false);
567  mpToken->IncRef();
568  }
569  }
570  else
571  {
572  mfValue = f;
573  mbToken = false;
575  mbValueCached = true;
576  }
577 }
578 
580 {
581  // Obtain values before changing anything.
582  double f = GetDouble();
583  OUString aFormula( GetHybridFormula());
584  ResetToDefaults();
585  if (mbToken && mpToken)
586  mpToken->DecRef();
587  mpToken = new ScHybridCellToken( f, rStr, aFormula, false);
588  mpToken->IncRef();
589  mbToken = true;
590 }
591 
593 {
594  // Obtain values before changing anything.
595  double f = GetDouble();
596  OUString aFormula( GetHybridFormula());
598  ResetToDefaults();
599  if (mbToken && mpToken)
600  mpToken->DecRef();
601  // XXX NOTE: we can't use mbEmpty and mbEmptyDisplayedAsString here because
602  // GetType() intentionally returns svEmptyCell if mbEmpty==true. So stick
603  // it into the ScHybridCellToken.
604  mpToken = new ScHybridCellToken( f, aStr, aFormula, true);
605  mpToken->IncRef();
606  mbToken = true;
607 }
608 
609 void ScFormulaResult::SetHybridFormula( const OUString & rFormula )
610 {
611  // Obtain values before changing anything.
612  double f = GetDouble();
614  ResetToDefaults();
615  if (mbToken && mpToken)
616  mpToken->DecRef();
617  mpToken = new ScHybridCellToken( f, aStr, rFormula, false);
618  mpToken->IncRef();
619  mbToken = true;
620 }
621 
622 void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL )
623 {
624  ResetToDefaults();
625  if (mbToken && mpToken)
626  mpToken->DecRef();
627  mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
628  mpToken->IncRef();
629  mbToken = true;
630 }
631 
633 {
634  return (GetType() == formula::svMatrixCell ?
635  static_cast<const ScMatrixFormulaCellToken*>(mpToken) : nullptr);
636 }
637 
639 {
640  return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
641 }
642 
643 /* 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:312
OUString getString() const
formula::FormulaConstTokenRef GetCellResultToken() const
Return upper left token if formula::svMatrixCell, else return GetToken().
#define EMPTY_OUSTRING
Definition: global.hxx:213
formula::StackVar GetType() const
Return type of result, including formula::svError, formula::svEmptyCell, formula::svDouble and formul...
static const Multiline MULTILINE_UNKNOWN
void SetMatrix(SCCOL nCols, SCROW nRows, const ScConstMatrixRef &pMat, const formula::FormulaToken *pUL)
static const Multiline MULTILINE_TRUE
const OUString & GetHybridFormula() const
Return formula string if type formula::svHybridCell, else empty string.
virtual double GetDouble() const
static const SharedString & getEmptyString()
void IncRef() const
void Assign(const ScMatrixCellResultToken &r)
Assign matrix result, keep matrix formula dimension.
Definition: token.cxx:1050
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:324
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:294
OUString maString
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:337
SCROW GetMatRows() const
Definition: token.hxx:348
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:318
const formula::FormulaToken * mpToken
bool GetErrorOrDouble(FormulaError &rErr, double &rVal) const
sal_Int16 SCCOL
Definition: types.hxx:21
const svl::SharedString & GetString() const
Return string if type formula::svString or formula::svHybridCell or formula::svMatrixCell and upper l...
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:1105
void Assign(const ScFormulaResult &r)
Assignment as in operator=() but without return.
sal_Int32 SCROW
Definition: types.hxx:17
bool IsValueNoError() const
Multiline meMultiline
SCCOL GetMatCols() const
Definition: token.hxx:347
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.
virtual const svl::SharedString & GetString() const
void ResetToDefaults()
Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults prior to assigning other types...
::boost::intrusive_ptr< const ScMatrix > ScConstMatrixRef
Definition: types.hxx:26
void SetUpperLeftDouble(double f)
Modify xUpperLeft if formula::svDouble, or create new formula::FormulaDoubleToken if not set yet...
Definition: token.cxx:1081
bool IsDisplayedAsString() const
Definition: token.hxx:286
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:389
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:390