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