lib

kformulamathmlread.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
3 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <iostream>
22#include <tqstring.h>
23#include <tqfontmetrics.h>
24
25#include <tdelocale.h>
26#include <tdemessagebox.h>
27
28//#include <KoUnit.h>
29
30#include "kformulamathmlread.h"
31#include "symboltable.h"
32
33KFORMULA_NAMESPACE_BEGIN
34using namespace std;
35
36class MathML2KFormulaPrivate
37{
38 friend class MathML2KFormula;
39
40public:
41 MathML2KFormulaPrivate( MathML2KFormula* mml_filter,
42 const ContextStyle& contextStyle,
43 const TQDomDocument& formuladoc );
44 ~MathML2KFormulaPrivate();
45
46 void math( TQDomElement element );
47
48 // Token Elements
49 void mi( TQDomElement element, TQDomNode docnode );
50 void mn( TQDomElement element, TQDomNode docnode );
51 void mo( TQDomElement element, TQDomNode docnode );
52 void mtext( TQDomElement element, TQDomNode docnode );
53 void mspace( TQDomElement element, TQDomNode docnode );
54 void ms( TQDomElement element, TQDomNode docnode );
55 // mglyph not supported
56
57 // General Layout Schemata
58 void mrow( TQDomElement element, TQDomNode docnode );
59 void mfrac( TQDomElement element, TQDomNode docnode );
60 void msqrt( TQDomElement element, TQDomNode docnode );
61 void mroot( TQDomElement element, TQDomNode docnode );
62 void mstyle( TQDomElement element, TQDomNode docnode );
63 // merror not supported
64 // mpadded not supported
65 // mphantom not supported
66 void mfenced( TQDomElement element, TQDomNode docnode );
67 // menclose not supported
68
69 // Script and Limit Schemata
70 void msub_msup( TQDomElement element, TQDomNode docnode );
71 void msubsup( TQDomElement element, TQDomNode docnode );
72 void munder( TQDomElement element, TQDomNode docnode, bool oasisFormat );
73 void mover( TQDomElement element, TQDomNode docnode, bool oasisFormat );
74 void munderover( TQDomElement element, TQDomNode docnode, bool oasisFormat );
75 // mmultiscripts not supported
76
77 // Tables and Matrices
78 void mtable( TQDomElement element, TQDomNode docnode );
79 // not much supported
80
81 // Enlivening Expressions
82 // maction not supported
83
84protected:
85 void createTextElements( TQString text, TQDomNode docnode );
86 void createNameSequence( TQString text, TQDomNode docnode );
87 double convertToPoint( TQString value, bool* ok );
88 bool isEmbellishedOperator( TQDomNode node, TQDomElement* mo, bool oasisFormat );
89 bool isSpaceLike( TQDomNode node, bool oasisFormat );
90
91 enum MathVariant {
92 normal,
93 bold,
94 italic,
95 bold_italic,
96 double_struck,
97 bold_fraktur,
98 script,
99 bold_script,
100 fraktur,
101 sans_serif,
102 bold_sans_serif,
103 sans_serif_italic,
104 sans_serif_bold_italic,
105 monospace
106 };
107
108 struct MathStyle {
109 MathStyle()
110 : scriptsizemultiplier( 0.71 ),
111 scriptminsize( 8 ),
112 veryverythinmathspace( 1.0/18.0 ),
113 verythinmathspace( 2.0/18.0 ),
114 thinmathspace( 3.0/18.0 ),
115 mediummathspace( 4.0/18.0 ),
116 thickmathspace( 5.0/18.0 ),
117 verythickmathspace( 6.0/18.0 ),
118 veryverythickmathspace( 7.0/18.0 ),
119
120 useVariant( false )
121 {
122 }
123
124 void styleChange()
125 {
126 kdDebug( DEBUGID ) << "Style Change:"
127 << "\n scriptlevel = " << scriptlevel
128 << "\n displaystyle = " << displaystyle
129 << "\n scriptsizemultiplier = "
130 << scriptsizemultiplier
131 << "\n scriptminsize = " << scriptminsize
132 << endl;
133 }
134
135 void setStyles( TQDomElement element )
136 {
137 if ( !useVariant )
138 return;
139
140 switch ( mathvariant )
141 {
142 case normal:
143 element.setAttribute( "STYLE", "normal" );
144 break;
145 case bold:
146 element.setAttribute( "STYLE", "bold" );
147 break;
148
149 case bold_italic:
150 element.setAttribute( "STYLE", "bolditalic" );
151 break;
152 case italic:
153 element.setAttribute( "STYLE", "italic" );
154 break;
155
156 case double_struck:
157 element.setAttribute( "FAMILY", "doublestruck" );
158 break;
159
160 case bold_fraktur:
161 element.setAttribute( "STYLE", "bold" );
162 case fraktur:
163 element.setAttribute( "FAMILY", "fraktur" );
164 break;
165
166 case bold_script:
167 element.setAttribute( "STYLE", "bold" );
168 case script:
169 element.setAttribute( "FAMILY", "script" );
170 break;
171
172 case bold_sans_serif:
173 element.setAttribute( "STYLE", "bold" );
174 case sans_serif:
175 element.setAttribute( "FAMILY", "normal" );
176 break;
177 case sans_serif_bold_italic:
178 element.setAttribute( "STYLE", "bolditalic" );
179 element.setAttribute( "FAMILY", "normal" );
180 break;
181 case sans_serif_italic:
182 element.setAttribute( "STYLE", "italic" );
183 element.setAttribute( "FAMILY", "normal" );
184 break;
185
186 //case monospace:
187 default:
188 break;
189 }
190 }
191
192 void readStyles( TQDomElement mmlElement )
193 {
194 if ( mmlElement.hasAttribute( "mathvariant" ) )
195 {
196 useVariant = true;
197
198 if ( mmlElement.attribute( "mathvariant" ) == "normal" )
199 mathvariant = normal;
200 else if ( mmlElement.attribute( "mathvariant" ) == "bold" )
201 mathvariant = bold;
202 else if ( mmlElement.attribute( "mathvariant" ) == "italic" )
203 mathvariant = italic;
204 else if ( mmlElement.attribute( "mathvariant" ) == "bold-italic" )
205 mathvariant = bold_italic;
206 else if ( mmlElement.attribute( "mathvariant" ) == "double-struck" )
207 mathvariant = double_struck;
208 else if ( mmlElement.attribute( "mathvariant" ) == "bold-fraktur" )
209 mathvariant = bold_fraktur;
210 else if ( mmlElement.attribute( "mathvariant" ) == "script" )
211 mathvariant = script;
212 else if ( mmlElement.attribute( "mathvariant" ) == "bold-script" )
213 mathvariant = bold_script;
214 else if ( mmlElement.attribute( "mathvariant" ) == "fraktur" )
215 mathvariant = fraktur;
216 else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif" )
217 mathvariant = sans_serif;
218 else if ( mmlElement.attribute( "mathvariant" ) == "bold-sans-serif" )
219 mathvariant = bold_sans_serif;
220 else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif-italic" )
221 mathvariant = sans_serif_italic;
222 else if ( mmlElement.attribute( "mathvariant" ) == "sans-serif-bold-italic" )
223 mathvariant = sans_serif_bold_italic;
224 else if ( mmlElement.attribute( "mathvariant" ) == "monospace" )
225 mathvariant = monospace;
226 }
227 }
228
229 // Styles, set by <mstyle> // default
230
231 int scriptlevel; // inherited
232 bool displaystyle; // inherited
233 double scriptsizemultiplier; // 0.71
234 double scriptminsize; // 8pt
235 // color
236 // background
237 double veryverythinmathspace; // 1/18em = 0.0555556em
238 double verythinmathspace; // 2/18em = 0.111111em
239 double thinmathspace; // 3/18em = 0.166667em
240 double mediummathspace; // 4/18em = 0.222222em
241 double thickmathspace; // 5/18em = 0.277778em
242 double verythickmathspace; // 6/18em = 0.333333em
243 double veryverythickmathspace; // 7/18em = 0.388889em
244
245 // 'Local' styles
246
247 MathVariant mathvariant;
248 bool useVariant;
249 //int mathsize;
250 };
251
252 MathStyle style;
253 TQDomDocument doc;
254
255private:
256 const ContextStyle& context;
257 MathML2KFormula* filter;
258};
259
260MathML2KFormulaPrivate::MathML2KFormulaPrivate( MathML2KFormula* mml_filter, const ContextStyle& cs, const TQDomDocument& formuladoc )
261 : doc( formuladoc ), context( cs ), filter( mml_filter )
262{
263}
264
265MathML2KFormulaPrivate::~MathML2KFormulaPrivate()
266{
267}
268
269void MathML2KFormulaPrivate::math( TQDomElement element )
270{
271 TQDomElement formula = doc.createElement( "FORMULA" );
272 TQDomNode n = element.firstChild();
273
274 TQString display = element.attribute( "display" );
275
276 if ( display == "block" ) {
277 style.displaystyle = true;
278 }
279 else {
280 // if display == "inline" (default) or illegal (then use default)
281 style.displaystyle = false;
282 }
283
284 style.scriptlevel = 0;
285
286 /*kdDebug( DEBUGID ) << "<math> element:\n displaystyle = "
287 << style.displaystyle << "\n scriptlevel = "
288 << style.scriptlevel << endl;*/
289
290 while ( !n.isNull() ) {
291 filter->processElement( n, doc, formula );
292 n = n.nextSibling();
293 }
294
295 doc.appendChild( formula );
296}
297
298void MathML2KFormulaPrivate::mi( TQDomElement element, TQDomNode docnode )
299{
300 MathStyle previousStyle( style );
301 TQString text = element.text().stripWhiteSpace();
302 if ( text.length() == 1 ) { // Default italic, only when content is one char
303 style.mathvariant = italic;
304 style.useVariant = true;
305 style.readStyles( element );
306 createTextElements( text, docnode );
307 } else { // If length is 0 or >1, it should be a text sequence
308 style.readStyles( element );
309 createNameSequence( text, docnode );
310 }
311 style = previousStyle;
312}
313
314void MathML2KFormulaPrivate::mo( TQDomElement element, TQDomNode docnode )
315{
316 MathStyle previousStyle( style );
317 style.readStyles( element );
318
319 TQString text = element.text().stripWhiteSpace();
320 createTextElements( text, docnode );
321
322 style = previousStyle;
323}
324
325void MathML2KFormulaPrivate::mn( TQDomElement element, TQDomNode docnode )
326{
327 MathStyle previousStyle( style );
328 style.readStyles( element );
329
330 TQString text = element.text().stripWhiteSpace();
331 createTextElements( text, docnode );
332
333 style = previousStyle;
334}
335
336void MathML2KFormulaPrivate::mtext( TQDomElement element, TQDomNode docnode )
337{
338 MathStyle previousStyle( style );
339 style.readStyles( element );
340
341 TQDomNode n = element.firstChild();
342
343 while ( !n.isNull() ) {
344 if ( n.isText() ) {
345 TQString text = n.toText().data().stripWhiteSpace();
346 createTextElements( text, docnode );
347 }
348 else if ( n.isElement() ) {
349 filter->processElement( n, doc, docnode );
350 }
351 else {
352 kdDebug( DEBUGID ) << "<mtext> child: " << n.nodeName() << endl;
353 }
354
355 n = n.nextSibling();
356 }
357
358 style = previousStyle;
359}
360
361void MathML2KFormulaPrivate::ms( TQDomElement element, TQDomNode docnode )
362{
363 TQString lquote = element.attribute( "lquote", "\"" );
364 TQString rquote = element.attribute( "rquote", "\"" );
365 TQString text;
366
367 text = lquote;
368 text += element.text().stripWhiteSpace();
369 text += rquote;
370
371 createTextElements( text, docnode );
372}
373
374void MathML2KFormulaPrivate::mspace( TQDomElement element, TQDomNode docnode )
375{
376 // we support only horizontal space
377 TQString width = element.attribute( "width" );
378
379 TQDomElement spaceelement = doc.createElement( "SPACE" );
380
381 // check for namedspace. We don't support much...
382 if ( width == "veryverythinmathspace" ) {
383 spaceelement.setAttribute( "WIDTH", "thin" );
384 }
385 else if ( width == "verythinmathspace" ) {
386 spaceelement.setAttribute( "WIDTH", "thin" );
387 }
388 else if ( width == "thinmathspace" ) {
389 spaceelement.setAttribute( "WIDTH", "thin" );
390 }
391 else if ( width == "mediummathspace" ) {
392 spaceelement.setAttribute( "WIDTH", "medium" );
393 }
394 else if ( width == "thickmathspace" ) {
395 spaceelement.setAttribute( "WIDTH", "thick" );
396 }
397 else if ( width == "verythickmathspace" ) {
398 spaceelement.setAttribute( "WIDTH", "thick" );
399 }
400 else if ( width == "veryverythickmathspace" ) {
401 spaceelement.setAttribute( "WIDTH", "quad" );
402 }
403
404 else {
405 // units
406
407 double w = 0;
408 bool ok;
409
410 if ( width.endsWith( "em" ) ) {
411 // See MathML specification, Appendix H
412 w = context.getDefaultFont().pointSize();
413 if ( w == -1 ) {
414 TQFontMetrics fm( context.getDefaultFont() );
415 w = fm.width( 'm' );
416 }
417 w = w * width.remove( width.length() - 2, 2 ).toDouble( &ok );
418 // w in points?
419 }
420 else if ( width.endsWith( "px" ) ) {
421 w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
422 // w in pixels
423 }
424 else if ( width.endsWith( "in" ) ) {
425 w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
426 w *= 72; // w in points
427 }
428 else if ( width.endsWith( "cm" ) ) {
429 w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
430 w *= 1/2.54 * 72; // w in points
431 }
432 else if ( width.endsWith( "mm" ) ) {
433 w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
434 w *= 1/25.4 * 72; // w in points
435 }
436 else if ( width.endsWith( "pt" ) ) {
437 w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
438 // w in points
439 }
440 else if ( width.endsWith( "pc" ) ) {
441 w = width.remove( width.length() - 2, 2 ).toDouble( &ok );
442 w /= 12; // w in points
443 }
444 else {
445 w = width.toDouble( &ok );
446 }
447
448 if ( !ok )
449 return;
450
451 if ( w < 20 )
452 spaceelement.setAttribute( "WIDTH", "thin" );
453 else if ( w < 40 )
454 spaceelement.setAttribute( "WIDTH", "medium" );
455 else if ( w < 80 )
456 spaceelement.setAttribute( "WIDTH", "thick" );
457 else
458 spaceelement.setAttribute( "WIDTH", "quad" );
459 }
460
461 docnode.appendChild( spaceelement );
462}
463
464void MathML2KFormulaPrivate::mrow( TQDomElement element, TQDomNode docnode )
465{
466 TQDomNode n = element.firstChild();
467 while ( !n.isNull() ) {
468 if ( n.isElement () ) {
469 TQDomElement e = n.toElement();
470 // We do not allow sequence inside sequence
471 filter->processElement( e, doc, docnode );
472 }
473 else {
474 kdDebug( DEBUGID ) << "<mrow> child: " << n.nodeName() << endl;
475 }
476 n = n.nextSibling();
477 }
478}
479
480void MathML2KFormulaPrivate::mfrac( TQDomElement element, TQDomNode docnode )
481{
482 TQDomNode n = element.firstChild();
483 TQDomElement fraction = doc.createElement( "FRACTION" );
484
485 MathStyle previousStyle( style );
486 style.displaystyle ? style.displaystyle = false : style.scriptlevel += 1;
487 style.styleChange();
488
489 int i = 0;
490 while ( !n.isNull() && i < 2 ) {
491 if ( n.isElement() ) {
492 ++i;
493 if ( i == 1 ) { //first is numerator
494 TQDomElement numerator =
495 doc.createElement( "NUMERATOR" );
496 TQDomElement sequence = doc.createElement( "SEQUENCE" );
497 numerator.appendChild( sequence );
498 TQDomElement e = n.toElement();
499 filter->processElement( e, doc, sequence );
500 fraction.appendChild( numerator );
501
502 }
503 else {
504 TQDomElement denominator =
505 doc.createElement( "DENOMINATOR" );
506 TQDomElement sequence = doc.createElement( "SEQUENCE" );
507 denominator.appendChild( sequence );
508 TQDomElement e = n.toElement();
509 filter->processElement( e, doc, sequence );
510 fraction.appendChild( denominator );
511
512 }
513 }
514 else {
515 kdDebug( DEBUGID ) << "<mfrac> child: " << n.nodeName() << endl;
516 }
517 n = n.nextSibling();
518 }
519
520 style = previousStyle;
521 docnode.appendChild( fraction );
522}
523
524void MathML2KFormulaPrivate::mroot( TQDomElement element, TQDomNode docnode )
525{
526 TQDomNode n = element.firstChild();
527 int i = 0;
528 TQDomElement root = doc.createElement( "ROOT" );
529
530 while ( !n.isNull() && i < 2 ) {
531 if ( n.isElement() ) {
532 ++i;
533 if ( i == 1 ) { //first is content (base)
534 TQDomElement content = doc.createElement( "CONTENT" );
535 TQDomElement sequence = doc.createElement( "SEQUENCE" );
536 content.appendChild( sequence );
537 TQDomElement e = n.toElement();
538 filter->processElement( e, doc, sequence );
539
540 root.appendChild(content);
541 }
542 else { // index
543 MathStyle previousStyle( style );
544 style.scriptlevel += 2;
545 style.displaystyle = false;
546 style.styleChange();
547
548 TQDomElement index = doc.createElement( "INDEX" );
549 TQDomElement sequence = doc.createElement( "SEQUENCE" );
550 index.appendChild( sequence );
551 TQDomElement e = n.toElement();
552 filter->processElement( e, doc, sequence );
553 root.appendChild( index );
554
555 style = previousStyle;
556 }
557 }
558 else {
559 kdDebug( DEBUGID ) << "<mroot> child: " << n.nodeName() << endl;
560 }
561 n = n.nextSibling();
562 }
563 docnode.appendChild( root );
564}
565
566void MathML2KFormulaPrivate::msqrt( TQDomElement element, TQDomNode docnode )
567{
568 TQDomNode n = element.firstChild();
569 TQDomElement root = doc.createElement( "ROOT" );
570
571 TQDomElement content = doc.createElement( "CONTENT" );
572 TQDomElement sequence = doc.createElement( "SEQUENCE" );
573 content.appendChild( sequence );
574 root.appendChild( content );
575
576 while ( !n.isNull() ) {
577 if ( n.isElement() ) {
578 filter->processElement( n.toElement(), doc, sequence );
579 }
580 else {
581 kdDebug( DEBUGID ) << "<msqrt> child: " << n.nodeName() << endl;
582 }
583 n = n.nextSibling();
584 }
585
586 docnode.appendChild( root );
587}
588
589void MathML2KFormulaPrivate::mstyle( TQDomElement element, TQDomNode docnode )
590{
591 bool ok;
592
593 MathStyle previousStyle( style );
594 style.readStyles( element );
595
596 if ( element.hasAttribute( "scriptlevel" ) ) {
597 TQString scriptlevel = element.attribute( "scriptlevel" );
598 if ( scriptlevel.startsWith( "+" ) || scriptlevel.startsWith( "-" ) )
599 style.scriptlevel += scriptlevel.toInt( &ok );
600 else
601 style.scriptlevel = scriptlevel.toInt( &ok );
602 if ( !ok )
603 style.scriptlevel = previousStyle.scriptlevel;
604 }
605 if ( element.hasAttribute( "displaystyle" ) ) {
606 TQString displaystyle = element.attribute( "displaystyle" );
607 if ( displaystyle == "true" )
608 style.displaystyle = true;
609 else if ( displaystyle == "false" )
610 style.displaystyle = false;
611 }
612 if ( element.hasAttribute( "scriptsizemultiplier" ) ) {
613 style.scriptsizemultiplier =
614 element.attribute( "scriptsizemultiplier" ).toDouble( &ok );
615 if ( !ok )
616 style.scriptsizemultiplier = previousStyle.scriptsizemultiplier;
617 }
618 if ( element.hasAttribute( "scriptminsize" ) ) {
619 TQString scriptminsize = element.attribute( "scriptminsize" );
620 style.scriptminsize = convertToPoint( scriptminsize, &ok );
621 if ( !ok )
622 style.scriptminsize = previousStyle.scriptminsize;
623 }
624
625 if ( element.hasAttribute( "veryverythinmathspace" ) ) {
626 TQString vvthinmspace = element.attribute( "veryverythinmathspace" );
627 style.veryverythinmathspace = convertToPoint( vvthinmspace, &ok );
628 if ( !ok )
629 style.veryverythinmathspace = previousStyle.veryverythinmathspace;
630 }
631 if ( element.hasAttribute( "verythinmathspace" ) ) {
632 TQString vthinmspace = element.attribute( "verythinmathspace" );
633 style.verythinmathspace = convertToPoint( vthinmspace, &ok );
634 if ( !ok )
635 style.verythinmathspace = previousStyle.verythinmathspace;
636 }
637 if ( element.hasAttribute( "thinmathspace" ) ) {
638 TQString thinmathspace = element.attribute( "thinmathspace" );
639 style.thinmathspace = convertToPoint( thinmathspace, &ok );
640 if ( !ok )
641 style.thinmathspace = previousStyle.thinmathspace;
642 }
643 if ( element.hasAttribute( "mediummathspace" ) ) {
644 TQString mediummathspace = element.attribute( "mediummathspace" );
645 style.mediummathspace = convertToPoint( mediummathspace, &ok );
646 if ( !ok )
647 style.mediummathspace = previousStyle.mediummathspace;
648 }
649 if ( element.hasAttribute( "thickmathspace" ) ) {
650 TQString thickmathspace = element.attribute( "thickmathspace" );
651 style.thickmathspace = convertToPoint( thickmathspace, &ok );
652 if ( !ok )
653 style.thickmathspace = previousStyle.thickmathspace;
654 }
655 if ( element.hasAttribute( "verythickmathspace" ) ) {
656 TQString vthickmspace = element.attribute( "verythickmathspace" );
657 style.verythickmathspace = convertToPoint( vthickmspace, &ok );
658 if ( !ok )
659 style.verythickmathspace = previousStyle.verythickmathspace;
660 }
661 if ( element.hasAttribute( "veryverythickmathspace" ) ) {
662 TQString vvthickmspace = element.attribute( "veryverythickmathspace" );
663 style.veryverythickmathspace = convertToPoint( vvthickmspace, &ok );
664 if ( !ok )
665 style.veryverythickmathspace =
666 previousStyle.veryverythickmathspace;
667 }
668
669 style.styleChange();
670
671 TQDomNode n = element.firstChild();
672 while ( !n.isNull() ) {
673 filter->processElement( n, doc, docnode );
674 n = n.nextSibling();
675 }
676
677 style = previousStyle;
678}
679
680void MathML2KFormulaPrivate::mfenced( TQDomElement element, TQDomNode docnode )
681{
682 TQDomElement bracket = doc.createElement( "BRACKET" );
683 TQString value = element.attribute( "open", "(" );
684 bracket.setAttribute( "LEFT", TQString::number( value.at( 0 ).latin1() ) );
685 value = element.attribute( "close", ")" );
686 bracket.setAttribute( "RIGHT", TQString::number( value.at( 0 ).latin1() ) );
687
688 TQDomElement content = doc.createElement( "CONTENT" );
689 TQDomElement sequence = doc.createElement( "SEQUENCE" );
690 content.appendChild( sequence );
691
692 TQString separators = element.attribute( "separators", "," );
693
694 TQDomNode n = element.firstChild();
695 uint i = 0;
696 while ( !n.isNull() ) {
697 if ( n.isElement() ) {
698 if ( i != 0 && !separators.isEmpty() ) {
699 TQDomElement textelement = doc.createElement( "TEXT" );
700 if ( i > separators.length() )
701 i = separators.length();
702 textelement.setAttribute( "CHAR", TQString( separators.at( i - 1 ) ) );
703 //style.setStyles( textelement );
704 sequence.appendChild( textelement );
705 }
706 ++i;
707 TQDomElement e = n.toElement();
708 filter->processElement( e, doc, sequence );
709 }
710 else {
711 kdDebug( DEBUGID ) << "<mfenced> child: " << n.nodeName() << endl;
712 }
713 n = n.nextSibling();
714 }
715 bracket.appendChild( content );
716 docnode.appendChild( bracket );
717}
718
719void MathML2KFormulaPrivate::mtable( TQDomElement element, TQDomNode docnode )
720{
721 MathStyle previousStyle( style );
722 TQString displaystyle = element.attribute( "displaystyle", "false" );
723 if ( displaystyle == "true" ) {
724 style.displaystyle = true;
725 }
726 else {
727 // false is default and also used for illegal values
728 style.displaystyle = false;
729 }
730 style.styleChange();
731
732 TQString subtag;
733 int rows = 0; int cols = 0;
734 TQDomNode n = element.firstChild();
735
736 while ( !n.isNull() ) {
737 if ( n.isElement() ) {
738 TQDomElement e = n.toElement();
739 subtag = e.tagName();
740 if (subtag == "mtr")
741 {
742 ++rows;
743
744 /* Determins the number of columns */
745
746 TQDomNode cellnode = e.firstChild();
747 int cc = 0;
748
749 while ( !cellnode.isNull() ) {
750 if ( cellnode.isElement() )
751 cc++;
752 cellnode = cellnode.nextSibling();
753 }
754
755 if ( cc > cols )
756 cols = cc;
757
758 }
759 }
760 else {
761 kdDebug( DEBUGID ) << "<mtable> child: " << n.nodeName() << endl;
762 }
763 n = n.nextSibling();
764 }
765
766 /* Again createing elements, I need to know the number
767 of rows and cols to leave empty spaces */
768
769 n = element.firstChild();
770 TQDomElement matrix = doc.createElement( "MATRIX" );
771 matrix.setAttribute( "COLUMNS", cols );
772 matrix.setAttribute( "ROWS", rows );
773
774 while ( !n.isNull() ) {
775 if ( n.isElement() ) {
776 TQDomElement e = n.toElement();
777 subtag = e.tagName();
778 if ( subtag == "mtr" ) {
779 TQDomNode cellnode = e.firstChild();
780 int cc = 0;
781 while ( !cellnode.isNull() ) {
782 if ( cellnode.isElement() ) {
783 ++cc;
784 TQDomElement cell = doc.createElement( "SEQUENCE" );
785 TQDomElement cellelement = cellnode.toElement();
786 filter->processElement( cellelement, doc, cell );
787 matrix.appendChild( cell );
788 }
789 cellnode = cellnode.nextSibling();
790 }
791
792 /* Add empty elements */
793 for(; cc < cols; cc++ ) {
794 TQDomElement cell = doc.createElement( "SEQUENCE" );
795 matrix.appendChild( cell );
796 }
797 }
798 }
799 n = n.nextSibling();
800 }
801
802 style = previousStyle;
803 docnode.appendChild(matrix);
804}
805
806void MathML2KFormulaPrivate::msub_msup( TQDomElement element, TQDomNode docnode )
807{
808 TQDomNode n = element.firstChild();
809 int i = 0;
810 TQDomElement root = doc.createElement( "INDEX" );
811
812 while ( !n.isNull() && i < 2 ) {
813 if ( n.isElement() ) {
814 ++i;
815 if ( i == 1 ) { // first is content (base)
816 TQDomElement content = doc.createElement( "CONTENT" );
817 TQDomElement sequence = doc.createElement( "SEQUENCE" );
818 content.appendChild( sequence );
819 TQDomElement e = n.toElement();
820 filter->processElement( e, doc, sequence );
821
822 root.appendChild( content );
823 }
824 else {
825 TQDomElement index;
826 if ( element.tagName() == "msup" )
827 index = doc.createElement( "UPPERRIGHT" );
828 else
829 index = doc.createElement( "LOWERRIGHT" );
830
831 MathStyle previousStyle( style );
832 style.scriptlevel += 1;
833 style.displaystyle = false;
834 style.styleChange();
835
836 TQDomElement sequence = doc.createElement( "SEQUENCE" );
837 index.appendChild( sequence );
838 TQDomElement e = n.toElement();
839 filter->processElement( e, doc, sequence );
840 root.appendChild( index );
841
842 style = previousStyle;
843 }
844 }
845 else {
846 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
847 << n.nodeName() << endl;
848 }
849 n = n.nextSibling();
850 }
851 docnode.appendChild( root );
852}
853
854void MathML2KFormulaPrivate::munder( TQDomElement element, TQDomNode docnode, bool oasisFormat )
855{
856 bool accentunder;
857
858 TQString au = element.attribute( "accentunder" );
859 if ( au == "true" )
860 accentunder = true;
861 else if ( au == "false" )
862 accentunder = false;
863 else {
864 // use default
865
866 TQDomElement mo;
867 // is underscript an embellished operator?
868 if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo, oasisFormat ) ) {
869 if ( mo.attribute( "accent" ) == "true" )
870 accentunder = true;
871 else
872 accentunder = false;
873 }
874 else
875 accentunder = false;
876 }
877
878 TQDomNode n = element.firstChild();
879 int i = 0;
880 TQDomElement root = doc.createElement( "INDEX" );
881
882 while ( !n.isNull() && i < 2 ) {
883 if ( n.isElement() ) {
884 ++i;
885 if ( i == 1 ) { // first is content (base)
886 TQDomElement content = doc.createElement( "CONTENT" );
887 TQDomElement sequence = doc.createElement( "SEQUENCE" );
888 content.appendChild( sequence );
889 TQDomElement e = n.toElement();
890 filter->processElement( e, doc, sequence );
891
892 root.appendChild( content );
893 }
894 else { // underscript
895 MathStyle previousStyle( style );
896 style.displaystyle = false;
897 if ( !accentunder ) {
898 style.scriptlevel += 1;
899 style.styleChange();
900 }
901
902 TQDomElement mo; TQDomElement index;
903 if ( isEmbellishedOperator( n.previousSibling(), &mo, oasisFormat ) &&
904 !previousStyle.displaystyle &&
905 mo.attribute( "movablelimits" ) == "true" )
906 {
907 index = doc.createElement( "LOWERRIGHT" );
908 }
909 else {
910 index = doc.createElement( "LOWERMIDDLE" );
911 }
912
913 TQDomElement sequence = doc.createElement( "SEQUENCE" );
914 index.appendChild( sequence );
915 TQDomElement e = n.toElement();
916 filter->processElement( e, doc, sequence );
917 root.appendChild( index );
918
919 style = previousStyle;
920 }
921 }
922 else {
923 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
924 << n.nodeName() << endl;
925 }
926 n = n.nextSibling();
927 }
928
929 docnode.appendChild( root );
930}
931
932void MathML2KFormulaPrivate::mover( TQDomElement element, TQDomNode docnode, bool oasisFormat )
933{
934 bool accent;
935
936 TQString ac = element.attribute( "accent" );
937 if ( ac == "true" )
938 accent = true;
939 else if ( ac == "false" )
940 accent = false;
941 else {
942 // use default
943
944 TQDomElement mo;
945 // is overscript an embellished operator?
946 if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo, oasisFormat ) ) {
947 if ( mo.attribute( "accent" ) == "true" )
948 accent = true;
949 else
950 accent = false;
951 }
952 else
953 accent = false;
954 }
955
956 TQDomNode n = element.firstChild();
957 int i = 0;
958 TQDomElement root = doc.createElement( "INDEX" );
959
960 while ( !n.isNull() && i < 2 ) {
961 if ( n.isElement() ) {
962 ++i;
963 if ( i == 1 ) { // first is content (base)
964 TQDomElement content = doc.createElement( "CONTENT" );
965 TQDomElement sequence = doc.createElement( "SEQUENCE" );
966 content.appendChild( sequence );
967 TQDomElement e = n.toElement();
968 filter->processElement( e, doc, sequence );
969
970 root.appendChild( content );
971 }
972 else { // overscript
973 MathStyle previousStyle( style );
974 style.displaystyle = false;
975 if ( !accent ) {
976 style.scriptlevel += 1;
977 style.styleChange();
978 }
979
980 TQDomElement mo; TQDomElement index;
981 if ( isEmbellishedOperator( n.previousSibling(), &mo, oasisFormat ) &&
982 !previousStyle.displaystyle &&
983 mo.attribute( "movablelimits" ) == "true" )
984 {
985 index = doc.createElement( "UPPERRIGHT" );
986 }
987 else {
988 index = doc.createElement( "UPPERMIDDLE" );
989 }
990
991 TQDomElement sequence = doc.createElement( "SEQUENCE" );
992 index.appendChild( sequence );
993 TQDomElement e = n.toElement();
994 filter->processElement( e, doc, sequence );
995 root.appendChild( index );
996
997 style = previousStyle;
998 }
999 }
1000 else {
1001 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
1002 << n.nodeName() << endl;
1003 }
1004 n = n.nextSibling();
1005 }
1006
1007 docnode.appendChild( root );
1008}
1009
1010void MathML2KFormulaPrivate::munderover( TQDomElement element, TQDomNode docnode, bool oasisFormat )
1011{
1012 bool accent;
1013 bool accentunder;
1014
1015 TQString value = element.attribute( "accentunder" );
1016 if ( value == "true" )
1017 accentunder = true;
1018 else if ( value == "false" )
1019 accentunder = false;
1020 else {
1021 // use default
1022
1023 TQDomElement mo;
1024 // is underscript an embellished operator?
1025 if ( isEmbellishedOperator( element.childNodes().item( 1 ), &mo, oasisFormat ) ) {
1026 if ( mo.attribute( "accent" ) == "true" )
1027 accentunder = true;
1028 else
1029 accentunder = false;
1030 }
1031 else
1032 accentunder = false;
1033 }
1034 value = element.attribute( "accent" );
1035 if ( value == "true" )
1036 accent = true;
1037 else if ( value == "false" )
1038 accent = false;
1039 else {
1040 // use default
1041
1042 TQDomElement mo;
1043 // is overscript an embellished operator?
1044 if ( isEmbellishedOperator( element.childNodes().item( 2 ), &mo,oasisFormat ) ) {
1045 kdDebug( DEBUGID ) << "embellished operator" << endl;
1046 if ( mo.attribute( "accent" ) == "true" )
1047 accent = true;
1048 else
1049 accent = false;
1050 }
1051 else
1052 accent = false;
1053 }
1054 kdDebug( DEBUGID ) << "munderover:\n accentunder = " << accentunder
1055 << "\n accent = " << accent << endl;
1056
1057 TQDomNode n = element.firstChild();
1058 int i = 0;
1059 TQDomElement root = doc.createElement( "INDEX" );
1060
1061 while ( !n.isNull() && i < 3 ) {
1062 if ( n.isElement() ) {
1063 ++i;
1064 if ( i == 1 ) { // base
1065 TQDomElement content = doc.createElement( "CONTENT" );
1066 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1067 content.appendChild( sequence );
1068 TQDomElement e = n.toElement();
1069 filter->processElement( e, doc, sequence );
1070
1071 root.appendChild( content );
1072 }
1073 else if ( i == 2 ) { // underscript
1074 MathStyle previousStyle( style );
1075 style.displaystyle = false;
1076 if ( !accentunder ) {
1077 style.scriptlevel += 1;
1078 style.styleChange();
1079 }
1080
1081 TQDomElement mo; TQDomElement index;
1082 // is the base an embellished operator?
1083 if ( isEmbellishedOperator( element.firstChild(), &mo, oasisFormat ) &&
1084 !previousStyle.displaystyle &&
1085 mo.attribute( "movablelimits" ) == "true" )
1086 {
1087 index = doc.createElement( "LOWERRIGHT" );
1088 }
1089 else {
1090 index = doc.createElement( "LOWERMIDDLE" );
1091 }
1092
1093 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1094 index.appendChild( sequence );
1095 TQDomElement e = n.toElement();
1096 filter->processElement( e, doc, sequence );
1097 root.appendChild( index );
1098
1099 style = previousStyle;
1100 }
1101 else { // overscript
1102 MathStyle previousStyle( style );
1103 style.displaystyle = false;
1104 if ( !accent ) {
1105 style.scriptlevel += 1;
1106 style.styleChange();
1107 }
1108
1109 TQDomElement mo; TQDomElement index;
1110 if ( isEmbellishedOperator( element.firstChild(), &mo, oasisFormat ) &&
1111 !previousStyle.displaystyle &&
1112 mo.attribute( "movablelimits" ) == "true" )
1113 {
1114 index = doc.createElement( "UPPERRIGHT" );
1115 }
1116 else {
1117 index = doc.createElement( "UPPERMIDDLE" );
1118 }
1119
1120 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1121 index.appendChild( sequence );
1122 TQDomElement e = n.toElement();
1123 filter->processElement( e, doc, sequence );
1124 root.appendChild( index );
1125
1126 style = previousStyle;
1127 }
1128 }
1129 else {
1130 kdDebug( DEBUGID ) << "<" << element.tagName() << "> child: "
1131 << n.nodeName() << endl;
1132 }
1133 n = n.nextSibling();
1134 }
1135
1136 docnode.appendChild( root );
1137}
1138
1139void MathML2KFormulaPrivate::msubsup( TQDomElement element, TQDomNode docnode )
1140{
1141 TQDomNode n = element.firstChild();
1142 int i = 0;
1143 TQDomElement root = doc.createElement("INDEX");
1144 MathStyle previousStyle( style );
1145
1146 while ( !n.isNull() && i < 2 ) {
1147 if ( n.isElement() ) {
1148 ++i;
1149 if ( i == 1 ) { // base
1150 TQDomElement content = doc.createElement( "CONTENT" );
1151 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1152 content.appendChild( sequence );
1153 TQDomElement e = n.toElement();
1154 filter->processElement( e, doc, sequence );
1155
1156 root.appendChild( content );
1157 }
1158 else if ( i == 2 ) { // subscript
1159 style.scriptlevel += 1;
1160 style.displaystyle = false;
1161 style.styleChange();
1162
1163 TQDomElement index;
1164 index = doc.createElement( "LOWERRIGHT" );
1165
1166 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1167 index.appendChild( sequence );
1168 TQDomElement e = n.toElement();
1169 filter->processElement( e, doc, sequence );
1170 root.appendChild( index );
1171 }
1172 else { // superscript
1173 TQDomElement index;
1174 index = doc.createElement( "UPPERRIGHT" );
1175
1176 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1177 index.appendChild( sequence );
1178 TQDomElement e = n.toElement();
1179 filter->processElement( e, doc, sequence );
1180 root.appendChild( index );
1181
1182 style = previousStyle;
1183
1184 }
1185 }
1186 else {
1187 kdDebug( DEBUGID ) << "<msubsup> child: " << n.nodeName() << endl;
1188 }
1189 n = n.nextSibling();
1190 }
1191 docnode.appendChild( root );
1192}
1193
1194void MathML2KFormulaPrivate::createTextElements( TQString text, TQDomNode docnode )
1195{
1196 for ( uint i = 0; i < text.length(); ++i ) {
1197 TQDomElement textelement = doc.createElement( "TEXT" );
1198 textelement.setAttribute( "CHAR", TQString( text.at( i ) ) );
1199 style.setStyles( textelement );
1200 if ( context.symbolTable().inTable( text.at( i ) ) ) {
1201 // The element is a symbol.
1202 textelement.setAttribute( "SYMBOL", "3" );
1203 }
1204 docnode.appendChild( textelement );
1205 }
1206}
1207
1208void MathML2KFormulaPrivate::createNameSequence( TQString text, TQDomNode docnode )
1209{
1210 TQDomElement namesequence = doc.createElement( "NAMESEQUENCE" );
1211 for ( uint i = 0; i < text.length(); ++i ) {
1212 TQDomElement textelement = doc.createElement( "TEXT" );
1213 textelement.setAttribute( "CHAR", TQString( text.at( i ) ) );
1214 style.setStyles( textelement );
1215 if ( context.symbolTable().inTable( text.at( i ) ) ) {
1216 // The element is a symbol.
1217 textelement.setAttribute( "SYMBOL", "3" );
1218 }
1219 namesequence.appendChild( textelement );
1220 }
1221 docnode.appendChild( namesequence );
1222}
1223
1224double MathML2KFormulaPrivate::convertToPoint( TQString value, bool* ok )
1225{
1226 double pt = 0;
1227
1228 if ( value.endsWith( "em" ) ) {
1229 // See MathML specification, Appendix H
1230 pt = context.getDefaultFont().pointSize();
1231 if ( pt == -1 ) {
1232 TQFontMetrics fm( context.getDefaultFont() );
1233 pt = fm.width( 'M' );
1234 // PIXELS!
1235 }
1236 pt = pt * value.remove( value.length() - 2, 2 ).toDouble( ok );
1237 }
1238 else if ( value.endsWith( "ex" ) ) {
1239 TQFontMetrics fm( context.getDefaultFont() );
1240 pt = fm.height();
1241 // PIXELS, and totally wrong!
1242 }
1243 else if ( value.endsWith( "px" ) ) {
1244 pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
1245 // PIXELS!
1246 }
1247 else if ( value.endsWith( "in" ) ) {
1248 pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
1249 pt *= 72;
1250 }
1251 else if ( value.endsWith( "cm" ) ) {
1252 pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
1253 pt *= 1/2.54 * 72;
1254 }
1255 else if ( value.endsWith( "mm" ) ) {
1256 pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
1257 pt *= 1/25.4 * 72;
1258 }
1259 else if ( value.endsWith( "pt" ) ) {
1260 pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
1261 }
1262 else if ( value.endsWith( "pc" ) ) {
1263 pt = value.remove( value.length() - 2, 2 ).toDouble( ok );
1264 pt /= 12;
1265 }
1266 else {
1267 pt = value.toDouble( ok );
1268 }
1269
1270 return pt;
1271}
1272
1273bool MathML2KFormulaPrivate::isEmbellishedOperator( TQDomNode node,
1274 TQDomElement* mo, bool oasisFormat )
1275{
1276 // See MathML 2.0 specification: 3.2.5.7
1277
1278 if ( !node.isElement() )
1279 return false;
1280
1281 TQDomElement element = node.toElement();
1282 TQString tag = element.tagName();
1283
1284 if ( tag == "mo" )
1285 {
1286 *mo = element;
1287 return true;
1288 }
1289 if ( tag == "msub" || tag == "msup" || tag == "msubsup" ||
1290 tag == "munder" || tag == "mover" || tag == "munderover" ||
1291 tag == "mmultiscripts" || tag == "mfrac" || tag == "semantics" )
1292 {
1293 return isEmbellishedOperator( element.firstChild(), mo,oasisFormat );
1294 }
1295 if ( tag == "maction" )
1296 {
1297 return false; // not supported
1298 }
1299 if ( tag == "mrow" || tag == "mstyle" || tag == "mphantom" || tag == "mpadded" ) {
1300 TQDomNode n = element.firstChild();
1301 int i = 0;
1302
1303 while ( !n.isNull() ) {
1304 if ( isEmbellishedOperator( n, mo,oasisFormat ) ) {
1305 if ( ++i > 1 ) // one (only one) embellished operator
1306 return false;
1307 }
1308 else if ( !isSpaceLike( n, oasisFormat ) ) { // zero or more space-like elements
1309 return false;
1310 }
1311 n = n.nextSibling();
1312 }
1313 return ( i == 1 );
1314 }
1315 return false;
1316}
1317
1318bool MathML2KFormulaPrivate::isSpaceLike( TQDomNode node, bool oasisFormat )
1319{
1320 // See MathML 2.0 specification: 3.2.7.3
1321
1322 if ( !node.isElement() )
1323 return false;
1324
1325 TQDomElement element = node.toElement();
1326 TQString tag = element.tagName();
1327
1328 if ( tag == "mtext" || tag == "mspace" ||
1329 tag == "maligngroup" || tag == "malignmark" ) {
1330 return true;
1331 }
1332 if ( tag == "mstyle" || tag == "mphantom" || tag == "mpadded" || tag == "mrow" ) {
1333 TQDomNode n = element.firstChild();
1334 while ( !n.isNull() ) {
1335 if ( isSpaceLike( n,oasisFormat ) )
1336 n = n.nextSibling();
1337 else
1338 return false;
1339 }
1340 return true;
1341 }
1342 if ( tag == "maction" ) {
1343 return false; // not supported
1344 }
1345
1346 return false;
1347}
1348
1349
1350MathML2KFormula::MathML2KFormula( const TQDomDocument& mmldoc, const ContextStyle &contextStyle, bool _oasisFormat )
1351 : m_error( false ), oasisFormat( _oasisFormat ), context( contextStyle )
1352{
1353 orig_element = mmldoc.documentElement();
1354 done = false;
1355}
1356
1357MathML2KFormula::MathML2KFormula( const TQDomElement& mmlelm, const ContextStyle &contextStyle, bool _oasisFormat )
1358 : m_error( false ), orig_element( mmlelm ), oasisFormat( _oasisFormat ), context( contextStyle )
1359{
1360 done = false;
1361}
1362
1363TQDomDocument MathML2KFormula::getKFormulaDom()
1364{
1365 return formuladoc;
1366}
1367
1368
1369
1370void MathML2KFormula::startConversion()
1371{
1372 //TODO:let it be async
1373 //kdDebug() << origdoc.toString() << endl;
1374 done = false;
1375 formuladoc = TQDomDocument( "KFORMULA" );
1376 impl = new MathML2KFormulaPrivate( this, context, formuladoc );
1377 if ( orig_element.tagName() == "math" ) {
1378 impl->math( orig_element );
1379 m_error = false;
1380 }
1381 else {
1382 kdError() << "Not a MathML document!" << endl;
1383 KMessageBox::error( 0, i18n( "The document does not seem to be MathML." ), i18n( "MathML Import Error" ) );
1384 m_error = true;
1385 }
1386 done = true;
1387}
1388
1389bool MathML2KFormula::processElement( TQDomNode node, TQDomDocument& doc, TQDomNode docnode )
1390{
1391
1392 //TQDomElement *element;
1393 Type type = UNKNOWN;
1394
1395 if ( node.isElement() ) {
1396 TQDomElement element = node.toElement();
1397 TQString tag = element.tagName();
1398
1399 if ( tag == "mi" ) {
1400 type = TOKEN;
1401 impl->mi( element, docnode );
1402 }
1403 else if ( tag == "mo" ) {
1404 type = TOKEN;
1405 impl->mo( element, docnode );
1406 }
1407 else if ( tag == "mn" ) {
1408 type = TOKEN;
1409 impl->mn( element, docnode );
1410 }
1411 else if ( tag == "mtext" ) {
1412 type = TOKEN;
1413 impl->mtext( element, docnode );
1414 }
1415 else if ( tag == "ms" ) {
1416 type = TOKEN;
1417 impl->ms( element, docnode );
1418 }
1419 else if ( tag == "mspace" ) {
1420 type = TOKEN;
1421 impl->mspace( element, docnode );
1422 }
1423 else if ( tag == "mrow" ) {
1424 type = LAYOUT;
1425 impl->mrow( element, docnode );
1426 }
1427 else if ( tag == "mfrac" ) {
1428 type = LAYOUT;
1429 impl->mfrac( element, docnode );
1430 }
1431 else if ( tag == "mroot" ) {
1432 type = LAYOUT;
1433 impl->mroot( element, docnode );
1434 }
1435 else if ( tag == "msqrt" ) {
1436 type = LAYOUT;
1437 impl->msqrt( element, docnode );
1438 }
1439 else if ( tag == "mstyle" ) {
1440 type = LAYOUT;
1441 impl->mstyle( element, docnode );
1442 }
1443 else if ( tag == "mfenced" ) {
1444 type = LAYOUT;
1445 impl->mfenced( element, docnode );
1446 }
1447 else if ( tag == "mtable" ) {
1448 type = TABLE;
1449 impl->mtable( element, docnode );
1450 }
1451 else if ( tag == "msub" || tag == "msup" ) {
1452 type = SCRIPT;
1453 impl->msub_msup( element, docnode );
1454 }
1455 else if ( tag == "munder" ) {
1456 type = SCRIPT;
1457 impl->munder( element, docnode,oasisFormat );
1458 }
1459 else if ( tag == "mover" ) {
1460 type = SCRIPT;
1461 impl->mover( element, docnode,oasisFormat );
1462 }
1463 else if ( tag == "munderover" ) {
1464 type = SCRIPT;
1465 impl->munderover( element, docnode, oasisFormat );
1466 }
1467 else if ( tag == "msubsup" ) {
1468 type = SCRIPT;
1469 impl->msubsup( element, docnode );
1470 }
1471
1472 // content markup (not yet complete)
1473 else if ( tag == "apply" ) {
1474 type = CONTENT;
1475 TQDomNode n = element.firstChild();
1476 TQDomElement op = n.toElement();
1477 uint count = element.childNodes().count();
1478 //adding explicit brackets to replace "apply"s implicit ones
1479 TQDomElement brackets = doc.createElement("BRACKET");
1480 brackets.setAttribute("RIGHT", "41");
1481 brackets.setAttribute("LEFT", "40");
1482 TQDomElement content = doc.createElement("CONTENT");
1483 brackets.appendChild(content);
1484 TQDomElement base = doc.createElement("SEQUENCE");
1485 content.appendChild(base);
1486 docnode.appendChild(brackets);
1487 //Arithmetic, Algebra and Logic operators status
1488 // quotient X
1489 // factorial O
1490 // divide O
1491 // max, min X
1492 // minus O
1493 // plus O
1494 // power O
1495 // rem X
1496 // times O
1497 // root X
1498 // gcd X
1499 // and O
1500 // or O
1501 // xor O
1502 // not O
1503 // implies O
1504 // forall X
1505 // exists X
1506 // abs O
1507 // conjugate X
1508 // arg X
1509 // real X
1510 // imaginary X
1511 // lcm X
1512 // floor X
1513 // ceiling X
1514
1515 // n-ary
1516 if ( op.tagName() == "plus" || op.tagName() == "times" ||
1517 op.tagName() == "and" || op.tagName() == "or" ||
1518 op.tagName() == "xor" ) {
1519
1520 n = n.nextSibling();
1521 bool first = true;
1522
1523 while ( !n.isNull() ) {
1524 if ( n.isElement() ) {
1525 if ( !first ) {
1526 TQDomElement text = doc.createElement( "TEXT" );
1527 TQString value;
1528
1529 if ( op.tagName() == "plus" )
1530 value = "+";
1531 else if ( op.tagName() == "times" )
1532 value = "*";
1533 else if ( op.tagName() == "and" )
1534 value = "&";
1535 else if ( op.tagName() == "or" )
1536 value = "|";
1537 else if ( op.tagName() == "xor" )
1538 value = "^"; // ???
1539
1540 text.setAttribute( "CHAR", value ); //switch to createTextElements?
1541 base.appendChild( text );
1542 }
1543 first = false;
1544 TQDomElement e = n.toElement();
1545 processElement( e, doc, base );
1546 }
1547 n = n.nextSibling();
1548 }
1549 }
1550
1551 else if ( op.tagName() == "factorial" ) {
1552 TQDomElement e = n.nextSibling().toElement();
1553 processElement( e, doc, docnode );
1554 impl->createTextElements( "!", base );
1555 }
1556 else if ( op.tagName() == "minus" ) {
1557 n = n.nextSibling();
1558 if ( count == 2 ) { // unary
1559 impl->createTextElements( "-", base );
1560 TQDomElement e = n.toElement();
1561 processElement( e, doc, base );
1562 }
1563 else if ( count == 3 ) { // binary
1564 TQDomElement e = n.toElement();
1565 processElement( e, doc, base );
1566 impl->createTextElements( "-", base );
1567 n = n.nextSibling();
1568 e = n.toElement();
1569 processElement( e, doc, base );
1570 }
1571 }
1572
1573 else if ( op.tagName() == "divide" && count == 3 ) {
1574 n = n.nextSibling();
1575 TQDomElement e = n.toElement();
1576 processElement( e, doc, base );
1577 impl->createTextElements("/", base);
1578 n = n.nextSibling();
1579 e = n.toElement();
1580 processElement( e, doc, base );
1581 }
1582 else if ( op.tagName() == "power" && count == 3 ) {
1583 //code duplication of msub_sup(), but I can't find a way to cleanly call it
1584 n = n.nextSibling();
1585 TQDomElement e = n.toElement();
1586 TQDomElement index = doc.createElement("INDEX");
1587 base.appendChild(index);
1588 TQDomElement content = doc.createElement("CONTENT");
1589 index.appendChild(content);
1590 TQDomElement sequence = doc.createElement("SEQUENCE");
1591 content.appendChild(sequence);
1592 processElement(e, doc, sequence);
1593 TQDomElement upper = doc.createElement("UPPERRIGHT");
1594 index.appendChild(upper);
1595 sequence = doc.createElement("SEQUENCE");
1596 upper.appendChild(sequence);
1597 n = n.nextSibling();
1598 e = n.toElement();
1599 processElement(e, doc, sequence);
1600 }
1601 else if ( op.tagName() == "abs" && count == 2) {
1602 n = n.nextSibling();
1603 TQDomElement e = n.toElement();
1604 TQDomElement bracket = doc.createElement("BRACKET");
1605 bracket.setAttribute("RIGHT", "257");
1606 bracket.setAttribute("LEFT", "256");
1607 base.appendChild(bracket);
1608 TQDomElement content = doc.createElement("CONTENT");
1609 bracket.appendChild(content);
1610 TQDomElement sequence = doc.createElement("SEQUENCE");
1611 content.appendChild(sequence);
1612 processElement(e, doc, sequence);
1613 }
1614 else if ( op.tagName() == "not" && count == 2) {
1615 n = n.nextSibling();
1616 TQDomElement e = n.toElement();
1617 impl->createTextElements(TQString(TQChar(0xAC)), base);
1618 processElement(e, doc, base);
1619 }
1620 else if ( op.tagName() == "implies" && count == 3 ) {
1621 n = n.nextSibling();
1622 TQDomElement e = n.toElement();
1623 processElement( e, doc, base );
1624 impl->createTextElements(TQString(TQChar(0x21D2)), base);
1625 n = n.nextSibling();
1626 e = n.toElement();
1627 processElement( e, doc, base );
1628 }
1629 // many, many more...
1630
1631 }
1632
1633 else if ( tag == "cn" ) {
1634 type = CONTENT;
1635 TQString type = element.attribute( "type", "real" );
1636
1637 if ( type == "real" || type == "constant" ) {
1638 impl->createTextElements( element.text().stripWhiteSpace(),
1639 docnode );
1640 }
1641 else if ( type == "integer" ) {
1642 TQString base = element.attribute( "base" );
1643 if ( !base ) {
1644 impl->createTextElements( element.text().stripWhiteSpace(),
1645 docnode );
1646 }
1647 else {
1648 TQDomElement index = doc.createElement( "INDEX" );
1649 TQDomElement content = doc.createElement( "CONTENT" );
1650 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1651 impl->createTextElements( element.text().stripWhiteSpace(),
1652 sequence );
1653 content.appendChild( sequence );
1654 index.appendChild( content );
1655
1656 TQDomElement lowerright = doc.createElement( "LOWERRIGHT" );
1657 sequence = doc.createElement( "SEQUENCE" );
1658
1659 impl->createTextElements( base, sequence );
1660
1661 lowerright.appendChild( sequence );
1662 index.appendChild( lowerright );
1663
1664 docnode.appendChild( index );
1665 }
1666 }
1667 else if ( type == "rational" ) {
1668 TQDomNode n = element.firstChild();
1669 impl->createTextElements( n.toText().data().stripWhiteSpace(),
1670 docnode );
1671
1672 n = n.nextSibling(); // <sep/>
1673 impl->createTextElements( "/", docnode );
1674
1675 n = n.nextSibling();
1676 impl->createTextElements( n.toText().data().stripWhiteSpace(),
1677 docnode );
1678 }
1679 else if ( type == "complex-cartesian" ) {
1680 TQDomNode n = element.firstChild();
1681 impl->createTextElements( n.toText().data().stripWhiteSpace(),
1682 docnode );
1683
1684 n = n.nextSibling(); // <sep/>
1685 impl->createTextElements( "+", docnode );
1686
1687 n = n.nextSibling();
1688 impl->createTextElements( n.toText().data().stripWhiteSpace(),
1689 docnode );
1690
1691 impl->createTextElements( "i", docnode );
1692 }
1693
1694 else if ( type == "complex-polar" ) {
1695 TQDomNode n = element.firstChild();
1696 impl->createTextElements( n.toText().data().stripWhiteSpace(),
1697 docnode );
1698
1699 n = n.nextSibling(); // <sep/>
1700 TQDomElement index = doc.createElement( "INDEX" );
1701 TQDomElement content = doc.createElement( "CONTENT" );
1702 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1703 TQDomElement textelement = doc.createElement( "TEXT" );
1704 textelement.setAttribute( "CHAR", "e" );
1705 sequence.appendChild( textelement );
1706 content.appendChild( sequence );
1707 index.appendChild( content );
1708
1709 TQDomElement upperright = doc.createElement( "UPPERRIGHT" );
1710 sequence = doc.createElement( "SEQUENCE" );
1711 textelement = doc.createElement( "TEXT" );
1712 textelement.setAttribute( "CHAR", "i" );
1713 sequence.appendChild( textelement );
1714
1715 n = n.nextSibling();
1716 impl->createTextElements( n.toText().data().stripWhiteSpace(),
1717 sequence );
1718
1719 upperright.appendChild( sequence );
1720 index.appendChild( upperright );
1721
1722 docnode.appendChild( index );
1723 }
1724 }
1725
1726 else if ( tag == "ci" ) {
1727 type = CONTENT;
1728 TQDomNode n = element.firstChild();
1729
1730 if ( n.isText() ) {
1731 impl->createTextElements( n.toText().data().stripWhiteSpace(),
1732 docnode );
1733 }
1734 else if ( n.isElement() ) {
1735 TQDomElement e = n.toElement();
1736 processElement( e, doc, docnode );
1737 }
1738 else if ( n.isEntityReference() ) {
1739 kdDebug( DEBUGID ) << "isEntityReference: "
1740 << n.toEntityReference().nodeName().latin1()
1741 << endl;
1742 }
1743 else
1744 kdDebug( DEBUGID ) << "ci: " << n.nodeName().latin1() << endl;
1745 }
1746
1747 else if ( tag == "list" ) {
1748 type = CONTENT;
1749 TQDomNode n = element.firstChild();
1750
1751 TQDomElement bracket = doc.createElement( "BRACKET" );
1752 bracket.setAttribute( "LEFT", 91 ); // [
1753 bracket.setAttribute( "RIGHT", 93 ); // ]
1754 TQDomElement content = doc.createElement( "CONTENT" );
1755 TQDomElement sequence = doc.createElement( "SEQUENCE" );
1756
1757 bool first = true;
1758
1759 while ( !n.isNull() ) {
1760 if ( n.isElement() ) {
1761 if ( !first ) {
1762 TQDomElement textelement = doc.createElement( "TEXT" );
1763 textelement.setAttribute( "CHAR", "," );
1764 sequence.appendChild( textelement );
1765 }
1766 first = false;
1767 TQDomElement e = n.toElement();
1768 processElement( e, doc, sequence );
1769 }
1770 n = n.nextSibling();
1771 }
1772
1773 content.appendChild( sequence );
1774 bracket.appendChild( content );
1775 docnode.appendChild( bracket );
1776 }
1777 }
1778
1779 if ( type == UNKNOWN && node.nodeType() != TQDomNode::AttributeNode ) {
1780 kdDebug() << "Not an element: " << node.nodeName() << endl;
1781 TQDomNode n = node.firstChild();
1782 while ( !n.isNull() ) {
1783 processElement( n, doc, docnode );
1784 n = n.nextSibling();
1785 }
1786 }
1787
1788 return true;
1789}
1790
1791KFORMULA_NAMESPACE_END
1792
1793using namespace KFormula;
1794#include "kformulamathmlread.moc"
Contains all the style information for the formela.
static void error(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, int options=Notify)
This class converts MathML to KFormula XML.
MathML2KFormula(const TQDomDocument &mmldoc, const ContextStyle &contextStyle, bool oasisFormat=false)
Build a MathML 2 KFormula converter.
bool m_error
Has an error happened while converting?