1 | /* This file is part of the KDE project |
2 | Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> |
3 | Copyright 2003,2004 Ariya Hidayat <ariya@kde.org> |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Library General Public |
7 | License as published by the Free Software Foundation; only |
8 | version 2 of the License. |
9 | |
10 | This library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Library General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Library General Public License |
16 | along with this library; see the file COPYING.LIB. If not, write to |
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #include "Value.h" |
22 | #include "CalculationSettings.h" |
23 | #include "CellStorage.h" |
24 | #include "ValueStorage.h" |
25 | |
26 | #include <kdebug.h> |
27 | #include <klocale.h> |
28 | |
29 | #include <QString> |
30 | #include <QTextStream> |
31 | |
32 | #include <float.h> |
33 | #include <math.h> |
34 | #include <limits.h> |
35 | |
36 | using namespace Calligra::Sheets; |
37 | |
38 | class ValueArray |
39 | { |
40 | public: |
41 | ValueArray() : m_size(0, 0) {} |
42 | ValueArray(const ValueStorage& storage, const QSize& size) : m_size(size), m_storage(storage) {} |
43 | |
44 | ValueStorage& storage() { return m_storage; } |
45 | int rows() const { return qMax(m_size.height(), m_storage.rows()); } |
46 | int columns() const { return qMax(m_size.width(), m_storage.columns()); } |
47 | |
48 | bool operator==(const ValueArray& a) const { return rows() == a.rows() && columns() == a.columns() && m_storage == a.m_storage; } |
49 | private: |
50 | QSize m_size; |
51 | ValueStorage m_storage; |
52 | }; |
53 | |
54 | class Value::Private : public QSharedData |
55 | { |
56 | public: |
57 | |
58 | Value::Type type: 4; |
59 | Value::Format format: 4; |
60 | |
61 | union { // 64 bits at max! |
62 | // b is also secondarily used to indicate a null value if type == Empty, |
63 | // without using up space for an explicit member variable. |
64 | bool b; |
65 | qint64 i; |
66 | Number f; |
67 | complex<Number>* pc; |
68 | QString* ps; |
69 | ValueArray* pa; |
70 | }; |
71 | |
72 | // create empty data |
73 | Private() : type(Value::Empty), format(Value::fmt_None), ps(0) {} |
74 | |
75 | Private(const Private& o) |
76 | : QSharedData(o) |
77 | , type(o.type) |
78 | , format(o.format) { |
79 | switch (type) { |
80 | case Value::Empty: |
81 | default: |
82 | ps = 0; |
83 | break; |
84 | case Value::Boolean: |
85 | b = o.b; |
86 | break; |
87 | case Value::Integer: |
88 | i = o.i; |
89 | break; |
90 | case Value::Float: |
91 | f = o.f; |
92 | break; |
93 | case Value::Complex: |
94 | pc = new complex<Number>(*o.pc); |
95 | break; |
96 | case Value::String: |
97 | case Value::Error: |
98 | ps = new QString(*o.ps); |
99 | break; |
100 | case Value::Array: |
101 | pa = new ValueArray(*o.pa); |
102 | break; |
103 | } |
104 | } |
105 | |
106 | // destroys data |
107 | ~Private() { |
108 | if (this == s_null) |
109 | s_null = 0; |
110 | clear(); |
111 | } |
112 | |
113 | // static empty data to be shared |
114 | static Private* null() { |
115 | if (!s_null) s_null = new Private; return s_null; |
116 | } |
117 | |
118 | // true if it's null (which is shared) |
119 | bool isNull() { |
120 | return this == s_null; |
121 | } |
122 | |
123 | /** Deletes all data. */ |
124 | void clear() { |
125 | if (type == Value::Array) delete pa; |
126 | if (type == Value::Complex) delete pc; |
127 | if (type == Value::Error) delete ps; |
128 | if (type == Value::String) delete ps; |
129 | type = Value::Empty; |
130 | b = 0; |
131 | } |
132 | |
133 | /** set most probable formatting based on the type */ |
134 | void setFormatByType(); |
135 | |
136 | private: |
137 | void operator=(const Value::Private& o); |
138 | |
139 | static Private* s_null; |
140 | }; |
141 | |
142 | void Value::Private::setFormatByType() |
143 | { |
144 | switch (type) { |
145 | case Value::Empty: |
146 | format = Value::fmt_None; |
147 | break; |
148 | case Value::Boolean: |
149 | format = Value::fmt_Boolean; |
150 | break; |
151 | case Value::Integer: |
152 | case Value::Float: |
153 | case Value::Complex: |
154 | format = Value::fmt_Number; |
155 | break; |
156 | case Value::String: |
157 | format = Value::fmt_String; |
158 | break; |
159 | case Value::Array: |
160 | format = Value::fmt_None; |
161 | break; |
162 | case Value::CellRange: |
163 | format = Value::fmt_None; |
164 | break; |
165 | case Value::Error: |
166 | format = Value::fmt_String; |
167 | break; |
168 | }; |
169 | } |
170 | |
171 | // to be shared between all empty value |
172 | Value::Private* Value::Private::s_null = 0; |
173 | |
174 | // static things |
175 | Value ks_value_empty; |
176 | Value ks_value_null; |
177 | Value ks_error_circle; |
178 | Value ks_error_depend; |
179 | Value ks_error_div0; |
180 | Value ks_error_na; |
181 | Value ks_error_name; |
182 | Value ks_error_null; |
183 | Value ks_error_num; |
184 | Value ks_error_parse; |
185 | Value ks_error_ref; |
186 | Value ks_error_value; |
187 | |
188 | // create an empty value |
189 | Value::Value() |
190 | : d(Private::null()) |
191 | { |
192 | } |
193 | |
194 | // destructor |
195 | Value::~Value() |
196 | { |
197 | } |
198 | |
199 | // create value of certain type |
200 | Value::Value(Value::Type _type) |
201 | : d(Private::null()) |
202 | { |
203 | d->type = _type; |
204 | d->setFormatByType(); |
205 | } |
206 | |
207 | // copy constructor |
208 | Value::Value(const Value& _value) |
209 | : d(_value.d) |
210 | { |
211 | } |
212 | |
213 | // assignment operator |
214 | Value& Value::operator=(const Value & _value) |
215 | { |
216 | d = _value.d; |
217 | return *this; |
218 | } |
219 | |
220 | // comparison operator - returns true only if strictly identical, unlike equal()/compare() |
221 | bool Value::operator==(const Value& o) const |
222 | { |
223 | if (d->type != o.d->type) |
224 | return false; |
225 | switch (d->type) { |
226 | // null() (d->b == 1) and empty() (d->b == 0) are equal to this operator |
227 | case Empty: return true; |
228 | case Boolean: return o.d->b == d->b; |
229 | case Integer: return o.d->i == d->i; |
230 | case Float: return compare(o.d->f, d->f) == 0; |
231 | case Complex: return (!d->pc && !o.d->pc) || ((d->pc && o.d->pc) && (*o.d->pc == *d->pc)); |
232 | case String: return (!d->ps && !o.d->ps) || ((d->ps && o.d->ps) && (*o.d->ps == *d->ps)); |
233 | case Array: return (!d->pa && !o.d->pa) || ((d->pa && o.d->pa) && (*o.d->pa == *d->pa)); |
234 | case Error: return (!d->ps && !o.d->ps) || ((d->ps && o.d->ps) && (*o.d->ps == *d->ps)); |
235 | default: break; |
236 | } |
237 | kWarning() << "Unhandled type in Value::operator==: " << d->type; |
238 | return false; |
239 | } |
240 | |
241 | // create a boolean value |
242 | Value::Value(bool b) |
243 | : d(Private::null()) |
244 | { |
245 | d->type = Boolean; |
246 | d->b = b; |
247 | d->format = fmt_Boolean; |
248 | } |
249 | |
250 | // create an integer value |
251 | Value::Value(qint64 i) |
252 | : d(Private::null()) |
253 | { |
254 | d->type = Integer; |
255 | d->i = i; |
256 | d->format = fmt_Number; |
257 | } |
258 | |
259 | // create an integer value |
260 | Value::Value(int i) |
261 | : d(Private::null()) |
262 | { |
263 | d->type = Integer; |
264 | d->i = static_cast<qint64>(i); |
265 | d->format = fmt_Number; |
266 | } |
267 | |
268 | // create a floating-point value |
269 | Value::Value(double f) |
270 | : d(Private::null()) |
271 | { |
272 | d->type = Float; |
273 | d->f = Number(f); |
274 | d->format = fmt_Number; |
275 | } |
276 | |
277 | // create a floating-point value |
278 | Value::Value(long double f) |
279 | : d(Private::null()) |
280 | { |
281 | d->type = Float; |
282 | d->f = Number(f); |
283 | d->format = fmt_Number; |
284 | } |
285 | |
286 | |
287 | #ifdef CALLIGRA_SHEETS_HIGH_PRECISION_SUPPORT |
288 | // create a floating-point value |
289 | Value::Value(Number f) |
290 | : d(Private::null()) |
291 | { |
292 | d->type = Float; |
293 | d->f = f; |
294 | d->format = fmt_Number; |
295 | } |
296 | #endif // CALLIGRA_SHEETS_HIGH_PRECISION_SUPPORT |
297 | |
298 | // create a complex number value |
299 | Value::Value(const complex<Number>& c) |
300 | : d(Private::null()) |
301 | { |
302 | d->type = Complex; |
303 | d->pc = new complex<Number>(c); |
304 | d->format = fmt_Number; |
305 | } |
306 | |
307 | // create a string value |
308 | Value::Value(const QString& s) |
309 | : d(Private::null()) |
310 | { |
311 | d->type = String; |
312 | d->ps = new QString(s); |
313 | d->format = fmt_String; |
314 | } |
315 | |
316 | // create a string value |
317 | Value::Value(const char *s) |
318 | : d(Private::null()) |
319 | { |
320 | d->type = String; |
321 | d->ps = new QString(s); |
322 | d->format = fmt_String; |
323 | } |
324 | |
325 | // create a floating-point value from date/time |
326 | Value::Value(const QDateTime& dt, const CalculationSettings* settings) |
327 | : d(Private::null()) |
328 | { |
329 | const QDate refDate(settings->referenceDate()); |
330 | const QTime refTime(0, 0); // reference time is midnight |
331 | d->type = Float; |
332 | d->f = Number(refDate.daysTo(dt.date())); |
333 | d->f += static_cast<double>(refTime.msecsTo(dt.time())) / 86400000.0; // 24*60*60*1000 |
334 | d->format = fmt_DateTime; |
335 | } |
336 | |
337 | // create a floating-point value from time |
338 | Value::Value(const QTime& time, const CalculationSettings* settings) |
339 | : d(Private::null()) |
340 | { |
341 | Q_UNUSED(settings); |
342 | const QTime refTime(0, 0); // reference time is midnight |
343 | |
344 | d->type = Float; |
345 | d->f = Number(static_cast<double>(refTime.msecsTo(time)) / 86400000.0); // 24*60*60*1000 |
346 | d->format = fmt_Time; |
347 | } |
348 | |
349 | // create a floating-point value from date |
350 | Value::Value(const QDate& date, const CalculationSettings* settings) |
351 | : d(Private::null()) |
352 | { |
353 | const QDate refDate(settings->referenceDate()); |
354 | |
355 | d->type = Integer; |
356 | d->i = refDate.daysTo(date); |
357 | d->format = fmt_Date; |
358 | } |
359 | |
360 | // create an array value |
361 | Value::Value(const ValueStorage& array, const QSize& size) |
362 | : d(Private::null()) |
363 | { |
364 | d->type = Array; |
365 | d->pa = new ValueArray(array, size); |
366 | d->format = fmt_None; |
367 | } |
368 | |
369 | // return type of the value |
370 | Value::Type Value::type() const |
371 | { |
372 | return d ? d->type : Empty; |
373 | } |
374 | |
375 | bool Value::isNull() const |
376 | { |
377 | return d ? d->type == Empty && d->b : false; |
378 | } |
379 | |
380 | // get the value as boolean |
381 | bool Value::asBoolean() const |
382 | { |
383 | bool result = false; |
384 | |
385 | if (type() == Value::Boolean) |
386 | result = d->b; |
387 | |
388 | return result; |
389 | } |
390 | |
391 | // get the value as integer |
392 | qint64 Value::asInteger() const |
393 | { |
394 | qint64 result = 0; |
395 | if (type() == Integer) |
396 | result = d->i; |
397 | else if (type() == Float) |
398 | result = static_cast<qint64>(floor(numToDouble(d->f))); |
399 | else if (type() == Complex) |
400 | result = static_cast<qint64>(floor(numToDouble(d->pc->real()))); |
401 | return result; |
402 | } |
403 | |
404 | // get the value as floating-point |
405 | Number Value::asFloat() const |
406 | { |
407 | Number result = 0.0; |
408 | if (type() == Float) |
409 | result = d->f; |
410 | else if (type() == Integer) |
411 | result = static_cast<Number>(d->i); |
412 | else if (type() == Complex) |
413 | result = d->pc->real(); |
414 | return result; |
415 | } |
416 | |
417 | // get the value as complex number |
418 | complex<Number> Value::asComplex() const |
419 | { |
420 | complex<Number> result(0.0, 0.0); |
421 | if (type() == Complex) |
422 | result = *d->pc; |
423 | else if (type() == Float) |
424 | result = d->f; |
425 | else if (type() == Integer) |
426 | result = static_cast<Number>(d->i); |
427 | return result; |
428 | } |
429 | |
430 | // get the value as string |
431 | QString Value::asString() const |
432 | { |
433 | QString result; |
434 | |
435 | if (type() == Value::String) |
436 | if (d->ps) |
437 | result = QString(*d->ps); |
438 | |
439 | return result; |
440 | } |
441 | |
442 | QString Value::asStringWithDoubleQuotes() const |
443 | { |
444 | QString s = asString(); |
445 | if (type() == Value::String) { |
446 | if (!(s.startsWith("\"" ) && s.endsWith("\"" ))) { |
447 | if (s.startsWith("'" ) && s.endsWith("'" )) |
448 | s = s.mid(1, s.length()-2); |
449 | s = "\"" + s + "\"" ; |
450 | } |
451 | } |
452 | return s; |
453 | } |
454 | |
455 | // get the value as QVariant |
456 | QVariant Value::asVariant() const |
457 | { |
458 | QVariant result; |
459 | |
460 | switch (d->type) { |
461 | case Value::Empty: |
462 | default: |
463 | result = 0; |
464 | break; |
465 | case Value::Boolean: |
466 | result = d->b; |
467 | break; |
468 | case Value::Integer: |
469 | result = d->i; |
470 | break; |
471 | case Value::Float: |
472 | result = (double) numToDouble(d->f); |
473 | break; |
474 | case Value::Complex: |
475 | // FIXME: add support for complex numbers |
476 | // pc = new complex<Number>( *o.pc ); |
477 | break; |
478 | case Value::String: |
479 | case Value::Error: |
480 | result = *d->ps; |
481 | break; |
482 | case Value::Array: |
483 | // FIXME: not supported yet |
484 | //result = ValueArray( d->pa ); |
485 | break; |
486 | } |
487 | |
488 | return result; |
489 | } |
490 | |
491 | // set error message |
492 | void Value::setError(const QString& msg) |
493 | { |
494 | d->clear(); |
495 | d->type = Error; |
496 | d->ps = new QString(msg); |
497 | } |
498 | |
499 | // get error message |
500 | QString Value::errorMessage() const |
501 | { |
502 | QString result; |
503 | |
504 | if (type() == Value::Error) |
505 | if (d->ps) |
506 | result = QString(*d->ps); |
507 | |
508 | return result; |
509 | } |
510 | |
511 | // get the value as date/time |
512 | QDateTime Value::asDateTime(const CalculationSettings* settings) const |
513 | { |
514 | QDateTime datetime(settings->referenceDate(), QTime(), Qt::UTC); |
515 | |
516 | const int days = asInteger(); |
517 | const int msecs = qRound((numToDouble(asFloat() - double(days))) * 86400000.0); // 24*60*60*1000 |
518 | datetime = datetime.addDays(days); |
519 | datetime = datetime.addMSecs(msecs); |
520 | |
521 | return datetime; |
522 | } |
523 | |
524 | // get the value as date |
525 | QDate Value::asDate(const CalculationSettings* settings) const |
526 | { |
527 | QDate dt(settings->referenceDate()); |
528 | |
529 | int i = asInteger(); |
530 | dt = dt.addDays(i); |
531 | |
532 | return dt; |
533 | } |
534 | |
535 | // get the value as time |
536 | QTime Value::asTime(const CalculationSettings* settings) const |
537 | { |
538 | Q_UNUSED(settings); |
539 | QTime dt; |
540 | |
541 | const int days = asInteger(); |
542 | const int msecs = qRound(numToDouble(asFloat() - double(days)) * 86400000.0); // 24*60*60*1000 |
543 | dt = dt.addMSecs(msecs); |
544 | |
545 | return dt; |
546 | } |
547 | |
548 | Value::Format Value::format() const |
549 | { |
550 | return d ? d->format : fmt_None; |
551 | } |
552 | |
553 | void Value::setFormat(Value::Format fmt) |
554 | { |
555 | d->format = fmt; |
556 | } |
557 | |
558 | Value Value::element(unsigned column, unsigned row) const |
559 | { |
560 | if (d->type != Array) return *this; |
561 | if (!d->pa) return empty(); |
562 | return d->pa->storage().lookup(column + 1, row + 1); |
563 | } |
564 | |
565 | Value Value::element(unsigned index) const |
566 | { |
567 | if (d->type != Array) return *this; |
568 | if (!d->pa) return empty(); |
569 | return d->pa->storage().data(index); |
570 | } |
571 | |
572 | void Value::setElement(unsigned column, unsigned row, const Value& v) |
573 | { |
574 | if (d->type != Array) return; |
575 | if (!d->pa) d->pa = new ValueArray(); |
576 | d->pa->storage().insert(column + 1, row + 1, v); |
577 | } |
578 | |
579 | unsigned Value::columns() const |
580 | { |
581 | if (d->type != Array) return 1; |
582 | if (!d->pa) return 1; |
583 | return d->pa->columns(); |
584 | } |
585 | |
586 | unsigned Value::rows() const |
587 | { |
588 | if (d->type != Array) return 1; |
589 | if (!d->pa) return 1; |
590 | return d->pa->rows(); |
591 | } |
592 | |
593 | unsigned Value::count() const |
594 | { |
595 | if (d->type != Array) return 1; |
596 | if (!d->pa) return 1; |
597 | return d->pa->storage().count(); |
598 | } |
599 | |
600 | // reference to empty value |
601 | const Value& Value::empty() |
602 | { |
603 | return ks_value_empty; |
604 | } |
605 | |
606 | // reference to null value |
607 | const Value& Value::null() |
608 | { |
609 | if (!ks_value_null.isNull()) |
610 | ks_value_null.d->b = true; |
611 | return ks_value_null; |
612 | } |
613 | |
614 | // reference to #CIRCLE! error |
615 | const Value& Value::errorCIRCLE() |
616 | { |
617 | if (!ks_error_circle.isError()) |
618 | ks_error_circle.setError(i18nc("Error: circular formula dependency" , "#CIRCLE!" )); |
619 | return ks_error_circle; |
620 | } |
621 | |
622 | // reference to #DEPEND! error |
623 | const Value& Value::errorDEPEND() |
624 | { |
625 | if (!ks_error_depend.isError()) |
626 | ks_error_depend.setError(i18nc("Error: broken cell reference" , "#DEPEND!" )); |
627 | return ks_error_depend; |
628 | } |
629 | |
630 | // reference to #DIV/0! error |
631 | const Value& Value::errorDIV0() |
632 | { |
633 | if (!ks_error_div0.isError()) |
634 | ks_error_div0.setError(i18nc("Error: division by zero" , "#DIV/0!" )); |
635 | return ks_error_div0; |
636 | } |
637 | |
638 | // reference to #N/A error |
639 | const Value& Value::errorNA() |
640 | { |
641 | if (!ks_error_na.isError()) |
642 | ks_error_na.setError(i18nc("Error: not available" , "#N/A" )); |
643 | return ks_error_na; |
644 | } |
645 | |
646 | // reference to #NAME? error |
647 | const Value& Value::errorNAME() |
648 | { |
649 | if (!ks_error_name.isError()) |
650 | ks_error_name.setError(i18nc("Error: unknown function name" , "#NAME?" )); |
651 | return ks_error_name; |
652 | } |
653 | |
654 | // reference to #NUM! error |
655 | const Value& Value::errorNUM() |
656 | { |
657 | if (!ks_error_num.isError()) |
658 | ks_error_num.setError(i18nc("Error: number out of range" , "#NUM!" )); |
659 | return ks_error_num; |
660 | } |
661 | |
662 | // reference to #NULL! error |
663 | const Value& Value::errorNULL() |
664 | { |
665 | if (!ks_error_null.isError()) |
666 | ks_error_null.setError(i18nc("Error: empty intersecting area" , "#NULL!" )); |
667 | return ks_error_null; |
668 | } |
669 | |
670 | // reference to #PARSE! error |
671 | const Value& Value::errorPARSE() |
672 | { |
673 | if (!ks_error_parse.isError()) |
674 | ks_error_parse.setError(i18nc("Error: formula not parseable" , "#PARSE!" )); |
675 | return ks_error_parse; |
676 | } |
677 | |
678 | // reference to #REF! error |
679 | const Value& Value::errorREF() |
680 | { |
681 | if (!ks_error_ref.isError()) |
682 | ks_error_ref.setError(i18nc("Error: invalid cell/array reference" , "#REF!" )); |
683 | return ks_error_ref; |
684 | } |
685 | |
686 | // reference to #VALUE! error |
687 | const Value& Value::errorVALUE() |
688 | { |
689 | if (!ks_error_value.isError()) |
690 | ks_error_value.setError(i18nc("Error: wrong (number of) function argument(s)" , "#VALUE!" )); |
691 | return ks_error_value; |
692 | } |
693 | |
694 | int Value::compare(Number v1, Number v2) |
695 | { |
696 | Number v3 = v1 - v2; |
697 | if (v3 > DBL_EPSILON) return 1; |
698 | if (v3 < -DBL_EPSILON) return -1; |
699 | return 0; |
700 | } |
701 | |
702 | bool Value::isZero(Number v) |
703 | { |
704 | return abs(v) < DBL_EPSILON; |
705 | } |
706 | |
707 | bool Value::isZero() const |
708 | { |
709 | if (!isNumber()) return false; |
710 | return isZero(asFloat()); |
711 | } |
712 | |
713 | bool Value::allowComparison(const Value& v) const |
714 | { |
715 | Value::Type t1 = d->type; |
716 | Value::Type t2 = v.type(); |
717 | |
718 | if ((t1 == Empty) && (t2 == Empty)) return true; |
719 | if ((t1 == Empty) && (t2 == String)) return true; |
720 | if ((t1 == Empty) && (t2 == Integer)) return true; |
721 | if ((t1 == Empty) && (t2 == Float)) return true; |
722 | if ((t1 == Empty) && (t2 == Boolean)) return true; |
723 | |
724 | if ((t1 == Boolean) && (t2 == Boolean)) return true; |
725 | if ((t1 == Boolean) && (t2 == Integer)) return true; |
726 | if ((t1 == Boolean) && (t2 == Float)) return true; |
727 | if ((t1 == Boolean) && (t2 == String)) return true; |
728 | |
729 | if ((t1 == Integer) && (t2 == Boolean)) return true; |
730 | if ((t1 == Integer) && (t2 == Integer)) return true; |
731 | if ((t1 == Integer) && (t2 == Float)) return true; |
732 | if ((t1 == Integer) && (t2 == String)) return true; |
733 | |
734 | if ((t1 == Float) && (t2 == Boolean)) return true; |
735 | if ((t1 == Float) && (t2 == Integer)) return true; |
736 | if ((t1 == Float) && (t2 == Float)) return true; |
737 | if ((t1 == Float) && (t2 == String)) return true; |
738 | |
739 | if ((t1 == Complex) && (t2 == Boolean)) return true; |
740 | if ((t1 == Complex) && (t2 == Integer)) return true; |
741 | if ((t1 == Complex) && (t2 == Float)) return true; |
742 | if ((t1 == Complex) && (t2 == String)) return true; |
743 | |
744 | if ((t1 == String) && (t2 == Empty)) return true; |
745 | if ((t1 == String) && (t2 == Boolean)) return true; |
746 | if ((t1 == String) && (t2 == Integer)) return true; |
747 | if ((t1 == String) && (t2 == Float)) return true; |
748 | if ((t1 == String) && (t2 == Complex)) return true; |
749 | if ((t1 == String) && (t2 == String)) return true; |
750 | |
751 | // errors can be compared too ... |
752 | if ((t1 == Error) && (t2 == Error)) return true; |
753 | |
754 | return false; |
755 | } |
756 | |
757 | // compare values. looks strange in order to be compatible with Excel |
758 | int Value::compare(const Value& v, Qt::CaseSensitivity cs) const |
759 | { |
760 | Value::Type t1 = d->type; |
761 | Value::Type t2 = v.type(); |
762 | |
763 | // errors always less than everything else |
764 | if ((t1 == Error) && (t2 != Error)) |
765 | return -1; |
766 | if ((t2 == Error) && (t1 != Error)) |
767 | return 1; |
768 | |
769 | // comparing errors only yields 0 if they are the same |
770 | if ((t1 == Error) && (t2 == Error)) |
771 | return errorMessage() != v.errorMessage(); |
772 | |
773 | // empty == empty |
774 | if ((t1 == Empty) && (t2 == Empty)) |
775 | return 0; |
776 | |
777 | // empty value is always less than string |
778 | // (except when the string is empty) |
779 | if ((t1 == Empty) && (t2 == String)) |
780 | return(v.asString().isEmpty()) ? 0 : -1; |
781 | |
782 | // empty vs integer |
783 | if ((t1 == Empty) && (t2 == Integer)) |
784 | return -1; |
785 | |
786 | // empty vs float |
787 | if ((t1 == Empty) && (t2 == Float)) |
788 | return -1; |
789 | |
790 | // empty vs boolean |
791 | if ((t1 == Empty) && (t2 == Boolean)) |
792 | return -1; |
793 | |
794 | // boolean vs boolean |
795 | if ((t1 == Boolean) && (t2 == Boolean)) { |
796 | bool p = asBoolean(); |
797 | bool q = v.asBoolean(); |
798 | if (p) return q ? 0 : 1; |
799 | else return q ? -1 : 0; |
800 | } |
801 | |
802 | // boolean is always greater than integer |
803 | if ((t1 == Boolean) && (t2 == Integer)) |
804 | return 1; |
805 | |
806 | // boolean is always greater than float |
807 | if ((t1 == Boolean) && (t2 == Float)) |
808 | return 1; |
809 | |
810 | // boolean is always greater than string |
811 | if ((t1 == Boolean) && (t2 == String)) |
812 | return 1; |
813 | |
814 | // integer is always less than boolean |
815 | if ((t1 == Integer) && (t2 == Boolean)) |
816 | return -1; |
817 | |
818 | // integer vs integer |
819 | if ((t1 == Integer) && (t2 == Integer)) { |
820 | qint64 p = asInteger(); |
821 | qint64 q = v.asInteger(); |
822 | return (p == q) ? 0 : (p < q) ? -1 : 1; |
823 | } |
824 | |
825 | // integer vs float |
826 | if ((t1 == Integer) && (t2 == Float)) |
827 | return compare(asFloat(), v.asFloat()); |
828 | |
829 | // integer is always less than string |
830 | if ((t1 == Integer) && (t2 == String)) |
831 | return -1; |
832 | |
833 | // float is always less than boolean |
834 | if ((t1 == Float) && (t2 == Boolean)) |
835 | return -1; |
836 | |
837 | // float vs integer |
838 | if ((t1 == Float) && (t2 == Integer)) |
839 | return compare(asFloat(), v.asFloat()); |
840 | |
841 | // float vs float |
842 | if ((t1 == Float) && (t2 == Float)) |
843 | return compare(asFloat(), v.asFloat()); |
844 | |
845 | // float is always less than string |
846 | if ((t1 == Float) && (t2 == String)) |
847 | return -1; |
848 | |
849 | // TODO Stefan: Complex |
850 | |
851 | // string is always greater than empty value |
852 | // (except when the string is empty) |
853 | if ((t1 == String) && (t2 == Empty)) |
854 | return(asString().isEmpty()) ? 0 : 1; |
855 | |
856 | // string is always less than boolean |
857 | if ((t1 == String) && (t2 == Boolean)) |
858 | return -1; |
859 | |
860 | // string is always greater than integer |
861 | if ((t1 == String) && (t2 == Integer)) |
862 | return 1; |
863 | |
864 | // string is always greater than float |
865 | if ((t1 == String) && (t2 == Float)) |
866 | return 1; |
867 | |
868 | // The-Real-String comparison |
869 | if ((t1 == String) && (t2 == String)) |
870 | return asString().compare(v.asString(), cs); |
871 | |
872 | // Undefined, actually allowComparison would return false |
873 | return 0; |
874 | } |
875 | |
876 | bool Value::equal(const Value& v, Qt::CaseSensitivity cs) const |
877 | { |
878 | if (!allowComparison(v)) return false; |
879 | return compare(v, cs) == 0; |
880 | } |
881 | |
882 | bool Value::less(const Value& v, Qt::CaseSensitivity cs) const |
883 | { |
884 | if (!allowComparison(v)) return false; |
885 | return compare(v, cs) < 0; |
886 | } |
887 | |
888 | bool Value::greater(const Value& v, Qt::CaseSensitivity cs) const |
889 | { |
890 | if (!allowComparison(v)) return false; |
891 | return compare(v, cs) > 0; |
892 | } |
893 | |
894 | QTextStream& operator<<(QTextStream& ts, Value::Type type) |
895 | { |
896 | switch (type) { |
897 | case Value::Empty: ts << "Empty" ; break; |
898 | case Value::Boolean: ts << "Boolean" ; break; |
899 | case Value::Integer: ts << "Integer" ; break; |
900 | case Value::Float: ts << "Float" ; break; |
901 | case Value::Complex: ts << "Complex" ; break; |
902 | case Value::String: ts << "String" ; break; |
903 | case Value::Array: ts << "Array" ; break; |
904 | case Value::Error: ts << "Error" ; break; |
905 | default: ts << "Unknown!" ; break; |
906 | }; |
907 | return ts; |
908 | } |
909 | |
910 | QTextStream& operator<<(QTextStream& ts, Value value) |
911 | { |
912 | ts << value.type(); |
913 | switch (value.type()) { |
914 | case Value::Empty: break; |
915 | |
916 | case Value::Boolean: |
917 | ts << ": " ; |
918 | if (value.asBoolean()) ts << "TRUE" ; |
919 | else ts << "FALSE" ; break; |
920 | |
921 | case Value::Integer: |
922 | ts << ": " << value.asInteger(); break; |
923 | |
924 | case Value::Float: |
925 | ts << ": " << (double) numToDouble(value.asFloat()); break; |
926 | |
927 | case Value::Complex: { |
928 | const complex<Number> complex(value.asComplex()); |
929 | ts << ": " << (double) numToDouble(complex.real()); |
930 | if (complex.imag() >= 0.0) |
931 | ts << '+'; |
932 | ts << (double) numToDouble(complex.imag()) << 'i'; |
933 | break; |
934 | } |
935 | |
936 | case Value::String: |
937 | ts << ": " << value.asString(); break; |
938 | |
939 | case Value::Array: { |
940 | ts << ": {" << value.asString(); |
941 | const int cols = value.columns(); |
942 | const int rows = value.rows(); |
943 | for (int row = 0; row < rows; ++row) { |
944 | for (int col = 0; col < cols; ++col) { |
945 | ts << value.element(col, row); |
946 | if (col < cols - 1) |
947 | ts << ';'; |
948 | } |
949 | if (row < rows - 1) |
950 | ts << '|'; |
951 | } |
952 | ts << '}'; |
953 | break; |
954 | } |
955 | |
956 | case Value::Error: |
957 | ts << '(' << value.errorMessage() << ')'; break; |
958 | |
959 | default: break; |
960 | } |
961 | return ts; |
962 | } |
963 | |
964 | /*************************************************************************** |
965 | QHash/QSet support |
966 | ****************************************************************************/ |
967 | |
968 | namespace Calligra |
969 | { |
970 | namespace Sheets |
971 | { |
972 | uint qHash(const Value& value) |
973 | { |
974 | switch (value.type()) { |
975 | case Value::Empty: |
976 | case Value::CellRange: |
977 | return 0; |
978 | case Value::Boolean: |
979 | return ::qHash(value.asBoolean()); |
980 | case Value::Integer: |
981 | return ::qHash(value.asInteger()); |
982 | case Value::Float: |
983 | return ::qHash((qint64)numToDouble(value.asFloat())); |
984 | case Value::Complex: |
985 | return ::qHash((qint64)value.asComplex().real()); |
986 | case Value::String: |
987 | return ::qHash(value.asString()); |
988 | case Value::Array: |
989 | return qHash(value.element(0, 0)); |
990 | case Value::Error: |
991 | return ::qHash(value.errorMessage()); |
992 | } |
993 | return 0; |
994 | } |
995 | } // namespace Sheets |
996 | } // namespace Calligra |
997 | |
998 | /*************************************************************************** |
999 | kDebug support |
1000 | ****************************************************************************/ |
1001 | |
1002 | QDebug operator<<(QDebug str, const Calligra::Sheets::Value& v) |
1003 | { |
1004 | QString string; |
1005 | QTextStream stream(&string); |
1006 | stream << v; |
1007 | str << string; |
1008 | return str; |
1009 | } |
1010 | |
1011 | QDebug operator<<(QDebug stream, const Calligra::Sheets::Value::Format& f) |
1012 | { |
1013 | switch (f) { |
1014 | case Calligra::Sheets::Value::fmt_None: stream << "None" ; break; |
1015 | case Calligra::Sheets::Value::fmt_Boolean: stream << "Boolean" ; break; |
1016 | case Calligra::Sheets::Value::fmt_Number: stream << "Number" ; break; |
1017 | case Calligra::Sheets::Value::fmt_Percent: stream << "Percent" ; break; |
1018 | case Calligra::Sheets::Value::fmt_Money: stream << "Money" ; break; |
1019 | case Calligra::Sheets::Value::fmt_DateTime: stream << "DateTime" ; break; |
1020 | case Calligra::Sheets::Value::fmt_Date: stream << "Date" ; break; |
1021 | case Calligra::Sheets::Value::fmt_Time: stream << "Time" ; break; |
1022 | case Calligra::Sheets::Value::fmt_String: stream << "String" ; break; |
1023 | } |
1024 | return stream; |
1025 | } |
1026 | |