00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00037
00038
00039 const BoxType OF_DIVIDE = '\\' + UNUSED_OFFSET;
00040 const BoxType OF_POWER = '^' + UNUSED_OFFSET;
00041 const BoxType OF_SQRT = '@' + UNUSED_OFFSET;
00042
00043
00044 const BoxType OF_SUB = '_' + UNUSED_OFFSET;
00045 const BoxType OF_LSUP = '6' + UNUSED_OFFSET;
00046 const BoxType OF_LSUB = '%' + UNUSED_OFFSET;
00047
00048
00049
00050
00051
00052
00053
00054 const BoxType OF_MATRIX = 'm' + UNUSED_OFFSET;
00055 const BoxType OF_SEPARATOR = '&' + UNUSED_OFFSET;
00056 const BoxType OF_ABOVE = ')' + UNUSED_OFFSET;
00057 const BoxType OF_BELOW = ']' + UNUSED_OFFSET;
00058 const BoxType OF_SYMBOL = 's' + UNUSED_OFFSET;
00059
00060
00061
00062 const int INTEGRAL = SYMBOL_ABOVE + 0;
00063 const int SUM = SYMBOL_ABOVE + 1;
00064 const int PRODUCT = SYMBOL_ABOVE + 2;
00065 const int ARROW = SYMBOL_ABOVE + 3;
00066
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
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
00212
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
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