kspread

kspread_value.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>
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.
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#include "kspread_value.h"
21
22#include <kdebug.h>
23
24#include <tqstring.h>
25#include <tqtextstream.h>
26
27#include <float.h>
28#include <math.h>
29#include <limits.h>
30
31using namespace KSpread;
32
33// helper struct for array implementation
34// this struct holds one piece of an array of size CHUNK_COLS x CHUNK_ROWS
35// or less
36struct arrayChunk {
37 arrayChunk (int c, int r) {
38 cols = c; rows = r;
39 ptr = new Value* [c*r];
40 for (int i = 0; i < c*r; ++i) ptr[i] = 0;
41 }
42
43 ~arrayChunk () {
44 if (!ptr) return;
45 unsigned count = cols * rows;
46 for (unsigned i = 0; i < count; i++)
47 delete ptr[i];
48 delete [] ptr;
49 }
50
51 arrayChunk( const arrayChunk& ac )
52 {
53 operator=( ac );
54 }
55
56 arrayChunk& operator= ( const arrayChunk& ac )
57 {
58 cols = ac.cols; rows = ac.rows;
59 ptr = new Value* [cols*rows];
60 unsigned count = cols * rows;
61 for( unsigned i = 0; i < count; i++ )
62 if( ac.ptr[i] )
63 ptr[i] = new Value( *ac.ptr[i] );
64 else
65 ptr[i] = 0;
66 return *this;
67 }
68
69 Value **ptr;
70 unsigned cols, rows;
71};
72
73#define CHUNK_COLS 128
74#define CHUNK_ROWS 128
75// helper class for array implementation
76class ValueArray
77{
78public:
79 arrayChunk **chunks;
80 unsigned columns;
81 unsigned rows;
82 unsigned chunkCols, chunkRows;
83
84 ValueArray(): chunks(0), columns(0), rows(0), chunkCols(0), chunkRows(0) {};
85
86 ~ValueArray()
87 {
88 clear();
89 };
90
91 ValueArray( const ValueArray& va )
92 : chunks(0), columns(0), rows(0), chunkCols(0), chunkRows(0)
93 {
94 operator=( va );
95 }
96
97 ValueArray& operator= ( const ValueArray& va )
98 {
99 init( va.columns, va.rows );
100 unsigned count = chunkCols * chunkRows;
101 for( unsigned i = 0; i < count; i++ )
102 if( va.chunks[i] )
103 chunks[i] = new arrayChunk (*va.chunks[i]);
104 else
105 chunks[i] = 0;
106 return *this;
107 }
108
109 void clear()
110 {
111 int c = columns / CHUNK_COLS;
112 int r = rows / CHUNK_ROWS;
113 if (columns % CHUNK_COLS != 0) c++;
114 if (rows % CHUNK_ROWS != 0) r++;
115 if( !chunks ) return;
116 unsigned count = c*r;
117 if( !count ) return;
118 for (unsigned i = 0; i < count; i++)
119 delete chunks[i];
120 delete [] chunks;
121 chunks = 0;
122 columns = rows = chunkCols = chunkRows = 0;
123 }
124
125 void init( unsigned c, unsigned r )
126 {
127 if (chunks) clear();
128 columns = c; rows = r;
129 int cc = columns / CHUNK_COLS;
130 int rr = rows / CHUNK_ROWS;
131 if (columns % CHUNK_COLS != 0) cc++;
132 if (rows % CHUNK_ROWS != 0) rr++;
133 chunkCols = cc;
134 chunkRows = rr;
135 unsigned count = cc*rr;
136 chunks = new arrayChunk* [count];
137 for( unsigned i = 0; i < count; i++ )
138 chunks[i] = 0;
139 }
140
141 Value* at( unsigned c, unsigned r ) const
142 {
143 if( !chunks ) return 0;
144 if( c >= columns ) return 0;
145 if( r >= rows ) return 0;
146
147 int col = c / CHUNK_COLS;
148 int row = r / CHUNK_ROWS;
149 int cpos = c % CHUNK_COLS;
150 int rpos = r % CHUNK_ROWS;
151 arrayChunk *chunk = chunks[row * chunkCols + col];
152 if (!chunk) return 0;
153 return chunk->ptr[rpos * chunk->cols + cpos];
154 };
155
156 void set( unsigned c, unsigned r, Value* v )
157 {
158 if (!chunks) return;
159 if( c >= columns ) return;
160 if( r >= rows ) return;
161 unsigned col = c / CHUNK_COLS;
162 unsigned row = r / CHUNK_ROWS;
163 unsigned cpos = c % CHUNK_COLS;
164 unsigned rpos = r % CHUNK_ROWS;
165 arrayChunk *chunk = chunks[row * chunkCols + col];
166 if (!chunk) {
167 unsigned cc = (col==chunkCols-1) ? (columns % CHUNK_COLS) : CHUNK_COLS;
168 unsigned rr = (row==chunkRows-1) ? (rows % CHUNK_ROWS) : CHUNK_ROWS;
169 chunk = new arrayChunk (cc, rr);
170 chunks[row * chunkCols + col] = chunk;
171 }
172 delete chunk->ptr[rpos * chunk->cols + cpos];
173 chunk->ptr[rpos * chunk->cols + cpos] = v;
174 }
175
176 bool operator==( const ValueArray& other ) const
177 {
178 if ( columns != other.columns || rows != other.rows )
179 return false;
180 for ( unsigned r = 0; r < rows; ++r )
181 for ( unsigned c = 0; c < columns; ++c ) {
182 Value* v1 = at( c, r );
183 Value* v2 = other.at( c, r );
184 if ( ( v1 && !v2 ) || ( !v1 && v2 ) )
185 return false;
186 if ( !( v1 && v2 && *v1 == *v2 ) )
187 return false;
188 }
189 return true;
190 }
191
192};
193
194
195// helper class for Value
196class KSpread::ValueData
197{
198 public:
199
200 Value::Type type:4;
201 Value::Format format:4;
202
203 // reference count, at least one when object exists
204 unsigned int count:24;
205
206 union
207 {
208 bool b;
209 long i;
210 double f;
211 TQString* ps;
212 ValueArray* pa;
213 };
214
215 // create empty data
216 ValueData(): type( Value::Empty ),
217 format (Value::fmt_None), count( 1 ), ps( 0 ) { };
218
219 // destroys data
220 ~ValueData(){ if( this == s_null ) s_null = 0;
221 if( type == Value::Array ) delete pa;
222 if( type == Value::String ) delete ps;
223 if( type == Value::Error ) delete ps;
224 }
225
226 // static empty data to be shared
227 static ValueData* null()
228 { if( !s_null) s_null = new ValueData; else s_null->ref(); return s_null; }
229
230 // increase reference count
231 void ref() { count++; }
232
233 // decrease reference count
234 void unref()
235 { --count; if( !count ) delete this; }
236
237 // true if it's null (which is shared)
238 bool isNull(){ return this == s_null; }
239
241 void setFormatByType ();
242
243 private:
244
245 static ValueData* s_null;
246};
247
248void KSpread::ValueData::setFormatByType ()
249{
250 switch (type) {
251 case Value::Empty:
252 format = Value::fmt_None;
253 break;
254 case Value::Boolean:
255 format = Value::fmt_Boolean;
256 break;
257 case Value::Integer:
258 format = Value::fmt_Number;
259 break;
260 case Value::Float:
261 format = Value::fmt_Number;
262 break;
263 case Value::String:
264 format = Value::fmt_String;
265 break;
266 case Value::Array:
267 format = Value::fmt_None;
268 break;
269 case Value::CellRange:
270 format = Value::fmt_None;
271 break;
272 case Value::Error:
273 format = Value::fmt_String;
274 break;
275 };
276}
277
278// to be shared between all empty value
279ValueData* ValueData::s_null = 0;
280
281// static things
282Value ks_value_empty;
283Value ks_error_div0;
284Value ks_error_na;
285Value ks_error_name;
286Value ks_error_null;
287Value ks_error_num;
288Value ks_error_ref;
289Value ks_error_value;
290
291// create an empty value
293{
294 d = ValueData::null();
295}
296
297// destructor
299{
300 d->unref();
301}
302
303// create value of certain type
304Value::Value( Value::Type _type )
305{
306 d = new ValueData;
307 d->type = _type;
308 d->setFormatByType ();
309}
310
311// copy constructor
312Value::Value( const Value& _value )
313{
314 d = ValueData::null();
315 assign( _value );
316}
317
318// assignment operator
319Value& Value::operator=( const Value& _value )
320{
321 return assign( _value );
322}
323
324// comparison operator - returns true only if strictly identical, unlike equal()/compare()
325bool Value::operator==( const Value& v ) const
326{
327 const ValueData* n = v.d;
328 if ( (uint)d->type != n->type )
329 return false;
330 switch( d->type )
331 {
332 case Empty: return true;
333 case Boolean: return n->b == d->b;
334 case Integer: return n->i == d->i;
335 case Float: return compare( n->f, d->f ) == 0;
336 case String: return *n->ps == *d->ps;
337 case Array: return *n->pa == *d->pa;
338 case Error: return *n->ps == *d->ps;
339 default: break;
340 }
341 kdWarning() << "Unhandled type in Value::operator==: " << d->type << endl;
342 return false;
343}
344
345// create a boolean value
347{
348 d = ValueData::null();
349 setValue( b );
350}
351
352// create an integer value
354{
355 d = ValueData::null();
356 setValue ( i );
357}
358
359// create an integer value
361{
362 d = ValueData::null();
363 setValue ( i );
364}
365
366// create a floating-point value
367Value::Value( double f )
368{
369 d = ValueData::null();
370 setValue( f );
371}
372
373// create a string value
374Value::Value( const TQString& s )
375{
376 d = ValueData::null();
377 setValue( s );
378}
379
380// create a string value
381Value::Value (const char *s)
382{
383 d = ValueData::null();
384 setValue (TQString (s));
385}
386
387// create a floating-point value from date/time
388Value::Value( const TQDateTime& dt )
389{
390 d = ValueData::null();
391 setValue( dt );
392}
393
394// create a floating-point value from time
395Value::Value( const TQTime& dt )
396{
397 d = ValueData::null();
398 setValue( dt );
399}
400
401// create a floating-point value from date
402Value::Value( const TQDate& dt )
403{
404 d = ValueData::null();
405 setValue( dt );
406}
407
408// create an array value
409Value::Value( unsigned columns, unsigned rows )
410{
411 d = new ValueData;
412 d->type = Array;
413 d->format = fmt_None;
414 d->pa = new ValueArray;
415 d->pa->init( columns, rows );
416}
417
418// assign value from other
419// shallow copy: only copy the data pointer
420Value& Value::assign( const Value& _value )
421{
422 d->unref();
423 d = _value.d;
424 d->ref();
425 return *this;
426}
427
428// return type of the value
429Value::Type Value::type() const
430{
431 return d ? d->type : Empty;
432}
433
434// set the value to boolean
435void Value::setValue( bool b )
436{
437 detach();
438 d->type = Boolean;
439 d->b = b;
440 d->format = fmt_Boolean;
441}
442
443// get the value as boolean
445{
446 bool result = false;
447
448 if( type() == Value::Boolean )
449 result = d->b;
450
451 return result;
452}
453
454// set the value to integer
455void Value::setValue( long i )
456{
457 detach();
458 d->type = Integer;
459 d->i = i;
460 d->format = fmt_Number;
461}
462
463// set the value to integer
464void Value::setValue( int i )
465{
466 detach();
467 d->type = Integer;
468 d->i = static_cast<long>( i );
469 d->format = fmt_Number;
470}
471
472// get the value as integer
474{
475 long result = 0;
476
477 if( type() == Value::Integer )
478 result = d->i;
479
480 if( type() == Value::Float )
481 result = static_cast<long>(d->f);
482
483 return result;
484}
485
486void Value::setValue( const Value& v )
487{
488 assign( v );
489}
490
491// set the value as floating-point
492void Value::setValue( double f )
493{
494 detach();
495 d->type = Float;
496 d->f = f;
497 d->format = fmt_Number;
498}
499
500// get the value as floating-point
501double Value::asFloat() const
502{
503 double result = 0.0;
504
505 if( type() == Value::Float )
506 result = d->f;
507
508 if( type() == Value::Integer )
509 result = static_cast<double>(d->i);
510
511 return result;
512}
513
514// set the value as string
515void Value::setValue( const TQString& s )
516{
517 detach();
518 d->type = String;
519 d->ps = new TQString( s );
520 d->format = fmt_String;
521}
522
523// get the value as string
524TQString Value::asString() const
525{
526 TQString result;
527
528 if( type() == Value::String )
529 if( d->ps )
530 result = TQString( *d->ps );
531
532 return result;
533}
534
535// set error message
536void Value::setError( const TQString& msg )
537{
538 detach();
539 d->type = Error;
540 d->ps = new TQString( msg );
541}
542
543// get error message
544TQString Value::errorMessage() const
545{
546 TQString result;
547
548 if( type() == Value::Error )
549 if( d->ps )
550 result = TQString( *d->ps );
551
552 return result;
553}
554
555// set the value as date/time
556// NOTE: date/time is stored as serial number
557// Day 61 means 1st of March, 1900
558void Value::setValue( const TQDateTime& dt )
559{
560 // reference is 31 Dec, 1899 midnight
561 TQDate refDate( 1899, 12, 31 );
562 TQTime refTime( 0, 0 );
563
564 int i = refDate.daysTo( dt.date() ) + 1;
565 i += refTime.secsTo( dt.time() ) / 86400;
566
567 setValue( i );
568 d->format = fmt_DateTime;
569}
570
571void Value::setValue( const TQTime& time )
572{
573 // reference time is midnight
574 TQTime refTime( 0, 0 );
575 int i = refTime.msecsTo( time ) /* / 86400000 */;
576
577 setValue( i );
578 d->format = fmt_Time;
579}
580
581void Value::setValue( const TQDate& date )
582{
583 // reference date is 31 Dec, 1899
584 TQDate refDate = TQDate( 1899, 12, 31 );
585 int i = refDate.daysTo( date ) + 1;
586
587 setValue( i );
588 d->format = fmt_Date;
589}
590
591// get the value as date/time
592TQDateTime Value::asDateTime() const
593{
594 return TQDateTime( asDate(), asTime() );
595}
596
597// get the value as date
598TQDate Value::asDate() const
599{
600 TQDate dt( 1899, 12, 30 );
601
602 int i = asInteger();
603 dt = dt.addDays( i );
604
605 return dt;
606}
607
608// get the value as time
609TQTime Value::asTime() const
610{
611 TQTime dt;
612
613 int i = asInteger();
614 dt = dt.addMSecs(i) /*( f * 86400 * 1000 )*/;
615
616 return dt;
617}
618
619Value::Format Value::format() const
620{
621 return d ? d->format : fmt_None;
622}
623
624void Value::setFormat (Value::Format fmt)
625{
626 detach();
627 d->format = fmt;
628}
629
630Value Value::element( unsigned column, unsigned row ) const
631{
632 if( (uint)d->type != Array ) return *this;
633 if( !d->pa ) return *this;
634 Value* v = d->pa->at (column % columns(), row % rows());
635 return v ? Value( *v ) : empty();
636}
637
638void Value::setElement( unsigned column, unsigned row, const Value& v )
639{
640 if( (uint)d->type != Array ) return;
641 if( !d->pa ) return;
642 detach();
643 d->pa->set( column, row, new Value( v ) );
644}
645
646unsigned Value::columns() const
647{
648 if( (uint)d->type != Array ) return 1;
649 if( !d->pa ) return 1;
650 return d->pa->columns;
651}
652
653unsigned Value::rows() const
654{
655 if( (uint)d->type != Array ) return 1;
656 if( !d->pa ) return 1;
657 return d->pa->rows;
658}
659
660// reference to empty value
662{
663 return ks_value_empty;
664}
665
666// reference to #DIV/0! error
668{
669 if( !ks_error_div0.isError() )
670 ks_error_div0.setError( "#DIV/0!" );
671 return ks_error_div0;
672}
673
674// reference to #N/A error
676{
677 if( !ks_error_na.isError() )
678 ks_error_na.setError( "#N/A" );
679 return ks_error_na;
680}
681
682// reference to #NAME? error
684{
685 if( !ks_error_name.isError() )
686 ks_error_name.setError( "#NAME?" );
687 return ks_error_name;
688}
689
690// reference to #NUM! error
692{
693 if( !ks_error_num.isError() )
694 ks_error_num.setError( "#NUM!" );
695 return ks_error_num;
696}
697
698// reference to #NULL! error
700{
701 if( !ks_error_null.isError() )
702 ks_error_null.setError( "#NULL!" );
703 return ks_error_null;
704}
705
706// reference to #REF! error
708{
709 if( !ks_error_ref.isError() )
710 ks_error_ref.setError( "#REF!" );
711 return ks_error_ref;
712}
713
714// reference to #VALUE! error
716{
717 if( !ks_error_value.isError() )
718 ks_error_value.setError( "#VALUE!" );
719 return ks_error_value;
720}
721
722// detach, create deep copy of ValueData
724{
725 if( d->isNull() || ( d->count > 1 ) )
726 {
727 ValueData* n;
728 n = new ValueData;
729
730 n->type = d->type;
731 switch( n->type )
732 {
733 case Empty: break;
734 case Boolean: n->b = d->b; break;
735 case Integer: n->i = d->i; break;
736 case Float: n->f = d->f; break;
737 case String: n->ps = new TQString( *d->ps ); break;
738 case Array: n->pa = new ValueArray; *n->pa = (*d->pa); break;
739 case Error: n->ps = new TQString( *d->ps ); break;
740 default: break;
741 }
742
743 d->unref();
744 d = n;
745 }
746}
747
748int Value::compare( double v1, double v2 )
749{
750 double v3 = v1 - v2;
751 if( v3 > DBL_EPSILON ) return 1;
752 if( v3 < -DBL_EPSILON ) return -1;
753 return 0;
754}
755
756bool Value::isZero( double v )
757{
758 return fabs( v ) < DBL_EPSILON;
759}
760
761bool Value::isZero() const
762{
763 if( !isNumber() ) return false;
764 return isZero( asFloat() );
765}
766
767bool Value::allowComparison( const Value& v ) const
768{
769 Value::Type t1 = d->type;
770 Value::Type t2 = v.type();
771
772 if( ( t1 == Empty ) && ( t2 == Empty ) ) return true;
773 if( ( t1 == Empty ) && ( t2 == String ) ) return true;
774
775 if( ( t1 == Boolean ) && ( t2 == Boolean ) ) return true;
776 if( ( t1 == Boolean ) && ( t2 == Integer ) ) return true;
777 if( ( t1 == Boolean ) && ( t2 == Float ) ) return true;
778 if( ( t1 == Boolean ) && ( t2 == String ) ) return true;
779
780 if( ( t1 == Integer ) && ( t2 == Boolean ) ) return true;
781 if( ( t1 == Integer ) && ( t2 == Integer ) ) return true;
782 if( ( t1 == Integer ) && ( t2 == Float ) ) return true;
783 if( ( t1 == Integer ) && ( t2 == String ) ) return true;
784
785 if( ( t1 == Float ) && ( t2 == Boolean ) ) return true;
786 if( ( t1 == Float ) && ( t2 == Integer ) ) return true;
787 if( ( t1 == Float ) && ( t2 == Float ) ) return true;
788 if( ( t1 == Float ) && ( t2 == String ) ) return true;
789
790 if( ( t1 == String ) && ( t2 == Empty ) ) return true;
791 if( ( t1 == String ) && ( t2 == Boolean ) ) return true;
792 if( ( t1 == String ) && ( t2 == Integer ) ) return true;
793 if( ( t1 == String ) && ( t2 == Float ) ) return true;
794 if( ( t1 == String ) && ( t2 == String ) ) return true;
795
796 // errors can be compared too ...
797 if ((t1 == Error) && (t2 == Error)) return true;
798
799 return false;
800}
801
802// compare values. looks strange in order to be compatible with Excel
803int Value::compare( const Value& v ) const
804{
805 Value::Type t1 = d->type;
806 Value::Type t2 = v.type();
807
808 // errors always less than everything else
809 if( ( t1 == Error ) && ( t2 != Error ) )
810 return -1;
811 if( ( t2 == Error ) && ( t1 != Error ) )
812 return 1;
813
814 // comparing errors only yields 0 if they are the same
815 if( ( t1 == Error ) && ( t2 == Error ) )
816 return errorMessage() != v.errorMessage();
817
818 // empty == empty
819 if( ( t1 == Empty ) && ( t2 == Empty ) )
820 return 0;
821
822 // empty value is always less than string
823 // (except when the string is empty)
824 if( ( t1 == Empty ) && ( t2 == String ) )
825 return( v.asString().isEmpty() ) ? 0 : -1;
826
827 // boolean vs boolean
828 if( ( t1 == Boolean ) && ( t2 == Boolean ) )
829 {
830 bool p = asBoolean();
831 bool q = v.asBoolean();
832 if( p ) return q ? 0 : 1;
833 else return q ? -1 : 0;
834 }
835
836 // boolean is always greater than integer
837 if( ( t1 == Boolean ) && ( t2 == Integer ) )
838 return 1;
839
840 // boolean is always greater than float
841 if( ( t1 == Boolean ) && ( t2 == Float ) )
842 return 1;
843
844 // boolean is always greater than string
845 if( ( t1 == Boolean ) && ( t2 == String ) )
846 return 1;
847
848 // integer is always less than boolean
849 if( ( t1 == Integer ) && ( t2 == Boolean ) )
850 return -1;
851
852 // integer vs integer
853 if( ( t1 == Integer ) && ( t2 == Integer ) )
854 {
855 long p = asInteger();
856 long q = v.asInteger();
857 return ( p == q ) ? 0 : ( p < q ) ? -1 : 1;
858 }
859
860 // integer vs float
861 if( ( t1 == Integer ) && ( t2 == Float ) )
862 return compare( asFloat(), v.asFloat() );
863
864 // integer is always less than string
865 if( ( t1 == Integer ) && ( t2 == String ) )
866 return -1;
867
868 // float is always less than boolean
869 if( ( t1 == Float ) && ( t2 == Boolean ) )
870 return -1;
871
872 // float vs integer
873 if( ( t1 == Float ) && ( t2 == Integer ) )
874 return compare( asFloat(), v.asFloat() );
875
876 // float vs float
877 if( ( t1 == Float ) && ( t2 == Float ) )
878 return compare( asFloat(), v.asFloat() );
879
880 // float is always less than string
881 if( ( t1 == Float ) && ( t2 == String ) )
882 return -1;
883
884 // string is always greater than empty value
885 // (except when the string is empty)
886 if( ( t1 == String ) && ( t2 == Empty ) )
887 return( asString().isEmpty() ) ? 0 : 1;
888
889 // string is always less than boolean
890 if( ( t1 == String ) && ( t2 == Boolean ) )
891 return -1;
892
893 // string is always greater than integer
894 if( ( t1 == String ) && ( t2 == Integer ) )
895 return 1;
896
897 // string is always greater than float
898 if( ( t1 == String ) && ( t2 == Float ) )
899 return 1;
900
901 // The-Real-String comparison
902 if( ( t1 == String ) && ( t2 == String ) )
903 return asString().compare( v.asString() );
904
905 // Undefined, actually allowComparison would return false
906 return 0;
907}
908
909bool Value::equal( const Value& v ) const
910{
911 if (!allowComparison (v)) return false;
912 return compare( v ) == 0;
913}
914
915bool Value::less( const Value& v ) const
916{
917 if (!allowComparison (v)) return false;
918 return compare( v ) < 0;
919}
920
921bool Value::greater( const Value& v ) const
922{
923 if (!allowComparison (v)) return false;
924 return compare( v ) > 0;
925}
926
927TQTextStream& operator<<( TQTextStream& ts, Value::Type type )
928{
929 switch( type )
930 {
931 case Value::Empty: ts << "Empty"; break;
932 case Value::Boolean: ts << "Boolean"; break;
933 case Value::Integer: ts << "Integer"; break;
934 case Value::Float: ts << "Float"; break;
935 case Value::String: ts << "String"; break;
936 case Value::Array: ts << "Array"; break;
937 case Value::Error: ts << "Error"; break;
938 default: ts << "Unknown!"; break;
939 };
940 return ts;
941}
942
943TQTextStream& operator<<( TQTextStream& ts, Value value )
944{
945 ts << value.type();
946 switch( value.type() )
947 {
948 case Value::Empty: break;
949
950 case Value::Boolean:
951 ts << ": ";
952 if (value.asBoolean()) ts << "TRUE";
953 else ts << "FALSE"; break;
954
955 case Value::Integer:
956 ts << ": " << value.asInteger(); break;
957
958 case Value::Float:
959 ts << ": " << value.asFloat(); break;
960
961 case Value::String:
962 ts << ": " << value.asString(); break;
963
964 case Value::Error:
965 ts << "(" << value.errorMessage() << ")"; break;
966
967 default: break;
968 }
969 return ts;
970}
Provides a wrapper for cell value.
unsigned columns() const
If this value is an array, return the number of columns.
static const Value & empty()
Returns constant reference to empty value.
Value element(unsigned column, unsigned row) const
Return an element in the array value.
static const Value & errorDIV0()
Returns constant reference to #DIV/0! error.
void setError(const TQString &msg)
Sets this value to hold error message.
void setFormat(Format fmt)
Sets format information for this value.
bool greater(const Value &v) const
Returns true if this value is greater than v.
static const Value & errorNULL()
Returns constant reference to #NULL! error.
Format format() const
Returns the format of the value (i.e.
void setValue(const Value &v)
Sets this value to another value.
virtual ~Value()
Destroys the value.
unsigned rows() const
If this value is an array, return the number of rows.
static const Value & errorNAME()
Returns constant reference to #NAME? error.
Value & assign(const Value &_value)
Assigns from another value.
bool isEmpty() const
Returns true if empty.
bool isNumber() const
Returns true if the type of this value is either integer or floating-point.
bool equal(const Value &v) const
Returns true if this value is equal to v.
static const Value & errorNUM()
Returns constant reference to #NUM! error.
TQDate asDate() const
Returns the date representation of this value.
bool allowComparison(const Value &v) const
Returns true if it is OK to compare this value with v.
Type type() const
Returns the type of the value.
static const Value & errorREF()
Returns constant reference to #REF! error.
double asFloat() const
Returns the floating-point value of this value.
long asInteger() const
Returns the integer value of this value.
Value & operator=(const Value &_value)
Assigns from another value.
TQString errorMessage() const
Returns error message associated with this value.
TQDateTime asDateTime() const
Returns the date/time representation of this value.
TQString asString() const
Returns the string value of this value.
Value()
Creates an empty value, i.e holds nothing.
void setElement(unsigned column, unsigned row, const Value &value)
Sets an element in the array value.
static const Value & errorVALUE()
Returns constant reference to #VALUE! error.
void detach()
Detaches itself from shared value data, i.e make a private, deep copy of the data.
bool isError() const
Returns true if this value holds error information.
int compare(const Value &v) const
Returns -1, 0, 1, depends whether this value is less than, equal to, or greater than v.
bool less(const Value &v) const
Returns true if this value is less than v.
TQTime asTime() const
Returns the time representation of this value.
bool asBoolean() const
Returns the boolean value of this value.
static const Value & errorNA()
Returns constant reference to #N/A error.
The KSpread namespace.
Definition commands.h:39
TQTextStream & operator<<(TQTextStream &ts, Formula formula)
Dumps the formula, should be used only to assist debugging.