File indexing completed on 2024-05-12 16:35:35
0001 /* This file is part of the KDE project 0002 Copyright (C) 1998-2002 The KSpread Team <calligra-devel@kde.org> 0003 Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; only 0008 version 2 of the License. 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 0022 // built-in text functions 0023 #include "TextModule.h" 0024 0025 #include <math.h> 0026 0027 #include <QRegExp> 0028 0029 #include <klocale.h> 0030 0031 #include "SheetsDebug.h" 0032 #include "CalculationSettings.h" 0033 #include "Function.h" 0034 #include "FunctionModuleRegistry.h" 0035 #include "ValueCalc.h" 0036 #include "ValueConverter.h" 0037 #include "ValueFormatter.h" 0038 0039 using namespace Calligra::Sheets; 0040 0041 // Functions DOLLAR and FIXED convert data to double, hence they will not 0042 // support arbitrary precision, when it will be introduced. 0043 0044 // prototypes 0045 Value func_asc(valVector args, ValueCalc *calc, FuncExtra *); 0046 Value func_char(valVector args, ValueCalc *calc, FuncExtra *); 0047 Value func_clean(valVector args, ValueCalc *calc, FuncExtra *); 0048 Value func_code(valVector args, ValueCalc *calc, FuncExtra *); 0049 Value func_compare(valVector args, ValueCalc *calc, FuncExtra *); 0050 Value func_concatenate(valVector args, ValueCalc *calc, FuncExtra *); 0051 Value func_dollar(valVector args, ValueCalc *calc, FuncExtra *); 0052 Value func_exact(valVector args, ValueCalc *calc, FuncExtra *); 0053 Value func_find(valVector args, ValueCalc *calc, FuncExtra *); 0054 Value func_fixed(valVector args, ValueCalc *calc, FuncExtra *); 0055 Value func_jis(valVector args, ValueCalc *calc, FuncExtra *); 0056 Value func_left(valVector args, ValueCalc *calc, FuncExtra *); 0057 Value func_len(valVector args, ValueCalc *calc, FuncExtra *); 0058 Value func_lower(valVector args, ValueCalc *calc, FuncExtra *); 0059 Value func_mid(valVector args, ValueCalc *calc, FuncExtra *); 0060 Value func_numbervalue(valVector args, ValueCalc *calc, FuncExtra *); 0061 Value func_proper(valVector args, ValueCalc *calc, FuncExtra *); 0062 Value func_regexp(valVector args, ValueCalc *calc, FuncExtra *); 0063 Value func_regexpre(valVector args, ValueCalc *calc, FuncExtra *); 0064 Value func_replace(valVector args, ValueCalc *calc, FuncExtra *); 0065 Value func_rept(valVector args, ValueCalc *calc, FuncExtra *); 0066 Value func_rot13(valVector args, ValueCalc *calc, FuncExtra *); 0067 Value func_right(valVector args, ValueCalc *calc, FuncExtra *); 0068 Value func_search(valVector args, ValueCalc *calc, FuncExtra *); 0069 Value func_sleek(valVector args, ValueCalc *calc, FuncExtra *); 0070 Value func_substitute(valVector args, ValueCalc *calc, FuncExtra *); 0071 Value func_t (valVector args, ValueCalc *calc, FuncExtra *); 0072 Value func_text(valVector args, ValueCalc *calc, FuncExtra *); 0073 Value func_toggle(valVector args, ValueCalc *calc, FuncExtra *); 0074 Value func_trim(valVector args, ValueCalc *calc, FuncExtra *); 0075 Value func_unichar(valVector args, ValueCalc *calc, FuncExtra *); 0076 Value func_unicode(valVector args, ValueCalc *calc, FuncExtra *); 0077 Value func_upper(valVector args, ValueCalc *calc, FuncExtra *); 0078 Value func_value(valVector args, ValueCalc *calc, FuncExtra *); 0079 Value func_bahttext(valVector args, ValueCalc *calc, FuncExtra *); 0080 0081 0082 CALLIGRA_SHEETS_EXPORT_FUNCTION_MODULE("kspreadtextmodule.json", TextModule) 0083 0084 0085 TextModule::TextModule(QObject* parent, const QVariantList&) 0086 : FunctionModule(parent) 0087 { 0088 Function *f; 0089 0090 // one-parameter functions 0091 f = new Function("ASC", func_asc); 0092 add(f); 0093 f = new Function("CHAR", func_char); 0094 add(f); 0095 f = new Function("CLEAN", func_clean); 0096 add(f); 0097 f = new Function("CODE", func_code); 0098 add(f); 0099 f = new Function("JIS", func_jis); 0100 add(f); 0101 f = new Function("LEN", func_len); 0102 f->setAlternateName("LENB"); 0103 add(f); 0104 f = new Function("LOWER", func_lower); 0105 add(f); 0106 f = new Function("PROPER", func_proper); 0107 add(f); 0108 f = new Function("ROT13", func_rot13); 0109 f->setAlternateName("COM.SUN.STAR.SHEET.ADDIN.DATEFUNCTIONS.GETROT13"); 0110 add(f); 0111 f = new Function("SLEEK", func_sleek); 0112 add(f); 0113 f = new Function("T", func_t); 0114 add(f); 0115 f = new Function("TOGGLE", func_toggle); 0116 add(f); 0117 f = new Function("TRIM", func_trim); 0118 add(f); 0119 f = new Function("UNICHAR", func_unichar); 0120 add(f); 0121 f = new Function("UNICODE", func_unicode); 0122 add(f); 0123 f = new Function("UPPER", func_upper); 0124 add(f); 0125 f = new Function("VALUE", func_value); 0126 add(f); 0127 0128 // other functions 0129 f = new Function("COMPARE", func_compare); 0130 f->setParamCount(3); 0131 add(f); 0132 f = new Function("CONCATENATE", func_concatenate); 0133 f->setParamCount(1, -1); 0134 f->setAcceptArray(); 0135 add(f); 0136 f = new Function("DOLLAR", func_dollar); 0137 f->setParamCount(1, 2); 0138 add(f); 0139 f = new Function("EXACT", func_exact); 0140 f->setParamCount(2); 0141 add(f); 0142 f = new Function("FIND", func_find); 0143 f->setParamCount(2, 3); 0144 f->setAlternateName("FINDB"); 0145 add(f); 0146 f = new Function("FIXED", func_fixed); 0147 f->setParamCount(1, 3); 0148 add(f); 0149 f = new Function("LEFT", func_left); 0150 f->setParamCount(1, 2); 0151 f->setAlternateName("LEFTB"); 0152 add(f); 0153 f = new Function("MID", func_mid); 0154 f->setParamCount(2, 3); 0155 f->setAlternateName("MIDB"); 0156 add(f); 0157 f = new Function("NUMBERVALUE", func_numbervalue); 0158 f->setParamCount(2, 3); 0159 add(f); 0160 f = new Function("REGEXP", func_regexp); 0161 f->setParamCount(2, 4); 0162 add(f); 0163 f = new Function("REGEXPRE", func_regexpre); 0164 f->setParamCount(3); 0165 add(f); 0166 f = new Function("REPLACE", func_replace); 0167 f->setParamCount(4); 0168 f->setAlternateName("REPLACEB"); 0169 add(f); 0170 f = new Function("REPT", func_rept); 0171 f->setParamCount(2); 0172 add(f); 0173 f = new Function("RIGHT", func_right); 0174 f->setParamCount(1, 2); 0175 f->setAlternateName("RIGHTB"); 0176 add(f); 0177 f = new Function("SEARCH", func_search); 0178 f->setParamCount(2, 3); 0179 f->setAlternateName("SEARCHB"); 0180 add(f); 0181 f = new Function("SUBSTITUTE", func_substitute); 0182 f->setParamCount(3, 4); 0183 add(f); 0184 f = new Function("TEXT", func_text); 0185 f->setParamCount(1, 2); 0186 add(f); 0187 f = new Function("BAHTTEXT", func_bahttext); 0188 f->setAlternateName("COM.MICROSOFT.BAHTTEXT"); 0189 f->setParamCount(1); 0190 add(f); 0191 } 0192 0193 QString TextModule::descriptionFileName() const 0194 { 0195 return QString("text.xml"); 0196 } 0197 0198 0199 // Function: ASC 0200 Value func_asc(valVector args, ValueCalc *calc, FuncExtra *) 0201 { 0202 QString s = calc->conv()->asString(args[0]).asString(); 0203 return Value(QString(s)); 0204 } 0205 0206 // Function: CHAR 0207 Value func_char(valVector args, ValueCalc *calc, FuncExtra *) 0208 { 0209 int val = calc->conv()->asInteger(args[0]).asInteger(); 0210 if (val >= 0) 0211 return Value(QString(QChar(val))); 0212 else 0213 return Value::errorNUM(); 0214 } 0215 0216 // Function: CLEAN 0217 Value func_clean(valVector args, ValueCalc *calc, FuncExtra *) 0218 { 0219 QString str(calc->conv()->asString(args[0]).asString()); 0220 QString result; 0221 QChar c; 0222 int i; 0223 int l = str.length(); 0224 0225 for (i = 0; i < l; ++i) { 0226 c = str[i]; 0227 if (c.isPrint()) 0228 result += c; 0229 } 0230 0231 return Value(result); 0232 } 0233 0234 // Function: CODE 0235 Value func_code(valVector args, ValueCalc *calc, FuncExtra *) 0236 { 0237 QString str(calc->conv()->asString(args[0]).asString()); 0238 if (str.length() <= 0) 0239 return Value::errorVALUE(); 0240 0241 return Value(str[0].unicode()); 0242 } 0243 0244 // Function: COMPARE 0245 Value func_compare(valVector args, ValueCalc *calc, FuncExtra *) 0246 { 0247 int result = 0; 0248 bool exact = calc->conv()->asBoolean(args[2]).asBoolean(); 0249 0250 QString s1 = calc->conv()->asString(args[0]).asString(); 0251 QString s2 = calc->conv()->asString(args[1]).asString(); 0252 0253 if (!exact) 0254 result = s1.toLower().localeAwareCompare(s2.toLower()); 0255 else 0256 result = s1.localeAwareCompare(s2); 0257 0258 if (result < 0) 0259 result = -1; 0260 else if (result > 0) 0261 result = 1; 0262 0263 return Value(result); 0264 } 0265 0266 void func_concatenate_helper(Value val, ValueCalc *calc, 0267 QString& tmp) 0268 { 0269 if (val.isArray()) { 0270 for (unsigned int row = 0; row < val.rows(); ++row) 0271 for (unsigned int col = 0; col < val.columns(); ++col) 0272 func_concatenate_helper(val.element(col, row), calc, tmp); 0273 } else 0274 tmp += calc->conv()->asString(val).asString(); 0275 } 0276 0277 // Function: CONCATENATE 0278 Value func_concatenate(valVector args, ValueCalc *calc, FuncExtra *) 0279 { 0280 QString tmp; 0281 for (int i = 0; i < args.count(); ++i) 0282 func_concatenate_helper(args[i], calc, tmp); 0283 0284 return Value(tmp); 0285 } 0286 0287 // Function: DOLLAR 0288 Value func_dollar(valVector args, ValueCalc *calc, FuncExtra *) 0289 { 0290 // ValueConverter doesn't support money directly, hence we need to 0291 // use the locale. This code has the same effect as the output 0292 // of ValueFormatter for money format. 0293 0294 // This function converts data to double/int, hence it won't support 0295 // larger precision. 0296 0297 double value = numToDouble(calc->conv()->toFloat(args[0])); 0298 int precision = 2; 0299 if (args.count() == 2) 0300 precision = calc->conv()->asInteger(args[1]).asInteger(); 0301 0302 // do round, because formatMoney doesn't 0303 value = floor(value * pow(10.0, precision) + 0.5) / pow(10.0, precision); 0304 0305 const KLocale *locale = calc->settings()->locale(); 0306 QString s = locale->formatMoney(value, locale->currencySymbol(), precision); 0307 0308 return Value(s); 0309 } 0310 0311 // Function: EXACT 0312 Value func_exact(valVector args, ValueCalc *calc, FuncExtra *) 0313 { 0314 QString s1 = calc->conv()->asString(args[0]).asString(); 0315 QString s2 = calc->conv()->asString(args[1]).asString(); 0316 bool exact = (s1 == s2); 0317 return Value(exact); 0318 } 0319 0320 // Function: FIND 0321 Value func_find(valVector args, ValueCalc *calc, FuncExtra *) 0322 { 0323 QString find_text, within_text; 0324 int start_num = 1; 0325 0326 find_text = calc->conv()->asString(args[0]).asString(); 0327 within_text = calc->conv()->asString(args[1]).asString(); 0328 if (args.count() == 3) 0329 start_num = calc->conv()->asInteger(args[2]).asInteger(); 0330 0331 // conforms to Excel behaviour 0332 if (start_num <= 0) return Value::errorVALUE(); 0333 if (start_num > (int)within_text.length()) return Value::errorVALUE(); 0334 0335 int pos = within_text.indexOf(find_text, start_num - 1); 0336 if (pos < 0) return Value::errorVALUE(); 0337 0338 return Value(pos + 1); 0339 } 0340 0341 // Function: FIXED 0342 Value func_fixed(valVector args, ValueCalc *calc, FuncExtra *) 0343 { 0344 // uses double, hence won't support big precision 0345 0346 int decimals = 2; 0347 bool decimalsIsNegative = false; 0348 bool no_commas = false; 0349 0350 double number = numToDouble(calc->conv()->toFloat(args[0])); 0351 if (args.count() > 1) { 0352 if (args[1].less(Value(0))) { 0353 decimalsIsNegative = true; 0354 decimals = -1 * ((calc->roundUp(args[1])).asInteger()); 0355 } else { 0356 decimals = calc->conv()->asInteger(args[1]).asInteger(); 0357 } 0358 } 0359 if (args.count() == 3) 0360 no_commas = calc->conv()->asBoolean(args[2]).asBoolean(); 0361 0362 QString result; 0363 const KLocale *locale = calc->settings()->locale(); 0364 0365 // unfortunately, we can't just use KLocale::formatNumber because 0366 // * if decimals < 0, number is rounded 0367 // * if no_commas is true, thousand separators shouldn't show up 0368 0369 if (decimalsIsNegative) { 0370 number = floor(number / pow(10.0, decimals) + 0.5) * pow(10.0, decimals); 0371 decimals = 0; 0372 } 0373 0374 bool neg = number < 0; 0375 result = QString::number(neg ? -number : number, 'f', decimals); 0376 0377 int pos = result.indexOf('.'); 0378 if (pos == -1) pos = result.length(); 0379 else result.replace(pos, 1, locale->decimalSymbol()); 0380 if (!no_commas) 0381 while (0 < (pos -= 3)) 0382 result.insert(pos, locale->thousandsSeparator()); 0383 0384 result.prepend(neg ? locale->negativeSign() : 0385 locale->positiveSign()); 0386 0387 return Value(result); 0388 } 0389 0390 // Function: JIS 0391 Value func_jis(valVector args, ValueCalc *calc, FuncExtra *) 0392 { 0393 Q_UNUSED(args); 0394 Q_UNUSED(calc); 0395 return Value(QString("FIXME JIS()")); 0396 } 0397 0398 // Function: LEFT 0399 Value func_left(valVector args, ValueCalc *calc, FuncExtra *) 0400 { 0401 QString str = calc->conv()->asString(args[0]).asString(); 0402 int nb = 1; 0403 if (args.count() == 2) 0404 nb = calc->conv()->asInteger(args[1]).asInteger(); 0405 if (nb < 0) 0406 return Value::errorVALUE(); 0407 0408 return Value(str.left(nb)); 0409 } 0410 0411 // Function: LEN 0412 Value func_len(valVector args, ValueCalc *calc, FuncExtra *) 0413 { 0414 int nb = calc->conv()->asString(args[0]).asString().length(); 0415 return Value(nb); 0416 } 0417 0418 // Function: LOWER 0419 Value func_lower(valVector args, ValueCalc *calc, FuncExtra *) 0420 { 0421 return Value(calc->conv()->asString(args[0]).asString().toLower()); 0422 } 0423 0424 // Function: MID 0425 Value func_mid(valVector args, ValueCalc *calc, FuncExtra *) 0426 { 0427 QString str = calc->conv()->asString(args[0]).asString(); 0428 0429 int pos = calc->conv()->asInteger(args[1]).asInteger(); 0430 if (pos < 0) { 0431 return Value::errorVALUE(); 0432 } 0433 0434 int len = 0x7fffffff; 0435 if (args.count() == 3) { 0436 len = (uint) calc->conv()->asInteger(args[2]).asInteger(); 0437 // the length cannot be less than zero 0438 if (len < 0) 0439 return Value::errorVALUE(); 0440 } 0441 0442 // Excel compatible 0443 pos--; 0444 0445 // workaround for Qt bug 0446 if (len > 0x7fffffff - pos) len = 0x7fffffff - pos; 0447 0448 return Value(str.mid(pos, len)); 0449 } 0450 0451 // Function: NUMBERVALUE 0452 Value func_numbervalue(valVector args, ValueCalc *calc, FuncExtra *) 0453 { 0454 QString text = calc->conv()->asString(args[0]).asString(); 0455 0456 QString decimalPoint = calc->conv()->asString(args[1]).asString(); 0457 0458 QString thousandsSeparator; 0459 if (args.count() >= 3) 0460 thousandsSeparator = calc->conv()->asString(args[2]).asString(); 0461 else if (decimalPoint == ".") 0462 thousandsSeparator = ','; 0463 else if (decimalPoint == ",") 0464 thousandsSeparator = '.'; 0465 0466 KLocale l(*KLocale::global()); 0467 l.setDecimalSymbol(decimalPoint); 0468 l.setThousandsSeparator(thousandsSeparator); 0469 l.setPositiveSign("+"); 0470 l.setNegativeSign("-"); 0471 0472 bool ok; 0473 double v = l.readNumber(text, &ok); 0474 return ok ? Value(v) : Value::errorVALUE(); 0475 } 0476 0477 // Function: PROPER 0478 Value func_proper(valVector args, ValueCalc *calc, FuncExtra *) 0479 { 0480 QString str = calc->conv()->asString(args[0]).asString().toLower(); 0481 0482 QChar f; 0483 bool first = true; 0484 0485 for (int i = 0; i < str.length(); ++i) { 0486 if (first) { 0487 f = str[i]; 0488 if (f.isNumber()) 0489 continue; 0490 0491 f = f.toUpper(); 0492 0493 str[i] = f; 0494 first = false; 0495 0496 continue; 0497 } 0498 0499 if (str[i].isSpace() || str[i].isPunct()) 0500 first = true; 0501 } 0502 0503 return Value(str); 0504 } 0505 0506 // Function: REGEXP 0507 Value func_regexp(valVector args, ValueCalc *calc, FuncExtra *) 0508 { 0509 // ensure that we got a valid regular expression 0510 QRegExp exp(calc->conv()->asString(args[1]).asString()); 0511 if (!exp.isValid()) 0512 return Value::errorVALUE(); 0513 0514 QString s = calc->conv()->asString(args[0]).asString(); 0515 QString defText; 0516 if (args.count() > 2) 0517 defText = calc->conv()->asString(args[2]).asString(); 0518 int bkref = 0; 0519 if (args.count() == 4) 0520 bkref = calc->conv()->asInteger(args[3]).asInteger(); 0521 if (bkref < 0) // strange back-reference 0522 return Value::errorVALUE(); 0523 0524 QString returnValue; 0525 0526 int pos = exp.indexIn(s); 0527 if (pos == -1) 0528 returnValue = defText; 0529 else 0530 returnValue = exp.cap(bkref); 0531 0532 return Value(returnValue); 0533 } 0534 0535 // Function: REGEXPRE 0536 Value func_regexpre(valVector args, ValueCalc *calc, FuncExtra *) 0537 { 0538 // ensure that we got a valid regular expression 0539 QRegExp exp(calc->conv()->asString(args[1]).asString()); 0540 if (!exp.isValid()) 0541 return Value::errorVALUE(); 0542 0543 QString s = calc->conv()->asString(args[0]).asString(); 0544 QString str = calc->conv()->asString(args[2]).asString(); 0545 0546 int pos = 0; 0547 while ((pos = exp.indexIn(s, pos)) != -1) { 0548 int i = exp.matchedLength(); 0549 s = s.replace(pos, i, str); 0550 pos += str.length(); 0551 } 0552 0553 return Value(s); 0554 } 0555 0556 // Function: REPLACE 0557 Value func_replace(valVector args, ValueCalc *calc, FuncExtra *) 0558 { 0559 QString text = calc->conv()->asString(args[0]).asString(); 0560 int pos = calc->conv()->asInteger(args[1]).asInteger(); 0561 int len = calc->conv()->asInteger(args[2]).asInteger(); 0562 QString new_text = calc->conv()->asString(args[3]).asString(); 0563 0564 if (pos < 0) pos = 0; 0565 0566 QString result = text.replace(pos - 1, len, new_text); 0567 return Value(result); 0568 } 0569 0570 // Function: REPT 0571 Value func_rept(valVector args, ValueCalc *calc, FuncExtra *) 0572 { 0573 QString s = calc->conv()->asString(args[0]).asString(); 0574 int nb = calc->conv()->asInteger(args[1]).asInteger(); 0575 0576 if (nb < 0) 0577 return Value::errorVALUE(); 0578 0579 QString result; 0580 for (int i = 0; i < nb; i++) result += s; 0581 return Value(result); 0582 } 0583 0584 // Function: RIGHT 0585 Value func_right(valVector args, ValueCalc *calc, FuncExtra *) 0586 { 0587 QString str = calc->conv()->asString(args[0]).asString(); 0588 int nb = 1; 0589 if (args.count() == 2) 0590 nb = calc->conv()->asInteger(args[1]).asInteger(); 0591 0592 if (nb < 0) 0593 return Value::errorVALUE(); 0594 0595 return Value(str.right(nb)); 0596 } 0597 0598 // Function: ROT13 0599 Value func_rot13(valVector args, ValueCalc *calc, FuncExtra *) 0600 { 0601 QString text = calc->conv()->asString(args[0]).asString(); 0602 0603 for (int i = 0; i < text.length(); i++) { 0604 unsigned c = text[i].toUpper().unicode(); 0605 if ((c >= 'A') && (c <= 'M')) 0606 text[i] = QChar(text[i].unicode() + 13); 0607 if ((c >= 'N') && (c <= 'Z')) 0608 text[i] = QChar(text[i].unicode() - 13); 0609 } 0610 0611 return Value(text); 0612 } 0613 0614 // Function: SEARCH 0615 Value func_search(valVector args, ValueCalc *calc, FuncExtra *) 0616 { 0617 QString find_text = calc->conv()->asString(args[0]).asString(); 0618 QString within_text = calc->conv()->asString(args[1]).asString(); 0619 int start_num = 1; 0620 if (args.count() == 3) 0621 start_num = calc->conv()->asInteger(args[2]).asInteger(); 0622 0623 // conforms to Excel behaviour 0624 if (start_num <= 0) return Value::errorVALUE(); 0625 if (start_num > (int)within_text.length()) return Value::errorVALUE(); 0626 0627 // use globbing feature of QRegExp 0628 QRegExp regex(find_text, Qt::CaseInsensitive, QRegExp::Wildcard); 0629 int pos = within_text.indexOf(regex, start_num - 1); 0630 if (pos < 0) return Value::errorNA(); 0631 0632 return Value(pos + 1); 0633 } 0634 0635 // Function: SLEEK 0636 Value func_sleek(valVector args, ValueCalc *calc, FuncExtra *) 0637 { 0638 QString str = calc->conv()->asString(args[0]).asString(); 0639 QString result; 0640 QChar c; 0641 int i; 0642 int l = str.length(); 0643 0644 for (i = 0; i < l; ++i) { 0645 c = str[i]; 0646 if (!c.isSpace()) 0647 result += c; 0648 } 0649 0650 return Value(result); 0651 } 0652 0653 // Function: SUBSTITUTE 0654 Value func_substitute(valVector args, ValueCalc *calc, FuncExtra *) 0655 { 0656 int occurrence = 1; 0657 bool all = true; 0658 0659 if (args.count() == 4) { 0660 occurrence = calc->conv()->asInteger(args[3]).asInteger(); 0661 all = false; 0662 } 0663 0664 QString text = calc->conv()->asString(args[0]).asString(); 0665 QString old_text = calc->conv()->asString(args[1]).asString(); 0666 QString new_text = calc->conv()->asString(args[2]).asString(); 0667 0668 if (occurrence <= 0) return Value::errorVALUE(); 0669 if (old_text.length() == 0) return Value(text); 0670 0671 QString result = text; 0672 0673 if (all) { 0674 result.replace(old_text, new_text); // case-sensitive 0675 } else { 0676 // We are only looking to modify a single value, by position. 0677 int position = -1; 0678 for (int i = 0; i < occurrence; ++i) { 0679 position = result.indexOf(old_text, position + 1); 0680 } 0681 result.replace(position, old_text.size(), new_text); 0682 } 0683 0684 return Value(result); 0685 } 0686 0687 // Function: T 0688 Value func_t (valVector args, ValueCalc *calc, FuncExtra *) 0689 { 0690 if (args[0].isString()) 0691 return calc->conv()->asString(args[0]); 0692 else 0693 return Value(""); 0694 } 0695 0696 // Function: TEXT 0697 Value func_text(valVector args, ValueCalc *calc, FuncExtra *) 0698 { 0699 ValueFormatter fmt(calc->conv()); 0700 0701 return Value(fmt.formatText(args[0], Format::Generic, -1, Style::OnlyNegSigned, 0702 QString(), QString(), QString(), 0703 calc->conv()->asString(args[1]).asString())); 0704 } 0705 0706 // Function: TOGGLE 0707 Value func_toggle(valVector args, ValueCalc *calc, FuncExtra *) 0708 { 0709 QString str = calc->conv()->asString(args[0]).asString(); 0710 int i; 0711 int l = str.length(); 0712 0713 for (i = 0; i < l; ++i) { 0714 QChar c = str[i]; 0715 QChar lc = c.toLower(); 0716 QChar uc = c.toUpper(); 0717 0718 if (c == lc) // it is in lowercase 0719 str[i] = c.toUpper(); 0720 else if (c == uc) // it is in uppercase 0721 str[i] = c.toLower(); 0722 } 0723 0724 return Value(str); 0725 } 0726 0727 // Function: TRIM 0728 Value func_trim(valVector args, ValueCalc *calc, FuncExtra *) 0729 { 0730 return Value( 0731 calc->conv()->asString(args[0]).asString().simplified()); 0732 } 0733 0734 // Function: UNICHAR 0735 Value func_unichar(valVector args, ValueCalc *calc, FuncExtra *) 0736 { 0737 ushort val = calc->conv()->asInteger(args[0]).asInteger(); 0738 if (val > 0) { 0739 QString str; 0740 str.setUtf16(&val, 1); 0741 return Value(str); 0742 } else 0743 return Value::errorNUM(); 0744 } 0745 0746 // Function: UNICODE 0747 Value func_unicode(valVector args, ValueCalc *calc, FuncExtra *) 0748 { 0749 QString str(calc->conv()->asString(args[0]).asString()); 0750 if (str.length() <= 0) 0751 return Value::errorVALUE(); 0752 0753 return Value((int)str.toUcs4().at(0)); 0754 } 0755 0756 // Function: UPPER 0757 Value func_upper(valVector args, ValueCalc *calc, FuncExtra *) 0758 { 0759 return Value(calc->conv()->asString(args[0]).asString().toUpper()); 0760 } 0761 0762 // Function: VALUE 0763 Value func_value(valVector args, ValueCalc *calc, FuncExtra *) 0764 { 0765 // same as the N function 0766 return calc->conv()->asFloat(args[0]); 0767 } 0768 0769 #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214" 0770 #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207" 0771 #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207" 0772 #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241" 0773 #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210" 0774 #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262" 0775 #define UTF8_TH_6 "\340\270\253\340\270\201" 0776 #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224" 0777 #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224" 0778 #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262" 0779 #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232" 0780 #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224" 0781 #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210" 0782 #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242" 0783 #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231" 0784 #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231" 0785 #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231" 0786 #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231" 0787 #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231" 0788 #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227" 0789 #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214" 0790 #define UTF8_TH_MINUS "\340\270\245\340\270\232" 0791 0792 inline void lclSplitBlock(double& rfInt, qint32& rnBlock, double fValue, double fSize) 0793 { 0794 rnBlock = static_cast< qint32 >(modf((fValue + 0.1) / fSize, &rfInt) * fSize + 0.1); 0795 } 0796 0797 /** Appends a digit (0 to 9) to the passed string. */ 0798 void lclAppendDigit(QString& rText, qint32 nDigit) 0799 { 0800 switch (nDigit) { 0801 case 0: rText += QString::fromUtf8(UTF8_TH_0); break; 0802 case 1: rText += QString::fromUtf8(UTF8_TH_1); break; 0803 case 2: rText += QString::fromUtf8(UTF8_TH_2); break; 0804 case 3: rText += QString::fromUtf8(UTF8_TH_3); break; 0805 case 4: rText += QString::fromUtf8(UTF8_TH_4); break; 0806 case 5: rText += QString::fromUtf8(UTF8_TH_5); break; 0807 case 6: rText += QString::fromUtf8(UTF8_TH_6); break; 0808 case 7: rText += QString::fromUtf8(UTF8_TH_7); break; 0809 case 8: rText += QString::fromUtf8(UTF8_TH_8); break; 0810 case 9: rText += QString::fromUtf8(UTF8_TH_9); break; 0811 default: debugSheets << "lclAppendDigit - illegal digit"; break; 0812 } 0813 } 0814 0815 /** Appends a value raised to a power of 10: nDigit*10^nPow10. 0816 @param rText The result text. 0817 @param nDigit A digit in the range from 1 to 9. 0818 @param nPow10 A value in the range from 2 to 5. 0819 */ 0820 void lclAppendPow10(QString& rText, qint32 nDigit, qint32 nPow10) 0821 { 0822 Q_ASSERT((1 <= nDigit) && (nDigit <= 9)); // illegal digit? 0823 lclAppendDigit(rText, nDigit); 0824 switch (nPow10) { 0825 case 2: rText += QString::fromUtf8(UTF8_TH_1E2); break; 0826 case 3: rText += QString::fromUtf8(UTF8_TH_1E3); break; 0827 case 4: rText += QString::fromUtf8(UTF8_TH_1E4); break; 0828 case 5: rText += QString::fromUtf8(UTF8_TH_1E5); break; 0829 default: debugSheets << "lclAppendPow10 - illegal power"; break; 0830 } 0831 } 0832 0833 /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */ 0834 void lclAppendBlock(QString& rText, qint32 nValue) 0835 { 0836 Q_ASSERT((1 <= nValue) && (nValue <= 999999)); // illegal value? 0837 if (nValue >= 100000) { 0838 lclAppendPow10(rText, nValue / 100000, 5); 0839 nValue %= 100000; 0840 } 0841 if (nValue >= 10000) { 0842 lclAppendPow10(rText, nValue / 10000, 4); 0843 nValue %= 10000; 0844 } 0845 if (nValue >= 1000) { 0846 lclAppendPow10(rText, nValue / 1000, 3); 0847 nValue %= 1000; 0848 } 0849 if (nValue >= 100) { 0850 lclAppendPow10(rText, nValue / 100, 2); 0851 nValue %= 100; 0852 } 0853 if (nValue > 0) { 0854 qint32 nTen = nValue / 10; 0855 qint32 nOne = nValue % 10; 0856 if (nTen >= 1) { 0857 if (nTen >= 3) 0858 lclAppendDigit(rText, nTen); 0859 else if (nTen == 2) 0860 rText += QString::fromUtf8(UTF8_TH_20); 0861 rText += QString::fromUtf8(UTF8_TH_10); 0862 } 0863 if ((nTen > 0) && (nOne == 1)) 0864 rText += QString::fromUtf8(UTF8_TH_11); 0865 else if (nOne > 0) 0866 lclAppendDigit(rText, nOne); 0867 } 0868 } 0869 0870 // Function: BAHTTEXT 0871 Value func_bahttext(valVector args, ValueCalc *calc, FuncExtra *) 0872 { 0873 double value = numToDouble(calc->conv()->toFloat(args[0])); 0874 0875 // sign 0876 bool bMinus = value < 0.0; 0877 value = fabs(value); 0878 0879 // round to 2 digits after decimal point, value contains Satang as integer 0880 value = floor(value * 100.0 + 0.5); 0881 0882 // split Baht and Satang 0883 double fBaht = 0.0; 0884 qint32 nSatang = 0; 0885 lclSplitBlock(fBaht, nSatang, value, 100.0); 0886 0887 QString aText; 0888 0889 // generate text for Baht value 0890 if (fBaht == 0.0) { 0891 if (nSatang == 0) 0892 aText += QString::fromUtf8(UTF8_TH_0); 0893 } else while (fBaht > 0.0) { 0894 QString aBlock; 0895 qint32 nBlock = 0; 0896 lclSplitBlock(fBaht, nBlock, fBaht, 1.0e6); 0897 if (nBlock > 0) 0898 lclAppendBlock(aBlock, nBlock); 0899 // add leading "million", if there will come more blocks 0900 if (fBaht > 0.0) 0901 aBlock = QString::fromUtf8(UTF8_TH_1E6) + aBlock; 0902 aText.insert(0, aBlock); 0903 } 0904 if (aText.length() > 0) 0905 aText += QString::fromUtf8(UTF8_TH_BAHT); 0906 0907 // generate text for Satang value 0908 if (nSatang == 0) { 0909 aText += QString::fromUtf8(UTF8_TH_DOT0); 0910 } else { 0911 lclAppendBlock(aText, nSatang); 0912 aText += QString::fromUtf8(UTF8_TH_SATANG); 0913 } 0914 0915 // add the minus sign 0916 if (bMinus) 0917 aText = QString::fromUtf8(UTF8_TH_MINUS) + aText; 0918 0919 return Value(aText); 0920 } 0921 0922 #include "text.moc"