File indexing completed on 2024-04-28 16:21:39
0001 /* This file is part of the KDE project 0002 Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org> 0003 Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> 0004 Copyright 2004 Tomas Mecir <mecirt@gmail.com> 0005 Copyright 1998-2004 KSpread Team <calligra-devel@kde.org> 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "ValueFormatter.h" 0024 0025 #include "CalculationSettings.h" 0026 #include "Cell.h" 0027 #include "Localization.h" 0028 #include "ValueConverter.h" 0029 #include "SheetsDebug.h" 0030 0031 #include <kcalendarsystem.h> 0032 #include <KLocalizedString> 0033 0034 #include <float.h> 0035 #include <math.h> 0036 0037 using namespace Calligra::Sheets; 0038 0039 ValueFormatter::ValueFormatter(const ValueConverter* converter) 0040 : m_converter(converter) 0041 { 0042 } 0043 0044 const CalculationSettings* ValueFormatter::settings() const 0045 { 0046 return m_converter->settings(); 0047 } 0048 0049 Value ValueFormatter::formatText(const Value &value, Format::Type fmtType, int precision, 0050 Style::FloatFormat floatFormat, const QString &prefix, 0051 const QString &postfix, const QString ¤cySymbol, 0052 const QString &formatString, bool thousandsSep) 0053 { 0054 if (value.isError()) 0055 return Value(value.errorMessage()); 0056 0057 //if we have an array, use its first element 0058 if (value.isArray()) 0059 return formatText(value.element(0, 0), fmtType, precision, 0060 floatFormat, prefix, postfix, currencySymbol, formatString); 0061 0062 Value result; 0063 0064 //step 1: determine formatting that will be used 0065 fmtType = determineFormatting(value, fmtType); 0066 0067 //step 2: format the value ! 0068 bool ok = false; 0069 0070 //text 0071 if (fmtType == Format::Text) { 0072 QString str = m_converter->asString(value).asString(); 0073 if (!str.isEmpty() && str[0] == '\'') 0074 str = str.mid(1); 0075 result = Value(str); 0076 if (value.isBoolean()) { 0077 result.setFormat(Value::fmt_Boolean); 0078 } 0079 ok = true; 0080 } 0081 0082 //datetime 0083 else if (fmtType == Format::DateTime || (Format::isDate(fmtType) && !formatString.isEmpty()) ) { 0084 Value dateValue = m_converter->asDateTime(value, &ok); 0085 if (ok) { 0086 result = Value(dateTimeFormat(dateValue.asDateTime(settings()), fmtType, formatString)); 0087 result.setFormat(Value::fmt_DateTime); 0088 } 0089 } 0090 0091 // 0092 else if (Format::isDate(fmtType)) { 0093 Value dateValue = m_converter->asDate(value, &ok); 0094 if (ok) { 0095 result = Value(dateFormat(dateValue.asDate(settings()), fmtType, formatString)); 0096 result.setFormat(Value::fmt_Date); 0097 } 0098 } 0099 0100 //time 0101 else if (Format::isTime(fmtType)) { 0102 Value timeValue = m_converter->asDateTime(value, &ok); 0103 if (ok) { 0104 result = Value(timeFormat(timeValue.asDateTime(settings()), fmtType, formatString)); 0105 result.setFormat(Value::fmt_Time); 0106 } 0107 } 0108 0109 //fraction 0110 else if (Format::isFraction(fmtType)) { 0111 Value fractionValue = m_converter->asFloat(value, &ok); 0112 if (ok) { 0113 result = Value(fractionFormat(fractionValue.asFloat(), fmtType)); 0114 result.setFormat(Value::fmt_Number); 0115 } 0116 } 0117 0118 //another 0119 else { 0120 // complex 0121 if (value.isComplex()) { 0122 Value complexValue = m_converter->asComplex(value, &ok); 0123 if (ok) { 0124 result = Value(complexFormat(complexValue, precision, fmtType, floatFormat, currencySymbol, thousandsSep)); 0125 result.setFormat(Value::fmt_Number); 0126 } 0127 } 0128 0129 // real number 0130 else { 0131 Number number = m_converter->asFloat(value, &ok).asFloat(); 0132 if (ok) { 0133 result = Value(createNumberFormat(number, precision, fmtType, floatFormat, currencySymbol, formatString, thousandsSep)); 0134 result.setFormat(Value::fmt_Number); 0135 } 0136 } 0137 } 0138 0139 // Only string values can fail. If so, keep the string. 0140 if (!ok) { 0141 QString str = m_converter->asString(value).asString(); 0142 if (!str.isEmpty() && str[0] == '\'') 0143 str = str.mid(1); 0144 result = Value(str); 0145 } 0146 0147 if (!prefix.isEmpty()) 0148 result = Value(prefix + ' ' + result.asString()); 0149 0150 if (!postfix.isEmpty()) 0151 result = Value(result.asString() + ' ' + postfix); 0152 0153 //debugSheets <<"ValueFormatter says:" << str; 0154 return result; 0155 } 0156 0157 Format::Type ValueFormatter::determineFormatting(const Value &value, 0158 Format::Type fmtType) 0159 { 0160 //now, everything depends on whether the formatting is Generic or not 0161 if (fmtType == Format::Generic) { 0162 //here we decide based on value's format... 0163 Value::Format fmt = value.format(); 0164 switch (fmt) { 0165 case Value::fmt_None: 0166 fmtType = Format::Text; 0167 break; 0168 case Value::fmt_Boolean: 0169 fmtType = Format::Text; 0170 break; 0171 case Value::fmt_Number: { 0172 Number val = fabs(value.asFloat()); 0173 if (((val > 10000e+10) || (val < 10000e-10)) && (val != 0.0)) 0174 fmtType = Format::Scientific; 0175 else 0176 fmtType = Format::Number; 0177 } 0178 break; 0179 case Value::fmt_Percent: 0180 fmtType = Format::Percentage; 0181 break; 0182 case Value::fmt_Money: 0183 fmtType = Format::Money; 0184 break; 0185 case Value::fmt_DateTime: 0186 fmtType = Format::DateTime; 0187 break; 0188 case Value::fmt_Date: 0189 fmtType = Format::ShortDate; 0190 break; 0191 case Value::fmt_Time: 0192 fmtType = Format::Time8; // [h]:mm 0193 break; 0194 case Value::fmt_String: 0195 //this should never happen 0196 fmtType = Format::Text; 0197 break; 0198 }; 0199 return fmtType; 0200 } else { 0201 //we'll mostly want to use the given formatting, the only exception 0202 //being Boolean values 0203 0204 //TODO: is this correct? We may also want to convert bools to 1s and 0s 0205 //if we want to display a number... 0206 0207 //TODO: what to do about Custom formatting? We don't support it as of now, 0208 // but we'll have it ... one day, that is ... 0209 if (value.isBoolean()) 0210 return Format::Text; 0211 else 0212 return fmtType; 0213 } 0214 } 0215 0216 0217 QString ValueFormatter::removeTrailingZeros(const QString& str, const QString& decimalSymbol) 0218 { 0219 if (!str.contains(decimalSymbol)) 0220 //no decimal symbol -> nothing to do 0221 return str; 0222 0223 int start = 0; 0224 int cslen = m_converter->settings()->locale()->currencySymbol().length(); 0225 if (str.indexOf('%') != -1) 0226 start = 2; 0227 else if (str.indexOf(m_converter->settings()->locale()->currencySymbol()) == 0228 ((int)(str.length() - cslen))) 0229 start = cslen + 1; 0230 else if ((start = str.indexOf('E')) != -1) 0231 start = str.length() - start; 0232 else 0233 start = 0; 0234 0235 QString result = str; 0236 int i = str.length() - start; 0237 bool bFinished = false; 0238 while (!bFinished && i > 0) { 0239 QChar ch = result[i - 1]; 0240 if (ch == '0') 0241 result.remove(--i, 1); 0242 else { 0243 bFinished = true; 0244 if (result.mid(i - decimalSymbol.length(), decimalSymbol.length()) == decimalSymbol) 0245 result.remove(i - decimalSymbol.length(), decimalSymbol.length()); 0246 } 0247 } 0248 return result; 0249 } 0250 0251 QString ValueFormatter::createNumberFormat(Number value, int precision, 0252 Format::Type fmt, Style::FloatFormat floatFormat, const QString& currencySymbol, 0253 const QString& _formatString, bool thousandsSep) 0254 { 0255 QString prefix, postfix; 0256 QString formatString(_formatString); 0257 0258 int numExpDigits = 0; // QString::number() will be used 0259 // try to split formatstring into prefix, formatstring and postfix. 0260 if (!formatString.isEmpty() ) { 0261 QRegExp re( QLatin1String( "^([^0#.,E+]*)([0#.,E+]*)(.*)$" ) ); 0262 if( re.exactMatch( formatString ) ) { 0263 prefix = re.cap( 1 ); 0264 formatString = re.cap( 2 ); 0265 postfix = re.cap( 3 ); 0266 } 0267 if (formatString.isEmpty()) { 0268 return prefix + postfix; 0269 } else if (formatString.contains(QLatin1Char('.'))) { 0270 // if it contains an 'E', precision is zeros between '.' and 'E' 0271 int len = formatString.indexOf(QLatin1Char('E')); 0272 if (len == -1) { 0273 len = formatString.length(); 0274 } 0275 precision = len - formatString.indexOf(QLatin1Char('.')) - 1; 0276 } else if (precision != -1) { 0277 precision = 0; 0278 } 0279 if (formatString.contains("E+")) { 0280 numExpDigits = formatString.length() - formatString.indexOf("E+") - 2; 0281 } 0282 } 0283 0284 int p = precision; 0285 if (p == -1) { 0286 // If precision (obtained from the cell style) is -1 (arbitrary), use the document default decimal precision 0287 // and if that value is -1 too then use either automatic decimal place adjustment or a hardcoded default. 0288 p = settings()->defaultDecimalPrecision(); 0289 if (p == -1) { 0290 if (fmt == Format::Number) { 0291 QString s = QString::number(double(numToDouble(value))); 0292 int _p = s.indexOf('.'); 0293 p = _p >= 0 ? qMax(0, 10 - _p) : 0; 0294 } else { 0295 p = 2; // hardcoded default 0296 } 0297 } 0298 } 0299 0300 QString localizedNumber; 0301 int pos = 0; 0302 0303 // Always unsigned ? 0304 if ((floatFormat == Style::AlwaysUnsigned) && (value < 0.0)) 0305 value *= -1.0; 0306 0307 //multiply value by 100 for percentage format 0308 if (fmt == Format::Percentage) 0309 value *= 100; 0310 0311 // round the number, based on desired precision if not scientific is chosen 0312 //(scientific has relative precision) 0313 if (fmt != Format::Scientific) { 0314 // this will avoid displaying negative zero, i.e "-0.0000" 0315 // TODO: is this really a good solution? 0316 if (fabs(value) < DBL_EPSILON) value = 0.0; 0317 0318 double m[] = { 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10 }; 0319 double mm = (p > 10) ? ::pow(10.0, p) : m[p]; 0320 bool neg = value < 0; 0321 value = floor(numToDouble(fabs(value)) * mm + 0.5) / mm; 0322 if (neg) value = -value; 0323 } 0324 0325 double val = numToDouble(value); 0326 switch (fmt) { 0327 case Format::Number: 0328 localizedNumber = m_converter->settings()->locale()->formatNumber(val, p); 0329 break; 0330 case Format::Percentage: 0331 localizedNumber = m_converter->settings()->locale()->formatNumber(val, p); 0332 if(!postfix.endsWith('%')) // percent formattings needs to end with a "%"-sign 0333 postfix += '%'; 0334 break; 0335 case Format::Money: 0336 // There is no substitute for this in QLocale (toCurrencyString cannot set precision) :( 0337 if (_formatString.isEmpty()) { 0338 localizedNumber = m_converter->settings()->locale()->formatMoney(val, currencySymbol, p); 0339 } else { 0340 localizedNumber = m_converter->settings()->locale()->formatNumber(val, p); 0341 } 0342 break; 0343 case Format::Scientific: { 0344 // TODO: port to QLocale or other (icu?) formatting 0345 const QString decimalSymbol = m_converter->settings()->locale()->decimalSymbol(); 0346 localizedNumber = QString::number(val, 'E', p); 0347 if ((pos = localizedNumber.indexOf('.')) != -1) { 0348 localizedNumber.replace(pos, 1, decimalSymbol); 0349 } 0350 if (numExpDigits > 0) { 0351 // adjust number of exponent digits 0352 int firstDigit = localizedNumber.indexOf('E') + 2; 0353 int digits = localizedNumber.length() - firstDigit; 0354 if (digits > numExpDigits) { 0355 // remove leading 0 if present 0356 if (localizedNumber.at(firstDigit) == '0') { 0357 localizedNumber.remove(firstDigit, 1); 0358 } 0359 } else { 0360 for (int i = digits; i < numExpDigits; ++i) { 0361 localizedNumber.insert(firstDigit, '0'); 0362 } 0363 } 0364 } 0365 break; 0366 } 0367 default : 0368 //other formatting? 0369 // This happens with Format::Custom... 0370 debugSheets << "Wrong usage of ValueFormatter::createNumberFormat fmt=" << fmt << ""; 0371 break; 0372 } 0373 0374 //prepend positive sign if needed 0375 if ((floatFormat == Style::AlwaysSigned) && value >= 0) 0376 if (m_converter->settings()->locale()->positiveSign().isEmpty()) 0377 localizedNumber = '+' + localizedNumber; 0378 0379 if (fmt != Format::Scientific) { 0380 // Remove trailing zeros and the decimal point if necessary 0381 // unless the number has no decimal point 0382 if (precision == -1) { 0383 QString decimalSymbol = m_converter->settings()->locale()->decimalSymbol(); 0384 if (decimalSymbol.isNull()) 0385 decimalSymbol = '.'; 0386 0387 localizedNumber = removeTrailingZeros(localizedNumber, decimalSymbol); 0388 } 0389 0390 // Remove thousands separators if necessary 0391 if (!thousandsSep) { 0392 const QString separator = m_converter->settings()->locale()->thousandsSeparator(); 0393 if (!separator.isNull()) { 0394 localizedNumber.remove(separator); 0395 } 0396 } 0397 } 0398 0399 // remove negative sign if prefix already ends with '-' 0400 if (!prefix.isEmpty() && prefix[prefix.length()-1] == '-' && !localizedNumber.isEmpty() && localizedNumber[0] == '-') { 0401 localizedNumber = localizedNumber.mid(1); 0402 } 0403 0404 return prefix + localizedNumber + postfix; 0405 } 0406 0407 QString ValueFormatter::fractionFormat(Number value, Format::Type fmtType) 0408 { 0409 bool isNegative = value < 0; 0410 QString prefix = isNegative ? "-" : ""; 0411 value = abs(value); 0412 Number result = value - floor(numToDouble(value)); 0413 int index; 0414 int limit = 0; 0415 0416 /* return w/o fraction part if not necessary */ 0417 if (result == 0) 0418 return prefix + QString::number((double) numToDouble(value)); 0419 0420 switch (fmtType) { 0421 case Format::fraction_half: 0422 index = 2; 0423 break; 0424 case Format::fraction_quarter: 0425 index = 4; 0426 break; 0427 case Format::fraction_eighth: 0428 index = 8; 0429 break; 0430 case Format::fraction_sixteenth: 0431 index = 16; 0432 break; 0433 case Format::fraction_tenth: 0434 index = 10; 0435 break; 0436 case Format::fraction_hundredth: 0437 index = 100; 0438 break; 0439 case Format::fraction_one_digit: 0440 index = 3; 0441 limit = 9; 0442 break; 0443 case Format::fraction_two_digits: 0444 index = 4; 0445 limit = 99; 0446 break; 0447 case Format::fraction_three_digits: 0448 index = 5; 0449 limit = 999; 0450 break; 0451 default: 0452 debugSheets << "Error in Fraction format"; 0453 return prefix + QString::number((double) numToDouble(value)); 0454 break; 0455 } /* switch */ 0456 0457 0458 /* handle halves, quarters, tenths, ... */ 0459 if (fmtType != Format::fraction_three_digits 0460 && fmtType != Format::fraction_two_digits 0461 && fmtType != Format::fraction_one_digit) { 0462 Number calc = 0; 0463 int index1 = 0; 0464 Number diff = result; 0465 for (int i = 1; i <= index; i++) { 0466 calc = i * 1.0 / index; 0467 if (fabs(result - calc) < diff) { 0468 index1 = i; 0469 diff = fabs(result - calc); 0470 } 0471 } 0472 if (index1 == 0) return prefix + QString("%1").arg((double) floor(numToDouble(value))); 0473 if (index1 == index) return prefix + QString("%1").arg((double) floor(numToDouble(value)) + 1); 0474 if (floor(numToDouble(value)) == 0) 0475 return prefix + QString("%1/%2").arg(index1).arg(index); 0476 0477 return prefix + QString("%1 %2/%3") 0478 .arg((double) floor(numToDouble(value))) 0479 .arg(index1) 0480 .arg(index); 0481 } 0482 0483 0484 /* handle Format::fraction_one_digit, Format::fraction_two_digit and Format::fraction_three_digit style */ 0485 double target = numToDouble(result); 0486 double numerator = 1; 0487 double denominator = 1; 0488 double bestNumerator = 0; 0489 double bestDenominator = 1; 0490 double bestDist = target; 0491 0492 // as soon as either numerator or denominator gets above the limit, we're done 0493 while (numerator <= limit && denominator <= limit) { 0494 double dist = abs((numerator / denominator) - target); 0495 if (dist < bestDist) { 0496 bestDist = dist; 0497 bestNumerator = numerator; 0498 bestDenominator = denominator; 0499 } 0500 if (numerator / denominator > target) { 0501 denominator++; 0502 } else { 0503 numerator++; 0504 } 0505 } 0506 0507 if (bestNumerator == 0) 0508 return prefix + QString().setNum((double) floor(numToDouble(value))); 0509 else if (bestDenominator == bestNumerator) 0510 return prefix + QString().setNum((double) floor(numToDouble(value + 1))); 0511 else { 0512 if (floor(numToDouble(value)) == 0) 0513 return prefix + QString("%1/%2").arg(bestNumerator).arg(bestDenominator); 0514 else 0515 return prefix + QString("%1 %2/%3") 0516 .arg((double)floor(numToDouble(value))) 0517 .arg(bestNumerator) 0518 .arg(bestDenominator); 0519 } 0520 } 0521 0522 QString ValueFormatter::timeFormat(const QDateTime &_dt, Format::Type fmtType, const QString& formatString) 0523 { 0524 if (!formatString.isEmpty()) { 0525 return _dt.toString( formatString ); 0526 } 0527 0528 const QDateTime dt(_dt.toUTC()); 0529 QString result; 0530 if (fmtType == Format::Time) 0531 result = m_converter->settings()->locale()->formatTime(dt.time(), false); 0532 else if (fmtType == Format::SecondeTime) 0533 result = m_converter->settings()->locale()->formatTime(dt.time(), true); 0534 else { 0535 const int d = settings()->referenceDate().daysTo(dt.date()); 0536 int h, m, s; 0537 if (fmtType != Format::Time6 && fmtType != Format::Time7 && fmtType != Format::Time8) { // time 0538 h = dt.time().hour(); 0539 m = dt.time().minute(); 0540 s = dt.time().second(); 0541 } else if (d >= 0) { // positive duration 0542 h = dt.time().hour() + 24 * d; 0543 m = dt.time().minute(); 0544 s = dt.time().second(); 0545 } else { // negative duration 0546 s = (60 - dt.time().second()) % 60; 0547 m = (60 - dt.time().minute() - ((s == 0) ? 0 : 1)) % 60; 0548 h = -(dt.time().hour() + 24 * d) - ((m == 0 && s == 0) ? 0 : 1); 0549 } 0550 const bool pm = (h > 12); 0551 const QString sign = d < 0 ? QString('-') : QString(""); 0552 0553 if (fmtType == Format::Time1) { // 9:01 AM 0554 result = QString("%1:%2 %3") 0555 .arg(QString::number(pm ? h - 12 : h), 1) 0556 .arg(QString::number(m), 2, '0') 0557 .arg(pm ? i18n("PM") : i18n("AM")); 0558 } else if (fmtType == Format::Time2) { // 9:01:05 AM 0559 result = QString("%1:%2:%3 %4") 0560 .arg(QString::number(pm ? h - 12 : h), 1) 0561 .arg(QString::number(m), 2, '0') 0562 .arg(QString::number(s), 2, '0') 0563 .arg(pm ? i18n("PM") : i18n("AM")); 0564 } else if (fmtType == Format::Time3) { // 9 h 01 min 28 s 0565 result = QString("%1 %2 %3 %4 %5 %6") 0566 .arg(QString::number(h), 2, '0') 0567 .arg(i18n("h")) 0568 .arg(QString::number(m), 2, '0') 0569 .arg(i18n("min")) 0570 .arg(QString::number(s), 2, '0') 0571 .arg(i18n("s")); 0572 } else if (fmtType == Format::Time4) { // 9:01 0573 result = QString("%1:%2") 0574 .arg(QString::number(h), 1) 0575 .arg(QString::number(m), 2, '0'); 0576 } else if (fmtType == Format::Time5) { // 9:01:12 0577 result = QString("%1:%2:%3") 0578 .arg(QString::number(h), 1) 0579 .arg(QString::number(m), 2, '0') 0580 .arg(QString::number(s), 2, '0'); 0581 } else if (fmtType == Format::Time6) { // [mm]:ss 0582 result = sign + QString("%1:%2") 0583 .arg(QString::number(m + h * 60), 2, '0') 0584 .arg(QString::number(s), 2, '0'); 0585 } else if (fmtType == Format::Time7) { // [h]:mm:ss 0586 result = sign + QString("%1:%2:%3") 0587 .arg(QString::number(h), 1) 0588 .arg(QString::number(m), 2, '0') 0589 .arg(QString::number(s), 2, '0'); 0590 } else if (fmtType == Format::Time8) { // [h]:mm 0591 result = sign + QString("%1:%2") 0592 .arg(QString::number(h), 1) 0593 .arg(QString::number(m), 2, '0'); 0594 } 0595 } 0596 return result; 0597 } 0598 0599 QString ValueFormatter::dateTimeFormat(const QDateTime &_dt, Format::Type fmtType, const QString& formatString ) 0600 { 0601 if( !formatString.isEmpty() ) { 0602 if (formatString.contains('X')) { // if we have the special extra-short month in the format string 0603 int monthPos = formatString.indexOf('X'); 0604 QString before = formatString.left(monthPos); // get string before and after the extra-short month sign 0605 QString after = formatString.right(formatString.size() - monthPos - 1); 0606 QString monthShort = _dt.toString("MMM").left(1); // format the month as extra-short (only 1st letter) 0607 return _dt.toString( before ) + monthShort + _dt.toString( after ); // and construct the final date 0608 } 0609 0610 return _dt.toString( formatString ); 0611 } 0612 0613 Q_UNUSED(fmtType); 0614 QString result; 0615 // pretty lame, just assuming something for the format 0616 // TODO: locale-aware formatting 0617 result += dateFormat(_dt.date(), Format::ShortDate) + ' ' + timeFormat(_dt, Format::Time1); 0618 return result; 0619 } 0620 0621 QString ValueFormatter::dateFormat(const QDate &date, Format::Type fmtType, const QString& formatString ) 0622 { 0623 if( !formatString.isEmpty() ) { 0624 return date.toString( formatString ); 0625 } 0626 0627 QString tmp; 0628 if (fmtType == Format::ShortDate) { 0629 tmp = m_converter->settings()->locale()->formatDate(date, KLocale::ShortDate); 0630 } else if (fmtType == Format::TextDate) { 0631 tmp = m_converter->settings()->locale()->formatDate(date, KLocale::LongDate); 0632 } else if (fmtType == Format::Date1) { /*18-Feb-99 */ 0633 tmp = QString().sprintf("%02d", date.day()) + 0634 '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0635 '-' + QString::number(date.year()).right(2); 0636 } else if (fmtType == Format::Date2) { /*18-Feb-1999 */ 0637 tmp = QString().sprintf("%02d", date.day()) + 0638 '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0639 '-' + QString::number(date.year()); 0640 } else if (fmtType == Format::Date3) { /*18-Feb */ 0641 tmp = QString().sprintf("%02d", date.day()) + 0642 '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber); 0643 } else if (fmtType == Format::Date4) { /*18-05 */ 0644 tmp = QString().sprintf("%02d", date.day()) + 0645 '-' + QString().sprintf("%02d", date.month()); 0646 } else if (fmtType == Format::Date5) { /*18/05/00 */ 0647 tmp = QString().sprintf("%02d", date.day()) + 0648 '/' + QString().sprintf("%02d", date.month()) + 0649 '/' + QString::number(date.year()).right(2); 0650 } else if (fmtType == Format::Date6) { /*18/05/1999 */ 0651 tmp = QString().sprintf("%02d", date.day()) + 0652 '/' + QString().sprintf("%02d", date.month()) + 0653 '/' + QString::number(date.year()); 0654 } else if (fmtType == Format::Date7) { /*Feb-99 */ 0655 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0656 '-' + QString::number(date.year()).right(2); 0657 } else if (fmtType == Format::Date8) { /*February-99 */ 0658 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + 0659 '-' + QString::number(date.year()).right(2); 0660 } else if (fmtType == Format::Date9) { /*February-1999 */ 0661 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + 0662 '-' + QString::number(date.year()); 0663 } else if (fmtType == Format::Date10) { /*F-99 */ 0664 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber).at(0) + 0665 '-' + QString::number(date.year()).right(2); 0666 } else if (fmtType == Format::Date11) { /*18/Feb */ 0667 tmp = QString().sprintf("%02d", date.day()) 0668 + '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber); 0669 } else if (fmtType == Format::Date12) { /*18/02 */ 0670 tmp = QString().sprintf("%02d", date.day()) + 0671 '/' + QString().sprintf("%02d", date.month()); 0672 } else if (fmtType == Format::Date13) { /*18/Feb/1999 */ 0673 tmp = QString().sprintf("%02d", date.day()) + 0674 '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0675 '/' + QString::number(date.year()); 0676 } else if (fmtType == Format::Date14) { /*2000/Feb/18 */ 0677 tmp = QString::number(date.year()) + 0678 '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0679 '/' + QString().sprintf("%02d", date.day()); 0680 } else if (fmtType == Format::Date15) { /*2000-Feb-18 */ 0681 tmp = QString::number(date.year()) + 0682 '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0683 '-' + QString().sprintf("%02d", date.day()); 0684 } else if (fmtType == Format::Date16) { /*2000-02-18 */ 0685 tmp = QString::number(date.year()) + 0686 '-' + QString().sprintf("%02d", date.month()) + 0687 '-' + QString().sprintf("%02d", date.day()); 0688 } else if (fmtType == Format::Date17) { /*2 february 2000 */ 0689 tmp = QString().sprintf("%d", date.day()) + 0690 ' ' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + 0691 ' ' + QString::number(date.year()); 0692 } else if (fmtType == Format::Date18) { /*02/18/1999 */ 0693 tmp = QString().sprintf("%02d", date.month()) + 0694 '/' + QString().sprintf("%02d", date.day()) + 0695 '/' + QString::number(date.year()); 0696 } else if (fmtType == Format::Date19) { /*02/18/99 */ 0697 tmp = QString().sprintf("%02d", date.month()) + 0698 '/' + QString().sprintf("%02d", date.day()) + 0699 '/' + QString::number(date.year()).right(2); 0700 } else if (fmtType == Format::Date20) { /*Feb/18/99 */ 0701 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0702 '/' + QString().sprintf("%02d", date.day()) + 0703 '/' + QString::number(date.year()).right(2); 0704 } else if (fmtType == Format::Date21) { /*Feb/18/1999 */ 0705 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0706 '/' + QString().sprintf("%02d", date.day()) + 0707 '/' + QString::number(date.year()); 0708 } else if (fmtType == Format::Date22) { /*Feb-1999 */ 0709 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0710 '-' + QString::number(date.year()); 0711 } else if (fmtType == Format::Date23) { /*1999 */ 0712 tmp = QString::number(date.year()); 0713 } else if (fmtType == Format::Date24) { /*99 */ 0714 tmp = QString::number(date.year()).right(2); 0715 } else if (fmtType == Format::Date25) { /*2000/02/18 */ 0716 tmp = QString::number(date.year()) + 0717 '/' + QString().sprintf("%02d", date.month()) + 0718 '/' + QString().sprintf("%02d", date.day()); 0719 } else if (fmtType == Format::Date26) { /*2000/Feb/18 */ 0720 tmp = QString::number(date.year()) + 0721 '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0722 '/' + QString().sprintf("%02d", date.day()); 0723 } else if (fmtType == Format::Date27) { /*Feb/99 */ 0724 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0725 '/' + QString::number(date.year()).right(2); 0726 } else if (fmtType == Format::Date28) { /*Feb/1999 */ 0727 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + 0728 '/' + QString::number(date.year()); 0729 } else if (fmtType == Format::Date29) { /*February/99 */ 0730 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + 0731 '/' + QString::number(date.year()).right(2); 0732 } else if (fmtType == Format::Date30) { /*February/1999 */ 0733 tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + 0734 '/' + QString::number(date.year()); 0735 } else if (fmtType == Format::Date31) { /*18-02 */ 0736 tmp = QString().sprintf("%02d", date.day()) + 0737 '-' + QString().sprintf("%02d", date.month()); 0738 } else if (fmtType == Format::Date32) { /*02/99 */ 0739 tmp = QString().sprintf("%02d", date.month()) + '/' + 0740 QString::number(date.year()).right(2); 0741 } else if (fmtType == Format::Date33) { /*02-99 */ 0742 tmp = QString().sprintf("%02d", date.month()) + 0743 '-' + QString::number(date.year()).right(2); 0744 } else if (fmtType == Format::Date34 || fmtType == Format::Date35) { /*Mon, 2 Feb 2000 and Mon, 2 February 2000 */ 0745 QLocale l(QLocale::English); 0746 tmp = l.toString(date, fmtType == Format::Date34 ? "ddd d MMM yy" : "dddd d MMM yyyy"); 0747 } else { /*fallback... */ 0748 tmp = m_converter->settings()->locale()->formatDate(date, KLocale::ShortDate); 0749 } 0750 0751 // Missing compared with gnumeric: 0752 // "m/d/yy h:mm", /* 20 */ 0753 // "m/d/yyyy h:mm", /* 21 */ 0754 // "mmm/ddd/yy", /* 12 */ 0755 // "mmm/ddd/yyyy", /* 13 */ 0756 // "mm/ddd/yy", /* 14 */ 0757 // "mm/ddd/yyyy", /* 15 */ 0758 0759 return tmp; 0760 } 0761 0762 QString ValueFormatter::complexFormat(const Value& value, int precision, 0763 Format::Type formatType, 0764 Style::FloatFormat floatFormat, 0765 const QString& currencySymbol, 0766 bool thousandsSep) 0767 { 0768 // FIXME Stefan: percentage, currency and scientific formats! 0769 QString str; 0770 const Number real = value.asComplex().real(); 0771 const Number imag = value.asComplex().imag(); 0772 str = createNumberFormat(real, precision, formatType, floatFormat, QString(), QString(), thousandsSep); 0773 str += createNumberFormat(imag, precision, formatType, Style::AlwaysSigned, currencySymbol, QString(), thousandsSep); 0774 str += 'i'; 0775 return str; 0776 }