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 &currencySymbol,
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 }