You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1795 lines
60 KiB
1795 lines
60 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
|
|
Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <tqstring.h>
|
|
#include <tqfontmetrics.h>
|
|
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
|
|
//#include <KoUnit.h>
|
|
|
|
#include "kformulamathmlread.h"
|
|
#include "symboltable.h"
|
|
|
|
KFORMULA_NAMESPACE_BEGIN
|
|
using namespace std;
|
|
|
|
class MathML2KFormulaPrivate
|
|
{
|
|
friend class MathML2KFormula;
|
|
|
|
public:
|
|
MathML2KFormulaPrivate( MathML2KFormula* mml_filter,
|
|
const ContextStyle& contextStyle,
|
|
const TQDomDocument& formuladoc );
|
|
~MathML2KFormulaPrivate();
|
|
|
|
void math( TQDomElement element );
|
|
|
|
// Token Elements
|
|
void mi( TQDomElement element, TQDomNode docnode );
|
|
void mn( TQDomElement element, TQDomNode docnode );
|
|
void mo( TQDomElement element, TQDomNode docnode );
|
|
void mtext( TQDomElement element, TQDomNode docnode );
|
|
void mspace( TQDomElement element, TQDomNode docnode );
|
|
void ms( TQDomElement element, TQDomNode docnode );
|
|
// mglyph not supported
|
|
|
|
// General Layout Schemata
|
|
void mrow( TQDomElement element, TQDomNode docnode );
|
|
void mfrac( TQDomElement element, TQDomNode docnode );
|
|
void msqrt( TQDomElement element, TQDomNode docnode );
|
|
void mroot( TQDomElement element, TQDomNode docnode );
|
|
void mstyle( TQDomElement element, TQDomNode docnode );
|
|
// merror not supported
|
|
// mpadded not supported
|
|
// mphantom not supported
|
|
void mfenced( TQDomElement element, TQDomNode docnode );
|
|
// menclose not supported
|
|
|
|
// Script and Limit Schemata
|
|
void msub_msup( TQDomElement element, TQDomNode docnode );
|
|
void msubsup( TQDomElement element, TQDomNode docnode );
|
|
void munder( TQDomElement element, TQDomNode docnode, bool oasisFormat );
|
|
void mover( TQDomElement element, TQDomNode docnode, bool oasisFormat );
|
|
void munderover( TQDomElement element, TQDomNode docnode, bool oasisFormat );
|
|
// mmultiscripts not supported
|
|
|
|
// Tables and Matrices
|
|
void mtable( TQDomElement element, TQDomNode docnode );
|
|
// not much supported
|
|
|
|
// Enlivening Expressions
|
|
// maction not supported
|
|
|
|
protected:
|
|
void createTextElements( TQString text, TQDomNode docnode );
|
|
void createNameSequence( TQString text, TQDomNode docnode );
|
|
double convertToPoint( TQString value, bool* ok );
|
|
bool isEmbellishedOperator( TQDomNode node, TQDomElement* mo, bool oasisFormat );
|
|
bool isSpaceLike( TQDomNode node, bool oasisFormat );
|
|
|
|
enum MathVariant {
|
|
normal,
|
|
bold,
|
|
italic,
|
|
bold_italic,
|
|
double_struck,
|
|
bold_fraktur,
|
|
script,
|
|
bold_script,
|
|
fraktur,
|
|
sans_serif,
|
|
bold_sans_serif,
|
|
sans_serif_italic,
|
|
sans_serif_bold_italic,
|
|
monospace
|
|
};
|
|
|
|
struct MathStyle {
|
|
MathStyle()
|
|
: scriptsizemultiplier( 0.71 ),
|
|
scriptminsize( 8 ),
|
|
veryverythinmathspace( 1.0/18.0 ),
|
|
verythinmathspace( 2.0/18.0 ),
|
|
thinmathspace( 3.0/18.0 ),
|
|
mediummathspace( 4.0/18.0 ),
|
|
thickmathspace( 5.0/18.0 ),
|
|
verythickmathspace( 6.0/18.0 ),
|
|
veryverythickmathspace( 7.0/18.0 ),
|
|
|
|
useVariant( false )
|
|
{
|
|
}
|
|
|
|
void styleChange()
|
|
{
|
|
kdDebug( DEBUGID ) << "Style Change:"
|
|
<< "\n scriptlevel = " << scriptlevel
|
|
<< "\n displaystyle = " << displaystyle
|
|
<< "\n scriptsizemultiplier = "
|
|
<< scriptsizemultiplier
|
|
<< "\n scriptminsize = " << scriptminsize
|
|
<< endl;
|
|
}
|
|
|
|
void setStyles( TQDomElement element )
|
|
{
|
|
if ( !useVariant )
|
|
return;
|
|
|
|
switch ( mathvariant )
|
|
{
|
|
case normal:
|
|
element.setAttribute( "STYLE", "normal" );
|
|
break;
|
|
case bold:
|
|
element.setAttribute( "STYLE", "bold" );
|
|
break;
|
|
|
|
case bold_italic:
|
|
element.setAttribute( "STYLE", "bolditalic" );
|
|
break;
|
|
case italic:
|
|
element.setAttribute( "STYLE", "italic" );
|
|
break;
|
|
|
|
case double_struck:
|
|
element.setAttribute( "FAMILY", "doublestruck" );
|
|
break;
|
|
|
|
case bold_fraktur:
|
|
element.setAttribute( "STYLE", "bold" );
|
|
case fraktur:
|
|
element.setAttribute( "FAMILY", "fraktur" );
|
|
break;
|
|
|
|
case bold_script:
|
|
element.setAttribute( "STYLE", "bold" );
|
|
case script:
|
|
element.setAttribute( "FAMILY", "script" );
|
|
break;
|
|
|
|
case bold_sans_serif:
|
|
element.setAttribute( "STYLE", "bold" );
|
|
case sans_serif:
|
|
element.setAttribute( "FAMILY", "normal" );
|
|
break;
|
|
case sans_serif_bold_italic:
|
|
element.setAttribute( "STYLE", "bolditalic" );
|
|
element.setAttribute( "FAMILY", "normal" );
|
|
break;
|
|
case sans_serif_italic:
|
|
element.setAttribute( "STYLE", "italic" );
|
|
element.setAttribute( "FAMILY", "normal" );
|
|
break;
|
|
|
|
//case monospace:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void readStyles( TQDomElement mmlElement )
|
|
{
|
|
if ( mmlElement.hasAttribute( "mathvariant" ) )
|
|
{
|
|
useVariant = true;
|
|
|
|
if ( mmlElement.attribute( "mathvariant" ) == "normal" )
|
|
mathvariant = normal;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "bold" )
|
|
mathvariant = bold;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "italic" )
|
|
mathvariant = italic;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "bold-italic" )
|
|
mathvariant = bold_italic;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "double-struck" )
|
|
mathvariant = double_struck;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "bold-fraktur" )
|
|
mathvariant = bold_fraktur;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "script" )
|
|
mathvariant = script;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "bold-script" )
|
|
mathvariant = bold_script;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "fraktur" )
|
|
mathvariant = fraktur;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif" )
|
|
mathvariant = sans_serif;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "bold-sans-serif" )
|
|
mathvariant = bold_sans_serif;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif-italic" )
|
|
mathvariant = sans_serif_italic;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif-bold-italic" )
|
|
mathvariant = sans_serif_bold_italic;
|
|
else if ( mmlElement.attribute( "mathvariant" ) == "monospace" )
|
|
mathvariant = monospace;
|
|
}
|
|
}
|
|
|
|
// Styles, set by <mstyle> // default
|
|
|
|
int scriptlevel; // inherited
|
|
bool displaystyle; // inherited
|
|
double scriptsizemultiplier; // 0.71
|
|
double scriptminsize; // 8pt
|
|
// color
|
|
// background
|
|
double veryverythinmathspace; // 1/18em = 0.0555556em
|
|
double verythinmathspace; // 2/18em = 0.111111em
|
|
double thinmathspace; // 3/18em = 0.166667em
|
|
double mediummathspace; // 4/18em = 0.222222em
|
|
double thickmathspace; // 5/18em = 0.277778em
|
|
double verythickmathspace; // 6/18em = 0.333333em
|
|
double veryverythickmathspace; // 7/18em = 0.388889em
|
|
|
|
// 'Local' styles
|
|
|
|
MathVariant mathvariant;
|
|
bool useVariant;
|
|
//int mathsize;
|
|
};
|
|
|
|
MathStyle style;
|
|
TQDomDocument doc;
|
|
|
|
private:
|
|
const ContextStyle& context;
|
|
MathML2KFormula* filter;
|
|
};
|
|
|
|
MathML2KFormulaPrivate::MathML2KFormulaPrivate( MathML2KFormula* mml_filter, const ContextStyle& cs, const TQDomDocument& formuladoc )
|
|
: doc( formuladoc ), context( cs ), filter( mml_filter )
|
|
{
|
|
}
|
|
|
|
MathML2KFormulaPrivate::~MathML2KFormulaPrivate()
|
|
{
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::math( TQDomElement element )
|
|
{
|
|
TQDomElement formula = doc.createElement( "FORMULA" );
|
|
TQDomNode n = element.firstChild();
|
|
|
|
TQString display = element.attribute( "display" );
|
|
|
|
if ( display == "block" ) {
|
|
style.displaystyle = true;
|
|
}
|
|
else {
|
|
// if display == "inline" (default) or illegal (then use default)
|
|
style.displaystyle = false;
|
|
}
|
|
|
|
style.scriptlevel = 0;
|
|
|
|
/*kdDebug( DEBUGID ) << "<math> element:\n displaystyle = "
|
|
<< style.displaystyle << "\n scriptlevel = "
|
|
<< style.scriptlevel << endl;*/
|
|
|
|
while ( !n.isNull() ) {
|
|
filter->processElement( n, doc, formula );
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
doc.appendChild( formula );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mi( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
MathStyle previousStyle( style );
|
|
TQString text = element.text().stripWhiteSpace();
|
|
if ( text.length() == 1 ) { // Default italic, only when content is one char
|
|
style.mathvariant = italic;
|
|
style.useVariant = true;
|
|
style.readStyles( element );
|
|
createTextElements( text, docnode );
|
|
} else { // If length is 0 or >1, it should be a text sequence
|
|
style.readStyles( element );
|
|
createNameSequence( text, docnode );
|
|
}
|
|
style = previousStyle;
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mo( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
MathStyle previousStyle( style );
|
|
style.readStyles( element );
|
|
|
|
TQString text = element.text().stripWhiteSpace();
|
|
createTextElements( text, docnode );
|
|
|
|
style = previousStyle;
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mn( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
MathStyle previousStyle( style );
|
|
style.readStyles( element );
|
|
|
|
TQString text = element.text().stripWhiteSpace();
|
|
createTextElements( text, docnode );
|
|
|
|
style = previousStyle;
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mtext( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
MathStyle previousStyle( style );
|
|
style.readStyles( element );
|
|
|
|
TQDomNode n = element.firstChild();
|
|
|
|
while ( !n.isNull() ) {
|
|
if ( n.isText() ) {
|
|
TQString text = n.toText().data().stripWhiteSpace();
|
|
createTextElements( text, docnode );
|
|
}
|
|
else if ( n.isElement() ) {
|
|
filter->processElement( n, doc, docnode );
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<mtext> child: " << n.nodeName() << endl;
|
|
}
|
|
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
style = previousStyle;
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::ms( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQString lquote = element.attribute( "lquote", "\"" );
|
|
TQString rquote = element.attribute( "rquote", "\"" );
|
|
TQString text;
|
|
|
|
text = lquote;
|
|
text += element.text().stripWhiteSpace();
|
|
text += rquote;
|
|
|
|
createTextElements( text, docnode );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mspace( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
// we support only horizontal space
|
|
TQString width = element.attribute( "width" );
|
|
|
|
TQDomElement spaceelement = doc.createElement( "SPACE" );
|
|
|
|
// check for namedspace. We don't support much...
|
|
if ( width == "veryverythinmathspace" ) {
|
|
spaceelement.setAttribute( "WIDTH", "thin" );
|
|
}
|
|
else if ( width == "verythinmathspace" ) {
|
|
spaceelement.setAttribute( "WIDTH", "thin" );
|
|
}
|
|
else if ( width == "thinmathspace" ) {
|
|
spaceelement.setAttribute( "WIDTH", "thin" );
|
|
}
|
|
else if ( width == "mediummathspace" ) {
|
|
spaceelement.setAttribute( "WIDTH", "medium" );
|
|
}
|
|
else if ( width == "thickmathspace" ) {
|
|
spaceelement.setAttribute( "WIDTH", "thick" );
|
|
}
|
|
else if ( width == "verythickmathspace" ) {
|
|
spaceelement.setAttribute( "WIDTH", "thick" );
|
|
}
|
|
else if ( width == "veryverythickmathspace" ) {
|
|
spaceelement.setAttribute( "WIDTH", "quad" );
|
|
}
|
|
|
|
else {
|
|
// units
|
|
|
|
double w = 0;
|
|
bool ok;
|
|
|
|
if ( width.endsWith( "em" ) ) {
|
|
// See MathML specification, Appendix H
|
|
w = context.getDefaultFont().pointSize();
|
|
if ( w == -1 ) {
|
|
TQFontMetrics fm( context.getDefaultFont() );
|
|
w = fm.width( 'm' );
|
|
}
|
|
w = w * width.remove( width.length() - 2, 2 ).toDouble( &ok );
|
|
// w in points?
|
|
}
|
|
else if ( width.endsWith( "px" ) ) {
|
|
w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
|
|
// w in pixels
|
|
}
|
|
else if ( width.endsWith( "in" ) ) {
|
|
w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
|
|
w *= 72; // w in points
|
|
}
|
|
else if ( width.endsWith( "cm" ) ) {
|
|
w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
|
|
w *= 1/2.54 * 72; // w in points
|
|
}
|
|
else if ( width.endsWith( "mm" ) ) {
|
|
w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
|
|
w *= 1/25.4 * 72; // w in points
|
|
}
|
|
else if ( width.endsWith( "pt" ) ) {
|
|
w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
|
|
// w in points
|
|
}
|
|
else if ( width.endsWith( "pc" ) ) {
|
|
w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
|
|
w /= 12; // w in points
|
|
}
|
|
else {
|
|
w = width.toDouble( &ok );
|
|
}
|
|
|
|
if ( !ok )
|
|
return;
|
|
|
|
if ( w < 20 )
|
|
spaceelement.setAttribute( "WIDTH", "thin" );
|
|
else if ( w < 40 )
|
|
spaceelement.setAttribute( "WIDTH", "medium" );
|
|
else if ( w < 80 )
|
|
spaceelement.setAttribute( "WIDTH", "thick" );
|
|
else
|
|
spaceelement.setAttribute( "WIDTH", "quad" );
|
|
}
|
|
|
|
docnode.appendChild( spaceelement );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mrow( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQDomNode n = element.firstChild();
|
|
while ( !n.isNull() ) {
|
|
if ( n.isElement () ) {
|
|
TQDomElement e = n.toElement();
|
|
// We do not allow sequence inside sequence
|
|
filter->processElement( e, doc, docnode );
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<mrow> child: " << n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mfrac( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQDomNode n = element.firstChild();
|
|
TQDomElement fraction = doc.createElement( "FRACTION" );
|
|
|
|
MathStyle previousStyle( style );
|
|
style.displaystyle ? style.displaystyle = false : style.scriptlevel += 1;
|
|
style.styleChange();
|
|
|
|
int i = 0;
|
|
while ( !n.isNull() && i < 2 ) {
|
|
if ( n.isElement() ) {
|
|
++i;
|
|
if ( i == 1 ) { //first is numerator
|
|
TQDomElement numerator =
|
|
doc.createElement( "NUMERATOR" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
numerator.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
fraction.appendChild( numerator );
|
|
|
|
}
|
|
else {
|
|
TQDomElement denominator =
|
|
doc.createElement( "DENOMINATOR" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
denominator.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
fraction.appendChild( denominator );
|
|
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<mfrac> child: " << n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
style = previousStyle;
|
|
docnode.appendChild( fraction );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mroot( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQDomNode n = element.firstChild();
|
|
int i = 0;
|
|
TQDomElement root = doc.createElement( "ROOT" );
|
|
|
|
while ( !n.isNull() && i < 2 ) {
|
|
if ( n.isElement() ) {
|
|
++i;
|
|
if ( i == 1 ) { //first is content (base)
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
|
|
root.appendChild(content);
|
|
}
|
|
else { // index
|
|
MathStyle previousStyle( style );
|
|
style.scriptlevel += 2;
|
|
style.displaystyle = false;
|
|
style.styleChange();
|
|
|
|
TQDomElement index = doc.createElement( "INDEX" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
|
|
style = previousStyle;
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<mroot> child: " << n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
docnode.appendChild( root );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::msqrt( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQDomNode n = element.firstChild();
|
|
TQDomElement root = doc.createElement( "ROOT" );
|
|
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
root.appendChild( content );
|
|
|
|
while ( !n.isNull() ) {
|
|
if ( n.isElement() ) {
|
|
filter->processElement( n.toElement(), doc, sequence );
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<msqrt> child: " << n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
docnode.appendChild( root );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mstyle( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
bool ok;
|
|
|
|
MathStyle previousStyle( style );
|
|
style.readStyles( element );
|
|
|
|
if ( element.hasAttribute( "scriptlevel" ) ) {
|
|
TQString scriptlevel = element.attribute( "scriptlevel" );
|
|
if ( scriptlevel.startsWith( "+" ) || scriptlevel.startsWith( "-" ) )
|
|
style.scriptlevel += scriptlevel.toInt( &ok );
|
|
else
|
|
style.scriptlevel = scriptlevel.toInt( &ok );
|
|
if ( !ok )
|
|
style.scriptlevel = previousStyle.scriptlevel;
|
|
}
|
|
if ( element.hasAttribute( "displaystyle" ) ) {
|
|
TQString displaystyle = element.attribute( "displaystyle" );
|
|
if ( displaystyle == "true" )
|
|
style.displaystyle = true;
|
|
else if ( displaystyle == "false" )
|
|
style.displaystyle = false;
|
|
}
|
|
if ( element.hasAttribute( "scriptsizemultiplier" ) ) {
|
|
style.scriptsizemultiplier =
|
|
element.attribute( "scriptsizemultiplier" ).toDouble( &ok );
|
|
if ( !ok )
|
|
style.scriptsizemultiplier = previousStyle.scriptsizemultiplier;
|
|
}
|
|
if ( element.hasAttribute( "scriptminsize" ) ) {
|
|
TQString scriptminsize = element.attribute( "scriptminsize" );
|
|
style.scriptminsize = convertToPoint( scriptminsize, &ok );
|
|
if ( !ok )
|
|
style.scriptminsize = previousStyle.scriptminsize;
|
|
}
|
|
|
|
if ( element.hasAttribute( "veryverythinmathspace" ) ) {
|
|
TQString vvthinmspace = element.attribute( "veryverythinmathspace" );
|
|
style.veryverythinmathspace = convertToPoint( vvthinmspace, &ok );
|
|
if ( !ok )
|
|
style.veryverythinmathspace = previousStyle.veryverythinmathspace;
|
|
}
|
|
if ( element.hasAttribute( "verythinmathspace" ) ) {
|
|
TQString vthinmspace = element.attribute( "verythinmathspace" );
|
|
style.verythinmathspace = convertToPoint( vthinmspace, &ok );
|
|
if ( !ok )
|
|
style.verythinmathspace = previousStyle.verythinmathspace;
|
|
}
|
|
if ( element.hasAttribute( "thinmathspace" ) ) {
|
|
TQString thinmathspace = element.attribute( "thinmathspace" );
|
|
style.thinmathspace = convertToPoint( thinmathspace, &ok );
|
|
if ( !ok )
|
|
style.thinmathspace = previousStyle.thinmathspace;
|
|
}
|
|
if ( element.hasAttribute( "mediummathspace" ) ) {
|
|
TQString mediummathspace = element.attribute( "mediummathspace" );
|
|
style.mediummathspace = convertToPoint( mediummathspace, &ok );
|
|
if ( !ok )
|
|
style.mediummathspace = previousStyle.mediummathspace;
|
|
}
|
|
if ( element.hasAttribute( "thickmathspace" ) ) {
|
|
TQString thickmathspace = element.attribute( "thickmathspace" );
|
|
style.thickmathspace = convertToPoint( thickmathspace, &ok );
|
|
if ( !ok )
|
|
style.thickmathspace = previousStyle.thickmathspace;
|
|
}
|
|
if ( element.hasAttribute( "verythickmathspace" ) ) {
|
|
TQString vthickmspace = element.attribute( "verythickmathspace" );
|
|
style.verythickmathspace = convertToPoint( vthickmspace, &ok );
|
|
if ( !ok )
|
|
style.verythickmathspace = previousStyle.verythickmathspace;
|
|
}
|
|
if ( element.hasAttribute( "veryverythickmathspace" ) ) {
|
|
TQString vvthickmspace = element.attribute( "veryverythickmathspace" );
|
|
style.veryverythickmathspace = convertToPoint( vvthickmspace, &ok );
|
|
if ( !ok )
|
|
style.veryverythickmathspace =
|
|
previousStyle.veryverythickmathspace;
|
|
}
|
|
|
|
style.styleChange();
|
|
|
|
TQDomNode n = element.firstChild();
|
|
while ( !n.isNull() ) {
|
|
filter->processElement( n, doc, docnode );
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
style = previousStyle;
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mfenced( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQDomElement bracket = doc.createElement( "BRACKET" );
|
|
TQString value = element.attribute( "open", "(" );
|
|
bracket.setAttribute( "LEFT", TQString::number( value.at( 0 ).latin1() ) );
|
|
value = element.attribute( "close", ")" );
|
|
bracket.setAttribute( "RIGHT", TQString::number( value.at( 0 ).latin1() ) );
|
|
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
|
|
TQString separators = element.attribute( "separators", "," );
|
|
|
|
TQDomNode n = element.firstChild();
|
|
uint i = 0;
|
|
while ( !n.isNull() ) {
|
|
if ( n.isElement() ) {
|
|
if ( i != 0 && !separators.isEmpty() ) {
|
|
TQDomElement textelement = doc.createElement( "TEXT" );
|
|
if ( i > separators.length() )
|
|
i = separators.length();
|
|
textelement.setAttribute( "CHAR", TQString( separators.at( i - 1 ) ) );
|
|
//style.setStyles( textelement );
|
|
sequence.appendChild( textelement );
|
|
}
|
|
++i;
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<mfenced> child: " << n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
bracket.appendChild( content );
|
|
docnode.appendChild( bracket );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mtable( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
MathStyle previousStyle( style );
|
|
TQString displaystyle = element.attribute( "displaystyle", "false" );
|
|
if ( displaystyle == "true" ) {
|
|
style.displaystyle = true;
|
|
}
|
|
else {
|
|
// false is default and also used for illegal values
|
|
style.displaystyle = false;
|
|
}
|
|
style.styleChange();
|
|
|
|
TQString subtag;
|
|
int rows = 0; int cols = 0;
|
|
TQDomNode n = element.firstChild();
|
|
|
|
while ( !n.isNull() ) {
|
|
if ( n.isElement() ) {
|
|
TQDomElement e = n.toElement();
|
|
subtag = e.tagName();
|
|
if (subtag == "mtr")
|
|
{
|
|
++rows;
|
|
|
|
/* Determins the number of columns */
|
|
|
|
TQDomNode cellnode = e.firstChild();
|
|
int cc = 0;
|
|
|
|
while ( !cellnode.isNull() ) {
|
|
if ( cellnode.isElement() )
|
|
cc++;
|
|
cellnode = cellnode.nextSibling();
|
|
}
|
|
|
|
if ( cc > cols )
|
|
cols = cc;
|
|
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<mtable> child: " << n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
/* Again createing elements, I need to know the number
|
|
of rows and cols to leave empty spaces */
|
|
|
|
n = element.firstChild();
|
|
TQDomElement matrix = doc.createElement( "MATRIX" );
|
|
matrix.setAttribute( "COLUMNS", cols );
|
|
matrix.setAttribute( "ROWS", rows );
|
|
|
|
while ( !n.isNull() ) {
|
|
if ( n.isElement() ) {
|
|
TQDomElement e = n.toElement();
|
|
subtag = e.tagName();
|
|
if ( subtag == "mtr" ) {
|
|
TQDomNode cellnode = e.firstChild();
|
|
int cc = 0;
|
|
while ( !cellnode.isNull() ) {
|
|
if ( cellnode.isElement() ) {
|
|
++cc;
|
|
TQDomElement cell = doc.createElement( "SEQUENCE" );
|
|
TQDomElement cellelement = cellnode.toElement();
|
|
filter->processElement( cellelement, doc, cell );
|
|
matrix.appendChild( cell );
|
|
}
|
|
cellnode = cellnode.nextSibling();
|
|
}
|
|
|
|
/* Add empty elements */
|
|
for(; cc < cols; cc++ ) {
|
|
TQDomElement cell = doc.createElement( "SEQUENCE" );
|
|
matrix.appendChild( cell );
|
|
}
|
|
}
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
style = previousStyle;
|
|
docnode.appendChild(matrix);
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::msub_msup( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQDomNode n = element.firstChild();
|
|
int i = 0;
|
|
TQDomElement root = doc.createElement( "INDEX" );
|
|
|
|
while ( !n.isNull() && i < 2 ) {
|
|
if ( n.isElement() ) {
|
|
++i;
|
|
if ( i == 1 ) { // first is content (base)
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
|
|
root.appendChild( content );
|
|
}
|
|
else {
|
|
TQDomElement index;
|
|
if ( element.tagName() == "msup" )
|
|
index = doc.createElement( "UPPERRIGHT" );
|
|
else
|
|
index = doc.createElement( "LOWERRIGHT" );
|
|
|
|
MathStyle previousStyle( style );
|
|
style.scriptlevel += 1;
|
|
style.displaystyle = false;
|
|
style.styleChange();
|
|
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
|
|
style = previousStyle;
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
|
|
<< n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
docnode.appendChild( root );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::munder( TQDomElement element, TQDomNode docnode, bool oasisFormat )
|
|
{
|
|
bool accentunder;
|
|
|
|
TQString au = element.attribute( "accentunder" );
|
|
if ( au == "true" )
|
|
accentunder = true;
|
|
else if ( au == "false" )
|
|
accentunder = false;
|
|
else {
|
|
// use default
|
|
|
|
TQDomElement mo;
|
|
// is underscript an embellished operator?
|
|
if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo, oasisFormat ) ) {
|
|
if ( mo.attribute( "accent" ) == "true" )
|
|
accentunder = true;
|
|
else
|
|
accentunder = false;
|
|
}
|
|
else
|
|
accentunder = false;
|
|
}
|
|
|
|
TQDomNode n = element.firstChild();
|
|
int i = 0;
|
|
TQDomElement root = doc.createElement( "INDEX" );
|
|
|
|
while ( !n.isNull() && i < 2 ) {
|
|
if ( n.isElement() ) {
|
|
++i;
|
|
if ( i == 1 ) { // first is content (base)
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
|
|
root.appendChild( content );
|
|
}
|
|
else { // underscript
|
|
MathStyle previousStyle( style );
|
|
style.displaystyle = false;
|
|
if ( !accentunder ) {
|
|
style.scriptlevel += 1;
|
|
style.styleChange();
|
|
}
|
|
|
|
TQDomElement mo; TQDomElement index;
|
|
if ( isEmbellishedOperator( n.previousSibling(), &mo, oasisFormat ) &&
|
|
!previousStyle.displaystyle &&
|
|
mo.attribute( "movablelimits" ) == "true" )
|
|
{
|
|
index = doc.createElement( "LOWERRIGHT" );
|
|
}
|
|
else {
|
|
index = doc.createElement( "LOWERMIDDLE" );
|
|
}
|
|
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
|
|
style = previousStyle;
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
|
|
<< n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
docnode.appendChild( root );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::mover( TQDomElement element, TQDomNode docnode, bool oasisFormat )
|
|
{
|
|
bool accent;
|
|
|
|
TQString ac = element.attribute( "accent" );
|
|
if ( ac == "true" )
|
|
accent = true;
|
|
else if ( ac == "false" )
|
|
accent = false;
|
|
else {
|
|
// use default
|
|
|
|
TQDomElement mo;
|
|
// is overscript an embellished operator?
|
|
if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo, oasisFormat ) ) {
|
|
if ( mo.attribute( "accent" ) == "true" )
|
|
accent = true;
|
|
else
|
|
accent = false;
|
|
}
|
|
else
|
|
accent = false;
|
|
}
|
|
|
|
TQDomNode n = element.firstChild();
|
|
int i = 0;
|
|
TQDomElement root = doc.createElement( "INDEX" );
|
|
|
|
while ( !n.isNull() && i < 2 ) {
|
|
if ( n.isElement() ) {
|
|
++i;
|
|
if ( i == 1 ) { // first is content (base)
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
|
|
root.appendChild( content );
|
|
}
|
|
else { // overscript
|
|
MathStyle previousStyle( style );
|
|
style.displaystyle = false;
|
|
if ( !accent ) {
|
|
style.scriptlevel += 1;
|
|
style.styleChange();
|
|
}
|
|
|
|
TQDomElement mo; TQDomElement index;
|
|
if ( isEmbellishedOperator( n.previousSibling(), &mo, oasisFormat ) &&
|
|
!previousStyle.displaystyle &&
|
|
mo.attribute( "movablelimits" ) == "true" )
|
|
{
|
|
index = doc.createElement( "UPPERRIGHT" );
|
|
}
|
|
else {
|
|
index = doc.createElement( "UPPERMIDDLE" );
|
|
}
|
|
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
|
|
style = previousStyle;
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
|
|
<< n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
docnode.appendChild( root );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::munderover( TQDomElement element, TQDomNode docnode, bool oasisFormat )
|
|
{
|
|
bool accent;
|
|
bool accentunder;
|
|
|
|
TQString value = element.attribute( "accentunder" );
|
|
if ( value == "true" )
|
|
accentunder = true;
|
|
else if ( value == "false" )
|
|
accentunder = false;
|
|
else {
|
|
// use default
|
|
|
|
TQDomElement mo;
|
|
// is underscript an embellished operator?
|
|
if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo, oasisFormat ) ) {
|
|
if ( mo.attribute( "accent" ) == "true" )
|
|
accentunder = true;
|
|
else
|
|
accentunder = false;
|
|
}
|
|
else
|
|
accentunder = false;
|
|
}
|
|
value = element.attribute( "accent" );
|
|
if ( value == "true" )
|
|
accent = true;
|
|
else if ( value == "false" )
|
|
accent = false;
|
|
else {
|
|
// use default
|
|
|
|
TQDomElement mo;
|
|
// is overscript an embellished operator?
|
|
if ( isEmbellishedOperator( element.childNodes().item( 2 ), &mo,oasisFormat ) ) {
|
|
kdDebug( DEBUGID ) << "embellished operator" << endl;
|
|
if ( mo.attribute( "accent" ) == "true" )
|
|
accent = true;
|
|
else
|
|
accent = false;
|
|
}
|
|
else
|
|
accent = false;
|
|
}
|
|
kdDebug( DEBUGID ) << "munderover:\n accentunder = " << accentunder
|
|
<< "\n accent = " << accent << endl;
|
|
|
|
TQDomNode n = element.firstChild();
|
|
int i = 0;
|
|
TQDomElement root = doc.createElement( "INDEX" );
|
|
|
|
while ( !n.isNull() && i < 3 ) {
|
|
if ( n.isElement() ) {
|
|
++i;
|
|
if ( i == 1 ) { // base
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
|
|
root.appendChild( content );
|
|
}
|
|
else if ( i == 2 ) { // underscript
|
|
MathStyle previousStyle( style );
|
|
style.displaystyle = false;
|
|
if ( !accentunder ) {
|
|
style.scriptlevel += 1;
|
|
style.styleChange();
|
|
}
|
|
|
|
TQDomElement mo; TQDomElement index;
|
|
// is the base an embellished operator?
|
|
if ( isEmbellishedOperator( element.firstChild(), &mo, oasisFormat ) &&
|
|
!previousStyle.displaystyle &&
|
|
mo.attribute( "movablelimits" ) == "true" )
|
|
{
|
|
index = doc.createElement( "LOWERRIGHT" );
|
|
}
|
|
else {
|
|
index = doc.createElement( "LOWERMIDDLE" );
|
|
}
|
|
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
|
|
style = previousStyle;
|
|
}
|
|
else { // overscript
|
|
MathStyle previousStyle( style );
|
|
style.displaystyle = false;
|
|
if ( !accent ) {
|
|
style.scriptlevel += 1;
|
|
style.styleChange();
|
|
}
|
|
|
|
TQDomElement mo; TQDomElement index;
|
|
if ( isEmbellishedOperator( element.firstChild(), &mo, oasisFormat ) &&
|
|
!previousStyle.displaystyle &&
|
|
mo.attribute( "movablelimits" ) == "true" )
|
|
{
|
|
index = doc.createElement( "UPPERRIGHT" );
|
|
}
|
|
else {
|
|
index = doc.createElement( "UPPERMIDDLE" );
|
|
}
|
|
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
|
|
style = previousStyle;
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
|
|
<< n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
docnode.appendChild( root );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::msubsup( TQDomElement element, TQDomNode docnode )
|
|
{
|
|
TQDomNode n = element.firstChild();
|
|
int i = 0;
|
|
TQDomElement root = doc.createElement("INDEX");
|
|
MathStyle previousStyle( style );
|
|
|
|
while ( !n.isNull() && i < 2 ) {
|
|
if ( n.isElement() ) {
|
|
++i;
|
|
if ( i == 1 ) { // base
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
content.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
|
|
root.appendChild( content );
|
|
}
|
|
else if ( i == 2 ) { // subscript
|
|
style.scriptlevel += 1;
|
|
style.displaystyle = false;
|
|
style.styleChange();
|
|
|
|
TQDomElement index;
|
|
index = doc.createElement( "LOWERRIGHT" );
|
|
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
}
|
|
else { // superscript
|
|
TQDomElement index;
|
|
index = doc.createElement( "UPPERRIGHT" );
|
|
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
index.appendChild( sequence );
|
|
TQDomElement e = n.toElement();
|
|
filter->processElement( e, doc, sequence );
|
|
root.appendChild( index );
|
|
|
|
style = previousStyle;
|
|
|
|
}
|
|
}
|
|
else {
|
|
kdDebug( DEBUGID ) << "<msubsup> child: " << n.nodeName() << endl;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
docnode.appendChild( root );
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::createTextElements( TQString text, TQDomNode docnode )
|
|
{
|
|
for ( uint i = 0; i < text.length(); ++i ) {
|
|
TQDomElement textelement = doc.createElement( "TEXT" );
|
|
textelement.setAttribute( "CHAR", TQString( text.at( i ) ) );
|
|
style.setStyles( textelement );
|
|
if ( context.symbolTable().inTable( text.at( i ) ) ) {
|
|
// The element is a symbol.
|
|
textelement.setAttribute( "SYMBOL", "3" );
|
|
}
|
|
docnode.appendChild( textelement );
|
|
}
|
|
}
|
|
|
|
void MathML2KFormulaPrivate::createNameSequence( TQString text, TQDomNode docnode )
|
|
{
|
|
TQDomElement namesequence = doc.createElement( "NAMESEQUENCE" );
|
|
for ( uint i = 0; i < text.length(); ++i ) {
|
|
TQDomElement textelement = doc.createElement( "TEXT" );
|
|
textelement.setAttribute( "CHAR", TQString( text.at( i ) ) );
|
|
style.setStyles( textelement );
|
|
if ( context.symbolTable().inTable( text.at( i ) ) ) {
|
|
// The element is a symbol.
|
|
textelement.setAttribute( "SYMBOL", "3" );
|
|
}
|
|
namesequence.appendChild( textelement );
|
|
}
|
|
docnode.appendChild( namesequence );
|
|
}
|
|
|
|
double MathML2KFormulaPrivate::convertToPoint( TQString value, bool* ok )
|
|
{
|
|
double pt = 0;
|
|
|
|
if ( value.endsWith( "em" ) ) {
|
|
// See MathML specification, Appendix H
|
|
pt = context.getDefaultFont().pointSize();
|
|
if ( pt == -1 ) {
|
|
TQFontMetrics fm( context.getDefaultFont() );
|
|
pt = fm.width( 'M' );
|
|
// PIXELS!
|
|
}
|
|
pt = pt * value.remove( value.length() - 2, 2 ).toDouble( ok );
|
|
}
|
|
else if ( value.endsWith( "ex" ) ) {
|
|
TQFontMetrics fm( context.getDefaultFont() );
|
|
pt = fm.height();
|
|
// PIXELS, and totally wrong!
|
|
}
|
|
else if ( value.endsWith( "px" ) ) {
|
|
pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
|
|
// PIXELS!
|
|
}
|
|
else if ( value.endsWith( "in" ) ) {
|
|
pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
|
|
pt *= 72;
|
|
}
|
|
else if ( value.endsWith( "cm" ) ) {
|
|
pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
|
|
pt *= 1/2.54 * 72;
|
|
}
|
|
else if ( value.endsWith( "mm" ) ) {
|
|
pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
|
|
pt *= 1/25.4 * 72;
|
|
}
|
|
else if ( value.endsWith( "pt" ) ) {
|
|
pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
|
|
}
|
|
else if ( value.endsWith( "pc" ) ) {
|
|
pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
|
|
pt /= 12;
|
|
}
|
|
else {
|
|
pt = value.toDouble( ok );
|
|
}
|
|
|
|
return pt;
|
|
}
|
|
|
|
bool MathML2KFormulaPrivate::isEmbellishedOperator( TQDomNode node,
|
|
TQDomElement* mo, bool oasisFormat )
|
|
{
|
|
// See MathML 2.0 specification: 3.2.5.7
|
|
|
|
if ( !node.isElement() )
|
|
return false;
|
|
|
|
TQDomElement element = node.toElement();
|
|
TQString tag = element.tagName();
|
|
|
|
if ( tag == "mo" )
|
|
{
|
|
*mo = element;
|
|
return true;
|
|
}
|
|
if ( tag == "msub" || tag == "msup" || tag == "msubsup" ||
|
|
tag == "munder" || tag == "mover" || tag == "munderover" ||
|
|
tag == "mmultiscripts" || tag == "mfrac" || tag == "semantics" )
|
|
{
|
|
return isEmbellishedOperator( element.firstChild(), mo,oasisFormat );
|
|
}
|
|
if ( tag == "maction" )
|
|
{
|
|
return false; // not supported
|
|
}
|
|
if ( tag == "mrow" || tag == "mstyle" || tag == "mphantom" || tag == "mpadded" ) {
|
|
TQDomNode n = element.firstChild();
|
|
int i = 0;
|
|
|
|
while ( !n.isNull() ) {
|
|
if ( isEmbellishedOperator( n, mo,oasisFormat ) ) {
|
|
if ( ++i > 1 ) // one (only one) embellished operator
|
|
return false;
|
|
}
|
|
else if ( !isSpaceLike( n, oasisFormat ) ) { // zero or more space-like elements
|
|
return false;
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
return ( i == 1 );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool MathML2KFormulaPrivate::isSpaceLike( TQDomNode node, bool oasisFormat )
|
|
{
|
|
// See MathML 2.0 specification: 3.2.7.3
|
|
|
|
if ( !node.isElement() )
|
|
return false;
|
|
|
|
TQDomElement element = node.toElement();
|
|
TQString tag = element.tagName();
|
|
|
|
if ( tag == "mtext" || tag == "mspace" ||
|
|
tag == "maligngroup" || tag == "malignmark" ) {
|
|
return true;
|
|
}
|
|
if ( tag == "mstyle" || tag == "mphantom" || tag == "mpadded" || tag == "mrow" ) {
|
|
TQDomNode n = element.firstChild();
|
|
while ( !n.isNull() ) {
|
|
if ( isSpaceLike( n,oasisFormat ) )
|
|
n = n.nextSibling();
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
if ( tag == "maction" ) {
|
|
return false; // not supported
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
MathML2KFormula::MathML2KFormula( const TQDomDocument& mmldoc, const ContextStyle &contextStyle, bool _oasisFormat )
|
|
: m_error( false ), oasisFormat( _oasisFormat ), context( contextStyle )
|
|
{
|
|
orig_element = mmldoc.documentElement();
|
|
done = false;
|
|
}
|
|
|
|
MathML2KFormula::MathML2KFormula( const TQDomElement& mmlelm, const ContextStyle &contextStyle, bool _oasisFormat )
|
|
: m_error( false ), orig_element( mmlelm ), oasisFormat( _oasisFormat ), context( contextStyle )
|
|
{
|
|
done = false;
|
|
}
|
|
|
|
TQDomDocument MathML2KFormula::getKFormulaDom()
|
|
{
|
|
return formuladoc;
|
|
}
|
|
|
|
|
|
|
|
void MathML2KFormula::startConversion()
|
|
{
|
|
//TODO:let it be async
|
|
//kdDebug() << origdoc.toString() << endl;
|
|
done = false;
|
|
formuladoc = TQDomDocument( "KFORMULA" );
|
|
impl = new MathML2KFormulaPrivate( this, context, formuladoc );
|
|
if ( orig_element.tagName() == "math" ) {
|
|
impl->math( orig_element );
|
|
m_error = false;
|
|
}
|
|
else {
|
|
kdError() << "Not a MathML document!" << endl;
|
|
KMessageBox::error( 0, i18n( "The document does not seem to be MathML." ), i18n( "MathML Import Error" ) );
|
|
m_error = true;
|
|
}
|
|
done = true;
|
|
}
|
|
|
|
bool MathML2KFormula::processElement( TQDomNode node, TQDomDocument& doc, TQDomNode docnode )
|
|
{
|
|
|
|
//TQDomElement *element;
|
|
Type type = UNKNOWN;
|
|
|
|
if ( node.isElement() ) {
|
|
TQDomElement element = node.toElement();
|
|
TQString tag = element.tagName();
|
|
|
|
if ( tag == "mi" ) {
|
|
type = TOKEN;
|
|
impl->mi( element, docnode );
|
|
}
|
|
else if ( tag == "mo" ) {
|
|
type = TOKEN;
|
|
impl->mo( element, docnode );
|
|
}
|
|
else if ( tag == "mn" ) {
|
|
type = TOKEN;
|
|
impl->mn( element, docnode );
|
|
}
|
|
else if ( tag == "mtext" ) {
|
|
type = TOKEN;
|
|
impl->mtext( element, docnode );
|
|
}
|
|
else if ( tag == "ms" ) {
|
|
type = TOKEN;
|
|
impl->ms( element, docnode );
|
|
}
|
|
else if ( tag == "mspace" ) {
|
|
type = TOKEN;
|
|
impl->mspace( element, docnode );
|
|
}
|
|
else if ( tag == "mrow" ) {
|
|
type = LAYOUT;
|
|
impl->mrow( element, docnode );
|
|
}
|
|
else if ( tag == "mfrac" ) {
|
|
type = LAYOUT;
|
|
impl->mfrac( element, docnode );
|
|
}
|
|
else if ( tag == "mroot" ) {
|
|
type = LAYOUT;
|
|
impl->mroot( element, docnode );
|
|
}
|
|
else if ( tag == "msqrt" ) {
|
|
type = LAYOUT;
|
|
impl->msqrt( element, docnode );
|
|
}
|
|
else if ( tag == "mstyle" ) {
|
|
type = LAYOUT;
|
|
impl->mstyle( element, docnode );
|
|
}
|
|
else if ( tag == "mfenced" ) {
|
|
type = LAYOUT;
|
|
impl->mfenced( element, docnode );
|
|
}
|
|
else if ( tag == "mtable" ) {
|
|
type = TABLE;
|
|
impl->mtable( element, docnode );
|
|
}
|
|
else if ( tag == "msub" || tag == "msup" ) {
|
|
type = SCRIPT;
|
|
impl->msub_msup( element, docnode );
|
|
}
|
|
else if ( tag == "munder" ) {
|
|
type = SCRIPT;
|
|
impl->munder( element, docnode,oasisFormat );
|
|
}
|
|
else if ( tag == "mover" ) {
|
|
type = SCRIPT;
|
|
impl->mover( element, docnode,oasisFormat );
|
|
}
|
|
else if ( tag == "munderover" ) {
|
|
type = SCRIPT;
|
|
impl->munderover( element, docnode, oasisFormat );
|
|
}
|
|
else if ( tag == "msubsup" ) {
|
|
type = SCRIPT;
|
|
impl->msubsup( element, docnode );
|
|
}
|
|
|
|
// content markup (not yet complete)
|
|
else if ( tag == "apply" ) {
|
|
type = CONTENT;
|
|
TQDomNode n = element.firstChild();
|
|
TQDomElement op = n.toElement();
|
|
uint count = element.childNodes().count();
|
|
//adding explicit brackets to tqreplace "apply"s implicit ones
|
|
TQDomElement brackets = doc.createElement("BRACKET");
|
|
brackets.setAttribute("RIGHT", "41");
|
|
brackets.setAttribute("LEFT", "40");
|
|
TQDomElement content = doc.createElement("CONTENT");
|
|
brackets.appendChild(content);
|
|
TQDomElement base = doc.createElement("SEQUENCE");
|
|
content.appendChild(base);
|
|
docnode.appendChild(brackets);
|
|
//Arithmetic, Algebra and Logic operators status
|
|
// quotient X
|
|
// factorial O
|
|
// divide O
|
|
// max, min X
|
|
// minus O
|
|
// plus O
|
|
// power O
|
|
// rem X
|
|
// times O
|
|
// root X
|
|
// gcd X
|
|
// and O
|
|
// or O
|
|
// xor O
|
|
// not O
|
|
// implies O
|
|
// forall X
|
|
// exists X
|
|
// abs O
|
|
// conjugate X
|
|
// arg X
|
|
// real X
|
|
// imaginary X
|
|
// lcm X
|
|
// floor X
|
|
// ceiling X
|
|
|
|
// n-ary
|
|
if ( op.tagName() == "plus" || op.tagName() == "times" ||
|
|
op.tagName() == "and" || op.tagName() == "or" ||
|
|
op.tagName() == "xor" ) {
|
|
|
|
n = n.nextSibling();
|
|
bool first = true;
|
|
|
|
while ( !n.isNull() ) {
|
|
if ( n.isElement() ) {
|
|
if ( !first ) {
|
|
TQDomElement text = doc.createElement( "TEXT" );
|
|
TQString value;
|
|
|
|
if ( op.tagName() == "plus" )
|
|
value = "+";
|
|
else if ( op.tagName() == "times" )
|
|
value = "*";
|
|
else if ( op.tagName() == "and" )
|
|
value = "&";
|
|
else if ( op.tagName() == "or" )
|
|
value = "|";
|
|
else if ( op.tagName() == "xor" )
|
|
value = "^"; // ???
|
|
|
|
text.setAttribute( "CHAR", value ); //switch to createTextElements?
|
|
base.appendChild( text );
|
|
}
|
|
first = false;
|
|
TQDomElement e = n.toElement();
|
|
processElement( e, doc, base );
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
}
|
|
|
|
else if ( op.tagName() == "factorial" ) {
|
|
TQDomElement e = n.nextSibling().toElement();
|
|
processElement( e, doc, docnode );
|
|
impl->createTextElements( "!", base );
|
|
}
|
|
else if ( op.tagName() == "minus" ) {
|
|
n = n.nextSibling();
|
|
if ( count == 2 ) { // unary
|
|
impl->createTextElements( "-", base );
|
|
TQDomElement e = n.toElement();
|
|
processElement( e, doc, base );
|
|
}
|
|
else if ( count == 3 ) { // binary
|
|
TQDomElement e = n.toElement();
|
|
processElement( e, doc, base );
|
|
impl->createTextElements( "-", base );
|
|
n = n.nextSibling();
|
|
e = n.toElement();
|
|
processElement( e, doc, base );
|
|
}
|
|
}
|
|
|
|
else if ( op.tagName() == "divide" && count == 3 ) {
|
|
n = n.nextSibling();
|
|
TQDomElement e = n.toElement();
|
|
processElement( e, doc, base );
|
|
impl->createTextElements("/", base);
|
|
n = n.nextSibling();
|
|
e = n.toElement();
|
|
processElement( e, doc, base );
|
|
}
|
|
else if ( op.tagName() == "power" && count == 3 ) {
|
|
//code duplication of msub_sup(), but I can't find a way to cleanly call it
|
|
n = n.nextSibling();
|
|
TQDomElement e = n.toElement();
|
|
TQDomElement index = doc.createElement("INDEX");
|
|
base.appendChild(index);
|
|
TQDomElement content = doc.createElement("CONTENT");
|
|
index.appendChild(content);
|
|
TQDomElement sequence = doc.createElement("SEQUENCE");
|
|
content.appendChild(sequence);
|
|
processElement(e, doc, sequence);
|
|
TQDomElement upper = doc.createElement("UPPERRIGHT");
|
|
index.appendChild(upper);
|
|
sequence = doc.createElement("SEQUENCE");
|
|
upper.appendChild(sequence);
|
|
n = n.nextSibling();
|
|
e = n.toElement();
|
|
processElement(e, doc, sequence);
|
|
}
|
|
else if ( op.tagName() == "abs" && count == 2) {
|
|
n = n.nextSibling();
|
|
TQDomElement e = n.toElement();
|
|
TQDomElement bracket = doc.createElement("BRACKET");
|
|
bracket.setAttribute("RIGHT", "257");
|
|
bracket.setAttribute("LEFT", "256");
|
|
base.appendChild(bracket);
|
|
TQDomElement content = doc.createElement("CONTENT");
|
|
bracket.appendChild(content);
|
|
TQDomElement sequence = doc.createElement("SEQUENCE");
|
|
content.appendChild(sequence);
|
|
processElement(e, doc, sequence);
|
|
}
|
|
else if ( op.tagName() == "not" && count == 2) {
|
|
n = n.nextSibling();
|
|
TQDomElement e = n.toElement();
|
|
impl->createTextElements(TQString(TQChar(0xAC)), base);
|
|
processElement(e, doc, base);
|
|
}
|
|
else if ( op.tagName() == "implies" && count == 3 ) {
|
|
n = n.nextSibling();
|
|
TQDomElement e = n.toElement();
|
|
processElement( e, doc, base );
|
|
impl->createTextElements(TQString(TQChar(0x21D2)), base);
|
|
n = n.nextSibling();
|
|
e = n.toElement();
|
|
processElement( e, doc, base );
|
|
}
|
|
// many, many more...
|
|
|
|
}
|
|
|
|
else if ( tag == "cn" ) {
|
|
type = CONTENT;
|
|
TQString type = element.attribute( "type", "real" );
|
|
|
|
if ( type == "real" || type == "constant" ) {
|
|
impl->createTextElements( element.text().stripWhiteSpace(),
|
|
docnode );
|
|
}
|
|
else if ( type == "integer" ) {
|
|
TQString base = element.attribute( "base" );
|
|
if ( !base ) {
|
|
impl->createTextElements( element.text().stripWhiteSpace(),
|
|
docnode );
|
|
}
|
|
else {
|
|
TQDomElement index = doc.createElement( "INDEX" );
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
impl->createTextElements( element.text().stripWhiteSpace(),
|
|
sequence );
|
|
content.appendChild( sequence );
|
|
index.appendChild( content );
|
|
|
|
TQDomElement lowerright = doc.createElement( "LOWERRIGHT" );
|
|
sequence = doc.createElement( "SEQUENCE" );
|
|
|
|
impl->createTextElements( base, sequence );
|
|
|
|
lowerright.appendChild( sequence );
|
|
index.appendChild( lowerright );
|
|
|
|
docnode.appendChild( index );
|
|
}
|
|
}
|
|
else if ( type == "rational" ) {
|
|
TQDomNode n = element.firstChild();
|
|
impl->createTextElements( n.toText().data().stripWhiteSpace(),
|
|
docnode );
|
|
|
|
n = n.nextSibling(); // <sep/>
|
|
impl->createTextElements( "/", docnode );
|
|
|
|
n = n.nextSibling();
|
|
impl->createTextElements( n.toText().data().stripWhiteSpace(),
|
|
docnode );
|
|
}
|
|
else if ( type == "complex-cartesian" ) {
|
|
TQDomNode n = element.firstChild();
|
|
impl->createTextElements( n.toText().data().stripWhiteSpace(),
|
|
docnode );
|
|
|
|
n = n.nextSibling(); // <sep/>
|
|
impl->createTextElements( "+", docnode );
|
|
|
|
n = n.nextSibling();
|
|
impl->createTextElements( n.toText().data().stripWhiteSpace(),
|
|
docnode );
|
|
|
|
impl->createTextElements( "i", docnode );
|
|
}
|
|
|
|
else if ( type == "complex-polar" ) {
|
|
TQDomNode n = element.firstChild();
|
|
impl->createTextElements( n.toText().data().stripWhiteSpace(),
|
|
docnode );
|
|
|
|
n = n.nextSibling(); // <sep/>
|
|
TQDomElement index = doc.createElement( "INDEX" );
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
TQDomElement textelement = doc.createElement( "TEXT" );
|
|
textelement.setAttribute( "CHAR", "e" );
|
|
sequence.appendChild( textelement );
|
|
content.appendChild( sequence );
|
|
index.appendChild( content );
|
|
|
|
TQDomElement upperright = doc.createElement( "UPPERRIGHT" );
|
|
sequence = doc.createElement( "SEQUENCE" );
|
|
textelement = doc.createElement( "TEXT" );
|
|
textelement.setAttribute( "CHAR", "i" );
|
|
sequence.appendChild( textelement );
|
|
|
|
n = n.nextSibling();
|
|
impl->createTextElements( n.toText().data().stripWhiteSpace(),
|
|
sequence );
|
|
|
|
upperright.appendChild( sequence );
|
|
index.appendChild( upperright );
|
|
|
|
docnode.appendChild( index );
|
|
}
|
|
}
|
|
|
|
else if ( tag == "ci" ) {
|
|
type = CONTENT;
|
|
TQDomNode n = element.firstChild();
|
|
|
|
if ( n.isText() ) {
|
|
impl->createTextElements( n.toText().data().stripWhiteSpace(),
|
|
docnode );
|
|
}
|
|
else if ( n.isElement() ) {
|
|
TQDomElement e = n.toElement();
|
|
processElement( e, doc, docnode );
|
|
}
|
|
else if ( n.isEntityReference() ) {
|
|
kdDebug( DEBUGID ) << "isEntityReference: "
|
|
<< n.toEntityReference().nodeName().latin1()
|
|
<< endl;
|
|
}
|
|
else
|
|
kdDebug( DEBUGID ) << "ci: " << n.nodeName().latin1() << endl;
|
|
}
|
|
|
|
else if ( tag == "list" ) {
|
|
type = CONTENT;
|
|
TQDomNode n = element.firstChild();
|
|
|
|
TQDomElement bracket = doc.createElement( "BRACKET" );
|
|
bracket.setAttribute( "LEFT", 91 ); // [
|
|
bracket.setAttribute( "RIGHT", 93 ); // ]
|
|
TQDomElement content = doc.createElement( "CONTENT" );
|
|
TQDomElement sequence = doc.createElement( "SEQUENCE" );
|
|
|
|
bool first = true;
|
|
|
|
while ( !n.isNull() ) {
|
|
if ( n.isElement() ) {
|
|
if ( !first ) {
|
|
TQDomElement textelement = doc.createElement( "TEXT" );
|
|
textelement.setAttribute( "CHAR", "," );
|
|
sequence.appendChild( textelement );
|
|
}
|
|
first = false;
|
|
TQDomElement e = n.toElement();
|
|
processElement( e, doc, sequence );
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
content.appendChild( sequence );
|
|
bracket.appendChild( content );
|
|
docnode.appendChild( bracket );
|
|
}
|
|
}
|
|
|
|
if ( type == UNKNOWN && node.nodeType() != TQDomNode::AttributeNode ) {
|
|
kdDebug() << "Not an element: " << node.nodeName() << endl;
|
|
TQDomNode n = node.firstChild();
|
|
while ( !n.isNull() ) {
|
|
processElement( n, doc, docnode );
|
|
n = n.nextSibling();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
KFORMULA_NAMESPACE_END
|
|
|
|
using namespace KFormula;
|
|
#include "kformulamathmlread.moc"
|