lib Library API Documentation

kformulamathmlread.cc

00001 /* This file is part of the KDE project 00002 Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org> 00003 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #include <iostream> 00022 #include <qstring.h> 00023 #include <qfontmetrics.h> 00024 00025 //#include <koUnit.h> 00026 00027 #include "kformulamathmlread.h" 00028 #include "symboltable.h" 00029 00030 KFORMULA_NAMESPACE_BEGIN 00031 using namespace std; 00032 00033 class MathML2KFormulaPrivate 00034 { 00035 friend class MathML2KFormula; 00036 00037 public: 00038 MathML2KFormulaPrivate( MathML2KFormula* mml_filter, 00039 const ContextStyle& contextStyle, 00040 QDomDocument formuladoc ); 00041 ~MathML2KFormulaPrivate(); 00042 00043 void math( QDomElement element ); 00044 00045 // Token Elements 00046 void mi( QDomElement element, QDomNode docnode ); 00047 void mn( QDomElement element, QDomNode docnode ); 00048 void mo( QDomElement element, QDomNode docnode ); 00049 void mtext( QDomElement element, QDomNode docnode ); 00050 void mspace( QDomElement element, QDomNode docnode ); 00051 void ms( QDomElement element, QDomNode docnode ); 00052 // mglyph not supported 00053 00054 // General Layout Schemata 00055 void mrow( QDomElement element, QDomNode docnode ); 00056 void mfrac( QDomElement element, QDomNode docnode ); 00057 void msqrt( QDomElement element, QDomNode docnode ); 00058 void mroot( QDomElement element, QDomNode docnode ); 00059 void mstyle( QDomElement element, QDomNode docnode ); 00060 // merror not supported 00061 // mpadded not supported 00062 // mphantom not supported 00063 void mfenced( QDomElement element, QDomNode docnode ); 00064 // menclose not supported 00065 00066 // Script and Limit Schemata 00067 void msub_msup( QDomElement element, QDomNode docnode ); 00068 void msubsup( QDomElement element, QDomNode docnode ); 00069 void munder( QDomElement element, QDomNode docnode ); 00070 void mover( QDomElement element, QDomNode docnode ); 00071 void munderover( QDomElement element, QDomNode docnode ); 00072 // mmultiscripts not supported 00073 00074 // Tables and Matrices 00075 void mtable( QDomElement element, QDomNode docnode ); 00076 // not much supported 00077 00078 // Enlivening Expressions 00079 // maction not supported 00080 00081 protected: 00082 void createTextElements( QString text, QDomNode docnode ); 00083 double convertToPoint( QString value, bool* ok ); 00084 bool isEmbellishedOperator( QDomNode node, QDomElement* mo ); 00085 bool isSpaceLike( QDomNode node ); 00086 00087 enum MathVariant { 00088 normal, 00089 bold, 00090 italic, 00091 bold_italic, 00092 double_struck, 00093 bold_fraktur, 00094 script, 00095 bold_script, 00096 fraktur, 00097 sans_serif, 00098 bold_sans_serif, 00099 sans_serif_italic, 00100 sans_serif_bold_italic, 00101 monospace 00102 }; 00103 00104 struct MathStyle { 00105 MathStyle() 00106 : scriptsizemultiplier( 0.71 ), 00107 scriptminsize( 8 ), 00108 veryverythinmathspace( 1.0/18.0 ), 00109 verythinmathspace( 2.0/18.0 ), 00110 thinmathspace( 3.0/18.0 ), 00111 mediummathspace( 4.0/18.0 ), 00112 thickmathspace( 5.0/18.0 ), 00113 verythickmathspace( 6.0/18.0 ), 00114 veryverythickmathspace( 7.0/18.0 ), 00115 00116 useVariant( false ) 00117 { 00118 } 00119 00120 void styleChange() 00121 { 00122 kdDebug( DEBUGID ) << "Style Change:" 00123 << "\n scriptlevel = " << scriptlevel 00124 << "\n displaystyle = " << displaystyle 00125 << "\n scriptsizemultiplier = " 00126 << scriptsizemultiplier 00127 << "\n scriptminsize = " << scriptminsize 00128 << endl; 00129 } 00130 00131 void setStyles( QDomElement element ) 00132 { 00133 if ( !useVariant ) 00134 return; 00135 00136 switch ( mathvariant ) 00137 { 00138 case normal: 00139 element.setAttribute( "STYLE", "normal" ); 00140 break; 00141 case bold: 00142 element.setAttribute( "STYLE", "bold" ); 00143 break; 00144 00145 case bold_italic: 00146 element.setAttribute( "STYLE", "bolditalic" ); 00147 break; 00148 case italic: 00149 element.setAttribute( "STYLE", "italic" ); 00150 break; 00151 00152 case double_struck: 00153 element.setAttribute( "FAMILY", "doublestruck" ); 00154 break; 00155 00156 case bold_fraktur: 00157 element.setAttribute( "STYLE", "bold" ); 00158 case fraktur: 00159 element.setAttribute( "FAMILY", "fraktur" ); 00160 break; 00161 00162 case bold_script: 00163 element.setAttribute( "STYLE", "bold" ); 00164 case script: 00165 element.setAttribute( "FAMILY", "script" ); 00166 break; 00167 00168 case bold_sans_serif: 00169 element.setAttribute( "STYLE", "bold" ); 00170 case sans_serif: 00171 element.setAttribute( "FAMILY", "normal" ); 00172 break; 00173 case sans_serif_bold_italic: 00174 element.setAttribute( "STYLE", "bolditalic" ); 00175 element.setAttribute( "FAMILY", "normal" ); 00176 break; 00177 case sans_serif_italic: 00178 element.setAttribute( "STYLE", "italic" ); 00179 element.setAttribute( "FAMILY", "normal" ); 00180 break; 00181 00182 //case monospace: 00183 } 00184 } 00185 00186 void readStyles( QDomElement mmlElement ) 00187 { 00188 if ( mmlElement.hasAttribute( "mathvariant" ) ) 00189 { 00190 useVariant = true; 00191 00192 if ( mmlElement.attribute( "mathvariant" ) == "normal" ) 00193 mathvariant = normal; 00194 else if ( mmlElement.attribute( "mathvariant" ) == "bold" ) 00195 mathvariant = bold; 00196 else if ( mmlElement.attribute( "mathvariant" ) == "italic" ) 00197 mathvariant = italic; 00198 else if ( mmlElement.attribute( "mathvariant" ) == "bold-italic" ) 00199 mathvariant = bold_italic; 00200 else if ( mmlElement.attribute( "mathvariant" ) == "double-struck" ) 00201 mathvariant = double_struck; 00202 else if ( mmlElement.attribute( "mathvariant" ) == "bold-fraktur" ) 00203 mathvariant = bold_fraktur; 00204 else if ( mmlElement.attribute( "mathvariant" ) == "script" ) 00205 mathvariant = script; 00206 else if ( mmlElement.attribute( "mathvariant" ) == "bold-script" ) 00207 mathvariant = bold_script; 00208 else if ( mmlElement.attribute( "mathvariant" ) == "fraktur" ) 00209 mathvariant = fraktur; 00210 else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif" ) 00211 mathvariant = sans_serif; 00212 else if ( mmlElement.attribute( "mathvariant" ) == "bold-sans-serif" ) 00213 mathvariant = bold_sans_serif; 00214 else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif-italic" ) 00215 mathvariant = sans_serif_italic; 00216 else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif-bold-italic" ) 00217 mathvariant = sans_serif_bold_italic; 00218 else if ( mmlElement.attribute( "mathvariant" ) == "monospace" ) 00219 mathvariant = monospace; 00220 } 00221 } 00222 00223 // Styles, set by <mstyle> // default 00224 00225 int scriptlevel; // inherited 00226 bool displaystyle; // inherited 00227 double scriptsizemultiplier; // 0.71 00228 double scriptminsize; // 8pt 00229 // color 00230 // background 00231 double veryverythinmathspace; // 1/18em = 0.0555556em 00232 double verythinmathspace; // 2/18em = 0.111111em 00233 double thinmathspace; // 3/18em = 0.166667em 00234 double mediummathspace; // 4/18em = 0.222222em 00235 double thickmathspace; // 5/18em = 0.277778em 00236 double verythickmathspace; // 6/18em = 0.333333em 00237 double veryverythickmathspace; // 7/18em = 0.388889em 00238 00239 // 'Local' styles 00240 00241 MathVariant mathvariant; 00242 bool useVariant; 00243 //int mathsize; 00244 }; 00245 00246 MathStyle style; 00247 QDomDocument doc; 00248 00249 private: 00250 const ContextStyle& context; 00251 MathML2KFormula* filter; 00252 }; 00253 00254 MathML2KFormulaPrivate::MathML2KFormulaPrivate( MathML2KFormula* mml_filter, const ContextStyle& cs, QDomDocument formuladoc ) 00255 : doc( formuladoc ), context( cs ), filter( mml_filter ) 00256 { 00257 } 00258 00259 MathML2KFormulaPrivate::~MathML2KFormulaPrivate() 00260 { 00261 } 00262 00263 void MathML2KFormulaPrivate::math( QDomElement element ) 00264 { 00265 QDomElement formula = doc.createElement( "FORMULA" ); 00266 QDomNode n = element.firstChild(); 00267 00268 QString display = element.attribute( "display" ); 00269 00270 if ( display == "block" ) { 00271 style.displaystyle = true; 00272 } 00273 else { 00274 // if display == "inline" (default) or illegal (then use default) 00275 style.displaystyle = false; 00276 } 00277 00278 style.scriptlevel = 0; 00279 00280 /*kdDebug( DEBUGID ) << "<math> element:\n displaystyle = " 00281 << style.displaystyle << "\n scriptlevel = " 00282 << style.scriptlevel << endl;*/ 00283 00284 while ( !n.isNull() ) { 00285 filter->processElement( n, doc, formula ); 00286 n = n.nextSibling(); 00287 } 00288 00289 doc.appendChild( formula ); 00290 } 00291 00292 void MathML2KFormulaPrivate::mi( QDomElement element, QDomNode docnode ) 00293 { 00294 MathStyle previousStyle( style ); 00295 //style.mathvariant = italic; 00296 style.readStyles( element ); 00297 00298 QString text = element.text().stripWhiteSpace(); 00299 createTextElements( text, docnode ); 00300 00301 style = previousStyle; 00302 } 00303 00304 void MathML2KFormulaPrivate::mo( QDomElement element, QDomNode docnode ) 00305 { 00306 MathStyle previousStyle( style ); 00307 style.readStyles( element ); 00308 00309 QString text = element.text().stripWhiteSpace(); 00310 createTextElements( text, docnode ); 00311 00312 style = previousStyle; 00313 } 00314 00315 void MathML2KFormulaPrivate::mn( QDomElement element, QDomNode docnode ) 00316 { 00317 MathStyle previousStyle( style ); 00318 style.readStyles( element ); 00319 00320 QString text = element.text().stripWhiteSpace(); 00321 createTextElements( text, docnode ); 00322 00323 style = previousStyle; 00324 } 00325 00326 void MathML2KFormulaPrivate::mtext( QDomElement element, QDomNode docnode ) 00327 { 00328 MathStyle previousStyle( style ); 00329 style.readStyles( element ); 00330 00331 QDomNode n = element.firstChild(); 00332 00333 while ( !n.isNull() ) { 00334 if ( n.isText() ) { 00335 QString text = n.toText().data().stripWhiteSpace(); 00336 createTextElements( text, docnode ); 00337 } 00338 else if ( n.isElement() ) { 00339 filter->processElement( n, doc, docnode ); 00340 } 00341 else { 00342 kdDebug( DEBUGID ) << "<mtext> child: " << n.nodeType() << endl; 00343 } 00344 00345 n = n.nextSibling(); 00346 } 00347 00348 style = previousStyle; 00349 } 00350 00351 void MathML2KFormulaPrivate::ms( QDomElement element, QDomNode docnode ) 00352 { 00353 QString lquote = element.attribute( "lquote", "\"" ); 00354 QString rquote = element.attribute( "rquote", "\"" ); 00355 QString text; 00356 00357 text = lquote; 00358 text += element.text().stripWhiteSpace(); 00359 text += rquote; 00360 00361 createTextElements( text, docnode ); 00362 } 00363 00364 void MathML2KFormulaPrivate::mspace( QDomElement element, QDomNode docnode ) 00365 { 00366 // we support only horizontal space 00367 QString width = element.attribute( "width" ); 00368 00369 QDomElement spaceelement = doc.createElement( "SPACE" ); 00370 00371 // check for namedspace. We don't support much... 00372 if ( width == "veryverythinmathspace" ) { 00373 spaceelement.setAttribute( "WIDTH", "thin" ); 00374 } 00375 else if ( width == "verythinmathspace" ) { 00376 spaceelement.setAttribute( "WIDTH", "thin" ); 00377 } 00378 else if ( width == "thinmathspace" ) { 00379 spaceelement.setAttribute( "WIDTH", "thin" ); 00380 } 00381 else if ( width == "mediummathspace" ) { 00382 spaceelement.setAttribute( "WIDTH", "medium" ); 00383 } 00384 else if ( width == "thickmathspace" ) { 00385 spaceelement.setAttribute( "WIDTH", "thick" ); 00386 } 00387 else if ( width == "verythickmathspace" ) { 00388 spaceelement.setAttribute( "WIDTH", "thick" ); 00389 } 00390 else if ( width == "veryverythickmathspace" ) { 00391 spaceelement.setAttribute( "WIDTH", "quad" ); 00392 } 00393 00394 else { 00395 // units 00396 00397 double w = 0; 00398 bool ok; 00399 00400 if ( width.endsWith( "em" ) ) { 00401 // See MathML specification, Appendix H 00402 w = context.getDefaultFont().pointSize(); 00403 if ( w == -1 ) { 00404 QFontMetrics fm( context.getDefaultFont() ); 00405 w = fm.width( 'm' ); 00406 } 00407 w = w * width.remove( width.length() - 2, 2 ).toDouble( &ok ); 00408 // w in points? 00409 } 00410 else if ( width.endsWith( "px" ) ) { 00411 w = width.remove( width.length() - 2, 2 ).toDouble( &ok ); 00412 // w in pixels 00413 } 00414 else if ( width.endsWith( "in" ) ) { 00415 w = width.remove( width.length() - 2, 2 ).toDouble( &ok ); 00416 w *= 72; // w in points 00417 } 00418 else if ( width.endsWith( "cm" ) ) { 00419 w = width.remove( width.length() - 2, 2 ).toDouble( &ok ); 00420 w *= 1/2.54 * 72; // w in points 00421 } 00422 else if ( width.endsWith( "mm" ) ) { 00423 w = width.remove( width.length() - 2, 2 ).toDouble( &ok ); 00424 w *= 1/25.4 * 72; // w in points 00425 } 00426 else if ( width.endsWith( "pt" ) ) { 00427 w = width.remove( width.length() - 2, 2 ).toDouble( &ok ); 00428 // w in points 00429 } 00430 else if ( width.endsWith( "pc" ) ) { 00431 w = width.remove( width.length() - 2, 2 ).toDouble( &ok ); 00432 w /= 12; // w in points 00433 } 00434 else { 00435 w = width.toDouble( &ok ); 00436 } 00437 00438 if ( !ok ) 00439 return; 00440 00441 if ( w < 20 ) 00442 spaceelement.setAttribute( "WIDTH", "thin" ); 00443 else if ( w < 40 ) 00444 spaceelement.setAttribute( "WIDTH", "medium" ); 00445 else if ( w < 80 ) 00446 spaceelement.setAttribute( "WIDTH", "thick" ); 00447 else 00448 spaceelement.setAttribute( "WIDTH", "quad" ); 00449 } 00450 00451 docnode.appendChild( spaceelement ); 00452 } 00453 00454 void MathML2KFormulaPrivate::mrow( QDomElement element, QDomNode docnode ) 00455 { 00456 QDomNode n = element.firstChild(); 00457 while ( !n.isNull() ) { 00458 if ( n.isElement () ) { 00459 QDomElement e = n.toElement(); 00460 // We do not allow sequence inside sequence 00461 filter->processElement( e, doc, docnode ); 00462 } 00463 else { 00464 kdDebug( DEBUGID ) << "<mrow> child: " << n.nodeType() << endl; 00465 } 00466 n = n.nextSibling(); 00467 } 00468 } 00469 00470 void MathML2KFormulaPrivate::mfrac( QDomElement element, QDomNode docnode ) 00471 { 00472 QDomNode n = element.firstChild(); 00473 QDomElement fraction = doc.createElement( "FRACTION" ); 00474 00475 MathStyle previousStyle( style ); 00476 style.displaystyle ? style.displaystyle = false : style.scriptlevel += 1; 00477 style.styleChange(); 00478 00479 int i = 0; 00480 while ( !n.isNull() && i < 2 ) { 00481 if ( n.isElement() ) { 00482 ++i; 00483 if ( i == 1 ) { //first is numerator 00484 QDomElement numerator = 00485 doc.createElement( "NUMERATOR" ); 00486 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00487 numerator.appendChild( sequence ); 00488 QDomElement e = n.toElement(); 00489 filter->processElement( e, doc, sequence ); 00490 fraction.appendChild( numerator ); 00491 00492 } 00493 else { 00494 QDomElement denominator = 00495 doc.createElement( "DENOMINATOR" ); 00496 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00497 denominator.appendChild( sequence ); 00498 QDomElement e = n.toElement(); 00499 filter->processElement( e, doc, sequence ); 00500 fraction.appendChild( denominator ); 00501 00502 } 00503 } 00504 else { 00505 kdDebug( DEBUGID ) << "<mfrac> child: " << n.nodeType() << endl; 00506 } 00507 n = n.nextSibling(); 00508 } 00509 00510 style = previousStyle; 00511 docnode.appendChild( fraction ); 00512 } 00513 00514 void MathML2KFormulaPrivate::mroot( QDomElement element, QDomNode docnode ) 00515 { 00516 QDomNode n = element.firstChild(); 00517 int i = 0; 00518 QDomElement root = doc.createElement( "ROOT" ); 00519 00520 while ( !n.isNull() && i < 2 ) { 00521 if ( n.isElement() ) { 00522 ++i; 00523 if ( i == 1 ) { //first is content (base) 00524 QDomElement content = doc.createElement( "CONTENT" ); 00525 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00526 content.appendChild( sequence ); 00527 QDomElement e = n.toElement(); 00528 filter->processElement( e, doc, sequence ); 00529 00530 root.appendChild(content); 00531 } 00532 else { // index 00533 MathStyle previousStyle( style ); 00534 style.scriptlevel += 2; 00535 style.displaystyle = false; 00536 style.styleChange(); 00537 00538 QDomElement index = doc.createElement( "INDEX" ); 00539 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00540 index.appendChild( sequence ); 00541 QDomElement e = n.toElement(); 00542 filter->processElement( e, doc, sequence ); 00543 root.appendChild( index ); 00544 00545 style = previousStyle; 00546 } 00547 } 00548 else { 00549 kdDebug( DEBUGID ) << "<mroot> child: " << n.nodeType() << endl; 00550 } 00551 n = n.nextSibling(); 00552 } 00553 docnode.appendChild( root ); 00554 } 00555 00556 void MathML2KFormulaPrivate::msqrt( QDomElement element, QDomNode docnode ) 00557 { 00558 QDomNode n = element.firstChild(); 00559 QDomElement root = doc.createElement( "ROOT" ); 00560 00561 QDomElement content = doc.createElement( "CONTENT" ); 00562 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00563 content.appendChild( sequence ); 00564 root.appendChild( content ); 00565 00566 while ( !n.isNull() ) { 00567 if ( n.isElement() ) { 00568 filter->processElement( n.toElement(), doc, sequence ); 00569 } 00570 else { 00571 kdDebug( DEBUGID ) << "<msqrt> child: " << n.nodeType() << endl; 00572 } 00573 n = n.nextSibling(); 00574 } 00575 00576 docnode.appendChild( root ); 00577 } 00578 00579 void MathML2KFormulaPrivate::mstyle( QDomElement element, QDomNode docnode ) 00580 { 00581 bool ok; 00582 00583 MathStyle previousStyle( style ); 00584 style.readStyles( element ); 00585 00586 if ( element.hasAttribute( "scriptlevel" ) ) { 00587 QString scriptlevel = element.attribute( "scriptlevel" ); 00588 if ( scriptlevel.startsWith( "+" ) || scriptlevel.startsWith( "-" ) ) 00589 style.scriptlevel += scriptlevel.toInt( &ok ); 00590 else 00591 style.scriptlevel = scriptlevel.toInt( &ok ); 00592 if ( !ok ) 00593 style.scriptlevel = previousStyle.scriptlevel; 00594 } 00595 if ( element.hasAttribute( "displaystyle" ) ) { 00596 QString displaystyle = element.attribute( "displaystyle" ); 00597 if ( displaystyle == "true" ) 00598 style.displaystyle = true; 00599 else if ( displaystyle == "false" ) 00600 style.displaystyle = false; 00601 } 00602 if ( element.hasAttribute( "scriptsizemultiplier" ) ) { 00603 style.scriptsizemultiplier = 00604 element.attribute( "scriptsizemultiplier" ).toDouble( &ok ); 00605 if ( !ok ) 00606 style.scriptsizemultiplier = previousStyle.scriptsizemultiplier; 00607 } 00608 if ( element.hasAttribute( "scriptminsize" ) ) { 00609 QString scriptminsize = element.attribute( "scriptminsize" ); 00610 style.scriptminsize = convertToPoint( scriptminsize, &ok ); 00611 if ( !ok ) 00612 style.scriptminsize = previousStyle.scriptminsize; 00613 } 00614 00615 if ( element.hasAttribute( "veryverythinmathspace" ) ) { 00616 QString vvthinmspace = element.attribute( "veryverythinmathspace" ); 00617 style.veryverythinmathspace = convertToPoint( vvthinmspace, &ok ); 00618 if ( !ok ) 00619 style.veryverythinmathspace = previousStyle.veryverythinmathspace; 00620 } 00621 if ( element.hasAttribute( "verythinmathspace" ) ) { 00622 QString vthinmspace = element.attribute( "verythinmathspace" ); 00623 style.verythinmathspace = convertToPoint( vthinmspace, &ok ); 00624 if ( !ok ) 00625 style.verythinmathspace = previousStyle.verythinmathspace; 00626 } 00627 if ( element.hasAttribute( "thinmathspace" ) ) { 00628 QString thinmathspace = element.attribute( "thinmathspace" ); 00629 style.thinmathspace = convertToPoint( thinmathspace, &ok ); 00630 if ( !ok ) 00631 style.thinmathspace = previousStyle.thinmathspace; 00632 } 00633 if ( element.hasAttribute( "mediummathspace" ) ) { 00634 QString mediummathspace = element.attribute( "mediummathspace" ); 00635 style.mediummathspace = convertToPoint( mediummathspace, &ok ); 00636 if ( !ok ) 00637 style.mediummathspace = previousStyle.mediummathspace; 00638 } 00639 if ( element.hasAttribute( "thickmathspace" ) ) { 00640 QString thickmathspace = element.attribute( "thickmathspace" ); 00641 style.thickmathspace = convertToPoint( thickmathspace, &ok ); 00642 if ( !ok ) 00643 style.thickmathspace = previousStyle.thickmathspace; 00644 } 00645 if ( element.hasAttribute( "verythickmathspace" ) ) { 00646 QString vthickmspace = element.attribute( "verythickmathspace" ); 00647 style.verythickmathspace = convertToPoint( vthickmspace, &ok ); 00648 if ( !ok ) 00649 style.verythickmathspace = previousStyle.verythickmathspace; 00650 } 00651 if ( element.hasAttribute( "veryverythickmathspace" ) ) { 00652 QString vvthickmspace = element.attribute( "veryverythickmathspace" ); 00653 style.veryverythickmathspace = convertToPoint( vvthickmspace, &ok ); 00654 if ( !ok ) 00655 style.veryverythickmathspace = 00656 previousStyle.veryverythickmathspace; 00657 } 00658 00659 style.styleChange(); 00660 00661 QDomNode n = element.firstChild(); 00662 while ( !n.isNull() ) { 00663 filter->processElement( n, doc, docnode ); 00664 n = n.nextSibling(); 00665 } 00666 00667 style = previousStyle; 00668 } 00669 00670 void MathML2KFormulaPrivate::mfenced( QDomElement element, QDomNode docnode ) 00671 { 00672 QDomElement bracket = doc.createElement( "BRACKET" ); 00673 QString value = element.attribute( "open", "(" ); 00674 bracket.setAttribute( "LEFT", QString::number( value.at( 0 ).latin1() ) ); 00675 value = element.attribute( "close", ")" ); 00676 bracket.setAttribute( "RIGHT", QString::number( value.at( 0 ).latin1() ) ); 00677 00678 QDomElement content = doc.createElement( "CONTENT" ); 00679 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00680 content.appendChild( sequence ); 00681 00682 QString separators = element.attribute( "separators", "," ); 00683 00684 QDomNode n = element.firstChild(); 00685 uint i = 0; 00686 while ( !n.isNull() ) { 00687 if ( n.isElement() ) { 00688 if ( i != 0 && !separators.isEmpty() ) { 00689 QDomElement textelement = doc.createElement( "TEXT" ); 00690 if ( i > separators.length() ) 00691 i = separators.length(); 00692 textelement.setAttribute( "CHAR", QString( separators.at( i - 1 ) ) ); 00693 //style.setStyles( textelement ); 00694 sequence.appendChild( textelement ); 00695 } 00696 ++i; 00697 QDomElement e = n.toElement(); 00698 filter->processElement( e, doc, sequence ); 00699 } 00700 else { 00701 kdDebug( DEBUGID ) << "<mfenced> child: " << n.nodeType() << endl; 00702 } 00703 n = n.nextSibling(); 00704 } 00705 bracket.appendChild( content ); 00706 docnode.appendChild( bracket ); 00707 } 00708 00709 void MathML2KFormulaPrivate::mtable( QDomElement element, QDomNode docnode ) 00710 { 00711 MathStyle previousStyle( style ); 00712 QString displaystyle = element.attribute( "displaystyle", "false" ); 00713 if ( displaystyle == "true" ) { 00714 style.displaystyle = true; 00715 } 00716 else { 00717 // false is default and also used for illegal values 00718 style.displaystyle = false; 00719 } 00720 style.styleChange(); 00721 00722 QString subtag; 00723 int rows = 0; int cols = 0; 00724 QDomNode n = element.firstChild(); 00725 00726 while ( !n.isNull() ) { 00727 if ( n.isElement() ) { 00728 QDomElement e = n.toElement(); 00729 subtag = e.tagName(); 00730 if (subtag == "mtr") 00731 { 00732 ++rows; 00733 00734 /* Determins the number of columns */ 00735 00736 QDomNode cellnode = e.firstChild(); 00737 int cc = 0; 00738 00739 while ( !cellnode.isNull() ) { 00740 if ( cellnode.isElement() ) 00741 cc++; 00742 cellnode = cellnode.nextSibling(); 00743 } 00744 00745 if ( cc > cols ) 00746 cols = cc; 00747 00748 } 00749 } 00750 else { 00751 kdDebug( DEBUGID ) << "<mtable> child: " << n.nodeType() << endl; 00752 } 00753 n = n.nextSibling(); 00754 } 00755 00756 /* Again createing elements, I need to know the number 00757 of rows and cols to leave empty spaces */ 00758 00759 n = element.firstChild(); 00760 QDomElement matrix = doc.createElement( "MATRIX" ); 00761 matrix.setAttribute( "COLUMNS", cols ); 00762 matrix.setAttribute( "ROWS", rows ); 00763 00764 while ( !n.isNull() ) { 00765 if ( n.isElement() ) { 00766 QDomElement e = n.toElement(); 00767 subtag = e.tagName(); 00768 if ( subtag == "mtr" ) { 00769 QDomNode cellnode = e.firstChild(); 00770 int cc = 0; 00771 while ( !cellnode.isNull() ) { 00772 if ( cellnode.isElement() ) { 00773 ++cc; 00774 QDomElement cell = doc.createElement( "SEQUENCE" ); 00775 QDomElement cellelement = cellnode.toElement(); 00776 filter->processElement( cellelement, doc, cell ); 00777 matrix.appendChild( cell ); 00778 } 00779 cellnode = cellnode.nextSibling(); 00780 } 00781 00782 /* Add empty elements */ 00783 for(; cc < cols; cc++ ) { 00784 QDomElement cell = doc.createElement( "SEQUENCE" ); 00785 matrix.appendChild( cell ); 00786 } 00787 } 00788 } 00789 n = n.nextSibling(); 00790 } 00791 00792 style = previousStyle; 00793 docnode.appendChild(matrix); 00794 } 00795 00796 void MathML2KFormulaPrivate::msub_msup( QDomElement element, QDomNode docnode ) 00797 { 00798 QDomNode n = element.firstChild(); 00799 int i = 0; 00800 QDomElement root = doc.createElement( "INDEX" ); 00801 00802 while ( !n.isNull() && i < 2 ) { 00803 if ( n.isElement() ) { 00804 ++i; 00805 if ( i == 1 ) { // first is content (base) 00806 QDomElement content = doc.createElement( "CONTENT" ); 00807 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00808 content.appendChild( sequence ); 00809 QDomElement e = n.toElement(); 00810 filter->processElement( e, doc, sequence ); 00811 00812 root.appendChild( content ); 00813 } 00814 else { 00815 QDomElement index; 00816 if ( element.tagName() == "msup" ) 00817 index = doc.createElement( "UPPERRIGHT" ); 00818 else 00819 index = doc.createElement( "LOWERRIGHT" ); 00820 00821 MathStyle previousStyle( style ); 00822 style.scriptlevel += 1; 00823 style.displaystyle = false; 00824 style.styleChange(); 00825 00826 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00827 index.appendChild( sequence ); 00828 QDomElement e = n.toElement(); 00829 filter->processElement( e, doc, sequence ); 00830 root.appendChild( index ); 00831 00832 style = previousStyle; 00833 } 00834 } 00835 else { 00836 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: " 00837 << n.nodeType() << endl; 00838 } 00839 n = n.nextSibling(); 00840 } 00841 docnode.appendChild( root ); 00842 } 00843 00844 void MathML2KFormulaPrivate::munder( QDomElement element, QDomNode docnode ) 00845 { 00846 bool accentunder; 00847 00848 QString au = element.attribute( "accentunder" ); 00849 if ( au == "true" ) 00850 accentunder = true; 00851 else if ( au == "false" ) 00852 accentunder = false; 00853 else { 00854 // use default 00855 00856 QDomElement mo; 00857 // is underscript an embellished operator? 00858 if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo ) ) { 00859 if ( mo.attribute( "accent" ) == "true" ) 00860 accentunder = true; 00861 else 00862 accentunder = false; 00863 } 00864 else 00865 accentunder = false; 00866 } 00867 00868 QDomNode n = element.firstChild(); 00869 int i = 0; 00870 QDomElement root = doc.createElement( "INDEX" ); 00871 00872 while ( !n.isNull() && i < 2 ) { 00873 if ( n.isElement() ) { 00874 ++i; 00875 if ( i == 1 ) { // first is content (base) 00876 QDomElement content = doc.createElement( "CONTENT" ); 00877 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00878 content.appendChild( sequence ); 00879 QDomElement e = n.toElement(); 00880 filter->processElement( e, doc, sequence ); 00881 00882 root.appendChild( content ); 00883 } 00884 else { // underscript 00885 MathStyle previousStyle( style ); 00886 style.displaystyle = false; 00887 if ( !accentunder ) { 00888 style.scriptlevel += 1; 00889 style.styleChange(); 00890 } 00891 00892 QDomElement mo; QDomElement index; 00893 if ( isEmbellishedOperator( n.previousSibling(), &mo ) && 00894 !previousStyle.displaystyle && 00895 mo.attribute( "movablelimits" ) == "true" ) 00896 { 00897 index = doc.createElement( "LOWERRIGHT" ); 00898 } 00899 else { 00900 index = doc.createElement( "LOWERMIDDLE" ); 00901 } 00902 00903 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00904 index.appendChild( sequence ); 00905 QDomElement e = n.toElement(); 00906 filter->processElement( e, doc, sequence ); 00907 root.appendChild( index ); 00908 00909 style = previousStyle; 00910 } 00911 } 00912 else { 00913 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: " 00914 << n.nodeType() << endl; 00915 } 00916 n = n.nextSibling(); 00917 } 00918 00919 docnode.appendChild( root ); 00920 } 00921 00922 void MathML2KFormulaPrivate::mover( QDomElement element, QDomNode docnode ) 00923 { 00924 bool accent; 00925 00926 QString ac = element.attribute( "accent" ); 00927 if ( ac == "true" ) 00928 accent = true; 00929 else if ( ac == "false" ) 00930 accent = false; 00931 else { 00932 // use default 00933 00934 QDomElement mo; 00935 // is overscript an embellished operator? 00936 if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo ) ) { 00937 if ( mo.attribute( "accent" ) == "true" ) 00938 accent = true; 00939 else 00940 accent = false; 00941 } 00942 else 00943 accent = false; 00944 } 00945 00946 QDomNode n = element.firstChild(); 00947 int i = 0; 00948 QDomElement root = doc.createElement( "INDEX" ); 00949 00950 while ( !n.isNull() && i < 2 ) { 00951 if ( n.isElement() ) { 00952 ++i; 00953 if ( i == 1 ) { // first is content (base) 00954 QDomElement content = doc.createElement( "CONTENT" ); 00955 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00956 content.appendChild( sequence ); 00957 QDomElement e = n.toElement(); 00958 filter->processElement( e, doc, sequence ); 00959 00960 root.appendChild( content ); 00961 } 00962 else { // overscript 00963 MathStyle previousStyle( style ); 00964 style.displaystyle = false; 00965 if ( !accent ) { 00966 style.scriptlevel += 1; 00967 style.styleChange(); 00968 } 00969 00970 QDomElement mo; QDomElement index; 00971 if ( isEmbellishedOperator( n.previousSibling(), &mo ) && 00972 !previousStyle.displaystyle && 00973 mo.attribute( "movablelimits" ) == "true" ) 00974 { 00975 index = doc.createElement( "UPPERRIGHT" ); 00976 } 00977 else { 00978 index = doc.createElement( "UPPERMIDDLE" ); 00979 } 00980 00981 QDomElement sequence = doc.createElement( "SEQUENCE" ); 00982 index.appendChild( sequence ); 00983 QDomElement e = n.toElement(); 00984 filter->processElement( e, doc, sequence ); 00985 root.appendChild( index ); 00986 00987 style = previousStyle; 00988 } 00989 } 00990 else { 00991 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: " 00992 << n.nodeType() << endl; 00993 } 00994 n = n.nextSibling(); 00995 } 00996 00997 docnode.appendChild( root ); 00998 } 00999 01000 void MathML2KFormulaPrivate::munderover( QDomElement element, 01001 QDomNode docnode ) 01002 { 01003 bool accent; 01004 bool accentunder; 01005 01006 QString value = element.attribute( "accentunder" ); 01007 if ( value == "true" ) 01008 accentunder = true; 01009 else if ( value == "false" ) 01010 accentunder = false; 01011 else { 01012 // use default 01013 01014 QDomElement mo; 01015 // is underscript an embellished operator? 01016 if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo ) ) { 01017 if ( mo.attribute( "accent" ) == "true" ) 01018 accentunder = true; 01019 else 01020 accentunder = false; 01021 } 01022 else 01023 accentunder = false; 01024 } 01025 value = element.attribute( "accent" ); 01026 if ( value == "true" ) 01027 accent = true; 01028 else if ( value == "false" ) 01029 accent = false; 01030 else { 01031 // use default 01032 01033 QDomElement mo; 01034 // is overscript an embellished operator? 01035 if ( isEmbellishedOperator( element.childNodes().item( 2 ), &mo ) ) { 01036 kdDebug( DEBUGID ) << "embellished operator" << endl; 01037 if ( mo.attribute( "accent" ) == "true" ) 01038 accent = true; 01039 else 01040 accent = false; 01041 } 01042 else 01043 accent = false; 01044 } 01045 kdDebug( DEBUGID ) << "munderover:\n accentunder = " << accentunder 01046 << "\n accent = " << accent << endl; 01047 01048 QDomNode n = element.firstChild(); 01049 int i = 0; 01050 QDomElement root = doc.createElement( "INDEX" ); 01051 01052 while ( !n.isNull() && i < 3 ) { 01053 if ( n.isElement() ) { 01054 ++i; 01055 if ( i == 1 ) { // base 01056 QDomElement content = doc.createElement( "CONTENT" ); 01057 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01058 content.appendChild( sequence ); 01059 QDomElement e = n.toElement(); 01060 filter->processElement( e, doc, sequence ); 01061 01062 root.appendChild( content ); 01063 } 01064 else if ( i == 2 ) { // underscript 01065 MathStyle previousStyle( style ); 01066 style.displaystyle = false; 01067 if ( !accentunder ) { 01068 style.scriptlevel += 1; 01069 style.styleChange(); 01070 } 01071 01072 QDomElement mo; QDomElement index; 01073 // is the base an embellished operator? 01074 if ( isEmbellishedOperator( element.firstChild(), &mo ) && 01075 !previousStyle.displaystyle && 01076 mo.attribute( "movablelimits" ) == "true" ) 01077 { 01078 index = doc.createElement( "LOWERRIGHT" ); 01079 } 01080 else { 01081 index = doc.createElement( "LOWERMIDDLE" ); 01082 } 01083 01084 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01085 index.appendChild( sequence ); 01086 QDomElement e = n.toElement(); 01087 filter->processElement( e, doc, sequence ); 01088 root.appendChild( index ); 01089 01090 style = previousStyle; 01091 } 01092 else { // overscript 01093 MathStyle previousStyle( style ); 01094 style.displaystyle = false; 01095 if ( !accent ) { 01096 style.scriptlevel += 1; 01097 style.styleChange(); 01098 } 01099 01100 QDomElement mo; QDomElement index; 01101 if ( isEmbellishedOperator( element.firstChild(), &mo ) && 01102 !previousStyle.displaystyle && 01103 mo.attribute( "movablelimits" ) == "true" ) 01104 { 01105 index = doc.createElement( "UPPERRIGHT" ); 01106 } 01107 else { 01108 index = doc.createElement( "UPPERMIDDLE" ); 01109 } 01110 01111 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01112 index.appendChild( sequence ); 01113 QDomElement e = n.toElement(); 01114 filter->processElement( e, doc, sequence ); 01115 root.appendChild( index ); 01116 01117 style = previousStyle; 01118 } 01119 } 01120 else { 01121 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: " 01122 << n.nodeType() << endl; 01123 } 01124 n = n.nextSibling(); 01125 } 01126 01127 docnode.appendChild( root ); 01128 } 01129 01130 void MathML2KFormulaPrivate::msubsup( QDomElement element, QDomNode docnode ) 01131 { 01132 QDomNode n = element.firstChild(); 01133 int i = 0; 01134 QDomElement root = doc.createElement("INDEX"); 01135 MathStyle previousStyle( style ); 01136 01137 while ( !n.isNull() && i < 2 ) { 01138 if ( n.isElement() ) { 01139 ++i; 01140 if ( i == 1 ) { // base 01141 QDomElement content = doc.createElement( "CONTENT" ); 01142 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01143 content.appendChild( sequence ); 01144 QDomElement e = n.toElement(); 01145 filter->processElement( e, doc, sequence ); 01146 01147 root.appendChild( content ); 01148 } 01149 else if ( i == 2 ) { // subscript 01150 style.scriptlevel += 1; 01151 style.displaystyle = false; 01152 style.styleChange(); 01153 01154 QDomElement index; 01155 index = doc.createElement( "LOWERRIGHT" ); 01156 01157 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01158 index.appendChild( sequence ); 01159 QDomElement e = n.toElement(); 01160 filter->processElement( e, doc, sequence ); 01161 root.appendChild( index ); 01162 } 01163 else { // superscript 01164 QDomElement index; 01165 index = doc.createElement( "UPPERRIGHT" ); 01166 01167 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01168 index.appendChild( sequence ); 01169 QDomElement e = n.toElement(); 01170 filter->processElement( e, doc, sequence ); 01171 root.appendChild( index ); 01172 01173 style = previousStyle; 01174 01175 } 01176 } 01177 else { 01178 kdDebug( DEBUGID ) << "<msubsup> child: " << n.nodeType() << endl; 01179 } 01180 n = n.nextSibling(); 01181 } 01182 docnode.appendChild( root ); 01183 } 01184 01185 void MathML2KFormulaPrivate::createTextElements( QString text, 01186 QDomNode docnode ) 01187 { 01188 for ( uint i = 0; i < text.length(); ++i ) { 01189 QDomElement textelement = doc.createElement( "TEXT" ); 01190 textelement.setAttribute( "CHAR", QString( text.at( i ) ) ); 01191 style.setStyles( textelement ); 01192 if ( context.symbolTable().inTable( text.at( i ) ) ) { 01193 // The element is a symbol. 01194 textelement.setAttribute( "SYMBOL", "3" ); 01195 } 01196 docnode.appendChild( textelement ); 01197 } 01198 } 01199 01200 double MathML2KFormulaPrivate::convertToPoint( QString value, bool* ok ) 01201 { 01202 double pt = 0; 01203 01204 if ( value.endsWith( "em" ) ) { 01205 // See MathML specification, Appendix H 01206 pt = context.getDefaultFont().pointSize(); 01207 if ( pt == -1 ) { 01208 QFontMetrics fm( context.getDefaultFont() ); 01209 pt = fm.width( 'M' ); 01210 // PIXELS! 01211 } 01212 pt = pt * value.remove( value.length() - 2, 2 ).toDouble( ok ); 01213 } 01214 else if ( value.endsWith( "ex" ) ) { 01215 QFontMetrics fm( context.getDefaultFont() ); 01216 pt = fm.height(); 01217 // PIXELS, and totally wrong! 01218 } 01219 else if ( value.endsWith( "px" ) ) { 01220 pt = value.remove( value.length() - 2, 2 ).toDouble( ok ); 01221 // PIXELS! 01222 } 01223 else if ( value.endsWith( "in" ) ) { 01224 pt = value.remove( value.length() - 2, 2 ).toDouble( ok ); 01225 pt *= 72; 01226 } 01227 else if ( value.endsWith( "cm" ) ) { 01228 pt = value.remove( value.length() - 2, 2 ).toDouble( ok ); 01229 pt *= 1/2.54 * 72; 01230 } 01231 else if ( value.endsWith( "mm" ) ) { 01232 pt = value.remove( value.length() - 2, 2 ).toDouble( ok ); 01233 pt *= 1/25.4 * 72; 01234 } 01235 else if ( value.endsWith( "pt" ) ) { 01236 pt = value.remove( value.length() - 2, 2 ).toDouble( ok ); 01237 } 01238 else if ( value.endsWith( "pc" ) ) { 01239 pt = value.remove( value.length() - 2, 2 ).toDouble( ok ); 01240 pt /= 12; 01241 } 01242 else { 01243 pt = value.toDouble( ok ); 01244 } 01245 01246 return pt; 01247 } 01248 01249 bool MathML2KFormulaPrivate::isEmbellishedOperator( QDomNode node, 01250 QDomElement* mo ) 01251 { 01252 // See MathML 2.0 specification: 3.2.5.7 01253 01254 if ( !node.isElement() ) 01255 return false; 01256 01257 QDomElement element = node.toElement(); 01258 QString tag = element.tagName(); 01259 01260 if ( tag == "mo" ) 01261 { 01262 *mo = element; 01263 return true; 01264 } 01265 if ( tag == "msub" || tag == "msup" || tag == "msubsup" || 01266 tag == "munder" || tag == "mover" || tag == "munderover" || 01267 tag == "mmultiscripts" || tag == "mfrac" || tag == "semantics" ) 01268 { 01269 return isEmbellishedOperator( element.firstChild(), mo ); 01270 } 01271 if ( tag == "maction" ) 01272 { 01273 return false; // not supported 01274 } 01275 if ( tag == "mrow" || tag == "mstyle" || tag == "mphantom" || 01276 tag == "mpadded" ) { 01277 QDomNode n = element.firstChild(); 01278 int i = 0; 01279 01280 while ( !n.isNull() ) { 01281 if ( isEmbellishedOperator( n, mo ) ) { 01282 if ( ++i > 1 ) // one (only one) embellished operator 01283 return false; 01284 } 01285 else if ( !isSpaceLike( n ) ) { // zero or more space-like elements 01286 return false; 01287 } 01288 n = n.nextSibling(); 01289 } 01290 return ( i == 1 ); 01291 } 01292 return false; 01293 } 01294 01295 bool MathML2KFormulaPrivate::isSpaceLike( QDomNode node ) 01296 { 01297 // See MathML 2.0 specification: 3.2.7.3 01298 01299 if ( !node.isElement() ) 01300 return false; 01301 01302 QDomElement element = node.toElement(); 01303 QString tag = element.tagName(); 01304 01305 if ( tag == "mtext" || tag == "mspace" || 01306 tag == "maligngroup" || tag == "malignmark" ) { 01307 return true; 01308 } 01309 if ( tag == "mstyle" || tag == "mphantom" || tag == "mpadded" || 01310 tag == "mrow" ) { 01311 QDomNode n = element.firstChild(); 01312 while ( !n.isNull() ) { 01313 if ( isSpaceLike( n ) ) 01314 n = n.nextSibling(); 01315 else 01316 return false; 01317 } 01318 return true; 01319 } 01320 if ( tag == "maction" ) { 01321 return false; // not supported 01322 } 01323 01324 return false; 01325 } 01326 01327 01328 MathML2KFormula::MathML2KFormula( QDomDocument mmldoc, const ContextStyle &contextStyle ) 01329 : context( contextStyle ) 01330 { 01331 done = false; 01332 origdoc = mmldoc; 01333 } 01334 01335 QDomDocument MathML2KFormula::getKFormulaDom() 01336 { 01337 return formuladoc; 01338 } 01339 01340 01341 01342 void MathML2KFormula::startConversion() 01343 { 01344 //TODO:let it be async 01345 done = false; 01346 formuladoc = QDomDocument( "KFORMULA" ); 01347 impl = new MathML2KFormulaPrivate( this, context, formuladoc ); 01348 QDomElement element = origdoc.documentElement(); 01349 if ( element.tagName() == "math" ) { 01350 impl->math( element ); 01351 } 01352 else { 01353 kdDebug() << "Fatal error: Not a MathML document!" << endl; 01354 } 01355 //cerr << formuladoc.toCString() << endl; 01356 done = true; 01357 } 01358 01359 bool MathML2KFormula::processElement( QDomNode node, QDomDocument doc, 01360 QDomNode docnode ) 01361 { 01362 01363 //QDomElement *element; 01364 Type type = UNKNOWN; 01365 01366 if ( node.isElement() ) { 01367 QDomElement element = node.toElement(); 01368 QString tag = element.tagName(); 01369 01370 if ( tag == "mi" ) { 01371 type = TOKEN; 01372 impl->mi( element, docnode ); 01373 } 01374 else if ( tag == "mo" ) { 01375 type = TOKEN; 01376 impl->mo( element, docnode ); 01377 } 01378 else if ( tag == "mn" ) { 01379 type = TOKEN; 01380 impl->mn( element, docnode ); 01381 } 01382 else if ( tag == "mtext" ) { 01383 type = TOKEN; 01384 impl->mtext( element, docnode ); 01385 } 01386 else if ( tag == "ms" ) { 01387 type = TOKEN; 01388 impl->ms( element, docnode ); 01389 } 01390 else if ( tag == "mspace" ) { 01391 type = TOKEN; 01392 impl->mspace( element, docnode ); 01393 } 01394 else if ( tag == "mrow" ) { 01395 type = LAYOUT; 01396 impl->mrow( element, docnode ); 01397 } 01398 else if ( tag == "mfrac" ) { 01399 type = LAYOUT; 01400 impl->mfrac( element, docnode ); 01401 } 01402 else if ( tag == "mroot" ) { 01403 type = LAYOUT; 01404 impl->mroot( element, docnode ); 01405 } 01406 else if ( tag == "msqrt" ) { 01407 type = LAYOUT; 01408 impl->msqrt( element, docnode ); 01409 } 01410 else if ( tag == "mstyle" ) { 01411 type = LAYOUT; 01412 impl->mstyle( element, docnode ); 01413 } 01414 01415 else if ( tag == "mfenced" ) { 01416 type = LAYOUT; 01417 impl->mfenced( element, docnode ); 01418 } 01419 01420 else if ( tag == "mtable" ) { 01421 type = TABLE; 01422 impl->mtable( element, docnode ); 01423 } 01424 01425 else if ( tag == "msub" || tag == "msup" ) { 01426 type = SCRIPT; 01427 impl->msub_msup( element, docnode ); 01428 } 01429 01430 else if ( tag == "munder" ) { 01431 type = SCRIPT; 01432 impl->munder( element, docnode ); 01433 } 01434 else if ( tag == "mover" ) { 01435 type = SCRIPT; 01436 impl->mover( element, docnode ); 01437 } 01438 else if ( tag == "munderover" ) { 01439 type = SCRIPT; 01440 impl->munderover( element, docnode ); 01441 } 01442 else if ( tag == "msubsup" ) { 01443 type = SCRIPT; 01444 impl->msubsup( element, docnode ); 01445 } 01446 01447 // content markup (not yet usable) 01448 else if ( tag == "apply" ) { 01449 type = CONTENT; 01450 QDomNode n = element.firstChild(); 01451 QDomElement op = n.toElement(); 01452 01453 // n-ary 01454 if ( op.tagName() == "plus" || op.tagName() == "times" || 01455 op.tagName() == "and" || op.tagName() == "or" || 01456 op.tagName() == "xor" ) { 01457 01458 n = n.nextSibling(); 01459 bool first = true; 01460 01461 while ( !n.isNull() ) { 01462 if ( n.isElement() ) { 01463 if ( !first ) { 01464 QDomElement text = doc.createElement( "TEXT" ); 01465 QString value; 01466 01467 if ( op.tagName() == "plus" ) 01468 value = "+"; 01469 else if ( op.tagName() == "times" ) 01470 value = "*"; 01471 else if ( op.tagName() == "and" ) 01472 value = "&"; 01473 else if ( op.tagName() == "or" ) 01474 value = "|"; 01475 else if ( op.tagName() == "xor" ) 01476 value = "#"; // ??? 01477 01478 text.setAttribute( "CHAR", value ); 01479 docnode.appendChild( text ); 01480 } 01481 first = false; 01482 QDomElement e = n.toElement(); 01483 processElement( e, doc, docnode ); 01484 } 01485 n = n.nextSibling(); 01486 } 01487 } 01488 01489 else if ( op.tagName() == "factorial" ) { 01490 QDomElement e = n.nextSibling().toElement(); 01491 processElement( e, doc, docnode ); 01492 impl->createTextElements( "!", docnode ); 01493 } 01494 else if ( op.tagName() == "minus" ) { 01495 uint count = op.childNodes().count(); 01496 n = n.nextSibling(); 01497 if ( count == 2 ) { // unary 01498 impl->createTextElements( "-", docnode ); 01499 QDomElement e = n.toElement(); 01500 processElement( e, doc, docnode ); 01501 } 01502 else if ( count == 3 ) { // binary 01503 n = n.nextSibling(); 01504 QDomElement e = n.toElement(); 01505 processElement( e, doc, docnode ); 01506 impl->createTextElements( "-", docnode ); 01507 n = n.nextSibling(); 01508 e = n.toElement(); 01509 processElement( e, doc, docnode ); 01510 } 01511 } 01512 01513 // many, many more... 01514 01515 } 01516 01517 else if ( tag == "cn" ) { 01518 type = CONTENT; 01519 QString type = element.attribute( "type", "real" ); 01520 01521 if ( type == "real" || type == "constant" ) { 01522 impl->createTextElements( element.text().stripWhiteSpace(), 01523 docnode ); 01524 } 01525 else if ( type == "integer" ) { 01526 QString base = element.attribute( "base" ); 01527 if ( !base ) { 01528 impl->createTextElements( element.text().stripWhiteSpace(), 01529 docnode ); 01530 } 01531 else { 01532 QDomElement index = doc.createElement( "INDEX" ); 01533 QDomElement content = doc.createElement( "CONTENT" ); 01534 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01535 impl->createTextElements( element.text().stripWhiteSpace(), 01536 sequence ); 01537 content.appendChild( sequence ); 01538 index.appendChild( content ); 01539 01540 QDomElement lowerright = doc.createElement( "LOWERRIGHT" ); 01541 sequence = doc.createElement( "SEQUENCE" ); 01542 01543 impl->createTextElements( base, sequence ); 01544 01545 lowerright.appendChild( sequence ); 01546 index.appendChild( lowerright ); 01547 01548 docnode.appendChild( index ); 01549 } 01550 } 01551 else if ( type == "rational" ) { 01552 QDomNode n = element.firstChild(); 01553 impl->createTextElements( n.toText().data().stripWhiteSpace(), 01554 docnode ); 01555 01556 n = n.nextSibling(); // <sep/> 01557 impl->createTextElements( "/", docnode ); 01558 01559 n = n.nextSibling(); 01560 impl->createTextElements( n.toText().data().stripWhiteSpace(), 01561 docnode ); 01562 } 01563 else if ( type == "complex-cartesian" ) { 01564 QDomNode n = element.firstChild(); 01565 impl->createTextElements( n.toText().data().stripWhiteSpace(), 01566 docnode ); 01567 01568 n = n.nextSibling(); // <sep/> 01569 impl->createTextElements( "+", docnode ); 01570 01571 n = n.nextSibling(); 01572 impl->createTextElements( n.toText().data().stripWhiteSpace(), 01573 docnode ); 01574 01575 impl->createTextElements( "i", docnode ); 01576 } 01577 01578 else if ( type == "complex-polar" ) { 01579 QDomNode n = element.firstChild(); 01580 impl->createTextElements( n.toText().data().stripWhiteSpace(), 01581 docnode ); 01582 01583 n = n.nextSibling(); // <sep/> 01584 QDomElement index = doc.createElement( "INDEX" ); 01585 QDomElement content = doc.createElement( "CONTENT" ); 01586 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01587 QDomElement textelement = doc.createElement( "TEXT" ); 01588 textelement.setAttribute( "CHAR", "e" ); 01589 sequence.appendChild( textelement ); 01590 content.appendChild( sequence ); 01591 index.appendChild( content ); 01592 01593 QDomElement upperright = doc.createElement( "UPPERRIGHT" ); 01594 sequence = doc.createElement( "SEQUENCE" ); 01595 textelement = doc.createElement( "TEXT" ); 01596 textelement.setAttribute( "CHAR", "i" ); 01597 sequence.appendChild( textelement ); 01598 01599 n = n.nextSibling(); 01600 impl->createTextElements( n.toText().data().stripWhiteSpace(), 01601 sequence ); 01602 01603 upperright.appendChild( sequence ); 01604 index.appendChild( upperright ); 01605 01606 docnode.appendChild( index ); 01607 } 01608 } 01609 01610 else if ( tag == "ci" ) { 01611 type = CONTENT; 01612 QDomNode n = element.firstChild(); 01613 01614 if ( n.isText() ) { 01615 impl->createTextElements( n.toText().data().stripWhiteSpace(), 01616 docnode ); 01617 } 01618 else if ( n.isElement() ) { 01619 QDomElement e = n.toElement(); 01620 processElement( e, doc, docnode ); 01621 } 01622 else if ( n.isEntityReference() ) { 01623 kdDebug( DEBUGID ) << "isEntityReference: " 01624 << n.toEntityReference().nodeName().latin1() 01625 << endl; 01626 } 01627 else 01628 kdDebug( DEBUGID ) << "ci: " << n.nodeName().latin1() << endl; 01629 } 01630 01631 else if ( tag == "list" ) { 01632 type = CONTENT; 01633 QDomNode n = element.firstChild(); 01634 01635 QDomElement bracket = doc.createElement( "BRACKET" ); 01636 bracket.setAttribute( "LEFT", 91 ); // [ 01637 bracket.setAttribute( "RIGHT", 93 ); // ] 01638 QDomElement content = doc.createElement( "CONTENT" ); 01639 QDomElement sequence = doc.createElement( "SEQUENCE" ); 01640 01641 bool first = true; 01642 01643 while ( !n.isNull() ) { 01644 if ( n.isElement() ) { 01645 if ( !first ) { 01646 QDomElement textelement = doc.createElement( "TEXT" ); 01647 textelement.setAttribute( "CHAR", "," ); 01648 sequence.appendChild( textelement ); 01649 } 01650 first = false; 01651 QDomElement e = n.toElement(); 01652 processElement( e, doc, sequence ); 01653 } 01654 n = n.nextSibling(); 01655 } 01656 01657 content.appendChild( sequence ); 01658 bracket.appendChild( content ); 01659 docnode.appendChild( bracket ); 01660 } 01661 } 01662 01663 if ( type == UNKNOWN && node.nodeType() != QDomNode::AttributeNode ) { 01664 cerr << "Not an element: " << node.nodeType() << endl; 01665 QDomNode n = node.firstChild(); 01666 while ( !n.isNull() ) { 01667 processElement( n, doc, docnode ); 01668 n = n.nextSibling(); 01669 } 01670 } 01671 01672 return true; 01673 } 01674 01675 KFORMULA_NAMESPACE_END 01676 01677 using namespace KFormula; 01678 #include "kformulamathmlread.moc"
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Nov 17 06:54:14 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003