1/* This file is part of the KDE project
2 Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; only
7 version 2 of the License.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#ifndef CALLIGRA_SHEETS_FORMULA
21#define CALLIGRA_SHEETS_FORMULA
22
23#include <QHash>
24#include <QSharedDataPointer>
25#include <QString>
26#include <QTextStream>
27#include <QVariant>
28#include <QVector>
29#include <QPoint>
30
31#include "calligra_sheets_export.h"
32#include "Cell.h"
33#include "Value.h"
34
35#define CALLIGRA_SHEETS_INLINE_ARRAYS
36
37class KLocale;
38
39namespace Calligra
40{
41namespace Sheets
42{
43class Sheet;
44typedef QHash<Cell, Cell> CellIndirection;
45
46/**
47 * \ingroup Value
48 * A formula token.
49 */
50class CALLIGRA_SHEETS_ODF_EXPORT Token
51{
52public:
53 /**
54 * token types
55 */
56 enum Type {
57 Unknown = 0, ///< unknown type
58 Boolean, ///< True, False (also i18n-ized)
59 Integer, ///< 14, 3, 1977
60 Float, ///< 3.141592, 1e10, 5.9e-7
61 String, ///< "Calligra", "The quick brown fox..."
62 Operator, ///< +, *, /, -
63 Cell, ///< $A$1, F4, Sheet2!B5, 'Sales Forecast'!Sum
64 Range, ///< C1:C100
65 Identifier, ///< function name or named area
66 Error ///< error, like #REF!, #VALUE!, ...
67 };
68
69 /**
70 * operator types
71 */
72 enum Op {
73 InvalidOp = 0, ///< invalid operator
74 Plus, ///< + (addition)
75 Minus, ///< - (subtraction, negation)
76 Asterisk, ///< * (multiplication)
77 Slash, ///< / (division)
78 Caret, ///< ^ (power)
79 Intersect, ///< " " (a space means intersection)
80 LeftPar, ///< (
81 RightPar, ///< )
82 Comma, ///< ,
83 Semicolon, ///< ; (argument separator)
84 Ampersand, ///< & (string concat)
85 Equal, ///< =
86 NotEqual, ///< <>
87 Less, ///< <
88 Greater, ///< >
89 LessEqual, ///< <=
90 GreaterEqual, ///< >=
91 Percent, ///< %
92 CurlyBra, ///< { (array start)
93 CurlyKet, ///< } (array end)
94 Pipe, ///< | (array row separator)
95 Union ///< ~ (union of ranges)
96 };
97
98 /**
99 * Creates a token.
100 */
101 explicit Token(Type type = Unknown, const QString& text = QString(), int pos = -1);
102
103 static const Token null;
104
105 Token(const Token&);
106 Token& operator=(const Token&);
107
108 /**
109 * Returns type of the token.
110 */
111 Type type() const {
112 return m_type;
113 }
114
115 /**
116 * Returns text associated with the token.
117 *
118 * If you want to obtain meaningful value of this token, instead of
119 * text(), you might use asInteger(), asFloat(), asString(), sheetName(),
120 * etc.
121 */
122 const QString& text() const {
123 return m_text;
124 }
125
126 int pos() const {
127 return m_pos;
128 }
129
130 /**
131 * Returns true if token is a boolean token.
132 */
133 bool isBoolean() const {
134 return m_type == Boolean;
135 }
136
137 /**
138 * Returns true if token is a integer token.
139 */
140 bool isInteger() const {
141 return m_type == Integer;
142 }
143
144 /**
145 * Returns true if token is a floating-point token.
146 */
147 bool isFloat() const {
148 return m_type == Float;
149 }
150
151 /**
152 * Returns true if token is either integer or floating-point token.
153 */
154 bool isNumber() const {
155 return (m_type == Integer) || (m_type == Float);
156 }
157
158 /**
159 * Returns true if token is a string token.
160 */
161 bool isString() const {
162 return m_type == String;
163 }
164
165 /**
166 * Returns true if token is an operator token.
167 */
168 bool isOperator() const {
169 return m_type == Operator;
170 }
171
172 /**
173 * Returns true if token is a cell reference token.
174 */
175 bool isCell() const {
176 return m_type == Cell;
177 }
178
179 /**
180 * Returns true if token is a range reference token.
181 */
182 bool isRange() const {
183 return m_type == Range;
184 }
185
186 /**
187 * Returns true if token is an identifier.
188 */
189 bool isIdentifier() const {
190 return m_type == Identifier;
191 }
192
193 /**
194 * Returns true if token is a error token.
195 */
196 bool isError() const {
197 return m_type == Error;
198 }
199
200 /**
201 * Returns boolean value for an boolean token.
202 * For any other type of token, return value is undefined.
203 */
204 bool asBoolean() const;
205
206 /**
207 * Returns integer value for an integer token.
208 * For any other type of token, returns 0.
209 */
210 qint64 asInteger() const;
211
212 /**
213 * Returns floating-point value for a floating-point token.
214 * For any other type of token, returns 0.0.
215 */
216 double asFloat() const;
217
218 /**
219 * Returns string value for a string token.
220 * For any other type of token, it returns QString().
221 *
222 * Note that token text for a string token still has leading and trailing
223 * double-quotes, i.e for "Calligra", text() return "Calligra"
224 * (with the quotes, 9 characters) while asString() only return Calligra
225 * (without quotes, 7 characters).
226 */
227 QString asString() const;
228
229 /**
230 * Returns operator value for an operator token.
231 * For any other type of token, returns Token::InvalidOp.
232 */
233 Op asOperator() const;
234
235 /**
236 * Returns string value for a error token.
237 * For any other type of token, it returns QString().
238 */
239 QString asError() const;
240
241 /**
242 * Returns sheet name in a cell reference token.
243 * For any other type of token, it returns QString().
244 *
245 * If the cell reference doesn't specify sheet name, an empty string
246 * is returned. As example, for "Sheet1!B3" , sheetName() returns
247 * "Sheet1" while for "A2" sheetName() returns "".
248 *
249 * When sheet name contains quotes (as if the name has spaces) like
250 * in "'Sales Forecast'!F4", sheetName() returns the name
251 * without the quotes, i.e "Sales Forecast" in this case.
252 */
253 QString sheetName() const;
254
255 /**
256 * Returns a short description of the token.
257 * Should be used only to assist debugging.
258 */
259 QString description() const;
260
261protected:
262
263 Type m_type;
264 QString m_text;
265 int m_pos;
266
267};
268
269/**
270 * \ingroup Value
271 * An array of formula tokens.
272 *
273 */
274class Tokens: public QVector<Token>
275{
276public:
277 Tokens(): QVector<Token>(), m_valid(true) {}
278 bool valid() const {
279 return m_valid;
280 }
281 void setValid(bool v) {
282 m_valid = v;
283 }
284protected:
285 bool m_valid;
286};
287
288
289/**
290 * \ingroup Value
291 * A formula for a cell.
292 *
293 * A Formula is a equations which perform calculations on values in the cells
294 * and sheets. Every formula must start with an equal sign (=).
295 *
296 *
297 */
298class CALLIGRA_SHEETS_ODF_EXPORT Formula
299{
300public:
301 /**
302 * Creates a formula. It must be owned by a sheet.
303 */
304 Formula(Sheet *sheet, const Cell& cell);
305
306 /**
307 * Creates a formula. It must be owned by a sheet.
308 */
309 explicit Formula(Sheet *sheet);
310
311 /**
312 * Creates a formula that is not owned by any sheet.
313 * This might be useful in some cases.
314 */
315 Formula();
316
317 /**
318 * Returns a null formula object, this is quicker than creating a new one.
319 */
320 static Formula empty();
321
322 /**
323 * Copy constructor.
324 */
325 Formula(const Formula&);
326
327 /**
328 * Destroys the formula.
329 */
330 ~Formula();
331
332 /**
333 * Returns the cell which owns this formula.
334 */
335 Sheet* sheet() const;
336 /**
337 * Returns the cell which owns this formula.
338 */
339 const Cell& cell() const;
340
341 /**
342 * Sets the expression for this formula.
343 */
344 void setExpression(const QString& expr);
345
346 /**
347 * Gets the expression of this formula.
348 */
349 QString expression() const;
350
351 /**
352 * Clears everything, makes as like a newly constructed formula.
353 */
354 void clear();
355
356 /**
357 * Returns true if the specified expression is valid, i.e. it contains
358 * no parsing error.
359 * Empty formula (i.e. without expression) is always invalid.
360 */
361 bool isValid() const;
362
363 /**
364 * Returns list of tokens associated with this formula. This has nothing to
365 * with the formula evaluation but might be useful, e.g. for syntax
366 * highlight or similar features.
367 * If the formula contains error, the returned tokens is invalid.
368 */
369 Tokens tokens() const;
370
371 /**
372 * Evaluates the formula and returns the result.
373 * The optional cellIndirections parameter can be used to replace all
374 * occurrences of a references to certain cells with references to
375 * different cells. If this mapping is non-empty this does mean
376 * that intermediate results can't be cached.
377 */
378 Value eval(CellIndirection cellIndirections = CellIndirection()) const;
379
380 /**
381 * Given an expression, this function separates it into tokens.
382 * If the expression contains error (e.g. unknown operator, string no terminated)
383 * this function returns tokens which is not valid.
384 */
385 Tokens scan(const QString& expr, const KLocale* locale = 0) const;
386
387 /**
388 * Assignment operator.
389 */
390 Formula& operator=(const Formula&);
391
392 bool operator==(const Formula&) const;
393 inline bool operator!=(const Formula& o) const {
394 return !operator==(o);
395 }
396
397 QString dump() const;
398
399protected:
400
401 void compile(const Tokens& tokens) const;
402
403 /**
404 * helper function: return true for valid named area
405 */
406 bool isNamedArea(const QString& expr) const;
407
408 /**
409 * helper function for recursive evaluations; makes sure one cell
410 * is not evaluated more than once resulting in infinite loops
411 */
412 Value evalRecursive(CellIndirection cellIndirections, QHash<Cell, Value>& values) const;
413
414private:
415 class Private;
416 QSharedDataPointer<Private> d;
417};
418
419/**
420 * Dumps the formula, should be used only to assist debugging.
421 */
422QTextStream& operator<<(QTextStream& ts, Formula formula);
423
424
425/**
426 * helper function: return operator of given token text
427 * e.g. "*" yields Operator::Asterisk, and so on
428 */
429Token::Op matchOperator(const QString& text);
430
431/**
432 * helper function to parse operator
433 *
434 * If a operator is found the data and out pointer are advanced by the number
435 * of chars the operators consits of.
436 * @param data pointer into the input string
437 * @param out pointer into the out string, The out string needs to be big enough
438 *
439 * @returns true if a operator was found, false otherwise.
440 */
441bool parseOperator(const QChar *&data, QChar *&out);
442
443/**
444 * helper function: return true for valid identifier character
445 */
446bool isIdentifier(QChar ch);
447
448/***************************************************************************
449 QHash/QSet support
450****************************************************************************/
451
452inline uint qHash(const Formula& formula)
453{
454 return qHash(formula.expression());
455}
456
457} // namespace Sheets
458} // namespace Calligra
459
460Q_DECLARE_METATYPE(Calligra::Sheets::Formula)
461Q_DECLARE_TYPEINFO(Calligra::Sheets::Formula, Q_MOVABLE_TYPE);
462
463#endif // CALLIGRA_SHEETS_FORMULA
464