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