File indexing completed on 2024-04-28 16:21:23
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; only 0007 version 2 of the License. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #ifndef CALLIGRA_SHEETS_FORMULA 0021 #define CALLIGRA_SHEETS_FORMULA 0022 0023 #include <QHash> 0024 #include <QSharedDataPointer> 0025 #include <QString> 0026 #include <QTextStream> 0027 #include <QVariant> 0028 #include <QVector> 0029 #include <QPoint> 0030 0031 #include "sheets_odf_export.h" 0032 #include "Cell.h" 0033 #include "Value.h" 0034 0035 #define CALLIGRA_SHEETS_INLINE_ARRAYS 0036 0037 class KLocale; 0038 0039 namespace Calligra 0040 { 0041 namespace Sheets 0042 { 0043 class Sheet; 0044 typedef QHash<Cell, Cell> CellIndirection; 0045 0046 /** 0047 * \ingroup Value 0048 * A formula token. 0049 */ 0050 class CALLIGRA_SHEETS_ODF_EXPORT Token 0051 { 0052 public: 0053 /** 0054 * token types 0055 */ 0056 enum Type { 0057 Unknown = 0, ///< unknown type 0058 Boolean, ///< True, False (also i18n-ized) 0059 Integer, ///< 14, 3, 1977 0060 Float, ///< 3.141592, 1e10, 5.9e-7 0061 String, ///< "Calligra", "The quick brown fox..." 0062 Operator, ///< +, *, /, - 0063 Cell, ///< $A$1, F4, Sheet2!B5, 'Sales Forecast'!Sum 0064 Range, ///< C1:C100 0065 Identifier, ///< function name or named area 0066 Error ///< error, like \#REF!, \#VALUE!, ... 0067 }; 0068 0069 /** 0070 * operator types 0071 */ 0072 enum Op { 0073 InvalidOp = 0, ///< invalid operator 0074 Plus, ///< + (addition) 0075 Minus, ///< - (subtraction, negation) 0076 Asterisk, ///< * (multiplication) 0077 Slash, ///< / (division) 0078 Caret, ///< ^ (power) 0079 Intersect, ///< " " (a space means intersection) 0080 LeftPar, ///< ( 0081 RightPar, ///< ) 0082 Comma, ///< , 0083 Semicolon, ///< ; (argument separator) 0084 Ampersand, ///< & (string concat) 0085 Equal, ///< = 0086 NotEqual, ///< <> 0087 Less, ///< < 0088 Greater, ///< > 0089 LessEqual, ///< <= 0090 GreaterEqual, ///< >= 0091 Percent, ///< % 0092 CurlyBra, ///< { (array start) 0093 CurlyKet, ///< } (array end) 0094 Pipe, ///< | (array row separator) 0095 Union ///< ~ (union of ranges) 0096 }; 0097 0098 /** 0099 * Creates a token. 0100 */ 0101 explicit Token(Type type = Unknown, const QString& text = QString(), int pos = -1); 0102 0103 static const Token null; 0104 0105 Token(const Token&); 0106 Token& operator=(const Token&); 0107 0108 /** 0109 * Returns type of the token. 0110 */ 0111 Type type() const { 0112 return m_type; 0113 } 0114 0115 /** 0116 * Returns text associated with the token. 0117 * 0118 * If you want to obtain meaningful value of this token, instead of 0119 * text(), you might use asInteger(), asFloat(), asString(), sheetName(), 0120 * etc. 0121 */ 0122 const QString& text() const { 0123 return m_text; 0124 } 0125 0126 int pos() const { 0127 return m_pos; 0128 } 0129 0130 /** 0131 * Returns true if token is a boolean token. 0132 */ 0133 bool isBoolean() const { 0134 return m_type == Boolean; 0135 } 0136 0137 /** 0138 * Returns true if token is a integer token. 0139 */ 0140 bool isInteger() const { 0141 return m_type == Integer; 0142 } 0143 0144 /** 0145 * Returns true if token is a floating-point token. 0146 */ 0147 bool isFloat() const { 0148 return m_type == Float; 0149 } 0150 0151 /** 0152 * Returns true if token is either integer or floating-point token. 0153 */ 0154 bool isNumber() const { 0155 return (m_type == Integer) || (m_type == Float); 0156 } 0157 0158 /** 0159 * Returns true if token is a string token. 0160 */ 0161 bool isString() const { 0162 return m_type == String; 0163 } 0164 0165 /** 0166 * Returns true if token is an operator token. 0167 */ 0168 bool isOperator() const { 0169 return m_type == Operator; 0170 } 0171 0172 /** 0173 * Returns true if token is a cell reference token. 0174 */ 0175 bool isCell() const { 0176 return m_type == Cell; 0177 } 0178 0179 /** 0180 * Returns true if token is a range reference token. 0181 */ 0182 bool isRange() const { 0183 return m_type == Range; 0184 } 0185 0186 /** 0187 * Returns true if token is an identifier. 0188 */ 0189 bool isIdentifier() const { 0190 return m_type == Identifier; 0191 } 0192 0193 /** 0194 * Returns true if token is a error token. 0195 */ 0196 bool isError() const { 0197 return m_type == Error; 0198 } 0199 0200 /** 0201 * Returns boolean value for an boolean token. 0202 * For any other type of token, return value is undefined. 0203 */ 0204 bool asBoolean() const; 0205 0206 /** 0207 * Returns integer value for an integer token. 0208 * For any other type of token, returns 0. 0209 */ 0210 qint64 asInteger() const; 0211 0212 /** 0213 * Returns floating-point value for a floating-point token. 0214 * For any other type of token, returns 0.0. 0215 */ 0216 double asFloat() const; 0217 0218 /** 0219 * Returns string value for a string token. 0220 * For any other type of token, it returns QString(). 0221 * 0222 * Note that token text for a string token still has leading and trailing 0223 * double-quotes, i.e for "Calligra", text() return "Calligra" 0224 * (with the quotes, 9 characters) while asString() only return Calligra 0225 * (without quotes, 7 characters). 0226 */ 0227 QString asString() const; 0228 0229 /** 0230 * Returns operator value for an operator token. 0231 * For any other type of token, returns Token::InvalidOp. 0232 */ 0233 Op asOperator() const; 0234 0235 /** 0236 * Returns string value for a error token. 0237 * For any other type of token, it returns QString(). 0238 */ 0239 QString asError() const; 0240 0241 /** 0242 * Returns sheet name in a cell reference token. 0243 * For any other type of token, it returns QString(). 0244 * 0245 * If the cell reference doesn't specify sheet name, an empty string 0246 * is returned. As example, for "Sheet1!B3" , sheetName() returns 0247 * "Sheet1" while for "A2" sheetName() returns "". 0248 * 0249 * When sheet name contains quotes (as if the name has spaces) like 0250 * in "'Sales Forecast'!F4", sheetName() returns the name 0251 * without the quotes, i.e "Sales Forecast" in this case. 0252 */ 0253 QString sheetName() const; 0254 0255 /** 0256 * Returns a short description of the token. 0257 * Should be used only to assist debugging. 0258 */ 0259 QString description() const; 0260 0261 protected: 0262 0263 Type m_type; 0264 QString m_text; 0265 int m_pos; 0266 0267 }; 0268 0269 /** 0270 * \ingroup Value 0271 * An array of formula tokens. 0272 * 0273 */ 0274 class Tokens: public QVector<Token> 0275 { 0276 public: 0277 Tokens(): QVector<Token>(), m_valid(true) {} 0278 bool valid() const { 0279 return m_valid; 0280 } 0281 void setValid(bool v) { 0282 m_valid = v; 0283 } 0284 protected: 0285 bool m_valid; 0286 }; 0287 0288 0289 /** 0290 * \ingroup Value 0291 * A formula for a cell. 0292 * 0293 * A Formula is a equations which perform calculations on values in the cells 0294 * and sheets. Every formula must start with an equal sign (=). 0295 * 0296 * 0297 */ 0298 class CALLIGRA_SHEETS_ODF_EXPORT Formula 0299 { 0300 public: 0301 /** 0302 * Creates a formula. It must be owned by a sheet. 0303 */ 0304 Formula(Sheet *sheet, const Cell& cell); 0305 0306 /** 0307 * Creates a formula. It must be owned by a sheet. 0308 */ 0309 explicit Formula(Sheet *sheet); 0310 0311 /** 0312 * Creates a formula that is not owned by any sheet. 0313 * This might be useful in some cases. 0314 */ 0315 Formula(); 0316 0317 /** 0318 * Returns a null formula object, this is quicker than creating a new one. 0319 */ 0320 static Formula empty(); 0321 0322 /** 0323 * Copy constructor. 0324 */ 0325 Formula(const Formula&); 0326 0327 /** 0328 * Destroys the formula. 0329 */ 0330 ~Formula(); 0331 0332 /** 0333 * Returns the cell which owns this formula. 0334 */ 0335 Sheet* sheet() const; 0336 /** 0337 * Returns the cell which owns this formula. 0338 */ 0339 const Cell& cell() const; 0340 0341 /** 0342 * Sets the expression for this formula. 0343 */ 0344 void setExpression(const QString& expr); 0345 0346 /** 0347 * Gets the expression of this formula. 0348 */ 0349 QString expression() const; 0350 0351 /** 0352 * Clears everything, makes as like a newly constructed formula. 0353 */ 0354 void clear(); 0355 0356 /** 0357 * Returns true if the specified expression is valid, i.e. it contains 0358 * no parsing error. 0359 * Empty formula (i.e. without expression) is always invalid. 0360 */ 0361 bool isValid() const; 0362 0363 /** 0364 * Returns list of tokens associated with this formula. This has nothing to 0365 * with the formula evaluation but might be useful, e.g. for syntax 0366 * highlight or similar features. 0367 * If the formula contains error, the returned tokens is invalid. 0368 */ 0369 Tokens tokens() const; 0370 0371 /** 0372 * Evaluates the formula and returns the result. 0373 * The optional cellIndirections parameter can be used to replace all 0374 * occurrences of a references to certain cells with references to 0375 * different cells. If this mapping is non-empty this does mean 0376 * that intermediate results can't be cached. 0377 */ 0378 Value eval(CellIndirection cellIndirections = CellIndirection()) const; 0379 0380 /** 0381 * Given an expression, this function separates it into tokens. 0382 * If the expression contains error (e.g. unknown operator, string no terminated) 0383 * this function returns tokens which is not valid. 0384 */ 0385 Tokens scan(const QString& expr, const KLocale* locale = 0) const; 0386 0387 /** 0388 * Assignment operator. 0389 */ 0390 Formula& operator=(const Formula&); 0391 0392 bool operator==(const Formula&) const; 0393 inline bool operator!=(const Formula& o) const { 0394 return !operator==(o); 0395 } 0396 0397 QString dump() const; 0398 0399 protected: 0400 0401 void compile(const Tokens& tokens) const; 0402 0403 /** 0404 * helper function: return true for valid named area 0405 */ 0406 bool isNamedArea(const QString& expr) const; 0407 0408 /** 0409 * helper function for recursive evaluations; makes sure one cell 0410 * is not evaluated more than once resulting in infinite loops 0411 */ 0412 Value evalRecursive(CellIndirection cellIndirections, QHash<Cell, Value>& values) const; 0413 0414 private: 0415 class Private; 0416 QSharedDataPointer<Private> d; 0417 }; 0418 0419 /** 0420 * Dumps the formula, should be used only to assist debugging. 0421 */ 0422 QTextStream& operator<<(QTextStream& ts, Formula formula); 0423 0424 0425 /** 0426 * helper function: return operator of given token text 0427 * e.g. "*" yields Operator::Asterisk, and so on 0428 */ 0429 Token::Op matchOperator(const QString& text); 0430 0431 /** 0432 * helper function to parse operator 0433 * 0434 * If a operator is found the data and out pointer are advanced by the number 0435 * of chars the operators consist of. 0436 * @param data pointer into the input string 0437 * @param out pointer into the out string, The out string needs to be big enough 0438 * 0439 * @returns true if a operator was found, false otherwise. 0440 */ 0441 bool parseOperator(const QChar *&data, QChar *&out); 0442 0443 /** 0444 * helper function: return true for valid identifier character 0445 */ 0446 bool isIdentifier(QChar ch); 0447 0448 /*************************************************************************** 0449 QHash/QSet support 0450 ****************************************************************************/ 0451 0452 inline uint qHash(const Formula& formula) 0453 { 0454 return qHash(formula.expression()); 0455 } 0456 0457 } // namespace Sheets 0458 } // namespace Calligra 0459 0460 Q_DECLARE_METATYPE(Calligra::Sheets::Formula) 0461 Q_DECLARE_TYPEINFO(Calligra::Sheets::Formula, Q_MOVABLE_TYPE); 0462 0463 #endif // CALLIGRA_SHEETS_FORMULA