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 | |
37 | class KLocale; |
38 | |
39 | namespace Calligra |
40 | { |
41 | namespace Sheets |
42 | { |
43 | class Sheet; |
44 | typedef QHash<Cell, Cell> CellIndirection; |
45 | |
46 | /** |
47 | * \ingroup Value |
48 | * A formula token. |
49 | */ |
50 | class CALLIGRA_SHEETS_ODF_EXPORT Token |
51 | { |
52 | public: |
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 | |
261 | protected: |
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 | */ |
274 | class Tokens: public QVector<Token> |
275 | { |
276 | public: |
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 | } |
284 | protected: |
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 | */ |
298 | class CALLIGRA_SHEETS_ODF_EXPORT Formula |
299 | { |
300 | public: |
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 | |
399 | protected: |
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 | |
414 | private: |
415 | class Private; |
416 | QSharedDataPointer<Private> d; |
417 | }; |
418 | |
419 | /** |
420 | * Dumps the formula, should be used only to assist debugging. |
421 | */ |
422 | QTextStream& 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 | */ |
429 | Token::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 | */ |
441 | bool parseOperator(const QChar *&data, QChar *&out); |
442 | |
443 | /** |
444 | * helper function: return true for valid identifier character |
445 | */ |
446 | bool isIdentifier(QChar ch); |
447 | |
448 | /*************************************************************************** |
449 | QHash/QSet support |
450 | ****************************************************************************/ |
451 | |
452 | inline uint qHash(const Formula& formula) |
453 | { |
454 | return qHash(formula.expression()); |
455 | } |
456 | |
457 | } // namespace Sheets |
458 | } // namespace Calligra |
459 | |
460 | Q_DECLARE_METATYPE(Calligra::Sheets::Formula) |
461 | Q_DECLARE_TYPEINFO(Calligra::Sheets::Formula, Q_MOVABLE_TYPE); |
462 | |
463 | #endif // CALLIGRA_SHEETS_FORMULA |
464 | |