F:/KPlato/koffice/libs/kformula/kformulacompatibility.cc

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
00003 
00004    This file is based on the other kformula lib
00005    Copyright (C) 1999 Ilya Baran (ibaran@mit.edu)
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include <q3valuelist.h>
00024 
00025 #include <kdebug.h>
00026 #include "kformuladefs.h"
00027 #include "kformulacompatibility.h"
00028 
00029 KFORMULA_NAMESPACE_BEGIN
00030 
00031 const int SYMBOL_ABOVE = 20000;
00032 const int UNUSED_OFFSET = 1000;
00033 
00034 typedef int BoxType;
00035 
00036 //const BoxType PLUS = '+';
00037 //const BoxType MINUS = '-';
00038 //const BoxType TIMES = '*';
00039 const BoxType OF_DIVIDE = '\\' + UNUSED_OFFSET;
00040 const BoxType OF_POWER  = '^' + UNUSED_OFFSET; //just a test to see if it works
00041 const BoxType OF_SQRT = '@' + UNUSED_OFFSET;
00042 //const BoxType TEXT = 't';
00043 //const BoxType CAT = '#' + UNUSED_OFFSET;
00044 const BoxType OF_SUB = '_' + UNUSED_OFFSET;
00045 const BoxType OF_LSUP = '6' + UNUSED_OFFSET;
00046 const BoxType OF_LSUB = '%' + UNUSED_OFFSET;
00047 //const BoxType PAREN = '(';
00048 //const BoxType EQUAL = '=';
00049 //const BoxType MORE = '>';
00050 //const BoxType LESS = '<';
00051 //const BoxType ABS = '|';
00052 //const BoxType BRACKET = '[';
00053 //const BoxType SLASH = '/';
00054 const BoxType OF_MATRIX = 'm' + UNUSED_OFFSET;
00055 const BoxType OF_SEPARATOR = '&' + UNUSED_OFFSET; // separator for matrices
00056 const BoxType OF_ABOVE = ')' + UNUSED_OFFSET; //something useless
00057 const BoxType OF_BELOW = ']' + UNUSED_OFFSET;
00058 const BoxType OF_SYMBOL = 's' + UNUSED_OFFSET; // whatever
00059 // char for keeping track of cursor position in undo/redo:
00060 //const BoxType CURSOR = 'c' + UNUSED_OFFSET;
00061 
00062 const int INTEGRAL = SYMBOL_ABOVE + 0; // symbols have values above that
00063 const int SUM      = SYMBOL_ABOVE + 1;
00064 const int PRODUCT  = SYMBOL_ABOVE + 2;
00065 const int ARROW    = SYMBOL_ABOVE + 3;
00066 // elements of the symbol font are their own codes + SYMBOL_ABOVE
00067 
00068 
00069 Compatibility::Compatibility()
00070 {
00071 }
00072 
00073 
00074 QDomDocument Compatibility::buildDOM(const QString & text)
00075 {
00076     QDomDocument doc("KFORMULA");
00077     pos = 0;
00078     formulaString = text;
00079     QDomElement formula = readSequence(doc);
00080     formula.setTagName("FORMULA");
00081     doc.appendChild(formula);
00082     return doc;
00083 }
00084 
00085 
00086 void Compatibility::appendNextSequence(const QDomDocument& doc, QDomElement element)
00087 {
00088     if (hasNext() && nextToken() == '{') {
00089         element.appendChild(readSequence(doc));
00090     }
00091     else {
00092         pushback();
00093         element.appendChild(doc.createElement("SEQUENCE"));
00094     }
00095 }
00096 
00097 
00098 QDomElement Compatibility::getLastSequence(const QDomDocument& doc, QDomElement sequence)
00099 {
00100     if (sequence.lastChild().nodeName() == "SEQUENCE") {
00101         QDomNode child = sequence.removeChild(sequence.lastChild());
00102         return child.toElement();
00103     }
00104     else {
00105         QDomElement newSeq = doc.createElement("SEQUENCE");
00106         if (!sequence.lastChild().isNull()) {
00107             QDomNode child = sequence.removeChild(sequence.lastChild());
00108             newSeq.appendChild(child);
00109         }
00110         return newSeq;
00111     }
00112 }
00113 
00114 
00115 QDomElement Compatibility::findIndexNode(const QDomDocument& doc, QDomElement sequence)
00116 {
00117     QDomElement element;
00118     if (sequence.lastChild().nodeName() == "INDEX") {
00119         element = sequence.lastChild().toElement();
00120     }
00121     else {
00122         element = doc.createElement("INDEX");
00123         QDomElement con = doc.createElement("CONTENT");
00124         element.appendChild(con);
00125         con.appendChild(getLastSequence(doc, sequence));
00126         sequence.appendChild(element);
00127     }
00128     return element;
00129 }
00130 
00131 
00132 void Compatibility::appendToSequence(QDomElement sequence, QDomElement element, int leftIndexSeen)
00133 {
00134     if (leftIndexSeen > 0) {
00135         if (sequence.lastChild().nodeName() == "INDEX") {
00136             QDomElement index = sequence.lastChild().toElement();
00137             if ((index.firstChild().nodeName() == "CONTENT") &&
00138                 (index.firstChild().firstChild().nodeName() == "SEQUENCE")) {
00139                 QDomElement seq = index.firstChild().firstChild().toElement();
00140                 if (element.nodeName() == "SEQUENCE") {
00141                     index.firstChild().replaceChild(element, seq);
00142                 }
00143                 else {
00144                     seq.appendChild(element);
00145                 }
00146                 return;
00147             }
00148         }
00149     }
00150     sequence.appendChild(element);
00151 }
00152 
00153 
00154 QDomElement Compatibility::readMatrix(const QDomDocument& doc)
00155 {
00156     QDomElement element = doc.createElement("MATRIX");
00157 
00158     uint cols = nextToken();
00159     nextToken();
00160     uint rows = nextToken();
00161 
00162     element.setAttribute("ROWS", rows);
00163     element.setAttribute("COLUMNS", cols);
00164 
00165     if ((nextToken() == '}') && (nextToken() == OF_MATRIX) && (nextToken() == '{')) {
00166         Q3ValueList<QDomElement> matrix;
00167         for (uint c = 0; c < cols; c++) {
00168             for (uint r = 0; r < rows; r++) {
00169                 if (hasNext() && (nextToken() == '{')) {
00170                     QDomElement tmp = readSequence(doc);
00171                     matrix.append(tmp);
00172                 }
00173                 if (hasNext() && (nextToken() != OF_SEPARATOR)) {
00174                     pushback();
00175                 }
00176             }
00177         }
00178         if (hasNext() && (nextToken() != '}')) {
00179             pushback();
00180         }
00181 
00182         if (matrix.count() == rows*cols) {
00183             for (uint r = 0; r < rows; r++) {
00184                 for (uint c = 0; c < cols; c++) {
00185                     element.appendChild(matrix[c*rows+r]);
00186                 }
00187             }
00188         }
00189     }
00190     else {
00191         pushback();
00192     }
00193 
00194     return element;
00195 }
00196 
00197 
00198 QDomElement Compatibility::readSequence(const QDomDocument& doc)
00199 {
00200     // matrizes start with something that isn't a sequence
00201     if ((tokenLeft() > 6) && (lookAhead(1) == OF_SEPARATOR)) {
00202         return readMatrix(doc);
00203     }
00204 
00205     int leftIndexSeen = 0;
00206     QDomElement sequence = doc.createElement("SEQUENCE");
00207 
00208     while (hasNext()) {
00209         ushort ch = nextToken();
00210 
00211         // Debug
00212         //cout << "read: " << ch << " (" << static_cast<char>(ch) << ')' << endl;
00213 
00214         if (leftIndexSeen > 0) leftIndexSeen--;
00215 
00216         switch (ch) {
00217             case '{':
00218                 appendToSequence(sequence, readSequence(doc), leftIndexSeen);
00219                 break;
00220             case '}':
00221                 return sequence;
00222             case '(':
00223             case '[':
00224             case '|': {
00225                 // There is an empty sequence we have to remove
00226                 if (!sequence.lastChild().isNull()) {
00227                     sequence.removeChild(sequence.lastChild());
00228                 }
00229 
00230                 QDomElement element = doc.createElement("BRACKET");
00231                 appendToSequence(sequence, element, leftIndexSeen);
00232                 element.setAttribute("LEFT", ch);
00233                 element.setAttribute("RIGHT", (ch=='(') ? ')' : ((ch=='[') ? ']' : '|'));
00234 
00235                 QDomElement con = doc.createElement("CONTENT");
00236                 element.appendChild(con);
00237                 appendNextSequence(doc, con);
00238                 break;
00239             }
00240             case OF_DIVIDE: {
00241                 QDomElement element = doc.createElement("FRACTION");
00242 
00243                 QDomElement num = doc.createElement("NUMERATOR");
00244                 element.appendChild(num);
00245                 num.appendChild(getLastSequence(doc, sequence));
00246 
00247                 QDomElement den = doc.createElement("DENOMINATOR");
00248                 element.appendChild(den);
00249                 appendNextSequence(doc, den);
00250 
00251                 appendToSequence(sequence, element, leftIndexSeen);
00252                 break;
00253             }
00254             case OF_SQRT: {
00255                 QDomElement element = doc.createElement("ROOT");
00256                 QDomElement con = doc.createElement("CONTENT");
00257                 element.appendChild(con);
00258                 appendNextSequence(doc, con);
00259 
00260                 QDomElement ind = doc.createElement("INDEX");
00261                 element.appendChild(ind);
00262                 ind.appendChild(getLastSequence(doc, sequence));
00263 
00264                 appendToSequence(sequence, element, leftIndexSeen);
00265                 break;
00266             }
00267             case OF_POWER: {
00268                 QDomElement element = findIndexNode(doc, sequence);
00269                 QDomElement upperRight = doc.createElement("UPPERRIGHT");
00270                 element.appendChild(upperRight);
00271                 appendNextSequence(doc, upperRight);
00272                 break;
00273             }
00274             case OF_SUB: {
00275                 QDomElement element = findIndexNode(doc, sequence);
00276                 QDomElement lowerRight = doc.createElement("LOWERRIGHT");
00277                 element.appendChild(lowerRight);
00278                 appendNextSequence(doc, lowerRight);
00279                 break;
00280             }
00281             case OF_LSUP: {
00282                 QDomElement upperLeft = doc.createElement("UPPERLEFT");
00283                 upperLeft.appendChild(getLastSequence(doc, sequence));
00284                 QDomElement element;
00285                 if (sequence.lastChild().nodeName() == "INDEX") {
00286                     element = sequence.lastChild().toElement();
00287                 }
00288                 else {
00289                     element = doc.createElement("INDEX");
00290                     QDomElement con = doc.createElement("CONTENT");
00291                     element.appendChild(con);
00292                     QDomElement seq = doc.createElement("SEQUENCE");
00293                     con.appendChild(seq);
00294                     appendToSequence(sequence, element, leftIndexSeen);
00295                 }
00296                 element.appendChild(upperLeft);
00297                 leftIndexSeen = 2;
00298                 break;
00299             }
00300             case OF_LSUB: {
00301                 QDomElement lowerLeft = doc.createElement("LOWERLEFT");
00302                 lowerLeft.appendChild(getLastSequence(doc, sequence));
00303                 QDomElement element;
00304                 if (sequence.lastChild().nodeName() == "INDEX") {
00305                     element = sequence.lastChild().toElement();
00306                 }
00307                 else {
00308                     element = doc.createElement("INDEX");
00309                     QDomElement con = doc.createElement("CONTENT");
00310                     element.appendChild(con);
00311                     QDomElement seq = doc.createElement("SEQUENCE");
00312                     con.appendChild(seq);
00313                     appendToSequence(sequence, element, leftIndexSeen);
00314                 }
00315                 element.appendChild(lowerLeft);
00316                 leftIndexSeen = 2;
00317                 break;
00318             }
00319             case OF_ABOVE: {
00320                 if (sequence.lastChild().nodeName() == "SEQUENCE") {
00321                     QDomElement seq = sequence.lastChild().toElement();
00322                     if ((seq.childNodes().count() == 1) &&
00323                         ((seq.lastChild().nodeName() == "SYMBOL") ||
00324                          (seq.lastChild().nodeName() == "INDEX"))) {
00325                         sequence.removeChild(seq);
00326 
00327                         QDomElement element = seq.lastChild().toElement();
00328                         QDomElement upper = (element.nodeName() == "SYMBOL") ?
00329                             doc.createElement("UPPER") :
00330                             doc.createElement("UPPERMIDDLE");
00331                         element.appendChild(upper);
00332                         appendNextSequence(doc, upper);
00333                         appendToSequence(sequence, element, leftIndexSeen);
00334                         break;
00335                     }
00336                 }
00337                 QDomElement element = findIndexNode(doc, sequence);
00338                 QDomElement upper = doc.createElement("UPPERMIDDLE");
00339                 element.appendChild(upper);
00340                 appendNextSequence(doc, upper);
00341                 break;
00342             }
00343             case OF_BELOW: {
00344                 if (sequence.lastChild().nodeName() == "SEQUENCE") {
00345                     QDomElement seq = sequence.lastChild().toElement();
00346                     if ((seq.childNodes().count() == 1) &&
00347                         ((seq.lastChild().nodeName() == "SYMBOL") ||
00348                          (seq.lastChild().nodeName() == "INDEX"))) {
00349                         sequence.removeChild(seq);
00350 
00351                         QDomElement element = seq.lastChild().toElement();
00352                         QDomElement lower = (element.nodeName() == "SYMBOL") ?
00353                             doc.createElement("LOWER") :
00354                             doc.createElement("LOWERMIDDLE");
00355                         element.appendChild(lower);
00356                         appendNextSequence(doc, lower);
00357                         appendToSequence(sequence, element, leftIndexSeen);
00358                         break;
00359                     }
00360                 }
00361                 QDomElement element = findIndexNode(doc, sequence);
00362                 QDomElement lower = doc.createElement("LOWERMIDDLE");
00363                 element.appendChild(lower);
00364                 appendNextSequence(doc, lower);
00365                 break;
00366             }
00367             case OF_SYMBOL:
00368                 kDebug() << "OF_SYMBOL" << endl;
00369                 break;
00370             case INTEGRAL:
00371             case SUM:
00372             case PRODUCT: {
00373                 QDomElement element = doc.createElement("SYMBOL");
00374                 element.setAttribute("TYPE",
00375                                      (ch==INTEGRAL) ? Integral :
00376                                      ((ch==SUM) ? Sum : Product));
00377 
00378                 QDomElement con = doc.createElement("CONTENT");
00379                 element.appendChild(con);
00380                 con.appendChild(readSequence(doc));
00381                 pushback();
00382                 appendToSequence(sequence, element, leftIndexSeen);
00383                 break;
00384             }
00385             case ARROW: {
00386                 QDomElement element = doc.createElement("TEXT");
00387                 element.setAttribute("CHAR", QString(QChar(static_cast<char>(174))));
00388                 element.setAttribute("SYMBOL", "1");
00389                 appendToSequence(sequence, element, leftIndexSeen);
00390                 break;
00391             }
00392             default: {
00393                 QDomElement element = doc.createElement("TEXT");
00394                 element.setAttribute("CHAR", QString(formulaString[pos-1]));
00395                 appendToSequence(sequence, element, leftIndexSeen);
00396             }
00397         }
00398     }
00399     return sequence;
00400 }
00401 
00402 KFORMULA_NAMESPACE_END

Généré le Wed Nov 22 23:41:01 2006 pour KPlato par  doxygen 1.5.1-p1