Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / tool / formularesult.cxx
blob35d58188b721c944c2c2eede2e26e07ada89948d
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"
13 namespace sc {
15 FormulaResultValue::FormulaResultValue() : meType(Invalid), mfValue(0.0), mnError(0) {}
16 FormulaResultValue::FormulaResultValue( double fValue ) : meType(Value), mfValue(fValue), mnError(0) {}
17 FormulaResultValue::FormulaResultValue( const svl::SharedString& rStr ) : meType(String), mfValue(0.0), maString(rStr), mnError(0) {}
18 FormulaResultValue::FormulaResultValue( sal_uInt16 nErr ) : meType(Error), mfValue(0.0), mnError(nErr) {}
22 ScFormulaResult::ScFormulaResult() :
23 mpToken(NULL), mnError(0), mbToken(true),
24 mbEmpty(false), mbEmptyDisplayedAsString(false),
25 meMultiline(MULTILINE_UNKNOWN) {}
27 ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
28 mnError( r.mnError), mbToken( r.mbToken),
29 mbEmpty( r.mbEmpty),
30 mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
31 meMultiline( r.meMultiline)
33 if (mbToken)
35 mpToken = r.mpToken;
36 if (mpToken)
38 // Since matrix dimension and
39 // results are assigned to a matrix
40 // cell formula token we have to
41 // clone that instead of sharing it.
42 const ScMatrixFormulaCellToken* pMatFormula =
43 r.GetMatrixFormulaCellToken();
44 if (pMatFormula)
46 mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
47 mpToken->IncRef();
49 else
50 IncrementTokenRef( mpToken);
53 else
54 mfValue = r.mfValue;
57 ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
58 mnError(0), mbToken(false), mbEmpty(false), mbEmptyDisplayedAsString(false),
59 meMultiline(MULTILINE_UNKNOWN)
61 SetToken( p);
64 ScFormulaResult::~ScFormulaResult()
66 if (mbToken && mpToken)
67 mpToken->DecRef();
71 void ScFormulaResult::ResetToDefaults()
73 mnError = 0;
74 mbEmpty = false;
75 mbEmptyDisplayedAsString = false;
76 meMultiline = MULTILINE_UNKNOWN;
79 void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
81 ResetToDefaults();
82 if (!p)
84 mpToken = p;
85 mbToken = true;
87 else
89 switch (p->GetType())
91 case formula::svError:
92 mnError = p->GetError();
93 p->DecRef();
94 mbToken = false;
95 // set in case mnError is 0 now, which shouldn't happen but ...
96 mfValue = 0.0;
97 meMultiline = MULTILINE_FALSE;
98 break;
99 case formula::svEmptyCell:
100 mbEmpty = true;
101 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
102 p->DecRef();
103 mbToken = false;
104 meMultiline = MULTILINE_FALSE;
105 break;
106 case formula::svDouble:
107 mfValue = p->GetDouble();
108 p->DecRef();
109 mbToken = false;
110 meMultiline = MULTILINE_FALSE;
111 break;
112 default:
113 mpToken = p;
114 mbToken = true;
119 ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
121 Assign( r);
122 return *this;
125 void ScFormulaResult::Assign( const ScFormulaResult & r )
127 if (this == &r)
128 return;
129 if (r.mbEmpty)
131 if (mbToken && mpToken)
132 mpToken->DecRef();
133 mbToken = false;
134 mbEmpty = true;
135 mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
136 meMultiline = r.meMultiline;
138 else if (r.mbToken)
140 // Matrix formula cell token must be cloned, see copy-ctor.
141 const ScMatrixFormulaCellToken* pMatFormula =
142 r.GetMatrixFormulaCellToken();
143 if (pMatFormula)
144 SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
145 else
146 SetToken( r.mpToken);
148 else
149 SetDouble( r.mfValue);
150 // If there was an error there will be an error, no matter what Set...()
151 // methods did.
152 mnError = r.mnError;
155 void ScFormulaResult::SetToken( const formula::FormulaToken* p )
157 ResetToDefaults();
158 IncrementTokenRef( p);
159 // Handle a result obtained from the interpreter to be assigned to a matrix
160 // formula cell's ScMatrixFormulaCellToken.
161 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
162 if (pMatFormula)
164 const ScMatrixCellResultToken* pMatResult =
165 (p && p->GetType() == formula::svMatrixCell ?
166 dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
167 if (pMatResult)
169 const ScMatrixFormulaCellToken* pNewMatFormula =
170 dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
171 if (pNewMatFormula)
173 SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
174 pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
175 pNewMatFormula->GetMatRows());
177 pMatFormula->Assign( *pMatResult);
178 p->DecRef();
180 else if (p)
182 // This may be the result of some constant expression like
183 // {="string"} that doesn't result in a matrix but still would
184 // display the result in all cells of this matrix formula.
185 pMatFormula->Assign( *p);
186 p->DecRef();
188 else
190 // NULL result? Well, if you say so ...
191 pMatFormula->ResetResult();
194 else
196 if (mbToken && mpToken)
197 mpToken->DecRef();
198 ResolveToken( p);
202 void ScFormulaResult::SetDouble( double f )
204 ResetToDefaults();
205 // Handle a result obtained from the interpreter to be assigned to a matrix
206 // formula cell's ScMatrixFormulaCellToken.
207 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
208 if (pMatFormula)
209 pMatFormula->SetUpperLeftDouble( f);
210 else
212 if (mbToken && mpToken)
213 mpToken->DecRef();
214 mfValue = f;
215 mbToken = false;
216 meMultiline = MULTILINE_FALSE;
220 formula::StackVar ScFormulaResult::GetType() const
222 // Order is significant.
223 if (mnError)
224 return formula::svError;
225 if (mbEmpty)
226 return formula::svEmptyCell;
227 if (!mbToken)
228 return formula::svDouble;
229 if (mpToken)
230 return mpToken->GetType();
231 return formula::svUnknown;
234 formula::StackVar ScFormulaResult::GetCellResultType() const
236 formula::StackVar sv = GetType();
237 if (sv == formula::svMatrixCell)
238 // don't need to test for mpToken here, GetType() already did it
239 sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
240 return sv;
243 bool ScFormulaResult::IsEmptyDisplayedAsString() const
245 if (mbEmpty)
246 return mbEmptyDisplayedAsString;
247 if (GetType() == formula::svMatrixCell)
249 // don't need to test for mpToken here, GetType() already did it
250 const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
251 static_cast<const ScMatrixCellResultToken*>(
252 mpToken)->GetUpperLeftToken().get());
253 if (p)
254 return p->IsDisplayedAsString();
256 return false;
259 namespace {
261 inline bool isValue( formula::StackVar sv )
263 return sv == formula::svDouble || sv == formula::svError
264 || sv == formula::svEmptyCell || sv == formula::svHybridValueCell;
267 inline bool isString( formula::StackVar sv )
269 switch (sv)
271 case formula::svString:
272 case formula::svHybridCell:
273 case formula::svHybridValueCell:
274 return true;
275 default:
276 break;
279 return false;
284 bool ScFormulaResult::IsValue() const
286 return isValue(GetCellResultType());
289 bool ScFormulaResult::IsValueNoError() const
291 switch (GetCellResultType())
293 case formula::svDouble:
294 case formula::svEmptyCell:
295 case formula::svHybridValueCell:
296 return true;
297 default:
298 return false;
302 bool ScFormulaResult::IsMultiline() const
304 if (meMultiline == MULTILINE_UNKNOWN)
306 svl::SharedString aStr = GetString();
307 if (!aStr.isEmpty() && aStr.getString().indexOf('\n') != -1)
308 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
309 else
310 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
312 return meMultiline == MULTILINE_TRUE;
315 bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const
317 if (mnError)
319 rErr = mnError;
320 return true;
323 formula::StackVar sv = GetCellResultType();
324 if (sv == formula::svError)
326 if (GetType() == formula::svMatrixCell)
328 // don't need to test for mpToken here, GetType() already did it
329 rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
330 GetUpperLeftToken()->GetError();
332 else if (mpToken)
334 rErr = mpToken->GetError();
338 if (rErr)
339 return true;
341 if (!isValue(sv))
342 return false;
344 rVal = GetDouble();
345 return true;
348 bool ScFormulaResult::GetErrorOrString( sal_uInt16& rErr, svl::SharedString& rStr ) const
350 if (mnError)
352 rErr = mnError;
353 return true;
356 formula::StackVar sv = GetCellResultType();
357 if (sv == formula::svError)
359 if (GetType() == formula::svMatrixCell)
361 // don't need to test for mpToken here, GetType() already did it
362 rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
363 GetUpperLeftToken()->GetError();
365 else if (mpToken)
367 rErr = mpToken->GetError();
371 if (rErr)
372 return true;
374 if (!mbToken)
375 return false;
377 if (!isString(sv))
378 return false;
380 rStr = GetString();
381 return true;
384 sc::FormulaResultValue ScFormulaResult::GetResult() const
386 if (mnError)
387 return sc::FormulaResultValue(mnError);
389 formula::StackVar sv = GetCellResultType();
390 sal_uInt16 nErr = 0;
391 if (sv == formula::svError)
393 if (GetType() == formula::svMatrixCell)
395 // don't need to test for mpToken here, GetType() already did it
396 nErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
397 GetUpperLeftToken()->GetError();
399 else if (mpToken)
401 nErr = mpToken->GetError();
405 if (nErr)
406 return sc::FormulaResultValue(nErr);
408 if (isValue(sv))
409 return sc::FormulaResultValue(GetDouble());
411 if (!mbToken)
412 // String result type needs token.
413 return sc::FormulaResultValue();
415 if (isString(sv))
416 return sc::FormulaResultValue(GetString());
418 // Invalid
419 return sc::FormulaResultValue();
422 sal_uInt16 ScFormulaResult::GetResultError() const
424 if (mnError)
425 return mnError;
426 formula::StackVar sv = GetCellResultType();
427 if (sv == formula::svError)
429 if (GetType() == formula::svMatrixCell)
430 // don't need to test for mpToken here, GetType() already did it
431 return static_cast<const ScMatrixCellResultToken*>(mpToken)->
432 GetUpperLeftToken()->GetError();
433 if (mpToken)
434 return mpToken->GetError();
436 return 0;
439 void ScFormulaResult::SetResultError( sal_uInt16 nErr )
441 mnError = nErr;
444 formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
446 if (mbToken)
447 return mpToken;
448 return NULL;
451 formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
453 if (GetType() == formula::svMatrixCell)
454 // don't need to test for mpToken here, GetType() already did it
455 return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
456 return GetToken();
459 double ScFormulaResult::GetDouble() const
461 if (mbToken)
463 // Should really not be of type formula::svDouble here.
464 if (mpToken)
466 switch (mpToken->GetType())
468 case formula::svHybridCell:
469 case formula::svHybridValueCell:
470 return mpToken->GetDouble();
471 case formula::svMatrixCell:
473 const ScMatrixCellResultToken* p =
474 static_cast<const ScMatrixCellResultToken*>(mpToken);
475 if (p->GetUpperLeftType() == formula::svDouble)
476 return p->GetUpperLeftToken()->GetDouble();
478 break;
479 default:
480 ; // nothing
483 return 0.0;
485 if (mbEmpty)
486 return 0.0;
487 return mfValue;
490 svl::SharedString ScFormulaResult::GetString() const
492 if (mbToken && mpToken)
494 switch (mpToken->GetType())
496 case formula::svString:
497 case formula::svHybridCell:
498 case formula::svHybridValueCell:
499 return mpToken->GetString();
500 case formula::svMatrixCell:
502 const ScMatrixCellResultToken* p =
503 static_cast<const ScMatrixCellResultToken*>(mpToken);
504 if (p->GetUpperLeftType() == formula::svString)
505 return p->GetUpperLeftToken()->GetString();
507 break;
508 default:
509 ; // nothing
512 return svl::SharedString::getEmptyString();
515 ScConstMatrixRef ScFormulaResult::GetMatrix() const
517 if (GetType() == formula::svMatrixCell)
518 return static_cast<const ScToken*>(mpToken)->GetMatrix();
519 return NULL;
522 const OUString& ScFormulaResult::GetHybridFormula() const
524 if (GetType() == formula::svHybridCell)
526 const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
527 if (p)
528 return p->GetFormula();
530 return EMPTY_OUSTRING;
533 void ScFormulaResult::SetHybridDouble( double f )
535 ResetToDefaults();
536 if (mbToken && mpToken)
538 if(GetType() == formula::svMatrixCell)
539 SetDouble(f);
540 else
542 svl::SharedString aString = GetString();
543 OUString aFormula( GetHybridFormula());
544 mpToken->DecRef();
545 mpToken = new ScHybridCellToken( f, aString, aFormula);
546 mpToken->IncRef();
549 else
551 mfValue = f;
552 mbToken = false;
553 meMultiline = MULTILINE_FALSE;
557 void ScFormulaResult::SetHybridString( const OUString & rStr )
559 // Obtain values before changing anything.
560 double f = GetDouble();
561 OUString aFormula( GetHybridFormula());
562 ResetToDefaults();
563 if (mbToken && mpToken)
564 mpToken->DecRef();
565 mpToken = new ScHybridCellToken( f, rStr, aFormula);
566 mpToken->IncRef();
567 mbToken = true;
570 void ScFormulaResult::SetHybridFormula( const OUString & rFormula )
572 // Obtain values before changing anything.
573 double f = GetDouble();
574 svl::SharedString aStr = GetString();
575 ResetToDefaults();
576 if (mbToken && mpToken)
577 mpToken->DecRef();
578 mpToken = new ScHybridCellToken( f, aStr, rFormula);
579 mpToken->IncRef();
580 mbToken = true;
583 void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL )
585 ResetToDefaults();
586 if (mbToken && mpToken)
587 mpToken->DecRef();
588 mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
589 mpToken->IncRef();
590 mbToken = true;
593 const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
595 return (GetType() == formula::svMatrixCell ?
596 dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
599 ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
601 return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
604 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */