Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * Version: MPL 1.1 / GPLv3+ / LGPLv3+
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License or as specified alternatively below. You may obtain a copy of
8 : * the License at http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * Major Contributor(s):
16 : * Copyright (C) 2012 Kohei Yoshida <kohei.yoshida@suse.com>
17 : *
18 : * All Rights Reserved.
19 : *
20 : * For minor contributions see the git repository.
21 : *
22 : * Alternatively, the contents of this file may be used under the terms of
23 : * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
24 : * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
25 : * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
26 : * instead of those above.
27 : */
28 :
29 : #include "formularesult.hxx"
30 :
31 3109 : ScFormulaResult::ScFormulaResult() :
32 : mpToken(NULL), mnError(0), mbToken(true),
33 : mbEmpty(false), mbEmptyDisplayedAsString(false),
34 3109 : meMultiline(MULTILINE_UNKNOWN) {}
35 :
36 26 : ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
37 : mnError( r.mnError), mbToken( r.mbToken),
38 : mbEmpty( r.mbEmpty),
39 : mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
40 26 : meMultiline( r.meMultiline)
41 : {
42 26 : if (mbToken)
43 : {
44 0 : mpToken = r.mpToken;
45 0 : 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 =
52 0 : r.GetMatrixFormulaCellToken();
53 0 : if (pMatFormula)
54 : {
55 0 : mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
56 0 : mpToken->IncRef();
57 : }
58 : else
59 0 : IncrementTokenRef( mpToken);
60 : }
61 : }
62 : else
63 26 : mfValue = r.mfValue;
64 26 : }
65 :
66 2432 : ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
67 : mnError(0), mbToken(false), mbEmpty(false), mbEmptyDisplayedAsString(false),
68 2432 : meMultiline(MULTILINE_UNKNOWN)
69 : {
70 2432 : SetToken( p);
71 2432 : }
72 :
73 5431 : ScFormulaResult::~ScFormulaResult()
74 : {
75 5431 : if (mbToken && mpToken)
76 91 : mpToken->DecRef();
77 5431 : }
78 :
79 :
80 11941 : void ScFormulaResult::ResetToDefaults()
81 : {
82 11941 : mnError = 0;
83 11941 : mbEmpty = false;
84 11941 : mbEmptyDisplayedAsString = false;
85 11941 : meMultiline = MULTILINE_UNKNOWN;
86 11941 : }
87 :
88 3374 : void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
89 : {
90 3374 : ResetToDefaults();
91 3374 : if (!p)
92 : {
93 230 : mpToken = p;
94 230 : mbToken = true;
95 : }
96 : else
97 : {
98 3144 : switch (p->GetType())
99 : {
100 : case formula::svError:
101 62 : mnError = p->GetError();
102 62 : p->DecRef();
103 62 : mbToken = false;
104 : // set in case mnError is 0 now, which shouldn't happen but ...
105 62 : mfValue = 0.0;
106 62 : meMultiline = MULTILINE_FALSE;
107 62 : break;
108 : case formula::svEmptyCell:
109 14 : mbEmpty = true;
110 14 : mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
111 14 : p->DecRef();
112 14 : mbToken = false;
113 14 : meMultiline = MULTILINE_FALSE;
114 14 : break;
115 : case formula::svDouble:
116 2961 : mfValue = p->GetDouble();
117 2961 : p->DecRef();
118 2961 : mbToken = false;
119 2961 : meMultiline = MULTILINE_FALSE;
120 2961 : break;
121 : default:
122 107 : mpToken = p;
123 107 : mbToken = true;
124 : }
125 : }
126 3374 : }
127 :
128 0 : ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
129 : {
130 0 : Assign( r);
131 0 : return *this;
132 : }
133 :
134 2321 : void ScFormulaResult::Assign( const ScFormulaResult & r )
135 : {
136 2321 : if (this == &r)
137 2321 : return;
138 2321 : if (r.mbEmpty)
139 : {
140 1 : if (mbToken && mpToken)
141 0 : mpToken->DecRef();
142 1 : mbToken = false;
143 1 : mbEmpty = true;
144 1 : mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
145 1 : meMultiline = r.meMultiline;
146 : }
147 2320 : else if (r.mbToken)
148 : {
149 : // Matrix formula cell token must be cloned, see copy-ctor.
150 : const ScMatrixFormulaCellToken* pMatFormula =
151 3 : r.GetMatrixFormulaCellToken();
152 3 : if (pMatFormula)
153 0 : SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
154 : else
155 3 : SetToken( r.mpToken);
156 : }
157 : else
158 2317 : SetDouble( r.mfValue);
159 : // If there was an error there will be an error, no matter what Set...()
160 : // methods did.
161 2321 : mnError = r.mnError;
162 : }
163 :
164 3385 : void ScFormulaResult::SetToken( const formula::FormulaToken* p )
165 : {
166 3385 : ResetToDefaults();
167 3385 : IncrementTokenRef( p);
168 : // Handle a result obtained from the interpreter to be assigned to a matrix
169 : // formula cell's ScMatrixFormulaCellToken.
170 3385 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
171 3385 : if (pMatFormula)
172 : {
173 : const ScMatrixCellResultToken* pMatResult =
174 11 : (p && p->GetType() == formula::svMatrixCell ?
175 22 : dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
176 11 : if (pMatResult)
177 : {
178 : const ScMatrixFormulaCellToken* pNewMatFormula =
179 9 : dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
180 9 : if (pNewMatFormula)
181 : {
182 : SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
183 0 : pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
184 0 : pNewMatFormula->GetMatRows());
185 : }
186 9 : pMatFormula->Assign( *pMatResult);
187 9 : p->DecRef();
188 : }
189 2 : else if (p)
190 : {
191 : // This may be the result of some constant expression like
192 : // {="string"} that doesn't result in a matrix but still would
193 : // display the result in all cells of this matrix formula.
194 2 : pMatFormula->Assign( *p);
195 2 : p->DecRef();
196 : }
197 : else
198 : {
199 : // NULL result? Well, if you say so ...
200 0 : pMatFormula->ResetResult();
201 : }
202 : }
203 : else
204 : {
205 3374 : if (mbToken && mpToken)
206 44 : mpToken->DecRef();
207 3374 : ResolveToken( p);
208 : }
209 3385 : }
210 :
211 4757 : void ScFormulaResult::SetDouble( double f )
212 : {
213 4757 : ResetToDefaults();
214 : // Handle a result obtained from the interpreter to be assigned to a matrix
215 : // formula cell's ScMatrixFormulaCellToken.
216 4757 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
217 4757 : if (pMatFormula)
218 17 : pMatFormula->SetUpperLeftDouble( f);
219 : else
220 : {
221 4740 : if (mbToken && mpToken)
222 0 : mpToken->DecRef();
223 4740 : mfValue = f;
224 4740 : mbToken = false;
225 4740 : meMultiline = MULTILINE_FALSE;
226 : }
227 4757 : }
228 :
229 42046 : formula::StackVar ScFormulaResult::GetType() const
230 : {
231 : // Order is significant.
232 42046 : if (mnError)
233 218 : return formula::svError;
234 41828 : if (mbEmpty)
235 74 : return formula::svEmptyCell;
236 41754 : if (!mbToken)
237 37102 : return formula::svDouble;
238 4652 : if (mpToken)
239 1099 : return mpToken->GetType();
240 3553 : return formula::svUnknown;
241 : }
242 :
243 30193 : formula::StackVar ScFormulaResult::GetCellResultType() const
244 : {
245 30193 : formula::StackVar sv = GetType();
246 30193 : if (sv == formula::svMatrixCell)
247 : // don't need to test for mpToken here, GetType() already did it
248 108 : sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
249 30193 : return sv;
250 : }
251 :
252 514 : bool ScFormulaResult::IsEmptyDisplayedAsString() const
253 : {
254 514 : if (mbEmpty)
255 4 : return mbEmptyDisplayedAsString;
256 510 : if (GetType() == formula::svMatrixCell)
257 : {
258 : // don't need to test for mpToken here, GetType() already did it
259 : const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
260 : static_cast<const ScMatrixCellResultToken*>(
261 3 : mpToken)->GetUpperLeftToken().get());
262 3 : if (p)
263 0 : return p->IsDisplayedAsString();
264 : }
265 510 : return false;
266 : }
267 :
268 12721 : bool ScFormulaResult::IsValue() const
269 : {
270 12721 : formula::StackVar sv = GetCellResultType();
271 12721 : return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell;
272 : }
273 :
274 0 : bool ScFormulaResult::IsMultiline() const
275 : {
276 0 : if (meMultiline == MULTILINE_UNKNOWN)
277 : {
278 0 : const String& rStr = GetString();
279 0 : if (rStr.Len() && rStr.Search( _LF ) != STRING_NOTFOUND)
280 0 : const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
281 : else
282 0 : const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
283 : }
284 0 : return meMultiline == MULTILINE_TRUE;
285 : }
286 :
287 12587 : sal_uInt16 ScFormulaResult::GetResultError() const
288 : {
289 12587 : if (mnError)
290 75 : return mnError;
291 12512 : formula::StackVar sv = GetCellResultType();
292 12512 : if (sv == formula::svError)
293 : {
294 0 : if (GetType() == formula::svMatrixCell)
295 : // don't need to test for mpToken here, GetType() already did it
296 : return static_cast<const ScMatrixCellResultToken*>(mpToken)->
297 0 : GetUpperLeftToken()->GetError();
298 0 : if (mpToken)
299 0 : return mpToken->GetError();
300 : }
301 12512 : return 0;
302 : }
303 :
304 3011 : void ScFormulaResult::SetResultError( sal_uInt16 nErr )
305 : {
306 3011 : mnError = nErr;
307 3011 : }
308 :
309 0 : formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
310 : {
311 0 : if (mbToken)
312 0 : return mpToken;
313 0 : return NULL;
314 : }
315 :
316 3 : formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
317 : {
318 3 : if (GetType() == formula::svMatrixCell)
319 : // don't need to test for mpToken here, GetType() already did it
320 3 : return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
321 0 : return GetToken();
322 : }
323 :
324 13793 : double ScFormulaResult::GetDouble() const
325 : {
326 13793 : if (mbToken)
327 : {
328 : // Should really not be of type formula::svDouble here.
329 99 : if (mpToken)
330 : {
331 53 : switch (mpToken->GetType())
332 : {
333 : case formula::svHybridCell:
334 0 : return mpToken->GetDouble();
335 : case formula::svMatrixCell:
336 : {
337 : const ScMatrixCellResultToken* p =
338 53 : static_cast<const ScMatrixCellResultToken*>(mpToken);
339 53 : if (p->GetUpperLeftType() == formula::svDouble)
340 43 : return p->GetUpperLeftToken()->GetDouble();
341 : }
342 10 : break;
343 : default:
344 : ; // nothing
345 : }
346 : }
347 56 : return 0.0;
348 : }
349 13694 : if (mbEmpty)
350 24 : return 0.0;
351 13670 : return mfValue;
352 : }
353 :
354 136 : const String & ScFormulaResult::GetString() const
355 : {
356 136 : if (mbToken && mpToken)
357 : {
358 135 : switch (mpToken->GetType())
359 : {
360 : case formula::svString:
361 : case formula::svHybridCell:
362 134 : return mpToken->GetString();
363 : case formula::svMatrixCell:
364 : {
365 : const ScMatrixCellResultToken* p =
366 1 : static_cast<const ScMatrixCellResultToken*>(mpToken);
367 1 : if (p->GetUpperLeftType() == formula::svString)
368 1 : return p->GetUpperLeftToken()->GetString();
369 : }
370 0 : break;
371 : default:
372 : ; // nothing
373 : }
374 : }
375 1 : return EMPTY_STRING;
376 : }
377 :
378 3094 : ScConstMatrixRef ScFormulaResult::GetMatrix() const
379 : {
380 3094 : if (GetType() == formula::svMatrixCell)
381 90 : return static_cast<const ScToken*>(mpToken)->GetMatrix();
382 3004 : return NULL;
383 : }
384 :
385 56 : const String & ScFormulaResult::GetHybridFormula() const
386 : {
387 56 : if (GetType() == formula::svHybridCell)
388 : {
389 0 : const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
390 0 : if (p)
391 0 : return p->GetFormula();
392 : }
393 56 : return EMPTY_STRING;
394 : }
395 :
396 369 : void ScFormulaResult::SetHybridDouble( double f )
397 : {
398 369 : ResetToDefaults();
399 369 : if (mbToken && mpToken)
400 : {
401 15 : if(GetType() == formula::svMatrixCell)
402 15 : SetDouble(f);
403 : else
404 : {
405 0 : String aString( GetString());
406 0 : String aFormula( GetHybridFormula());
407 0 : mpToken->DecRef();
408 0 : mpToken = new ScHybridCellToken( f, aString, aFormula);
409 0 : mpToken->IncRef();
410 15 : }
411 : }
412 : else
413 : {
414 354 : mfValue = f;
415 354 : mbToken = false;
416 354 : meMultiline = MULTILINE_FALSE;
417 : }
418 369 : }
419 :
420 56 : void ScFormulaResult::SetHybridString( const rtl::OUString & rStr )
421 : {
422 : // Obtain values before changing anything.
423 56 : double f = GetDouble();
424 56 : String aFormula( GetHybridFormula());
425 56 : ResetToDefaults();
426 56 : if (mbToken && mpToken)
427 10 : mpToken->DecRef();
428 56 : mpToken = new ScHybridCellToken( f, rStr, aFormula);
429 56 : mpToken->IncRef();
430 56 : mbToken = true;
431 56 : }
432 :
433 0 : void ScFormulaResult::SetHybridFormula( const String & rFormula )
434 : {
435 : // Obtain values before changing anything.
436 0 : double f = GetDouble();
437 0 : String aStr( GetString());
438 0 : ResetToDefaults();
439 0 : if (mbToken && mpToken)
440 0 : mpToken->DecRef();
441 0 : mpToken = new ScHybridCellToken( f, aStr, rFormula);
442 0 : mpToken->IncRef();
443 0 : mbToken = true;
444 0 : }
445 :
446 8175 : const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
447 : {
448 8175 : return (GetType() == formula::svMatrixCell ?
449 8175 : dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
450 : }
451 :
452 8170 : ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
453 : {
454 8170 : return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
455 : }
456 :
457 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|