00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kspread_value.h"
00021
00022 #include <kdebug.h>
00023
00024 #include <qstring.h>
00025 #include <qtextstream.h>
00026
00027 #include <float.h>
00028 #include <math.h>
00029 #include <limits.h>
00030
00031 using namespace KSpread;
00032
00033
00034
00035
00036 struct arrayChunk {
00037 arrayChunk (int c, int r) {
00038 cols = c; rows = r;
00039 ptr = new Value* [c*r];
00040 for (int i = 0; i < c*r; ++i) ptr[i] = 0;
00041 }
00042
00043 ~arrayChunk () {
00044 if (!ptr) return;
00045 unsigned count = cols * rows;
00046 for (unsigned i = 0; i < count; i++)
00047 delete ptr[i];
00048 delete [] ptr;
00049 }
00050
00051 arrayChunk( const arrayChunk& ac )
00052 {
00053 operator=( ac );
00054 }
00055
00056 arrayChunk& operator= ( const arrayChunk& ac )
00057 {
00058 cols = ac.cols; rows = ac.rows;
00059 ptr = new Value* [cols*rows];
00060 unsigned count = cols * rows;
00061 for( unsigned i = 0; i < count; i++ )
00062 if( ac.ptr[i] )
00063 ptr[i] = new Value( *ac.ptr[i] );
00064 else
00065 ptr[i] = 0;
00066 return *this;
00067 }
00068
00069 Value **ptr;
00070 unsigned cols, rows;
00071 };
00072
00073 #define CHUNK_COLS 128
00074 #define CHUNK_ROWS 128
00075
00076 class ValueArray
00077 {
00078 public:
00079 arrayChunk **chunks;
00080 unsigned columns;
00081 unsigned rows;
00082 unsigned chunkCols, chunkRows;
00083
00084 ValueArray(): chunks(0), columns(0), rows(0), chunkCols(0), chunkRows(0) {};
00085
00086 ~ValueArray()
00087 {
00088 clear();
00089 };
00090
00091 ValueArray( const ValueArray& va )
00092 : chunks(0), columns(0), rows(0), chunkCols(0), chunkRows(0)
00093 {
00094 operator=( va );
00095 }
00096
00097 ValueArray& operator= ( const ValueArray& va )
00098 {
00099 init( va.columns, va.rows );
00100 unsigned count = chunkCols * chunkRows;
00101 for( unsigned i = 0; i < count; i++ )
00102 if( va.chunks[i] )
00103 chunks[i] = new arrayChunk (*va.chunks[i]);
00104 else
00105 chunks[i] = 0;
00106 return *this;
00107 }
00108
00109 void clear()
00110 {
00111 int c = columns / CHUNK_COLS;
00112 int r = rows / CHUNK_ROWS;
00113 if (columns % CHUNK_COLS != 0) c++;
00114 if (rows % CHUNK_ROWS != 0) r++;
00115 if( !chunks ) return;
00116 unsigned count = c*r;
00117 if( !count ) return;
00118 for (unsigned i = 0; i < count; i++)
00119 delete chunks[i];
00120 delete [] chunks;
00121 chunks = 0;
00122 columns = rows = chunkCols = chunkRows = 0;
00123 }
00124
00125 void init( unsigned c, unsigned r )
00126 {
00127 if (chunks) clear();
00128 columns = c; rows = r;
00129 int cc = columns / CHUNK_COLS;
00130 int rr = rows / CHUNK_ROWS;
00131 if (columns % CHUNK_COLS != 0) cc++;
00132 if (rows % CHUNK_ROWS != 0) rr++;
00133 chunkCols = cc;
00134 chunkRows = rr;
00135 unsigned count = cc*rr;
00136 chunks = new arrayChunk* [count];
00137 for( unsigned i = 0; i < count; i++ )
00138 chunks[i] = 0;
00139 }
00140
00141 Value* at( unsigned c, unsigned r ) const
00142 {
00143 if( !chunks ) return 0;
00144 if( c >= columns ) return 0;
00145 if( r >= rows ) return 0;
00146
00147 int col = c / CHUNK_COLS;
00148 int row = r / CHUNK_ROWS;
00149 int cpos = c % CHUNK_COLS;
00150 int rpos = r % CHUNK_ROWS;
00151 arrayChunk *chunk = chunks[row * chunkCols + col];
00152 if (!chunk) return 0;
00153 return chunk->ptr[rpos * chunk->cols + cpos];
00154 };
00155
00156 void set( unsigned c, unsigned r, Value* v )
00157 {
00158 if (!chunks) return;
00159 if( c >= columns ) return;
00160 if( r >= rows ) return;
00161 unsigned col = c / CHUNK_COLS;
00162 unsigned row = r / CHUNK_ROWS;
00163 unsigned cpos = c % CHUNK_COLS;
00164 unsigned rpos = r % CHUNK_ROWS;
00165 arrayChunk *chunk = chunks[row * chunkCols + col];
00166 if (!chunk) {
00167 unsigned cc = (col==chunkCols-1) ? (columns % CHUNK_COLS) : CHUNK_COLS;
00168 unsigned rr = (row==chunkRows-1) ? (rows % CHUNK_ROWS) : CHUNK_ROWS;
00169 chunk = new arrayChunk (cc, rr);
00170 chunks[row * chunkCols + col] = chunk;
00171 }
00172 delete chunk->ptr[rpos * chunk->cols + cpos];
00173 chunk->ptr[rpos * chunk->cols + cpos] = v;
00174 }
00175
00176 bool operator==( const ValueArray& other ) const
00177 {
00178 if ( columns != other.columns || rows != other.rows )
00179 return false;
00180 for ( unsigned r = 0; r < rows; ++r )
00181 for ( unsigned c = 0; c < columns; ++c ) {
00182 Value* v1 = at( c, r );
00183 Value* v2 = other.at( c, r );
00184 if ( ( v1 && !v2 ) || ( !v1 && v2 ) )
00185 return false;
00186 if ( !( v1 && v2 && *v1 == *v2 ) )
00187 return false;
00188 }
00189 return true;
00190 }
00191
00192 };
00193
00194
00195
00196 class KSpread::ValueData
00197 {
00198 public:
00199
00200 Value::Type type:4;
00201 Value::Format format:4;
00202
00203
00204 unsigned int count:24;
00205
00206 union
00207 {
00208 bool b;
00209 long i;
00210 double f;
00211 QString* ps;
00212 ValueArray* pa;
00213 };
00214
00215
00216 ValueData(): type( Value::Empty ),
00217 format (Value::fmt_None), count( 1 ), ps( 0 ) { };
00218
00219
00220 ~ValueData(){ if( this == s_null ) s_null = 0;
00221 if( type == Value::Array ) delete pa;
00222 if( type == Value::String ) delete ps;
00223 if( type == Value::Error ) delete ps;
00224 }
00225
00226
00227 static ValueData* null()
00228 { if( !s_null) s_null = new ValueData; else s_null->ref(); return s_null; }
00229
00230
00231 void ref() { count++; }
00232
00233
00234 void unref()
00235 { --count; if( !count ) delete this; }
00236
00237
00238 bool isNull(){ return this == s_null; }
00239
00241 void setFormatByType ();
00242
00243 private:
00244
00245 static ValueData* s_null;
00246 };
00247
00248 void KSpread::ValueData::setFormatByType ()
00249 {
00250 switch (type) {
00251 case Value::Empty:
00252 format = Value::fmt_None;
00253 break;
00254 case Value::Boolean:
00255 format = Value::fmt_Boolean;
00256 break;
00257 case Value::Integer:
00258 format = Value::fmt_Number;
00259 break;
00260 case Value::Float:
00261 format = Value::fmt_Number;
00262 break;
00263 case Value::String:
00264 format = Value::fmt_String;
00265 break;
00266 case Value::Array:
00267 format = Value::fmt_None;
00268 break;
00269 case Value::CellRange:
00270 format = Value::fmt_None;
00271 break;
00272 case Value::Error:
00273 format = Value::fmt_String;
00274 break;
00275 };
00276 }
00277
00278
00279 ValueData* ValueData::s_null = 0;
00280
00281
00282 Value ks_value_empty;
00283 Value ks_error_div0;
00284 Value ks_error_na;
00285 Value ks_error_name;
00286 Value ks_error_null;
00287 Value ks_error_num;
00288 Value ks_error_ref;
00289 Value ks_error_value;
00290
00291
00292 Value::Value()
00293 {
00294 d = ValueData::null();
00295 }
00296
00297
00298 Value::~Value()
00299 {
00300 d->unref();
00301 }
00302
00303
00304 Value::Value( Value::Type _type )
00305 {
00306 d = new ValueData;
00307 d->type = _type;
00308 d->setFormatByType ();
00309 }
00310
00311
00312 Value::Value( const Value& _value )
00313 {
00314 d = ValueData::null();
00315 assign( _value );
00316 }
00317
00318
00319 Value& Value::operator=( const Value& _value )
00320 {
00321 return assign( _value );
00322 }
00323
00324
00325 bool Value::operator==( const Value& v ) const
00326 {
00327 const ValueData* n = v.d;
00328 if ( (uint)d->type != n->type )
00329 return false;
00330 switch( d->type )
00331 {
00332 case Empty: return true;
00333 case Boolean: return n->b == d->b;
00334 case Integer: return n->i == d->i;
00335 case Float: return compare( n->f, d->f ) == 0;
00336 case String: return *n->ps == *d->ps;
00337 case Array: return *n->pa == *d->pa;
00338 case Error: return *n->ps == *d->ps;
00339 default: break;
00340 }
00341 kdWarning() << "Unhandled type in Value::operator==: " << d->type << endl;
00342 return false;
00343 }
00344
00345
00346 Value::Value( bool b )
00347 {
00348 d = ValueData::null();
00349 setValue( b );
00350 }
00351
00352
00353 Value::Value( long i )
00354 {
00355 d = ValueData::null();
00356 setValue ( i );
00357 }
00358
00359
00360 Value::Value( int i )
00361 {
00362 d = ValueData::null();
00363 setValue ( i );
00364 }
00365
00366
00367 Value::Value( double f )
00368 {
00369 d = ValueData::null();
00370 setValue( f );
00371 }
00372
00373
00374 Value::Value( const QString& s )
00375 {
00376 d = ValueData::null();
00377 setValue( s );
00378 }
00379
00380
00381 Value::Value (const char *s)
00382 {
00383 d = ValueData::null();
00384 setValue (QString (s));
00385 }
00386
00387
00388 Value::Value( const QDateTime& dt )
00389 {
00390 d = ValueData::null();
00391 setValue( dt );
00392 }
00393
00394
00395 Value::Value( const QTime& dt )
00396 {
00397 d = ValueData::null();
00398 setValue( dt );
00399 }
00400
00401
00402 Value::Value( const QDate& dt )
00403 {
00404 d = ValueData::null();
00405 setValue( dt );
00406 }
00407
00408
00409 Value::Value( unsigned columns, unsigned rows )
00410 {
00411 d = new ValueData;
00412 d->type = Array;
00413 d->format = fmt_None;
00414 d->pa = new ValueArray;
00415 d->pa->init( columns, rows );
00416 }
00417
00418
00419
00420 Value& Value::assign( const Value& _value )
00421 {
00422 d->unref();
00423 d = _value.d;
00424 d->ref();
00425 return *this;
00426 }
00427
00428
00429 Value::Type Value::type() const
00430 {
00431 return d ? d->type : Empty;
00432 }
00433
00434
00435 void Value::setValue( bool b )
00436 {
00437 detach();
00438 d->type = Boolean;
00439 d->b = b;
00440 d->format = fmt_Boolean;
00441 }
00442
00443
00444 bool Value::asBoolean() const
00445 {
00446 bool result = false;
00447
00448 if( type() == Value::Boolean )
00449 result = d->b;
00450
00451 return result;
00452 }
00453
00454
00455 void Value::setValue( long i )
00456 {
00457 detach();
00458 d->type = Integer;
00459 d->i = i;
00460 d->format = fmt_Number;
00461 }
00462
00463
00464 void Value::setValue( int i )
00465 {
00466 detach();
00467 d->type = Integer;
00468 d->i = static_cast<long>( i );
00469 d->format = fmt_Number;
00470 }
00471
00472
00473 long Value::asInteger() const
00474 {
00475 long result = 0;
00476
00477 if( type() == Value::Integer )
00478 result = d->i;
00479
00480 if( type() == Value::Float )
00481 result = static_cast<int>(d->f);
00482
00483 return result;
00484 }
00485
00486 void Value::setValue( const Value& v )
00487 {
00488 assign( v );
00489 }
00490
00491
00492 void Value::setValue( double f )
00493 {
00494 detach();
00495 d->type = Float;
00496 d->f = f;
00497 d->format = fmt_Number;
00498 }
00499
00500
00501 double Value::asFloat() const
00502 {
00503 double result = 0.0;
00504
00505 if( type() == Value::Float )
00506 result = d->f;
00507
00508 if( type() == Value::Integer )
00509 result = static_cast<double>(d->i);
00510
00511 return result;
00512 }
00513
00514
00515 void Value::setValue( const QString& s )
00516 {
00517 detach();
00518 d->type = String;
00519 d->ps = new QString( s );
00520 d->format = fmt_String;
00521 }
00522
00523
00524 QString Value::asString() const
00525 {
00526 QString result;
00527
00528 if( type() == Value::String )
00529 if( d->ps )
00530 result = QString( *d->ps );
00531
00532 return result;
00533 }
00534
00535
00536 void Value::setError( const QString& msg )
00537 {
00538 detach();
00539 d->type = Error;
00540 d->ps = new QString( msg );
00541 }
00542
00543
00544 QString Value::errorMessage() const
00545 {
00546 QString result;
00547
00548 if( type() == Value::Error )
00549 if( d->ps )
00550 result = QString( *d->ps );
00551
00552 return result;
00553 }
00554
00555
00556
00557
00558 void Value::setValue( const QDateTime& dt )
00559 {
00560
00561 QDate refDate( 1899, 12, 31 );
00562 QTime refTime( 0, 0 );
00563
00564 int i = refDate.daysTo( dt.date() ) + 1;
00565 i += refTime.secsTo( dt.time() ) / 86400;
00566
00567 setValue( i );
00568 d->format = fmt_DateTime;
00569 }
00570
00571 void Value::setValue( const QTime& time )
00572 {
00573
00574 QTime refTime( 0, 0 );
00575 int i = refTime.msecsTo( time ) ;
00576
00577 setValue( i );
00578 d->format = fmt_Time;
00579 }
00580
00581 void Value::setValue( const QDate& date )
00582 {
00583
00584 QDate refDate = QDate( 1899, 12, 31 );
00585 int i = refDate.daysTo( date ) + 1;
00586
00587 setValue( i );
00588 d->format = fmt_Date;
00589 }
00590
00591
00592 QDateTime Value::asDateTime() const
00593 {
00594 return QDateTime( asDate(), asTime() );
00595 }
00596
00597
00598 QDate Value::asDate() const
00599 {
00600 QDate dt( 1899, 12, 30 );
00601
00602 int i = asInteger();
00603 dt = dt.addDays( i );
00604
00605 return dt;
00606 }
00607
00608
00609 QTime Value::asTime() const
00610 {
00611 QTime dt;
00612
00613 int i = asInteger();
00614 dt = dt.addMSecs(i) ;
00615
00616 return dt;
00617 }
00618
00619 Value::Format Value::format() const
00620 {
00621 return d ? d->format : fmt_None;
00622 }
00623
00624 void Value::setFormat (Value::Format fmt)
00625 {
00626 detach();
00627 d->format = fmt;
00628 }
00629
00630 Value Value::element( unsigned column, unsigned row ) const
00631 {
00632 if( (uint)d->type != Array ) return *this;
00633 if( !d->pa ) return *this;
00634 Value* v = d->pa->at (column % columns(), row % rows());
00635 return v ? Value( *v ) : empty();
00636 }
00637
00638 void Value::setElement( unsigned column, unsigned row, const Value& v )
00639 {
00640 if( (uint)d->type != Array ) return;
00641 if( !d->pa ) return;
00642 detach();
00643 d->pa->set( column, row, new Value( v ) );
00644 }
00645
00646 unsigned Value::columns() const
00647 {
00648 if( (uint)d->type != Array ) return 1;
00649 if( !d->pa ) return 1;
00650 return d->pa->columns;
00651 }
00652
00653 unsigned Value::rows() const
00654 {
00655 if( (uint)d->type != Array ) return 1;
00656 if( !d->pa ) return 1;
00657 return d->pa->rows;
00658 }
00659
00660
00661 const Value& Value::empty()
00662 {
00663 return ks_value_empty;
00664 }
00665
00666
00667 const Value& Value::errorDIV0()
00668 {
00669 if( !ks_error_div0.isError() )
00670 ks_error_div0.setError( "#DIV/0!" );
00671 return ks_error_div0;
00672 }
00673
00674
00675 const Value& Value::errorNA()
00676 {
00677 if( !ks_error_na.isError() )
00678 ks_error_na.setError( "#N/A" );
00679 return ks_error_na;
00680 }
00681
00682
00683 const Value& Value::errorNAME()
00684 {
00685 if( !ks_error_name.isError() )
00686 ks_error_name.setError( "#NAME?" );
00687 return ks_error_name;
00688 }
00689
00690
00691 const Value& Value::errorNUM()
00692 {
00693 if( !ks_error_num.isError() )
00694 ks_error_num.setError( "#NUM!" );
00695 return ks_error_num;
00696 }
00697
00698
00699 const Value& Value::errorNULL()
00700 {
00701 if( !ks_error_null.isError() )
00702 ks_error_null.setError( "#NULL!" );
00703 return ks_error_null;
00704 }
00705
00706
00707 const Value& Value::errorREF()
00708 {
00709 if( !ks_error_ref.isError() )
00710 ks_error_ref.setError( "#REF!" );
00711 return ks_error_ref;
00712 }
00713
00714
00715 const Value& Value::errorVALUE()
00716 {
00717 if( !ks_error_value.isError() )
00718 ks_error_value.setError( "#VALUE!" );
00719 return ks_error_value;
00720 }
00721
00722
00723 void Value::detach()
00724 {
00725 if( d->isNull() || ( d->count > 1 ) )
00726 {
00727 ValueData* n;
00728 n = new ValueData;
00729
00730 n->type = d->type;
00731 switch( n->type )
00732 {
00733 case Empty: break;
00734 case Boolean: n->b = d->b; break;
00735 case Integer: n->i = d->i; break;
00736 case Float: n->f = d->f; break;
00737 case String: n->ps = new QString( *d->ps ); break;
00738 case Array: n->pa = new ValueArray; *n->pa = (*d->pa); break;
00739 case Error: n->ps = new QString( *d->ps ); break;
00740 default: break;
00741 }
00742
00743 d->unref();
00744 d = n;
00745 }
00746 }
00747
00748 int Value::compare( double v1, double v2 )
00749 {
00750 double v3 = v1 - v2;
00751 if( v3 > DBL_EPSILON ) return 1;
00752 if( v3 < -DBL_EPSILON ) return -1;
00753 return 0;
00754 }
00755
00756 bool Value::isZero( double v )
00757 {
00758 return fabs( v ) < DBL_EPSILON;
00759 }
00760
00761 bool Value::isZero() const
00762 {
00763 if( !isNumber() ) return false;
00764 return isZero( asFloat() );
00765 }
00766
00767 bool Value::allowComparison( const Value& v ) const
00768 {
00769 Value::Type t1 = d->type;
00770 Value::Type t2 = v.type();
00771
00772 if( ( t1 == Empty ) && ( t2 == Empty ) ) return true;
00773 if( ( t1 == Empty ) && ( t2 == String ) ) return true;
00774
00775 if( ( t1 == Boolean ) && ( t2 == Boolean ) ) return true;
00776 if( ( t1 == Boolean ) && ( t2 == Integer ) ) return true;
00777 if( ( t1 == Boolean ) && ( t2 == Float ) ) return true;
00778 if( ( t1 == Boolean ) && ( t2 == String ) ) return true;
00779
00780 if( ( t1 == Integer ) && ( t2 == Boolean ) ) return true;
00781 if( ( t1 == Integer ) && ( t2 == Integer ) ) return true;
00782 if( ( t1 == Integer ) && ( t2 == Float ) ) return true;
00783 if( ( t1 == Integer ) && ( t2 == String ) ) return true;
00784
00785 if( ( t1 == Float ) && ( t2 == Boolean ) ) return true;
00786 if( ( t1 == Float ) && ( t2 == Integer ) ) return true;
00787 if( ( t1 == Float ) && ( t2 == Float ) ) return true;
00788 if( ( t1 == Float ) && ( t2 == String ) ) return true;
00789
00790 if( ( t1 == String ) && ( t2 == Empty ) ) return true;
00791 if( ( t1 == String ) && ( t2 == Boolean ) ) return true;
00792 if( ( t1 == String ) && ( t2 == Integer ) ) return true;
00793 if( ( t1 == String ) && ( t2 == Float ) ) return true;
00794 if( ( t1 == String ) && ( t2 == String ) ) return true;
00795
00796
00797 if ((t1 == Error) && (t2 == Error)) return true;
00798
00799 return false;
00800 }
00801
00802
00803 int Value::compare( const Value& v ) const
00804 {
00805 Value::Type t1 = d->type;
00806 Value::Type t2 = v.type();
00807
00808
00809 if( ( t1 == Error ) && ( t2 != Error ) )
00810 return -1;
00811 if( ( t2 == Error ) && ( t1 != Error ) )
00812 return 1;
00813
00814
00815 if( ( t1 == Error ) && ( t2 == Error ) )
00816 return errorMessage() != v.errorMessage();
00817
00818
00819 if( ( t1 == Empty ) && ( t2 == Empty ) )
00820 return 0;
00821
00822
00823
00824 if( ( t1 == Empty ) && ( t2 == String ) )
00825 return( v.asString().isEmpty() ) ? 0 : -1;
00826
00827
00828 if( ( t1 == Boolean ) && ( t2 == Boolean ) )
00829 {
00830 bool p = asBoolean();
00831 bool q = v.asBoolean();
00832 if( p ) return q ? 0 : 1;
00833 else return q ? -1 : 0;
00834 }
00835
00836
00837 if( ( t1 == Boolean ) && ( t2 == Integer ) )
00838 return 1;
00839
00840
00841 if( ( t1 == Boolean ) && ( t2 == Float ) )
00842 return 1;
00843
00844
00845 if( ( t1 == Boolean ) && ( t2 == String ) )
00846 return 1;
00847
00848
00849 if( ( t1 == Integer ) && ( t2 == Boolean ) )
00850 return -1;
00851
00852
00853 if( ( t1 == Integer ) && ( t2 == Integer ) )
00854 {
00855 long p = asInteger();
00856 long q = v.asInteger();
00857 return ( p == q ) ? 0 : ( p < q ) ? -1 : 1;
00858 }
00859
00860
00861 if( ( t1 == Integer ) && ( t2 == Float ) )
00862 return compare( asFloat(), v.asFloat() );
00863
00864
00865 if( ( t1 == Integer ) && ( t2 == String ) )
00866 return -1;
00867
00868
00869 if( ( t1 == Float ) && ( t2 == Boolean ) )
00870 return -1;
00871
00872
00873 if( ( t1 == Float ) && ( t2 == Integer ) )
00874 return compare( asFloat(), v.asFloat() );
00875
00876
00877 if( ( t1 == Float ) && ( t2 == Float ) )
00878 return compare( asFloat(), v.asFloat() );
00879
00880
00881 if( ( t1 == Float ) && ( t2 == String ) )
00882 return -1;
00883
00884
00885
00886 if( ( t1 == String ) && ( t2 == Empty ) )
00887 return( asString().isEmpty() ) ? 0 : 1;
00888
00889
00890 if( ( t1 == String ) && ( t2 == Boolean ) )
00891 return -1;
00892
00893
00894 if( ( t1 == String ) && ( t2 == Integer ) )
00895 return 1;
00896
00897
00898 if( ( t1 == String ) && ( t2 == Float ) )
00899 return 1;
00900
00901
00902 if( ( t1 == String ) && ( t2 == String ) )
00903 return asString().compare( v.asString() );
00904
00905
00906 return 0;
00907 }
00908
00909 bool Value::equal( const Value& v ) const
00910 {
00911 if (!allowComparison (v)) return false;
00912 return compare( v ) == 0;
00913 }
00914
00915 bool Value::less( const Value& v ) const
00916 {
00917 if (!allowComparison (v)) return false;
00918 return compare( v ) < 0;
00919 }
00920
00921 bool Value::greater( const Value& v ) const
00922 {
00923 if (!allowComparison (v)) return false;
00924 return compare( v ) > 0;
00925 }
00926
00927 QTextStream& operator<<( QTextStream& ts, Value::Type type )
00928 {
00929 switch( type )
00930 {
00931 case Value::Empty: ts << "Empty"; break;
00932 case Value::Boolean: ts << "Boolean"; break;
00933 case Value::Integer: ts << "Integer"; break;
00934 case Value::Float: ts << "Float"; break;
00935 case Value::String: ts << "String"; break;
00936 case Value::Array: ts << "Array"; break;
00937 case Value::Error: ts << "Error"; break;
00938 default: ts << "Unknown!"; break;
00939 };
00940 return ts;
00941 }
00942
00943 QTextStream& operator<<( QTextStream& ts, Value value )
00944 {
00945 ts << value.type();
00946 switch( value.type() )
00947 {
00948 case Value::Empty: break;
00949
00950 case Value::Boolean:
00951 ts << ": ";
00952 if (value.asBoolean()) ts << "TRUE";
00953 else ts << "FALSE"; break;
00954
00955 case Value::Integer:
00956 ts << ": " << value.asInteger(); break;
00957
00958 case Value::Float:
00959 ts << ": " << value.asFloat(); break;
00960
00961 case Value::String:
00962 ts << ": " << value.asString(); break;
00963
00964 case Value::Error:
00965 ts << "(" << value.errorMessage() << ")"; break;
00966
00967 default: break;
00968 }
00969 return ts;
00970 }