1 | /* This file is part of the KDE project |
2 | Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org> |
3 | Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net> |
4 | Copyright 2004 Tomas Mecir <mecirt@gmail.com> |
5 | Copyright 1998-2004 KSpread Team <calligra-devel@kde.org> |
6 | |
7 | This library is free software; you can redistribute it and/or |
8 | modify it under the terms of the GNU Library General Public |
9 | License as published by the Free Software Foundation; either |
10 | version 2 of the License, or (at your option) any later version. |
11 | |
12 | This library is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | Library General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU Library General Public License |
18 | along with this library; see the file COPYING.LIB. If not, write to |
19 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 | Boston, MA 02110-1301, USA. |
21 | */ |
22 | |
23 | #include "ValueFormatter.h" |
24 | |
25 | #include "CalculationSettings.h" |
26 | #include "Cell.h" |
27 | #include "Localization.h" |
28 | #include "ValueConverter.h" |
29 | |
30 | #include <kcalendarsystem.h> |
31 | #include <kdebug.h> |
32 | #include <klocale.h> |
33 | |
34 | #include <float.h> |
35 | #include <math.h> |
36 | |
37 | using namespace Calligra::Sheets; |
38 | |
39 | ValueFormatter::ValueFormatter(const ValueConverter* converter) |
40 | : m_converter(converter) |
41 | { |
42 | } |
43 | |
44 | const CalculationSettings* ValueFormatter::settings() const |
45 | { |
46 | return m_converter->settings(); |
47 | } |
48 | |
49 | Value ValueFormatter::formatText(const Value &value, Format::Type fmtType, int precision, |
50 | Style::FloatFormat floatFormat, const QString &prefix, |
51 | const QString &postfix, const QString ¤cySymbol, |
52 | const QString &formatString, bool thousandsSep) |
53 | { |
54 | if (value.isError()) |
55 | return Value(value.errorMessage()); |
56 | |
57 | //if we have an array, use its first element |
58 | if (value.isArray()) |
59 | return formatText(value.element(0, 0), fmtType, precision, |
60 | floatFormat, prefix, postfix, currencySymbol, formatString); |
61 | |
62 | Value result; |
63 | |
64 | //step 1: determine formatting that will be used |
65 | fmtType = determineFormatting(value, fmtType); |
66 | |
67 | //step 2: format the value ! |
68 | bool ok = false; |
69 | |
70 | //text |
71 | if (fmtType == Format::Text) { |
72 | QString str = m_converter->asString(value).asString(); |
73 | if (!str.isEmpty() && str[0] == '\'') |
74 | str = str.mid(1); |
75 | result = Value(str); |
76 | if (value.isBoolean()) { |
77 | result.setFormat(Value::fmt_Boolean); |
78 | } |
79 | ok = true; |
80 | } |
81 | |
82 | //datetime |
83 | else if (fmtType == Format::DateTime || (Format::isDate(fmtType) && !formatString.isEmpty()) ) { |
84 | Value dateValue = m_converter->asDateTime(value, &ok); |
85 | if (ok) { |
86 | result = Value(dateTimeFormat(dateValue.asDateTime(settings()), fmtType, formatString)); |
87 | result.setFormat(Value::fmt_DateTime); |
88 | } |
89 | } |
90 | |
91 | // |
92 | else if (Format::isDate(fmtType)) { |
93 | Value dateValue = m_converter->asDate(value, &ok); |
94 | if (ok) { |
95 | result = Value(dateFormat(dateValue.asDate(settings()), fmtType, formatString)); |
96 | result.setFormat(Value::fmt_Date); |
97 | } |
98 | } |
99 | |
100 | //time |
101 | else if (Format::isTime(fmtType)) { |
102 | Value timeValue = m_converter->asDateTime(value, &ok); |
103 | if (ok) { |
104 | result = Value(timeFormat(timeValue.asDateTime(settings()), fmtType, formatString)); |
105 | result.setFormat(Value::fmt_Time); |
106 | } |
107 | } |
108 | |
109 | //fraction |
110 | else if (Format::isFraction(fmtType)) { |
111 | Value fractionValue = m_converter->asFloat(value, &ok); |
112 | if (ok) { |
113 | result = Value(fractionFormat(fractionValue.asFloat(), fmtType)); |
114 | result.setFormat(Value::fmt_Number); |
115 | } |
116 | } |
117 | |
118 | //another |
119 | else { |
120 | // complex |
121 | if (value.isComplex()) { |
122 | Value complexValue = m_converter->asComplex(value, &ok); |
123 | if (ok) { |
124 | result = Value(complexFormat(complexValue, precision, fmtType, floatFormat, currencySymbol, thousandsSep)); |
125 | result.setFormat(Value::fmt_Number); |
126 | } |
127 | } |
128 | |
129 | // real number |
130 | else { |
131 | Number number = m_converter->asFloat(value, &ok).asFloat(); |
132 | if (ok) { |
133 | result = Value(createNumberFormat(number, precision, fmtType, floatFormat, currencySymbol, formatString, thousandsSep)); |
134 | result.setFormat(Value::fmt_Number); |
135 | } |
136 | } |
137 | } |
138 | |
139 | // Only string values can fail. If so, keep the string. |
140 | if (!ok) { |
141 | QString str = m_converter->asString(value).asString(); |
142 | if (!str.isEmpty() && str[0] == '\'') |
143 | str = str.mid(1); |
144 | result = Value(str); |
145 | } |
146 | |
147 | if (!prefix.isEmpty()) |
148 | result = Value(prefix + ' ' + result.asString()); |
149 | |
150 | if (!postfix.isEmpty()) |
151 | result = Value(result.asString() + ' ' + postfix); |
152 | |
153 | //kDebug() <<"ValueFormatter says:" << str; |
154 | return result; |
155 | } |
156 | |
157 | Format::Type ValueFormatter::determineFormatting(const Value &value, |
158 | Format::Type fmtType) |
159 | { |
160 | //now, everything depends on whether the formatting is Generic or not |
161 | if (fmtType == Format::Generic) { |
162 | //here we decide based on value's format... |
163 | Value::Format fmt = value.format(); |
164 | switch (fmt) { |
165 | case Value::fmt_None: |
166 | fmtType = Format::Text; |
167 | break; |
168 | case Value::fmt_Boolean: |
169 | fmtType = Format::Text; |
170 | break; |
171 | case Value::fmt_Number: { |
172 | Number val = fabs(value.asFloat()); |
173 | if (((val > 10000e+10) || (val < 10000e-10)) && (val != 0.0)) |
174 | fmtType = Format::Scientific; |
175 | else |
176 | fmtType = Format::Number; |
177 | } |
178 | break; |
179 | case Value::fmt_Percent: |
180 | fmtType = Format::Percentage; |
181 | break; |
182 | case Value::fmt_Money: |
183 | fmtType = Format::Money; |
184 | break; |
185 | case Value::fmt_DateTime: |
186 | fmtType = Format::DateTime; |
187 | break; |
188 | case Value::fmt_Date: |
189 | fmtType = Format::ShortDate; |
190 | break; |
191 | case Value::fmt_Time: |
192 | fmtType = Format::Time8; // [h]:mm |
193 | break; |
194 | case Value::fmt_String: |
195 | //this should never happen |
196 | fmtType = Format::Text; |
197 | break; |
198 | }; |
199 | return fmtType; |
200 | } else { |
201 | //we'll mostly want to use the given formatting, the only exception |
202 | //being Boolean values |
203 | |
204 | //TODO: is this correct? We may also want to convert bools to 1s and 0s |
205 | //if we want to display a number... |
206 | |
207 | //TODO: what to do about Custom formatting? We don't support it as of now, |
208 | // but we'll have it ... one day, that is ... |
209 | if (value.isBoolean()) |
210 | return Format::Text; |
211 | else |
212 | return fmtType; |
213 | } |
214 | } |
215 | |
216 | |
217 | QString ValueFormatter::removeTrailingZeros(const QString& str, const QString& decimalSymbol) |
218 | { |
219 | if (!str.contains(decimalSymbol)) |
220 | //no decimal symbol -> nothing to do |
221 | return str; |
222 | |
223 | int start = 0; |
224 | int cslen = m_converter->settings()->locale()->currencySymbol().length(); |
225 | if (str.indexOf('%') != -1) |
226 | start = 2; |
227 | else if (str.indexOf(m_converter->settings()->locale()->currencySymbol()) == |
228 | ((int)(str.length() - cslen))) |
229 | start = cslen + 1; |
230 | else if ((start = str.indexOf('E')) != -1) |
231 | start = str.length() - start; |
232 | else |
233 | start = 0; |
234 | |
235 | QString result = str; |
236 | int i = str.length() - start; |
237 | bool bFinished = false; |
238 | while (!bFinished && i > 0) { |
239 | QChar ch = result[i - 1]; |
240 | if (ch == '0') |
241 | result.remove(--i, 1); |
242 | else { |
243 | bFinished = true; |
244 | if (result.mid(i - decimalSymbol.length(), decimalSymbol.length()) == decimalSymbol) |
245 | result.remove(i - decimalSymbol.length(), decimalSymbol.length()); |
246 | } |
247 | } |
248 | return result; |
249 | } |
250 | |
251 | QString ValueFormatter::createNumberFormat(Number value, int precision, |
252 | Format::Type fmt, Style::FloatFormat floatFormat, const QString& currencySymbol, |
253 | const QString& _formatString, bool thousandsSep) |
254 | { |
255 | QString prefix, postfix; |
256 | QString formatString(_formatString); |
257 | |
258 | // try to split formatstring into prefix, formatstring and postfix. |
259 | if (!formatString.isEmpty() ) { |
260 | QRegExp re( QLatin1String( "^([^0#.,E+]*)([0#.,E+]*)(.*)$" ) ); |
261 | if( re.exactMatch( formatString ) ) { |
262 | prefix = re.cap( 1 ); |
263 | formatString = re.cap( 2 ); |
264 | postfix = re.cap( 3 ); |
265 | } |
266 | if (formatString.isEmpty()) { |
267 | return prefix + postfix; |
268 | } else if (formatString.contains(QLatin1Char('.'))) { |
269 | precision = formatString.length() - formatString.indexOf(QLatin1Char('.')) - 1; |
270 | } else if (precision != -1) { |
271 | precision = 0; |
272 | } |
273 | } |
274 | |
275 | int p = precision; |
276 | if (p == -1) { |
277 | // If precision (obtained from the cell style) is -1 (arbitrary), use the document default decimal precision |
278 | // and if that value is -1 too then use either automatic decimal place adjustment or a hardcoded default. |
279 | p = settings()->defaultDecimalPrecision(); |
280 | if (p == -1) { |
281 | if (fmt == Format::Number) { |
282 | QString s = QString::number(double(numToDouble(value))); |
283 | int _p = s.indexOf('.'); |
284 | p = _p >= 0 ? qMax(0, 10 - _p) : 0; |
285 | } else { |
286 | p = 2; // hardcoded default |
287 | } |
288 | } |
289 | } |
290 | |
291 | QString localizedNumber; |
292 | int pos = 0; |
293 | |
294 | // Always unsigned ? |
295 | if ((floatFormat == Style::AlwaysUnsigned) && (value < 0.0)) |
296 | value *= -1.0; |
297 | |
298 | //multiply value by 100 for percentage format |
299 | if (fmt == Format::Percentage) |
300 | value *= 100; |
301 | |
302 | // round the number, based on desired precision if not scientific is chosen |
303 | //(scientific has relative precision) |
304 | if (fmt != Format::Scientific) { |
305 | // this will avoid displaying negative zero, i.e "-0.0000" |
306 | // TODO: is this really a good solution? |
307 | if (fabs(value) < DBL_EPSILON) value = 0.0; |
308 | |
309 | double m[] = { 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10 }; |
310 | double mm = (p > 10) ? ::pow(10.0, p) : m[p]; |
311 | bool neg = value < 0; |
312 | value = floor(numToDouble(fabs(value)) * mm + 0.5) / mm; |
313 | if (neg) value = -value; |
314 | } |
315 | |
316 | double val = numToDouble(value); |
317 | switch (fmt) { |
318 | case Format::Number: |
319 | localizedNumber = m_converter->settings()->locale()->formatNumber(val, p); |
320 | break; |
321 | case Format::Percentage: |
322 | localizedNumber = m_converter->settings()->locale()->formatNumber(val, p); |
323 | if(!postfix.endsWith('%')) // percent formattings needs to end with a "%"-sign |
324 | postfix += '%'; |
325 | break; |
326 | case Format::Money: |
327 | localizedNumber = m_converter->settings()->locale()->formatMoney(val, currencySymbol.isEmpty() ? m_converter->settings()->locale()->currencySymbol() : currencySymbol, p); |
328 | break; |
329 | case Format::Scientific: { |
330 | const QString decimalSymbol = m_converter->settings()->locale()->decimalSymbol(); |
331 | localizedNumber = QString::number(val, 'E', p); |
332 | if ((pos = localizedNumber.indexOf('.')) != -1) |
333 | localizedNumber.replace(pos, 1, decimalSymbol); |
334 | break; |
335 | } |
336 | default : |
337 | //other formatting? |
338 | // This happens with Format::Custom... |
339 | kDebug(36001) << "Wrong usage of ValueFormatter::createNumberFormat fmt=" << fmt << "" ; |
340 | break; |
341 | } |
342 | |
343 | //prepend positive sign if needed |
344 | if ((floatFormat == Style::AlwaysSigned) && value >= 0) |
345 | if (m_converter->settings()->locale()->positiveSign().isEmpty()) |
346 | localizedNumber = '+' + localizedNumber; |
347 | |
348 | // Remove trailing zeros and the decimal point if necessary |
349 | // unless the number has no decimal point |
350 | if (precision == -1) { |
351 | QString decimalSymbol = m_converter->settings()->locale()->decimalSymbol(); |
352 | if (decimalSymbol.isNull()) |
353 | decimalSymbol = '.'; |
354 | |
355 | localizedNumber = removeTrailingZeros(localizedNumber, decimalSymbol); |
356 | } |
357 | |
358 | // Remove thousands separators if necessary |
359 | if (!thousandsSep) { |
360 | const QString separator = m_converter->settings()->locale()->thousandsSeparator(); |
361 | if (!separator.isNull()) { |
362 | localizedNumber.remove(separator); |
363 | } |
364 | } |
365 | |
366 | // remove negative sign if prefix already ends with '-' |
367 | if (!prefix.isEmpty() && prefix[prefix.length()-1] == '-' && !localizedNumber.isEmpty() && localizedNumber[0] == '-') { |
368 | localizedNumber = localizedNumber.mid(1); |
369 | } |
370 | |
371 | return prefix + localizedNumber + postfix; |
372 | } |
373 | |
374 | QString ValueFormatter::fractionFormat(Number value, Format::Type fmtType) |
375 | { |
376 | bool isNegative = value < 0; |
377 | QString prefix = isNegative ? "-" : "" ; |
378 | value = abs(value); |
379 | Number result = value - floor(numToDouble(value)); |
380 | int index; |
381 | int limit = 0; |
382 | |
383 | /* return w/o fraction part if not necessary */ |
384 | if (result == 0) |
385 | return prefix + QString::number((double) numToDouble(value)); |
386 | |
387 | switch (fmtType) { |
388 | case Format::fraction_half: |
389 | index = 2; |
390 | break; |
391 | case Format::fraction_quarter: |
392 | index = 4; |
393 | break; |
394 | case Format::fraction_eighth: |
395 | index = 8; |
396 | break; |
397 | case Format::fraction_sixteenth: |
398 | index = 16; |
399 | break; |
400 | case Format::fraction_tenth: |
401 | index = 10; |
402 | break; |
403 | case Format::fraction_hundredth: |
404 | index = 100; |
405 | break; |
406 | case Format::fraction_one_digit: |
407 | index = 3; |
408 | limit = 9; |
409 | break; |
410 | case Format::fraction_two_digits: |
411 | index = 4; |
412 | limit = 99; |
413 | break; |
414 | case Format::fraction_three_digits: |
415 | index = 5; |
416 | limit = 999; |
417 | break; |
418 | default: |
419 | kDebug(36001) << "Error in Fraction format" ; |
420 | return prefix + QString::number((double) numToDouble(value)); |
421 | break; |
422 | } /* switch */ |
423 | |
424 | |
425 | /* handle halves, quarters, tenths, ... */ |
426 | if (fmtType != Format::fraction_three_digits |
427 | && fmtType != Format::fraction_two_digits |
428 | && fmtType != Format::fraction_one_digit) { |
429 | Number calc = 0; |
430 | int index1 = 0; |
431 | Number diff = result; |
432 | for (int i = 1; i <= index; i++) { |
433 | calc = i * 1.0 / index; |
434 | if (fabs(result - calc) < diff) { |
435 | index1 = i; |
436 | diff = fabs(result - calc); |
437 | } |
438 | } |
439 | if (index1 == 0) return prefix + QString("%1" ).arg((double) floor(numToDouble(value))); |
440 | if (index1 == index) return prefix + QString("%1" ).arg((double) floor(numToDouble(value)) + 1); |
441 | if (floor(numToDouble(value)) == 0) |
442 | return prefix + QString("%1/%2" ).arg(index1).arg(index); |
443 | |
444 | return prefix + QString("%1 %2/%3" ) |
445 | .arg((double) floor(numToDouble(value))) |
446 | .arg(index1) |
447 | .arg(index); |
448 | } |
449 | |
450 | |
451 | /* handle Format::fraction_one_digit, Format::fraction_two_digit and Format::fraction_three_digit style */ |
452 | double target = numToDouble(result); |
453 | double numerator = 1; |
454 | double denominator = 1; |
455 | double bestNumerator = 0; |
456 | double bestDenominator = 1; |
457 | double bestDist = target; |
458 | |
459 | // as soon as either numerator or denominator gets above the limit, we're done |
460 | while (numerator <= limit && denominator <= limit) { |
461 | double dist = abs((numerator / denominator) - target); |
462 | if (dist < bestDist) { |
463 | bestDist = dist; |
464 | bestNumerator = numerator; |
465 | bestDenominator = denominator; |
466 | } |
467 | if (numerator / denominator > target) { |
468 | denominator++; |
469 | } else { |
470 | numerator++; |
471 | } |
472 | } |
473 | |
474 | if (bestNumerator == 0) |
475 | return prefix + QString().setNum((double) floor(numToDouble(value))); |
476 | else if (bestDenominator == bestNumerator) |
477 | return prefix + QString().setNum((double) floor(numToDouble(value + 1))); |
478 | else { |
479 | if (floor(numToDouble(value)) == 0) |
480 | return prefix + QString("%1/%2" ).arg(bestNumerator).arg(bestDenominator); |
481 | else |
482 | return prefix + QString("%1 %2/%3" ) |
483 | .arg((double)floor(numToDouble(value))) |
484 | .arg(bestNumerator) |
485 | .arg(bestDenominator); |
486 | } |
487 | } |
488 | |
489 | QString ValueFormatter::timeFormat(const QDateTime &_dt, Format::Type fmtType, const QString& formatString) |
490 | { |
491 | if (!formatString.isEmpty()) { |
492 | return _dt.toString( formatString ); |
493 | } |
494 | |
495 | const QDateTime dt(_dt.toUTC()); |
496 | QString result; |
497 | if (fmtType == Format::Time) |
498 | result = m_converter->settings()->locale()->formatTime(dt.time(), false); |
499 | else if (fmtType == Format::SecondeTime) |
500 | result = m_converter->settings()->locale()->formatTime(dt.time(), true); |
501 | else { |
502 | const int d = settings()->referenceDate().daysTo(dt.date()); |
503 | int h, m, s; |
504 | if (fmtType != Format::Time6 && fmtType != Format::Time7 && fmtType != Format::Time8) { // time |
505 | h = dt.time().hour(); |
506 | m = dt.time().minute(); |
507 | s = dt.time().second(); |
508 | } else if (d >= 0) { // positive duration |
509 | h = dt.time().hour() + 24 * d; |
510 | m = dt.time().minute(); |
511 | s = dt.time().second(); |
512 | } else { // negative duration |
513 | s = (60 - dt.time().second()) % 60; |
514 | m = (60 - dt.time().minute() - ((s == 0) ? 0 : 1)) % 60; |
515 | h = -(dt.time().hour() + 24 * d) - ((m == 0 && s == 0) ? 0 : 1); |
516 | } |
517 | const bool pm = (h > 12); |
518 | const QString sign = d < 0 ? QString('-') : QString("" ); |
519 | |
520 | if (fmtType == Format::Time1) { // 9:01 AM |
521 | result = QString("%1:%2 %3" ) |
522 | .arg(QString::number(pm ? h - 12 : h), 1) |
523 | .arg(QString::number(m), 2, '0') |
524 | .arg(pm ? i18n("PM" ) : i18n("AM" )); |
525 | } else if (fmtType == Format::Time2) { // 9:01:05 AM |
526 | result = QString("%1:%2:%3 %4" ) |
527 | .arg(QString::number(pm ? h - 12 : h), 1) |
528 | .arg(QString::number(m), 2, '0') |
529 | .arg(QString::number(s), 2, '0') |
530 | .arg(pm ? i18n("PM" ) : i18n("AM" )); |
531 | } else if (fmtType == Format::Time3) { // 9 h 01 min 28 s |
532 | result = QString("%1 %2 %3 %4 %5 %6" ) |
533 | .arg(QString::number(h), 2, '0') |
534 | .arg(i18n("h" )) |
535 | .arg(QString::number(m), 2, '0') |
536 | .arg(i18n("min" )) |
537 | .arg(QString::number(s), 2, '0') |
538 | .arg(i18n("s" )); |
539 | } else if (fmtType == Format::Time4) { // 9:01 |
540 | result = QString("%1:%2" ) |
541 | .arg(QString::number(h), 1) |
542 | .arg(QString::number(m), 2, '0'); |
543 | } else if (fmtType == Format::Time5) { // 9:01:12 |
544 | result = QString("%1:%2:%3" ) |
545 | .arg(QString::number(h), 1) |
546 | .arg(QString::number(m), 2, '0') |
547 | .arg(QString::number(s), 2, '0'); |
548 | } else if (fmtType == Format::Time6) { // [mm]:ss |
549 | result = sign + QString("%1:%2" ) |
550 | .arg(QString::number(m + h * 60), 2, '0') |
551 | .arg(QString::number(s), 2, '0'); |
552 | } else if (fmtType == Format::Time7) { // [h]:mm:ss |
553 | result = sign + QString("%1:%2:%3" ) |
554 | .arg(QString::number(h), 1) |
555 | .arg(QString::number(m), 2, '0') |
556 | .arg(QString::number(s), 2, '0'); |
557 | } else if (fmtType == Format::Time8) { // [h]:mm |
558 | result = sign + QString("%1:%2" ) |
559 | .arg(QString::number(h), 1) |
560 | .arg(QString::number(m), 2, '0'); |
561 | } |
562 | } |
563 | return result; |
564 | } |
565 | |
566 | QString ValueFormatter::dateTimeFormat(const QDateTime &_dt, Format::Type fmtType, const QString& formatString ) |
567 | { |
568 | if( !formatString.isEmpty() ) { |
569 | if (formatString.contains('X')) { // if we have the special extra-short month in the format string |
570 | int monthPos = formatString.indexOf('X'); |
571 | QString before = formatString.left(monthPos); // get string before and after the extra-short month sign |
572 | QString after = formatString.right(formatString.size() - monthPos - 1); |
573 | QString monthShort = _dt.toString("MMM" ).left(1); // format the month as extra-short (only 1st letter) |
574 | return _dt.toString( before ) + monthShort + _dt.toString( after ); // and construct the final date |
575 | } |
576 | |
577 | return _dt.toString( formatString ); |
578 | } |
579 | |
580 | Q_UNUSED(fmtType); |
581 | QString result; |
582 | // pretty lame, just asssuming something for the format |
583 | // TODO: locale-aware formatting |
584 | result += dateFormat(_dt.date(), Format::ShortDate) + ' ' + timeFormat(_dt, Format::Time1); |
585 | return result; |
586 | } |
587 | |
588 | QString ValueFormatter::dateFormat(const QDate &date, Format::Type fmtType, const QString& formatString ) |
589 | { |
590 | if( !formatString.isEmpty() ) { |
591 | return date.toString( formatString ); |
592 | } |
593 | |
594 | QString tmp; |
595 | if (fmtType == Format::ShortDate) { |
596 | tmp = m_converter->settings()->locale()->formatDate(date, KLocale::ShortDate); |
597 | } else if (fmtType == Format::TextDate) { |
598 | tmp = m_converter->settings()->locale()->formatDate(date, KLocale::LongDate); |
599 | } else if (fmtType == Format::Date1) { /*18-Feb-99 */ |
600 | tmp = QString().sprintf("%02d" , date.day()) + |
601 | '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
602 | '-' + QString::number(date.year()).right(2); |
603 | } else if (fmtType == Format::Date2) { /*18-Feb-1999 */ |
604 | tmp = QString().sprintf("%02d" , date.day()) + |
605 | '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
606 | '-' + QString::number(date.year()); |
607 | } else if (fmtType == Format::Date3) { /*18-Feb */ |
608 | tmp = QString().sprintf("%02d" , date.day()) + |
609 | '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber); |
610 | } else if (fmtType == Format::Date4) { /*18-05 */ |
611 | tmp = QString().sprintf("%02d" , date.day()) + |
612 | '-' + QString().sprintf("%02d" , date.month()); |
613 | } else if (fmtType == Format::Date5) { /*18/05/00 */ |
614 | tmp = QString().sprintf("%02d" , date.day()) + |
615 | '/' + QString().sprintf("%02d" , date.month()) + |
616 | '/' + QString::number(date.year()).right(2); |
617 | } else if (fmtType == Format::Date6) { /*18/05/1999 */ |
618 | tmp = QString().sprintf("%02d" , date.day()) + |
619 | '/' + QString().sprintf("%02d" , date.month()) + |
620 | '/' + QString::number(date.year()); |
621 | } else if (fmtType == Format::Date7) { /*Feb-99 */ |
622 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
623 | '-' + QString::number(date.year()).right(2); |
624 | } else if (fmtType == Format::Date8) { /*February-99 */ |
625 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + |
626 | '-' + QString::number(date.year()).right(2); |
627 | } else if (fmtType == Format::Date9) { /*February-1999 */ |
628 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + |
629 | '-' + QString::number(date.year()); |
630 | } else if (fmtType == Format::Date10) { /*F-99 */ |
631 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber).at(0) + |
632 | '-' + QString::number(date.year()).right(2); |
633 | } else if (fmtType == Format::Date11) { /*18/Feb */ |
634 | tmp = QString().sprintf("%02d" , date.day()) |
635 | + '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber); |
636 | } else if (fmtType == Format::Date12) { /*18/02 */ |
637 | tmp = QString().sprintf("%02d" , date.day()) + |
638 | '/' + QString().sprintf("%02d" , date.month()); |
639 | } else if (fmtType == Format::Date13) { /*18/Feb/1999 */ |
640 | tmp = QString().sprintf("%02d" , date.day()) + |
641 | '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
642 | '/' + QString::number(date.year()); |
643 | } else if (fmtType == Format::Date14) { /*2000/Feb/18 */ |
644 | tmp = QString::number(date.year()) + |
645 | '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
646 | '/' + QString().sprintf("%02d" , date.day()); |
647 | } else if (fmtType == Format::Date15) { /*2000-Feb-18 */ |
648 | tmp = QString::number(date.year()) + |
649 | '-' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
650 | '-' + QString().sprintf("%02d" , date.day()); |
651 | } else if (fmtType == Format::Date16) { /*2000-02-18 */ |
652 | tmp = QString::number(date.year()) + |
653 | '-' + QString().sprintf("%02d" , date.month()) + |
654 | '-' + QString().sprintf("%02d" , date.day()); |
655 | } else if (fmtType == Format::Date17) { /*2 february 2000 */ |
656 | tmp = QString().sprintf("%d" , date.day()) + |
657 | ' ' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + |
658 | ' ' + QString::number(date.year()); |
659 | } else if (fmtType == Format::Date18) { /*02/18/1999 */ |
660 | tmp = QString().sprintf("%02d" , date.month()) + |
661 | '/' + QString().sprintf("%02d" , date.day()) + |
662 | '/' + QString::number(date.year()); |
663 | } else if (fmtType == Format::Date19) { /*02/18/99 */ |
664 | tmp = QString().sprintf("%02d" , date.month()) + |
665 | '/' + QString().sprintf("%02d" , date.day()) + |
666 | '/' + QString::number(date.year()).right(2); |
667 | } else if (fmtType == Format::Date20) { /*Feb/18/99 */ |
668 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
669 | '/' + QString().sprintf("%02d" , date.day()) + |
670 | '/' + QString::number(date.year()).right(2); |
671 | } else if (fmtType == Format::Date21) { /*Feb/18/1999 */ |
672 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
673 | '/' + QString().sprintf("%02d" , date.day()) + |
674 | '/' + QString::number(date.year()); |
675 | } else if (fmtType == Format::Date22) { /*Feb-1999 */ |
676 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
677 | '-' + QString::number(date.year()); |
678 | } else if (fmtType == Format::Date23) { /*1999 */ |
679 | tmp = QString::number(date.year()); |
680 | } else if (fmtType == Format::Date24) { /*99 */ |
681 | tmp = QString::number(date.year()).right(2); |
682 | } else if (fmtType == Format::Date25) { /*2000/02/18 */ |
683 | tmp = QString::number(date.year()) + |
684 | '/' + QString().sprintf("%02d" , date.month()) + |
685 | '/' + QString().sprintf("%02d" , date.day()); |
686 | } else if (fmtType == Format::Date26) { /*2000/Feb/18 */ |
687 | tmp = QString::number(date.year()) + |
688 | '/' + m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
689 | '/' + QString().sprintf("%02d" , date.day()); |
690 | } else if (fmtType == Format::Date27) { /*Feb/99 */ |
691 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
692 | '/' + QString::number(date.year()).right(2); |
693 | } else if (fmtType == Format::Date28) { /*Feb/1999 */ |
694 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::ShortNumber) + |
695 | '/' + QString::number(date.year()); |
696 | } else if (fmtType == Format::Date29) { /*February/99 */ |
697 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + |
698 | '/' + QString::number(date.year()).right(2); |
699 | } else if (fmtType == Format::Date30) { /*February/1999 */ |
700 | tmp = m_converter->settings()->locale()->calendar()->formatDate(date, KLocale::Month, KLocale::LongNumber) + |
701 | '/' + QString::number(date.year()); |
702 | } else if (fmtType == Format::Date31) { /*18-02 */ |
703 | tmp = QString().sprintf("%02d" , date.day()) + |
704 | '-' + QString().sprintf("%02d" , date.month()); |
705 | } else if (fmtType == Format::Date32) { /*02/99 */ |
706 | tmp = QString().sprintf("%02d" , date.month()) + '/' + |
707 | QString::number(date.year()).right(2); |
708 | } else if (fmtType == Format::Date33) { /*02-99 */ |
709 | tmp = QString().sprintf("%02d" , date.month()) + |
710 | '-' + QString::number(date.year()).right(2); |
711 | } else if (fmtType == Format::Date34 || fmtType == Format::Date35) { /*Mon, 2 Feb 2000 and Mon, 2 February 2000 */ |
712 | QLocale l(QLocale::English); |
713 | tmp = l.toString(date, fmtType == Format::Date34 ? "ddd d MMM yy" : "dddd d MMM yyyy" ); |
714 | } else { /*fallback... */ |
715 | tmp = m_converter->settings()->locale()->formatDate(date, KLocale::ShortDate); |
716 | } |
717 | |
718 | // Missing compared with gnumeric: |
719 | // "m/d/yy h:mm", /* 20 */ |
720 | // "m/d/yyyy h:mm", /* 21 */ |
721 | // "mmm/ddd/yy", /* 12 */ |
722 | // "mmm/ddd/yyyy", /* 13 */ |
723 | // "mm/ddd/yy", /* 14 */ |
724 | // "mm/ddd/yyyy", /* 15 */ |
725 | |
726 | return tmp; |
727 | } |
728 | |
729 | QString ValueFormatter::complexFormat(const Value& value, int precision, |
730 | Format::Type formatType, |
731 | Style::FloatFormat floatFormat, |
732 | const QString& currencySymbol, |
733 | bool thousandsSep) |
734 | { |
735 | // FIXME Stefan: percentage, currency and scientific formats! |
736 | QString str; |
737 | const Number real = value.asComplex().real(); |
738 | const Number imag = value.asComplex().imag(); |
739 | str = createNumberFormat(real, precision, formatType, floatFormat, QString(), QString(), thousandsSep); |
740 | str += createNumberFormat(imag, precision, formatType, Style::AlwaysSigned, currencySymbol, QString(), thousandsSep); |
741 | str += 'i'; |
742 | return str; |
743 | } |
744 | |