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