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 1266 : FormulaResultValue::FormulaResultValue( double fValue ) : meType(Value), mfValue(fValue), mnError(0) {}
17 40 : FormulaResultValue::FormulaResultValue( const svl::SharedString& rStr ) : meType(String), mfValue(0.0), maString(rStr), mnError(0) {}
18 22 : FormulaResultValue::FormulaResultValue( sal_uInt16 nErr ) : meType(Error), mfValue(0.0), mnError(nErr) {}
19 :
20 : }
21 :
22 17460 : ScFormulaResult::ScFormulaResult() :
23 : mpToken(NULL), mnError(0), mbToken(true),
24 : mbEmpty(false), mbEmptyDisplayedAsString(false),
25 17460 : meMultiline(MULTILINE_UNKNOWN) {}
26 :
27 1990 : ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
28 : mnError( r.mnError), mbToken( r.mbToken),
29 : mbEmpty( r.mbEmpty),
30 : mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
31 1990 : meMultiline( r.meMultiline)
32 : {
33 1990 : if (mbToken)
34 : {
35 1228 : mpToken = r.mpToken;
36 1228 : 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 148 : r.GetMatrixFormulaCellToken();
44 148 : if (pMatFormula)
45 : {
46 0 : mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
47 0 : mpToken->IncRef();
48 : }
49 : else
50 148 : IncrementTokenRef( mpToken);
51 : }
52 : }
53 : else
54 762 : mfValue = r.mfValue;
55 1990 : }
56 :
57 14637 : ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
58 : mnError(0), mbToken(false), mbEmpty(false), mbEmptyDisplayedAsString(false),
59 14637 : meMultiline(MULTILINE_UNKNOWN)
60 : {
61 14637 : SetToken( p);
62 14637 : }
63 :
64 34039 : ScFormulaResult::~ScFormulaResult()
65 : {
66 34039 : if (mbToken && mpToken)
67 886 : mpToken->DecRef();
68 34039 : }
69 :
70 71937 : void ScFormulaResult::ResetToDefaults()
71 : {
72 71937 : mnError = 0;
73 71937 : mbEmpty = false;
74 71937 : mbEmptyDisplayedAsString = false;
75 71937 : meMultiline = MULTILINE_UNKNOWN;
76 71937 : }
77 :
78 23945 : void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
79 : {
80 23945 : ResetToDefaults();
81 23945 : if (!p)
82 : {
83 2588 : mpToken = p;
84 2588 : mbToken = true;
85 : }
86 : else
87 : {
88 21357 : switch (p->GetType())
89 : {
90 : case formula::svError:
91 516 : mnError = p->GetError();
92 516 : p->DecRef();
93 516 : mbToken = false;
94 : // set in case mnError is 0 now, which shouldn't happen but ...
95 516 : mfValue = 0.0;
96 516 : meMultiline = MULTILINE_FALSE;
97 516 : break;
98 : case formula::svEmptyCell:
99 1372 : mbEmpty = true;
100 1372 : mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
101 1372 : p->DecRef();
102 1372 : mbToken = false;
103 1372 : meMultiline = MULTILINE_FALSE;
104 1372 : break;
105 : case formula::svDouble:
106 17959 : mfValue = p->GetDouble();
107 17959 : p->DecRef();
108 17959 : mbToken = false;
109 17959 : meMultiline = MULTILINE_FALSE;
110 17959 : break;
111 : default:
112 1510 : mpToken = p;
113 1510 : mbToken = true;
114 : }
115 : }
116 23945 : }
117 :
118 0 : ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
119 : {
120 0 : Assign( r);
121 0 : return *this;
122 : }
123 :
124 13721 : void ScFormulaResult::Assign( const ScFormulaResult & r )
125 : {
126 13721 : if (this == &r)
127 13721 : return;
128 13721 : if (r.mbEmpty)
129 : {
130 1310 : if (mbToken && mpToken)
131 0 : mpToken->DecRef();
132 1310 : mbToken = false;
133 1310 : mbEmpty = true;
134 1310 : mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
135 1310 : meMultiline = r.meMultiline;
136 : }
137 12411 : else if (r.mbToken)
138 : {
139 : // Matrix formula cell token must be cloned, see copy-ctor.
140 : const ScMatrixFormulaCellToken* pMatFormula =
141 74 : r.GetMatrixFormulaCellToken();
142 74 : if (pMatFormula)
143 28 : SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
144 : else
145 46 : SetToken( r.mpToken);
146 : }
147 : else
148 12337 : SetDouble( r.mfValue);
149 : // If there was an error there will be an error, no matter what Set...()
150 : // methods did.
151 13721 : mnError = r.mnError;
152 : }
153 :
154 24063 : void ScFormulaResult::SetToken( const formula::FormulaToken* p )
155 : {
156 24063 : ResetToDefaults();
157 24063 : IncrementTokenRef( p);
158 : // Handle a result obtained from the interpreter to be assigned to a matrix
159 : // formula cell's ScMatrixFormulaCellToken.
160 24063 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
161 24063 : if (pMatFormula)
162 : {
163 : const ScMatrixCellResultToken* pMatResult =
164 118 : (p && p->GetType() == formula::svMatrixCell ?
165 166 : dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
166 118 : if (pMatResult)
167 : {
168 : const ScMatrixFormulaCellToken* pNewMatFormula =
169 48 : dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
170 48 : if (pNewMatFormula)
171 : {
172 : SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
173 48 : pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
174 96 : pNewMatFormula->GetMatRows());
175 : }
176 48 : pMatFormula->Assign( *pMatResult);
177 48 : p->DecRef();
178 : }
179 70 : 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 70 : pMatFormula->Assign( *p);
185 70 : p->DecRef();
186 : }
187 : else
188 : {
189 : // NULL result? Well, if you say so ...
190 0 : pMatFormula->ResetResult();
191 : }
192 : }
193 : else
194 : {
195 23945 : if (mbToken && mpToken)
196 1014 : mpToken->DecRef();
197 23945 : ResolveToken( p);
198 : }
199 24063 : }
200 :
201 22203 : void ScFormulaResult::SetDouble( double f )
202 : {
203 22203 : ResetToDefaults();
204 : // Handle a result obtained from the interpreter to be assigned to a matrix
205 : // formula cell's ScMatrixFormulaCellToken.
206 22203 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
207 22203 : if (pMatFormula)
208 32 : pMatFormula->SetUpperLeftDouble( f);
209 : else
210 : {
211 22171 : if (mbToken && mpToken)
212 0 : mpToken->DecRef();
213 22171 : mfValue = f;
214 22171 : mbToken = false;
215 22171 : meMultiline = MULTILINE_FALSE;
216 : }
217 22203 : }
218 :
219 278941 : formula::StackVar ScFormulaResult::GetType() const
220 : {
221 : // Order is significant.
222 278941 : if (mnError)
223 1788 : return formula::svError;
224 277153 : if (mbEmpty)
225 8286 : return formula::svEmptyCell;
226 268867 : if (!mbToken)
227 222490 : return formula::svDouble;
228 46377 : if (mpToken)
229 13180 : return mpToken->GetType();
230 33197 : return formula::svUnknown;
231 : }
232 :
233 202332 : formula::StackVar ScFormulaResult::GetCellResultType() const
234 : {
235 202332 : formula::StackVar sv = GetType();
236 202332 : if (sv == formula::svMatrixCell)
237 : // don't need to test for mpToken here, GetType() already did it
238 1332 : sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
239 202332 : return sv;
240 : }
241 :
242 4793 : bool ScFormulaResult::IsEmptyDisplayedAsString() const
243 : {
244 4793 : if (mbEmpty)
245 36 : return mbEmptyDisplayedAsString;
246 4757 : 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 38 : mpToken)->GetUpperLeftToken().get());
252 38 : if (p)
253 0 : return p->IsDisplayedAsString();
254 : }
255 4757 : return false;
256 : }
257 :
258 : namespace {
259 :
260 83454 : inline bool isValue( formula::StackVar sv )
261 : {
262 9367 : return sv == formula::svDouble || sv == formula::svError
263 91545 : || sv == formula::svEmptyCell || sv == formula::svHybridValueCell;
264 : }
265 :
266 40 : inline bool isString( formula::StackVar sv )
267 : {
268 40 : switch (sv)
269 : {
270 : case formula::svString:
271 : case formula::svHybridCell:
272 : case formula::svHybridValueCell:
273 40 : return true;
274 : default:
275 0 : break;
276 : }
277 :
278 0 : return false;
279 : }
280 :
281 : }
282 :
283 74792 : bool ScFormulaResult::IsValue() const
284 : {
285 74792 : return isValue(GetCellResultType());
286 : }
287 :
288 1258 : bool ScFormulaResult::IsValueNoError() const
289 : {
290 1258 : switch (GetCellResultType())
291 : {
292 : case formula::svDouble:
293 : case formula::svEmptyCell:
294 : case formula::svHybridValueCell:
295 1210 : return true;
296 : default:
297 48 : return false;
298 : }
299 : }
300 :
301 171 : bool ScFormulaResult::IsMultiline() const
302 : {
303 171 : 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 171 : return meMultiline == MULTILINE_TRUE;
312 : }
313 :
314 7644 : bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const
315 : {
316 7644 : if (mnError)
317 : {
318 288 : rErr = mnError;
319 288 : return true;
320 : }
321 :
322 7356 : formula::StackVar sv = GetCellResultType();
323 7356 : 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 7356 : if (rErr)
338 0 : return true;
339 :
340 7356 : if (!isValue(sv))
341 0 : return false;
342 :
343 7356 : rVal = GetDouble();
344 7356 : return true;
345 : }
346 :
347 1328 : sc::FormulaResultValue ScFormulaResult::GetResult() const
348 : {
349 1328 : if (mnError)
350 22 : return sc::FormulaResultValue(mnError);
351 :
352 1306 : formula::StackVar sv = GetCellResultType();
353 1306 : sal_uInt16 nErr = 0;
354 1306 : 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 1306 : if (nErr)
369 0 : return sc::FormulaResultValue(nErr);
370 :
371 1306 : if (isValue(sv))
372 1266 : return sc::FormulaResultValue(GetDouble());
373 :
374 40 : if (!mbToken)
375 : // String result type needs token.
376 0 : return sc::FormulaResultValue();
377 :
378 40 : if (isString(sv))
379 40 : return sc::FormulaResultValue(GetString());
380 :
381 : // Invalid
382 0 : return sc::FormulaResultValue();
383 : }
384 :
385 88154 : sal_uInt16 ScFormulaResult::GetResultError() const
386 : {
387 88154 : if (mnError)
388 960 : return mnError;
389 87194 : formula::StackVar sv = GetCellResultType();
390 87194 : if (sv == formula::svError)
391 : {
392 32 : 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 32 : GetUpperLeftToken()->GetError();
396 0 : if (mpToken)
397 0 : return mpToken->GetError();
398 : }
399 87162 : return 0;
400 : }
401 :
402 20367 : void ScFormulaResult::SetResultError( sal_uInt16 nErr )
403 : {
404 20367 : mnError = nErr;
405 20367 : }
406 :
407 0 : formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
408 : {
409 0 : if (mbToken)
410 0 : return mpToken;
411 0 : return NULL;
412 : }
413 :
414 32 : formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
415 : {
416 32 : if (GetType() == formula::svMatrixCell)
417 : // don't need to test for mpToken here, GetType() already did it
418 32 : return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
419 0 : return GetToken();
420 : }
421 :
422 85776 : double ScFormulaResult::GetDouble() const
423 : {
424 85776 : if (mbToken)
425 : {
426 : // Should really not be of type formula::svDouble here.
427 1402 : if (mpToken)
428 : {
429 1152 : 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 458 : static_cast<const ScMatrixCellResultToken*>(mpToken);
438 458 : if (p->GetUpperLeftType() == formula::svDouble)
439 446 : return p->GetUpperLeftToken()->GetDouble();
440 : }
441 12 : break;
442 : default:
443 : ; // nothing
444 : }
445 : }
446 956 : return 0.0;
447 : }
448 84374 : if (mbEmpty)
449 2774 : return 0.0;
450 81600 : return mfValue;
451 : }
452 :
453 1093 : svl::SharedString ScFormulaResult::GetString() const
454 : {
455 1093 : if (mbToken && mpToken)
456 : {
457 1058 : switch (mpToken->GetType())
458 : {
459 : case formula::svString:
460 : case formula::svHybridCell:
461 : case formula::svHybridValueCell:
462 1030 : return mpToken->GetString();
463 : case formula::svMatrixCell:
464 : {
465 : const ScMatrixCellResultToken* p =
466 28 : static_cast<const ScMatrixCellResultToken*>(mpToken);
467 28 : if (p->GetUpperLeftType() == formula::svString)
468 28 : return p->GetUpperLeftToken()->GetString();
469 : }
470 0 : break;
471 : default:
472 : ; // nothing
473 : }
474 : }
475 35 : return svl::SharedString::getEmptyString();
476 : }
477 :
478 20821 : ScConstMatrixRef ScFormulaResult::GetMatrix() const
479 : {
480 20821 : if (GetType() == formula::svMatrixCell)
481 638 : return mpToken->GetMatrix();
482 20183 : return NULL;
483 : }
484 :
485 262 : const OUString& ScFormulaResult::GetHybridFormula() const
486 : {
487 262 : if (GetType() == formula::svHybridCell)
488 : {
489 10 : const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
490 10 : if (p)
491 10 : return p->GetFormula();
492 : }
493 252 : return EMPTY_OUSTRING;
494 : }
495 :
496 1432 : void ScFormulaResult::SetHybridDouble( double f )
497 : {
498 1432 : ResetToDefaults();
499 1432 : 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 1432 : mfValue = f;
515 1432 : mbToken = false;
516 1432 : meMultiline = MULTILINE_FALSE;
517 : }
518 1432 : }
519 :
520 234 : void ScFormulaResult::SetHybridString( const svl::SharedString& rStr )
521 : {
522 : // Obtain values before changing anything.
523 234 : double f = GetDouble();
524 234 : OUString aFormula( GetHybridFormula());
525 234 : ResetToDefaults();
526 234 : if (mbToken && mpToken)
527 0 : mpToken->DecRef();
528 234 : mpToken = new ScHybridCellToken( f, rStr, aFormula);
529 234 : mpToken->IncRef();
530 234 : mbToken = true;
531 234 : }
532 :
533 10 : void ScFormulaResult::SetHybridFormula( const OUString & rFormula )
534 : {
535 : // Obtain values before changing anything.
536 10 : double f = GetDouble();
537 10 : svl::SharedString aStr = GetString();
538 10 : ResetToDefaults();
539 10 : if (mbToken && mpToken)
540 0 : mpToken->DecRef();
541 10 : mpToken = new ScHybridCellToken( f, aStr, rFormula);
542 10 : mpToken->IncRef();
543 10 : mbToken = true;
544 10 : }
545 :
546 50 : void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL )
547 : {
548 50 : ResetToDefaults();
549 50 : if (mbToken && mpToken)
550 50 : mpToken->DecRef();
551 50 : mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
552 50 : mpToken->IncRef();
553 50 : mbToken = true;
554 50 : }
555 :
556 46644 : const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
557 : {
558 46644 : return (GetType() == formula::svMatrixCell ?
559 46644 : dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
560 : }
561 :
562 46360 : ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
563 : {
564 46360 : return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
565 228 : }
566 :
567 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|