1 | /* This file is part of the KDE project |
2 | Copyright 2004 Tomas Mecir <mecirt@gmail.com> |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | // Local |
21 | #include "ValueConverter.h" |
22 | |
23 | #include "CalculationSettings.h" |
24 | #include "Localization.h" |
25 | #include "ValueParser.h" |
26 | |
27 | using namespace Calligra::Sheets; |
28 | |
29 | ValueConverter::ValueConverter(const ValueParser* parser) |
30 | : m_parser(parser) |
31 | { |
32 | } |
33 | |
34 | const CalculationSettings* ValueConverter::settings() const |
35 | { |
36 | return m_parser->settings(); |
37 | } |
38 | |
39 | Value ValueConverter::asBoolean(const Value &value, bool* ok) const |
40 | { |
41 | Value val; |
42 | |
43 | if (ok) |
44 | *ok = true; |
45 | bool okay = true; |
46 | |
47 | switch (value.type()) { |
48 | case Value::Empty: |
49 | val = Value(false); |
50 | break; |
51 | case Value::Boolean: |
52 | val = value; |
53 | break; |
54 | case Value::Integer: |
55 | val = Value(value.asInteger() ? true : false); |
56 | break; |
57 | case Value::Float: |
58 | val = Value((value.asFloat() == 0.0) ? false : true); |
59 | break; |
60 | case Value::Complex: |
61 | val = Value((value.asComplex().real() == complex<Number>(0.0, 0.0)) ? false : true); |
62 | break; |
63 | case Value::String: |
64 | val = m_parser->tryParseBool(value.asString(), &okay); |
65 | if (!okay) |
66 | val = Value(false); |
67 | if (ok) |
68 | *ok = okay; |
69 | break; |
70 | case Value::Array: |
71 | val = asBoolean(value.element(0, 0)); |
72 | break; |
73 | case Value::CellRange: |
74 | /* NOTHING */ |
75 | break; |
76 | case Value::Error: |
77 | val = Value(false); |
78 | break; |
79 | }; |
80 | |
81 | return val; |
82 | } |
83 | |
84 | Value ValueConverter::asInteger(const Value &value, bool* ok) const |
85 | { |
86 | Value val; |
87 | |
88 | if (ok) |
89 | *ok = true; |
90 | |
91 | switch (value.type()) { |
92 | case Value::Empty: |
93 | val = Value(0); |
94 | break; |
95 | case Value::Boolean: |
96 | val = Value(value.asBoolean() ? 1 : 0); |
97 | break; |
98 | case Value::Integer: |
99 | val = value; |
100 | break; |
101 | case Value::Float: |
102 | val = Value(value.asInteger()); |
103 | break; |
104 | case Value::Complex: |
105 | val = Value(value.asInteger()); |
106 | break; |
107 | case Value::String: |
108 | val = m_parser->parse(value.asString()); |
109 | if (!val.isNumber()) { |
110 | val = Value(0); |
111 | if (ok) |
112 | *ok = false; |
113 | } |
114 | val = Value(val.asInteger()); |
115 | break; |
116 | case Value::Array: |
117 | val = asInteger(value.element(0, 0)); |
118 | break; |
119 | case Value::CellRange: |
120 | /* NOTHING */ |
121 | break; |
122 | case Value::Error: |
123 | val = Value(0); |
124 | break; |
125 | }; |
126 | |
127 | return val; |
128 | } |
129 | |
130 | Value ValueConverter::asFloat(const Value &value, bool* ok) const |
131 | { |
132 | Value val; |
133 | |
134 | if (ok) |
135 | *ok = true; |
136 | |
137 | switch (value.type()) { |
138 | case Value::Empty: |
139 | val = Value(0.0); |
140 | break; |
141 | case Value::Boolean: |
142 | val = Value(value.asBoolean() ? 1.0 : 0.0); |
143 | break; |
144 | case Value::Integer: |
145 | val = Value(value.asFloat()); |
146 | break; |
147 | case Value::Float: |
148 | val = value; |
149 | break; |
150 | case Value::Complex: |
151 | val = Value(value.asFloat()); |
152 | break; |
153 | case Value::String: |
154 | val = m_parser->parse(value.asString()); |
155 | if (!val.isNumber()) { |
156 | val = Value(0.0); |
157 | if (ok) |
158 | *ok = false; |
159 | } |
160 | val = Value(val.asFloat()); |
161 | break; |
162 | case Value::Array: |
163 | val = asFloat(value.element(0, 0)); |
164 | break; |
165 | case Value::CellRange: |
166 | /* NOTHING */ |
167 | break; |
168 | case Value::Error: |
169 | val = Value(0.0); |
170 | break; |
171 | }; |
172 | |
173 | return val; |
174 | } |
175 | |
176 | Value ValueConverter::asComplex(const Value &value, bool* ok) const |
177 | { |
178 | Value val; |
179 | |
180 | if (ok) |
181 | *ok = true; |
182 | |
183 | switch (value.type()) { |
184 | case Value::Empty: |
185 | val = Value(complex<Number>(0.0, 0.0)); |
186 | break; |
187 | case Value::Boolean: |
188 | val = Value(complex<Number>(value.asBoolean() ? 1.0 : 0.0, 0.0)); |
189 | break; |
190 | case Value::Integer: |
191 | case Value::Float: |
192 | val = Value(complex<Number>(value.asFloat(), 0.0)); |
193 | break; |
194 | case Value::Complex: |
195 | val = value; |
196 | break; |
197 | case Value::String: |
198 | val = m_parser->parse(value.asString()); |
199 | if (!val.isNumber()) { |
200 | val = Value(complex<Number>(0.0, 0.0)); |
201 | if (ok) |
202 | *ok = false; |
203 | } |
204 | val = Value(val.asComplex()); |
205 | break; |
206 | case Value::Array: |
207 | val = asComplex(value.element(0, 0)); |
208 | break; |
209 | case Value::CellRange: |
210 | /* NOTHING */ |
211 | break; |
212 | case Value::Error: |
213 | val = Value(complex<Number>(0.0, 0.0)); |
214 | break; |
215 | }; |
216 | |
217 | return val; |
218 | } |
219 | |
220 | Value ValueConverter::asNumeric(const Value &value, bool* ok) const |
221 | { |
222 | Value val; |
223 | |
224 | if (ok) |
225 | *ok = true; |
226 | |
227 | switch (value.type()) { |
228 | case Value::Empty: |
229 | val = Value(0.0); |
230 | break; |
231 | case Value::Boolean: |
232 | val = Value(value.asBoolean() ? 1.0 : 0.0); |
233 | break; |
234 | case Value::Integer: |
235 | case Value::Float: |
236 | case Value::Complex: |
237 | val = value; |
238 | break; |
239 | case Value::String: |
240 | val = m_parser->parse(value.asString()); |
241 | if (!val.isNumber()) { |
242 | val = Value(0.0); |
243 | if (ok) |
244 | *ok = false; |
245 | } |
246 | break; |
247 | case Value::Array: |
248 | val = asNumeric(value.element(0, 0)); |
249 | break; |
250 | case Value::CellRange: |
251 | /* NOTHING */ |
252 | break; |
253 | case Value::Error: |
254 | val = Value(0.0); |
255 | break; |
256 | }; |
257 | |
258 | return val; |
259 | } |
260 | |
261 | Value ValueConverter::asString(const Value &value) const |
262 | { |
263 | // This is a simpler version of ValueFormatter... We cannot use that one, |
264 | // as we sometimes want to generate the string differently ... |
265 | |
266 | Value val; |
267 | QString s; |
268 | Value::Format fmt; |
269 | int pos; |
270 | switch (value.type()) { |
271 | case Value::Empty: |
272 | val = Value(QString()); |
273 | break; |
274 | case Value::Boolean: |
275 | val = Value(value.asBoolean() ? ki18n("True" ).toString(m_parser->settings()->locale()) : |
276 | ki18n("False" ).toString(m_parser->settings()->locale())); |
277 | break; |
278 | case Value::Integer: { |
279 | fmt = value.format(); |
280 | if (fmt == Value::fmt_Percent) |
281 | val = Value(QString::number(value.asInteger() * 100) + " %" ); |
282 | else if (fmt == Value::fmt_DateTime) |
283 | val = Value(m_parser->settings()->locale()->formatDateTime(value.asDateTime(settings()))); |
284 | else if (fmt == Value::fmt_Date) |
285 | val = Value(m_parser->settings()->locale()->formatDate(value.asDate(settings()))); |
286 | else if (fmt == Value::fmt_Time) |
287 | val = Value(m_parser->settings()->locale()->formatTime(value.asTime(settings()))); |
288 | else |
289 | val = Value(QString::number(value.asInteger())); |
290 | } |
291 | break; |
292 | case Value::Float: |
293 | fmt = value.format(); |
294 | if (fmt == Value::fmt_DateTime) |
295 | val = Value(m_parser->settings()->locale()->formatDateTime(value.asDateTime(settings()))); |
296 | else if (fmt == Value::fmt_Date) |
297 | val = Value(m_parser->settings()->locale()->formatDate(value.asDate(settings()), KLocale::ShortDate)); |
298 | else if (fmt == Value::fmt_Time) |
299 | val = Value(m_parser->settings()->locale()->formatTime(value.asTime(settings()))); |
300 | else { |
301 | //convert the number, change decimal point from English to local |
302 | s = QString::number(numToDouble(value.asFloat()), 'g', 10); |
303 | const QString decimalSymbol = m_parser->settings()->locale()->decimalSymbol(); |
304 | if (!decimalSymbol.isNull() && ((pos = s.indexOf('.')) != -1)) |
305 | s.replace(pos, 1, decimalSymbol); |
306 | if (fmt == Value::fmt_Percent) |
307 | s += " %" ; |
308 | val = Value(s); |
309 | } |
310 | break; |
311 | case Value::Complex: |
312 | fmt = value.format(); |
313 | if (fmt == Value::fmt_DateTime) |
314 | val = Value(m_parser->settings()->locale()->formatDateTime(value.asDateTime(settings()))); |
315 | else if (fmt == Value::fmt_Date) |
316 | val = Value(m_parser->settings()->locale()->formatDate(value.asDate(settings()), KLocale::ShortDate)); |
317 | else if (fmt == Value::fmt_Time) |
318 | val = Value(m_parser->settings()->locale()->formatTime(value.asTime(settings()))); |
319 | else { |
320 | //convert the number, change decimal point from English to local |
321 | const QString decimalSymbol = m_parser->settings()->locale()->decimalSymbol(); |
322 | QString real = QString::number(numToDouble(value.asComplex().real()), 'g', 10); |
323 | if (!decimalSymbol.isNull() && ((pos = real.indexOf('.')) != -1)) |
324 | real.replace(pos, 1, decimalSymbol); |
325 | QString imag = QString::number(numToDouble(value.asComplex().imag()), 'g', 10); |
326 | if (!decimalSymbol.isNull() && ((pos = imag.indexOf('.')) != -1)) |
327 | imag.replace(pos, 1, decimalSymbol); |
328 | s = real; |
329 | if (value.asComplex().imag() >= 0.0) |
330 | s += '+'; |
331 | // TODO Stefan: Some prefer 'j'. Configure option? Spec? |
332 | s += imag + 'i'; |
333 | // NOTE Stefan: Never recognized a complex percentage anywhere. ;-) |
334 | // if (fmt == Value::fmt_Percent) |
335 | // s += " %"; |
336 | val = Value(s); |
337 | } |
338 | break; |
339 | case Value::String: |
340 | val = value; |
341 | break; |
342 | case Value::Array: |
343 | val = Value(asString(value.element(0, 0))); |
344 | break; |
345 | case Value::CellRange: |
346 | /* NOTHING */ |
347 | break; |
348 | case Value::Error: |
349 | val = Value(value.errorMessage()); |
350 | break; |
351 | }; |
352 | |
353 | return val; |
354 | } |
355 | |
356 | Value ValueConverter::asDateTime(const Value &value, bool* ok) const |
357 | { |
358 | Value val; |
359 | |
360 | if (ok) |
361 | *ok = true; |
362 | bool okay = true; |
363 | |
364 | switch (value.type()) { |
365 | case Value::Empty: |
366 | val = Value(QDateTime::currentDateTime(), settings()); |
367 | break; |
368 | case Value::Boolean: |
369 | //ignore the bool value... any better idea? ;) |
370 | val = Value(QDateTime::currentDateTime(), settings()); |
371 | break; |
372 | case Value::Integer: |
373 | case Value::Float: |
374 | case Value::Complex: |
375 | val = Value(value.asFloat()); |
376 | val.setFormat(Value::fmt_DateTime); |
377 | break; |
378 | case Value::String: |
379 | //no DateTime m_parser, so we parse as Date, hoping for the best ... |
380 | val = m_parser->tryParseDate(value.asString(), &okay); |
381 | if (!okay) |
382 | val = Value::errorVALUE(); |
383 | if (ok) |
384 | *ok = okay; |
385 | val.setFormat(Value::fmt_DateTime); |
386 | break; |
387 | case Value::Array: |
388 | val = asDateTime(value.element(0, 0)); |
389 | break; |
390 | case Value::CellRange: |
391 | /* NOTHING */ |
392 | break; |
393 | case Value::Error: |
394 | break; |
395 | }; |
396 | |
397 | return val; |
398 | } |
399 | |
400 | Value ValueConverter::asDate(const Value &value, bool* ok) const |
401 | { |
402 | Value val; |
403 | |
404 | if (ok) |
405 | *ok = true; |
406 | bool okay = true; |
407 | |
408 | switch (value.type()) { |
409 | case Value::Empty: |
410 | val = Value(QDate::currentDate(), settings()); |
411 | break; |
412 | case Value::Boolean: |
413 | //ignore the bool value... any better idea? ;) |
414 | val = Value(QDate::currentDate(), settings()); |
415 | break; |
416 | case Value::Integer: |
417 | case Value::Float: |
418 | case Value::Complex: |
419 | val = Value(value.asFloat()); |
420 | val.setFormat(Value::fmt_Date); |
421 | break; |
422 | case Value::String: |
423 | val = m_parser->tryParseDate(value.asString(), &okay); |
424 | if (!okay) |
425 | val = Value::errorVALUE(); |
426 | if (ok) |
427 | *ok = okay; |
428 | break; |
429 | case Value::Array: |
430 | val = asDate(value.element(0, 0)); |
431 | break; |
432 | case Value::CellRange: |
433 | /* NOTHING */ |
434 | break; |
435 | case Value::Error: |
436 | break; |
437 | }; |
438 | |
439 | return val; |
440 | } |
441 | |
442 | Value ValueConverter::asTime(const Value &value, bool* ok) const |
443 | { |
444 | Value val; |
445 | |
446 | if (ok) |
447 | *ok = true; |
448 | bool okay = true; |
449 | |
450 | switch (value.type()) { |
451 | case Value::Empty: |
452 | val = Value(QTime::currentTime(), settings()); |
453 | break; |
454 | case Value::Boolean: |
455 | //ignore the bool value... any better idea? ;) |
456 | val = Value(QTime::currentTime(), settings()); |
457 | break; |
458 | case Value::Integer: |
459 | case Value::Float: |
460 | case Value::Complex: |
461 | val = Value(value.asFloat()); |
462 | val.setFormat(Value::fmt_Time); |
463 | break; |
464 | case Value::String: |
465 | val = m_parser->tryParseTime(value.asString(), &okay); |
466 | if (!okay) |
467 | val = Value::errorVALUE(); |
468 | if (ok) |
469 | *ok = okay; |
470 | break; |
471 | case Value::Array: |
472 | val = asTime(value.element(0, 0)); |
473 | break; |
474 | case Value::CellRange: |
475 | /* NOTHING */ |
476 | break; |
477 | case Value::Error: |
478 | break; |
479 | }; |
480 | |
481 | return val; |
482 | } |
483 | |
484 | bool ValueConverter::toBoolean(const Value& value) const |
485 | { |
486 | return asBoolean(value).asBoolean(); |
487 | } |
488 | |
489 | int ValueConverter::toInteger(const Value& value) const |
490 | { |
491 | return asInteger(value).asInteger(); |
492 | } |
493 | |
494 | Number ValueConverter::toFloat(const Value& value) const |
495 | { |
496 | return asFloat(value).asFloat(); |
497 | } |
498 | |
499 | complex<Number> ValueConverter::toComplex(const Value& value) const |
500 | { |
501 | return asComplex(value).asComplex(); |
502 | } |
503 | |
504 | QString ValueConverter::toString(const Value& value) const |
505 | { |
506 | return asString(value).asString(); |
507 | } |
508 | |
509 | QDateTime ValueConverter::toDateTime(const Value& value) const |
510 | { |
511 | return asDateTime(value).asDateTime(settings()); |
512 | } |
513 | |
514 | QDate ValueConverter::toDate(const Value& value) const |
515 | { |
516 | return asDate(value).asDate(settings()); |
517 | } |
518 | |
519 | QTime ValueConverter::toTime(const Value& value) const |
520 | { |
521 | return asTime(value).asTime(settings()); |
522 | } |
523 | |