Warning, file /office/calligra/libs/odf/KoOdfNumberStyles.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004-2006 David Faure <faure@kde.org>
0003    Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
0004    Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License version 2 as published by the Free Software Foundation.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KoOdfNumberStyles.h"
0022 
0023 #include "KoGenStyles.h"
0024 #include "KoXmlNS.h"
0025 
0026 #include <QBuffer>
0027 #include <QDateTime>
0028 #include <QTime>
0029 
0030 #include <klocalizedstring.h>
0031 #include <OdfDebug.h>
0032 
0033 #include <KoXmlReader.h>
0034 #include <KoXmlWriter.h>
0035 #include <writeodf/writeodfnumber.h>
0036 
0037 #include <math.h>
0038 
0039 using namespace writeodf;
0040 
0041 namespace KoOdfNumberStyles
0042 {
0043 
0044     static bool saveOdfTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text, bool &antislash);
0045     static void parseOdfDatelocale(KoXmlWriter &elementWriter, QString &format, QString &text);
0046     static bool saveOdflocaleTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text);
0047     static void parseOdfTimelocale(KoXmlWriter &elementWriter, QString &format, QString &text);
0048     static void addCalligraNumericStyleExtension(KoXmlWriter &elementWriter, const QString &_suffix, const QString &_prefix);
0049 
0050 
0051 QString format(const QString &value, const NumericStyleFormat &format)
0052 {
0053     switch (format.type) {
0054         case Number: {
0055             bool ok;
0056             qreal v = value.toDouble(&ok);
0057             return ok ? formatNumber(v, format.formatStr, format.precision) : value;
0058         } break;
0059         case Boolean: {
0060             return formatBoolean(value, format.formatStr);
0061         } break;
0062         case Date: {
0063             bool ok;
0064             int v = value.toInt(&ok);
0065             return ok ? formatDate(v, format.formatStr) : value;
0066         } break;
0067         case Time: {
0068             bool ok;
0069             qreal v = value.toDouble(&ok);
0070             return ok ? formatTime(v, format.formatStr) : value;
0071         } break;
0072         case Percentage: {
0073             return formatPercent(value, format.formatStr, format.precision);
0074         } break;
0075         case Currency: {
0076             bool ok;
0077             qreal v = value.toDouble(&ok);
0078             return ok ? formatCurrency(v, format.formatStr, format.currencySymbol, format.precision) : value;
0079         } break;
0080         case Scientific: {
0081             bool ok;
0082             qreal v = value.toDouble(&ok);
0083             return ok ? formatScientific(v, format.formatStr, format.precision) : value;
0084         } break;
0085         case Fraction: {
0086             bool ok;
0087             qreal v = value.toDouble(&ok);
0088             return ok ? formatFraction(v, format.formatStr) : value;
0089         } break;
0090         case Text: {
0091             return value;
0092         } break;
0093     }
0094     return value;
0095 }
0096 
0097 QString formatNumber(qreal value, const QString &format, int precision)
0098 {
0099     QString result;
0100     int start = 0;
0101     bool showNegative = format.startsWith('-');
0102     if (showNegative)
0103         start = 1;
0104     for (int i = start; i < format.length(); ++i) {
0105         QChar c = format[ i ];
0106         switch (c.unicode()) {
0107             case '.':
0108             case ',':
0109             case '#':
0110             case '0':
0111             case '?': {
0112 //                bool grouping = false;
0113                 bool gotDot = false;
0114                 bool gotE = false;
0115                 bool gotFraction = false;
0116                 int decimalPlaces = 0;
0117                 int integerDigits = 0;
0118                 int optionalDecimalPlaces = 0;
0119                 int optionalIntegerDigits = 0;
0120                 int exponentDigits = 0;
0121                 int numeratorDigits = 0;
0122                 int denominatorDigits = 0;
0123                 char ch = format[ i ].toLatin1();
0124                 do {
0125                     if (ch == '.') {
0126                         gotDot = true;
0127                     } else if (ch == ',') {
0128                 //        grouping = true; 
0129                     } else if (ch == 'E' || ch == 'e') {
0130                         //SET_TYPE_OR_RETURN(KoGenStyle::NumericScientificStyle);
0131 
0132                         if (i >= format.length() - 1) break;
0133                         const char chN = format[ i + 1 ].toLatin1();
0134                         if (chN == '-' || chN == '+') {
0135                             gotE = true;
0136                             ++i;
0137                         }
0138                     } else if (ch == '0' && gotE) {
0139                         ++exponentDigits;
0140                     } else if (ch == '0' && !gotDot && !gotFraction) {
0141                         ++integerDigits;
0142                     } else if (ch == '#' && !gotDot && !gotFraction) {
0143                         ++optionalIntegerDigits;
0144                     } else if (ch == '0' && gotDot && !gotFraction) {
0145                         ++decimalPlaces;
0146                     } else if (ch == '#' && gotDot && !gotFraction) {
0147                         ++optionalDecimalPlaces;
0148                     } else if (ch == '?' && !gotFraction) {
0149                         ++numeratorDigits;
0150                     } else if (ch == '?' && gotFraction) {
0151                         ++denominatorDigits;
0152                     } else if (ch == '/') {
0153                         //SET_TYPE_OR_RETURN(KoGenStyle::NumericFractionStyle);
0154                         if (gotDot) return QString(); // invalid
0155                         gotFraction = true;
0156                     }
0157 
0158                     if (i >= format.length() - 1) break;
0159                     ch = format[ ++i ].toLatin1();
0160 
0161                     if (ch == ' ') {
0162                         // spaces are not allowed - but there's an exception: if this is a fraction. Let's check for '?' or '/'
0163                         const char c = format[ i + 1 ].toLatin1();
0164                         if (c == '?' || c == '/')
0165                             ch = format[ ++i ].toLatin1();
0166                     }
0167                 } while (i < format.length() && (ch == '.' || ch == ',' || ch == '#' || ch == '0' || ch == 'E' || ch == 'e' || ch == '?' || ch == '/'));
0168                 if (!(ch == '.' || ch == ',' || ch == '#' || ch == '0' || ch == 'E' || ch == 'e' || ch == '?' || ch == '/')) {
0169                     --i;
0170                 }
0171 
0172                 QString v(QString::number(qAbs(value), 'f', precision >= 0 ? precision : (optionalDecimalPlaces + decimalPlaces)));
0173                 int p = v.indexOf('.');
0174                 QString integerValue = p >= 0 ? v.left(p) : v;
0175                 if (integerValue.length() < integerDigits)
0176                     integerValue.prepend(QString().fill('0', integerDigits - integerValue.length()));
0177                 QString decimalValue =  p >= 0 ? v.mid(p + 1) : QString();
0178                 if (decimalValue.length() < decimalPlaces)
0179                     decimalValue.append(QString().fill('0', decimalPlaces - decimalValue.length()));
0180 
0181                 if (showNegative && value < 0)
0182                     result.append('-');
0183                 result.append(integerValue);
0184                 if (!decimalValue.isEmpty())
0185                     result.append('.' + decimalValue);
0186             } break;
0187             case '\\': { // backslash escapes the next char
0188                 if (i < format.length() - 1) {
0189                     result.append(format[ ++i ]);
0190                 }
0191             } break;
0192             default:
0193                 result.append(c);
0194                 break;
0195         }
0196     }
0197 
0198     return result;
0199 }
0200 
0201 QString formatBoolean(const QString &value, const QString &format)
0202 {
0203     Q_UNUSED(format);
0204     bool ok = false;
0205     int v = value.toInt(&ok);
0206     return ok && v != 0 ? "TRUE" : "FALSE";
0207 }
0208 
0209 QString formatDate(int value, const QString &format)
0210 {
0211     QDateTime dt(QDate(1899, 12, 30)); // reference date
0212     dt = dt.addDays(value);
0213     return dt.toString(format);
0214 }
0215 
0216 QString formatTime(qreal value, const QString &format)
0217 {
0218     QTime t(0,0,0);
0219     t = t.addSecs(qRound(value * 86400.0)); // 24 hours
0220     return t.toString(format);
0221 }
0222 
0223 QString formatCurrency(qreal value, const QString &format, const QString& currencySymbol, int precision)
0224 {
0225     if (currencySymbol == "CCC") // undocumented hack, see doc attached to comment 6 at bug 282972
0226         return QLocale().toCurrencyString(value, "USD");
0227     if (format.isEmpty()) // no format means use locale format
0228         return QLocale().toCurrencyString(value, currencySymbol.isEmpty() ? QLocale().currencySymbol(QLocale::CurrencySymbol)
0229                                                                           : currencySymbol);
0230     return formatNumber(value, format, precision);
0231 }
0232 
0233 QString formatScientific(qreal value, const QString &format, int precision)
0234 {
0235     Q_UNUSED(format);
0236     QString v(QString::number(value, 'E', precision));
0237     int pos = v.indexOf('.');
0238     if (pos != -1) {
0239         v.replace(pos, 1, QLocale().decimalPoint());
0240     }
0241     return v;
0242 }
0243 
0244 QString formatFraction(qreal value, const QString &format)
0245 {
0246     QString prefix = value < 0 ? "-" : "";
0247     value = fabs(value);
0248     qreal result = value - floor(value);
0249 
0250     if (result == 0) // return w/o fraction part if not necessary
0251         return prefix + QString::number(value);
0252 
0253     int index = 0;
0254     int limit = 0;
0255     if (format.endsWith(QLatin1String("/2"))) {
0256         index = 2;
0257     } else if (format.endsWith(QLatin1String("/4"))) {
0258         index = 4;
0259     } else if (format.endsWith(QLatin1String("/8"))) {
0260         index = 8;
0261     } else if (format.endsWith(QLatin1String("/16"))) {
0262         index = 16;
0263     } else if (format.endsWith(QLatin1String("/10"))) {
0264         index = 10;
0265     } else if (format.endsWith(QLatin1String("/100"))) {
0266         index = 100;
0267     } else if (format.endsWith(QLatin1String("/?"))) {
0268         index = 3;
0269         limit = 9;
0270     } else if (format.endsWith(QLatin1String("/??"))) {
0271         index = 4;
0272         limit = 99;
0273     } else if (format.endsWith(QLatin1String("/???"))) {
0274         index = 5;
0275         limit = 999;
0276     } else { // fallback
0277         return prefix + QString::number(value);
0278     }
0279 
0280     // handle halves, quarters, tenths, ...
0281     if (!format.endsWith(QLatin1String("/?")) &&
0282         !format.endsWith(QLatin1String("/??")) &&
0283         !format.endsWith(QLatin1String("/???"))) {
0284         qreal calc = 0;
0285         int index1 = 0;
0286         qreal diff = result;
0287         for (int i = 1; i <= index; i++) {
0288             calc = i * 1.0 / index;
0289             if (fabs(result - calc) < diff) {
0290                 index1 = i;
0291                 diff = fabs(result - calc);
0292             }
0293         }
0294         if (index1 == 0)
0295             return prefix + QString("%1").arg(floor(value));
0296         if (index1 == index)
0297             return prefix + QString("%1").arg(floor(value) + 1);
0298         if (floor(value) == 0)
0299             return prefix + QString("%1/%2").arg(index1).arg(index);
0300         return prefix + QString("%1 %2/%3").arg(floor(value)).arg(index1).arg(index);
0301     }
0302 
0303     // handle Format::fraction_one_digit, Format::fraction_two_digit and Format::fraction_three_digit style
0304     qreal target = result;
0305     qreal numerator = 1;
0306     qreal denominator = 1;
0307     qreal bestNumerator = 0;
0308     qreal bestDenominator = 1;
0309     qreal bestDist = target;
0310 
0311     // as soon as either numerator or denominator gets above the limit, we're done
0312     while (numerator <= limit && denominator <= limit) {
0313         qreal dist = fabs((numerator / denominator) - target);
0314         if (dist < bestDist) {
0315             bestDist = dist;
0316             bestNumerator = numerator;
0317             bestDenominator = denominator;
0318         }
0319         if (numerator / denominator > target) {
0320             ++denominator;
0321         } else {
0322             ++numerator;
0323         }
0324     }
0325 
0326     if (bestNumerator == 0)
0327         return prefix + QString().setNum(floor(value));
0328     if (bestDenominator == bestNumerator)
0329         return prefix + QString().setNum(floor(value + 1));
0330     if (floor(value) == 0)
0331         return prefix + QString("%1/%2").arg(bestNumerator).arg(bestDenominator);
0332     return prefix + QString("%1 %2/%3").arg(floor(value)).arg(bestNumerator).arg(bestDenominator);
0333 
0334 }
0335 
0336 QString formatPercent(const QString &value, const QString &/*format*/, int precision)
0337 {
0338     if (value.contains('.')) {
0339         bool ok;
0340         qreal v = value.toDouble(&ok);
0341         if (ok)
0342             return QString::number(v * 100., 'f', precision) + QLatin1String("%");
0343     }
0344     return value;
0345 }
0346 
0347 // OO spec 2.5.4. p68. Conversion to Qt format: see qdate.html
0348 // OpenCalcImport::loadFormat has similar code, but slower, intermixed with other stuff,
0349 // lacking long-textual forms.
0350 QPair<QString, NumericStyleFormat> loadOdfNumberStyle(const KoXmlElement &parent)
0351 {
0352     NumericStyleFormat dataStyle;
0353 
0354     const QString localName = parent.localName();
0355     if (localName == "number-style")
0356         dataStyle.type = Number;
0357     else if (localName == "currency-style")
0358         dataStyle.type = Currency;
0359     else if (localName == "percentage-style")
0360         dataStyle.type = Percentage;
0361     else if (localName == "boolean-style")
0362         dataStyle.type = Boolean;
0363     else if (localName == "text-style")
0364         dataStyle.type = Text;
0365     else if (localName == "date-style")
0366         dataStyle.type = Date;
0367     else if (localName == "time-style")
0368         dataStyle.type = Time;
0369 
0370     QString format;
0371     int precision = -1;
0372     int leadingZ  = 1;
0373 
0374     bool thousandsSep = false;
0375     //todo negred
0376     //bool negRed = false;
0377     bool ok = false;
0378     int i = 0;
0379     KoXmlElement e;
0380     QString prefix;
0381     QString suffix;
0382     forEachElement(e, parent) {
0383         if (e.namespaceURI() != KoXmlNS::number)
0384             continue;
0385         QString localName = e.localName();
0386         const QString numberStyle = e.attributeNS(KoXmlNS::number, "style", QString());
0387         const bool shortForm = numberStyle == "short" || numberStyle.isEmpty();
0388         if (localName == "day") {
0389             format += shortForm ? "d" : "dd";
0390         } else if (localName == "day-of-week") {
0391             format += shortForm ? "ddd" : "dddd";
0392         } else if (localName == "month") {
0393             if (e.attributeNS(KoXmlNS::number, "possessive-form", QString()) == "true") {
0394                 format += shortForm ? "PPP" : "PPPP";
0395             }
0396             // TODO the spec has a strange mention of number:format-source
0397             else if (e.attributeNS(KoXmlNS::number, "textual", QString()) == "true") {
0398                 bool isExtraShort = false;      // find out if we have to use the extra-short month name (just 1st letter)
0399                 if (e.attributeNS(KoXmlNS::calligra, "number-length", QString()) == "extra-short") {
0400                     isExtraShort = true;
0401                 }
0402 
0403                 if (!isExtraShort) {            // for normal month format (first 3 letters or complete name)
0404                     format += shortForm ? "MMM" : "MMMM";
0405                 } else {                        // for the extra-short month name use 'X' as a special mark
0406                     format += "X";
0407                 }
0408             } else { // month number
0409                 format += shortForm ? "M" : "MM";
0410             }
0411         } else if (localName == "year") {
0412             format += shortForm ? "yy" : "yyyy";
0413         } else if (localName == "era") {
0414             //TODO I don't know what is it... (define into oo spec)
0415         } else if (localName == "week-of-year" || localName == "quarter") {
0416             // ### not supported in Qt
0417         } else if (localName == "hours") {
0418             format += shortForm ? "h" : "hh";
0419         } else if (localName == "minutes") {
0420             format += shortForm ? "m" : "mm";
0421         } else if (localName == "seconds") {
0422             format += shortForm ? "s" : "ss";
0423         } else if (localName == "am-pm") {
0424             format += "ap";
0425         } else if (localName == "text") {   // literal
0426             format += e.text();
0427         } else if (localName == "suffix") {
0428             suffix = e.text();
0429             debugOdf << " suffix :" << suffix;
0430         } else if (localName == "prefix") {
0431             prefix = e.text();
0432             debugOdf << " prefix :" << prefix;
0433         } else if (localName == "currency-symbol") {
0434             dataStyle.currencySymbol = e.text();
0435             debugOdf << " currency-symbol:" << dataStyle.currencySymbol;
0436             format += e.text();
0437             //TODO
0438             // number:language="de" number:country="DE">€</number:currency-symbol>
0439             // Stefan: localization of the symbol?
0440         } else if (localName == "number") {
0441             if (e.hasAttributeNS(KoXmlNS::number, "grouping")) {
0442                 thousandsSep = e.attributeNS(KoXmlNS::number, "grouping", QString()).toLower() == "true";
0443             }
0444             if (e.hasAttributeNS(KoXmlNS::number, "decimal-places")) {
0445                 int d = e.attributeNS(KoXmlNS::number, "decimal-places", QString()).toInt(&ok);
0446                 if (ok)
0447                     precision = d;
0448             }
0449             if (e.hasAttributeNS(KoXmlNS::number, "min-integer-digits")) {
0450                 int d = e.attributeNS(KoXmlNS::number, "min-integer-digits", QString()).toInt(&ok);
0451                 if (ok)
0452                     leadingZ = d;
0453             }
0454             if (thousandsSep && leadingZ <= 3) {
0455                 format += "#,";
0456                 for (i = leadingZ; i <= 3; ++i)
0457                     format += '#';
0458             }
0459             for (i = 1; i <= leadingZ; ++i) {
0460                 format +=  '0';
0461                 if ((i % 3 == 0) && thousandsSep)
0462                     format = + ',' ;
0463             }
0464             if (precision > -1) {
0465                 format += '.';
0466                 for (i = 0; i < precision; ++i)
0467                     format += '0';
0468             }
0469         } else if (localName == "scientific-number") {
0470             if (dataStyle.type == Number)
0471                 dataStyle.type = Scientific;
0472             int exp = 2;
0473 
0474             if (e.hasAttributeNS(KoXmlNS::number, "decimal-places")) {
0475                 int d = e.attributeNS(KoXmlNS::number, "decimal-places", QString()).toInt(&ok);
0476                 if (ok)
0477                     precision = d;
0478             }
0479 
0480             if (e.hasAttributeNS(KoXmlNS::number, "min-integer-digits")) {
0481                 int d = e.attributeNS(KoXmlNS::number, "min-integer-digits", QString()).toInt(&ok);
0482                 if (ok)
0483                     leadingZ = d;
0484             }
0485 
0486             if (e.hasAttributeNS(KoXmlNS::number, "min-exponent-digits")) {
0487                 int d = e.attributeNS(KoXmlNS::number, "min-exponent-digits", QString()).toInt(&ok);
0488                 if (ok)
0489                     exp = d;
0490                 if (exp <= 0)
0491                     exp = 1;
0492             }
0493 
0494             if (e.hasAttributeNS(KoXmlNS::number, "grouping")) {
0495                 thousandsSep = e.attributeNS(KoXmlNS::number, "grouping", QString()).toLower() == "true";
0496             }
0497 
0498             if (thousandsSep && leadingZ <= 3) {
0499                 format += "#,";
0500                 for (i = leadingZ; i <= 3; ++i)
0501                     format += '#';
0502             }
0503 
0504             for (i = 1; i <= leadingZ; ++i) {
0505                 format += '0';
0506                 if ((i % 3 == 0) && thousandsSep)
0507                     format += ',';
0508             }
0509 
0510             if (precision > -1) {
0511                 format += '.';
0512                 for (i = 0; i < precision; ++i)
0513                     format += '0';
0514             }
0515 
0516             format += "E+";
0517             for (i = 0; i < exp; ++i)
0518                 format += '0';
0519         } else if (localName == "fraction") {
0520             if (dataStyle.type == Number)
0521                 dataStyle.type = Fraction;
0522             int integer = 0;
0523             int numerator = 1;
0524             int denominator = 1;
0525             int denominatorValue = 0;
0526             if (e.hasAttributeNS(KoXmlNS::number, "min-integer-digits")) {
0527                 int d = e.attributeNS(KoXmlNS::number, "min-integer-digits", QString()).toInt(&ok);
0528                 if (ok)
0529                     integer = d;
0530             }
0531             if (e.hasAttributeNS(KoXmlNS::number, "min-numerator-digits")) {
0532                 int d = e.attributeNS(KoXmlNS::number, "min-numerator-digits", QString()).toInt(&ok);
0533                 if (ok)
0534                     numerator = d;
0535             }
0536             if (e.hasAttributeNS(KoXmlNS::number, "min-denominator-digits")) {
0537                 int d = e.attributeNS(KoXmlNS::number, "min-denominator-digits", QString()).toInt(&ok);
0538                 if (ok)
0539                     denominator = d;
0540             }
0541             if (e.hasAttributeNS(KoXmlNS::number, "denominator-value")) {
0542                 int d = e.attributeNS(KoXmlNS::number, "denominator-value", QString()).toInt(&ok);
0543                 if (ok)
0544                     denominatorValue = d;
0545             }
0546             if (e.hasAttributeNS(KoXmlNS::number, "grouping")) {
0547                 thousandsSep = e.attributeNS(KoXmlNS::number, "grouping", QString()).toLower() == "true";
0548             }
0549 
0550             for (i = 0; i < integer; ++i)
0551                 format += '#';
0552 
0553             format += ' ';
0554 
0555             for (i = 0; i < numerator; ++i)
0556                 format += '?';
0557 
0558             format += '/';
0559 
0560             if (denominatorValue != 0)
0561                 format += QString::number(denominatorValue);
0562             else {
0563                 for (i = 0; i < denominator; ++i)
0564                     format += '?';
0565             }
0566         }
0567 
0568         // stylesmap's are embedded into a style and are pointing to another style that
0569         // should be used instead of this style if the defined condition is true. E.g.;
0570         // <number:number-style style:name="N139P0" style:volatile="true"/>
0571         // <number:number-style style:name="N139P1" style:volatile="true"/>
0572         // <number:number-style style:name="N139P2" style:volatile="true"/>
0573         // <number:text-style style:name="N139">
0574         //   <style:map style:condition="value()&gt;0" style:apply-style-name="N139P0"/>
0575         //   <style:map style:condition="value()&lt;0" style:apply-style-name="N139P1"/>
0576         //   <style:map style:condition="value()=0" style:apply-style-name="N139P2"/>
0577         // </number:text-style>
0578         for (KoXmlNode node(e); !node.isNull(); node = node.nextSibling()) {
0579             KoXmlElement elem = node.toElement();
0580             if (elem.namespaceURI() == KoXmlNS::style && elem.localName() == "map") {
0581                 QString condition, applyStyleName;
0582                 if (elem.hasAttributeNS(KoXmlNS::style, "condition"))
0583                     condition = elem.attributeNS(KoXmlNS::style, "condition");
0584                 if (elem.hasAttributeNS(KoXmlNS::style, "apply-style-name"))
0585                     applyStyleName = elem.attributeNS(KoXmlNS::style, "apply-style-name");
0586                 dataStyle.styleMaps.append( QPair<QString,QString>(condition,applyStyleName) );
0587             }
0588         }
0589     }
0590 
0591     const QString styleName = parent.attributeNS(KoXmlNS::style, "name", QString());
0592 
0593 debugOdf<<"99 *****************************************************************************";
0594 //Q_ASSERT(false);
0595     debugOdf << "data style:" << styleName << " qt format=" << format;
0596     if (!prefix.isEmpty()) {
0597         debugOdf << " format.left( prefix.length() ) :" << format.left(prefix.length()) << " prefix :" << prefix;
0598         if (format.left(prefix.length()) == prefix) {
0599             format = format.right(format.length() - prefix.length());
0600         } else
0601             prefix.clear();
0602     }
0603     if (!suffix.isEmpty()) {
0604         debugOdf << "format.right( suffix.length() ) :" << format.right(suffix.length()) << " suffix :" << suffix;
0605         if (format.right(suffix.length()) == suffix) {
0606             format = format.left(format.length() - suffix.length());
0607         } else
0608             suffix.clear();
0609     }
0610 
0611     dataStyle.formatStr = format;
0612     dataStyle.prefix = prefix;
0613     dataStyle.suffix = suffix;
0614     dataStyle.precision = precision;
0615     dataStyle.thousandsSep = thousandsSep;
0616     debugOdf << " finish insert format :" << format << " prefix :" << prefix << " suffix :" << suffix;
0617     return QPair<QString, NumericStyleFormat>(styleName, dataStyle);
0618 }
0619 
0620 QString saveOdfNumberStyle(KoGenStyles &mainStyles, const NumericStyleFormat &format)
0621 {
0622     QString styleName;
0623     switch (format.type) {
0624         case KoOdfNumberStyles::Number: {
0625             styleName = KoOdfNumberStyles::saveOdfNumberStyle(mainStyles, format.formatStr, format.prefix, format.suffix, format.thousandsSep);
0626         } break;
0627         case KoOdfNumberStyles::Boolean: {
0628             styleName = KoOdfNumberStyles::saveOdfBooleanStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
0629         } break;
0630         case KoOdfNumberStyles::Date: {
0631             bool localeFormat = format.formatStr.isEmpty();
0632             styleName = KoOdfNumberStyles::saveOdfDateStyle(mainStyles, format.formatStr, localeFormat, format.prefix, format.suffix);
0633         } break;
0634         case KoOdfNumberStyles::Time: {
0635             bool localeFormat = format.formatStr.isEmpty();
0636             styleName = KoOdfNumberStyles::saveOdfTimeStyle(mainStyles, format.formatStr, localeFormat, format.prefix, format.suffix);
0637         } break;
0638         case KoOdfNumberStyles::Percentage: {
0639             styleName = KoOdfNumberStyles::saveOdfPercentageStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
0640         } break;
0641         case KoOdfNumberStyles::Currency: {
0642             styleName = KoOdfNumberStyles::saveOdfCurrencyStyle(mainStyles, format.formatStr, format.currencySymbol, format.prefix, format.suffix);
0643         } break;
0644         case KoOdfNumberStyles::Scientific: {
0645             styleName = KoOdfNumberStyles::saveOdfScientificStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
0646         } break;
0647         case KoOdfNumberStyles::Fraction: {
0648             styleName = KoOdfNumberStyles::saveOdfFractionStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
0649         } break;
0650         case KoOdfNumberStyles::Text: {
0651             styleName = KoOdfNumberStyles::saveOdfTextStyle(mainStyles, format.formatStr, format.prefix, format.suffix);
0652         } break;
0653     }
0654     return styleName;
0655 }
0656 
0657 void addTextNumber(QString& text, KoXmlWriter &elementWriter)
0658 {
0659     if (!text.isEmpty()) {
0660         number_text(&elementWriter).addTextNode(text);
0661         text.clear();
0662     }
0663 }
0664 
0665 void parseOdfTimelocale(KoXmlWriter &elementWriter, QString &format, QString &text)
0666 {
0667     debugOdf << "parseOdfTimelocale(KoXmlWriter &elementWriter, QString & format, QString & text ) :" << format;
0668     do {
0669         if (!saveOdflocaleTimeFormat(elementWriter, format, text)) {
0670             text += format[0];
0671             format.remove(0, 1);
0672         }
0673     } while (format.length() > 0);
0674     addTextNumber(text, elementWriter);
0675 }
0676 
0677 bool saveOdflocaleTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text)
0678 {
0679     bool changed = false;
0680     if (format.startsWith("%H")) {   //hh
0681         //hour in 24h
0682         addTextNumber(text, elementWriter);
0683 
0684         number_hours(&elementWriter).set_number_style("long");
0685         format.remove(0, 2);
0686         changed = true;
0687     } else if (format.startsWith("%k")) { //h
0688         addTextNumber(text, elementWriter);
0689 
0690         number_hours(&elementWriter).set_number_style("short");
0691         format.remove(0, 2);
0692         changed = true;
0693     } else if (format.startsWith("%I")) { // ?????
0694         //TODO hour in 12h
0695         changed = true;
0696     } else if (format.startsWith("%l")) {
0697         //TODO hour in 12h with 1 digit
0698         changed = true;
0699     } else if (format.startsWith("%M")) { // mm
0700         addTextNumber(text, elementWriter);
0701 
0702         number_minutes(&elementWriter).set_number_style("long");
0703         format.remove(0, 2);
0704         changed = true;
0705 
0706     } else if (format.startsWith("%S")) {  //ss
0707         addTextNumber(text, elementWriter);
0708 
0709         number_seconds(&elementWriter).set_number_style("long");
0710         format.remove(0, 2);
0711         changed = true;
0712     } else if (format.startsWith("%p")) {
0713         //TODO am or pm
0714         addTextNumber(text, elementWriter);
0715 
0716         number_am_pm(&elementWriter).end();
0717         format.remove(0, 2);
0718         changed = true;
0719     }
0720     return changed;
0721 }
0722 
0723 
0724 bool saveOdfTimeFormat(KoXmlWriter &elementWriter, QString &format, QString &text, bool &antislash)
0725 {
0726     bool changed = false;
0727     //we can also add time to date.
0728     if (antislash) {
0729         text += format[0];
0730         format.remove(0, 1);
0731         antislash = false;
0732         changed = true;
0733     } else if (format.startsWith("hh")) {
0734         addTextNumber(text, elementWriter);
0735 
0736         number_hours(&elementWriter).set_number_style("long");
0737         format.remove(0, 2);
0738         changed = true;
0739     } else if (format.startsWith('h')) {
0740         addTextNumber(text, elementWriter);
0741 
0742         number_hours(&elementWriter).set_number_style("short");
0743         format.remove(0, 1);
0744         changed = true;
0745     } else if (format.startsWith("mm")) {
0746         addTextNumber(text, elementWriter);
0747 
0748         number_minutes(&elementWriter).set_number_style("long");
0749         format.remove(0, 2);
0750         changed = true;
0751     } else if (format.startsWith('m')) {
0752         addTextNumber(text, elementWriter);
0753 
0754         number_minutes(&elementWriter).set_number_style("short");
0755         format.remove(0, 1);
0756         changed = true;
0757     } else if (format.startsWith("ss")) {
0758         addTextNumber(text, elementWriter);
0759 
0760         number_seconds(&elementWriter).set_number_style("long");
0761         format.remove(0, 2);
0762         changed = true;
0763     } else if (format.startsWith('s')) {
0764         addTextNumber(text, elementWriter);
0765 
0766         number_seconds(&elementWriter).set_number_style("short");
0767         format.remove(0, 1);
0768         changed = true;
0769     } else if (format.startsWith("ap")) {
0770         addTextNumber(text, elementWriter);
0771 
0772         number_am_pm(&elementWriter).end();
0773         format.remove(0, 2);
0774         changed = true;
0775     }
0776     return changed;
0777 }
0778 
0779 QString saveOdfTimeStyle(KoGenStyles &mainStyles, const QString &_format, bool localeFormat,
0780         const QString &_prefix, const QString &_suffix)
0781 {
0782     Q_UNUSED(_prefix);
0783     Q_UNUSED(_suffix);
0784     //debugOdf << "QString KoOdfNumberStyles::saveOdfTimeStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
0785     QString format(_format);
0786     KoGenStyle currentStyle(KoGenStyle::NumericTimeStyle);
0787     QBuffer buffer;
0788     buffer.open(QIODevice::WriteOnly);
0789     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
0790     QString text;
0791     if (localeFormat) {
0792         parseOdfTimelocale(elementWriter, format, text);
0793     } else {
0794         bool antislash = false;
0795         do {
0796             if (!saveOdfTimeFormat(elementWriter, format, text, antislash)) {
0797                 QString elem(format[0]);
0798                 format.remove(0, 1);
0799                 if (elem == "\\") {
0800                     antislash = true;
0801                 } else {
0802                     text += elem;
0803                     antislash = false;
0804                 }
0805             }
0806         } while (format.length() > 0);
0807         addTextNumber(text, elementWriter);
0808     }
0809     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
0810     currentStyle.addChildElement("number", elementContents);
0811     return mainStyles.insert(currentStyle, "N");
0812 }
0813 
0814 //convert locale string to good format
0815 void parseOdfDatelocale(KoXmlWriter &elementWriter, QString &format, QString &text)
0816 {
0817     debugOdf << format;
0818     do {
0819         if (format.startsWith("%Y")) {
0820             addTextNumber(text, elementWriter);
0821 
0822             number_year(&elementWriter).set_number_style("long");
0823             format.remove(0, 2);
0824         } else if (format.startsWith("%y")) {
0825 
0826             addTextNumber(text, elementWriter);
0827 
0828             number_year(&elementWriter).set_number_style("short");
0829             format.remove(0, 2);
0830         } else if (format.startsWith("%n")) {
0831             addTextNumber(text, elementWriter);
0832 
0833             number_month month(&elementWriter);
0834             month.set_number_style("short");
0835             month.set_number_textual("false");
0836             format.remove(0, 2);
0837         } else if (format.startsWith("%m")) {
0838             addTextNumber(text, elementWriter);
0839 
0840             number_month month(&elementWriter);
0841             month.set_number_style("long");
0842             month.set_number_textual("false");  //not necessary remove it
0843             format.remove(0, 2);
0844         } else if (format.startsWith("%e")) {
0845             addTextNumber(text, elementWriter);
0846 
0847             number_day(&elementWriter).set_number_style("short");
0848             format.remove(0, 2);
0849         } else if (format.startsWith("%d")) {
0850             addTextNumber(text, elementWriter);
0851 
0852             number_day(&elementWriter).set_number_style("long");
0853             format.remove(0, 2);
0854         } else if (format.startsWith("%b")) {
0855             addTextNumber(text, elementWriter);
0856 
0857             number_month month(&elementWriter);
0858             month.set_number_style("short");
0859             month.set_number_textual("true");
0860             format.remove(0, 2);
0861         } else if (format.startsWith("%B")) {
0862             addTextNumber(text, elementWriter);
0863 
0864             number_month month(&elementWriter);
0865             month.set_number_style("long");
0866             month.set_number_textual("true");
0867             elementWriter.endElement();
0868             format.remove(0, 2);
0869         } else if (format.startsWith("%a")) {
0870             addTextNumber(text, elementWriter);
0871 
0872             number_day_of_week(&elementWriter).set_number_style("short");
0873 
0874             format.remove(0, 2);
0875         } else if (format.startsWith("%A")) {
0876             addTextNumber(text, elementWriter);
0877 
0878             number_day_of_week(&elementWriter).set_number_style("long");
0879             format.remove(0, 2);
0880         } else {
0881             if (!saveOdflocaleTimeFormat(elementWriter, format, text)) {
0882                 text += format[0];
0883                 format.remove(0, 1);
0884             }
0885         }
0886     } while (format.length() > 0);
0887     addTextNumber(text, elementWriter);
0888 }
0889 
0890 QString saveOdfDateStyle(KoGenStyles &mainStyles, const QString &_format, bool localeFormat,
0891         const QString &_prefix, const QString &_suffix)
0892 {
0893     Q_UNUSED(_prefix);
0894     Q_UNUSED(_suffix);
0895     //debugOdf << _format;
0896     QString format(_format);
0897 
0898     // Not supported into Qt: "era" "week-of-year" "quarter"
0899 
0900     KoGenStyle currentStyle(KoGenStyle::NumericDateStyle);
0901     QBuffer buffer;
0902     buffer.open(QIODevice::WriteOnly);
0903     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
0904     QString text;
0905     if (localeFormat) {
0906         parseOdfDatelocale(elementWriter, format, text);
0907     } else {
0908         bool antislash = false;
0909         do {
0910             if (antislash) {
0911                 text += format[0];
0912                 format.remove(0, 1);
0913             }
0914             //TODO implement loading ! What is it ?
0915             else if (format.startsWith("MMMMM")) {        // MMMMM is extra-short month name (only 1st character)
0916                 addTextNumber(text, elementWriter);
0917 
0918                 number_month month(&elementWriter);
0919                 month.set_number_textual("true");
0920                 month.set_calligra_number_length("extra-short");
0921                 format.remove(0, 5);
0922             } else if (format.startsWith("MMMM")) {
0923                 addTextNumber(text, elementWriter);
0924 
0925                 number_month month(&elementWriter);
0926                 month.set_number_style("long");
0927                 month.set_number_textual("true");
0928                 format.remove(0, 4);
0929             } else if (format.startsWith("MMM")) {
0930                 addTextNumber(text, elementWriter);
0931 
0932                 number_month month(&elementWriter);
0933                 month.set_number_style("short");
0934                 month.set_number_textual("true");
0935                 format.remove(0, 3);
0936             } else if (format.startsWith("MM")) {
0937                 addTextNumber(text, elementWriter);
0938 
0939                 number_month month(&elementWriter);
0940                 month.set_number_style("long");
0941                 month.set_number_textual("false"); //not necessary remove it
0942                 format.remove(0, 2);
0943             } else if (format.startsWith('M')) {
0944                 addTextNumber(text, elementWriter);
0945 
0946                 number_month month(&elementWriter);
0947                 month.set_number_style("short");
0948                 month.set_number_textual("false");
0949                 format.remove(0, 1);
0950             } else if (format.startsWith("PPPP")) {
0951                 addTextNumber(text, elementWriter);
0952                 //<number:month number:possessive-form="true" number:textual="true" number:style="long"/>
0953 
0954                 number_month month(&elementWriter);
0955                 month.set_number_style("short");
0956                 month.set_number_textual("false");
0957                 month.set_number_possessive_form("true");
0958                 format.remove(0, 4);
0959             } else if (format.startsWith("PPP")) {
0960                 addTextNumber(text, elementWriter);
0961                 //<number:month number:possessive-form="true" number:textual="true" number:style="short"/>
0962                 number_month month(&elementWriter);
0963                 month.set_number_possessive_form("true");
0964                 month.set_number_style("short");
0965                 month.set_number_textual("false");
0966                 format.remove(0, 3);
0967             } else if (format.startsWith("dddd")) {
0968                 addTextNumber(text, elementWriter);
0969 
0970                 number_day_of_week(&elementWriter).set_number_style("long");
0971                 format.remove(0, 4);
0972             } else if (format.startsWith("ddd")) {
0973                 addTextNumber(text, elementWriter);
0974 
0975                 number_day_of_week(&elementWriter).set_number_style("short");
0976                 format.remove(0, 3);
0977             } else if (format.startsWith("dd")) {
0978                 addTextNumber(text, elementWriter);
0979 
0980                 number_day(&elementWriter).set_number_style("long");
0981                 format.remove(0, 2);
0982             } else if (format.startsWith('d')) {
0983                 addTextNumber(text, elementWriter);
0984 
0985                 number_day(&elementWriter).set_number_style("short");
0986                 format.remove(0, 1);
0987             } else if (format.startsWith("yyyy")) {
0988                 addTextNumber(text, elementWriter);
0989 
0990                 number_year(&elementWriter).set_number_style("long");
0991                 format.remove(0, 4);
0992             } else if (format.startsWith("yy")) {
0993                 addTextNumber(text, elementWriter);
0994 
0995                 number_year(&elementWriter).set_number_style("short");
0996                 format.remove(0, 2);
0997             } else {
0998                 if (!saveOdfTimeFormat(elementWriter, format, text, antislash)) {
0999                     QString elem(format[0]);
1000                     format.remove(0, 1);
1001                     if (elem == "\\") {
1002                         antislash = true;
1003                     } else {
1004                         text += elem;
1005                         antislash = false;
1006                     }
1007                 }
1008             }
1009         } while (format.length() > 0);
1010         addTextNumber(text, elementWriter);
1011     }
1012 
1013     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1014     currentStyle.addChildElement("number", elementContents);
1015     return mainStyles.insert(currentStyle, "N");
1016 }
1017 
1018 
1019 QString saveOdfFractionStyle(KoGenStyles &mainStyles, const QString &_format,
1020         const QString &_prefix, const QString &_suffix)
1021 {
1022     //debugOdf << "QString saveOdfFractionStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
1023     QString format(_format);
1024 
1025     KoGenStyle currentStyle(KoGenStyle::NumericFractionStyle);
1026     QBuffer buffer;
1027     buffer.open(QIODevice::WriteOnly);
1028     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
1029     QString text;
1030     int integer = 0;
1031     int numerator = 0;
1032     int denominator = 0;
1033     int denominatorValue = 0;
1034     bool beforeSlash = true;
1035     do {
1036         if (format[0] == '#')
1037             integer++;
1038         else if (format[0] == '/')
1039             beforeSlash = false;
1040         else if (format[0] == '?') {
1041             if (beforeSlash)
1042                 numerator++;
1043             else
1044                 denominator++;
1045         } else {
1046             bool ok;
1047             int value = format.toInt(&ok);
1048             if (ok) {
1049                 denominatorValue = value;
1050                 break;
1051             }
1052         }
1053         format.remove(0, 1);
1054     } while (format.length() > 0);
1055 
1056     text = _prefix;
1057     addTextNumber(text, elementWriter);
1058 
1059     number_fraction fraction(&elementWriter);
1060     fraction.set_number_min_integer_digits(integer);
1061     fraction.set_number_min_numerator_digits(numerator);
1062     fraction.set_number_min_denominator_digits(denominator);
1063     if (denominatorValue != 0) {
1064         fraction.set_number_denominator_value(denominatorValue);
1065     }
1066     fraction.end();
1067 
1068     addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
1069 
1070     text = _suffix;
1071     addTextNumber(text, elementWriter);
1072 
1073     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1074     currentStyle.addChildElement("number", elementContents);
1075     return mainStyles.insert(currentStyle, "N");
1076 }
1077 
1078 
1079 QString saveOdfNumberStyle(KoGenStyles &mainStyles, const QString &_format,
1080         const QString &_prefix, const QString &_suffix, bool thousandsSep)
1081 {
1082     //debugOdf << "QString saveOdfNumberStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
1083     QString format(_format);
1084 
1085     KoGenStyle currentStyle(KoGenStyle::NumericNumberStyle);
1086     QBuffer buffer;
1087     buffer.open(QIODevice::WriteOnly);
1088     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
1089     QString text;
1090     int decimalplaces = 0;
1091     int integerdigits = 0;
1092     bool beforeSeparator = true;
1093     do {
1094         if (format[0] == '.' || format[0] == ',')
1095             beforeSeparator = false;
1096         else if (format[0] == '0' && beforeSeparator)
1097             integerdigits++;
1098         else if (format[0] == '0' && !beforeSeparator)
1099             decimalplaces++;
1100         else
1101             debugOdf << " error format 0";
1102         format.remove(0, 1);
1103     } while (format.length() > 0);
1104     text = _prefix ;
1105     addTextNumber(text, elementWriter);
1106     number_number number(&elementWriter);
1107     //debugOdf << " decimalplaces :" << decimalplaces << " integerdigits :" << integerdigits;
1108     if (!beforeSeparator) {
1109         number.set_number_decimal_places(decimalplaces);
1110     }
1111     number.set_number_min_integer_digits(integerdigits);
1112     if (thousandsSep) {
1113         number.set_number_grouping(true);
1114     }
1115     number.end();
1116 
1117     text = _suffix ;
1118     addTextNumber(text, elementWriter);
1119     addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
1120 
1121     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1122     currentStyle.addChildElement("number", elementContents);
1123     return mainStyles.insert(currentStyle, "N");
1124 }
1125 
1126 QString saveOdfBooleanStyle(KoGenStyles &mainStyles, const QString &format, const QString &prefix, const QString &suffix)
1127 {
1128     Q_UNUSED(format);
1129 
1130     KoGenStyle currentStyle(KoGenStyle::NumericBooleanStyle);
1131 
1132     QBuffer buffer;
1133     buffer.open(QIODevice::WriteOnly);
1134     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
1135     QString text = prefix;
1136     addTextNumber(text, elementWriter);
1137     number_boolean(&elementWriter).end();
1138     text = suffix;
1139     addTextNumber(text, elementWriter);
1140 
1141     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1142     currentStyle.addChildElement("number", elementContents);
1143     return mainStyles.insert(currentStyle, "N");
1144 }
1145 
1146 QString saveOdfPercentageStyle(KoGenStyles &mainStyles, const QString &_format,
1147         const QString &_prefix, const QString &_suffix)
1148 {
1149     //<number:percentage-style style:name="N11">
1150     //<number:number number:decimal-places="2" number:min-integer-digits="1"/>
1151     //<number:text>%</number:text>
1152     //</number:percentage-style>
1153 
1154     //debugOdf << "QString saveOdfPercentageStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
1155     QString format(_format);
1156 
1157     KoGenStyle currentStyle(KoGenStyle::NumericPercentageStyle);
1158     QBuffer buffer;
1159     buffer.open(QIODevice::WriteOnly);
1160     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
1161     QString text;
1162     int decimalplaces = 0;
1163     int integerdigits = 0;
1164     bool beforeSeparator = true;
1165     do {
1166         if (format[0] == '.' || format[0] == ',')
1167             beforeSeparator = false;
1168         else if (format[0] == '0' && beforeSeparator)
1169             integerdigits++;
1170         else if (format[0] == '0' && !beforeSeparator)
1171             decimalplaces++;
1172         else
1173             debugOdf << " error format 0";
1174         format.remove(0, 1);
1175     } while (format.length() > 0);
1176     text = _prefix ;
1177     addTextNumber(text, elementWriter);
1178     number_number number(&elementWriter);
1179     if (!beforeSeparator) {
1180         number.set_number_decimal_places(decimalplaces);
1181     }
1182     number.set_number_min_integer_digits(integerdigits);
1183     number.end();
1184 
1185     QString percent(QChar('%'));
1186     addTextNumber(percent, elementWriter);
1187 
1188     text = _suffix ;
1189     addTextNumber(text, elementWriter);
1190     addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
1191 
1192     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1193     currentStyle.addChildElement("number", elementContents);
1194     return mainStyles.insert(currentStyle, "N");
1195 
1196 }
1197 
1198 QString saveOdfScientificStyle(KoGenStyles &mainStyles, const QString &_format,
1199         const QString &_prefix, const QString &_suffix, bool thousandsSep)
1200 {
1201     //<number:number-style style:name="N60">
1202     //<number:scientific-number number:decimal-places="2" number:min-integer-digits="1" number:min-exponent-digits="3"/>
1203     //</number:number-style>
1204 
1205     //example 000,000e+0000
1206     //debugOdf << "QString saveOdfScientificStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
1207     QString format(_format);
1208 
1209     KoGenStyle currentStyle(KoGenStyle::NumericScientificStyle);
1210     QBuffer buffer;
1211     buffer.open(QIODevice::WriteOnly);
1212     int decimalplace = 0;
1213     int integerdigits = 0;
1214     int exponentdigits = 0;
1215     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
1216     QString text;
1217     bool beforeSeparator = true;
1218     bool exponential = false;
1219     bool positive = true;
1220     do {
1221         if (!exponential) {
1222             if (format[0] == '0' && beforeSeparator)
1223                 integerdigits++;
1224             else if (format[0] == ',' || format[0] == '.')
1225                 beforeSeparator = false;
1226             else if (format[0] == '0' && !beforeSeparator)
1227                 decimalplace++;
1228             else if (format[0].toLower() == 'e') {
1229                 format.remove(0, 1);
1230                 if (format[0] == '+')
1231                     positive = true;
1232                 else if (format[0] == '-')
1233                     positive = false;
1234                 else
1235                     debugOdf << "Error into scientific number";
1236                 exponential = true;
1237             }
1238         } else {
1239             if (format[0] == '0' && positive)
1240                 exponentdigits++;
1241             else if (format[0] == '0' && !positive)
1242                 exponentdigits--;
1243             else
1244                 debugOdf << " error into scientific number exponential value";
1245         }
1246         format.remove(0, 1);
1247     } while (format.length() > 0);
1248     text =  _prefix ;
1249     addTextNumber(text, elementWriter);
1250 
1251     number_scientific_number number(&elementWriter);
1252     //debugOdf << " decimalplace :" << decimalplace << " integerdigits :" << integerdigits << " exponentdigits :" << exponentdigits;
1253     if (!beforeSeparator) {
1254         number.set_number_decimal_places(decimalplace);
1255     }
1256     number.set_number_min_integer_digits(integerdigits);
1257     number.set_number_min_exponent_digits(exponentdigits);
1258     if (thousandsSep) {
1259         number.set_number_grouping(true);
1260     }
1261     number.end();
1262 
1263     text = _suffix;
1264     addTextNumber(text, elementWriter);
1265     addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
1266 
1267     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1268     currentStyle.addChildElement("number", elementContents);
1269     return mainStyles.insert(currentStyle, "N");
1270 }
1271 
1272 QString saveOdfCurrencyStyle(KoGenStyles &mainStyles,
1273         const QString &_format, const QString &symbol,
1274         const QString &_prefix, const QString &_suffix)
1275 {
1276 
1277     //<number:currency-style style:name="N107P0" style:volatile="true">
1278     //<number:number number:decimal-places="2" number:min-integer-digits="1" number:grouping="true"/>
1279     //<number:text> </number:text>
1280     //<number:currency-symbol>VEB</number:currency-symbol>
1281     //</number:currency-style>
1282 
1283     //debugOdf << "QString saveOdfCurrencyStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
1284     QString format(_format);
1285 
1286     KoGenStyle currentStyle(KoGenStyle::NumericCurrencyStyle);
1287     QBuffer buffer;
1288     buffer.open(QIODevice::WriteOnly);
1289     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
1290     QString text;
1291     int decimalplaces = 0;
1292     int integerdigits = 0;
1293     bool beforeSeparator = true;
1294     do {
1295         if (format[0] == '.' || format[0] == ',')
1296             beforeSeparator = false;
1297         else if (format[0] == '0' && beforeSeparator)
1298             integerdigits++;
1299         else if (format[0] == '0' && !beforeSeparator)
1300             decimalplaces++;
1301         else
1302             debugOdf << " error format 0";
1303         format.remove(0, 1);
1304     } while (format.length() > 0);
1305 
1306     text =  _prefix ;
1307     addTextNumber(text, elementWriter);
1308 
1309     number_number number(&elementWriter);
1310     //debugOdf << " decimalplaces :" << decimalplaces << " integerdigits :" << integerdigits;
1311     if (!beforeSeparator) {
1312         number.set_number_decimal_places(decimalplaces);
1313     }
1314     number.set_number_min_integer_digits(integerdigits);
1315     number.end();
1316 
1317     text =  _suffix ;
1318     addTextNumber(text, elementWriter);
1319     addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
1320 
1321     number_currency_symbol sym(&elementWriter);
1322     //debugOdf << " currency-symbol:" << symbol;
1323     sym.addTextNode(symbol.toUtf8());
1324     sym.end();
1325 
1326     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1327     currentStyle.addChildElement("number", elementContents);
1328     return mainStyles.insert(currentStyle, "N");
1329 }
1330 
1331 QString saveOdfTextStyle(KoGenStyles &mainStyles, const QString &_format, const QString &_prefix, const QString &_suffix)
1332 {
1333     Q_UNUSED(_format);
1334 
1335     //<number:text-style style:name="N100">
1336     //<number:text-content/>
1337     ///</number:text-style>
1338 
1339     //debugOdf << "QString saveOdfTextStyle( KoGenStyles &mainStyles, const QString & _format ) :" << _format;
1340 
1341     KoGenStyle currentStyle(KoGenStyle::NumericTextStyle);
1342     QBuffer buffer;
1343     buffer.open(QIODevice::WriteOnly);
1344     KoXmlWriter elementWriter(&buffer);    // TODO pass indentation level
1345     QString text =  _prefix ;
1346     addTextNumber(text, elementWriter);
1347 
1348     number_text_content(&elementWriter).end();
1349 
1350     text =  _suffix ;
1351     addTextNumber(text, elementWriter);
1352     addCalligraNumericStyleExtension(elementWriter, _suffix, _prefix);
1353 
1354     QString elementContents = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
1355     currentStyle.addChildElement("number", elementContents);
1356     return mainStyles.insert(currentStyle, "N");
1357 }
1358 
1359 //This is an extension of numeric style. For the moment we used namespace of
1360 //oasis format for specific calligra extension. Change it for the future.
1361 void addCalligraNumericStyleExtension(KoXmlWriter &elementWriter, const QString &_suffix, const QString &_prefix)
1362 {
1363     if (!_suffix.isEmpty()) {
1364         elementWriter.startElement("number:suffix");
1365         elementWriter.addTextNode(_suffix);
1366         elementWriter.endElement();
1367     }
1368     if (!_prefix.isEmpty()) {
1369         elementWriter.startElement("number:prefix");
1370         elementWriter.addTextNode(_prefix);
1371         elementWriter.endElement();
1372     }
1373 }
1374 }