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 ( 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 d->format = fmt;
00627 }
00628
00629 Value Value::element( unsigned column, unsigned row ) const
00630 {
00631 if( d->type != Array ) return *this;
00632 if( !d->pa ) return *this;
00633 Value* v = d->pa->at (column % columns(), row % rows());
00634 return v ? Value( *v ) : empty();
00635 }
00636
00637 void Value::setElement( unsigned column, unsigned row, const Value& v )
00638 {
00639 if( d->type != Array ) return;
00640 if( !d->pa ) return;
00641 detach();
00642 d->pa->set( column, row, new Value( v ) );
00643 }
00644
00645 unsigned Value::columns() const
00646 {
00647 if( d->type != Array ) return 1;
00648 if( !d->pa ) return 1;
00649 return d->pa->columns;
00650 }
00651
00652 unsigned Value::rows() const
00653 {
00654 if( d->type != Array ) return 1;
00655 if( !d->pa ) return 1;
00656 return d->pa->rows;
00657 }
00658
00659
00660 const Value& Value::empty()
00661 {
00662 return ks_value_empty;
00663 }
00664
00665
00666 const Value& Value::errorDIV0()
00667 {
00668 if( !ks_error_div0.isError() )
00669 ks_error_div0.setError( "#DIV/0!" );
00670 return ks_error_div0;
00671 }
00672
00673
00674 const Value& Value::errorNA()
00675 {
00676 if( !ks_error_na.isError() )
00677 ks_error_na.setError( "#N/A" );
00678 return ks_error_na;
00679 }
00680
00681
00682 const Value& Value::errorNAME()
00683 {
00684 if( !ks_error_name.isError() )
00685 ks_error_name.setError( "#NAME?" );
00686 return ks_error_name;
00687 }
00688
00689
00690 const Value& Value::errorNUM()
00691 {
00692 if( !ks_error_num.isError() )
00693 ks_error_num.setError( "#NUM!" );
00694 return ks_error_num;
00695 }
00696
00697
00698 const Value& Value::errorNULL()
00699 {
00700 if( !ks_error_null.isError() )
00701 ks_error_null.setError( "#NULL!" );
00702 return ks_error_null;
00703 }
00704
00705
00706 const Value& Value::errorREF()
00707 {
00708 if( !ks_error_ref.isError() )
00709 ks_error_ref.setError( "#REF!" );
00710 return ks_error_ref;
00711 }
00712
00713
00714 const Value& Value::errorVALUE()
00715 {
00716 if( !ks_error_value.isError() )
00717 ks_error_value.setError( "#VALUE!" );
00718 return ks_error_value;
00719 }
00720
00721
00722 void Value::detach()
00723 {
00724 if( d->isNull() || ( d->count > 1 ) )
00725 {
00726 ValueData* n;
00727 n = new ValueData;
00728
00729 n->type = d->type;
00730 switch( n->type )
00731 {
00732 case Empty: break;
00733 case Boolean: n->b = d->b; break;
00734 case Integer: n->i = d->i; break;
00735 case Float: n->f = d->f; break;
00736 case String: n->ps = new QString( *d->ps ); break;
00737 case Array: n->pa = new ValueArray; *n->pa = (*d->pa); break;
00738 case Error: n->ps = new QString( *d->ps ); break;
00739 default: break;
00740 }
00741
00742 d->unref();
00743 d = n;
00744 }
00745 }
00746
00747 int Value::compare( double v1, double v2 )
00748 {
00749 double v3 = v1 - v2;
00750 if( v3 > DBL_EPSILON ) return 1;
00751 if( v3 < -DBL_EPSILON ) return -1;
00752 return 0;
00753 }
00754
00755 bool Value::isZero( double v )
00756 {
00757 return fabs( v ) < DBL_EPSILON;
00758 }
00759
00760 bool Value::isZero() const
00761 {
00762 if( !isNumber() ) return false;
00763 return isZero( asFloat() );
00764 }
00765
00766 bool Value::allowComparison( const Value& v ) const
00767 {
00768 Value::Type t1 = d->type;
00769 Value::Type t2 = v.type();
00770
00771 if( ( t1 == Empty ) && ( t2 == Empty ) ) return true;
00772 if( ( t1 == Empty ) && ( t2 == String ) ) return true;
00773
00774 if( ( t1 == Boolean ) && ( t2 == Boolean ) ) return true;
00775 if( ( t1 == Boolean ) && ( t2 == Integer ) ) return true;
00776 if( ( t1 == Boolean ) && ( t2 == Float ) ) return true;
00777 if( ( t1 == Boolean ) && ( t2 == String ) ) return true;
00778
00779 if( ( t1 == Integer ) && ( t2 == Boolean ) ) return true;
00780 if( ( t1 == Integer ) && ( t2 == Integer ) ) return true;
00781 if( ( t1 == Integer ) && ( t2 == Float ) ) return true;
00782 if( ( t1 == Integer ) && ( t2 == String ) ) return true;
00783
00784 if( ( t1 == Float ) && ( t2 == Boolean ) ) return true;
00785 if( ( t1 == Float ) && ( t2 == Integer ) ) return true;
00786 if( ( t1 == Float ) && ( t2 == Float ) ) return true;
00787 if( ( t1 == Float ) && ( t2 == String ) ) return true;
00788
00789 if( ( t1 == String ) && ( t2 == Empty ) ) return true;
00790 if( ( t1 == String ) && ( t2 == Boolean ) ) return true;
00791 if( ( t1 == String ) && ( t2 == Integer ) ) return true;
00792 if( ( t1 == String ) && ( t2 == Float ) ) return true;
00793 if( ( t1 == String ) && ( t2 == String ) ) return true;
00794
00795
00796 if ((t1 == Error) && (t2 == Error)) return true;
00797
00798 return false;
00799 }
00800
00801
00802 int Value::compare( const Value& v ) const
00803 {
00804 Value::Type t1 = d->type;
00805 Value::Type t2 = v.type();
00806
00807
00808 if( ( t1 == Error ) && ( t2 != Error ) )
00809 return -1;
00810 if( ( t2 == Error ) && ( t1 != Error ) )
00811 return 1;
00812
00813
00814 if( ( t1 == Error ) && ( t2 == Error ) )
00815 return errorMessage() != v.errorMessage();
00816
00817
00818 if( ( t1 == Empty ) && ( t2 == Empty ) )
00819 return 0;
00820
00821
00822
00823 if( ( t1 == Empty ) && ( t2 == String ) )
00824 return( v.asString().isEmpty() ) ? 0 : -1;
00825
00826
00827 if( ( t1 == Boolean ) && ( t2 == Boolean ) )
00828 {
00829 bool p = asBoolean();
00830 bool q = v.asBoolean();
00831 if( p ) return q ? 0 : 1;
00832 else return q ? -1 : 0;
00833 }
00834
00835
00836 if( ( t1 == Boolean ) && ( t2 == Integer ) )
00837 return 1;
00838
00839
00840 if( ( t1 == Boolean ) && ( t2 == Float ) )
00841 return 1;
00842
00843
00844 if( ( t1 == Boolean ) && ( t2 == String ) )
00845 return 1;
00846
00847
00848 if( ( t1 == Integer ) && ( t2 == Boolean ) )
00849 return -1;
00850
00851
00852 if( ( t1 == Integer ) && ( t2 == Integer ) )
00853 {
00854 long p = asInteger();
00855 long q = v.asInteger();
00856 return ( p == q ) ? 0 : ( p < q ) ? -1 : 1;
00857 }
00858
00859
00860 if( ( t1 == Integer ) && ( t2 == Float ) )
00861 return compare( asFloat(), v.asFloat() );
00862
00863
00864 if( ( t1 == Integer ) && ( t2 == String ) )
00865 return -1;
00866
00867
00868 if( ( t1 == Float ) && ( t2 == Boolean ) )
00869 return -1;
00870
00871
00872 if( ( t1 == Float ) && ( t2 == Integer ) )
00873 return compare( asFloat(), v.asFloat() );
00874
00875
00876 if( ( t1 == Float ) && ( t2 == Float ) )
00877 return compare( asFloat(), v.asFloat() );
00878
00879
00880 if( ( t1 == Float ) && ( t2 == String ) )
00881 return -1;
00882
00883
00884
00885 if( ( t1 == String ) && ( t2 == Empty ) )
00886 return( asString().isEmpty() ) ? 0 : 1;
00887
00888
00889 if( ( t1 == String ) && ( t2 == Boolean ) )
00890 return -1;
00891
00892
00893 if( ( t1 == String ) && ( t2 == Integer ) )
00894 return 1;
00895
00896
00897 if( ( t1 == String ) && ( t2 == Float ) )
00898 return 1;
00899
00900
00901 if( ( t1 == String ) && ( t2 == String ) )
00902 return asString().compare( v.asString() );
00903
00904
00905 return 0;
00906 }
00907
00908 bool Value::equal( const Value& v ) const
00909 {
00910 if (!allowComparison (v)) return false;
00911 return compare( v ) == 0;
00912 }
00913
00914 bool Value::less( const Value& v ) const
00915 {
00916 if (!allowComparison (v)) return false;
00917 return compare( v ) < 0;
00918 }
00919
00920 bool Value::greater( const Value& v ) const
00921 {
00922 if (!allowComparison (v)) return false;
00923 return compare( v ) > 0;
00924 }
00925
00926 QTextStream& operator<<( QTextStream& ts, Value::Type type )
00927 {
00928 switch( type )
00929 {
00930 case Value::Empty: ts << "Empty"; break;
00931 case Value::Boolean: ts << "Boolean"; break;
00932 case Value::Integer: ts << "Integer"; break;
00933 case Value::Float: ts << "Float"; break;
00934 case Value::String: ts << "String"; break;
00935 case Value::Array: ts << "Array"; break;
00936 case Value::Error: ts << "Error"; break;
00937 default: ts << "Unknown!"; break;
00938 };
00939 return ts;
00940 }
00941
00942 QTextStream& operator<<( QTextStream& ts, Value value )
00943 {
00944 ts << value.type();
00945 switch( value.type() )
00946 {
00947 case Value::Empty: break;
00948
00949 case Value::Boolean:
00950 ts << ": ";
00951 if (value.asBoolean()) ts << "TRUE";
00952 else ts << "FALSE"; break;
00953
00954 case Value::Integer:
00955 ts << ": " << value.asInteger(); break;
00956
00957 case Value::Float:
00958 ts << ": " << value.asFloat(); break;
00959
00960 case Value::String:
00961 ts << ": " << value.asString(); break;
00962
00963 case Value::Error:
00964 ts << "(" << value.errorMessage() << ")"; break;
00965
00966 default: break;
00967 }
00968 return ts;
00969 }