File: Formula.h

package info (click to toggle)
calligra 1%3A2.9.11%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 189,332 kB
  • sloc: cpp: 919,806; xml: 27,759; ansic: 10,472; python: 8,190; perl: 2,724; yacc: 2,557; sh: 1,675; lex: 1,431; java: 1,304; sql: 903; ruby: 734; makefile: 48
file content (463 lines) | stat: -rw-r--r-- 11,858 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
/* This file is part of the KDE project
   Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; only
   version 2 of the License.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#ifndef CALLIGRA_SHEETS_FORMULA
#define CALLIGRA_SHEETS_FORMULA

#include <QHash>
#include <QSharedDataPointer>
#include <QString>
#include <QTextStream>
#include <QVariant>
#include <QVector>
#include <QPoint>

#include "calligra_sheets_export.h"
#include "Cell.h"
#include "Value.h"

#define CALLIGRA_SHEETS_INLINE_ARRAYS

class KLocale;

namespace Calligra
{
namespace Sheets
{
class Sheet;
typedef QHash<Cell, Cell> CellIndirection;

/**
 * \ingroup Value
 * A formula token.
 */
class CALLIGRA_SHEETS_ODF_EXPORT Token
{
public:
    /**
     * token types
     */
    enum Type {
        Unknown = 0, ///< unknown type
        Boolean,     ///< True, False (also i18n-ized)
        Integer,     ///< 14, 3, 1977
        Float,       ///< 3.141592, 1e10, 5.9e-7
        String,      ///< "Calligra", "The quick brown fox..."
        Operator,    ///< +, *, /, -
        Cell,        ///< $A$1, F4, Sheet2!B5, 'Sales Forecast'!Sum
        Range,       ///< C1:C100
        Identifier,  ///< function name or named area
        Error        ///< error, like #REF!, #VALUE!, ...
    };

    /**
     * operator types
     */
    enum Op {
        InvalidOp = 0,  ///< invalid operator
        Plus,           ///<  + (addition)
        Minus,          ///<  - (subtraction, negation)
        Asterisk,       ///<  * (multiplication)
        Slash,          ///<  / (division)
        Caret,          ///<  ^ (power)
        Intersect,      ///< " " (a space means intersection)
        LeftPar,        ///<  (
        RightPar,       ///<  )
        Comma,          ///<  ,
        Semicolon,      ///<  ; (argument separator)
        Ampersand,      ///<  & (string concat)
        Equal,          ///<  =
        NotEqual,       ///<  <>
        Less,           ///<  <
        Greater,        ///<  >
        LessEqual,      ///<  <=
        GreaterEqual,   ///<  >=
        Percent,        ///<  %
        CurlyBra,       ///<  { (array start)
        CurlyKet,       ///<  } (array end)
        Pipe,           ///<  | (array row separator)
        Union           ///<  ~ (union of ranges)
    };

    /**
     * Creates a token.
     */
    explicit Token(Type type = Unknown, const QString& text = QString(), int pos = -1);

    static const Token null;

    Token(const Token&);
    Token& operator=(const Token&);

    /**
     * Returns type of the token.
     */
    Type type() const {
        return m_type;
    }

    /**
     * Returns text associated with the token.
     *
     * If you want to obtain meaningful value of this token, instead of
     * text(), you might use asInteger(), asFloat(), asString(), sheetName(),
     * etc.
     */
    const QString& text() const {
        return m_text;
    }

    int pos() const {
        return m_pos;
    }

    /**
     * Returns true if token is a boolean token.
     */
    bool isBoolean() const {
        return m_type == Boolean;
    }

    /**
     * Returns true if token is a integer token.
     */
    bool isInteger() const {
        return m_type == Integer;
    }

    /**
     * Returns true if token is a floating-point token.
     */
    bool isFloat() const {
        return m_type == Float;
    }

    /**
     * Returns true if token is either integer or floating-point token.
     */
    bool isNumber() const {
        return (m_type == Integer) || (m_type == Float);
    }

    /**
     * Returns true if token is a string token.
     */
    bool isString() const {
        return m_type == String;
    }

    /**
     * Returns true if token is an operator token.
     */
    bool isOperator() const {
        return m_type == Operator;
    }

    /**
     * Returns true if token is a cell reference token.
     */
    bool isCell() const {
        return m_type == Cell;
    }

    /**
     * Returns true if token is a range reference token.
     */
    bool isRange() const {
        return m_type == Range;
    }

    /**
     * Returns true if token is an identifier.
     */
    bool isIdentifier() const {
        return m_type == Identifier;
    }

    /**
     * Returns true if token is a error token.
     */
    bool isError() const {
        return m_type == Error;
    }

    /**
     * Returns boolean value for an boolean token.
     * For any other type of token, return value is undefined.
     */
    bool asBoolean() const;

    /**
     * Returns integer value for an integer token.
     * For any other type of token, returns 0.
     */
    qint64 asInteger() const;

    /**
     * Returns floating-point value for a floating-point token.
     * For any other type of token, returns 0.0.
     */
    double asFloat() const;

    /**
     * Returns string value for a string token.
     * For any other type of token, it returns QString().
     *
     * Note that token text for a string token still has leading and trailing
     * double-quotes, i.e for "Calligra", text() return "Calligra"
     * (with the quotes, 9 characters) while asString() only return Calligra
     * (without quotes, 7 characters).
     */
    QString asString() const;

    /**
     * Returns operator value for an operator token.
     * For any other type of token, returns Token::InvalidOp.
     */
    Op asOperator() const;

    /**
     * Returns string value for a error token.
     * For any other type of token, it returns QString().
     */
    QString asError() const;

    /**
     * Returns sheet name in a cell reference token.
     * For any other type of token, it returns QString().
     *
     * If the cell reference doesn't specify sheet name, an empty string
     * is returned. As example, for "Sheet1!B3" , sheetName() returns
     * "Sheet1" while for "A2" sheetName() returns "".
     *
     * When sheet name contains quotes (as if the name has spaces) like
     * in "'Sales Forecast'!F4", sheetName() returns the name
     * without the quotes, i.e "Sales Forecast" in this case.
     */
    QString sheetName() const;

    /**
     * Returns a short description of the token.
     * Should be used only to assist debugging.
     */
    QString description() const;

protected:

    Type m_type;
    QString m_text;
    int m_pos;

};

/**
 * \ingroup Value
 * An array of formula tokens.
 *
 */
class Tokens: public QVector<Token>
{
public:
    Tokens(): QVector<Token>(), m_valid(true) {}
    bool valid() const {
        return m_valid;
    }
    void setValid(bool v) {
        m_valid = v;
    }
protected:
    bool m_valid;
};


/**
 * \ingroup Value
 * A formula for a cell.
 *
 * A Formula is a equations which perform calculations on values in the cells
 * and sheets. Every formula must start with an equal sign (=).
 *
 *
 */
class CALLIGRA_SHEETS_ODF_EXPORT Formula
{
public:
    /**
     * Creates a formula. It must be owned by a sheet.
     */
    Formula(Sheet *sheet, const Cell& cell);

    /**
     * Creates a formula. It must be owned by a sheet.
     */
    explicit Formula(Sheet *sheet);

    /**
     * Creates a formula that is not owned by any sheet.
     * This might be useful in some cases.
     */
    Formula();

    /**
     * Returns a null formula object, this is quicker than creating a new one.
     */
    static Formula empty();

    /**
     * Copy constructor.
     */
    Formula(const Formula&);

    /**
     * Destroys the formula.
     */
    ~Formula();

    /**
     * Returns the cell which owns this formula.
     */
    Sheet* sheet() const;
    /**
     * Returns the cell which owns this formula.
     */
    const Cell& cell() const;

    /**
     * Sets the expression for this formula.
     */
    void setExpression(const QString& expr);

    /**
     * Gets the expression of this formula.
     */
    QString expression() const;

    /**
     * Clears everything, makes as like a newly constructed formula.
     */
    void clear();

    /**
     * Returns true if the specified expression is valid, i.e. it contains
     * no parsing error.
     * Empty formula (i.e. without expression) is always invalid.
     */
    bool isValid() const;

    /**
     * Returns list of tokens associated with this formula. This has nothing to
     * with the formula evaluation but might be useful, e.g. for syntax
     * highlight or similar features.
     * If the formula contains error, the returned tokens is invalid.
     */
    Tokens tokens() const;

    /**
     * Evaluates the formula and returns the result.
     * The optional cellIndirections parameter can be used to replace all
     * occurrences of a references to certain cells with references to
     * different cells. If this mapping is non-empty this does mean
     * that intermediate results can't be cached.
     */
    Value eval(CellIndirection cellIndirections = CellIndirection()) const;

    /**
     * Given an expression, this function separates it into tokens.
     * If the expression contains error (e.g. unknown operator, string no terminated)
     * this function returns tokens which is not valid.
     */
    Tokens scan(const QString& expr, const KLocale* locale = 0) const;

    /**
     * Assignment operator.
     */
    Formula& operator=(const Formula&);

    bool operator==(const Formula&) const;
    inline bool operator!=(const Formula& o) const {
        return !operator==(o);
    }

    QString dump() const;

protected:

    void compile(const Tokens& tokens) const;

    /**
     * helper function: return true for valid named area
     */
    bool isNamedArea(const QString& expr) const;

    /**
     * helper function for recursive evaluations; makes sure one cell
     * is not evaluated more than once resulting in infinite loops
     */
    Value evalRecursive(CellIndirection cellIndirections, QHash<Cell, Value>& values) const;

private:
    class Private;
    QSharedDataPointer<Private> d;
};

/**
 * Dumps the formula, should be used only to assist debugging.
 */
QTextStream& operator<<(QTextStream& ts, Formula formula);


/**
 * helper function: return operator of given token text
 * e.g. "*" yields Operator::Asterisk, and so on
 */
Token::Op matchOperator(const QString& text);

/**
 * helper function to parse operator
 *
 * If a operator is found the data and out pointer are advanced by the number
 * of chars the operators consits of.
 * @param data pointer into the input string 
 * @param out pointer into the out string, The out string needs to be big enough
 * 
 * @returns true if a operator was found, false otherwise.
 */
bool parseOperator(const QChar *&data, QChar *&out);

/**
 * helper function: return true for valid identifier character
 */
bool isIdentifier(QChar ch);

/***************************************************************************
  QHash/QSet support
****************************************************************************/

inline uint qHash(const Formula& formula)
{
    return qHash(formula.expression());
}

} // namespace Sheets
} // namespace Calligra

Q_DECLARE_METATYPE(Calligra::Sheets::Formula)
Q_DECLARE_TYPEINFO(Calligra::Sheets::Formula, Q_MOVABLE_TYPE);

#endif // CALLIGRA_SHEETS_FORMULA