00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "valueformatter.h"
00022
00023 #include "kspread_cell.h"
00024 #include "kspread_locale.h"
00025 #include "kspread_util.h"
00026 #include "valueconverter.h"
00027
00028 #include <kcalendarsystem.h>
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031
00032 #include <float.h>
00033 #include <math.h>
00034
00035 using namespace KSpread;
00036
00037 ValueFormatter::ValueFormatter (ValueConverter *conv) : converter( conv )
00038 {
00039 }
00040
00041 QString ValueFormatter::formatText (Cell *cell, FormatType fmtType)
00042 {
00043 if (cell->hasError ())
00044 return errorFormat (cell);
00045
00046 QString str;
00047
00048 Format::FloatFormat floatFormat =
00049 cell->format()->floatFormat (cell->column(), cell->row());
00050 int precision = cell->format()->precision (cell->column(), cell->row());
00051 QString prefix = cell->format()->prefix (cell->column(), cell->row());
00052 QString postfix = cell->format()->postfix (cell->column(), cell->row());
00053 Format::Currency currency;
00054 bool valid = cell->format()->currencyInfo(currency);
00055 QString currencySymbol = valid ? currency.symbol : QString::null;
00056
00057 return formatText (cell->value(), fmtType, precision,
00058 floatFormat, prefix, postfix, currencySymbol);
00059 }
00060
00061 QString ValueFormatter::formatText (const Value &value,
00062 FormatType fmtType, int precision, Format::FloatFormat floatFormat,
00063 const QString &prefix, const QString &postfix, const QString ¤cySymbol)
00064 {
00065
00066 if (value.isArray())
00067 return formatText (value.element (0, 0), fmtType, precision,
00068 floatFormat, prefix, postfix, currencySymbol);
00069
00070 QString str;
00071
00072
00073 fmtType = determineFormatting (value, fmtType);
00074
00075
00076
00077
00078 if (fmtType == Text_format)
00079 {
00080 str = converter->asString (value).asString();
00081 if (!str.isEmpty() && str[0]=='\'' )
00082 str = str.mid(1);
00083 }
00084
00085
00086 else if (formatIsDate (fmtType))
00087 str = dateFormat (value.asDate(), fmtType);
00088
00089
00090 else if (formatIsTime (fmtType))
00091 str = timeFormat (value.asDateTime(), fmtType);
00092
00093
00094 else if (formatIsFraction (fmtType))
00095 str = fractionFormat (value.asFloat(), fmtType);
00096
00097
00098 else if (value.isInteger())
00099 {
00100 long v = value.asInteger();
00101
00102 if ((floatFormat == Format::AlwaysUnsigned) && (v < 0))
00103 v *= -1;
00104 str = createNumberFormat (v, fmtType,
00105 (floatFormat == Format::AlwaysSigned), currencySymbol);
00106 }
00107 else
00108 {
00109 QChar decimal_point = converter->locale()->decimalSymbol()[0];
00110 if ( decimal_point.isNull() )
00111 decimal_point = '.';
00112
00113
00114 double v = converter->asFloat (value).asFloat();
00115
00116
00117 if ((floatFormat == Format::AlwaysUnsigned) && (v < 0.0))
00118 v *= -1.0;
00119
00120
00121 str = createNumberFormat (v, precision, fmtType,
00122 (floatFormat == Format::AlwaysSigned), currencySymbol);
00123
00124
00125
00126 if (precision == -1)
00127 removeTrailingZeros (str, decimal_point);
00128 }
00129
00130 if (!prefix.isEmpty())
00131 str = prefix + ' ' + str;
00132
00133 if( !postfix.isEmpty())
00134 str += ' ' + postfix;
00135
00136
00137 return str;
00138 }
00139
00140 FormatType ValueFormatter::determineFormatting (const Value &value,
00141 FormatType fmtType)
00142 {
00143
00144
00145 if (value.isString () || (value.format() == Value::fmt_None))
00146 return Text_format;
00147
00148 if (fmtType == Text_format)
00149 return Text_format;
00150
00151
00152 if (fmtType == Generic_format)
00153 {
00154
00155 Value::Format fmt = value.format();
00156 switch (fmt) {
00157 case Value::fmt_None:
00158 fmtType = Text_format;
00159 break;
00160 case Value::fmt_Boolean:
00161 fmtType = Text_format;
00162 break;
00163 case Value::fmt_Number:
00164 if (value.asFloat() > 1e+10)
00165 fmtType = Scientific_format;
00166 else
00167 fmtType = Number_format;
00168 break;
00169 case Value::fmt_Percent:
00170 fmtType = Percentage_format;
00171 break;
00172 case Value::fmt_Money:
00173 fmtType = Money_format;
00174 break;
00175 case Value::fmt_DateTime:
00176 fmtType = TextDate_format;
00177 break;
00178 case Value::fmt_Date:
00179 fmtType = ShortDate_format;
00180 break;
00181 case Value::fmt_Time:
00182 fmtType = Time_format;
00183 break;
00184 case Value::fmt_String:
00185
00186 fmtType = Text_format;
00187 break;
00188 };
00189 return fmtType;
00190 }
00191 else
00192 {
00193
00194
00195
00196
00197
00198
00199
00200
00201 if (value.isBoolean())
00202 return Text_format;
00203 else
00204 return fmtType;
00205 }
00206 }
00207
00208
00209 void ValueFormatter::removeTrailingZeros (QString &str, QChar decimal_point)
00210 {
00211 if (str.find (decimal_point) < 0)
00212
00213 return;
00214
00215 int start = 0;
00216 int cslen = converter->locale()->currencySymbol().length();
00217 if (str.find ('%') != -1)
00218 start = 2;
00219 else if (str.find (converter->locale()->currencySymbol()) ==
00220 ((int) (str.length() - cslen)))
00221 start = cslen + 1;
00222 else if ((start = str.find ('E')) != -1)
00223 start = str.length() - start;
00224 else
00225 start = 0;
00226
00227 int i = str.length() - start;
00228 bool bFinished = false;
00229 while ( !bFinished && i > 0 )
00230 {
00231 QChar ch = str[i - 1];
00232 if (ch == '0')
00233 str.remove (--i,1);
00234 else
00235 {
00236 bFinished = true;
00237 if (ch == decimal_point)
00238 str.remove (--i, 1);
00239 }
00240 }
00241 }
00242
00243
00244 QString ValueFormatter::createNumberFormat ( long value, FormatType fmt,
00245 bool alwaysSigned, const QString& currencySymbol)
00246 {
00247 QString number;
00248
00249
00250 if (fmt == Percentage_format)
00251 value *= 100;
00252
00253 switch (fmt)
00254 {
00255 case Number_format:
00256 case Scientific_format:
00257 number = QString::number(value);
00258 break;
00259 case Percentage_format:
00260 number = QString::number(value) + " %";
00261 break;
00262 case Money_format:
00263 number = converter->locale()->formatMoney (value, currencySymbol.isEmpty() ? converter->locale()->currencySymbol() : currencySymbol);
00264 break;
00265 default :
00266
00267
00268 kdDebug(36001)<<"Wrong usage of ValueFormatter::createNumberFormat fmt=" << fmt << "\n";
00269 break;
00270 }
00271
00272
00273 if (alwaysSigned && value >= 0 )
00274 if (converter->locale()->positiveSign().isEmpty())
00275 number='+'+number;
00276
00277 return number;
00278 }
00279
00280 QString ValueFormatter::createNumberFormat ( double value, int precision,
00281 FormatType fmt, bool alwaysSigned, const QString& currencySymbol)
00282 {
00283
00284
00285 int p = (precision == -1) ? 8 : precision;
00286 QString localizedNumber;
00287 int pos = 0;
00288
00289
00290 if (fmt == Percentage_format)
00291 value *= 100;
00292
00293
00294 if( fabs( value ) < DBL_EPSILON ) value = 0.0;
00295
00296
00297
00298 if( fmt != Scientific_format )
00299 {
00300 double m[] = { 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10 };
00301 double mm = (p > 10) ? pow(10.0,p) : m[p];
00302 bool neg = value < 0;
00303 value = floor( fabs(value)*mm + 0.5 ) / mm;
00304 if( neg ) value = -value;
00305 }
00306
00307 QChar decimal_point;
00308 switch (fmt)
00309 {
00310 case Number_format:
00311 localizedNumber = converter->locale()->formatNumber(value, p);
00312 break;
00313 case Percentage_format:
00314 localizedNumber = converter->locale()->formatNumber (value, p)+ " %";
00315 break;
00316 case Money_format:
00317 localizedNumber = converter->locale()->formatMoney (value,
00318 currencySymbol.isEmpty() ? converter->locale()->currencySymbol() : currencySymbol, p );
00319 break;
00320 case Scientific_format:
00321 decimal_point = converter->locale()->decimalSymbol()[0];
00322 localizedNumber = QString::number (value, 'E', p);
00323 if ((pos = localizedNumber.find ('.')) != -1)
00324 localizedNumber = localizedNumber.replace (pos, 1, decimal_point);
00325 break;
00326 default :
00327
00328
00329 kdDebug(36001)<<"Wrong usage of ValueFormatter::createNumberFormat fmt=" << fmt << "\n";
00330 break;
00331 }
00332
00333
00334 if (alwaysSigned && value >= 0 )
00335 if (converter->locale()->positiveSign().isEmpty())
00336 localizedNumber='+'+localizedNumber;
00337
00338 return localizedNumber;
00339 }
00340
00341 QString ValueFormatter::fractionFormat (double value, FormatType fmtType)
00342 {
00343 double result = value - floor(value);
00344 int index;
00345 int limit = 0;
00346
00347
00348 if (result == 0)
00349 return QString::number(value);
00350
00351 switch (fmtType) {
00352 case fraction_half:
00353 index = 2;
00354 break;
00355 case fraction_quarter:
00356 index = 4;
00357 break;
00358 case fraction_eighth:
00359 index = 8;
00360 break;
00361 case fraction_sixteenth:
00362 index = 16;
00363 break;
00364 case fraction_tenth:
00365 index = 10;
00366 break;
00367 case fraction_hundredth:
00368 index = 100;
00369 break;
00370 case fraction_one_digit:
00371 index = 3;
00372 limit = 9;
00373 break;
00374 case fraction_two_digits:
00375 index = 4;
00376 limit = 99;
00377 break;
00378 case fraction_three_digits:
00379 index = 5;
00380 limit = 999;
00381 break;
00382 default:
00383 kdDebug(36001) << "Error in Fraction format\n";
00384 return QString::number(value);
00385 break;
00386 }
00387
00388
00389
00390
00391 if (fmtType != fraction_three_digits
00392 && fmtType != fraction_two_digits
00393 && fmtType != fraction_one_digit) {
00394 double calc = 0;
00395 int index1 = 0;
00396 double diff = result;
00397 for (int i = 1; i <= index; i++) {
00398 calc = i * 1.0 / index;
00399 if (fabs(result - calc) < diff) {
00400 index1 = i;
00401 diff = fabs(result - calc);
00402 }
00403 }
00404 if( index1 == 0 ) return QString("%1").arg( floor(value) );
00405 if( index1 == index ) return QString("%1").arg( floor(value)+1 );
00406 if( floor(value) == 0)
00407 return QString("%1/%2").arg( index1 ).arg( index );
00408
00409 return QString("%1 %2/%3")
00410 .arg( floor(value) )
00411 .arg( index1 )
00412 .arg( index );
00413 }
00414
00415
00416
00417
00418
00419 double precision, denominator, numerator;
00420
00421 do {
00422 double val1 = result;
00423 double val2 = rint(result);
00424 double inter2 = 1;
00425 double inter4, p, q;
00426 inter4 = p = q = 0;
00427
00428 precision = pow(10.0, -index);
00429 numerator = val2;
00430 denominator = 1;
00431
00432 while (fabs(numerator/denominator - result) > precision) {
00433 val1 = (1 / (val1 - val2));
00434 val2 = rint(val1);
00435 p = val2 * numerator + inter2;
00436 q = val2 * denominator + inter4;
00437 inter2 = numerator;
00438 inter4 = denominator;
00439 numerator = p;
00440 denominator = q;
00441 }
00442 index--;
00443 } while (fabs(denominator) > limit);
00444
00445 denominator = fabs(denominator);
00446 numerator = fabs(numerator);
00447
00448 if (denominator == numerator)
00449 return QString().setNum(floor(value + 1));
00450 else
00451 {
00452 if ( floor(value) == 0 )
00453 return QString("%1/%2").arg(numerator).arg(denominator);
00454 else
00455 return QString("%1 %2/%3")
00456 .arg(floor(value))
00457 .arg(numerator)
00458 .arg(denominator);
00459 }
00460 }
00461
00462 QString ValueFormatter::timeFormat (const QDateTime &dt, FormatType fmtType)
00463 {
00464 if (fmtType == Time_format)
00465 return converter->locale()->formatTime(dt.time(), false);
00466
00467 if (fmtType == SecondeTime_format)
00468 return converter->locale()->formatTime(dt.time(), true);
00469
00470 int h = dt.time().hour();
00471 int m = dt.time().minute();
00472 int s = dt.time().second();
00473
00474 QString hour = ( h < 10 ? "0" + QString::number(h) : QString::number(h) );
00475 QString minute = ( m < 10 ? "0" + QString::number(m) : QString::number(m) );
00476 QString second = ( s < 10 ? "0" + QString::number(s) : QString::number(s) );
00477 bool pm = (h > 12);
00478 QString AMPM( pm ? i18n("PM"):i18n("AM") );
00479
00480 if (fmtType == Time_format1) {
00481 return QString("%1:%2 %3")
00482 .arg((pm ? h - 12 : h),2)
00483 .arg(minute,2)
00484 .arg(AMPM);
00485 }
00486
00487 if (fmtType == Time_format2) {
00488 return QString("%1:%2:%3 %4")
00489 .arg((pm ? h-12 : h),2)
00490 .arg(minute,2)
00491 .arg(second,2)
00492 .arg(AMPM);
00493 }
00494
00495 if (fmtType == Time_format3) {
00496 return QString("%1 %2 %3 %4 %5 %6")
00497 .arg(hour,2)
00498 .arg(i18n("h"))
00499 .arg(minute,2)
00500 .arg(i18n("min"))
00501 .arg(second,2)
00502 .arg(i18n("s"));
00503 }
00504
00505 if (fmtType == Time_format4) {
00506 return QString("%1:%2").arg(hour, 2).arg(minute, 2);
00507 }
00508
00509 if (fmtType == Time_format5) {
00510 return QString("%1:%2:%3").arg(hour, 2).arg(minute, 2).arg(second, 2);
00511 }
00512
00513 QDate d1(dt.date());
00514 QDate d2( 1899, 12, 31 );
00515 int d = d2.daysTo( d1 ) + 1;
00516
00517 h += d * 24;
00518
00519 if (fmtType == Time_format6)
00520 {
00521 m += (h * 60);
00522 return QString("%1:%2").arg(m, 1).arg(second, 2);
00523 }
00524 if (fmtType == Time_format7) {
00525 return QString("%1:%2:%3").arg(h, 1).arg(minute, 2).arg(second, 2);
00526 }
00527 if (fmtType == Time_format8)
00528 {
00529 m += (h * 60);
00530 return QString("%1:%2").arg(h, 1).arg(minute, 2);
00531 }
00532
00533 return converter->locale()->formatTime( dt.time(), false );
00534 }
00535
00536 QString ValueFormatter::dateFormat (const QDate &date, FormatType fmtType)
00537 {
00538 QString tmp;
00539 if (fmtType == ShortDate_format) {
00540 tmp = converter->locale()->formatDate(date, true);
00541 }
00542 else if (fmtType == TextDate_format) {
00543 tmp = converter->locale()->formatDate(date, false);
00544 }
00545 else if (fmtType == date_format1) {
00546 tmp = QString().sprintf("%02d", date.day());
00547 tmp += "-" + converter->locale()->calendar()->monthString(date, true) + "-";
00548 tmp += QString::number(date.year()).right(2);
00549 }
00550 else if (fmtType == date_format2) {
00551 tmp = QString().sprintf("%02d", date.day());
00552 tmp += "-" + converter->locale()->calendar()->monthString(date, true) + "-";
00553 tmp += QString::number(date.year());
00554 }
00555 else if (fmtType == date_format3) {
00556 tmp = QString().sprintf("%02d", date.day());
00557 tmp += "-" + converter->locale()->calendar()->monthString(date, true);
00558 }
00559 else if (fmtType == date_format4) {
00560 tmp = QString().sprintf("%02d", date.day());
00561 tmp += "-" + QString().sprintf("%02d", date.month() );
00562 }
00563 else if (fmtType == date_format5) {
00564 tmp = QString().sprintf("%02d", date.day());
00565 tmp += "/" + QString().sprintf("%02d", date.month()) + "/";
00566 tmp += QString::number(date.year()).right(2);
00567 }
00568 else if (fmtType == date_format6) {
00569 tmp = QString().sprintf("%02d", date.day());
00570 tmp += "/" + QString().sprintf("%02d", date.month()) + "/";
00571 tmp += QString::number(date.year());
00572 }
00573 else if (fmtType == date_format7) {
00574 tmp = converter->locale()->calendar()->monthString(date, true) + "-";
00575 tmp += QString::number(date.year()).right(2);
00576 }
00577 else if (fmtType == date_format8) {
00578 tmp = converter->locale()->calendar()->monthString(date, false) + "-";
00579 tmp += QString::number(date.year()).right(2);
00580 }
00581 else if (fmtType == date_format9) {
00582 tmp = converter->locale()->calendar()->monthString(date, false) + "-";
00583 tmp += QString::number(date.year());
00584 }
00585 else if (fmtType == date_format10) {
00586 tmp = converter->locale()->calendar()->monthString(date, false).at(0) + "-";
00587 tmp += QString::number(date.year()).right(2);
00588 }
00589 else if (fmtType == date_format11) {
00590 tmp = QString().sprintf("%02d", date.day()) + "/";
00591 tmp += converter->locale()->calendar()->monthString(date, true);
00592 }
00593 else if (fmtType == date_format12) {
00594 tmp = QString().sprintf("%02d", date.day()) + "/";
00595 tmp += QString().sprintf("%02d", date.month());
00596 }
00597 else if (fmtType == date_format13) {
00598 tmp = QString().sprintf("%02d", date.day());
00599 tmp += "/" + converter->locale()->calendar()->monthString(date, true) + "/";
00600 tmp += QString::number(date.year());
00601 }
00602 else if (fmtType == date_format14) {
00603 tmp = QString::number(date.year());
00604 tmp += "/" + converter->locale()->calendar()->monthString(date, true) + "/";
00605 tmp += QString().sprintf("%02d", date.day());
00606 }
00607 else if (fmtType == date_format15) {
00608 tmp = QString::number(date.year());
00609 tmp += "-" + converter->locale()->calendar()->monthString(date, true) + "-";
00610 tmp += QString().sprintf("%02d", date.day());
00611 }
00612 else if (fmtType == date_format16) {
00613 tmp = QString::number(date.year());
00614 tmp += "-" + QString().sprintf("%02d", date.month()) + "-";
00615 tmp += QString().sprintf("%02d", date.day());
00616 }
00617 else if (fmtType == date_format17) {
00618 tmp = QString().sprintf("%d", date.day());
00619 tmp += " " + converter->locale()->calendar()->monthString(date, false) + " ";
00620 tmp += QString::number(date.year());
00621 }
00622 else if (fmtType == date_format18) {
00623 tmp = QString().sprintf("%02d", date.month());
00624 tmp += "/" + QString().sprintf("%02d", date.day());
00625 tmp += "/" + QString::number(date.year());
00626 }
00627 else if (fmtType == date_format19) {
00628 tmp = QString().sprintf("%02d", date.month());
00629 tmp += "/" + QString().sprintf("%02d", date.day());
00630 tmp += "/" + QString::number(date.year()).right(2);
00631 }
00632 else if (fmtType == date_format20) {
00633 tmp = converter->locale()->calendar()->monthString(date, true);
00634 tmp += "/" + QString().sprintf("%02d", date.day());
00635 tmp += "/" + QString::number(date.year()).right(2);
00636 }
00637 else if (fmtType == date_format21) {
00638 tmp = converter->locale()->calendar()->monthString(date, true);
00639 tmp += "/" + QString().sprintf("%02d", date.day());
00640 tmp += "/" + QString::number(date.year());
00641 }
00642 else if (fmtType == date_format22) {
00643 tmp = converter->locale()->calendar()->monthString(date, true) + "-";
00644 tmp += QString::number(date.year());
00645 }
00646 else if (fmtType == date_format23) {
00647 tmp = QString::number(date.year());
00648 }
00649 else if (fmtType == date_format24) {
00650 tmp = QString::number(date.year()).right(2);
00651 }
00652 else if (fmtType == date_format25) {
00653 tmp = QString::number(date.year());
00654 tmp += "/" + QString().sprintf("%02d", date.month());
00655 tmp += "/" + QString().sprintf("%02d", date.day());
00656 }
00657 else if (fmtType == date_format26) {
00658 tmp = QString::number(date.year());
00659 tmp += "/" + converter->locale()->calendar()->monthString(date, true);
00660 tmp += "/" + QString().sprintf("%02d", date.day());
00661 }
00662 else
00663 tmp = converter->locale()->formatDate(date, true);
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 return tmp;
00674 }
00675
00676 QString ValueFormatter::errorFormat (Cell *cell)
00677 {
00678 QString err;
00679 if (cell->testFlag (Cell::Flag_ParseError))
00680 err = "#" + i18n ("Parse") + "!";
00681 else if ( cell->testFlag (Cell::Flag_CircularCalculation))
00682 err = "#" + i18n ("Circle") + "!";
00683 else if ( cell->testFlag (Cell::Flag_DependancyError))
00684 err = "#" + i18n ("Depend") + "!";
00685 else
00686 {
00687 err = "####";
00688 kdDebug(36001) << "Unhandled error type." << endl;
00689 }
00690 return err;
00691 }
00692