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 Sun Mar 20 14:25:24 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003