/* This file is part of the KDE project Copyright (C) 2001 Ulrich Kuettler 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 #include #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 ETQUAL = '='; //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 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(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(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