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()>0" style:apply-style-name="N139P0"/> 0575 // <style:map style:condition="value()<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 }