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 6236 : ScFormulaResult::ScFormulaResult() :
32 : mpToken(NULL), mnError(0), mbToken(true),
33 : mbEmpty(false), mbEmptyDisplayedAsString(false),
34 6236 : meMultiline(MULTILINE_UNKNOWN) {}
35 :
36 72 : ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
37 : mnError( r.mnError), mbToken( r.mbToken),
38 : mbEmpty( r.mbEmpty),
39 : mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
40 72 : meMultiline( r.meMultiline)
41 : {
42 72 : if (mbToken)
43 : {
44 16 : mpToken = r.mpToken;
45 16 : 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 16 : r.GetMatrixFormulaCellToken();
53 16 : if (pMatFormula)
54 : {
55 0 : mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
56 0 : mpToken->IncRef();
57 : }
58 : else
59 16 : IncrementTokenRef( mpToken);
60 : }
61 : }
62 : else
63 56 : mfValue = r.mfValue;
64 72 : }
65 :
66 4868 : ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
67 : mnError(0), mbToken(false), mbEmpty(false), mbEmptyDisplayedAsString(false),
68 4868 : meMultiline(MULTILINE_UNKNOWN)
69 : {
70 4868 : SetToken( p);
71 4868 : }
72 :
73 10894 : ScFormulaResult::~ScFormulaResult()
74 : {
75 10894 : if (mbToken && mpToken)
76 192 : mpToken->DecRef();
77 10894 : }
78 :
79 :
80 24006 : void ScFormulaResult::ResetToDefaults()
81 : {
82 24006 : mnError = 0;
83 24006 : mbEmpty = false;
84 24006 : mbEmptyDisplayedAsString = false;
85 24006 : meMultiline = MULTILINE_UNKNOWN;
86 24006 : }
87 :
88 6800 : void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
89 : {
90 6800 : ResetToDefaults();
91 6800 : if (!p)
92 : {
93 486 : mpToken = p;
94 486 : mbToken = true;
95 : }
96 : else
97 : {
98 6314 : switch (p->GetType())
99 : {
100 : case formula::svError:
101 124 : mnError = p->GetError();
102 124 : p->DecRef();
103 124 : mbToken = false;
104 : // set in case mnError is 0 now, which shouldn't happen but ...
105 124 : mfValue = 0.0;
106 124 : meMultiline = MULTILINE_FALSE;
107 124 : break;
108 : case formula::svEmptyCell:
109 28 : mbEmpty = true;
110 28 : mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
111 28 : p->DecRef();
112 28 : mbToken = false;
113 28 : meMultiline = MULTILINE_FALSE;
114 28 : break;
115 : case formula::svDouble:
116 5940 : mfValue = p->GetDouble();
117 5940 : p->DecRef();
118 5940 : mbToken = false;
119 5940 : meMultiline = MULTILINE_FALSE;
120 5940 : break;
121 : default:
122 222 : mpToken = p;
123 222 : mbToken = true;
124 : }
125 : }
126 6800 : }
127 :
128 0 : ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
129 : {
130 0 : Assign( r);
131 0 : return *this;
132 : }
133 :
134 4646 : void ScFormulaResult::Assign( const ScFormulaResult & r )
135 : {
136 4646 : if (this == &r)
137 4646 : return;
138 4646 : if (r.mbEmpty)
139 : {
140 2 : if (mbToken && mpToken)
141 0 : mpToken->DecRef();
142 2 : mbToken = false;
143 2 : mbEmpty = true;
144 2 : mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
145 2 : meMultiline = r.meMultiline;
146 : }
147 4644 : else if (r.mbToken)
148 : {
149 : // Matrix formula cell token must be cloned, see copy-ctor.
150 : const ScMatrixFormulaCellToken* pMatFormula =
151 6 : r.GetMatrixFormulaCellToken();
152 6 : if (pMatFormula)
153 0 : SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
154 : else
155 6 : SetToken( r.mpToken);
156 : }
157 : else
158 4638 : SetDouble( r.mfValue);
159 : // If there was an error there will be an error, no matter what Set...()
160 : // methods did.
161 4646 : mnError = r.mnError;
162 : }
163 :
164 6822 : void ScFormulaResult::SetToken( const formula::FormulaToken* p )
165 : {
166 6822 : ResetToDefaults();
167 6822 : IncrementTokenRef( p);
168 : // Handle a result obtained from the interpreter to be assigned to a matrix
169 : // formula cell's ScMatrixFormulaCellToken.
170 6822 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
171 6822 : if (pMatFormula)
172 : {
173 : const ScMatrixCellResultToken* pMatResult =
174 22 : (p && p->GetType() == formula::svMatrixCell ?
175 44 : dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
176 22 : if (pMatResult)
177 : {
178 : const ScMatrixFormulaCellToken* pNewMatFormula =
179 18 : dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
180 18 : 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 18 : pMatFormula->Assign( *pMatResult);
187 18 : p->DecRef();
188 : }
189 4 : 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 4 : pMatFormula->Assign( *p);
195 4 : p->DecRef();
196 : }
197 : else
198 : {
199 : // NULL result? Well, if you say so ...
200 0 : pMatFormula->ResetResult();
201 : }
202 : }
203 : else
204 : {
205 6800 : if (mbToken && mpToken)
206 112 : mpToken->DecRef();
207 6800 : ResolveToken( p);
208 : }
209 6822 : }
210 :
211 9518 : void ScFormulaResult::SetDouble( double f )
212 : {
213 9518 : ResetToDefaults();
214 : // Handle a result obtained from the interpreter to be assigned to a matrix
215 : // formula cell's ScMatrixFormulaCellToken.
216 9518 : ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
217 9518 : if (pMatFormula)
218 34 : pMatFormula->SetUpperLeftDouble( f);
219 : else
220 : {
221 9484 : if (mbToken && mpToken)
222 0 : mpToken->DecRef();
223 9484 : mfValue = f;
224 9484 : mbToken = false;
225 9484 : meMultiline = MULTILINE_FALSE;
226 : }
227 9518 : }
228 :
229 84350 : formula::StackVar ScFormulaResult::GetType() const
230 : {
231 : // Order is significant.
232 84350 : if (mnError)
233 436 : return formula::svError;
234 83914 : if (mbEmpty)
235 148 : return formula::svEmptyCell;
236 83766 : if (!mbToken)
237 74348 : return formula::svDouble;
238 9418 : if (mpToken)
239 2286 : return mpToken->GetType();
240 7132 : return formula::svUnknown;
241 : }
242 :
243 60536 : formula::StackVar ScFormulaResult::GetCellResultType() const
244 : {
245 60536 : formula::StackVar sv = GetType();
246 60536 : if (sv == formula::svMatrixCell)
247 : // don't need to test for mpToken here, GetType() already did it
248 216 : sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
249 60536 : return sv;
250 : }
251 :
252 1028 : bool ScFormulaResult::IsEmptyDisplayedAsString() const
253 : {
254 1028 : if (mbEmpty)
255 8 : return mbEmptyDisplayedAsString;
256 1020 : 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 6 : mpToken)->GetUpperLeftToken().get());
262 6 : if (p)
263 0 : return p->IsDisplayedAsString();
264 : }
265 1020 : return false;
266 : }
267 :
268 25494 : bool ScFormulaResult::IsValue() const
269 : {
270 25494 : formula::StackVar sv = GetCellResultType();
271 25494 : 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 25264 : sal_uInt16 ScFormulaResult::GetResultError() const
288 : {
289 25264 : if (mnError)
290 150 : return mnError;
291 25114 : formula::StackVar sv = GetCellResultType();
292 25114 : 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 25114 : return 0;
302 : }
303 :
304 6048 : void ScFormulaResult::SetResultError( sal_uInt16 nErr )
305 : {
306 6048 : mnError = nErr;
307 6048 : }
308 :
309 0 : formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
310 : {
311 0 : if (mbToken)
312 0 : return mpToken;
313 0 : return NULL;
314 : }
315 :
316 6 : formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
317 : {
318 6 : if (GetType() == formula::svMatrixCell)
319 : // don't need to test for mpToken here, GetType() already did it
320 6 : return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
321 0 : return GetToken();
322 : }
323 :
324 27644 : double ScFormulaResult::GetDouble() const
325 : {
326 27644 : if (mbToken)
327 : {
328 : // Should really not be of type formula::svDouble here.
329 216 : if (mpToken)
330 : {
331 114 : switch (mpToken->GetType())
332 : {
333 : case formula::svHybridCell:
334 0 : return mpToken->GetDouble();
335 : case formula::svMatrixCell:
336 : {
337 : const ScMatrixCellResultToken* p =
338 106 : static_cast<const ScMatrixCellResultToken*>(mpToken);
339 106 : if (p->GetUpperLeftType() == formula::svDouble)
340 86 : return p->GetUpperLeftToken()->GetDouble();
341 : }
342 20 : break;
343 : default:
344 : ; // nothing
345 : }
346 : }
347 130 : return 0.0;
348 : }
349 27428 : if (mbEmpty)
350 48 : return 0.0;
351 27380 : return mfValue;
352 : }
353 :
354 272 : const String & ScFormulaResult::GetString() const
355 : {
356 272 : if (mbToken && mpToken)
357 : {
358 270 : switch (mpToken->GetType())
359 : {
360 : case formula::svString:
361 : case formula::svHybridCell:
362 268 : return mpToken->GetString();
363 : case formula::svMatrixCell:
364 : {
365 : const ScMatrixCellResultToken* p =
366 2 : static_cast<const ScMatrixCellResultToken*>(mpToken);
367 2 : if (p->GetUpperLeftType() == formula::svString)
368 2 : return p->GetUpperLeftToken()->GetString();
369 : }
370 0 : break;
371 : default:
372 : ; // nothing
373 : }
374 : }
375 2 : return EMPTY_STRING;
376 : }
377 :
378 6214 : ScConstMatrixRef ScFormulaResult::GetMatrix() const
379 : {
380 6214 : if (GetType() == formula::svMatrixCell)
381 180 : return static_cast<const ScToken*>(mpToken)->GetMatrix();
382 6034 : return NULL;
383 : }
384 :
385 122 : const String & ScFormulaResult::GetHybridFormula() const
386 : {
387 122 : 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 122 : return EMPTY_STRING;
394 : }
395 :
396 744 : void ScFormulaResult::SetHybridDouble( double f )
397 : {
398 744 : ResetToDefaults();
399 744 : if (mbToken && mpToken)
400 : {
401 30 : if(GetType() == formula::svMatrixCell)
402 30 : 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 30 : }
411 : }
412 : else
413 : {
414 714 : mfValue = f;
415 714 : mbToken = false;
416 714 : meMultiline = MULTILINE_FALSE;
417 : }
418 744 : }
419 :
420 122 : void ScFormulaResult::SetHybridString( const rtl::OUString & rStr )
421 : {
422 : // Obtain values before changing anything.
423 122 : double f = GetDouble();
424 122 : String aFormula( GetHybridFormula());
425 122 : ResetToDefaults();
426 122 : if (mbToken && mpToken)
427 20 : mpToken->DecRef();
428 122 : mpToken = new ScHybridCellToken( f, rStr, aFormula);
429 122 : mpToken->IncRef();
430 122 : mbToken = true;
431 122 : }
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 16422 : const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
447 : {
448 16422 : return (GetType() == formula::svMatrixCell ?
449 16422 : dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
450 : }
451 :
452 16396 : ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
453 : {
454 16396 : return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
455 : }
456 :
457 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|