File indexing completed on 2024-05-12 16:35:28

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 // built-in conversion functions
0022 
0023 #include "ConversionModule.h"
0024 
0025 #include "Function.h"
0026 #include "FunctionModuleRegistry.h"
0027 #include "ValueCalc.h"
0028 #include "ValueConverter.h"
0029 
0030 #include <QByteArray>
0031 
0032 using namespace Calligra::Sheets;
0033 
0034 // prototypes
0035 Value func_arabic(valVector args, ValueCalc *calc, FuncExtra *);
0036 Value func_carx(valVector args, ValueCalc *calc, FuncExtra *);
0037 Value func_cary(valVector args, ValueCalc *calc, FuncExtra *);
0038 Value func_decsex(valVector args, ValueCalc *calc, FuncExtra *);
0039 Value func_polr(valVector args, ValueCalc *calc, FuncExtra *);
0040 Value func_pola(valVector args, ValueCalc *calc, FuncExtra *);
0041 Value func_roman(valVector args, ValueCalc *calc, FuncExtra *);
0042 Value func_sexdec(valVector args, ValueCalc *calc, FuncExtra *);
0043 Value func_AsciiToChar(valVector args, ValueCalc *calc, FuncExtra *);
0044 Value func_CharToAscii(valVector args, ValueCalc *calc, FuncExtra *);
0045 Value func_inttobool(valVector args, ValueCalc *calc, FuncExtra *);
0046 Value func_booltoint(valVector args, ValueCalc *calc, FuncExtra *);
0047 Value func_ToString(valVector args, ValueCalc *calc, FuncExtra *);
0048 
0049 
0050 CALLIGRA_SHEETS_EXPORT_FUNCTION_MODULE("kspreadconversionmodule.json", ConversionModule)
0051 
0052 
0053 ConversionModule::ConversionModule(QObject* parent, const QVariantList&)
0054         : FunctionModule(parent)
0055 {
0056     Function *f;
0057 
0058     f = new Function("ARABIC", func_arabic);
0059     add(f);
0060     f = new Function("CARX", func_carx);
0061     f->setParamCount(2);
0062     add(f);
0063     f = new Function("CARY", func_cary);
0064     f->setParamCount(2);
0065     add(f);
0066     f = new Function("DECSEX", func_decsex);
0067     add(f);
0068     f = new Function("POLR", func_polr);
0069     f->setParamCount(2);
0070     add(f);
0071     f = new Function("POLA", func_pola);
0072     f->setParamCount(2);
0073     add(f);
0074     f = new Function("ROMAN", func_roman);
0075     f->setParamCount(1, 2);
0076     add(f);
0077     f = new Function("SEXDEC", func_sexdec);
0078     f->setParamCount(1, 3);
0079     add(f);
0080     f = new Function("ASCIITOCHAR", func_AsciiToChar);
0081     f->setParamCount(1, -1);
0082     f->setAcceptArray();
0083     add(f);
0084     f = new Function("CHARTOASCII", func_CharToAscii);
0085     add(f);
0086     f = new Function("BOOL2INT", func_booltoint);
0087     add(f);
0088     f = new Function("INT2BOOL", func_inttobool);
0089     add(f);
0090     f = new Function("BOOL2STRING", func_ToString);
0091     add(f);
0092     f = new Function("NUM2STRING", func_ToString);
0093     add(f);
0094     f = new Function("STRING", func_ToString);
0095     add(f);
0096 }
0097 
0098 QString ConversionModule::descriptionFileName() const
0099 {
0100     return QString("conversion.xml");
0101 }
0102 
0103 
0104 // Function: POLR
0105 Value func_polr(valVector args, ValueCalc *calc, FuncExtra *)
0106 {
0107     // sqrt (a^2 + b^2)
0108     Value a = args[0];
0109     Value b = args[1];
0110     Value res = calc->sqrt(calc->add(calc->sqr(a), calc->sqr(b)));
0111     return res;
0112 }
0113 
0114 // Function: POLA
0115 Value func_pola(valVector args, ValueCalc *calc, FuncExtra *)
0116 {
0117     // acos (a / polr(a,b))
0118     Value polr = func_polr(args, calc, 0);
0119     if (calc->isZero(polr))
0120         return Value::errorDIV0();
0121     Value res = calc->acos(calc->div(args[0], polr));
0122     return res;
0123 }
0124 
0125 // Function: CARX
0126 Value func_carx(valVector args, ValueCalc *calc, FuncExtra *)
0127 {
0128     // a * cos(b)
0129     Value res = calc->mul(args[0], calc->cos(args[1]));
0130     return res;
0131 }
0132 
0133 // Function: CARY
0134 Value func_cary(valVector args, ValueCalc *calc, FuncExtra *)
0135 {
0136     // a * sin(b)
0137     Value res = calc->mul(args[0], calc->sin(args[1]));
0138     return res;
0139 }
0140 
0141 // Function: DECSEX
0142 Value func_decsex(valVector args, ValueCalc *calc, FuncExtra *)
0143 {
0144     // original function was very complicated, but I see no reason for that,
0145     // when it can be done as simply as this ...
0146     // maybe it was due to all the infrastructure not being ready back then
0147     return calc->conv()->asTime(calc->div(args[0], 24));
0148 }
0149 
0150 // Function: SEXDEC
0151 Value func_sexdec(valVector args, ValueCalc *calc, FuncExtra *)
0152 {
0153     if (args.count() == 1) {
0154         // convert given value to number
0155         Value time = calc->conv()->asTime(args[0]);
0156         return calc->mul(calc->conv()->asFloat(time), 24);
0157     }
0158 
0159     // convert h/m/s to number of hours
0160     Value h = args[0];
0161     Value m = args[1];
0162 
0163     Value res = calc->add(h, calc->div(m, 60));
0164     if (args.count() == 3) {
0165         Value s = args[2];
0166         res = calc->add(res, calc->div(s, 3600));
0167     }
0168     return res;
0169 }
0170 
0171 // Function: ROMAN
0172 Value func_roman(valVector args, ValueCalc *calc, FuncExtra *)
0173 {
0174     static const QString RNUnits[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
0175     static const QString RNTens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
0176     static const QString RNHundreds[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
0177     static const QString RNThousands[] = {"", "M", "MM", "MMM"};
0178 
0179     // precision loss is not a problem here, as we only use the 0-3999 range
0180     qint64 value = calc->conv()->asInteger(args[0]).asInteger();
0181     if ((value < 0) || (value > 3999)) {
0182         return Value::errorNA();
0183     }
0184 
0185     // There is an optional argument, but the specification only covers the case
0186     // where it is zero for conciseness, and zero is the default. So we just
0187     // ignore it.
0188     QString result = RNThousands[(value / 1000)] +
0189                      RNHundreds[(value / 100) % 10] +
0190                      RNTens[(value / 10) % 10] +
0191                      RNUnits[(value) % 10];
0192     return Value(result);
0193 }
0194 
0195 // convert single roman character to decimal
0196 // return < 0 if invalid
0197 int func_arabic_helper(QChar c)
0198 {
0199     switch (c.toUpper().unicode()) {
0200     case 'M': return 1000;
0201     case 'D': return 500;
0202     case 'C': return 100;
0203     case 'L': return 50;
0204     case 'X': return 10;
0205     case 'V': return 5;
0206     case 'I': return 1;
0207     }
0208     return -1;
0209 }
0210 
0211 // Function: ARABIC
0212 Value func_arabic(valVector args, ValueCalc *calc, FuncExtra *)
0213 {
0214     QString roman = calc->conv()->asString(args[0]).asString();
0215     if (roman.isEmpty()) return Value::errorVALUE();
0216 
0217     int val = 0, lastd = 0, d = 0;
0218 
0219     for (int i = 0; i < roman.length(); i++) {
0220         d = func_arabic_helper(roman[i]);
0221         if (d < 0) return Value::errorVALUE();
0222 
0223         if (lastd < d) val -= lastd;
0224         else val += lastd;
0225         lastd = d;
0226     }
0227     if (lastd < d) val -= lastd;
0228     else val += lastd;
0229 
0230     return Value(val);
0231 }
0232 
0233 // helper for AsciiToChar
0234 void func_a2c_helper(ValueCalc *calc, QString &s, Value val)
0235 {
0236     if (val.isArray()) {
0237         for (uint row = 0; row < val.rows(); ++row)
0238             for (uint col = 0; col < val.columns(); ++col)
0239                 func_a2c_helper(calc, s, val.element(col, row));
0240     } else {
0241         int v = calc->conv()->asInteger(val).asInteger();
0242         if (v == 0) return;
0243         QChar c(v);
0244         s = s + c;
0245     }
0246 }
0247 
0248 // Function: AsciiToChar
0249 Value func_AsciiToChar(valVector args, ValueCalc *calc, FuncExtra *)
0250 {
0251     QString str;
0252     for (int i = 0; i < args.count(); i++)
0253         func_a2c_helper(calc, str, args[i]);
0254     return Value(str);
0255 }
0256 
0257 // Function: CharToAscii
0258 Value func_CharToAscii(valVector args, ValueCalc *calc, FuncExtra *)
0259 {
0260     QString val = calc->conv()->asString(args[0]).asString();
0261     if (val.length() == 1)
0262         return Value(QString(val[0]));
0263     return Value::errorVALUE();
0264 }
0265 
0266 // Function: inttobool
0267 Value func_inttobool(valVector args, ValueCalc *calc, FuncExtra *)
0268 {
0269     return calc->conv()->asBoolean(args[0]);
0270 }
0271 
0272 // Function: booltoint
0273 Value func_booltoint(valVector args, ValueCalc *calc, FuncExtra *)
0274 {
0275     return calc->conv()->asInteger(args[0]);
0276 }
0277 
0278 // Function: BoolToString, NumberToString, String
0279 Value func_ToString(valVector args, ValueCalc *calc, FuncExtra *)
0280 {
0281     return calc->conv()->asString(args[0]);
0282 }
0283 
0284 #include "conversion.moc"