lib Library API Documentation

kformulacompatibility.cc

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., 59 Temple Place - Suite 330, 00020 Boston, MA 02111-1307, USA. 00021 */ 00022 00023 #include <qvaluelist.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(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(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(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(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(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 QValueList<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(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 kdDebug() << "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
KDE Logo
This file is part of the documentation for lib Library Version 1.3.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 24 18:22:22 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003