summaryrefslogtreecommitdiffstats
path: root/lib/kformula/kformulacompatibility.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kformula/kformulacompatibility.cpp')
-rw-r--r--lib/kformula/kformulacompatibility.cpp402
1 files changed, 402 insertions, 0 deletions
diff --git a/lib/kformula/kformulacompatibility.cpp b/lib/kformula/kformulacompatibility.cpp
new file mode 100644
index 000000000..f64bf9de4
--- /dev/null
+++ b/lib/kformula/kformulacompatibility.cpp
@@ -0,0 +1,402 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+
+ This file is based on the other kformula lib
+ Copyright (C) 1999 Ilya Baran (ibaran@mit.edu)
+
+ 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; either
+ version 2 of the License, or (at your option) any later version.
+
+ 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.
+*/
+
+#include <tqvaluelist.h>
+
+#include <kdebug.h>
+#include "kformuladefs.h"
+#include "kformulacompatibility.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+const int SYMBOL_ABOVE = 20000;
+const int UNUSED_OFFSET = 1000;
+
+typedef int BoxType;
+
+//const BoxType PLUS = '+';
+//const BoxType MINUS = '-';
+//const BoxType TIMES = '*';
+const BoxType OF_DIVIDE = '\\' + UNUSED_OFFSET;
+const BoxType OF_POWER = '^' + UNUSED_OFFSET; //just a test to see if it works
+const BoxType OF_SQRT = '@' + UNUSED_OFFSET;
+//const BoxType TEXT = 't';
+//const BoxType CAT = '#' + UNUSED_OFFSET;
+const BoxType OF_SUB = '_' + UNUSED_OFFSET;
+const BoxType OF_LSUP = '6' + UNUSED_OFFSET;
+const BoxType OF_LSUB = '%' + UNUSED_OFFSET;
+//const BoxType PAREN = '(';
+//const BoxType EQUAL = '=';
+//const BoxType MORE = '>';
+//const BoxType LESS = '<';
+//const BoxType ABS = '|';
+//const BoxType BRACKET = '[';
+//const BoxType SLASH = '/';
+const BoxType OF_MATRIX = 'm' + UNUSED_OFFSET;
+const BoxType OF_SEPARATOR = '&' + UNUSED_OFFSET; // separator for matrices
+const BoxType OF_ABOVE = ')' + UNUSED_OFFSET; //something useless
+const BoxType OF_BELOW = ']' + UNUSED_OFFSET;
+const BoxType OF_SYMBOL = 's' + UNUSED_OFFSET; // whatever
+// char for keeping track of cursor position in undo/redo:
+//const BoxType CURSOR = 'c' + UNUSED_OFFSET;
+
+const int INTEGRAL = SYMBOL_ABOVE + 0; // symbols have values above that
+const int SUM = SYMBOL_ABOVE + 1;
+const int PRODUCT = SYMBOL_ABOVE + 2;
+const int ARROW = SYMBOL_ABOVE + 3;
+// elements of the symbol font are their own codes + SYMBOL_ABOVE
+
+
+Compatibility::Compatibility()
+{
+}
+
+
+TQDomDocument Compatibility::buildDOM(TQString text)
+{
+ TQDomDocument doc("KFORMULA");
+ pos = 0;
+ formulaString = text;
+ TQDomElement formula = readSequence(doc);
+ formula.setTagName("FORMULA");
+ doc.appendChild(formula);
+ return doc;
+}
+
+
+void Compatibility::appendNextSequence(const TQDomDocument& doc, TQDomElement element)
+{
+ if (hasNext() && nextToken() == '{') {
+ element.appendChild(readSequence(doc));
+ }
+ else {
+ pushback();
+ element.appendChild(doc.createElement("SEQUENCE"));
+ }
+}
+
+
+TQDomElement Compatibility::getLastSequence(const TQDomDocument& doc, TQDomElement sequence)
+{
+ if (sequence.lastChild().nodeName() == "SEQUENCE") {
+ TQDomNode child = sequence.removeChild(sequence.lastChild());
+ return child.toElement();
+ }
+ else {
+ TQDomElement newSeq = doc.createElement("SEQUENCE");
+ if (!sequence.lastChild().isNull()) {
+ TQDomNode child = sequence.removeChild(sequence.lastChild());
+ newSeq.appendChild(child);
+ }
+ return newSeq;
+ }
+}
+
+
+TQDomElement Compatibility::findIndexNode(const TQDomDocument& doc, TQDomElement sequence)
+{
+ TQDomElement element;
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ element = sequence.lastChild().toElement();
+ }
+ else {
+ element = doc.createElement("INDEX");
+ TQDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ con.appendChild(getLastSequence(doc, sequence));
+ sequence.appendChild(element);
+ }
+ return element;
+}
+
+
+void Compatibility::appendToSequence(TQDomElement sequence, TQDomElement element, int leftIndexSeen)
+{
+ if (leftIndexSeen > 0) {
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ TQDomElement index = sequence.lastChild().toElement();
+ if ((index.firstChild().nodeName() == "CONTENT") &&
+ (index.firstChild().firstChild().nodeName() == "SEQUENCE")) {
+ TQDomElement seq = index.firstChild().firstChild().toElement();
+ if (element.nodeName() == "SEQUENCE") {
+ index.firstChild().replaceChild(element, seq);
+ }
+ else {
+ seq.appendChild(element);
+ }
+ return;
+ }
+ }
+ }
+ sequence.appendChild(element);
+}
+
+
+TQDomElement Compatibility::readMatrix(const TQDomDocument& doc)
+{
+ TQDomElement element = doc.createElement("MATRIX");
+
+ uint cols = nextToken();
+ nextToken();
+ uint rows = nextToken();
+
+ element.setAttribute("ROWS", rows);
+ element.setAttribute("COLUMNS", cols);
+
+ if ((nextToken() == '}') && (nextToken() == OF_MATRIX) && (nextToken() == '{')) {
+ TQValueList<TQDomElement> matrix;
+ for (uint c = 0; c < cols; c++) {
+ for (uint r = 0; r < rows; r++) {
+ if (hasNext() && (nextToken() == '{')) {
+ TQDomElement tmp = readSequence(doc);
+ matrix.append(tmp);
+ }
+ if (hasNext() && (nextToken() != OF_SEPARATOR)) {
+ pushback();
+ }
+ }
+ }
+ if (hasNext() && (nextToken() != '}')) {
+ pushback();
+ }
+
+ if (matrix.count() == rows*cols) {
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < cols; c++) {
+ element.appendChild(matrix[c*rows+r]);
+ }
+ }
+ }
+ }
+ else {
+ pushback();
+ }
+
+ return element;
+}
+
+
+TQDomElement Compatibility::readSequence(const TQDomDocument& doc)
+{
+ // matrizes start with something that isn't a sequence
+ if ((tokenLeft() > 6) && (lookAhead(1) == OF_SEPARATOR)) {
+ return readMatrix(doc);
+ }
+
+ int leftIndexSeen = 0;
+ TQDomElement sequence = doc.createElement("SEQUENCE");
+
+ while (hasNext()) {
+ ushort ch = nextToken();
+
+ // Debug
+ //cout << "read: " << ch << " (" << static_cast<char>(ch) << ')' << endl;
+
+ if (leftIndexSeen > 0) leftIndexSeen--;
+
+ switch (ch) {
+ case '{':
+ appendToSequence(sequence, readSequence(doc), leftIndexSeen);
+ break;
+ case '}':
+ return sequence;
+ case '(':
+ case '[':
+ case '|': {
+ // There is an empty sequence we have to remove
+ if (!sequence.lastChild().isNull()) {
+ sequence.removeChild(sequence.lastChild());
+ }
+
+ TQDomElement element = doc.createElement("BRACKET");
+ appendToSequence(sequence, element, leftIndexSeen);
+ element.setAttribute("LEFT", ch);
+ element.setAttribute("RIGHT", (ch=='(') ? ')' : ((ch=='[') ? ']' : '|'));
+
+ TQDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ appendNextSequence(doc, con);
+ break;
+ }
+ case OF_DIVIDE: {
+ TQDomElement element = doc.createElement("FRACTION");
+
+ TQDomElement num = doc.createElement("NUMERATOR");
+ element.appendChild(num);
+ num.appendChild(getLastSequence(doc, sequence));
+
+ TQDomElement den = doc.createElement("DENOMINATOR");
+ element.appendChild(den);
+ appendNextSequence(doc, den);
+
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ case OF_SQRT: {
+ TQDomElement element = doc.createElement("ROOT");
+ TQDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ appendNextSequence(doc, con);
+
+ TQDomElement ind = doc.createElement("INDEX");
+ element.appendChild(ind);
+ ind.appendChild(getLastSequence(doc, sequence));
+
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ case OF_POWER: {
+ TQDomElement element = findIndexNode(doc, sequence);
+ TQDomElement upperRight = doc.createElement("UPPERRIGHT");
+ element.appendChild(upperRight);
+ appendNextSequence(doc, upperRight);
+ break;
+ }
+ case OF_SUB: {
+ TQDomElement element = findIndexNode(doc, sequence);
+ TQDomElement lowerRight = doc.createElement("LOWERRIGHT");
+ element.appendChild(lowerRight);
+ appendNextSequence(doc, lowerRight);
+ break;
+ }
+ case OF_LSUP: {
+ TQDomElement upperLeft = doc.createElement("UPPERLEFT");
+ upperLeft.appendChild(getLastSequence(doc, sequence));
+ TQDomElement element;
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ element = sequence.lastChild().toElement();
+ }
+ else {
+ element = doc.createElement("INDEX");
+ TQDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ TQDomElement seq = doc.createElement("SEQUENCE");
+ con.appendChild(seq);
+ appendToSequence(sequence, element, leftIndexSeen);
+ }
+ element.appendChild(upperLeft);
+ leftIndexSeen = 2;
+ break;
+ }
+ case OF_LSUB: {
+ TQDomElement lowerLeft = doc.createElement("LOWERLEFT");
+ lowerLeft.appendChild(getLastSequence(doc, sequence));
+ TQDomElement element;
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ element = sequence.lastChild().toElement();
+ }
+ else {
+ element = doc.createElement("INDEX");
+ TQDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ TQDomElement seq = doc.createElement("SEQUENCE");
+ con.appendChild(seq);
+ appendToSequence(sequence, element, leftIndexSeen);
+ }
+ element.appendChild(lowerLeft);
+ leftIndexSeen = 2;
+ break;
+ }
+ case OF_ABOVE: {
+ if (sequence.lastChild().nodeName() == "SEQUENCE") {
+ TQDomElement seq = sequence.lastChild().toElement();
+ if ((seq.childNodes().count() == 1) &&
+ ((seq.lastChild().nodeName() == "SYMBOL") ||
+ (seq.lastChild().nodeName() == "INDEX"))) {
+ sequence.removeChild(seq);
+
+ TQDomElement element = seq.lastChild().toElement();
+ TQDomElement upper = (element.nodeName() == "SYMBOL") ?
+ doc.createElement("UPPER") :
+ doc.createElement("UPPERMIDDLE");
+ element.appendChild(upper);
+ appendNextSequence(doc, upper);
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ }
+ TQDomElement element = findIndexNode(doc, sequence);
+ TQDomElement upper = doc.createElement("UPPERMIDDLE");
+ element.appendChild(upper);
+ appendNextSequence(doc, upper);
+ break;
+ }
+ case OF_BELOW: {
+ if (sequence.lastChild().nodeName() == "SEQUENCE") {
+ TQDomElement seq = sequence.lastChild().toElement();
+ if ((seq.childNodes().count() == 1) &&
+ ((seq.lastChild().nodeName() == "SYMBOL") ||
+ (seq.lastChild().nodeName() == "INDEX"))) {
+ sequence.removeChild(seq);
+
+ TQDomElement element = seq.lastChild().toElement();
+ TQDomElement lower = (element.nodeName() == "SYMBOL") ?
+ doc.createElement("LOWER") :
+ doc.createElement("LOWERMIDDLE");
+ element.appendChild(lower);
+ appendNextSequence(doc, lower);
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ }
+ TQDomElement element = findIndexNode(doc, sequence);
+ TQDomElement lower = doc.createElement("LOWERMIDDLE");
+ element.appendChild(lower);
+ appendNextSequence(doc, lower);
+ break;
+ }
+ case OF_SYMBOL:
+ kdDebug() << "OF_SYMBOL" << endl;
+ break;
+ case INTEGRAL:
+ case SUM:
+ case PRODUCT: {
+ TQDomElement element = doc.createElement("SYMBOL");
+ element.setAttribute("TYPE",
+ (ch==INTEGRAL) ? Integral :
+ ((ch==SUM) ? Sum : Product));
+
+ TQDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ con.appendChild(readSequence(doc));
+ pushback();
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ case ARROW: {
+ TQDomElement element = doc.createElement("TEXT");
+ element.setAttribute("CHAR", TQString(TQChar(static_cast<char>(174))));
+ element.setAttribute("SYMBOL", "1");
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ default: {
+ TQDomElement element = doc.createElement("TEXT");
+ element.setAttribute("CHAR", TQString(formulaString[pos-1]));
+ appendToSequence(sequence, element, leftIndexSeen);
+ }
+ }
+ }
+ return sequence;
+}
+
+KFORMULA_NAMESPACE_END