Line data Source code
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 :
13 : namespace sc {
14 :
15 0 : FormulaResultValue::FormulaResultValue() : meType(Invalid), mfValue(0.0), mnError(0) {}
16 612 : FormulaResultValue::FormulaResultValue( double fValue ) : meType(Value), mfValue(fValue), mnError(0) {}
17 20 : FormulaResultValue::FormulaResultValue( const svl::SharedString& rStr ) : meType(String), mfValue(0.0), maString(rStr), mnError(0) {}
18 6 : FormulaResultValue::FormulaResultValue( sal_uInt16 nErr ) : meType(Error), mfValue(0.0), mnError(nErr) {}
19 :
20 : }
21 :
22 9718 : ScFormulaResult::ScFormulaResult() :
23 : mpToken(NULL), mnError(0), mbToken(true),
24 : mbEmpty(false), mbEmptyDisplayedAsString(false),
25 9718 : meMultiline(MULTILINE_UNKNOWN) {}
26 :
27 1182 : ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
28 : mnError( r.mnError), mbToken( r.mbToken),
29 : mbEmpty( r.mbEmpty),
30 : mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
31 1182 : meMultiline( r.meMultiline)
32 : {
33 1182 : if (mbToken)
34 : {
35 657 : mpToken = r.mpToken;
36 657 : if (mpToken)
37 : {
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 102 : r.GetMatrixFormulaCellToken();
44 102 : if (pMatFormula)
45 : {
46 8 : mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
47 8 : mpToken->IncRef();
48 : }
49 : else
50 94 : IncrementTokenRef( mpToken);
51 : }
52 : }
53 : else
54 525 : mfValue = r.mfValue;
55 1182 : }
56 :
57 7476 : ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
58 : mnError(0), mbToken(false), mbEmpty(false), mbEmptyDisplayedAsString(false),
59 7476 : meMultiline(MULTILINE_UNKNOWN)
60 : {
61 7476 : SetToken( p);
62 7476 : }
63 :
64 17719 : ScFormulaResult::~ScFormulaResult()
65 : {
66 17719 : if (mbToken && mpToken)
67 460 : mpToken->DecRef();
68 17719 : }
69 :
70 40273 : void ScFormulaResult::ResetToDefaults()
71 : {
72 40273 : mnError = 0;
73 40273 : mbEmpty = false;
74 40273 : mbEmptyDisplayedAsString = false;
75 40273 : meMultiline = MULTILINE_UNKNOWN;
76 40273 : }
77 :
78 13622 : void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
79 : {
80 13622 : ResetToDefaults();
81 13622 : if (!p)
82 : {
83 1383 : mpToken = p;
84 1383 : mbToken = true;
85 : }
86 : else
87 : {
88 12239 : switch (p->GetType())
89 : {
90 : case formula::svError:
91 267 : mnError = p->GetError();
92 267 : p->DecRef();
93 267 : mbToken = false;
94 : // set in case mnError is 0 now, which shouldn't happen but ...
95 267 : mfValue = 0.0;
96 267 : meMultiline = MULTILINE_FALSE;
97 267 : break;
98 : case formula::svEmptyCell:
99 730 : mbEmpty = true;
100 730 : mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
101 730 : p->DecRef();
102 730 : mbToken = false;
103 730 : meMultiline = MULTILINE_FALSE;
104 730 : break;
105 : case formula::svDouble:
106 10357 : mfValue = p->GetDouble();
107 10357 : p->DecRef();
108 10357 : mbToken = false;
109 10357 : meMultiline = MULTILINE_FALSE;
110 10357 : break;
111 : default:
112 885 : mpToken = p;
113 885 : mbToken = true;
114 : }
115 : }
116 13622 : }
117 :
118 0 : ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
119 : {
120 0 : Assign( r);
121 0 : return *this;
122 : }
123 :
124 7092 : void ScFormulaResult::Assign( const ScFormulaResult & r )
125 : {
126 7092 : if (this == &r)
127 7092 : return;
128 7092 : if (r.mbEmpty)
129 : {
130 691 : if (mbToken && mpToken)
131 0 : mpToken->DecRef();
132 691 : mbToken = false;
133 691 : mbEmpty = true;
134 691 : mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
135 691 : meMultiline = r.meMultiline;
136 : }
137 6401 : else if (r.mbToken)
138 : {
139 : // Matrix formula cell token must be cloned, see copy-ctor.
140 : const ScMatrixFormulaCellToken* pMatFormula =
141 45 : r.GetMatrixFormulaCellToken();
142 45 : if (pMatFormula)
143 18 : SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
144 : else
145 27 : SetToken( r.mpToken);
146 : }
147 : else
148 6356 : SetDouble( r.mfValue);
149 : // If there was an error there will be an error, no matter what Set...()
150 : // methods did.
151 7092 : mnError = r.mnError;
152 : }
153 :
154 13726 : void ScFormulaResult::SetToken( const formula::FormulaToken* p )
155 : {
156 13726 : ResetToDefaults();
157 13726 : IncrementTokenRef( p);
158 : // Handle a result obtained from the interpreter to be assigned to a matrix
159 : // formula cell's ScMatrixFormulaCellToken.
160 13726 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
161 13726 : if (pMatFormula)
162 : {
163 : const ScMatrixCellResultToken* pMatResult =
164 104 : (p && p->GetType() == formula::svMatrixCell ?
165 140 : dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
166 104 : if (pMatResult)
167 : {
168 : const ScMatrixFormulaCellToken* pNewMatFormula =
169 36 : dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
170 36 : if (pNewMatFormula && (pMatFormula->GetMatCols() <= 0 || pMatFormula->GetMatRows() <= 0))
171 : {
172 : SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
173 0 : pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
174 0 : pNewMatFormula->GetMatRows());
175 : }
176 36 : pMatFormula->Assign( *pMatResult);
177 36 : p->DecRef();
178 : }
179 68 : else if (p)
180 : {
181 : // This may be the result of some constant expression like
182 : // {="string"} that doesn't result in a matrix but still would
183 : // display the result in all cells of this matrix formula.
184 68 : pMatFormula->Assign( *p);
185 68 : p->DecRef();
186 : }
187 : else
188 : {
189 : // NULL result? Well, if you say so ...
190 0 : pMatFormula->ResetResult();
191 : }
192 : }
193 : else
194 : {
195 13622 : if (mbToken && mpToken)
196 609 : mpToken->DecRef();
197 13622 : ResolveToken( p);
198 : }
199 13726 : }
200 :
201 11373 : void ScFormulaResult::SetDouble( double f )
202 : {
203 11373 : ResetToDefaults();
204 : // Handle a result obtained from the interpreter to be assigned to a matrix
205 : // formula cell's ScMatrixFormulaCellToken.
206 11373 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
207 11373 : if (pMatFormula)
208 16 : pMatFormula->SetUpperLeftDouble( f);
209 : else
210 : {
211 11357 : if (mbToken && mpToken)
212 0 : mpToken->DecRef();
213 11357 : mfValue = f;
214 11357 : mbToken = false;
215 11357 : meMultiline = MULTILINE_FALSE;
216 : }
217 11373 : }
218 :
219 158431 : formula::StackVar ScFormulaResult::GetType() const
220 : {
221 : // Order is significant.
222 158431 : if (mnError)
223 964 : return formula::svError;
224 157467 : if (mbEmpty)
225 4539 : return formula::svEmptyCell;
226 152928 : if (!mbToken)
227 126844 : return formula::svDouble;
228 26084 : if (mpToken)
229 8497 : return mpToken->GetType();
230 17587 : return formula::svUnknown;
231 : }
232 :
233 115263 : formula::StackVar ScFormulaResult::GetCellResultType() const
234 : {
235 115263 : formula::StackVar sv = GetType();
236 115263 : if (sv == formula::svMatrixCell)
237 : // don't need to test for mpToken here, GetType() already did it
238 1015 : sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
239 115263 : return sv;
240 : }
241 :
242 3045 : bool ScFormulaResult::IsEmptyDisplayedAsString() const
243 : {
244 3045 : if (mbEmpty)
245 30 : return mbEmptyDisplayedAsString;
246 3015 : if (GetType() == formula::svMatrixCell)
247 : {
248 : // don't need to test for mpToken here, GetType() already did it
249 : const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
250 : static_cast<const ScMatrixCellResultToken*>(
251 46 : mpToken)->GetUpperLeftToken().get());
252 46 : if (p)
253 0 : return p->IsDisplayedAsString();
254 : }
255 3015 : return false;
256 : }
257 :
258 : namespace {
259 :
260 48860 : inline bool isValue( formula::StackVar sv )
261 : {
262 5542 : return sv == formula::svDouble || sv == formula::svError
263 53698 : || sv == formula::svEmptyCell || sv == formula::svHybridValueCell;
264 : }
265 :
266 20 : inline bool isString( formula::StackVar sv )
267 : {
268 20 : switch (sv)
269 : {
270 : case formula::svString:
271 : case formula::svHybridCell:
272 : case formula::svHybridValueCell:
273 20 : return true;
274 : default:
275 0 : break;
276 : }
277 :
278 0 : return false;
279 : }
280 :
281 : }
282 :
283 43711 : bool ScFormulaResult::IsValue() const
284 : {
285 43711 : return isValue(GetCellResultType());
286 : }
287 :
288 629 : bool ScFormulaResult::IsValueNoError() const
289 : {
290 629 : switch (GetCellResultType())
291 : {
292 : case formula::svDouble:
293 : case formula::svEmptyCell:
294 : case formula::svHybridValueCell:
295 605 : return true;
296 : default:
297 24 : return false;
298 : }
299 : }
300 :
301 154 : bool ScFormulaResult::IsMultiline() const
302 : {
303 154 : if (meMultiline == MULTILINE_UNKNOWN)
304 : {
305 29 : svl::SharedString aStr = GetString();
306 29 : if (!aStr.isEmpty() && aStr.getString().indexOf('\n') != -1)
307 0 : const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
308 : else
309 29 : const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
310 : }
311 154 : return meMultiline == MULTILINE_TRUE;
312 : }
313 :
314 4665 : bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const
315 : {
316 4665 : if (mnError)
317 : {
318 148 : rErr = mnError;
319 148 : return true;
320 : }
321 :
322 4517 : formula::StackVar sv = GetCellResultType();
323 4517 : if (sv == formula::svError)
324 : {
325 0 : if (GetType() == formula::svMatrixCell)
326 : {
327 : // don't need to test for mpToken here, GetType() already did it
328 : rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
329 0 : GetUpperLeftToken()->GetError();
330 : }
331 0 : else if (mpToken)
332 : {
333 0 : rErr = mpToken->GetError();
334 : }
335 : }
336 :
337 4517 : if (rErr)
338 0 : return true;
339 :
340 4517 : if (!isValue(sv))
341 0 : return false;
342 :
343 4517 : rVal = GetDouble();
344 4517 : return true;
345 : }
346 :
347 638 : sc::FormulaResultValue ScFormulaResult::GetResult() const
348 : {
349 638 : if (mnError)
350 6 : return sc::FormulaResultValue(mnError);
351 :
352 632 : formula::StackVar sv = GetCellResultType();
353 632 : sal_uInt16 nErr = 0;
354 632 : if (sv == formula::svError)
355 : {
356 0 : if (GetType() == formula::svMatrixCell)
357 : {
358 : // don't need to test for mpToken here, GetType() already did it
359 : nErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
360 0 : GetUpperLeftToken()->GetError();
361 : }
362 0 : else if (mpToken)
363 : {
364 0 : nErr = mpToken->GetError();
365 : }
366 : }
367 :
368 632 : if (nErr)
369 0 : return sc::FormulaResultValue(nErr);
370 :
371 632 : if (isValue(sv))
372 612 : return sc::FormulaResultValue(GetDouble());
373 :
374 20 : if (!mbToken)
375 : // String result type needs token.
376 0 : return sc::FormulaResultValue();
377 :
378 20 : if (isString(sv))
379 20 : return sc::FormulaResultValue(GetString());
380 :
381 : // Invalid
382 0 : return sc::FormulaResultValue();
383 : }
384 :
385 50700 : sal_uInt16 ScFormulaResult::GetResultError() const
386 : {
387 50700 : if (mnError)
388 501 : return mnError;
389 50199 : formula::StackVar sv = GetCellResultType();
390 50199 : if (sv == formula::svError)
391 : {
392 17 : if (GetType() == formula::svMatrixCell)
393 : // don't need to test for mpToken here, GetType() already did it
394 : return static_cast<const ScMatrixCellResultToken*>(mpToken)->
395 17 : GetUpperLeftToken()->GetError();
396 0 : if (mpToken)
397 0 : return mpToken->GetError();
398 : }
399 50182 : return 0;
400 : }
401 :
402 11831 : void ScFormulaResult::SetResultError( sal_uInt16 nErr )
403 : {
404 11831 : mnError = nErr;
405 11831 : }
406 :
407 0 : formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
408 : {
409 0 : if (mbToken)
410 0 : return mpToken;
411 0 : return NULL;
412 : }
413 :
414 24 : formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
415 : {
416 24 : if (GetType() == formula::svMatrixCell)
417 : // don't need to test for mpToken here, GetType() already did it
418 24 : return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
419 0 : return GetToken();
420 : }
421 :
422 47445 : double ScFormulaResult::GetDouble() const
423 : {
424 47445 : if (mbToken)
425 : {
426 : // Should really not be of type formula::svDouble here.
427 832 : if (mpToken)
428 : {
429 676 : switch (mpToken->GetType())
430 : {
431 : case formula::svHybridCell:
432 : case formula::svHybridValueCell:
433 0 : return mpToken->GetDouble();
434 : case formula::svMatrixCell:
435 : {
436 : const ScMatrixCellResultToken* p =
437 329 : static_cast<const ScMatrixCellResultToken*>(mpToken);
438 329 : if (p->GetUpperLeftType() == formula::svDouble)
439 322 : return p->GetUpperLeftToken()->GetDouble();
440 : }
441 7 : break;
442 : default:
443 : ; // nothing
444 : }
445 : }
446 510 : return 0.0;
447 : }
448 46613 : if (mbEmpty)
449 1525 : return 0.0;
450 45088 : return mfValue;
451 : }
452 :
453 703 : svl::SharedString ScFormulaResult::GetString() const
454 : {
455 703 : if (mbToken && mpToken)
456 : {
457 671 : switch (mpToken->GetType())
458 : {
459 : case formula::svString:
460 : case formula::svHybridCell:
461 : case formula::svHybridValueCell:
462 649 : return mpToken->GetString();
463 : case formula::svMatrixCell:
464 : {
465 : const ScMatrixCellResultToken* p =
466 22 : static_cast<const ScMatrixCellResultToken*>(mpToken);
467 22 : if (p->GetUpperLeftType() == formula::svString)
468 22 : return p->GetUpperLeftToken()->GetString();
469 : }
470 0 : break;
471 : default:
472 : ; // nothing
473 : }
474 : }
475 32 : return svl::SharedString::getEmptyString();
476 : }
477 :
478 12064 : ScConstMatrixRef ScFormulaResult::GetMatrix() const
479 : {
480 12064 : if (GetType() == formula::svMatrixCell)
481 368 : return mpToken->GetMatrix();
482 11696 : return NULL;
483 : }
484 :
485 170 : const OUString& ScFormulaResult::GetHybridFormula() const
486 : {
487 170 : if (GetType() == formula::svHybridCell)
488 : {
489 5 : const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
490 5 : if (p)
491 5 : return p->GetFormula();
492 : }
493 165 : return EMPTY_OUSTRING;
494 : }
495 :
496 1352 : void ScFormulaResult::SetHybridDouble( double f )
497 : {
498 1352 : ResetToDefaults();
499 1352 : if (mbToken && mpToken)
500 : {
501 0 : if(GetType() == formula::svMatrixCell)
502 0 : SetDouble(f);
503 : else
504 : {
505 0 : svl::SharedString aString = GetString();
506 0 : OUString aFormula( GetHybridFormula());
507 0 : mpToken->DecRef();
508 0 : mpToken = new ScHybridCellToken( f, aString, aFormula);
509 0 : mpToken->IncRef();
510 0 : }
511 : }
512 : else
513 : {
514 1352 : mfValue = f;
515 1352 : mbToken = false;
516 1352 : meMultiline = MULTILINE_FALSE;
517 : }
518 1352 : }
519 :
520 156 : void ScFormulaResult::SetHybridString( const svl::SharedString& rStr )
521 : {
522 : // Obtain values before changing anything.
523 156 : double f = GetDouble();
524 156 : OUString aFormula( GetHybridFormula());
525 156 : ResetToDefaults();
526 156 : if (mbToken && mpToken)
527 0 : mpToken->DecRef();
528 156 : mpToken = new ScHybridCellToken( f, rStr, aFormula);
529 156 : mpToken->IncRef();
530 156 : mbToken = true;
531 156 : }
532 :
533 5 : void ScFormulaResult::SetHybridFormula( const OUString & rFormula )
534 : {
535 : // Obtain values before changing anything.
536 5 : double f = GetDouble();
537 5 : svl::SharedString aStr = GetString();
538 5 : ResetToDefaults();
539 5 : if (mbToken && mpToken)
540 0 : mpToken->DecRef();
541 5 : mpToken = new ScHybridCellToken( f, aStr, rFormula);
542 5 : mpToken->IncRef();
543 5 : mbToken = true;
544 5 : }
545 :
546 39 : void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL )
547 : {
548 39 : ResetToDefaults();
549 39 : if (mbToken && mpToken)
550 39 : mpToken->DecRef();
551 39 : mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
552 39 : mpToken->IncRef();
553 39 : mbToken = true;
554 39 : }
555 :
556 25339 : const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
557 : {
558 25339 : return (GetType() == formula::svMatrixCell ?
559 25339 : dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
560 : }
561 :
562 25162 : ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
563 : {
564 25162 : return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
565 156 : }
566 :
567 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|