00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <ctype.h>
00030 #include <math.h>
00031
00032 #include <qdatetime.h>
00033 #include <qmap.h>
00034 #include <qstring.h>
00035
00036 #include <kcalendarsystem.h>
00037 #include <klocale.h>
00038
00039 #include "kspread_util.h"
00040 #include "kspread_value.h"
00041
00042 namespace NumFormat_Local
00043 {
00044 enum { Unknown, TimeDate, Number, Scientific, Fraction } Type;
00045
00046 QString g_Monday;
00047 QString g_Tuesday;
00048 QString g_Wednesday;
00049 QString g_Thursday;
00050 QString g_Friday;
00051 QString g_Saturday;
00052 QString g_Sunday;
00053 QString g_Mon;
00054 QString g_Tue;
00055 QString g_Wed;
00056 QString g_Thu;
00057 QString g_Fri;
00058 QString g_Sat;
00059 QString g_Sun;
00060 QString g_January;
00061 QString g_February;
00062 QString g_March;
00063 QString g_April;
00064 QString g_MayL;
00065 QString g_June;
00066 QString g_July;
00067 QString g_August;
00068 QString g_September;
00069 QString g_October;
00070 QString g_November;
00071 QString g_December;
00072 QString g_Jan;
00073 QString g_Feb;
00074 QString g_Mar;
00075 QString g_Apr;
00076 QString g_May;
00077 QString g_Jun;
00078 QString g_Jul;
00079 QString g_Aug;
00080 QString g_Sep;
00081 QString g_Oct;
00082 QString g_Nov;
00083 QString g_Dec;
00084
00085 struct DateTime
00086 {
00087 int year;
00088 int month;
00089 int day;
00090 int hour;
00091 int minute;
00092 int second;
00093 };
00094
00095 struct ConvertionInfo
00096 {
00097 DateTime * dt;
00098
00099 int rightOpt;
00100 int rightReq;
00101 int leftReq;
00102 int rightSpace;
00103 int leftSpace;
00104 int upReq;
00105
00106 int reqCounter;
00107 int reqFirst;
00108 int optFirst;
00109
00110 bool ampm;
00111
00112 bool thSet;
00113 bool showMinus;
00114 bool negRed;
00115 bool negBr;
00116 QString postfix;
00117 QString prefix;
00118 };
00119
00120 class BaseFormat
00121 {
00122 public:
00123 int type;
00124
00125 QString postfix;
00126 QString prefix;
00127 };
00128
00129 class NumberFormat : public BaseFormat
00130 {
00131 public:
00132 bool thSet;
00133 bool showMinus;
00134 bool negRed;
00135 bool negBr;
00136 int rightOpt;
00137 int rightReq;
00138 int leftReq;
00139 int rightSpace;
00140 int leftSpace;
00141 };
00142
00143 class FractionFormat : public BaseFormat
00144 {
00145 public:
00146 bool thSet;
00147 bool showMinus;
00148 bool negRed;
00149 bool negBr;
00150 int optFirst;
00151 int reqFirst;
00152 int reqCounter;
00153 int fraction;
00154 int fractionDigists;
00155 };
00156
00157 class DateTimeFormat : public BaseFormat
00158 {
00159 public:
00160 bool ampm;
00161 QString format;
00162 };
00163
00164 class ScientificFormat : public BaseFormat
00165 {
00166 public:
00167 bool thSet;
00168 int leftReq;
00169 int rightReq;
00170 int rightOpt;
00171 int upReq;
00172 bool showMinus;
00173 bool negRed;
00174 bool negBr;
00175 int rightSpace;
00176 int leftSpace;
00177 };
00178
00179 class FormatStore
00180 {
00181 public:
00182
00183 int getType( QString const & format, BaseFormat * f ) const
00184 {
00185 FormatMap::const_iterator iter = m_formats.find( format );
00186 if ( iter == m_formats.end() )
00187 {
00188 f = 0;
00189 return -1;
00190 }
00191
00192 f = iter.data();
00193 return f->type;
00194 }
00195
00196 void addFraction( QString const & format, FractionFormat * f )
00197 {
00198 m_formats.insert( format, f );
00199 }
00200
00201 void addNumber( QString const & format, NumberFormat * n )
00202 {
00203 m_formats.insert( format, n );
00204 }
00205
00206 void addDateTime( QString const & format, DateTimeFormat * d )
00207 {
00208 m_formats.insert( format, d );
00209 }
00210
00211 void addScientific( QString const & format, ScientificFormat * d )
00212 {
00213 m_formats.insert( format, d );
00214 }
00215
00216 private:
00217 class FormatMap : public QMap<QString, BaseFormat *> {};
00218 FormatMap m_formats;
00219 };
00220
00221 QChar g_dcSymbol;
00222 QChar g_thSymbol;
00223 QChar g_posSymbol;
00224 QChar g_negSymbol;
00225 DateTime g_dateTime;
00226 ConvertionInfo g_convertionInfo;
00227 bool g_init = false;
00228
00229 FormatStore g_formatStore;
00230 }
00231
00232 using namespace NumFormat_Local;
00233 using namespace KSpread;
00234
00235 void resetGlobals()
00236 {
00237 g_convertionInfo.dt = 0;
00238 g_convertionInfo.thSet = false;
00239 g_convertionInfo.showMinus = true;
00240 g_convertionInfo.negRed = false;
00241 g_convertionInfo.negBr = false;
00242 g_convertionInfo.reqCounter = 0;
00243 g_convertionInfo.reqFirst = 0;
00244 g_convertionInfo.prefix = "";
00245 g_convertionInfo.postfix = "";
00246 g_convertionInfo.rightOpt = 0;
00247 g_convertionInfo.rightReq = 0;
00248 g_convertionInfo.leftReq = 0;
00249 g_convertionInfo.rightSpace = 0;
00250 g_convertionInfo.leftSpace = 0;
00251 g_convertionInfo.optFirst = 0;
00252 g_convertionInfo.upReq = 0;
00253 g_convertionInfo.ampm = false;
00254 }
00255
00256 void initGlobals( KLocale const * const locale )
00257 {
00258 g_Monday = locale->calendar()->weekDayName( 1, false );
00259 g_Tuesday = locale->calendar()->weekDayName( 2, false );
00260 g_Wednesday = locale->calendar()->weekDayName( 3, false );
00261 g_Thursday = locale->calendar()->weekDayName( 4, false );
00262 g_Friday = locale->calendar()->weekDayName( 5, false );
00263 g_Saturday = locale->calendar()->weekDayName( 6, false );
00264 g_Sunday = locale->calendar()->weekDayName( 7, false );
00265 g_Mon = locale->calendar()->weekDayName( 1, true );
00266 g_Tue = locale->calendar()->weekDayName( 2, true );
00267 g_Wed = locale->calendar()->weekDayName( 3, true );
00268 g_Thu = locale->calendar()->weekDayName( 4, true );
00269 g_Fri = locale->calendar()->weekDayName( 5, true );
00270 g_Sat = locale->calendar()->weekDayName( 6, true );
00271 g_Sun = locale->calendar()->weekDayName( 7, true );
00272 g_January = locale->calendar()->monthName( 1, 2005, false );
00273 g_February = locale->calendar()->monthName( 2, 2005, false );
00274 g_March = locale->calendar()->monthName( 3, 2005, false );
00275 g_April = locale->calendar()->monthName( 4, 2005, false );
00276 g_MayL = locale->calendar()->monthName( 5, 2005, false );
00277 g_June = locale->calendar()->monthName( 6, 2005, false );
00278 g_July = locale->calendar()->monthName( 7, 2005, false );
00279 g_August = locale->calendar()->monthName( 8, 2005, false );
00280 g_September = locale->calendar()->monthName( 9, 2005, false );
00281 g_October = locale->calendar()->monthName( 10, 2005, false );
00282 g_November = locale->calendar()->monthName( 11, 2005, false );
00283 g_December = locale->calendar()->monthName( 12, 2005, false );
00284 g_Jan = locale->calendar()->monthName( 1, 2005, true );
00285 g_Feb = locale->calendar()->monthName( 2, 2005, true );
00286 g_Mar = locale->calendar()->monthName( 3, 2005, true );
00287 g_Apr = locale->calendar()->monthName( 4, 2005, true );
00288 g_May = locale->calendar()->monthName( 5, 2005, true );
00289 g_Jun = locale->calendar()->monthName( 6, 2005, true );
00290 g_Jul = locale->calendar()->monthName( 7, 2005, true );
00291 g_Aug = locale->calendar()->monthName( 8, 2005, true );
00292 g_Sep = locale->calendar()->monthName( 9, 2005, true );
00293 g_Oct = locale->calendar()->monthName( 10, 2005, true );
00294 g_Nov = locale->calendar()->monthName( 11, 2005, true );
00295 g_Dec = locale->calendar()->monthName( 12, 2005, true );
00296
00297 g_dcSymbol = locale->decimalSymbol()[0];
00298 g_thSymbol = locale->thousandsSeparator()[0];
00299 g_posSymbol = locale->positiveSign()[0];
00300 g_negSymbol = locale->negativeSign()[0];
00301
00302 g_init = true;
00303 }
00304
00305 void convertDateTime( Value const & value )
00306 {
00307 QDateTime dt( value.asDateTime() );
00308 QDate d( dt.date() );
00309 QTime t( dt.time() );
00310
00311 g_dateTime.year = d.year();
00312 g_dateTime.month = d.month();
00313 g_dateTime.day = d.day();
00314 g_dateTime.hour = t.hour();
00315 g_dateTime.minute = t.minute();
00316 g_dateTime.second = t.second();
00317
00318 g_convertionInfo.dt = &g_dateTime;
00319 }
00320
00321 void parseNegativePart( QString & format, int i,
00322 int l, bool acceptDigits )
00323 {
00324 g_convertionInfo.showMinus = false;
00325 g_convertionInfo.negRed = false;
00326 g_convertionInfo.negRed = false;
00327 bool end = false;
00328
00329 while ( i < l && !end)
00330 {
00331 QChar c( format[i] );
00332 switch( c )
00333 {
00334 case '-':
00335 g_convertionInfo.showMinus = true;
00336 break;
00337 case '(':
00338 g_convertionInfo.negBr = true;
00339 break;
00340 case '[':
00341 if ( format.find( "[red]", i, false ) == i )
00342 {
00343 g_convertionInfo.negRed = true;
00344 i += 5;
00345 }
00346 break;
00347 default:
00348 end = true;
00349 }
00350 ++i;
00351 }
00352
00353
00354 bool quote = false;
00355 for ( int j = l - 1; j > i; --j )
00356 {
00357 if ( format[j] == '"' )
00358 {
00359 quote = !quote;
00360 continue;
00361 }
00362
00363 if ( !quote && ( format[j] == '0' || format[j] != '?'
00364 || format[j] != '#'
00365 || ( format[j].isDigit() && acceptDigits ) ) )
00366 {
00367 g_convertionInfo.postfix = format.mid( j + 1 );
00368 format.remove( (unsigned int) (j + 1), (unsigned int) (l - j) );
00369 break;
00370 }
00371 }
00372
00373 int p = g_convertionInfo.postfix.find( '"' );
00374 while ( p != -1 )
00375 {
00376 g_convertionInfo.postfix.remove( p, 1 );
00377
00378 p = g_convertionInfo.postfix.find( '"', p );
00379 }
00380 }
00381
00382 void createNumberStruct( BaseFormat * data, QString const & format, bool insert )
00383 {
00384 NumberFormat * d = new NumberFormat();
00385 d->type = Number;
00386 d->prefix = g_convertionInfo.prefix;
00387 d->postfix = g_convertionInfo.postfix;
00388 d->thSet = g_convertionInfo.thSet;
00389 d->showMinus = g_convertionInfo.showMinus;
00390 d->negRed = g_convertionInfo.negRed;
00391 d->negBr = g_convertionInfo.negBr;
00392 d->rightOpt = g_convertionInfo.rightOpt;
00393 d->rightReq = g_convertionInfo.rightReq;
00394 d->leftReq = g_convertionInfo.leftReq;
00395 d->rightSpace = g_convertionInfo.rightSpace;
00396 d->leftSpace = g_convertionInfo.leftSpace;
00397
00398 if ( insert )
00399 g_formatStore.addNumber( format, d );
00400 data = d;
00401 }
00402
00403 void createDateTimeStruct( BaseFormat * data, QString const & format,
00404 QString const & optFormat, bool insert )
00405 {
00406 DateTimeFormat * d = new DateTimeFormat();
00407 d->type = TimeDate;
00408 d->prefix = g_convertionInfo.prefix;
00409 d->postfix = g_convertionInfo.postfix;
00410 d->ampm = g_convertionInfo.ampm;
00411 d->format = optFormat;
00412
00413 if ( insert )
00414 g_formatStore.addDateTime( format, d );
00415 data = d;
00416 }
00417
00418 void createScientificStruct( BaseFormat * data, QString const & format, bool insert )
00419 {
00420 ScientificFormat * d = new ScientificFormat();
00421 d->type = Scientific;
00422 d->prefix = g_convertionInfo.prefix;
00423 d->postfix = g_convertionInfo.postfix;
00424 d->thSet = g_convertionInfo.thSet;
00425 d->showMinus = g_convertionInfo.showMinus;
00426 d->negRed = g_convertionInfo.negRed;
00427 d->negBr = g_convertionInfo.negBr;
00428 d->rightOpt = g_convertionInfo.rightOpt;
00429 d->rightReq = g_convertionInfo.rightReq;
00430 d->leftReq = g_convertionInfo.leftReq;
00431 d->rightSpace = g_convertionInfo.rightSpace;
00432 d->leftSpace = g_convertionInfo.leftSpace;
00433 d->upReq = g_convertionInfo.upReq;
00434
00435 if ( insert )
00436 g_formatStore.addScientific( format, d );
00437 data = d;
00438 }
00439
00440
00441 int doPreScan( QString & format, QString const & formatBack, KLocale const * const ,
00442 bool insert, BaseFormat * data )
00443 {
00444 int type = g_formatStore.getType( format, data );
00445 if ( data != 0 )
00446 return type;
00447
00448 resetGlobals();
00449
00450 int l = format.length();
00451 int i = 0;
00452 int thFound = false;
00453 int leftReq = 0;
00454 int leftOpt = 0;
00455 int rightOpt = 0;
00456 int spaceInNum = -1;
00457 bool dcSeen = false;
00458 bool endFixed = false;
00459
00460 FractionFormat * df = 0;
00461 int f = 0;
00462 int d = 0;
00463 int len = 0;
00464 int n = 0;
00465 bool ok = false;
00466 QString frac;
00467
00468 while ( i < l )
00469 {
00470 QString s;
00471 if ( endFixed )
00472 {
00473 g_convertionInfo.postfix += format.mid( i );
00474 format.remove( i, l - i );
00475 break;
00476 }
00477 QChar ch( format[i] );
00478 switch( ch )
00479 {
00480 case '[':
00481 if ( type == Number )
00482 endFixed = true;
00483
00484 if ( format[ i + 1] == '$' )
00485 {
00486 i += 2;
00487 bool found = false;
00488 while ( i < l && format[i] != ']' )
00489 {
00490 if ( format[i] == '-' )
00491 found = true;
00492 if ( !found )
00493 {
00494 if ( !endFixed )
00495 g_convertionInfo.prefix += format[i];
00496 else
00497 g_convertionInfo.postfix += format[i];
00498 format.remove( i, 1 );
00499 --i; --l;
00500 }
00501 ++i;
00502 }
00503 }
00504 else
00505 {
00506 if ( i + 1 >= l )
00507 {
00508 g_convertionInfo.postfix += '[';
00509 format.remove( i, 1 );
00510 --l; --i;
00511 }
00512 else
00513 if ( ( format[ i + 1].lower() != 's' )
00514 && ( format[ i + 1].lower() != 'm' )
00515 && ( format[ i + 1].lower() != 'h' ) )
00516 {
00517
00518
00519 if ( endFixed )
00520 g_convertionInfo.postfix += format[i];
00521 else
00522 g_convertionInfo.prefix += format[i];
00523 format.remove( i, 1 );
00524 --l; --i;
00525 }
00526 else
00527 {
00528 type = TimeDate;
00529 ++i;
00530 QChar c( format[i] );
00531 ++i;
00532 while ( i < l && format[i] != ']' )
00533 {
00534 if ( format[i] != c )
00535 {
00536 format.remove( i, 1 );
00537 --l; --i;
00538 break;
00539 }
00540 ++i;
00541 }
00542 }
00543 }
00544 break;
00545
00546 case '¤':
00547 case '$':
00548 case '¥':
00549 case '£':
00550 case '%':
00551 if ( type == Number )
00552 endFixed = true;
00553
00554 if ( endFixed )
00555 g_convertionInfo.postfix += format[i];
00556 else
00557 g_convertionInfo.prefix += format[i];
00558 format.remove( i, 1 );
00559 --i; --l;
00560 break;
00561
00562 case '#':
00563 type = Number;
00564 if ( !dcSeen && leftReq > 0 )
00565 {
00566 format.remove( i, 1 );
00567 --l; --i;
00568 }
00569 if ( !dcSeen )
00570 ++leftOpt;
00571 else
00572 ++g_convertionInfo.rightOpt;
00573 break;
00574
00575 case '0':
00576 if ( spaceInNum > 0 )
00577 {
00578 ++g_convertionInfo.reqCounter;
00579 break;
00580 }
00581 type = Number;
00582 if ( !dcSeen && rightOpt > 0 )
00583 {
00584 format.remove( i, 1 );
00585 --l; --i;
00586 }
00587 if ( !dcSeen )
00588 ++g_convertionInfo.leftReq;
00589 else
00590 ++g_convertionInfo.rightReq;
00591 break;
00592
00593 case '/':
00594 if ( ( i + 1 < l ) && ( format[i + 1] == ' ' ) )
00595 ++i;
00596 while ( i < l )
00597 {
00598 if ( format[i] != '?' && !format[i].isDigit() && format[i] != '#' )
00599 {
00600 g_convertionInfo.postfix = format.mid(i);
00601 format.remove( i, l - i );
00602 break;
00603 }
00604 else
00605 {
00606 ++d;
00607 frac += format[i];
00608 }
00609 ++i;
00610 }
00611 if ( i < l )
00612 {
00613 if ( format[i] == ';' )
00614 {
00615 ++i;
00616 parseNegativePart( format, i, l, true );
00617 }
00618 else
00619 if ( i + 3 < l )
00620 {
00621 if ( ( format[i + 1] == ')' ) && ( format[i + 2] == ';' ) )
00622 {
00623 i += 3;
00624 parseNegativePart( format, i, l, true );
00625 }
00626 }
00627 }
00628
00629 ok = false;
00630 f = frac.toInt( &ok );
00631
00632 df = new FractionFormat();
00633 if ( ok )
00634 df->fraction = f;
00635 else
00636 df->fraction = -1;
00637 df->type = Fraction;
00638 df->thSet = g_convertionInfo.thSet;
00639 df->showMinus = g_convertionInfo.showMinus;
00640 df->negRed = g_convertionInfo.negRed;
00641 df->negBr = g_convertionInfo.negBr;
00642 df->fractionDigists = d;
00643 df->reqCounter = g_convertionInfo.reqCounter;
00644 df->reqFirst = g_convertionInfo.reqFirst;
00645 df->prefix = g_convertionInfo.prefix;
00646 df->postfix = g_convertionInfo.postfix;
00647
00648 if ( insert )
00649 g_formatStore.addFraction( formatBack, df );
00650 data = df;
00651
00652 return Fraction;
00653 break;
00654
00655 case ',':
00656 if ( type == Unknown )
00657 {
00658 g_convertionInfo.prefix += ',';
00659 }
00660 else if ( type == Number )
00661 {
00662 if ( dcSeen )
00663 {
00664 g_convertionInfo.postfix += ',';
00665 format.remove( i, 1 );
00666 --i; --l;
00667 }
00668 else
00669 {
00670 if ( thFound )
00671 {
00672 format.remove( i, 1 );
00673 --l; --i;
00674 }
00675 else
00676 thFound = true;
00677 }
00678 }
00679
00680 case '.':
00681 if ( type == Unknown )
00682 {
00683 int j = i + 1;
00684 if ( ( j < l )
00685 && ( format[j] == '0' || format[j] == '#' ) )
00686 {
00687 type = Number;
00688 dcSeen = true;
00689 }
00690 else
00691 {
00692 if ( j == l )
00693 g_convertionInfo.postfix += '.';
00694 else
00695 g_convertionInfo.prefix += '.';
00696 format.remove( i, 1 );
00697 --i; --l;
00698 }
00699 }
00700 else if ( type == Number )
00701 {
00702 dcSeen = true;
00703 }
00704 break;
00705
00706 case '*':
00707 break;
00708
00709 case '"':
00710 n = i;
00711 ++i;
00712 while ( i < l && format[i] != '"' )
00713 {
00714 s += format[i];
00715 ++i;
00716 }
00717 if ( type == Unknown )
00718 g_convertionInfo.prefix += s;
00719 else
00720 {
00721 g_convertionInfo.postfix += s;
00722 }
00723 len = s.length();
00724 format.remove( i, len );
00725 i -= len; l -= len;
00726 break;
00727
00728 case '_':
00729 if ( type == Number )
00730 {
00731 bool pr = false;
00732 if ( i + 3 < l )
00733 {
00734 if ( ( format[i + 1] != ')' ) || ( format[i + 2] != ';' ) )
00735 pr = true;
00736 else
00737 {
00738 i += 3;
00739 parseNegativePart( format, i, l, false );
00740
00741 createNumberStruct( data, formatBack, insert );
00742
00743 return Number;
00744 }
00745 }
00746
00747 if ( pr )
00748 {
00749 g_convertionInfo.postfix += format.mid( i );
00750 format.remove( i, l - i );
00751
00752 createNumberStruct( data, formatBack, insert );
00753
00754 return Number;
00755 }
00756 }
00757 break;
00758
00759 case ';':
00760 if ( type == Unknown )
00761 {
00762 g_convertionInfo.postfix += ';';
00763 format.remove( i, 1 );
00764 --i; --l;
00765 }
00766 else
00767 {
00768 if ( type == Number )
00769 {
00770 ++i;
00771 parseNegativePart( format, i, l, false );
00772
00773 createNumberStruct( data, formatBack, insert );
00774
00775 return Number;
00776 }
00777 else
00778 if ( type == Scientific )
00779 {
00780 ++i;
00781 parseNegativePart( format, i, l, false );
00782
00783 createScientificStruct( data, formatBack, insert );
00784
00785 return Scientific;
00786 }
00787 }
00788
00789 case ' ':
00790 if ( type == Number )
00791 {
00792 g_convertionInfo.optFirst = (leftOpt > 0 ? leftOpt : 0);
00793 g_convertionInfo.reqFirst = (leftReq > 0 ? leftReq : 0);
00794
00795 spaceInNum = i;
00796 g_convertionInfo.postfix += ' ';
00797 }
00798 else if ( type == Unknown )
00799 {
00800 g_convertionInfo.prefix += ' ';
00801 format.remove( i, 1 );
00802 --i; --l;
00803 }
00804 break;
00805
00806 case 'A':
00807 case 'a':
00808 if ( type == TimeDate || type == Unknown )
00809 {
00810 if ( ( i + 1 < l ) && ( format[i + 1].lower() == 'm' ) )
00811 {
00812 g_convertionInfo.ampm = true;
00813 ++i;
00814 if ( ( i + 3 < l ) && ( format[i + 1] == '/' )
00815 && ( format[i + 2].lower() == 'p' )
00816 && ( format[i + 3].lower() == 'm' ) )
00817 {
00818 i += 3;
00819 }
00820 }
00821 else if ( type == Unknown )
00822 {
00823 g_convertionInfo.prefix += format[i];
00824 format.remove( i, 1 );
00825 --i; --l;
00826 }
00827 }
00828 else
00829 {
00830 if ( !endFixed )
00831 endFixed = true;
00832 g_convertionInfo.postfix += format[i];
00833 format.remove( i, 1 );
00834 --i; --l;
00835 }
00836 break;
00837
00838 case 'P':
00839 case 'p':
00840 if ( type == TimeDate || type == Unknown )
00841 {
00842 if ( ( i + 1 < l ) && ( format[i + 1].lower() == 'm' ) )
00843 {
00844 g_convertionInfo.ampm = true;
00845 i += 1;
00846 }
00847 else if ( type == Unknown )
00848 {
00849 g_convertionInfo.prefix += format[i];
00850 format.remove( i, 1 );
00851 --i; --l;
00852 }
00853 }
00854 else
00855 {
00856 if ( !endFixed )
00857 endFixed = true;
00858 g_convertionInfo.postfix += format[i];
00859 format.remove( i, 1 );
00860 --i; --l;
00861 }
00862 break;
00863
00864 case 'M':
00865 case 'm':
00866 if ( type == Unknown )
00867 type = TimeDate;
00868 else if ( type != TimeDate )
00869 endFixed = true;
00870 break;
00871
00872 case 'S':
00873 case 's':
00874 case 'H':
00875 case 'h':
00876 if ( type != Unknown && type != TimeDate )
00877 endFixed = true;
00878 else
00879 type = TimeDate;
00880 break;
00881
00882 case 'D':
00883 case 'd':
00884 case 'Y':
00885 case 'y':
00886 if ( type != Unknown && type != TimeDate )
00887 endFixed = true;
00888 else
00889 type = TimeDate;
00890 break;
00891
00892 default:
00893 if ( type == Unknown )
00894 {
00895 g_convertionInfo.prefix += format[i];
00896 format.remove( i, 1 );
00897 --i; --l;
00898 }
00899 else if ( type == Number || type == Scientific
00900 || type == Fraction )
00901 {
00902 endFixed = true;
00903 g_convertionInfo.postfix += format[i];
00904 format.remove( i, 1 );
00905 --l; --i;
00906 }
00907 }
00908
00909 ++i;
00910 }
00911
00912 if ( type == Number )
00913 createNumberStruct( data, formatBack, insert );
00914 else if ( type == TimeDate )
00915 createDateTimeStruct( data, formatBack, format, insert );
00916 else if ( type == Scientific )
00917 createScientificStruct( data, formatBack, insert );
00918
00919 return type;
00920 }
00921
00922 void createNumber( QString & result, Value const & value,
00923 QString const & , bool & setRed,
00924 NumberFormat const * const data )
00925 {
00926 int prec = data->rightReq + data->rightOpt;
00927 double num = value.asFloat();
00928 double m[] = { 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10 };
00929 double mm = ( prec > 10 ) ? pow( 10.0, prec ) : m[prec];
00930
00931 num = floor( fabs( num ) * mm + 0.5 ) / mm;
00932
00933 bool negative = ( num < 0 ? true : false );
00934 double nnum = ( negative ? -num : num );
00935
00936 result = QString::number( nnum, 'f', prec );
00937
00938 int pos = result.find( '.' );
00939 if ( pos >= 0 )
00940 {
00941 result = result.replace( pos, 1, g_dcSymbol );
00942
00943
00944 if ( data->rightOpt > 0 )
00945 {
00946 int i = result.length() - 1;
00947 int n = result.length() - data->rightOpt;
00948
00949 for ( ; i > n; --i )
00950 {
00951 if ( result[i] != '0' )
00952 break;
00953 }
00954 result = result.left( i + 1 );
00955
00956 if ( i == pos )
00957 result = result.remove( i, 1 );
00958 }
00959
00960
00961 while ( data->leftReq > pos )
00962 {
00963 result.prepend( '0' );
00964 ++pos;
00965 }
00966
00967
00968 if ( data->thSet && pos > 3 )
00969 {
00970 int l = pos - 3;
00971 while ( 0 < l )
00972 {
00973 result.insert( l, g_thSymbol );
00974 l -= 3;
00975 }
00976 }
00977 }
00978
00979 if ( data->leftSpace > 0 )
00980 {
00981 for ( int i = 0; i < data->leftSpace; ++i )
00982 result.prepend( ' ' );
00983 }
00984 if ( data->rightSpace > 0 )
00985 {
00986 for ( int i = 0; i < data->rightSpace; ++i )
00987 result.append( ' ' );
00988 }
00989
00990 if ( negative )
00991 {
00992 if ( data->showMinus )
00993 result.prepend( g_negSymbol );
00994
00995 if ( data->negBr )
00996 {
00997 result.prepend( '(' );
00998 result.append( ')' );
00999 }
01000
01001 if ( data->negRed )
01002 setRed = true;
01003 }
01004
01005 result.prepend( data->prefix );
01006 result.append( data->postfix );
01007 }
01008
01009 void createFraction( QString & result, Value const & value,
01010 QString const & , bool & setRed,
01011 FractionFormat const * const data )
01012 {
01013 double num = value.asFloat();
01014
01015 bool negative = ( num < 0 ? true : false );
01016
01017 double fnum = floor( negative ? -num : num );
01018
01019 double dec = num - fnum;
01020 double fraction;
01021 int index = 0;
01022
01023 if ( data->fraction <= 0 )
01024 {
01025
01026 double nnum = ( negative ? -num : num );
01027 double precision, denominator, numerator;
01028 int index = 2 + data->fractionDigists;
01029 int limit = 9;
01030 if ( data->fractionDigists == 2 )
01031 limit += 90;
01032 if ( data->fractionDigists >= 3 )
01033 limit += 990;
01034
01035 do
01036 {
01037 double val1 = nnum;
01038 double val2 = rint( nnum );
01039 double inter2 = 1;
01040 double inter4, p, q;
01041 inter4 = p = q = 0.0;
01042
01043 precision = pow( 10.0, - index );
01044 numerator = val2;
01045 denominator = 1;
01046
01047 while ( fabs( numerator / denominator - nnum ) > precision )
01048 {
01049 val1 = (1 / ( val1 - val2 ) );
01050 val2 = rint( val1 );
01051 p = val2 * numerator + inter2;
01052 q = val2 * denominator + inter4;
01053 inter2 = numerator;
01054 inter4 = denominator;
01055
01056 numerator = p;
01057 denominator = q;
01058 }
01059 --index;
01060 } while ( fabs( denominator ) > limit );
01061
01062 index = (int) fabs( numerator );
01063 fraction = (int) fabs( denominator );
01064 }
01065 else
01066 {
01067
01068 fraction = data->fraction;
01069
01070 double calc = 0.0;
01071 double diff = dec;
01072 double d;
01073 for ( int i = 1; i <= fraction; ++i )
01074 {
01075 calc = i * 1.0 / index;
01076 d = fabs( dec - calc );
01077 if ( d < diff )
01078 {
01079 index = i;
01080 diff = d;
01081 }
01082 }
01083 }
01084
01085
01086
01087
01088 if ( data->optFirst == 0 && data->reqFirst == 0 && fnum > 0 )
01089 index += (int) (fnum * fraction);
01090
01091 QString frac;
01092 QString left;
01093 if ( index > 0 )
01094 {
01095 QString numerator;
01096 QString denominator;
01097
01098 numerator = QString::number( index );
01099 int n = numerator.length() - data->reqCounter;
01100 for ( int i = 0; i < n; ++i )
01101 {
01102 numerator.prepend( '0' );
01103 }
01104
01105 denominator = QString::number( fraction );
01106 frac = numerator + '/' + denominator;
01107 }
01108
01109 if ( data->optFirst > 0 || data->reqFirst > 0 )
01110 {
01111 if ( fnum == 0 && data->reqFirst > 0 )
01112 {
01113 for ( int i = 0; i < data->reqFirst; ++i )
01114 left += '0';
01115 }
01116 else if ( fnum > 0 )
01117 {
01118 left = QString::number( fnum );
01119 int n = data->reqFirst - left.length();
01120 if ( n > 0 )
01121 {
01122 for ( int i = 0; i < n; ++i )
01123 {
01124 left.prepend( '0' );
01125 }
01126 }
01127 }
01128 }
01129
01130 if ( data->thSet )
01131 {
01132 int l = left.length() - 3;
01133 while ( 0 < l )
01134 {
01135 left.insert( l, g_thSymbol );
01136 l -= 3;
01137 }
01138 }
01139
01140 left = left + ' ' + frac;
01141
01142 if ( negative )
01143 {
01144 if ( data->showMinus )
01145 left.prepend( g_negSymbol );
01146
01147 if ( data->negBr )
01148 {
01149 left.prepend( '(' );
01150 left.append( ')' );
01151 }
01152
01153 if ( data->negRed )
01154 setRed = true;
01155 }
01156
01157 result = left;
01158 }
01159
01160 void createScientific( QString & result, Value const & value,
01161 QString const & , bool & setRed,
01162 ScientificFormat const * const data )
01163 {
01164 double num = value.asFloat();
01165
01166 bool negative = ( num < 0 ? true : false );
01167 double nnum = ( negative ? -num : num );
01168
01169 result = QString::number( nnum, 'E', data->rightReq + data->rightOpt );
01170
01171 int pos = result.find( '.' );
01172 if ( pos >= 0 )
01173 {
01174 result = result.replace( pos, 1, g_dcSymbol );
01175 if ( data->rightOpt > 0 )
01176 {
01177 int i = result.find( 'E', pos, false ) - 1;
01178 int n = result.length() - data->rightOpt;
01179
01180 if ( i > 0 )
01181 {
01182 int rem = 0;
01183 for ( ; i > n; --i )
01184 {
01185 if ( result[i] != '0' )
01186 break;
01187 else
01188 ++rem;
01189 }
01190 result = result.remove( i + 1, rem );
01191 }
01192 }
01193
01194 while ( data->leftReq > pos )
01195 {
01196 result.prepend( '0' );
01197 ++pos;
01198 }
01199
01200 if ( data->thSet && pos > 3 )
01201 {
01202 int l = pos - 3;
01203 while ( 0 < l )
01204 {
01205 result.insert( l, g_thSymbol );
01206 l -= 3;
01207 }
01208 }
01209 }
01210
01211 if ( negative )
01212 {
01213 if ( data->showMinus )
01214 result.prepend( g_negSymbol );
01215
01216 if ( data->negBr )
01217 {
01218 result.prepend( '(' );
01219 result.append( ')' );
01220 }
01221
01222 if ( data->negRed )
01223 setRed = true;
01224 }
01225
01226 result.prepend( data->prefix );
01227 result.append( data->postfix );
01228 }
01229
01230 void appendAMPM( QString & result, Value const & value )
01231 {
01232 if ( !g_convertionInfo.dt )
01233 convertDateTime( value );
01234
01235 int hour = g_convertionInfo.dt->hour;
01236 if ( hour > 12 )
01237 result.append( i18n("PM") );
01238 else
01239 result.append( i18n("AM") );
01240 }
01241
01242 void appendHour( QString & result, Value const & value,
01243 int digits, bool elapsed, bool ampm )
01244 {
01245 if ( !g_convertionInfo.dt )
01246 convertDateTime( value );
01247
01248 int hour = g_convertionInfo.dt->hour;
01249 if ( elapsed )
01250 {
01251 QDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
01252 QDate d2( 1900, 1, 1 );
01253 hour += ( d2.daysTo( d1 ) * 24 );
01254 }
01255 if ( hour < 10 && digits == 2 )
01256 result += '0';
01257 else
01258 if ( hour > 12 && ampm )
01259 {
01260 hour -= 12;
01261 if ( digits == 2 && hour < 10 )
01262 result += '0';
01263 }
01264
01265 result += QString::number( hour );
01266 }
01267
01268 void appendMinutes( QString & result, Value const & value,
01269 int digits, bool elapsed )
01270 {
01271 if ( !g_convertionInfo.dt )
01272 convertDateTime( value );
01273
01274 int minute = g_convertionInfo.dt->minute;
01275 if ( elapsed )
01276 {
01277 QDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
01278 QDate d2( 1900, 1, 1 );
01279 minute += ( d2.daysTo( d1 ) * 24 * 60 );
01280 }
01281 if ( minute < 10 && digits == 2 )
01282 result += '0';
01283
01284 result += QString::number( minute );
01285 }
01286
01287 void appendSecond( QString & result, Value const & value,
01288 int digits, bool elapsed )
01289 {
01290 if ( !g_convertionInfo.dt )
01291 convertDateTime( value );
01292
01293 int second = g_convertionInfo.dt->second;
01294 if ( elapsed )
01295 {
01296 QDate d1( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
01297 QDate d2( 1900, 1, 1 );
01298 second += ( d2.daysTo( d1 ) * 24 * 60 * 60 );
01299 }
01300 if ( second < 10 && digits == 2 )
01301 result += '0';
01302
01303 result += QString::number( second );
01304 }
01305
01306 void appendYear( QString & result, Value const & value,
01307 int digits )
01308 {
01309 if ( !g_convertionInfo.dt )
01310 convertDateTime( value );
01311
01312 int year = g_convertionInfo.dt->year;
01313 if ( digits <= 2 )
01314 result += QString::number( year ).right( 2 );
01315 else
01316 result += QString::number( year );
01317 }
01318
01319 void appendMonth( QString & result, Value const & value,
01320 int digits )
01321 {
01322 if ( !g_convertionInfo.dt )
01323 convertDateTime( value );
01324
01325 int month = g_convertionInfo.dt->month;
01326 if ( digits == 1 )
01327 result += QString::number( month );
01328 else
01329 if ( digits == 2 )
01330 {
01331 if ( month < 10 )
01332 result += '0';
01333
01334 result += QString::number( month );
01335 }
01336 else
01337 {
01338 switch ( month )
01339 {
01340 case 1:
01341 result += ( digits != 3 ? g_January : g_Jan );
01342 break;
01343
01344 case 2:
01345 result += ( digits != 3 ? g_February : g_Feb );
01346 break;
01347
01348 case 3:
01349 result += ( digits != 3 ? g_March : g_Mar );
01350 break;
01351
01352 case 4:
01353 result += ( digits != 3 ? g_April : g_Apr );
01354 break;
01355
01356 case 5:
01357 result += ( digits != 3 ? g_MayL : g_May );
01358 break;
01359
01360 case 6:
01361 result += ( digits != 3 ? g_June : g_Jun );
01362 break;
01363
01364 case 7:
01365 result += ( digits != 3 ? g_July : g_Jul );
01366 break;
01367
01368 case 8:
01369 result += ( digits != 3 ? g_August : g_Aug );
01370 break;
01371
01372 case 9:
01373 result += ( digits != 3 ? g_September : g_Sep );
01374 break;
01375
01376 case 10:
01377 result += ( digits != 3 ? g_October : g_Oct );
01378 break;
01379
01380 case 11:
01381 result += ( digits != 3 ? g_November : g_Nov );
01382 break;
01383
01384 case 12:
01385 result += ( digits != 3 ? g_December : g_Dec );
01386 break;
01387 }
01388 }
01389 }
01390
01391 void appendDays( QString & result, Value const & value,
01392 int digits )
01393 {
01394 if ( !g_convertionInfo.dt )
01395 convertDateTime( value );
01396
01397 int day = g_convertionInfo.dt->day;
01398 if ( digits == 1 )
01399 result += QString::number( day );
01400 else
01401 if ( digits == 2 )
01402 {
01403 if ( day < 10 )
01404 result += '0';
01405
01406 result += QString::number( day );
01407 }
01408 else
01409 {
01410 QDate date( g_convertionInfo.dt->year, g_convertionInfo.dt->month, g_convertionInfo.dt->day );
01411 int weekDay = date.dayOfWeek();
01412 switch ( weekDay )
01413 {
01414 case 1:
01415 result += ( digits != 3 ? g_Monday : g_Mon );
01416 break;
01417
01418 case 2:
01419 result += ( digits != 3 ? g_Tuesday : g_Tue );
01420 break;
01421
01422 case 3:
01423 result += ( digits != 3 ? g_Wednesday : g_Wed );
01424 break;
01425
01426 case 4:
01427 result += ( digits != 3 ? g_Thursday : g_Thu );
01428 break;
01429
01430 case 5:
01431 result += ( digits != 3 ? g_Friday : g_Fri );
01432 break;
01433
01434 case 6:
01435 result += ( digits != 3 ? g_Saturday : g_Sat );
01436 break;
01437
01438 case 7:
01439 result += ( digits != 3 ? g_Sunday : g_Sun );
01440 break;
01441 }
01442 }
01443 }
01444
01445 void createDateTime( QString & result, Value const & value,
01446 QString const & ,
01447 DateTimeFormat const * const data )
01448 {
01449 result = data->prefix;
01450 bool elapsed = false;
01451 bool elapsedFound = false;
01452 bool minute = false;
01453 int digits = 1;
01454 int i = 0;
01455 int l = (int) data->format.length();
01456 while ( i < l )
01457 {
01458 switch( data->format[i].lower() )
01459 {
01460 case '"':
01461 ++i;
01462 while ( i < l )
01463 {
01464 if ( data->format[i] == '"' )
01465 break;
01466 else
01467 result += data->format[i];
01468 }
01469 break;
01470
01471 case '[':
01472 if ( elapsedFound )
01473 result += '[';
01474 else
01475 {
01476 elapsed = true;
01477 elapsedFound = true;
01478 }
01479 break;
01480
01481 case ']':
01482 if ( elapsed )
01483 elapsed = false;
01484 else
01485 result += ']';
01486 break;
01487
01488 case 'h':
01489 minute = true;
01490 if ( data->format[i + 1] == 'h' )
01491 {
01492 appendHour( result, value, 2, elapsed, data->ampm );
01493 ++i;
01494 }
01495 else
01496 appendHour( result, value, 1, elapsed, data->ampm );
01497 break;
01498
01499 case 'm':
01500 digits = 1;
01501
01502 while ( data->format[i + 1] == 'm' )
01503 {
01504 ++i;
01505 ++digits;
01506 }
01507
01508 if ( minute )
01509 appendMinutes( result, value, digits, elapsed );
01510 else
01511 appendMonth( result, value, digits );
01512
01513 break;
01514
01515 case 's':
01516 minute = true;
01517 if ( data->format[i + 1] == 's' )
01518 {
01519 appendSecond( result, value, 2, elapsed );
01520 ++i;
01521 }
01522 else
01523 appendSecond( result, value, 1, elapsed );
01524 break;
01525
01526 case 'd':
01527 minute = false;
01528 digits = 1;
01529
01530 while ( data->format[i + 1] == 'd' )
01531 {
01532 ++i;
01533 ++digits;
01534 }
01535 appendDays( result, value, digits );
01536 break;
01537
01538 case 'y':
01539 minute = false;
01540 digits = 1;
01541
01542 while ( data->format[i + 1] == 'y' )
01543 {
01544 ++i;
01545 ++digits;
01546 }
01547 appendYear( result, value, digits );
01548 break;
01549
01550 case 'a':
01551 case 'p':
01552 if ( data->format[i + 1] == 'm' )
01553 {
01554 ++i;
01555 if ( data->format[i + 1] == '/'
01556 && data->format[i + 2].lower() == 'p'
01557 && data->format[i + 3].lower() == 'm' )
01558 i += 3;
01559
01560 appendAMPM( result, value );
01561 }
01562
01563 default:
01564 result += data->format[i];
01565 }
01566
01567 ++i;
01568 }
01569
01570 result += data->postfix;
01571 }
01572
01573 QString formatNumber( Value const & value, QString format, bool & setRed,
01574 KLocale const * const locale, bool insert )
01575 {
01576
01577 if ( !g_init )
01578 initGlobals( locale );
01579
01580 QString backup( format );
01581 QString result;
01582 BaseFormat * data = 0;
01583 setRed = false;
01584
01585 int t = doPreScan( format, backup, locale, insert, data );
01586
01587 if ( t == Number )
01588 {
01589 createNumber( result, value, format, setRed, (NumberFormat *) data );
01590
01591 if ( !insert )
01592 delete (NumberFormat *) data;
01593
01594 return result;
01595 }
01596 else if ( t == Fraction )
01597 {
01598 createFraction( result, value, format, setRed, (FractionFormat *) data );
01599
01600 if ( !insert )
01601 delete (FractionFormat *) data;
01602
01603 return result;
01604 }
01605 else if ( t == Scientific )
01606 {
01607 createScientific( result, value, format, setRed, (ScientificFormat *) data );
01608
01609 if ( !insert )
01610 delete (ScientificFormat *) data;
01611
01612 return result;
01613 }
01614 else if ( t == TimeDate )
01615 {
01616 createDateTime( result, value, format, (DateTimeFormat *) data );
01617
01618 if ( !insert )
01619 delete (DateTimeFormat *) data;
01620
01621 return result;
01622 }
01623 else if ( data != 0 )
01624 {
01625 result = data->prefix + data->postfix;
01626
01627 if ( !insert )
01628 delete data;
01629
01630 return result;
01631 }
01632
01633 return result;
01634 }