summaryrefslogtreecommitdiffstats
path: root/lib/kformula
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kformula')
-rw-r--r--lib/kformula/AUTHORS4
-rw-r--r--lib/kformula/DESIGN364
-rw-r--r--lib/kformula/FILTERS35
-rw-r--r--lib/kformula/Makefile.am39
-rw-r--r--lib/kformula/MatrixDialog.cc77
-rw-r--r--lib/kformula/MatrixDialog.h54
-rw-r--r--lib/kformula/README45
-rw-r--r--lib/kformula/TODO227
-rw-r--r--lib/kformula/actionelement.cc77
-rw-r--r--lib/kformula/actionelement.h49
-rw-r--r--lib/kformula/basicelement.cc400
-rw-r--r--lib/kformula/basicelement.h548
-rw-r--r--lib/kformula/bracketelement.cc1005
-rw-r--r--lib/kformula/bracketelement.h436
-rw-r--r--lib/kformula/config/Makefile.am27
-rw-r--r--lib/kformula/config/esstixeight.font31
-rw-r--r--lib/kformula/config/esstixeleven.font7
-rw-r--r--lib/kformula/config/esstixfifteen.font7
-rw-r--r--lib/kformula/config/esstixfive.font17
-rw-r--r--lib/kformula/config/esstixfour.font41
-rw-r--r--lib/kformula/config/esstixfourteen.font11
-rw-r--r--lib/kformula/config/esstixnine.font7
-rw-r--r--lib/kformula/config/esstixone.font57
-rw-r--r--lib/kformula/config/esstixseven.font16
-rw-r--r--lib/kformula/config/esstixseventeen.font7
-rw-r--r--lib/kformula/config/esstixsix.font12
-rw-r--r--lib/kformula/config/esstixsixteen.font7
-rw-r--r--lib/kformula/config/esstixten.font52
-rw-r--r--lib/kformula/config/esstixthirteen.font7
-rw-r--r--lib/kformula/config/esstixthree.font75
-rw-r--r--lib/kformula/config/esstixtwelve.font7
-rw-r--r--lib/kformula/config/esstixtwo.font35
-rw-r--r--lib/kformula/config/euclid%20math%20one.font151
-rw-r--r--lib/kformula/config/euclid%20math%20two.font131
-rw-r--r--lib/kformula/config/euclid%20symbol.font188
-rw-r--r--lib/kformula/config/mt%20extra.font144
-rw-r--r--lib/kformula/config/mt%20symbol.font188
-rw-r--r--lib/kformula/config/symbol.font188
-rw-r--r--lib/kformula/config/unicode.tbl635
-rw-r--r--lib/kformula/contextstyle.cc765
-rw-r--r--lib/kformula/contextstyle.h480
-rw-r--r--lib/kformula/creationstrategy.cc144
-rw-r--r--lib/kformula/creationstrategy.h113
-rw-r--r--lib/kformula/dtd/Makefile.am4
-rw-r--r--lib/kformula/dtd/kformula.dtd95
-rw-r--r--lib/kformula/elementindex.h33
-rw-r--r--lib/kformula/elementtype.cc765
-rw-r--r--lib/kformula/elementtype.h503
-rw-r--r--lib/kformula/elementvisitor.h70
-rw-r--r--lib/kformula/encloseelement.cc44
-rw-r--r--lib/kformula/encloseelement.h42
-rw-r--r--lib/kformula/entities.cc2037
-rw-r--r--lib/kformula/entities.h49
-rw-r--r--lib/kformula/errorelement.cc51
-rw-r--r--lib/kformula/errorelement.h51
-rw-r--r--lib/kformula/fonts/Arev.ttfbin0 -> 348154 bytes
-rw-r--r--lib/kformula/fonts/ArevBI.ttfbin0 -> 361426 bytes
-rw-r--r--lib/kformula/fonts/ArevBd.ttfbin0 -> 347796 bytes
-rw-r--r--lib/kformula/fonts/ArevIt.ttfbin0 -> 360544 bytes
-rw-r--r--lib/kformula/fonts/LICENSE.AREV47
-rw-r--r--lib/kformula/fonts/LICENSE.BAKOMA40
-rw-r--r--lib/kformula/fonts/LICENSE.BITSTREAM42
-rw-r--r--lib/kformula/fonts/Makefile.am11
-rw-r--r--lib/kformula/fonts/README10
-rw-r--r--lib/kformula/fonts/cmex10.ttfbin0 -> 21092 bytes
-rw-r--r--lib/kformula/fontstyle.cc891
-rw-r--r--lib/kformula/fontstyle.h193
-rw-r--r--lib/kformula/formulacursor.cc746
-rw-r--r--lib/kformula/formulacursor.h465
-rw-r--r--lib/kformula/formulaelement.cc336
-rw-r--r--lib/kformula/formulaelement.h234
-rw-r--r--lib/kformula/fractionelement.cc657
-rw-r--r--lib/kformula/fractionelement.h255
-rw-r--r--lib/kformula/glyphelement.cc159
-rw-r--r--lib/kformula/glyphelement.h68
-rw-r--r--lib/kformula/identifierelement.cc206
-rw-r--r--lib/kformula/identifierelement.h62
-rw-r--r--lib/kformula/indexelement.cc1763
-rw-r--r--lib/kformula/indexelement.h442
-rw-r--r--lib/kformula/kformulacommand.cc625
-rw-r--r--lib/kformula/kformulacommand.h562
-rw-r--r--lib/kformula/kformulacompatibility.cc402
-rw-r--r--lib/kformula/kformulacompatibility.h74
-rw-r--r--lib/kformula/kformulaconfigpage.cc543
-rw-r--r--lib/kformula/kformulaconfigpage.h150
-rw-r--r--lib/kformula/kformulacontainer.cc643
-rw-r--r--lib/kformula/kformulacontainer.h439
-rw-r--r--lib/kformula/kformuladefs.h430
-rw-r--r--lib/kformula/kformuladocument.cc1299
-rw-r--r--lib/kformula/kformuladocument.h510
-rw-r--r--lib/kformula/kformulainputfilter.cc24
-rw-r--r--lib/kformula/kformulainputfilter.h57
-rw-r--r--lib/kformula/kformulalib.h32
-rw-r--r--lib/kformula/kformulamathmlread.cc1794
-rw-r--r--lib/kformula/kformulamathmlread.h100
-rw-r--r--lib/kformula/kformulamimesource.cc154
-rw-r--r--lib/kformula/kformulamimesource.h60
-rw-r--r--lib/kformula/kformulaview.cc413
-rw-r--r--lib/kformula/kformulaview.h189
-rw-r--r--lib/kformula/kformulawidget.cc171
-rw-r--r--lib/kformula/kformulawidget.h119
-rw-r--r--lib/kformula/main.cc298
-rw-r--r--lib/kformula/mathml.xml25
-rw-r--r--lib/kformula/matrixelement.cc2692
-rw-r--r--lib/kformula/matrixelement.h464
-rw-r--r--lib/kformula/numberelement.cc153
-rw-r--r--lib/kformula/numberelement.h47
-rw-r--r--lib/kformula/oasiscreationstrategy.cc210
-rw-r--r--lib/kformula/oasiscreationstrategy.h77
-rw-r--r--lib/kformula/oldformulabin0 -> 318 bytes
-rw-r--r--lib/kformula/operatordictionary.cc4266
-rw-r--r--lib/kformula/operatordictionary.h75
-rw-r--r--lib/kformula/operatorelement.cc547
-rw-r--r--lib/kformula/operatorelement.h83
-rw-r--r--lib/kformula/paddedelement.cc296
-rw-r--r--lib/kformula/paddedelement.h75
-rw-r--r--lib/kformula/phantomelement.cc39
-rw-r--r--lib/kformula/phantomelement.h51
-rw-r--r--lib/kformula/pics/Makefile.am1
-rw-r--r--lib/kformula/pics/crystalsvg/Makefile.am5
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-abs.pngbin0 -> 270 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-brackets.pngbin0 -> 286 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-frac.pngbin0 -> 214 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-gsub.pngbin0 -> 190 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-gsup.pngbin0 -> 191 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-int.pngbin0 -> 594 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-lsub.pngbin0 -> 240 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-lsup.pngbin0 -> 237 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-matrix.pngbin0 -> 245 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-multiline.pngbin0 -> 310 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-onetwomatrix.pngbin0 -> 249 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-over.pngbin0 -> 302 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-paren.pngbin0 -> 316 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-prod.pngbin0 -> 196 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-rsub.pngbin0 -> 240 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-rsup.pngbin0 -> 228 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-sqrt.pngbin0 -> 431 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-sum.pngbin0 -> 376 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr16-action-under.pngbin0 -> 311 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-abs.pngbin0 -> 710 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-brackets.pngbin0 -> 740 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-frac.pngbin0 -> 491 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-gsub.pngbin0 -> 322 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-gsup.pngbin0 -> 309 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-inscol.pngbin0 -> 304 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-insrow.pngbin0 -> 287 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-int.pngbin0 -> 708 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-lsub.pngbin0 -> 376 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-lsup.pngbin0 -> 362 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-matrix.pngbin0 -> 176 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-multiline.pngbin0 -> 294 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-onetwomatrix.pngbin0 -> 527 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-over.pngbin0 -> 737 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-paren.pngbin0 -> 744 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-prod.pngbin0 -> 380 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-remcol.pngbin0 -> 326 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-remrow.pngbin0 -> 303 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-rsub.pngbin0 -> 371 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-rsup.pngbin0 -> 395 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-sqrt.pngbin0 -> 442 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-sum.pngbin0 -> 764 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr22-action-under.pngbin0 -> 728 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-abs.pngbin0 -> 606 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-brackets.pngbin0 -> 475 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-frac.pngbin0 -> 346 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-gsub.pngbin0 -> 283 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-gsup.pngbin0 -> 278 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-int.pngbin0 -> 436 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-lsub.pngbin0 -> 402 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-lsup.pngbin0 -> 402 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-matrix.pngbin0 -> 636 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-multiline.pngbin0 -> 733 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-onetwomatrix.pngbin0 -> 386 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-over.pngbin0 -> 646 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-paren.pngbin0 -> 480 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-prod.pngbin0 -> 308 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-rsub.pngbin0 -> 402 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-rsup.pngbin0 -> 389 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-sqrt.pngbin0 -> 473 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-sum.pngbin0 -> 324 bytes
-rw-r--r--lib/kformula/pics/crystalsvg/cr32-action-under.pngbin0 -> 645 bytes
-rw-r--r--lib/kformula/prototype/README9
-rw-r--r--lib/kformula/prototype/engine.py1180
-rw-r--r--lib/kformula/prototype/gensymbolfontmap.py250
-rwxr-xr-xlib/kformula/prototype/main.py13
-rw-r--r--lib/kformula/prototype/symbol.xml2375
-rwxr-xr-xlib/kformula/prototype/unicode.py192
-rw-r--r--lib/kformula/rootelement.cc680
-rw-r--r--lib/kformula/rootelement.h273
-rwxr-xr-xlib/kformula/scripts/bycodes.py63
-rwxr-xr-xlib/kformula/scripts/bynames.py153
-rwxr-xr-xlib/kformula/scripts/oper-dict.py256
-rw-r--r--lib/kformula/scrollview.h32
-rw-r--r--lib/kformula/sequenceelement.cc1934
-rw-r--r--lib/kformula/sequenceelement.h620
-rw-r--r--lib/kformula/sequenceparser.cc241
-rw-r--r--lib/kformula/sequenceparser.h132
-rw-r--r--lib/kformula/spaceelement.cc431
-rw-r--r--lib/kformula/spaceelement.h167
-rw-r--r--lib/kformula/stringelement.cc88
-rw-r--r--lib/kformula/stringelement.h49
-rw-r--r--lib/kformula/styleelement.cc390
-rw-r--r--lib/kformula/styleelement.h81
-rw-r--r--lib/kformula/symbolaction.cc174
-rw-r--r--lib/kformula/symbolaction.h52
-rw-r--r--lib/kformula/symbolelement.cc906
-rw-r--r--lib/kformula/symbolelement.h313
-rw-r--r--lib/kformula/symbolfontmapping.cc171
-rw-r--r--lib/kformula/symboltable.cc152
-rw-r--r--lib/kformula/symboltable.h148
-rw-r--r--lib/kformula/textelement.cc567
-rw-r--r--lib/kformula/textelement.h287
-rw-r--r--lib/kformula/tokenelement.cc124
-rw-r--r--lib/kformula/tokenelement.h61
-rw-r--r--lib/kformula/tokenstyleelement.cc624
-rw-r--r--lib/kformula/tokenstyleelement.h168
-rw-r--r--lib/kformula/unicodetable.cc546
217 files changed, 49377 insertions, 0 deletions
diff --git a/lib/kformula/AUTHORS b/lib/kformula/AUTHORS
new file mode 100644
index 00000000..9df44bb2
--- /dev/null
+++ b/lib/kformula/AUTHORS
@@ -0,0 +1,4 @@
+Andrea Rizzi <rizzi@kde.org>
+Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+Claus O. Wilke <wilke@caltech.edu>
+Alfredo Beaumont <alfredo.beaumont@gmail.com>
diff --git a/lib/kformula/DESIGN b/lib/kformula/DESIGN
new file mode 100644
index 00000000..a6a7eccb
--- /dev/null
+++ b/lib/kformula/DESIGN
@@ -0,0 +1,364 @@
+
+ The design of kformula
+ (as we imagine it)
+
+The core of kformula is a tree of element objects that make up the
+formula which is beeing edited.
+
+The element tree itself
+#######################
+
+BasicElement
+------------
+
+All element classes are derived from this one.
+So it provides the interface that is common to all elements.
+BasicElement itself is an abstract class. You never want to create
+objects from it.
+
+Responsebilities
+(This goes for every derived element and therefore for each one.)
+
+- knows its children. Actually BasicElement doesn't have any. But it
+ already defines that children must be known by their parent.
+- knows its bounding rectangle (its size.) The children are included
+ in this rect. (The position is relative to the parent.)
+//- knows its middle line. (for alignment)
+- knows it's zero point for midline (vertical alignment) and
+ keep open the possibility of negative positions (out of bounding rect)
+- draws itself (given a painter); children are drawn, too
+- knows all positions where the cursor is allowed to be. (see below)
+- knows its parent; The topmost element has no parent; there is a
+ implicit guaranty that the topmost element is always a
+ SequenceElement.
+- can save and load itself. different formates. (see below)
+- all children must be a SequenceElement. Except for SequenceElement's
+ children that might be of any type.
+- might have its own color.
+- might have its own font size (see below).
+
+
+SequenceElement from BasicElement
+---------------
+
+Manages a list of children. The children are aligned horizontally at
+one middle line. No gaps, no overlaps.
+
+Has no own look. It just draws all its children and is done. Except if
+its empty. It looks like an empty space then (i.e. a little square)
+
+Has n+1 valid cursor positions where n is the number of
+children. These are before, between and after the children.
+
+May contain any (type of) element as child
+
+except SequenceElements if they contains a SequenceElement they merge
+it in the list
+
+They can handle splitting of the sequence to allow "select an put selected item
+between parenthesis" i.e. as content child of a delimiterelement)
+
+
+FormulaElement from SequenceElement
+--------------
+
+The only element those parent is null. The root of the element object
+tree.
+
+This is the element that is created by the KFormulaDoc and that knows
+about it. As every other element knows its parent and therefore the
+FormulaElement we get a chance to pass messages to the outside world.
+
+
+RootElement from BasicElement
+-----------
+
+contains two children. content and index. index is optional.
+
+
+IndexElement from BasicElement
+------------
+
+contains five children. content and four indexes. all indexes are
+optional. If there is no index the element might be replaced by its content.
+
+
+TextElement from BasicElement
+-----------
+
+contains one char and no children at all.
+
+
+Might have its own font and size. But preferes to use a reasonalbe
+font and size that are calculated from its parents font and a given
+scheme (see below).
+
+
+DelimiterElement from BasicElement
+----------------
+
+contains one child and draws delimiters around it. You are free to
+choose with.
+
+
+FractionElement from BasicElement
+---------------
+
+2 children: numerator, denominator
+
+
+DecorationElement from BasicElement
+-----------------
+
+A piece of art. It has one child and decorates it above (or below or
+both) with some nice decor. Some decor might be required to be as
+width as the content. There is a way to guarantee this.
+
+We could even add yet another child that can optionally be shown at
+the other side of the decoration.
+
+
+SumIntegralElement from BasicElement //PrefixedElement
+------------------
+
+draws all sorts of mathematical symbols with three children. Above,
+below (or whereever the indices and limits go)and to the right.
+
+
+GeometryElement from BasicElement
+---------------
+
+One child.
+Draw it at a fixed position relative to parent or absolute.
+This is to do dirty things.
+
+This element must not be used, kformula will provide you everything
+without the use of this kind of element, any way for strange reasons
+you want to do things that are not usually allowed and that are not
+typical of a math formula.
+[We will decide if implement this element or not]
+
+
+MatrixElement from BasicElement
+-------------
+
+A matrix of children.
+With all align stuff, internal borders etc, matrix dots handling (i.e.
+those dots or lines that complete the matrix, not well handled in TeX),
+etc..
+
+SpaceElement from BasicElement
+------------
+
+No children at all. Provides the facility to insert horizontal spaces
+in the formula. (therefore it is similar to TextElement.)
+
+
+OperatorElement from TextElement
+---------------
+
+The element to be used for all kinds of operators. It needed because
+operators require some space before and after and are therefore no
+simple text.
+
+They can you pixamps inestead of fonts, the use of pixmaps is needed only
+to give the user the possibilty of introduce its strange operator that we
+do not provide as a font. There problems with the scalability but we will
+include as fonts (or vectorial images) in kformula all TeX operators so we
+hope there is no need to use pixamps for a standard use of KFormula
+
+
+
+Navigation
+##########
+
+There is a class Cursor that implements a pointer to a valid cursor
+position inside the formula structure. Each kformula view needs to
+have its own object of this class.
+
+The Cursor class uses the elements facility to travel throught the
+structure. (It gives the key to the current element and asks for the
+new position.)
+
+If the cursor points into an element this element is said to own the
+cursor. There are a few rules that describe how new cursor positions
+are calculated given the current key:
+
+- An elements cursor positions are its children. The element might not
+own the cursor except when it is owned by one of its children. The
+only exception is SequenceElement which has valid cursor positions
+before, between and after its children, too.
+
+(Therefore the cursor is always owned by a SequenceElement.)
+
+- Each element's children are ordered. If the cursor leaves one child
+the next child it. The direction depends on the key that moved the
+cursor. If there is child left the cursor is passed to the parent.
+
+- If the cursor comes from our parent the first or the last child gets
+it. Depending on the direction in which the cursor moved.
+
+Please note that because each element knows its own cursor positions
+and how to behave, it is possible for each combination of elements to
+work together correctly.
+
+
+
+Editing (undo/redo)
+###################
+
+You always use a cursor to work on the element tree. The cursor
+provides all the basic facilities that are needed to change the tree
+in any way. Its up to you to build bigger functions out of the
+cursor's primitives.
+
+The cursor's interface was designed to allow implement undo support.
+
+There are a few things that you need to know:
+
+- You are not supposed to know the elements that are stored in the
+tree. If you remove them from the tree they are yours and you are
+responsible to delete them properly. But as soon as you put them back
+its the trees business to manage them.
+
+- All the cursors operations that change the tree come in pairs. If
+you call both operations in a row (with the right parameters) you get
+back to the place you started. `insert' for example inserts one or
+more elements and selects them. `remove' removes the selected
+elements and returns them.
+
+- You can always save the current cursor position by calling
+getCursorData(). To set a cursor to a place it was before use
+setCursorData(). But note that its up to you to ensure that the
+position still exists. This means you will only want to call it if you
+are certain that the element tree is exactly the same as it was when
+you called getCursorData().
+
+- The creation of new object is not the cursors business. You do this
+yourself.
+
+- If you want to insert special elements like indexes you will have to
+ask the IndexElement in question for the cursor position where to put
+it. But please note that you might only put empty SequenceElements
+there.
+
+- Its a mistake to insert a SequenceElement at a non-special place.
+
+- After a removal the cursor might point to a strange place like a
+removed index. To get it back to point to something meaningful you
+will have to normalize() it. If the cursor is normalized it is inside a
+SequenceElement. If not its not. Most operations expect the cursor to
+be normalized.
+
+- If you remove something from a element it might become
+senseless. This means you must replace it with its main childs
+content.
+
+
+
+Syntax highlighting
+###################
+
+Everytime a sequence is edited it builds a new syntax tree. (The old
+one gets recycled :) ) The parser goes throught the sequence and
+builds a type object for every token is finds. A token consists of
+one or more elements.
+
+On drawing the elements use their types to find the right font, color
+and spacing.
+
+One nice thing about the syntax checking is that it allows us to
+replace symbol names with a more fancy graphical representation.
+
+The syntax tree is meant to support evaluation of formulas as well,
+but this is yet another story...
+
+
+
+Save and Load (Import/Export)
+#############################
+
+there are quite a few formats we want to read and write:
+
+Built in:
+- native koffice xml
+
+Import/Export filters
+- MathML
+- C like math strings
+- LaTeX
+
+
+
+Element templates
+#################
+
+example: you can create a template to write limits:
+it is a "lim ( )" string over 2 empty elements with an arrows that separe
+them
+
+
+
+Style templates
+###############
+
+There need to be templates that tell which font to use, how the sizes
+differ among different elements and what spaces are to be
+included. (And much more.)
+
+Your only need to choose one of them to get a reasonable good look.
+
+Therefore we pass a StyleContext to the
+FormulaElement. The StyleContext contains the font family to use, the
+normal font size, the spaces to include between certain elements and
+all sorts of context information that is needed to draw the
+formula.
+
+The elements use this information to calculate their sizes and to draw
+themselves. Each element is allowed to choose different settings for
+whatever reason. But if the formula looks ugly then its the elements
+blame.
+
+
+
+Interface templates
+###################
+
+Decide what KAction have to be toolbars,
+what element templates must be loaded, what toolbar display....
+There will be predefined (sorry for the spelling error) templates for
+-General...
+-Physics (Vectors , integral, partial derivative etc are preferred..)
+-Analysis (Integral and diff equation stuff)
+-Geometry (Tensor product etc)
+-Chemistry (Arrows, Periodic table external toolbar)
+-Computer science (...)
+-????
+
+
+
+Context sensibility
+###################
+
+We want a formula to look different according to its
+surroundings. (Most obviosly according to the available height and/or width.)
+
+It would be great to get something like automatic operator
+alignment. So if you type some formulas each on its own line the
+assigment operators should be automatically in a column. (If the user
+turns this on.)
+
+
+
+Fonts and font size
+###################
+
+Each elements font size is calculated starting from its parents font
+size. It knows how it differs to those.
+
+The font size might also be used to choose the pen width and other
+size dependent settings.
+
+
+Andrea Rizzi <rizzi@kde.org>
+Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
diff --git a/lib/kformula/FILTERS b/lib/kformula/FILTERS
new file mode 100644
index 00000000..b335573d
--- /dev/null
+++ b/lib/kformula/FILTERS
@@ -0,0 +1,35 @@
+Filter status:
+
+IMPORT:
+
+-MathML
+ Missing good <mo> (i.e. operator) import.
+
+-LaTeX
+ Need a parser...I'll look at formula1 parser
+
+-C Style (i.e. niceThisFormula(QString))
+ this is easy to do, cooming soon.
+
+
+
+EXPORT:
+
+-LaTex:
+ Supports:
+ brackets,matrix,roots,indeces,text,operator,greekcharacters(partially),fractions
+
+ Needs:
+ AMSmath package
+
+ Todo:
+ Symbols and greek letters
+ Options...
+
+
+
+-C Style
+ To be done. Thinking about how to handle some things
+
+-MathML
+
diff --git a/lib/kformula/Makefile.am b/lib/kformula/Makefile.am
new file mode 100644
index 00000000..83ba7198
--- /dev/null
+++ b/lib/kformula/Makefile.am
@@ -0,0 +1,39 @@
+
+INCLUDES= $(KOFFICE_INCLUDES) $(KOTEXT_INCLUDES) $(all_includes)
+
+SUBDIRS = pics fonts dtd
+
+#######
+# We have to name it kformulalib, not just kformula, since that's the name of the kdeinit module for kformula.
+lib_LTLIBRARIES = libkformulalib.la
+
+libkformulalib_la_SOURCES = basicelement.cc contextstyle.cc formulacursor.cc \
+ formulaelement.cc indexelement.cc kformulacontainer.cc \
+ sequenceelement.cc textelement.cc bracketelement.cc \
+ matrixelement.cc fractionelement.cc rootelement.cc symbolelement.cc \
+ kformulacommand.cc kformulamimesource.cc \
+ MatrixDialog.cc sequenceparser.cc elementtype.cc kformuladocument.cc \
+ symboltable.cc kformulainputfilter.cc kformulaview.cc \
+ spaceelement.cc kformulaconfigpage.cc \
+ symbolaction.cc fontstyle.cc creationstrategy.cc \
+ oasiscreationstrategy.cc tokenstyleelement.cc tokenelement.cc \
+ identifierelement.cc operatorelement.cc glyphelement.cc styleelement.cc \
+ stringelement.cc paddedelement.cc errorelement.cc phantomelement.cc \
+ actionelement.cc encloseelement.cc entities.cc operatordictionary.cc \
+ numberelement.cc
+
+#include_HEADERS = kformulacontainer.h kformuladocument.h kformulaview.h \
+# kformuladefs.h kformulaconfigpage.h
+
+libkformulalib_la_LDFLAGS = $(all_libraries) -version-info 4:0 -no-undefined $(KDE_RPATH)
+libkformulalib_la_LIBADD = $(LIB_KDEUI) $(LIB_KOTEXT)
+
+libkformulalib_la_METASOURCES = AUTO
+
+check_PROGRAMS = kformulatest
+
+kformulatest_SOURCES = main.cc kformulawidget.cc
+kformulatest_LDADD = libkformulalib.la
+
+#symbolnames.cc:
+# awk -F, '$$1 !~ "#" {if (split($$3,a," ")>0) print "i18n(\"" a[1] "\");"}' config/unicode.tbl > symbolnames.cc
diff --git a/lib/kformula/MatrixDialog.cc b/lib/kformula/MatrixDialog.cc
new file mode 100644
index 00000000..7f8ee9d5
--- /dev/null
+++ b/lib/kformula/MatrixDialog.cc
@@ -0,0 +1,77 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Ilya Baran (ibaran@mit.edu)
+
+ 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 "MatrixDialog.h"
+#include <qpushbutton.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <klocale.h>
+
+KFORMULA_NAMESPACE_BEGIN
+
+const int DEFAULT_SIZE = 3;
+const int MAX_SIZE = 200;
+
+MatrixDialog::MatrixDialog( QWidget *parent, int _width, int _height )
+ : KDialogBase(parent, "Matrix Dialog", true,i18n("Add Matrix"),Ok|Cancel)
+{
+ w = _width;
+ h = _height;
+
+ QLabel *rows, *columns;
+ QWidget *page = new QWidget( this );
+ setMainWidget(page);
+ QGridLayout *grid = new QGridLayout(page, 4, 2, 10);
+
+ rows = new QLabel(i18n("Rows:"), page);
+ columns = new QLabel(i18n("Columns:"), page);
+
+ grid->addWidget(rows, 0, 0);
+ grid->addWidget(columns, 0, 1);
+
+ QSpinBox *width, *height;
+
+ height = new QSpinBox(1, MAX_SIZE, 1, page);
+ grid->addWidget(height, 1, 0);
+ height->setValue(h);
+ connect(height, SIGNAL(valueChanged(int)), SLOT(setHeight(int)));
+
+ width = new QSpinBox(1, MAX_SIZE, 1, page);
+ grid->addWidget(width, 1, 1);
+ width->setValue(w);
+ connect(width, SIGNAL(valueChanged(int)), SLOT(setWidth(int)));
+ height->setFocus();
+}
+
+void MatrixDialog::setHeight(int value)
+{
+ h = value;
+}
+
+void MatrixDialog::setWidth(int value)
+{
+ w = value;
+}
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+#include "MatrixDialog.moc"
diff --git a/lib/kformula/MatrixDialog.h b/lib/kformula/MatrixDialog.h
new file mode 100644
index 00000000..d8b728d3
--- /dev/null
+++ b/lib/kformula/MatrixDialog.h
@@ -0,0 +1,54 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1999 Ilya Baran (ibaran@mit.edu)
+
+ 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.
+*/
+
+#ifndef MATRIXDIALOG_H_INCLUDED
+#define MATRIXDIALOG_H_INCLUDED
+
+#include <qwidget.h>
+#include <kdialogbase.h>
+#include <qvalidator.h>
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+/**
+ * Dialog for entering matrix sizes.
+ */
+class MatrixDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ int w;
+ int h;
+
+ MatrixDialog( QWidget *parent, int width = 3, int height = 3 );
+ ~MatrixDialog() {}
+
+protected slots:
+
+ void setWidth(int value);
+ void setHeight(int value);
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // MATRIXDIALOG_H_INCLUDED
diff --git a/lib/kformula/README b/lib/kformula/README
new file mode 100644
index 00000000..5cd97995
--- /dev/null
+++ b/lib/kformula/README
@@ -0,0 +1,45 @@
+
+This is the new kformula library. It's used by the kformula part and kword.
+
+To test the library do
+make kformulatest
+./kformulatest
+
+Supported actions include:
+
+Ctrl-O open (to "test.xml")
+Ctrl-S save (from "test.xml")
+Ctrl-M open (from "mathml.xml")
+Ctrl-Q quit
+
+Ctrl-Z undo
+Ctrl-Shift-Z redo
+
+Ctrl-X cut
+Ctrl-C copy
+Ctrl-V paste
+Ctrl-A selectAll
+
+---
+
+Ctrl-U upper index (symbol/root)
+Ctrl-L lower index (symbol)
+
+Ctrl-1 sum
+Ctrl-2 product
+Ctrl-3 integral
+Ctrl-4 root
+Ctrl-5 fraction
+Ctrl-6 matrix
+Ctrl-D, Ctrl-R remove enclosing element
+Ctrl-G make current letter a greek one
+
+^, _, Ctrl-^, Ctrl-_ standart indexes
+(, [, | brackets
+
+Text, numbers and operators are supported as well.
+
+Please note that the key bindings are for testing only. The library
+is meant to be used with KActions. Look at KFormulaDocument::createActions.
+
+See DESIGN to know the structure of the formulas
diff --git a/lib/kformula/TODO b/lib/kformula/TODO
new file mode 100644
index 00000000..a6ebc27c
--- /dev/null
+++ b/lib/kformula/TODO
@@ -0,0 +1,227 @@
+=== OASIS OpenDocument / MathML ===
+
+NOTE: Only Presentation Markup is considered here.
+
+== Token Elements ==
+
+= mo =
+
+* Support for attribute form: rendering ( Section 3.2.5.2, 3.2.5.7 )
+* Support for attribute fence: rendering ( Section 3.2.5.2, 3.2.5.7 )
+* Support for attribute separator: rendering ( Section 3.2.5.2, 3.2.5.7 )
+* Support for attribute lspace: rendering ( Section 3.2.5.2, 3.2.5.7 )
+* Support for attribute rspace: rendering ( Section 3.2.5.2, 3.2.5.7 )
+* Support for attribute stretchy: rendering ( Section 3.2.5.2, 3.2.5.7, 3.2.5.8 )
+* Support for attribute symmetric: rendering ( Section 3.2.5.2, 3.2.5.7, 3.2.5.8 )
+* Support for attribute maxsize: rendering ( Section 3.2.5.2, 3.2.5.7, 3.2.5.8 )
+* Support for attribute minsize: rendering ( Section 3.2.5.2, 3.2.5.7, 3.2.5.8 )
+* Support for attribute largeop: rendering ( Section 3.2.5.2, 3.2.5.7, 3.2.5.9 )
+* Support for attribute movablelimits: rendering ( Section 3.2.5.2, 3.2.5.7, 3.2.5.9 )
+* Support for attribute accent: rendering ( Section 3.2.5.2, 3.2.5.7 )
+
+= mtext =
+
+* Proper support for space-like elements ( Section 3.2.6.2 )
+
+= mspace =
+
+* Support for attribute linebreak: rendering ( Section 3.2.7.2 )
+
+= ms =
+
+* Support for attribute lquote: rendering ( Section 3.2.8.2 )
+* Support for attribute rquote: rendering ( Section 3.2.8.2 )
+* Support for escaping content ( Section 3.2.8.2 )
+
+= Misc =
+
+* Support for <malignmark> element inside Token Elements ( Sections 3.2.1, 3.5.5 )
+* Implement surrounding spaces around Token Elements
+
+
+== General Layout Schemata ==
+
+= mrow =
+
+* Support for 1 argument behaviour as the argument itself ( Section 3.3.1.2.1 )
+* Support for proper grouping of mrow elements ( Section 3.3.1.3.1 )
+
+= mfrac =
+
+* Support for attribute bevelled: rendering ( Section 3.3.2.2 )
+
+= mstyle =
+
+* Support for attributes of all presentation elements which do not have required values ( Section 3.3.4.1, 3.3.4.2 ):
+- form (mo)
+- fence (mo)
+- separator (mo)
+- lspace (mo)
+- rspace (mo)
+- stretchy (mo)
+- symmetric (mo)
+- maxsize (mo)
+- minsize (mo)
+- largeop (mo)
+- movablelimits (mo)
+- accent (mo)
+- width (mspace)
+- heigth (mspace)
+- depth (mspace)
+- linebreak (mspace)
+- lquote (ms)
+- rquote (ms)
+- linethickness (mfrac)
+- numalign (mfrac)
+- denomalign (mfrac)
+- bevelled (mfrac)
+- open (mfenced)
+- close (mfenced)
+- separators (mfenced)
+- notation (menclose)
+- subscriptshift (msub, msubsup, mmultiscripts)
+- superscriptshift (msup, msubsup, mmultiscripts)
+- accentunder (munder, munderover)
+- accent (mover, munderover)
+- align (mtable)
+- rowalign (mtable)
+- columnalign (mtable)
+- groupalign (mtable)
+- alignmentscope (mtable)
+- columnwidth (mtable)
+- width (mtable)
+- rowspacing (mtable)
+- columnspacing (mtable)
+- rowlines (mtable)
+- columnlines (mtable)
+- frame (mtable)
+- framespaciing (mtable)
+- equalrows (mtable)
+- equalcolumns (mtable)
+- displaystyle (mtable)
+- side (mtable)
+- minlabelspacing (mtable)
+- rowspan (mtd)
+- columnspan (mtd)
+- edge (malignmark)
+- selection (maction)
+* Support for rendering differences for attribute displaystyle ( Section 3.3.4.2.1 ) OPTIONAL
+* Support proper order of priority applying attribute scriptlevel ( Section 3.3.4.2.2 ) OPTIONAL
+
+= mfenced =
+
+* Support for arbitrary string in attribute open ( Section 3.3.8.2 )
+* Support for arbitrary string in attribute close ( Section 3.3.8.2 )
+
+= menclose =
+
+* Support for longdiv value ( Section 3.3.9.2 ) OPTIONAL
+* Support for actuarial value ( Section 3.3.9.2) OPTIONAL
+* Support for radical value ( Section 3.3.9.2 ) OPTIONAL
+* Support for box value ( Section 3.3.9.2) OPTIONAL
+* Support for roundedbox value ( Section 3.3.9.2 ) OPTIONAL
+* Support for circle value ( Section 3.3.9.2) OPTIONAL
+* Support for left value ( Section 3.3.9.2) OPTIONAL
+* Support for right value ( Section 3.3.9.2) OPTIONAL
+* Support for top value ( Section 3.3.9.2) OPTIONAL
+* Support for bottom value ( Section 3.3.9.2) OPTIONAL
+* Support for updiagonalstrike value ( Section 3.3.9.2) OPTIONAL
+* Support for downdiagonalstrike value ( Section 3.3.9.2) OPTIONAL
+* Support for verticalstrike value ( Section 3.3.9.2) OPTIONAL
+* Support for horizontalstrike value ( Section 3.3.9.2) OPTIONAL
+
+
+== Script and Limit Schemata ==
+
+= munder =
+
+* Support for attribute accentunder: rendering ( Section 3.4.4.2 )
+* Proper rendering of underscript element
+
+= mover =
+
+* Support for attribute accent: rendering ( Section 3.4.5.2 )
+* Proper rendering of overscript element
+
+= munderover =
+
+* Support for attribute accent: rendering ( Section 3.4.6.2, 3.4.5.2 )
+* Support for attribute accentunder: rendering ( Section 3.4.6.2, 3.4.4.2 )
+* Proper rendering of overscript element
+* Proper rendering of underscript element
+
+= mmultiscripts =
+
+* Support for <mmultiscripts> element: loading, saving, rendering ( Section 3.4.7.1 )
+* Support for attribute subscriptshift: loading, saving, rendering ( Section 3.4.7.2, 3.4.3.2 )
+* Support for attribute superscriptshift: loading, saving, rendering ( Section 3.4.7.2, 3.4.3.2 )
+
+== Tables and Matrices ==
+
+= mtable =
+
+* Support proper alignment ( Section 3.5.5.10 )
+* Support for MathML 1.01 deprecated inferred mtr loading ( Section 3.5.1.1 ) OPTIONAL
+* Support for MathML 1.01 deprecated inferred mtd loading ( Section 3.5.1.1 ) OPTIONAL
+* Support for attribute align: rendering ( Section 3.5.1.2 )
+* Support for attribute rowalign: rendering ( Section 3.5.1.2 )
+* Support for attribute columnalign: rendering ( Section 3.5.1.2, 3.5.5 )
+* Support for attribute alignmentscope: rendering ( Section 3.5.1.2, 3.5.5, 3.5.5.9 )
+* Support for attribute columnwidth: rendering ( Section 3.5.1.2 )
+* Support for attribute width: rendering ( Section 3.5.1.2 )
+* Support for attribute rowspacing: rendering ( Section 3.5.1.2 )
+* Support for attribute columnspacing: rendering ( Section 3.5.1.2 )
+* Support for attribute rowlines: rendering ( Section 3.5.1.2 )
+* Support for attribute columnlines: rendering ( Section 3.5.1.2 )
+* Support for attribute frame: rendering ( Section 3.5.1.2 )
+* Support for attribute framespacing: rendering ( Section 3.5.1.2 )
+* Support for attribute equalrows: rendering ( Section 3.5.1.2 )
+* Support for attribute equalcolumns: rendering ( Section 3.5.1.2 )
+* Support for attribute displaystyle: rendering ( Section 3.5.1.2 )
+* Support for attribute side: rendering ( Section 3.5.1.2 )
+* Support for attribute minlabelspacing: rendering ( Section 3.5.1.2 )
+
+= mtr =
+
+* Support for attribute rowalign: loading, saving, rendering ( Section 3.5.2.2 )
+* Support for attribute columnalign: loading, saving, rendering ( Section 3.5.2.2 )
+* Support for attribute groupalign: loading, saving, rendering ( Section 3.5.2.2, 3.5.5, 3.5.5.7 )
+
+= mlabeledtr =
+
+* Support for <mlabeledtr> element: loading, saving, rendering ( Section 3.5.3 )
+* Support for attribute rowalign: loading, saving, rendering ( Section 3.5.3.2, 3.5.2.2 )
+* Support for attribute columnalign: loading, saving, rendering ( Section 3.5.3.2, 3.5.2.2 )
+* Support for attribute groupalign: loading, saving, rendering ( Section 3.5.3.2, 3.5.2.2, 3.5.5, 3.5.5.7 )
+
+= mtd =
+
+* Support for attribute rowspan: loading, saving, rendering ( Section 3.5.4.2 )
+* Support for attribute columnspan: loading, saving, rendering ( Section 3.5.4.2 )
+* Support for attribute rowalign: loading, saving, rendering ( Section 3.5.4.2 )
+* Support for attribute columnalign: loading, saving, rendering ( Section 3.5.4.2 )
+* Support for attribute groupalign: loading, saving, rendering ( Section 3.5.4.2, 3.5.5, 3.5.5.7 )
+
+= malignmark =
+
+* Support for <malignmark> element: loading, saving, rendering ( Section 3.5.5.4, 3.5.5.9 )
+* Support for attribute edge: loading, saving, rendering ( Section 3.5.5.5 )
+
+= maligngroup =
+
+* Support for <maligngroup> element: loading, saving, rendering ( Section 3.5.5.1, 3.5.5.2, 3.5.5.3, 3.5.5.9 )
+* Support for attribute gropualign: loading, saving, rendering ( Section 3.5.5.6, 3.5.5.7 )
+
+== Enlivening Expressions ==
+
+= maction =
+
+* Support for toggle actiontype ( Section 3.6.1.1 ) OPTIONAL
+* Support for statusline actiontype ( Section 3.6.1.1 ) OPTIONAL
+* Support for tooltip actiontype ( Section 3.6.1.1 ) OPTIONAL
+* Support for highlight actiontype ( Section 3.6.1.1 ) OPTIONAL
+
+
+== Misc ==
+
+* Full support for named unicode characters, ( Chapter 6 )
diff --git a/lib/kformula/actionelement.cc b/lib/kformula/actionelement.cc
new file mode 100644
index 00000000..fdee73a5
--- /dev/null
+++ b/lib/kformula/actionelement.cc
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "creationstrategy.h"
+#include "actionelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+ActionElement::ActionElement( BasicElement* parent ) : SequenceElement( parent ),
+ m_selection( 0 )
+{
+}
+
+bool ActionElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ m_actionType = element.attribute( "actiontype" );
+ QString selectionStr = element.attribute( "selection" );
+ if ( ! selectionStr.isNull() ) {
+ bool ok;
+ m_selection = selectionStr.toUInt( &ok );
+ if ( ! ok ) m_selection = 0;
+ }
+
+ return true;
+}
+
+int ActionElement::buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n)
+{
+ if ( ! n.isElement() )
+ return -1;
+ QDomElement e = n.toElement();
+ QString tag = e.tagName().lower();
+ BasicElement* child = getCreationStrategy()->createElement( tag, e );
+ if ( child == 0 )
+ return -1;
+ child->setParent( this );
+ if ( child->buildFromMathMLDom( e ) == -1 ) {
+ delete child;
+ return -1;
+ }
+ list.append( child );
+ parse();
+ return 1;
+}
+
+void ActionElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ if ( ! m_actionType.isNull() ) {
+ element.setAttribute( "actiontype", m_actionType );
+ }
+ if ( m_selection ) {
+ element.setAttribute( "selection", QString( "%1" ).arg( m_selection ) );
+ }
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/actionelement.h b/lib/kformula/actionelement.h
new file mode 100644
index 00000000..d4a0906b
--- /dev/null
+++ b/lib/kformula/actionelement.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef ACTIONELEMENT_H
+#define ACTIONELEMENT_H
+
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+/**
+ * Support for action elements in MathML. According to MathML spec
+ * (Section 3.6.1.1), a MathML conformant application is not required to
+ * recognize any single actiontype.
+ */
+class ActionElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+ ActionElement( BasicElement* parent = 0 );
+ virtual int buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n);
+
+private:
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+ virtual QString getElementName() const { return "maction"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+
+ QString m_actionType;
+ uint m_selection;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // ACTIONELEMENT_H
diff --git a/lib/kformula/basicelement.cc b/lib/kformula/basicelement.cc
new file mode 100644
index 00000000..82913cec
--- /dev/null
+++ b/lib/kformula/basicelement.cc
@@ -0,0 +1,400 @@
+/* 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 <qstring.h>
+#include <kdebug.h>
+
+#include "contextstyle.h"
+#include "basicelement.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+using namespace std;
+
+
+int BasicElement::evilDestructionCount = 0;
+
+BasicElement::BasicElement( BasicElement* p )
+ : parent( p ), m_baseline( 0 ), elementType( 0 )
+{
+ setX( 0 );
+ setY( 0 );
+ setWidth( 0 );
+ setHeight( 0 );
+ evilDestructionCount++;
+}
+
+BasicElement::~BasicElement()
+{
+ evilDestructionCount--;
+}
+
+BasicElement::BasicElement( const BasicElement& other )
+ : parent( 0 ),
+ m_baseline( other.m_baseline ),
+ elementType( other.elementType )
+{
+ setX( other.getX() );
+ setY( other.getY() );
+ setWidth( other.getWidth() );
+ setHeight( other.getHeight() );
+ evilDestructionCount++;
+}
+
+
+bool BasicElement::readOnly( const BasicElement* /*child*/ ) const
+{
+ return parent->readOnly( this );
+}
+
+
+FormulaElement* BasicElement::formula()
+{
+ //if ( parent != 0 ) {
+ return parent->formula();
+ //}
+ //return 0;
+}
+
+
+/**
+ * Returns the element the point is in.
+ */
+BasicElement* BasicElement::goToPos( FormulaCursor*, bool&,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ luPixel x = point.x() - (parentOrigin.x() + getX());
+ if ((x >= 0) && (x < getWidth())) {
+ luPixel y = point.y() - (parentOrigin.y() + getY());
+ if ((y >= 0) && (y < getHeight())) {
+ return this;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Returns our position inside the widget.
+ */
+LuPixelPoint BasicElement::widgetPos()
+{
+ luPixel x = 0;
+ luPixel y = 0;
+ for (BasicElement* element = this; element != 0; element = element->parent) {
+ x += element->getX();
+ y += element->getY();
+ }
+ return LuPixelPoint(x, y);
+}
+
+
+/**
+ * Sets the cursor inside this element to its start position.
+ * For most elements that is the main child.
+ */
+void BasicElement::goInside(FormulaCursor* cursor)
+{
+ BasicElement* mainChild = getMainChild();
+ if (mainChild != 0) {
+ mainChild->goInside(cursor);
+ }
+}
+
+
+void BasicElement::entered( SequenceElement* /*child*/ )
+{
+ formula()->tell( "" );
+}
+
+
+/**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+void BasicElement::moveLeft(FormulaCursor* cursor, BasicElement*)
+{
+ getParent()->moveLeft(cursor, this);
+}
+
+
+/**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+void BasicElement::moveRight(FormulaCursor* cursor, BasicElement*)
+{
+ getParent()->moveRight(cursor, this);
+}
+
+
+/**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+void BasicElement::normalize(FormulaCursor* cursor, Direction direction)
+{
+ BasicElement* element = getMainChild();
+ if (element != 0) {
+ if (direction == beforeCursor) {
+ element->moveLeft(cursor, this);
+ }
+ else {
+ element->moveRight(cursor, this);
+ }
+ }
+}
+
+
+QDomElement BasicElement::getElementDom( QDomDocument& doc)
+{
+ QDomElement de = doc.createElement(getTagName());
+ writeDom(de);
+ return de;
+}
+
+
+void BasicElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
+{
+ QDomElement de = doc.createElement( oasisFormat ? "math:" + getElementName() : getElementName() );
+ writeMathMLAttributes( de );
+ writeMathMLContent( doc, de, oasisFormat );
+ parent.appendChild( de );
+}
+
+bool BasicElement::buildFromDom(QDomElement element)
+{
+ if (element.tagName() != getTagName()) {
+ kdWarning( DEBUGID ) << "Wrong tag name " << element.tagName().latin1() << " for " << getTagName().latin1() << ".\n";
+ return false;
+ }
+ if (!readAttributesFromDom(element)) {
+ return false;
+ }
+ QDomNode node = element.firstChild();
+ return readContentFromDom(node);
+}
+
+int BasicElement::buildFromMathMLDom(QDomElement element)
+{/*
+ if (element.tagName() != getTagName()) {
+ kdWarning( DEBUGID ) << "Wrong tag name " << element.tagName().latin1() << " for " << getTagName().latin1() << ".\n";
+ return false;
+ }*/
+ if (!readAttributesFromMathMLDom(element)) {
+ return -1;
+ }
+ QDomNode node = element.firstChild();
+ return readContentFromMathMLDom(node);
+}
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void BasicElement::writeDom(QDomElement)
+{
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool BasicElement::readAttributesFromDom(QDomElement)
+{
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool BasicElement::readContentFromDom(QDomNode&)
+{
+ return true;
+}
+
+/**
+ * Returns a SequenceElement constructed from the nodes first child
+ * if the nodes name matches the given name.
+ */
+bool BasicElement::buildChild( SequenceElement* child, QDomNode node, QString name )
+{
+ if (node.isElement()) {
+ QDomElement e = node.toElement();
+ if (e.tagName().upper() == name) {
+ QDomNode nodeInner = e.firstChild();
+ if (nodeInner.isElement()) {
+ QDomElement element = nodeInner.toElement();
+ return child->buildFromDom( element );
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Reads our attributes from the MathML element.
+ * Returns false if it failed.
+ */
+bool BasicElement::readAttributesFromMathMLDom(const QDomElement& )
+{
+ return true;
+}
+
+/**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+int BasicElement::readContentFromMathMLDom(QDomNode&)
+{
+ return 1;
+}
+
+QString BasicElement::toLatex()
+{
+ return "{}";
+}
+
+/**
+ * Utility function that sets the size type and returns the size value from
+ * a MathML attribute string with unit as defined in Section 2.4.4.2
+ *
+ * @returns the size value
+ *
+ * @param str the attribute string.
+ * @param st size type container. It will be properly assigned to its size
+ * type or NoSize if str is invalid
+ */
+double BasicElement::getSize( const QString& str, SizeType* st )
+{
+ int index = str.find( "%" );
+ if ( index != -1 ) {
+ return str2size( str, st, index, RelativeSize ) / 100.0;
+ }
+ index = str.find( "pt", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, AbsoluteSize );
+ }
+ index = str.find( "mm", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, AbsoluteSize ) * 72.0 / 20.54;
+ }
+ index = str.find( "cm", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, AbsoluteSize ) * 72.0 / 2.54;
+ }
+ index = str.find( "in", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, AbsoluteSize ) * 72.0;
+ }
+ index = str.find( "em", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, RelativeSize );
+ }
+ index = str.find( "ex", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, RelativeSize );
+ }
+ index = str.find( "pc", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, AbsoluteSize ) * 12.0;
+ }
+ index = str.find( "px", 0, false );
+ if ( index != -1 ) {
+ return str2size( str, st, index, PixelSize );
+ }
+ // If there's no unit, assume 'pt'
+ return str2size( str, st, str.length(),AbsoluteSize );
+}
+
+SizeType BasicElement::getSpace( const QString& str )
+{
+ if ( str == "negativeveryverythinmathspace" ) {
+ return NegativeVeryVeryThinMathSpace;
+ }
+ if ( str == "negativeverythinmathspace" ) {
+ return NegativeVeryThinMathSpace;
+ }
+ if ( str == "negativethinmathspace" ) {
+ return NegativeThinMathSpace;
+ }
+ if ( str == "negativemediummathspace" ) {
+ return NegativeMediumMathSpace;
+ }
+ if ( str == "negativethickmathspace" ) {
+ return NegativeThickMathSpace;
+ }
+ if ( str == "negativeverythickmathspace" ) {
+ return NegativeVeryThickMathSpace;
+ }
+ if ( str == "negativeveryverythickmathspace" ) {
+ return NegativeVeryVeryThickMathSpace;
+ }
+ if ( str == "veryverythinmathspace" ) {
+ return VeryVeryThinMathSpace;
+ }
+ if ( str == "verythinmathspace" ) {
+ return VeryThinMathSpace;
+ }
+ if ( str == "thinmathspace" ) {
+ return ThinMathSpace;
+ }
+ if ( str == "mediummathspace" ) {
+ return MediumMathSpace;
+ }
+ if ( str == "thickmathspace" ) {
+ return ThickMathSpace;
+ }
+ if ( str == "verythickmathspace" ) {
+ return VeryThickMathSpace;
+ }
+ if ( str == "veryverythickmathspace" ) {
+ return VeryVeryThickMathSpace;
+ }
+ return NoSize;
+}
+
+
+/**
+ * Used internally by getSize()
+ */
+double BasicElement::str2size( const QString& str, SizeType *st, uint index, SizeType type )
+{
+ QString num = str.left( index );
+ bool ok;
+ double size = num.toDouble( &ok );
+ if ( ok ) {
+ if ( st ) {
+ *st = type;
+ }
+ return size;
+ }
+ if ( st ) {
+ *st = NoSize;
+ }
+ return -1;
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/basicelement.h b/lib/kformula/basicelement.h
new file mode 100644
index 00000000..ee9cffe0
--- /dev/null
+++ b/lib/kformula/basicelement.h
@@ -0,0 +1,548 @@
+/* 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.
+*/
+
+#ifndef BASICELEMENT_H
+#define BASICELEMENT_H
+
+// Qt Include
+#include <qdom.h>
+#include <qptrlist.h>
+#include <qstring.h>
+
+// KDE Include
+
+// Formula include
+#include "contextstyle.h"
+#include "kformuladefs.h"
+
+class QKeyEvent;
+
+class KCommand;
+
+KFORMULA_NAMESPACE_BEGIN
+
+class ComplexElement;
+class Container;
+class ElementType;
+class ElementVisitor;
+class FontCommand;
+class FormulaCursor;
+class FormulaElement;
+class SequenceElement;
+class StyleElement;
+
+
+/**
+ * Basis of every formula element. An element is used basically by
+ * other elements and by the @ref FormulaCursor .
+ *
+ * Each element knows its size (a rect that includes all children)
+ * and how to draw itself. See @ref calcSizes and @ref draw .
+ *
+ * An element might contain valid cursor position. If the cursor
+ * enters the element it must find the next valid position
+ * depending on the direction in that the cursor moves and the
+ * element it comes from. There might also be some flags inside the
+ * cursor that tell how it wants to move. See @ref moveLeft ,
+ * @ref moveRight , @ref moveUp , @ref moveDown .
+ *
+ * To build a tree an element must own children. If there are children
+ * there must be a main child. This is the child that might be used to
+ * replace the element. See @ref getMainChild().
+ *
+ * If there can be children you might want to @ref insert and @ref remove
+ * them. After a removal the element might be senseless.
+ * (See @ref isSenseless )
+ * If it is it must be removed.
+ */
+class BasicElement
+{
+ friend class SequenceElement;
+ friend class SequenceParser;
+
+ BasicElement& operator= ( const BasicElement& ) { return *this; }
+public:
+
+ /*
+ * Each element might contain children. Each child needs
+ * its own unique number. It is not guaranteed, however,
+ * that the number stays the same all the time.
+ * (The SequenceElement's children are simply counted.)
+ */
+
+ BasicElement(BasicElement* parent = 0);
+ virtual ~BasicElement();
+
+ // deep copy
+ BasicElement( const BasicElement& );
+
+ virtual BasicElement* clone() = 0;
+
+ /**
+ * Visit this element. An implementation of the visitor pattern.
+ */
+ virtual bool accept( ElementVisitor* ) = 0;
+
+ /**
+ * @returns whether the child should be read-only. The idea is
+ * that a read-only parent has read-only children.
+ */
+ virtual bool readOnly( const BasicElement* child ) const;
+
+ /**
+ * Provide fast access to the rootElement for each child.
+ */
+ virtual FormulaElement* formula();
+
+ /**
+ * Provide fast access to the rootElement for each child.
+ */
+ virtual const FormulaElement* formula() const { return parent->formula(); }
+
+ /**
+ * @returns the character that represents this element. Used for
+ * parsing a sequence.
+ * This is guaranteed to be QChar::null for all non-text elements.
+ */
+ virtual QChar getCharacter() const { return QChar::null; }
+
+ /**
+ * @returns the type of this element. Used for
+ * parsing a sequence.
+ */
+ virtual TokenType getTokenType() const { return ELEMENT; }
+
+ /**
+ * @returns true if we don't want to see the element.
+ */
+ virtual bool isInvisible() const { return false; }
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ /**
+ * Returns our position inside the widget.
+ */
+ LuPixelPoint widgetPos();
+
+
+ // drawing
+ //
+ // Drawing depends on a context which knows the required properties like
+ // fonts, spaces and such.
+ // It is essential to calculate elements size with the same context
+ // before you draw.
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style ) = 0;
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin ) = 0;
+
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* /*cmd*/ ) {}
+
+ // navigation
+ //
+ // The elements are responsible to handle cursor movement themselves.
+ // To do this they need to know the direction the cursor moves and
+ // the element it comes from.
+ //
+ // The cursor might be in normal or in selection mode.
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor*, BasicElement*) {}
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor*, BasicElement* ) {}
+
+ /**
+ * Moves the cursor to the first position in this sequence.
+ * (That is before the first child.)
+ */
+ virtual void moveHome(FormulaCursor*) {}
+
+ /**
+ * Moves the cursor to the last position in this sequence.
+ * (That is behind the last child.)
+ */
+ virtual void moveEnd(FormulaCursor*) {}
+
+ /**
+ * Sets the cursor inside this element to its start position.
+ * For most elements that is the main child.
+ */
+ virtual void goInside(FormulaCursor* cursor);
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* /*child*/ );
+
+ // children
+
+ /**
+ * Removes the child. If this was the main child this element might
+ * request its own removal.
+ * The cursor is the one that caused the removal. It has to be moved
+ * to the place any user expects the cursor after that particular
+ * element has been removed.
+ */
+ //virtual void removeChild(FormulaCursor* cursor, BasicElement* child) {}
+
+
+ // main child
+ //
+ // If an element has children one has to become the main one.
+
+ virtual SequenceElement* getMainChild() { return 0; }
+ //virtual void setMainChild(SequenceElement*) {}
+
+
+ // editing
+ //
+ // Insert and remove children.
+
+ /**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction.
+ *
+ * The list will be emptied but stays the property of the caller.
+ */
+ virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction) {}
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ */
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction) {}
+
+ /**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+ virtual void normalize(FormulaCursor*, Direction);
+
+
+ /**
+ * Returns wether the element has no more useful
+ * children (except its main child) and should therefore
+ * be replaced by its main child's content.
+ */
+ virtual bool isSenseless() { return false; }
+
+ /**
+ * Returns the child at the cursor.
+ */
+ virtual BasicElement* getChild(FormulaCursor*, Direction = beforeCursor) { return 0; }
+
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor*, BasicElement*) {}
+
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ virtual void childWillVanish(FormulaCursor*, BasicElement*) {}
+
+
+ /**
+ * Callback for the tabs among our children. Needed for alignment.
+ */
+ virtual void registerTab( BasicElement* /*tab*/ ) {}
+
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* ) { return 0; }
+
+ /**
+ * Parses the input. It's the container which does create
+ * new elements because it owns the undo stack. But only the
+ * sequence knows what chars are allowed.
+ */
+ virtual KCommand* input( Container*, QKeyEvent* ) { return 0; }
+
+ // basic support
+
+ const BasicElement* getParent() const { return parent; }
+ BasicElement* getParent() { return parent; }
+ void setParent(BasicElement* p) { parent = p; }
+
+ luPixel getX() const { return m_x; }
+ luPixel getY() const { return m_y; }
+
+ void setX( luPixel x ) { m_x = x; }
+ void setY( luPixel y ) { m_y = y; }
+
+ //QSize getSize() { return size; }
+
+ luPixel getWidth() const { return m_width; }
+ luPixel getHeight() const { return m_height; }
+
+ void setWidth( luPixel width ) { m_width = width; }
+ void setHeight( luPixel height ) { m_height = height; }
+
+ luPixel getBaseline() const { return m_baseline; }
+ void setBaseline( luPixel line ) { m_baseline = line; }
+
+ luPixel axis( const ContextStyle& style,
+ ContextStyle::TextStyle tstyle,
+ double factor ) const {
+ return getBaseline() - style.axisHeight( tstyle, factor ); }
+
+ /**
+ * @return a QDomElement that contain as DomChildren the
+ * children, and as attribute the attribute of this
+ * element.
+ */
+ QDomElement getElementDom( QDomDocument& doc);
+
+ /**
+ * Same as above, just MathML.
+ * It shouldn't be redefined but for exceptional cases, use the general writeMathML* API instead
+ */
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
+
+ /**
+ * Set this element attribute, build children and
+ * call their buildFromDom.
+ */
+ bool buildFromDom(QDomElement element);
+
+ /**
+ * Set this element attribute, build children and call
+ * their builFromMathMLDom.
+ * Returns the number of nodes processed or -1 if it failed.
+ */
+ int buildFromMathMLDom( QDomElement element );
+
+ // debug
+ static int getEvilDestructionCount() { return evilDestructionCount; }
+
+ /**
+ * @returns our type. This is an object from our parent's syntax tree
+ * or 0 if there was a very bad parsing error.
+ */
+ ElementType* getElementType() const { return elementType; }
+
+ /**
+ * Sets a new type. This is done during parsing.
+ */
+ virtual void setElementType(ElementType* t) { elementType = t; }
+
+ virtual void setStyle(StyleElement*) {}
+
+ virtual QString getElementName() const { return ""; };
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "BASIC"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ virtual void writeMathMLAttributes( QDomElement& /*element*/ ) const {};
+ virtual void writeMathMLContent( QDomDocument& /*doc*/,
+ QDomElement& /*element*/,
+ bool /*oasisFormat*/ ) const {};
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ /**
+ * Returns if the SequenceElement could be constructed from the nodes first child.
+ * The node name must match the given name.
+ *
+ * This is a service for all subclasses that contain children.
+ */
+ bool buildChild( SequenceElement* child, QDomNode node, QString name );
+
+
+ /**
+ * Reads our attributes from the MathML element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+
+ /**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read. It is sometimes needed to read more than one node
+ * (e. g. for fence operators).
+ * Returns the number of nodes processed or -1 if it failed.
+ */
+ virtual int readContentFromMathMLDom(QDomNode& node);
+
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString() { return ""; }
+
+ /**
+ * Utility function that sets the size type and returns the size value from
+ * a MathML attribute string with unit as defined in Section 2.4.4.2
+ *
+ * @returns the size value
+ *
+ * @param str the attribute string.
+ * @param st size type container. It will be properly assigned to its size
+ * type or NoSize if str is invalid
+ */
+ double getSize( const QString& str, SizeType* st );
+
+ SizeType getSpace( const QString& str );
+
+private:
+
+ /**
+ * Used internally by getSize()
+ */
+ double str2size( const QString& str, SizeType* st, uint index, SizeType type );
+
+ /**
+ * Our parent.
+ * The parent might not be null except for the FormulaElement
+ * that is the top of the element tree.
+ */
+ BasicElement* parent;
+
+ /**
+ * This elements size.
+ */
+ //QSize size;
+ luPixel m_width;
+ luPixel m_height;
+
+ /**
+ * Our position relative to our parent.
+ */
+ //KoPoint position;
+ luPixel m_x;
+ luPixel m_y;
+
+ /**
+ * The position of our base line from
+ * the upper border. A sequence aligns its elements
+ * along this line.
+ *
+ * There are elements (like matrix) that don't have a base line. It is
+ * -1 in this case. The alignment is done using the middle line.
+ */
+ luPixel m_baseline;
+
+ /**
+ * The position of our middle line from
+ * the upper border. The strike out position.
+ *
+ * This will have to go. (?)
+ */
+ //luPixel m_axis;
+
+ /**
+ * The token that describes our type. Please note that we don't
+ * own it.
+ */
+ ElementType* elementType;
+
+ // debug
+ static int evilDestructionCount;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // BASICELEMENT_H
diff --git a/lib/kformula/bracketelement.cc b/lib/kformula/bracketelement.cc
new file mode 100644
index 00000000..2e00af12
--- /dev/null
+++ b/lib/kformula/bracketelement.cc
@@ -0,0 +1,1005 @@
+/* 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 <qptrlist.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qpointarray.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "bracketelement.h"
+#include "elementvisitor.h"
+#include "fontstyle.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+SingleContentElement::SingleContentElement(BasicElement* parent )
+ : BasicElement( parent )
+{
+ content = new SequenceElement( this );
+}
+
+
+SingleContentElement::SingleContentElement( const SingleContentElement& other )
+ : BasicElement( other )
+{
+ content = new SequenceElement( other.content );
+ content->setParent( this );
+}
+
+
+SingleContentElement::~SingleContentElement()
+{
+ delete content;
+}
+
+
+QChar SingleContentElement::getCharacter() const
+{
+ // This is meant to make the SingleContentElement text only.
+ // This "fixes" the parenthesis problem (parenthesis too large).
+ // I'm not sure if we really want this. There should be better ways.
+ if ( content->isTextOnly() ) {
+ return '\\';
+ }
+ return content->getCharacter();
+}
+
+BasicElement* SingleContentElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+
+ e = content->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ return this;
+ }
+ return 0;
+}
+
+void SingleContentElement::dispatchFontCommand( FontCommand* cmd )
+{
+ content->dispatchFontCommand( cmd );
+}
+
+void SingleContentElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ //bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ content->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+}
+
+void SingleContentElement::moveRight(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ //bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ content->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ }
+}
+
+void SingleContentElement::moveUp(FormulaCursor* cursor, BasicElement* /*from*/)
+{
+ getParent()->moveUp(cursor, this);
+}
+
+void SingleContentElement::moveDown(FormulaCursor* cursor, BasicElement* /*from*/)
+{
+ getParent()->moveDown(cursor, this);
+}
+
+void SingleContentElement::remove( FormulaCursor* cursor,
+ QPtrList<BasicElement>& removedChildren,
+ Direction direction )
+{
+ switch (cursor->getPos()) {
+ case contentPos:
+ BasicElement* parent = getParent();
+ parent->selectChild(cursor, this);
+ parent->remove(cursor, removedChildren, direction);
+ }
+}
+
+void SingleContentElement::normalize( FormulaCursor* cursor, Direction direction )
+{
+ if (direction == beforeCursor) {
+ content->moveLeft(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+}
+
+SequenceElement* SingleContentElement::getMainChild()
+{
+ return content;
+}
+
+void SingleContentElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ if (child == content) {
+ cursor->setTo(this, contentPos);
+ }
+}
+
+void SingleContentElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ QDomDocument doc = element.ownerDocument();
+
+ QDomElement con = doc.createElement("CONTENT");
+ con.appendChild(content->getElementDom(doc));
+ element.appendChild(con);
+}
+
+bool SingleContentElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ if ( !buildChild( content, node, "CONTENT" ) ) {
+ kdWarning( DEBUGID ) << "Empty content in " << getTagName() << endl;
+ return false;
+ }
+ node = node.nextSibling();
+
+ return true;
+}
+
+int SingleContentElement::readContentFromMathMLDom( QDomNode& node )
+{
+ if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
+ return -1;
+ }
+
+ int nodeCounter = content->buildMathMLChild( node );
+ if ( nodeCounter == -1 ) {
+ kdWarning( DEBUGID) << "Empty content in SingleContentElement\n";
+ return -1;
+ }
+
+ return nodeCounter;
+}
+
+void SingleContentElement::writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const
+{
+ content->writeMathML( doc, element, oasisFormat );
+}
+
+
+
+BracketElement::BracketElement(SymbolType l, SymbolType r, BasicElement* parent)
+ : SingleContentElement(parent),
+ left( 0 ), right( 0 ),
+ leftType( l ), rightType( r ),
+ m_operator( false ), m_customLeft( false ), m_customRight( false )
+{
+}
+
+
+BracketElement::~BracketElement()
+{
+ delete left;
+ delete right;
+}
+
+
+BracketElement::BracketElement( const BracketElement& other )
+ : SingleContentElement( other ),
+ left( 0 ), right( 0 ),
+ leftType( other.leftType ), rightType( other.rightType ),
+ m_operator( other.m_operator ),
+ m_customLeft( other.m_customLeft ), m_customRight( other.m_customRight )
+{
+}
+
+
+bool BracketElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void BracketElement::entered( SequenceElement* /*child*/ )
+{
+ formula()->tell( i18n( "Delimited list" ) );
+}
+
+
+BasicElement* BracketElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+ e = getContent()->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+
+ // We are in one of those gaps.
+ luPixel dx = point.x() - myPos.x();
+ luPixel dy = point.y() - myPos.y();
+
+ if ((dx > getContent()->getX()+getContent()->getWidth()) ||
+ (dy > getContent()->getY()+getContent()->getHeight())) {
+ getContent()->moveEnd(cursor);
+ handled = true;
+ return getContent();
+ }
+ return this;
+ }
+ return 0;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void BracketElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ SequenceElement* content = getContent();
+ content->calcSizes( context, tstyle, istyle, style );
+
+ //if ( left == 0 ) {
+ delete left;
+ delete right;
+ left = context.fontStyle().createArtwork( leftType );
+ right = context.fontStyle().createArtwork( rightType );
+ //}
+
+ double factor = style.sizeFactor();
+ if (content->isTextOnly()) {
+ left->calcSizes(context, tstyle, factor);
+ right->calcSizes(context, tstyle, factor);
+
+ setBaseline(QMAX(content->getBaseline(),
+ QMAX(left->getBaseline(), right->getBaseline())));
+
+ content->setY(getBaseline() - content->getBaseline());
+ left ->setY(getBaseline() - left ->getBaseline());
+ right ->setY(getBaseline() - right ->getBaseline());
+
+ //setMidline(content->getY() + content->getMidline());
+ setHeight(QMAX(content->getY() + content->getHeight(),
+ QMAX(left ->getY() + left ->getHeight(),
+ right->getY() + right->getHeight())));
+ }
+ else {
+ //kdDebug( DEBUGID ) << "BracketElement::calcSizes " << content->axis( context, tstyle ) << " " << content->getHeight() << endl;
+ luPixel contentHeight = 2 * QMAX( content->axis( context, tstyle, factor ),
+ content->getHeight() - content->axis( context, tstyle, factor ) );
+ left->calcSizes( context, tstyle, factor, contentHeight );
+ right->calcSizes( context, tstyle, factor, contentHeight );
+
+ // height
+ setHeight(QMAX(contentHeight,
+ QMAX(left->getHeight(), right->getHeight())));
+ //setMidline(getHeight() / 2);
+
+ content->setY(getHeight() / 2 - content->axis( context, tstyle, factor ));
+ setBaseline(content->getBaseline() + content->getY());
+
+ if ( left->isNormalChar() ) {
+ left->setY(getBaseline() - left->getBaseline());
+ }
+ else {
+ left->setY((getHeight() - left->getHeight())/2);
+ }
+ if ( right->isNormalChar() ) {
+ right->setY(getBaseline() - right->getBaseline());
+ }
+ else {
+ right->setY((getHeight() - right->getHeight())/2);
+ }
+
+// kdDebug() << "BracketElement::calcSizes" << endl
+// << "getHeight(): " << getHeight() << endl
+// << "left->getHeight(): " << left->getHeight() << endl
+// << "right->getHeight(): " << right->getHeight() << endl
+// << "left->getY(): " << left->getY() << endl
+// << "right->getY(): " << right->getY() << endl
+// << endl;
+ }
+
+ // width
+ setWidth(left->getWidth() + content->getWidth() + right->getWidth());
+ content->setX(left->getWidth());
+ right ->setX(left->getWidth()+content->getWidth());
+}
+
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void BracketElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ SequenceElement* content = getContent();
+ content->draw(painter, r, context, tstyle, istyle, style, myPos);
+
+ if (content->isTextOnly()) {
+ left->draw(painter, r, context, tstyle, style, myPos);
+ right->draw(painter, r, context, tstyle, style, myPos);
+ }
+ else {
+ double factor = style.sizeFactor();
+ luPixel contentHeight = 2 * QMAX(content->axis( context, tstyle, factor ),
+ content->getHeight() - content->axis( context, tstyle, factor ));
+ left->draw(painter, r, context, tstyle, style, contentHeight, myPos);
+ right->draw(painter, r, context, tstyle, style, contentHeight, myPos);
+ }
+
+ // Debug
+#if 0
+ painter.setBrush( Qt::NoBrush );
+ painter.setPen( Qt::red );
+ painter.drawRect( context.layoutUnitToPixelX( myPos.x()+left->getX() ),
+ context.layoutUnitToPixelY( myPos.y()+left->getY() ),
+ context.layoutUnitToPixelX( left->getWidth() ),
+ context.layoutUnitToPixelY( left->getHeight() ) );
+ painter.drawRect( context.layoutUnitToPixelX( myPos.x()+right->getX() ),
+ context.layoutUnitToPixelY( myPos.y()+right->getY() ),
+ context.layoutUnitToPixelX( right->getWidth() ),
+ context.layoutUnitToPixelY( right->getHeight() ) );
+#endif
+}
+
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void BracketElement::writeDom(QDomElement element)
+{
+ SingleContentElement::writeDom(element);
+ element.setAttribute("LEFT", leftType);
+ element.setAttribute("RIGHT", rightType);
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool BracketElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ QString leftStr = element.attribute("LEFT");
+ if(!leftStr.isNull()) {
+ leftType = static_cast<SymbolType>(leftStr.toInt());
+ }
+ QString rightStr = element.attribute("RIGHT");
+ if(!rightStr.isNull()) {
+ rightType = static_cast<SymbolType>(rightStr.toInt());
+ }
+ return true;
+}
+
+/**
+ * Reads our attributes from the MathML element.
+ * Returns false if it failed.
+ */
+bool BracketElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ if ( element.tagName().lower() == "mo" ) {
+ m_operator = true;
+ // TODO: parse attributes in section 3.2.5.2
+ }
+ else { // mfenced, see attributes in section 3.3.8.2
+ leftType = LeftRoundBracket;
+ rightType = RightRoundBracket;
+ QString openStr = element.attribute( "open" ).stripWhiteSpace();
+ if ( !openStr.isNull() ) {
+ m_customLeft = true;
+ if ( openStr == "[" )
+ leftType = LeftSquareBracket;
+ else if ( openStr == "]" )
+ leftType = RightSquareBracket;
+ else if ( openStr == "{" )
+ leftType = LeftCurlyBracket;
+ else if ( openStr == "}" )
+ leftType = RightCurlyBracket;
+ else if ( openStr == "<" )
+ leftType = LeftCornerBracket;
+ else if ( openStr == ">" )
+ leftType = RightCornerBracket;
+ else if ( openStr == "(" )
+ leftType = LeftRoundBracket;
+ else if ( openStr == ")" )
+ leftType = RightRoundBracket;
+ else if ( openStr == "/" )
+ leftType = SlashBracket;
+ else if ( openStr == "\\" )
+ leftType = BackSlashBracket;
+ else // TODO: Check for entity references
+ leftType = LeftRoundBracket;
+ }
+ QString closeStr = element.attribute( "close" ).stripWhiteSpace();
+ if ( !closeStr.isNull() ) {
+ m_customRight = true;
+ if ( closeStr == "[" )
+ rightType = LeftSquareBracket;
+ else if ( closeStr == "]" )
+ rightType = RightSquareBracket;
+ else if ( closeStr == "{" )
+ rightType = LeftCurlyBracket;
+ else if ( closeStr == "}" )
+ rightType = RightCurlyBracket;
+ else if ( closeStr == "<" )
+ rightType = LeftCornerBracket;
+ else if ( closeStr == ">" )
+ rightType = RightCornerBracket;
+ else if ( closeStr == "(" )
+ rightType = LeftRoundBracket;
+ else if ( closeStr == ")" )
+ rightType = RightRoundBracket;
+ else if ( closeStr == "/" )
+ rightType = SlashBracket;
+ else if ( closeStr == "\\" )
+ rightType = BackSlashBracket;
+ else // TODO: Check for entity references
+ rightType = LeftRoundBracket;
+ }
+ m_separators = element.attribute( "separators" ).simplifyWhiteSpace();
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+int BracketElement::readContentFromMathMLDom(QDomNode& node)
+{
+ bool empty = false;
+ int nodeCounter = 0;
+ if ( m_operator ) {
+ node = node.parentNode();
+ QDomNode open = node;
+ QDomNode parent = node.parentNode();
+ if ( ! operatorType( node, true ) )
+ return -1;
+ int nodeNum = searchOperator( node );
+ if ( nodeNum == -1 ) // Closing bracket not found
+ return -1;
+ if ( nodeNum == 0 ) { // Empty content
+ empty = true;
+ }
+ else if ( nodeNum == 1 ) {
+ do {
+ node = node.nextSibling();
+ nodeCounter++;
+ } while ( ! node.isElement() );
+ }
+ else { // More than two elements inside, infer a mrow
+ nodeCounter += nodeNum;
+ kdWarning() << "NodeNum: " << nodeNum << endl;
+ QDomDocument doc = node.ownerDocument();
+ QDomElement de = doc.createElement( "mrow" );
+ int i = 0;
+ do {
+ QDomNode n = node.nextSibling();
+ de.appendChild( node.toElement() );
+ node = n;
+ } while ( ++i < nodeNum );
+ parent.insertAfter( de, open );
+ node = de;
+ kdWarning() << doc.toString() << endl;
+ }
+ }
+ else {
+ // if it's a mfence tag, we need to convert to equivalent expanded form.
+ // See section 3.3.8
+ while ( ! node.isNull() && ! node.isElement() )
+ node = node.nextSibling();
+ QDomNode next = node.nextSibling();
+ while ( ! next.isNull() && ! next.isElement() )
+ next = next.nextSibling();
+ if ( ! next.isNull()) {
+ QDomDocument doc = node.ownerDocument();
+ QDomNode parent = node.parentNode();
+ QString ns = parent.prefix();
+ QDomElement de = doc.createElementNS( ns, "mrow" );
+ uint pos = 0;
+ while ( ! node.isNull() ) {
+ QDomNode no = node.nextSibling();
+ while ( ! no.isNull() && ! no.isElement() )
+ no = no.nextSibling();
+ de.appendChild( node.toElement() );
+ if ( ! no.isNull() && ( m_separators.isNull() || ! m_separators.isEmpty() ) ) {
+ QDomElement sep = doc.createElementNS( ns, "mo" );
+ de.appendChild( sep );
+ if ( m_separators.isNull() ) {
+ sep.appendChild( doc.createTextNode( "," ) );
+ }
+ else {
+ if ( m_separators.at( pos ).isSpace() ) {
+ pos++;
+ }
+ sep.appendChild( doc.createTextNode( QString ( m_separators.at( pos ) ) ) );
+ }
+ if ( pos < m_separators.length() - 1 ) {
+ pos++;
+ }
+ }
+ node = no;
+ }
+ parent.appendChild( de );
+ node = parent.firstChild();
+ while ( ! node.isElement() )
+ node = node.nextSibling();
+ }
+ }
+ if ( ! empty ) {
+ int contentNumber = inherited::readContentFromMathMLDom( node );
+ if ( contentNumber == -1 )
+ return -1;
+ nodeCounter += contentNumber;
+ for (int i = 0; i < contentNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+ }
+ if ( m_operator ) {
+ int operatorNumber = operatorType( node, false );
+ if ( operatorNumber == -1 ) {
+ return -1;
+ }
+ nodeCounter += operatorNumber;
+ }
+ kdDebug( DEBUGID ) << "Number of bracket nodes: " << nodeCounter << endl;
+ return nodeCounter;
+}
+
+QString BracketElement::toLatex()
+{
+ QString ls,rs,cs;
+ cs=getContent()->toLatex();
+ ls="\\left"+latexString(leftType) + " ";
+ rs=" \\right"+latexString(rightType);
+
+ return ls+cs+rs;
+}
+
+QString BracketElement::latexString(char type)
+{
+ switch (type) {
+ case ']':
+ return "]";
+ case '[':
+ return "[";
+ case '{':
+ return "\\{";
+ case '}':
+ return "\\}";
+ case '(':
+ return "(";
+ case ')':
+ return ")";
+ case '|':
+ return "|";
+ case '<':
+ return "\\langle";
+ case '>':
+ return "\\rangle";
+ case '/':
+ return "/";
+ case '\\':
+ return "\\backslash";
+ }
+ return ".";
+}
+
+QString BracketElement::formulaString()
+{
+ return "(" + getContent()->formulaString() + ")";
+}
+
+int BracketElement::operatorType( QDomNode& node, bool open )
+{
+ int counter = 1;
+ SymbolType* type = open ? &leftType : &rightType;
+ while ( ! node.isNull() && ! node.isElement() ) {
+ node = node.nextSibling();
+ counter++;
+ }
+ if ( node.isElement() ) {
+ QDomElement e = node.toElement();
+ QDomNode child = e.firstChild();
+ if ( child.isEntityReference() ) {
+ kdWarning() << "Entity Reference\n";
+ QString name = node.nodeName();
+ // TODO: To fully support these, SymbolType has to be extended,
+ // and better Unicode support is a must
+ // CloseCurlyDoubleQuote 0x201D
+ // CloseCurlyQoute 0x2019
+ // LeftCeiling 0x2308
+ // LeftDoubleBracket 0x301A
+ // LeftFloor 0x230A
+ // OpenCurlyDoubleQuote 0x201C
+ // OpenCurlyQuote 0x2018
+ // RightCeiling 0x2309
+ // RightDoubleBracket 0x301B
+ // RightFloor 0x230B
+ if ( name == "LeftAngleBracket" ) {
+ *type = LeftCornerBracket;
+ }
+ else if ( name == "RightAngleBracket" ) {
+ *type = RightCornerBracket;
+ }
+ else {
+ if ( open ) {
+ *type = LeftRoundBracket;
+ }
+ else
+ *type = RightRoundBracket;
+ }
+ }
+ else {
+ QString s = e.text();
+ if ( s.isNull() )
+ return -1;
+ *type = static_cast<SymbolType>( QString::number( s.at( 0 ).latin1() ).toInt() );
+ }
+ }
+ else {
+ return -1;
+ }
+ return counter;
+}
+
+int BracketElement::searchOperator( const QDomNode& node )
+{
+ QDomNode n = node;
+ for ( int i = -2; ! n.isNull(); n = n.nextSibling() ) {
+ if ( n.isElement() ) {
+ i++;
+ QDomElement e = n.toElement();
+ if ( e.tagName().lower() == "mo" ) {
+ // Try to guess looking at attributes
+ QString form = e.attribute( "form" );
+ QString f;
+ if ( ! form.isNull() ) {
+ f = form.stripWhiteSpace().lower();
+ }
+ QString fence = e.attribute( "fence" );
+ if ( ! fence.isNull() ) {
+ if ( fence.stripWhiteSpace().lower() == "false" ) {
+ continue;
+ }
+ if ( ! f.isNull() ) {
+ if ( f == "postfix" ) {
+ return i;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+
+ // Guess looking at contents
+ QDomNode child = e.firstChild();
+ QString name;
+ if ( child.isText() )
+ name = child.toText().data().stripWhiteSpace();
+ else if ( child.isEntityReference() )
+ name = child.nodeName();
+ else
+ continue;
+ if ( name == ")"
+ || name == "]"
+ || name == "}"
+ || name == "CloseCurlyDoubleQuote"
+ || name == "CloseCurlyQuote"
+ || name == "RightAngleBracket"
+ || name == "RightCeiling"
+ || name == "RightDoubleBracket"
+ || name == "RightFloor" ) {
+ if ( f.isNull() || f == "postfix" )
+ return i;
+ }
+ if ( name == "("
+ || name == "["
+ || name == "{"
+ || name == "LeftAngleBracket"
+ || name == "LeftCeiling"
+ || name == "LeftDoubleBracket"
+ || name == "LeftFloor"
+ || name == "OpenCurlyQuote" ) {
+ if ( ! f.isNull() && f == "postfix" )
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+
+void BracketElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ if ( left->getType() != LeftRoundBracket ||
+ right->getType() != RightRoundBracket )
+ {
+ element.setAttribute( "open", QString( QChar( leftType ) ) );
+ element.setAttribute( "close", QString( QChar( rightType ) ) );
+ }
+ if ( ! m_separators.isNull() ) {
+ element.setAttribute( "separators", m_separators );
+ }
+}
+
+OverlineElement::OverlineElement( BasicElement* parent )
+ : SingleContentElement( parent )
+{
+}
+
+OverlineElement::~OverlineElement()
+{
+}
+
+OverlineElement::OverlineElement( const OverlineElement& other )
+ : SingleContentElement( other )
+{
+}
+
+
+bool OverlineElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void OverlineElement::entered( SequenceElement* /*child*/ )
+{
+ formula()->tell( i18n( "Overline" ) );
+}
+
+
+void OverlineElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ SequenceElement* content = getContent();
+ content->calcSizes(context, tstyle,
+ context.convertIndexStyleLower(istyle), style );
+
+ //luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, style.sizeFactor() ) );
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, style.sizeFactor() ) );
+ //luPixel unit = (content->getHeight() + distY)/ 3;
+
+ setWidth( content->getWidth() );
+ setHeight( content->getHeight() + distY );
+
+ content->setX( 0 );
+ content->setY( distY );
+ setBaseline(content->getBaseline() + content->getY());
+}
+
+void OverlineElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ SequenceElement* content = getContent();
+ content->draw( painter, r, context, tstyle,
+ context.convertIndexStyleLower( istyle ), style, myPos );
+
+ luPixel x = myPos.x();
+ luPixel y = myPos.y();
+ //int distX = context.getDistanceX(tstyle);
+ double factor = style.sizeFactor();
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+ //luPixel unit = (content->getHeight() + distY)/ 3;
+
+ painter.setPen( QPen( context.getDefaultColor(),
+ context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
+
+ painter.drawLine( context.layoutUnitToPixelX( x ),
+ context.layoutUnitToPixelY( y+distY/3 ),
+ context.layoutUnitToPixelX( x+content->getWidth() ),
+ context.layoutUnitToPixelY( y+distY/3 ) );
+}
+
+
+QString OverlineElement::toLatex()
+{
+ return "\\overline{" + getContent()->toLatex() + "}";
+}
+
+QString OverlineElement::formulaString()
+{
+ return getContent()->formulaString();
+}
+
+void OverlineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
+{
+ QDomElement de = doc.createElement( oasisFormat ? "math:mover" : "mover" );
+ SingleContentElement::writeMathML( doc, de, oasisFormat );
+ QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
+ // is this the right entity? Mozilla renders it correctly.
+ op.appendChild( doc.createEntityReference( "OverBar" ) );
+ de.appendChild( op );
+ parent.appendChild( de );
+}
+
+
+UnderlineElement::UnderlineElement( BasicElement* parent )
+ : SingleContentElement( parent )
+{
+}
+
+UnderlineElement::~UnderlineElement()
+{
+}
+
+
+UnderlineElement::UnderlineElement( const UnderlineElement& other )
+ : SingleContentElement( other )
+{
+}
+
+
+bool UnderlineElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void UnderlineElement::entered( SequenceElement* /*child*/ )
+{
+ formula()->tell( i18n( "Underline" ) );
+}
+
+
+void UnderlineElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ SequenceElement* content = getContent();
+ double factor = style.sizeFactor();
+ content->calcSizes(context, tstyle,
+ context.convertIndexStyleLower(istyle), style );
+
+ //luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle ) );
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+ //luPixel unit = (content->getHeight() + distY)/ 3;
+
+ setWidth( content->getWidth() );
+ setHeight( content->getHeight() + distY );
+
+ content->setX( 0 );
+ content->setY( 0 );
+ setBaseline(content->getBaseline() + content->getY());
+}
+
+void UnderlineElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ SequenceElement* content = getContent();
+ content->draw( painter, r, context, tstyle,
+ context.convertIndexStyleLower( istyle ), style, myPos );
+
+ luPixel x = myPos.x();
+ luPixel y = myPos.y();
+ //int distX = context.getDistanceX(tstyle);
+ //luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle ) );
+ //luPixel unit = (content->getHeight() + distY)/ 3;
+
+ double factor = style.sizeFactor();
+ painter.setPen( QPen( context.getDefaultColor(),
+ context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
+
+ painter.drawLine( context.layoutUnitToPixelX( x ),
+ context.layoutUnitToPixelY( y+getHeight()-context.getLineWidth( factor ) ),
+ context.layoutUnitToPixelX( x+content->getWidth() ),
+ context.layoutUnitToPixelY( y+getHeight()-context.getLineWidth( factor ) ) );
+}
+
+
+QString UnderlineElement::toLatex()
+{
+ return "\\underline{" + getContent()->toLatex() + "}";
+}
+
+QString UnderlineElement::formulaString()
+{
+ return getContent()->formulaString();
+}
+
+void UnderlineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
+{
+ QDomElement de = doc.createElement( oasisFormat ? "math:munder" : "munder" );
+ SingleContentElement::writeMathML( doc, de, oasisFormat );
+ QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
+ // is this the right entity? Mozilla renders it correctly.
+ op.appendChild( doc.createEntityReference( "UnderBar" ) );
+ de.appendChild( op );
+ parent.appendChild( de );
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/bracketelement.h b/lib/kformula/bracketelement.h
new file mode 100644
index 00000000..a929c04b
--- /dev/null
+++ b/lib/kformula/bracketelement.h
@@ -0,0 +1,436 @@
+/* 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.
+*/
+
+#ifndef BRACKETELEMENT_H
+#define BRACKETELEMENT_H
+
+#include <qpoint.h>
+#include <qsize.h>
+
+#include "basicelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class Artwork;
+class SequenceElement;
+
+
+/**
+ * The base of (all) elements that contain just one content element.
+ * (No indexes.)
+ */
+class SingleContentElement : public BasicElement {
+ SingleContentElement& operator=( const SingleContentElement& ) { return *this; }
+public:
+
+ SingleContentElement(BasicElement* parent = 0);
+ ~SingleContentElement();
+
+ SingleContentElement( const SingleContentElement& );
+
+ /**
+ * @returns the character that represents this element. Used for
+ * parsing a sequence.
+ * This is guaranteed to be QChar::null for all non-text elements.
+ */
+ virtual QChar getCharacter() const;
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * We remove ourselve if we are requested to remove our content.
+ */
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+ virtual void normalize(FormulaCursor*, Direction);
+
+ // main child
+ //
+ // If an element has children one has to become the main one.
+
+ virtual SequenceElement* getMainChild();
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor* cursor, BasicElement* child);
+
+protected:
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ virtual void writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const;
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ /**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual int readContentFromMathMLDom(QDomNode& node);
+
+ SequenceElement* getContent() { return content; }
+
+private:
+
+ /**
+ * The one below the graph.
+ */
+ SequenceElement* content;
+};
+
+
+/**
+ * A left and/or right bracket around one child.
+ */
+class BracketElement : public SingleContentElement {
+ typedef SingleContentElement inherited;
+ BracketElement& operator=( const BracketElement& ) { return *this; }
+public:
+
+ enum { contentPos };
+
+ BracketElement(SymbolType left = EmptyBracket, SymbolType right = EmptyBracket,
+ BasicElement* parent = 0);
+ ~BracketElement();
+
+ BracketElement( const BracketElement& );
+
+ virtual BracketElement* clone() {
+ return new BracketElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns the type of this element. Used for
+ * parsing a sequence.
+ */
+ virtual TokenType getTokenType() const { return BRACKET; }
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "BRACKET"; }
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ virtual void writeDom(QDomElement element);
+
+ virtual QString getElementName() const { return "mfenced"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const;
+ /**
+ * Reads our attributes from the MathML element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+
+ /**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read. It is sometimes needed to read more than one node
+ * (e. g. for fence operators).
+ * Returns the number of nodes processed or -1 if it failed.
+ */
+ virtual int readContentFromMathMLDom(QDomNode& node);
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+private:
+
+ /**
+ * @return a LaTex string for the given symbol
+ */
+ QString latexString(char);
+
+ /**
+ * Set left and right types in operator fences
+ * @param open if true set SymbolType for open (left) bracket,
+ * otherwise set for close (right) bracket.
+ */
+ int operatorType( QDomNode& node, bool open );
+
+ /**
+ * Search through the nodes to find the close operator to match current
+ * open bracket.
+ */
+ int searchOperator( const QDomNode& node );
+
+ /**
+ * The brackets we are showing.
+ */
+ Artwork* left;
+ Artwork* right;
+
+ SymbolType leftType;
+ SymbolType rightType;
+
+ QString m_separators;
+ bool m_operator;
+ bool m_customLeft;
+ bool m_customRight;
+};
+
+
+/**
+ * A line above the content.
+ */
+class OverlineElement : public SingleContentElement {
+ OverlineElement& operator=( const OverlineElement& ) { return *this; }
+public:
+
+ OverlineElement(BasicElement* parent = 0);
+ ~OverlineElement();
+
+ OverlineElement( const OverlineElement& );
+
+ virtual OverlineElement* clone() {
+ return new OverlineElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const;
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "OVERLINE"; }
+
+private:
+};
+
+
+/**
+ * A line below the content.
+ */
+class UnderlineElement : public SingleContentElement {
+ UnderlineElement& operator=( const UnderlineElement& ) { return *this; }
+public:
+ UnderlineElement(BasicElement* parent = 0);
+ ~UnderlineElement();
+
+ UnderlineElement( const UnderlineElement& );
+
+ virtual UnderlineElement* clone() {
+ return new UnderlineElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const;
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "UNDERLINE"; }
+
+private:
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // BRACKETELEMENT_H
diff --git a/lib/kformula/config/Makefile.am b/lib/kformula/config/Makefile.am
new file mode 100644
index 00000000..92541798
--- /dev/null
+++ b/lib/kformula/config/Makefile.am
@@ -0,0 +1,27 @@
+
+scripts_DATA = unicode.tbl \
+ esstixeight.font \
+ esstixeleven.font \
+ esstixfifteen.font \
+ esstixfive.font \
+ esstixfour.font \
+ esstixfourteen.font \
+ esstixnine.font \
+ esstixone.font \
+ esstixseven.font \
+ esstixseventeen.font \
+ esstixsix.font \
+ esstixsixteen.font \
+ esstixten.font \
+ esstixthirteen.font \
+ esstixthree.font \
+ esstixtwelve.font \
+ esstixtwo.font \
+ mt%20extra.font \
+ mt%20symbol.font \
+ euclid%20math%20one.font \
+ euclid%20math%20two.font \
+ euclid%20symbol.font \
+ symbol.font
+
+scriptsdir = $(kde_datadir)/kformula
diff --git a/lib/kformula/config/esstixeight.font b/lib/kformula/config/esstixeight.font
new file mode 100644
index 00000000..37cbdfdb
--- /dev/null
+++ b/lib/kformula/config/esstixeight.font
@@ -0,0 +1,31 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixeight font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+33, 0xE201
+37, 0xE205
+99, 0x2321
+97, 0x2320
+93, 0xF8F6
+94, 0xF8F7
+80, 0xF8F4
+98, 0xF8F5
+81, 0xF8F2
+82, 0xF8F3
+75, 0xF8F0
+79, 0xF8F1
+95, 0xF8F8
+76, 0xF8F9
+84, 0xF8FD
+85, 0xF8FE
+78, 0xF8FB
+83, 0xF8FC
+77, 0xF8FA
+74, 0xF8EF
+73, 0xF8EE
+92, 0xF8ED
+91, 0xF8EC
+90, 0xF8EB
diff --git a/lib/kformula/config/esstixeleven.font b/lib/kformula/config/esstixeleven.font
new file mode 100644
index 00000000..d94bd375
--- /dev/null
+++ b/lib/kformula/config/esstixeleven.font
@@ -0,0 +1,7 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixeleven font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
diff --git a/lib/kformula/config/esstixfifteen.font b/lib/kformula/config/esstixfifteen.font
new file mode 100644
index 00000000..3df00e54
--- /dev/null
+++ b/lib/kformula/config/esstixfifteen.font
@@ -0,0 +1,7 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixfifteen font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
diff --git a/lib/kformula/config/esstixfive.font b/lib/kformula/config/esstixfive.font
new file mode 100644
index 00000000..9f57fec2
--- /dev/null
+++ b/lib/kformula/config/esstixfive.font
@@ -0,0 +1,17 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixfive font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+52, 0x2295
+53, 0x2297
+50, 0x2296
+49, 0x2299
+47, 0x2298
+71, 0x00B1
+35, 0x00D7
+79, 0x00F7
+72, 0x2213
+37, 0x22C5
diff --git a/lib/kformula/config/esstixfour.font b/lib/kformula/config/esstixfour.font
new file mode 100644
index 00000000..dc6844b9
--- /dev/null
+++ b/lib/kformula/config/esstixfour.font
@@ -0,0 +1,41 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixfour font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+56, 0x2291
+77, 0x2290
+72, 0x220B
+50, 0x220A
+94, 0x2250
+105, 0x2253
+106, 0x2252
+47, 0x22EF
+51, 0x2282
+73, 0x2283
+52, 0x2286
+74, 0x2287
+60, 0x2284
+63, 0x2288
+83, 0x2289
+82, 0xE2BA
+85, 0xE2BB
+108, 0x00AC
+86, 0xE2B0
+84, 0xE2B7
+64, 0xE2B6
+62, 0xE2B9
+65, 0xE2B8
+81, 0x228B
+61, 0x228A
+55, 0x228F
+53, 0xE304
+75, 0xE305
+162, 0x223C
+121, 0x2245
+54, 0x22D0
+76, 0x22D1
+115, 0x2260
+49, 0x22F1
diff --git a/lib/kformula/config/esstixfourteen.font b/lib/kformula/config/esstixfourteen.font
new file mode 100644
index 00000000..802c47ec
--- /dev/null
+++ b/lib/kformula/config/esstixfourteen.font
@@ -0,0 +1,11 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixfourteen font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+99, 0x2138
+97, 0x2135
+98, 0x2136
+100, 0x2137
diff --git a/lib/kformula/config/esstixnine.font b/lib/kformula/config/esstixnine.font
new file mode 100644
index 00000000..4f4e6197
--- /dev/null
+++ b/lib/kformula/config/esstixnine.font
@@ -0,0 +1,7 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixnine font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
diff --git a/lib/kformula/config/esstixone.font b/lib/kformula/config/esstixone.font
new file mode 100644
index 00000000..9ff6cabf
--- /dev/null
+++ b/lib/kformula/config/esstixone.font
@@ -0,0 +1,57 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixone font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+75, 0x219B
+70, 0x219A
+44, 0x219D
+56, 0x219E
+97, 0x2198
+99, 0x2199
+47, 0x2192
+89, 0x2193
+41, 0x2190
+91, 0x2191
+95, 0x2196
+98, 0x2197
+52, 0x2194
+104, 0x2195
+79, 0x21AE
+59, 0x21A2
+60, 0x21A3
+57, 0x21A0
+38, 0x21A9
+73, 0x21AC
+45, 0x21AA
+43, 0x21AD
+106, 0x21C8
+37, 0x21C4
+36, 0x21C6
+46, 0x21C0
+72, 0x21C1
+88, 0x21C2
+87, 0x21C3
+171, 0x22EE
+71, 0x21CD
+80, 0x21CE
+76, 0x21CF
+69, 0x21BD
+105, 0x21D5
+53, 0x21D4
+92, 0x21D1
+42, 0x21D0
+90, 0x21D3
+48, 0x21D2
+107, 0x21CA
+33, 0x21CB
+35, 0x21CC
+40, 0x21BC
+93, 0x21BF
+94, 0x21BE
+108, 0x21B1
+81, 0x21B0
+103, 0x21B7
+102, 0x21B6
diff --git a/lib/kformula/config/esstixseven.font b/lib/kformula/config/esstixseven.font
new file mode 100644
index 00000000..25a7d01c
--- /dev/null
+++ b/lib/kformula/config/esstixseven.font
@@ -0,0 +1,16 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixseven font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+61, 0x0028
+62, 0x0029
+67, 0x2329
+68, 0x232A
+66, 0x007D
+75, 0x007C
+65, 0x007B
+63, 0x005B
+64, 0x005D
diff --git a/lib/kformula/config/esstixseventeen.font b/lib/kformula/config/esstixseventeen.font
new file mode 100644
index 00000000..c3b8f311
--- /dev/null
+++ b/lib/kformula/config/esstixseventeen.font
@@ -0,0 +1,7 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixseventeen font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
diff --git a/lib/kformula/config/esstixsix.font b/lib/kformula/config/esstixsix.font
new file mode 100644
index 00000000..a6412a58
--- /dev/null
+++ b/lib/kformula/config/esstixsix.font
@@ -0,0 +1,12 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixsix font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+46, 0x220F
+35, 0x222E
+33, 0x222B
+48, 0x221A
+45, 0x2211
diff --git a/lib/kformula/config/esstixsixteen.font b/lib/kformula/config/esstixsixteen.font
new file mode 100644
index 00000000..c212e08d
--- /dev/null
+++ b/lib/kformula/config/esstixsixteen.font
@@ -0,0 +1,7 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixsixteen font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
diff --git a/lib/kformula/config/esstixten.font b/lib/kformula/config/esstixten.font
new file mode 100644
index 00000000..dd4c2b0f
--- /dev/null
+++ b/lib/kformula/config/esstixten.font
@@ -0,0 +1,52 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixten font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+118, 0x2202
+86, 0x2207
+120, 0x03BE
+110, 0x03BD
+91, 0x2127
+108, 0x03BB
+107, 0x03BA
+111, 0x00F8
+105, 0x03B9
+113, 0x03B8
+104, 0x03B7
+122, 0x03B6
+51, 0x03B5
+100, 0x03B4
+103, 0x03B3
+98, 0x03B2
+97, 0x03B1
+88, 0x039E
+76, 0x039B
+81, 0x0398
+68, 0x0394
+71, 0x0393
+119, 0x03D1
+54, 0x03D6
+101, 0xE629
+109, 0x03BC
+57, 0x03F1
+56, 0x03F0
+89, 0xE663
+70, 0x03A6
+83, 0x03A3
+80, 0x03A0
+74, 0x03A8
+85, 0x03A9
+112, 0x03C0
+114, 0x03C1
+50, 0x03C2
+115, 0x03C3
+116, 0x03C4
+121, 0x03C5
+102, 0x03C6
+99, 0x03C7
+106, 0x03C8
+117, 0x03C9
+52, 0x03D5
diff --git a/lib/kformula/config/esstixthirteen.font b/lib/kformula/config/esstixthirteen.font
new file mode 100644
index 00000000..fc13f891
--- /dev/null
+++ b/lib/kformula/config/esstixthirteen.font
@@ -0,0 +1,7 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixthirteen font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
diff --git a/lib/kformula/config/esstixthree.font b/lib/kformula/config/esstixthree.font
new file mode 100644
index 00000000..c55acaeb
--- /dev/null
+++ b/lib/kformula/config/esstixthree.font
@@ -0,0 +1,75 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixthree font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+101, 0x2204
+95, 0x227B
+45, 0xE2F9
+51, 0x227A
+58, 0x2220
+54, 0xE2FE
+35, 0xE2FA
+87, 0x2277
+103, 0x2323
+104, 0x2322
+63, 0xE2A7
+89, 0xE2F5
+85, 0xE2F4
+43, 0x2276
+108, 0xE2A0
+120, 0xE5F1
+97, 0x227F
+100, 0x227D
+55, 0x227C
+67, 0xE2A2
+110, 0x22E7
+66, 0x22E6
+117, 0x22E9
+74, 0x22E8
+41, 0xE2F8
+36, 0xE5CF
+84, 0x2273
+40, 0x2272
+114, 0x2271
+70, 0x2270
+65, 0x2268
+73, 0x2280
+116, 0x2281
+78, 0x221E
+102, 0x221D
+107, 0xE2A6
+75, 0xE2B2
+118, 0xE2B4
+77, 0xE5DC
+53, 0xE2FD
+98, 0xE2FF
+46, 0x2243
+81, 0xE5DF
+101, 0x22DF
+56, 0x22DE
+88, 0x22DB
+44, 0x22DA
+80, 0xE2F6
+49, 0x22D6
+93, 0x22D7
+105, 0x22D4
+71, 0xE2A8
+48, 0x22D8
+92, 0x22D9
+111, 0xE29F
+37, 0x2264
+82, 0x2265
+38, 0x2266
+83, 0x2267
+109, 0x2269
+64, 0xE2A3
+99, 0xE300
+47, 0x226A
+91, 0x226B
+72, 0x226C
+62, 0x226E
+106, 0x226F
+52, 0x227E
diff --git a/lib/kformula/config/esstixtwelve.font b/lib/kformula/config/esstixtwelve.font
new file mode 100644
index 00000000..b82e5d7f
--- /dev/null
+++ b/lib/kformula/config/esstixtwelve.font
@@ -0,0 +1,7 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixtwelve font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
diff --git a/lib/kformula/config/esstixtwo.font b/lib/kformula/config/esstixtwo.font
new file mode 100644
index 00000000..ed83909f
--- /dev/null
+++ b/lib/kformula/config/esstixtwo.font
@@ -0,0 +1,35 @@
+#
+# KFormula font mapping.
+# Unicode mapping for the esstixtwo font. You can find it at
+# ftp://ftp.elsevier.nl/pub/styles/esstix/esstix.zip
+#
+# Each line consist of a char position and its unicode value.
+#
+100, 0x2203
+99, 0x2200
+102, 0x2201
+108, 0x2293
+107, 0x2294
+111, 0x2227
+118, 0x22BB
+119, 0x22BC
+110, 0x2228
+104, 0x2229
+58, 0x25B4
+103, 0x222A
+57, 0x22B2
+56, 0x22B3
+43, 0x2605
+59, 0x25BE
+121, 0x2306
+60, 0x25B6
+54, 0x25B5
+167, 0x2118
+40, 0x2660
+38, 0x2661
+37, 0x2662
+41, 0x2663
+109, 0x228E
+106, 0x22D2
+105, 0x22D3
+61, 0x25C0
diff --git a/lib/kformula/config/euclid%20math%20one.font b/lib/kformula/config/euclid%20math%20one.font
new file mode 100644
index 00000000..38ad8011
--- /dev/null
+++ b/lib/kformula/config/euclid%20math%20one.font
@@ -0,0 +1,151 @@
+82, 0x211B
+189, 0x219B
+188, 0x219A
+179, 0x219E
+79, 0xF10E
+78, 0xF10D
+240, 0x2201
+243, 0x2204
+35, 0x229B
+40, 0x229E
+39, 0x229F
+33, 0x2296
+37, 0x2298
+162, 0x2256
+41, 0x22A0
+163, 0x2253
+137, 0xE92F
+246, 0xED01
+248, 0xED02
+140, 0x2224
+141, 0x2226
+65, 0xF100
+201, 0x21DA
+67, 0xF102
+75, 0xF10A
+87, 0xF116
+200, 0x21DB
+150, 0x22AC
+250, 0x22BA
+131, 0x2215
+71, 0xF106
+152, 0x22AE
+74, 0xF109
+151, 0x22AD
+66, 0x212C
+153, 0x22AF
+192, 0x21AE
+32, 0x0020
+231, 0x266D
+72, 0x210B
+85, 0xF114
+255, 0x210F
+130, 0x2216
+177, 0x21A2
+176, 0x21A3
+178, 0x21A0
+34, 0x229A
+244, 0x03DC
+254, 0x00F0
+68, 0xF103
+205, 0x21AB
+204, 0x21AC
+161, 0x2257
+164, 0x2251
+207, 0x21AD
+165, 0x2252
+81, 0xF110
+242, 0x03B5
+195, 0x21C9
+168, 0x22B8
+196, 0x21C8
+198, 0x21C6
+182, 0x21C0
+183, 0x21C1
+185, 0x21C2
+187, 0x21C3
+194, 0x21C7
+145, 0x22A8
+128, 0xFE68
+190, 0x21CD
+193, 0x21CE
+191, 0x21CF
+181, 0x21BD
+233, 0x266F
+160, 0x00A0
+76, 0x2112
+73, 0x2110
+80, 0x2118
+241, 0x03F1
+249, 0x03F0
+139, 0xEA2F
+86, 0xF115
+83, 0xF112
+84, 0xF113
+89, 0xF118
+90, 0xF119
+42, 0x22A1
+148, 0x22A3
+144, 0x22A2
+149, 0x22A4
+138, 0xEA2E
+253, 0x2138
+88, 0xF117
+174, 0x2247
+147, 0x22AA
+251, 0x2136
+252, 0x2137
+69, 0x2130
+70, 0x2131
+245, 0x2132
+77, 0x2133
+210, 0x21BB
+146, 0x22A9
+230, 0x22C7
+135, 0x231F
+170, 0x2240
+136, 0xE92E
+228, 0x2720
+173, 0x2241
+232, 0x266E
+55, 0x0037
+54, 0x0036
+53, 0x0035
+52, 0x0034
+51, 0x0033
+50, 0x0032
+49, 0x0031
+48, 0x0030
+234, 0x2214
+57, 0x0039
+56, 0x0038
+134, 0x231D
+133, 0x231E
+171, 0x2242
+132, 0x231C
+226, 0x22C9
+247, 0x0131
+45, 0x25AA
+166, 0x224F
+224, 0x22CB
+169, 0x224D
+167, 0x224E
+172, 0x224A
+43, 0x25A0
+206, 0x21DD
+197, 0x21CA
+44, 0x25A1
+199, 0x21CB
+180, 0x21BC
+211, 0x21BA
+186, 0x21BF
+184, 0x21BE
+229, 0x22C6
+38, 0x24C8
+202, 0x21B1
+203, 0x21B0
+208, 0x21B7
+209, 0x21B6
+225, 0x22CC
+129, 0x005C
+227, 0x22CA
diff --git a/lib/kformula/config/euclid%20math%20two.font b/lib/kformula/config/euclid%20math%20two.font
new file mode 100644
index 00000000..7b402419
--- /dev/null
+++ b/lib/kformula/config/euclid%20math%20two.font
@@ -0,0 +1,131 @@
+228, 0x2208
+212, 0xE90C
+244, 0x2291
+241, 0x2290
+243, 0x2293
+245, 0x2292
+242, 0x2294
+229, 0x220B
+67, 0x2102
+168, 0xE92D
+169, 0x22BB
+170, 0x22BC
+225, 0xEA0B
+224, 0xEA0C
+149, 0xEA0E
+156, 0xEA06
+157, 0xEA07
+72, 0x210D
+167, 0xE922
+90, 0x2124
+164, 0x2277
+221, 0xEA45
+107, 0xF0A4
+40, 0x22B4
+36, 0x25BC
+217, 0xEA43
+163, 0x2276
+69, 0xF084
+70, 0xF085
+71, 0xF086
+65, 0xF080
+66, 0xF081
+68, 0xF083
+34, 0x25BD
+73, 0xF088
+74, 0xF089
+171, 0x2306
+183, 0x227F
+177, 0x227D
+176, 0x227C
+159, 0x22E7
+158, 0x22E6
+191, 0x22E1
+190, 0x22E0
+199, 0x22E9
+198, 0x22E8
+43, 0x22ED
+42, 0x22EA
+44, 0x22EC
+41, 0x22EB
+137, 0x2273
+136, 0x2272
+147, 0x2271
+146, 0x2270
+152, 0x2268
+75, 0xF08A
+76, 0xF08B
+77, 0xF08C
+37, 0x25B6
+33, 0x25B3
+35, 0x25B2
+186, 0x2280
+187, 0x2281
+218, 0x2288
+219, 0x2289
+160, 0x00A0
+220, 0xEA44
+222, 0xEA46
+81, 0x211A
+196, 0xEA40
+197, 0xEA41
+82, 0x211D
+213, 0xE90B
+78, 0x2115
+80, 0x2119
+215, 0x228B
+214, 0x228A
+240, 0x228F
+226, 0x228E
+145, 0xEA35
+144, 0xEA34
+79, 0xF08E
+223, 0xEA47
+192, 0xEA3E
+189, 0xEA3D
+193, 0xEA3F
+200, 0xEA3A
+188, 0xEA3C
+201, 0xEA3B
+179, 0x22DF
+131, 0x22DD
+178, 0x22DE
+166, 0x22DB
+130, 0x22DC
+165, 0x22DA
+148, 0xEA10
+162, 0xEA33
+161, 0xEA32
+139, 0xE933
+138, 0xE932
+184, 0xE93A
+185, 0xE93B
+202, 0x22CF
+203, 0x22CE
+128, 0x22D6
+129, 0x22D7
+227, 0x22D4
+211, 0x22D2
+210, 0x22D3
+208, 0x22D0
+209, 0x22D1
+140, 0x22D8
+141, 0x22D9
+216, 0xEA42
+132, 0x2264
+133, 0x2265
+134, 0x2266
+135, 0x2267
+153, 0x2269
+38, 0x25C0
+84, 0xF093
+83, 0xF092
+88, 0xF097
+87, 0xF096
+86, 0xF095
+85, 0xF094
+89, 0xF098
+142, 0x226E
+143, 0x226F
+39, 0x22B5
+182, 0x227E
diff --git a/lib/kformula/config/euclid%20symbol.font b/lib/kformula/config/euclid%20symbol.font
new file mode 100644
index 00000000..02651285
--- /dev/null
+++ b/lib/kformula/config/euclid%20symbol.font
@@ -0,0 +1,188 @@
+206, 0x2208
+207, 0x2209
+182, 0x2202
+36, 0x2203
+34, 0x2200
+209, 0x2207
+198, 0x2205
+197, 0x2295
+196, 0x2297
+213, 0x220F
+39, 0x220D
+174, 0x2192
+175, 0x2193
+172, 0x2190
+173, 0x2191
+171, 0x2194
+217, 0x2227
+208, 0x2220
+176, 0x00B0
+177, 0x00B1
+43, 0x002B
+44, 0x002C
+218, 0x2228
+199, 0x2229
+47, 0x002F
+178, 0x2033
+162, 0x2032
+40, 0x0028
+41, 0x0029
+200, 0x222A
+32, 0x0020
+33, 0x0021
+35, 0x0023
+37, 0x0025
+38, 0x0026
+180, 0x00D7
+212, 0x2122
+120, 0x03BE
+110, 0x03BD
+108, 0x03BB
+107, 0x03BA
+225, 0x2329
+245, 0x2321
+243, 0x2320
+246, 0xF8F6
+247, 0xF8F7
+239, 0xF8F4
+244, 0xF8F5
+237, 0xF8F2
+238, 0xF8F3
+235, 0xF8F0
+236, 0xF8F1
+248, 0xF8F8
+249, 0xF8F9
+253, 0xF8FD
+254, 0xF8FE
+251, 0xF8FB
+252, 0xF8FC
+250, 0xF8FA
+241, 0x232A
+242, 0x222B
+105, 0x03B9
+113, 0x03B8
+104, 0x03B7
+122, 0x03B6
+101, 0x03B5
+100, 0x03B4
+103, 0x03B3
+98, 0x03B2
+97, 0x03B1
+79, 0x039F
+78, 0x039D
+88, 0x039E
+76, 0x039B
+77, 0x039C
+75, 0x039A
+81, 0x0398
+73, 0x0399
+90, 0x0396
+72, 0x0397
+68, 0x0394
+69, 0x0395
+184, 0x00F7
+71, 0x0393
+65, 0x0391
+74, 0x03D1
+161, 0x03D2
+118, 0x03D6
+204, 0x2282
+201, 0x2283
+205, 0x2286
+202, 0x2287
+203, 0x2284
+169, 0x2665
+214, 0x221A
+165, 0x221E
+181, 0x221D
+210, 0x00AE
+166, 0x0192
+216, 0x00AC
+194, 0x211C
+111, 0x03BF
+193, 0x2111
+109, 0x03BC
+195, 0x2118
+211, 0x00A9
+168, 0x2666
+170, 0x2660
+167, 0x2663
+219, 0x21D4
+45, 0x2212
+221, 0x21D1
+220, 0x21D0
+223, 0x21D3
+222, 0x21D2
+229, 0x2211
+42, 0x2217
+188, 0x2026
+125, 0x007D
+183, 0x2022
+126, 0x223C
+70, 0x03A6
+67, 0x03A7
+84, 0x03A4
+85, 0x03A5
+83, 0x03A3
+80, 0x03A0
+82, 0x03A1
+94, 0x22A5
+89, 0x03A8
+87, 0x03A9
+192, 0x2135
+92, 0x2234
+124, 0x007C
+55, 0x0037
+54, 0x0036
+53, 0x0035
+52, 0x0034
+51, 0x0033
+50, 0x0032
+49, 0x0031
+48, 0x0030
+57, 0x0039
+56, 0x0038
+164, 0x2244
+64, 0x2245
+215, 0x22C5
+66, 0x0392
+187, 0x2248
+112, 0x03C0
+114, 0x03C1
+86, 0x03C2
+115, 0x03C3
+116, 0x03C4
+117, 0x03C5
+102, 0x03C6
+99, 0x03C7
+121, 0x03C8
+119, 0x03C9
+224, 0x26C4
+63, 0x003F
+62, 0x003E
+61, 0x003D
+60, 0x003C
+59, 0x003B
+58, 0x003A
+234, 0xF8EF
+233, 0xF8EE
+232, 0xF8ED
+231, 0xF8EC
+230, 0xF8EB
+228, 0xF8EA
+185, 0x2260
+186, 0x2261
+163, 0x2264
+179, 0x2265
+46, 0x002E
+123, 0x007B
+191, 0x21B5
+91, 0x005B
+93, 0x005D
+95, 0x005F
+106, 0x03D5
+227, 0xF8E9
+226, 0xF8E8
+190, 0xF8E7
+189, 0xF8E6
+96, 0xF8E5
diff --git a/lib/kformula/config/mt%20extra.font b/lib/kformula/config/mt%20extra.font
new file mode 100644
index 00000000..96fe35b0
--- /dev/null
+++ b/lib/kformula/config/mt%20extra.font
@@ -0,0 +1,144 @@
+53, 0xEC0B
+124, 0xEC0C
+249, 0x2044
+240, 0xFB01
+70, 0xEC0F
+126, 0xEC0D
+209, 0xEE11
+101, 0x2299
+123, 0xFE38
+102, 0x227B
+115, 0x20D6
+118, 0x20D1
+66, 0x2250
+93, 0x2198
+91, 0x2199
+67, 0x2210
+94, 0x2196
+90, 0x2197
+98, 0x2195
+112, 0x227A
+163, 0x2102
+80, 0x2225
+82, 0x2221
+73, 0x2229
+192, 0xEE0D
+187, 0xEE0B
+253, 0x02C7
+193, 0xEE0E
+194, 0xEE0F
+72, 0xEC11
+71, 0xEC10
+103, 0xE98F
+188, 0xEE0C
+176, 0xEE04
+233, 0x00DD
+96, 0x2035
+85, 0x222A
+60, 0x22B2
+62, 0x22B3
+246, 0x00BD
+104, 0x210F
+235, 0x00D0
+254, 0x02DA
+74, 0x2127
+162, 0x2124
+97, 0x21A6
+64, 0x225C
+40, 0x2323
+41, 0x2322
+211, 0xEE13
+213, 0xEE15
+239, 0x00F0
+132, 0xEB03
+234, 0x00DE
+65, 0x2259
+248, 0x00BE
+129, 0xEB01
+128, 0x21C4
+134, 0x21C0
+186, 0xEE0A
+77, 0x22EE
+68, 0x019B
+76, 0x22EF
+113, 0xEB1A
+232, 0x0160
+86, 0x25B3
+89, 0x25B1
+69, 0xEC0E
+178, 0xEE06
+252, 0x02D8
+181, 0xEE07
+110, 0xFFFD
+105, 0xEE00
+135, 0x21BD
+106, 0xEE01
+38, 0x0307
+35, 0x0300
+37, 0x0303
+36, 0x0302
+119, 0x20D0
+164, 0x211A
+161, 0x211D
+120, 0xEB19
+108, 0x2113
+165, 0x2115
+236, 0x0161
+250, 0x00A6
+111, 0x2218
+99, 0x21D5
+109, 0x2213
+49, 0xEC00
+54, 0xEC04
+255, 0x02DB
+167, 0x301A
+251, 0x02DD
+168, 0x301B
+75, 0x2026
+116, 0x20E1
+58, 0x223C
+51, 0xEC02
+237, 0x00FD
+52, 0xEC03
+172, 0xEC25
+56, 0xEC06
+238, 0x00FE
+81, 0x2235
+59, 0x2243
+171, 0xEC24
+173, 0xEC26
+174, 0xEC27
+169, 0xEC22
+170, 0xEC23
+177, 0xEE05
+182, 0xEE08
+183, 0xEE09
+247, 0x00BC
+242, 0x0131
+88, 0x25AD
+114, 0x20D7
+55, 0xEC05
+125, 0xFE37
+243, 0x00B9
+214, 0xEE16
+231, 0xF8FF
+83, 0x2222
+210, 0xEE12
+87, 0x25A1
+195, 0xEE10
+131, 0x21CC
+244, 0x00B2
+245, 0x00B3
+100, 0x25CB
+50, 0xEC01
+61, 0x226A
+63, 0x226B
+130, 0xEB02
+78, 0x22F0
+79, 0x22F1
+92, 0xEB05
+136, 0xF8E7
+117, 0xEB00
+241, 0xFB02
+95, 0xEB06
+133, 0xEB04
diff --git a/lib/kformula/config/mt%20symbol.font b/lib/kformula/config/mt%20symbol.font
new file mode 100644
index 00000000..02651285
--- /dev/null
+++ b/lib/kformula/config/mt%20symbol.font
@@ -0,0 +1,188 @@
+206, 0x2208
+207, 0x2209
+182, 0x2202
+36, 0x2203
+34, 0x2200
+209, 0x2207
+198, 0x2205
+197, 0x2295
+196, 0x2297
+213, 0x220F
+39, 0x220D
+174, 0x2192
+175, 0x2193
+172, 0x2190
+173, 0x2191
+171, 0x2194
+217, 0x2227
+208, 0x2220
+176, 0x00B0
+177, 0x00B1
+43, 0x002B
+44, 0x002C
+218, 0x2228
+199, 0x2229
+47, 0x002F
+178, 0x2033
+162, 0x2032
+40, 0x0028
+41, 0x0029
+200, 0x222A
+32, 0x0020
+33, 0x0021
+35, 0x0023
+37, 0x0025
+38, 0x0026
+180, 0x00D7
+212, 0x2122
+120, 0x03BE
+110, 0x03BD
+108, 0x03BB
+107, 0x03BA
+225, 0x2329
+245, 0x2321
+243, 0x2320
+246, 0xF8F6
+247, 0xF8F7
+239, 0xF8F4
+244, 0xF8F5
+237, 0xF8F2
+238, 0xF8F3
+235, 0xF8F0
+236, 0xF8F1
+248, 0xF8F8
+249, 0xF8F9
+253, 0xF8FD
+254, 0xF8FE
+251, 0xF8FB
+252, 0xF8FC
+250, 0xF8FA
+241, 0x232A
+242, 0x222B
+105, 0x03B9
+113, 0x03B8
+104, 0x03B7
+122, 0x03B6
+101, 0x03B5
+100, 0x03B4
+103, 0x03B3
+98, 0x03B2
+97, 0x03B1
+79, 0x039F
+78, 0x039D
+88, 0x039E
+76, 0x039B
+77, 0x039C
+75, 0x039A
+81, 0x0398
+73, 0x0399
+90, 0x0396
+72, 0x0397
+68, 0x0394
+69, 0x0395
+184, 0x00F7
+71, 0x0393
+65, 0x0391
+74, 0x03D1
+161, 0x03D2
+118, 0x03D6
+204, 0x2282
+201, 0x2283
+205, 0x2286
+202, 0x2287
+203, 0x2284
+169, 0x2665
+214, 0x221A
+165, 0x221E
+181, 0x221D
+210, 0x00AE
+166, 0x0192
+216, 0x00AC
+194, 0x211C
+111, 0x03BF
+193, 0x2111
+109, 0x03BC
+195, 0x2118
+211, 0x00A9
+168, 0x2666
+170, 0x2660
+167, 0x2663
+219, 0x21D4
+45, 0x2212
+221, 0x21D1
+220, 0x21D0
+223, 0x21D3
+222, 0x21D2
+229, 0x2211
+42, 0x2217
+188, 0x2026
+125, 0x007D
+183, 0x2022
+126, 0x223C
+70, 0x03A6
+67, 0x03A7
+84, 0x03A4
+85, 0x03A5
+83, 0x03A3
+80, 0x03A0
+82, 0x03A1
+94, 0x22A5
+89, 0x03A8
+87, 0x03A9
+192, 0x2135
+92, 0x2234
+124, 0x007C
+55, 0x0037
+54, 0x0036
+53, 0x0035
+52, 0x0034
+51, 0x0033
+50, 0x0032
+49, 0x0031
+48, 0x0030
+57, 0x0039
+56, 0x0038
+164, 0x2244
+64, 0x2245
+215, 0x22C5
+66, 0x0392
+187, 0x2248
+112, 0x03C0
+114, 0x03C1
+86, 0x03C2
+115, 0x03C3
+116, 0x03C4
+117, 0x03C5
+102, 0x03C6
+99, 0x03C7
+121, 0x03C8
+119, 0x03C9
+224, 0x26C4
+63, 0x003F
+62, 0x003E
+61, 0x003D
+60, 0x003C
+59, 0x003B
+58, 0x003A
+234, 0xF8EF
+233, 0xF8EE
+232, 0xF8ED
+231, 0xF8EC
+230, 0xF8EB
+228, 0xF8EA
+185, 0x2260
+186, 0x2261
+163, 0x2264
+179, 0x2265
+46, 0x002E
+123, 0x007B
+191, 0x21B5
+91, 0x005B
+93, 0x005D
+95, 0x005F
+106, 0x03D5
+227, 0xF8E9
+226, 0xF8E8
+190, 0xF8E7
+189, 0xF8E6
+96, 0xF8E5
diff --git a/lib/kformula/config/symbol.font b/lib/kformula/config/symbol.font
new file mode 100644
index 00000000..02651285
--- /dev/null
+++ b/lib/kformula/config/symbol.font
@@ -0,0 +1,188 @@
+206, 0x2208
+207, 0x2209
+182, 0x2202
+36, 0x2203
+34, 0x2200
+209, 0x2207
+198, 0x2205
+197, 0x2295
+196, 0x2297
+213, 0x220F
+39, 0x220D
+174, 0x2192
+175, 0x2193
+172, 0x2190
+173, 0x2191
+171, 0x2194
+217, 0x2227
+208, 0x2220
+176, 0x00B0
+177, 0x00B1
+43, 0x002B
+44, 0x002C
+218, 0x2228
+199, 0x2229
+47, 0x002F
+178, 0x2033
+162, 0x2032
+40, 0x0028
+41, 0x0029
+200, 0x222A
+32, 0x0020
+33, 0x0021
+35, 0x0023
+37, 0x0025
+38, 0x0026
+180, 0x00D7
+212, 0x2122
+120, 0x03BE
+110, 0x03BD
+108, 0x03BB
+107, 0x03BA
+225, 0x2329
+245, 0x2321
+243, 0x2320
+246, 0xF8F6
+247, 0xF8F7
+239, 0xF8F4
+244, 0xF8F5
+237, 0xF8F2
+238, 0xF8F3
+235, 0xF8F0
+236, 0xF8F1
+248, 0xF8F8
+249, 0xF8F9
+253, 0xF8FD
+254, 0xF8FE
+251, 0xF8FB
+252, 0xF8FC
+250, 0xF8FA
+241, 0x232A
+242, 0x222B
+105, 0x03B9
+113, 0x03B8
+104, 0x03B7
+122, 0x03B6
+101, 0x03B5
+100, 0x03B4
+103, 0x03B3
+98, 0x03B2
+97, 0x03B1
+79, 0x039F
+78, 0x039D
+88, 0x039E
+76, 0x039B
+77, 0x039C
+75, 0x039A
+81, 0x0398
+73, 0x0399
+90, 0x0396
+72, 0x0397
+68, 0x0394
+69, 0x0395
+184, 0x00F7
+71, 0x0393
+65, 0x0391
+74, 0x03D1
+161, 0x03D2
+118, 0x03D6
+204, 0x2282
+201, 0x2283
+205, 0x2286
+202, 0x2287
+203, 0x2284
+169, 0x2665
+214, 0x221A
+165, 0x221E
+181, 0x221D
+210, 0x00AE
+166, 0x0192
+216, 0x00AC
+194, 0x211C
+111, 0x03BF
+193, 0x2111
+109, 0x03BC
+195, 0x2118
+211, 0x00A9
+168, 0x2666
+170, 0x2660
+167, 0x2663
+219, 0x21D4
+45, 0x2212
+221, 0x21D1
+220, 0x21D0
+223, 0x21D3
+222, 0x21D2
+229, 0x2211
+42, 0x2217
+188, 0x2026
+125, 0x007D
+183, 0x2022
+126, 0x223C
+70, 0x03A6
+67, 0x03A7
+84, 0x03A4
+85, 0x03A5
+83, 0x03A3
+80, 0x03A0
+82, 0x03A1
+94, 0x22A5
+89, 0x03A8
+87, 0x03A9
+192, 0x2135
+92, 0x2234
+124, 0x007C
+55, 0x0037
+54, 0x0036
+53, 0x0035
+52, 0x0034
+51, 0x0033
+50, 0x0032
+49, 0x0031
+48, 0x0030
+57, 0x0039
+56, 0x0038
+164, 0x2244
+64, 0x2245
+215, 0x22C5
+66, 0x0392
+187, 0x2248
+112, 0x03C0
+114, 0x03C1
+86, 0x03C2
+115, 0x03C3
+116, 0x03C4
+117, 0x03C5
+102, 0x03C6
+99, 0x03C7
+121, 0x03C8
+119, 0x03C9
+224, 0x26C4
+63, 0x003F
+62, 0x003E
+61, 0x003D
+60, 0x003C
+59, 0x003B
+58, 0x003A
+234, 0xF8EF
+233, 0xF8EE
+232, 0xF8ED
+231, 0xF8EC
+230, 0xF8EB
+228, 0xF8EA
+185, 0x2260
+186, 0x2261
+163, 0x2264
+179, 0x2265
+46, 0x002E
+123, 0x007B
+191, 0x21B5
+91, 0x005B
+93, 0x005D
+95, 0x005F
+106, 0x03D5
+227, 0xF8E9
+226, 0xF8E8
+190, 0xF8E7
+189, 0xF8E6
+96, 0xF8E5
diff --git a/lib/kformula/config/unicode.tbl b/lib/kformula/config/unicode.tbl
new file mode 100644
index 00000000..e3e27db8
--- /dev/null
+++ b/lib/kformula/config/unicode.tbl
@@ -0,0 +1,635 @@
+#
+# KFormula unicode table
+# Each line contains the unicode value, the char class
+# (ORDINARY, BINOP or RELATION) and optionally the
+# chars TeX name.
+#
+0x2282, RELATION, subset
+0x2283, RELATION, supset
+0x2044, ORDINARY
+0xE201, RELATION, longleftarrow
+0xE205, RELATION, longrightarrow
+0x219B, ORDINARY, nrightarrow
+0x2286, RELATION, subseteq
+0x219A, ORDINARY, nleftarrow
+0x219D, RELATION, rightsquigarrow
+0x219E, ORDINARY, twoheadleftarrow
+0xEC11, ORDINARY
+0x2208, RELATION, in
+0x2209, RELATION, notin
+0xEC0D, ORDINARY
+0x22D0, ORDINARY, Subset
+0xEC10, ORDINARY
+0x2202, ORDINARY, partial
+0x2203, ORDINARY, exists
+0x2200, ORDINARY, forall
+0x2201, ORDINARY, complement
+0x2207, ORDINARY, nabla
+0x2204, ORDINARY, nexists
+0x2205, BINOP, oslash
+0x229A, ORDINARY, circledcirc
+0x229B, ORDINARY, circledast
+0x229E, ORDINARY, boxplus
+0x229F, ORDINARY, boxminus
+0x2291, ORDINARY, sqsubseteq
+0x2290, ORDINARY, sqsupset
+0x2293, ORDINARY, sqcap
+0x2292, ORDINARY, sqsupseteq
+0x2295, BINOP, oplus
+0x2294, ORDINARY, sqcup
+0x2297, BINOP, otimes
+0x2296, ORDINARY, ominus
+0x2299, ORDINARY, odot
+0x2298, ORDINARY, oslash
+0x02DD, ORDINARY
+0x21AA, RELATION, hookrightarrow
+0xFE38, ORDINARY
+0x22A0, ORDINARY, boxtimes
+0x220B, ORDINARY, ni
+0x2251, ORDINARY, Doteq
+0x20D6, ORDINARY, overleftarrow
+0xFE37, ORDINARY
+0x220F, ORDINARY, prod
+0x20D1, ORDINARY, rightharpoonaccent
+0x220D, RELATION, ni
+0xE2F8, RELATION, lessapprox
+0x2198, ORDINARY, searrow
+0x2199, ORDINARY, swarrow
+0x21AD, ORDINARY
+0x2192, RELATION, rightarrow
+0x2193, RELATION, downarrow
+0x2190, RELATION, leftarrow
+0x2191, RELATION, uparrow
+0x2196, ORDINARY, nwarrow
+0x2197, ORDINARY, nearrow
+0x2194, RELATION, leftrightarrow
+0x2195, ORDINARY, updownarrow
+0xF8EB, ORDINARY
+0x03A6, ORDINARY, Phi
+0xF092, ORDINARY
+0x2211, ORDINARY, sum
+0x2102, ORDINARY
+0xE92F, ORDINARY
+0xE92D, ORDINARY
+0x228E, ORDINARY, uplus
+0xED01, ORDINARY
+0xED02, ORDINARY
+0x2224, ORDINARY
+0x00B9, ORDINARY
+0x2226, ORDINARY
+0x2227, BINOP, wedge
+0xE2A8, RELATION, nleqq
+0x2221, ORDINARY, measuredangle
+0x2222, ORDINARY
+0x22BC, ORDINARY, barwedge
+0x00B0, ORDINARY, degree
+0x00B1, BINOP, pm
+0x002B, BINOP
+0x002C, PUNCTUATION
+0x2228, BINOP, vee
+0x2229, BINOP, cap
+0xE2A2, RELATION, lnapprox
+0xE2A3, RELATION, lneq
+0xEE0D, ORDINARY
+0x21D4, RELATION, Leftrightarrow
+0xEA06, ORDINARY
+0xF088, ORDINARY
+0x221E, ORDINARY, infty
+0xEA07, ORDINARY
+0x22D4, RELATION, pitchfork
+0xF10E, ORDINARY
+0xF10D, ORDINARY
+0xEA0B, ORDINARY
+0xEA0C, ORDINARY
+0xF10A, ORDINARY
+0xEA0E, ORDINARY
+0x21CA, ORDINARY, downdownarrows
+0x2136, ORDINARY, beth
+0x22D3, ORDINARY, Cup
+0xF106, ORDINARY
+0xF100, ORDINARY
+0x02C7, ORDINARY
+0xF102, ORDINARY
+0x2130, ORDINARY
+0x03B8, ORDINARY, theta
+0xF109, ORDINARY
+0x2131, ORDINARY
+0x03B7, ORDINARY, eta
+0xE2BB, RELATION, varsupsetneqq
+0x2035, ORDINARY, backprime
+0x2133, ORDINARY
+0x03A7, ORDINARY
+0xEA33, ORDINARY
+0x2033, ORDINARY
+0x2032, ORDINARY, prime
+0x0028, ORDINARY
+0x222E, ORDINARY, oint
+0x222A, BINOP, cup
+0x22B2, RELATION, vartriangleleft
+0x22B3, RELATION, vartriangleright
+0x0020, ORDINARY
+0x0021, ORDINARY
+0x00BC, ORDINARY
+0x00BD, ORDINARY
+0x0025, ORDINARY
+0x0026, ORDINARY
+0x00AE, ORDINARY
+0x210B, ORDINARY
+0x210D, ORDINARY
+0x210F, ORDINARY
+0x22D9, RELATION, ggg
+0xE922, ORDINARY
+0x00D0, ORDINARY
+0x00D7, BINOP, times
+0x02DA, ORDINARY
+0x2122, ORDINARY
+0xE90B, ORDINARY
+0xE90C, ORDINARY
+0x03BC, ORDINARY, mu
+0x03BB, ORDINARY, lambda
+0x03BA, ORDINARY, kappa
+0x2124, ORDINARY
+0x21A2, ORDINARY, leftarrowtail
+0x21A3, ORDINARY, rightarrowtail
+0x21A0, ORDINARY, twoheadrightarrow
+0x21A6, ORDINARY, mapsto
+0x225C, RELATION, triangleq
+0xE2FE, RELATION, preceq
+0xF080, ORDINARY
+0xE2FF, RELATION, succapprox
+0xE2FA, RELATION, leqslant
+0x227E, RELATION, precsim
+0x2329, ORDINARY, langle
+0x222B, ORDINARY, int
+0x211C, ORDINARY, Re
+0x2321, ORDINARY
+0x2320, ORDINARY
+0x2323, RELATION, smile
+0x2322, RELATION, frown
+0xF0A4, ORDINARY
+0xF8F6, ORDINARY
+0xF8F7, ORDINARY
+0xF8F4, ORDINARY
+0xF8F5, ORDINARY
+0xF8F2, ORDINARY
+0xF8F3, ORDINARY
+0xF8F0, ORDINARY
+0xF8F1, ORDINARY
+0x25BE, ORDINARY, blacktriangledown
+0xF8F8, ORDINARY
+0xF8F9, ORDINARY
+0xF8FF, ORDINARY
+0xEE12, ORDINARY
+0xEE11, ORDINARY
+0xEE10, ORDINARY
+0xF8FB, ORDINARY
+0xEE16, ORDINARY
+0xEE15, ORDINARY
+0x0029, ORDINARY
+0x25BC, ORDINARY
+0x21CD, ORDINARY, nLeftarrow
+0xF089, ORDINARY
+0xE2A7, RELATION, nleqslant
+0x00B2, ORDINARY
+0x22B5, ORDINARY, trianglerighteq
+0x232A, ORDINARY, rangle
+0xEA35, ORDINARY
+0xEA44, ORDINARY
+0xF103, ORDINARY
+0x21AB, ORDINARY, looparrowleft
+0x21AC, ORDINARY, looparrowright
+0x2257, ORDINARY, circeq
+0x2256, ORDINARY, eqcirc
+0xE2F9, RELATION, lesseqqgtr
+0x2250, RELATION, doteq
+0x2253, ORDINARY, risingdotseq
+0x21AE, ORDINARY
+0xE2F5, RELATION, gtreqqless
+0xE2F4, RELATION, gtrapprox
+0xE2F6, RELATION, geqslant
+0x2259, RELATION, wedgeq
+0xF110, ORDINARY
+0xE2A0, RELATION, gneq
+0xEB02, ORDINARY
+0x22DC, ORDINARY, eqless
+0x00DD, ORDINARY
+0x00DE, ORDINARY
+0x212C, ORDINARY
+0x03B6, ORDINARY, zeta
+0x03B5, ORDINARY, varepsilon
+0x03B4, ORDINARY, delta
+0x03B3, ORDINARY, gamma
+0x03B2, ORDINARY, beta
+0x03B1, ORDINARY, alpha
+0x2306, ORDINARY, doublebarwedge
+0xF084, ORDINARY
+0xF085, ORDINARY
+0xF086, ORDINARY
+0x0023, ORDINARY, sharp
+0x00F8, ORDINARY, o
+0xF081, ORDINARY
+0xF083, ORDINARY
+0x22B8, ORDINARY, multimap
+0x03DC, ORDINARY
+0x25BD, ORDINARY, bigtriangledown
+0x00F0, ORDINARY
+0x22B4, ORDINARY, trianglelefteq
+0x00BE, ORDINARY
+0xE5F1, RELATION, nsucceq
+0xEB01, ORDINARY
+0x2111, ORDINARY, Im
+0x21C8, ORDINARY, upuparrows
+0x21C9, ORDINARY, rightrightarrows
+0x21C4, ORDINARY, rightleftarrows
+0x227F, RELATION, succsim
+0x21C6, ORDINARY, leftrightarrows
+0x21D2, RELATION, Rightarrow
+0x21C0, ORDINARY, rightharpoonup
+0x227B, RELATION, succ
+0x227A, RELATION, prec
+0x21C3, ORDINARY, downharpoonleft
+0x227D, RELATION, succcurlyeq
+0x039F, ORDINARY
+0x227C, RELATION, preccurlyeq
+0x039D, ORDINARY
+0x039E, ORDINARY, Xi
+0x039B, ORDINARY, Lambda
+0x039C, ORDINARY
+0x21C1, ORDINARY, rightharpoondown
+0x22E7, RELATION, gnsim
+0x22E6, RELATION, lnsim
+0x22E1, ORDINARY
+0x21C2, ORDINARY, downharpoonright
+0xFE68, ORDINARY
+0x22E9, RELATION, succnsim
+0x22E8, RELATION, precnsim
+0x22EE, ORDINARY, vdots
+0x22ED, ORDINARY, ntrianglerighteq
+0x019B, ORDINARY, lambdabar
+0x22EF, ORDINARY, cdots
+0x22EA, ORDINARY, ntriangleleft
+0x22EC, ORDINARY, ntrianglelefteq
+0x22EB, ORDINARY, ntriangleright
+0xEA42, ORDINARY
+0xEB1A, ORDINARY
+0xE5CF, RELATION, eqslantless
+0x0398, ORDINARY, Theta
+0x0399, ORDINARY
+0x0396, ORDINARY
+0x0397, ORDINARY
+0x0394, ORDINARY, Delta
+0x0395, ORDINARY
+0x0392, ORDINARY
+0x0393, ORDINARY, Gamma
+0x0391, ORDINARY
+0x2252, ORDINARY, fallingdotseq
+0x03B9, ORDINARY, iota
+0xE2B0, RELATION, nsupseteqq
+0x2277, RELATION, gtrless
+0x2276, RELATION, lessgtr
+0x21CF, ORDINARY, nRightarrow
+0x2273, RELATION, gtrsim
+0x2272, RELATION, lesssim
+0x2271, RELATION, ngeq
+0x2270, RELATION, nleq
+0x21BC, ORDINARY, leftharpoonup
+0x22C6, ORDINARY, star
+0xF08A, ORDINARY
+0xF08B, ORDINARY
+0x2269, RELATION, gneqq
+0x03D1, ORDINARY, vartheta
+0x25B6, ORDINARY, blacktriangleright
+0x25B5, ORDINARY, vartriangle
+0x25B4, ORDINARY, blacktriangle
+0x03D5, ORDINARY, varphi
+0x25B2, ORDINARY
+0x25B1, ORDINARY
+0x03D6, ORDINARY, varpi
+0xEC0B, ORDINARY
+0xEC0C, ORDINARY
+0x2280, RELATION, nprec
+0x2281, RELATION, nsucc
+0xEC0F, ORDINARY
+0xEE0B, ORDINARY
+0x2284, RELATION, nsubset
+0xEC0E, ORDINARY
+0xE629, ORDINARY, epsilon
+0x2288, ORDINARY, nsubseteq
+0x2289, ORDINARY, nsupseteq
+0x22DD, ORDINARY, eqgtr
+0x02D8, ORDINARY
+0x22DE, RELATION, curlyeqprec
+0xFFFD, ORDINARY
+0xE2B8, RELATION, varsubsetneqq
+0x221A, ORDINARY, surd
+0x22DB, RELATION, gtreqless
+0x039A, ORDINARY
+0x21DA, ORDINARY, Lleftarrow
+0x221D, RELATION, propto
+0x21DB, ORDINARY, Rrightarrow
+0xE2BA, RELATION, varsupsetneq
+0x0307, ORDINARY
+0x220A, RELATION, in
+0x0300, ORDINARY, grave
+0x0303, ORDINARY
+0x0302, ORDINARY, hat
+0x266D, ORDINARY, flat
+0x20D0, ORDINARY, leftharpoonaccent
+0x266F, ORDINARY, sharp
+0x22DA, RELATION, lesseqgtr
+0x0192, ORDINARY
+0x00AC, ORDINARY, neg
+0x2661, ORDINARY, heartsuit
+0x211B, ORDINARY
+0xEA45, ORDINARY
+0xEA46, ORDINARY
+0x211A, ORDINARY
+0xEA40, ORDINARY
+0xEA41, ORDINARY
+0x211D, ORDINARY
+0xEA43, ORDINARY
+0x03BE, ORDINARY, xi
+0x22E0, ORDINARY
+0x2112, ORDINARY
+0x2113, ORDINARY
+0x2110, ORDINARY
+0x03BD, ORDINARY, nu
+0x2115, ORDINARY
+0x2127, ORDINARY, mho
+0x2118, ORDINARY, wp
+0x2119, ORDINARY
+0x0161, ORDINARY
+0x0160, ORDINARY
+0xE2B2, RELATION, precnapprox
+0x00A9, ORDINARY
+0xE2B4, RELATION, succnapprox
+0xE2B7, RELATION, supsetneqq
+0xE2B6, RELATION, subsetneqq
+0xE2B9, RELATION, varsubsetneq
+0x2665, ORDINARY, heartsuit
+0x2666, ORDINARY, diamondsuit
+0x00A6, ORDINARY
+0x2660, ORDINARY, spadesuit
+0x00A0, ORDINARY
+0x2662, ORDINARY, diamondsuit
+0x2663, ORDINARY, clubsuit
+0x2218, ORDINARY, circ
+0x03F1, ORDINARY, varrho
+0x03F0, ORDINARY, varkappa
+0xEA2F, ORDINARY
+0x21D5, ORDINARY, Updownarrow
+0x2210, ORDINARY, coprod
+0x2213, ORDINARY, mp
+0x2212, BINOP, minus
+0x2215, ORDINARY, slash
+0x21D0, RELATION, Leftarrow
+0x21D3, RELATION, Downarrow
+0x2216, ORDINARY
+0xEC02, ORDINARY
+0xEC03, ORDINARY
+0xEC00, ORDINARY
+0x228A, ORDINARY, subsetneq
+0xEC06, ORDINARY
+0xEC04, ORDINARY
+0xEC05, ORDINARY
+0x02DB, ORDINARY
+0xF116, ORDINARY
+0xF117, ORDINARY
+0xF114, ORDINARY
+0xE5DC, RELATION, npreceq
+0xF112, ORDINARY
+0xF113, ORDINARY
+0xE304, RELATION, subseteqq
+0xE305, RELATION, supseteqq
+0x21D1, RELATION, Uparrow
+0x25CB, ORDINARY, bigcirc
+0xF118, ORDINARY
+0xF119, ORDINARY
+0x22DF, RELATION, curlyeqsucc
+0x2217, BINOP, ast
+0xE2FD, RELATION, precapprox
+0x2026, ORDINARY, ldots
+0x20E1, ORDINARY, overleftrightarrow
+0x007D, ORDINARY, rbrace
+0x2022, BINOP, bullet
+0x223C, RELATION, sim
+0x228B, ORDINARY, supsetneq
+0x21A9, RELATION, hookleftarrow
+0x00FD, ORDINARY
+0x03D2, ORDINARY, Upsilon
+0xE663, ORDINARY, Upsilon
+0x22D1, ORDINARY, Supset
+0x00F7, BINOP, div
+0x22A9, ORDINARY, Vdash
+0x22A8, ORDINARY, vDash
+0x03A4, ORDINARY
+0x03A5, ORDINARY
+0x03A3, ORDINARY, Sigma
+0x03A0, ORDINARY, Pi
+0x03A1, ORDINARY
+0x22A1, ORDINARY, boxdot
+0x228F, ORDINARY, sqsubset
+0x22A3, ORDINARY, dashv
+0x22A2, ORDINARY
+0x22A5, ORDINARY
+0x22A4, ORDINARY, top
+0x03A8, ORDINARY, Psi
+0x03A9, ORDINARY, Omega
+0xEA2E, ORDINARY
+0x2138, ORDINARY, daleth
+0x231E, ORDINARY, llcorner
+0x22AA, ORDINARY, Vvdash
+0x2135, ORDINARY, aleph
+0x22AC, ORDINARY, nvdash
+0x2137, ORDINARY, gimel
+0x22AE, ORDINARY, nVdash
+0x22AD, ORDINARY, nvDash
+0x2132, ORDINARY, Finv
+0x22AF, ORDINARY, nVDash
+0x002E, PUNCTUATION
+0xEC01, ORDINARY
+0xEA47, ORDINARY
+0x2235, BINOP, because
+0x2234, BINOP, therefore
+0x2242, ORDINARY, eqsim
+0x231F, ORDINARY, lrcorner
+0x03BF, ORDINARY, o
+0x2243, RELATION, simeq
+0x2240, ORDINARY, wr
+0xE92E, ORDINARY
+0x226A, RELATION, ll
+0x231C, ORDINARY, ulcorner
+0x2214, ORDINARY, dotplus
+0xEA3E, ORDINARY
+0xEA3D, ORDINARY
+0xEA3F, ORDINARY
+0xEA3A, ORDINARY
+0x266E, ORDINARY, natural
+0xEA3C, ORDINARY
+0xEA3B, ORDINARY
+0xEC24, ORDINARY
+0xEC25, ORDINARY
+0xEC26, ORDINARY
+0xEC27, ORDINARY
+0xEC22, ORDINARY
+0xEC23, ORDINARY
+0xEE04, ORDINARY
+0xEE05, ORDINARY
+0xEE06, ORDINARY
+0xEE07, ORDINARY
+0xEE00, ORDINARY
+0xEE01, ORDINARY
+0xEA34, ORDINARY
+0x22D7, RELATION, gtrdot
+0xEE08, ORDINARY
+0xEE09, ORDINARY
+0xEA10, ORDINARY
+0x0037, ORDINARY
+0x0036, ORDINARY
+0x0035, ORDINARY
+0x0034, ORDINARY
+0x0033, ORDINARY
+0x0032, ORDINARY
+0x0031, ORDINARY
+0x0030, ORDINARY
+0x21C7, ORDINARY, leftleftarrows
+0x0039, ORDINARY
+0x0038, ORDINARY
+0x231D, ORDINARY, urcorner
+0x2247, ORDINARY, ncong
+0x2244, ORDINARY, nsime
+0x2245, RELATION, cong
+0x22C7, ORDINARY, divideontimes
+0xE5DF, RELATION, eqslantgtr
+0x22C5, BINOP, cdot
+0x2241, ORDINARY
+0x22C9, ORDINARY, ltimes
+0xEA32, ORDINARY
+0x2287, RELATION, supseteq
+0x2248, RELATION, approx
+0x0131, ORDINARY
+0x03C0, ORDINARY, pi
+0x03C1, ORDINARY, rho
+0x03C2, ORDINARY
+0x03C3, ORDINARY, sigma
+0x03C4, ORDINARY, tau
+0x03C5, ORDINARY, upsilon
+0x03C6, ORDINARY, phi
+0x03C7, ORDINARY, chi
+0x03C8, ORDINARY, psi
+0x03C9, ORDINARY, omega
+0xE933, ORDINARY
+0xE932, ORDINARY
+0x25AD, ORDINARY
+0x26C4, ORDINARY, Diamond
+0x25A0, ORDINARY
+0x25AA, ORDINARY
+0x25A1, ORDINARY
+0xE93A, ORDINARY
+0xE93B, ORDINARY
+0x224F, ORDINARY, bumpeq
+0x22CB, ORDINARY, leftthreetimes
+0x22CA, ORDINARY, rtimes
+0x224E, ORDINARY, Bumpeq
+0x22CF, ORDINARY, curlywedge
+0x22CE, ORDINARY, curlyvee
+0x224A, ORDINARY, approxeq
+0x003F, ORDINARY
+0x003E, RELATION, greater
+0x003D, RELATION
+0x003C, RELATION, less
+0x003B, PUNCTUATION
+0x003A, PUNCTUATION, colon
+0x2225, ORDINARY
+0xEB19, ORDINARY
+0xF115, ORDINARY
+0x22D6, RELATION, lessdot
+0xEE0E, ORDINARY
+0xEE0F, ORDINARY
+0x22D2, ORDINARY, Cap
+0xEE0A, ORDINARY
+0xE98F, ORDINARY
+0xEE0C, ORDINARY
+0xEB04, ORDINARY
+0x2220, ORDINARY, angle
+0x22D8, RELATION, lll
+0x22BA, ORDINARY, intercal
+0xEE13, ORDINARY
+0x21DD, ORDINARY, rightzigzagarrow
+0x22BB, ORDINARY, veebar
+0xF08C, ORDINARY
+0xF8EF, ORDINARY
+0xF8EE, ORDINARY
+0xF8ED, ORDINARY
+0xF8EC, ORDINARY
+0xF8FD, ORDINARY
+0xF8EA, ORDINARY
+0x2720, ORDINARY, maltese
+0x2605, ORDINARY, bigstar
+0xF8FE, ORDINARY
+0x21CB, ORDINARY, leftrightharpoons
+0x21CC, ORDINARY, rightleftharpoons
+0xE2A6, RELATION, ngeqslant
+0xF8FC, ORDINARY
+0x2260, RELATION, neq
+0x2261, RELATION, equiv
+0xE29F, RELATION, gnapprox
+0x00B3, ORDINARY
+0x2264, RELATION, leq
+0x2265, RELATION, geq
+0x2266, RELATION, leqq
+0x2267, RELATION, geqq
+0x2268, RELATION, lneqq
+0x21BB, ORDINARY, cwopencirclearrow
+0x21BA, ORDINARY, acwopencirclearrow
+0xF8FA, ORDINARY
+0x21BF, ORDINARY, upharpoonleft
+0x21BE, ORDINARY, upharpoonright
+0x21BD, ORDINARY, leftharpoondown
+0x25C0, ORDINARY, blacktriangleleft
+0x002F, ORDINARY
+0x24C8, ORDINARY, circledS
+0x007B, ORDINARY, lbrace
+0xF093, ORDINARY
+0x301A, ORDINARY
+0x301B, ORDINARY
+0xF097, ORDINARY
+0xF096, ORDINARY
+0xF095, ORDINARY
+0xF094, ORDINARY
+0xF098, ORDINARY
+0x21CE, ORDINARY, nLeftrightarrow
+0xE300, RELATION, succeq
+0xF8E7, ORDINARY
+0x226B, RELATION, gg
+0x226C, RELATION, between
+0x007C, ORDINARY, mid
+0x226E, RELATION, nless
+0x226F, RELATION, ngtr
+0x00FE, ORDINARY
+0x21B1, ORDINARY, Rsh
+0x21B0, ORDINARY, Lsh
+0x21B7, ORDINARY, curvearrowright
+0x21B6, ORDINARY, curvearrowleft
+0x21B5, ORDINARY, carriagereturn
+0x22CC, ORDINARY, rightthreetimes
+0x005C, ORDINARY, backslash
+0x005B, ORDINARY, lbrack
+0xF08E, ORDINARY
+0x005D, ORDINARY, rbrack
+0x005F, ORDINARY
+0x25B3, ORDINARY, bigtriangleup
+0x224D, ORDINARY, asymp
+0x22F0, ORDINARY, adots
+0x22F1, ORDINARY, ddots
+0x20D7, ORDINARY, vec
+0xF8E9, ORDINARY
+0xF8E8, ORDINARY
+0xEB03, ORDINARY
+0xF8E6, RELATION
+0xF8E5, ORDINARY
+0xEB00, ORDINARY
+0xFB02, ORDINARY
+0xEB06, ORDINARY
+0xEB05, ORDINARY
+0xFB01, ORDINARY
diff --git a/lib/kformula/contextstyle.cc b/lib/kformula/contextstyle.cc
new file mode 100644
index 00000000..61e290f4
--- /dev/null
+++ b/lib/kformula/contextstyle.cc
@@ -0,0 +1,765 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
+ Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+ 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qfontmetrics.h>
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <KoGlobal.h>
+
+#include "contextstyle.h"
+#include "fontstyle.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+ContextStyle::ContextStyle()
+ : symbolFont( "Symbol" ),
+ defaultColor(Qt::black), numberColor(Qt::blue),
+ operatorColor(Qt::darkGreen), errorColor(Qt::darkRed),
+ emptyColor(Qt::blue), helpColor( Qt::gray ), m_sizeFactor( 0 )
+{
+// kdDebug() << "ContextStyle::ContextStyle" << endl
+// << "defaultFont: " << defaultFont.rawName() << endl
+// << "nameFont: " << nameFont.rawName() << endl
+// << "numberFont: " << numberFont.rawName() << endl
+// << "operatorFont: " << operatorFont.rawName() << endl
+// << "symbolFont: " << symbolFont.rawName() << endl;
+
+ textStyleValues[ displayStyle ].setup( 1. );
+ textStyleValues[ textStyle ].setup( 1. );
+ textStyleValues[ scriptStyle ].setup( .7 );
+ textStyleValues[ scriptScriptStyle ].setup( .49 );
+
+ m_baseTextStyle = displayStyle;
+
+ lineWidth = 1;
+ linearMovement = false;
+ centerSymbol = true;
+ m_syntaxHighlighting = true;
+
+ m_fontStyle = 0;
+}
+
+
+ContextStyle::~ContextStyle()
+{
+ delete m_fontStyle;
+}
+
+
+void ContextStyle::init( bool init )
+{
+ setup();
+ setFontStyle( m_fontStyleName, init );
+}
+
+
+void ContextStyle::setFontStyle( const QString& fontStyle, bool init )
+{
+ delete m_fontStyle;
+ m_fontStyleName = fontStyle;
+ m_fontStyle = new FontStyle();
+ m_fontStyle->init( this, init );
+}
+
+
+const SymbolTable& ContextStyle::symbolTable() const
+{
+ return *( m_fontStyle->symbolTable() );
+}
+
+
+void ContextStyle::readConfig( KConfig* config, bool init )
+{
+ config->setGroup( "kformula Font" );
+ QString fontName = config->readEntry( "defaultFont", "Times,12,-1,5,50,1,0,0,0,0" );
+ defaultFont.fromString( fontName );
+ fontName = config->readEntry( "nameFont", "Times,12,-1,5,50,0,0,0,0,0" );
+ nameFont.fromString( fontName );
+ fontName = config->readEntry( "numberFont", "Times,12,-1,5,50,0,0,0,0,0" );
+ numberFont.fromString( fontName );
+ fontName = config->readEntry( "operatorFont", "Times,12,-1,5,50,0,0,0,0,0" );
+ operatorFont.fromString( fontName );
+ QString baseSize = config->readEntry( "baseSize", "20" );
+ m_baseSize = baseSize.toInt();
+
+ if ( ! FontStyle::missingFonts( init ).isEmpty() ) {
+ kdWarning( DEBUGID) << "Not all basic fonts found\n";
+ }
+ mathFont.fromString("Arev Sans");
+ bracketFont.fromString("cmex10");
+
+
+ // There's no gui right anymore but I'll leave it here...
+ config->setGroup( "kformula Color" );
+ defaultColor = config->readColorEntry( "defaultColor", &defaultColor );
+ numberColor = config->readColorEntry( "numberColor", &numberColor );
+ operatorColor = config->readColorEntry( "operatorColor", &operatorColor );
+ emptyColor = config->readColorEntry( "emptyColor", &emptyColor );
+ errorColor = config->readColorEntry( "errorColor", &errorColor );
+ helpColor = config->readColorEntry( "helpColor", &helpColor );
+
+ m_syntaxHighlighting = config->readBoolEntry( "syntaxHighlighting", true );
+}
+
+void ContextStyle::setZoomAndResolution( int zoom, int dpiX, int dpiY )
+{
+ KoZoomHandler::setZoomAndResolution( zoom, dpiX, dpiY );
+}
+
+bool ContextStyle::setZoomAndResolution( int zoom, double zoomX, double zoomY, bool, bool )
+{
+ bool changes = m_zoom != zoom || m_zoomedResolutionX != zoomX || m_zoomedResolutionY != zoomY;
+ m_zoom = zoom;
+ m_zoomedResolutionX = zoomX;
+ m_zoomedResolutionY = zoomY;
+ return changes;
+}
+
+QColor ContextStyle::getNumberColor() const
+{
+ if ( edit() && syntaxHighlighting() ) {
+ return numberColor;
+ }
+ return getDefaultColor();
+}
+
+QColor ContextStyle::getOperatorColor() const
+{
+ if ( edit() && syntaxHighlighting() ) {
+ return operatorColor;
+ }
+ return getDefaultColor();
+}
+
+QColor ContextStyle::getErrorColor() const
+{
+ if ( edit() && syntaxHighlighting() ) {
+ return errorColor;
+ }
+ return getDefaultColor();
+}
+
+QColor ContextStyle::getEmptyColor() const
+{
+ if ( edit() && syntaxHighlighting() ) {
+ return emptyColor;
+ }
+ return getDefaultColor();
+}
+
+QColor ContextStyle::getHelpColor() const
+{
+ if ( edit() && syntaxHighlighting() ) {
+ return helpColor;
+ }
+ return getDefaultColor();
+}
+
+void ContextStyle::setDefaultColor( const QColor& color )
+{
+ defaultColor = color;
+}
+void ContextStyle::setNumberColor( const QColor& color )
+{
+ numberColor = color;
+}
+void ContextStyle::setOperatorColor( const QColor& color )
+{
+ operatorColor = color;
+}
+void ContextStyle::setErrorColor( const QColor& color )
+{
+ errorColor = color;
+}
+void ContextStyle::setEmptyColor( const QColor& color )
+{
+ emptyColor = color;
+}
+void ContextStyle::setHelpColor( const QColor& color )
+{
+ helpColor = color;
+}
+
+#if 0
+const QStringList& ContextStyle::requestedFonts() const
+{
+ return m_requestedFonts;
+}
+
+void ContextStyle::setRequestedFonts( const QStringList& list )
+{
+ m_requestedFonts = list;
+ //table.init( this );
+}
+#endif
+
+double ContextStyle::getReductionFactor( TextStyle tstyle ) const
+{
+ return textStyleValues[ tstyle ].reductionFactor;
+}
+
+luPt ContextStyle::getAdjustedSize( TextStyle tstyle, double factor ) const
+{
+ return qRound( ptToLayoutUnitPt( m_sizeFactor
+ * m_baseSize
+ * getReductionFactor( tstyle )
+ * factor
+ * zoom() / 100.0 ) );
+}
+
+luPixel ContextStyle::getSpace( TextStyle tstyle, SpaceWidth space, double factor ) const
+{
+ switch ( space ) {
+ case NEGTHIN: return -getThinSpace( tstyle, factor );
+ case THIN: return getThinSpace( tstyle, factor );
+ case MEDIUM: return getMediumSpace( tstyle, factor );
+ case THICK: return getThickSpace( tstyle, factor );
+ case QUAD: return getQuadSpace( tstyle, factor );
+ }
+ return 0;
+}
+
+luPixel ContextStyle::getThinSpace( TextStyle tstyle, double factor ) const
+{
+ return ptToPixelX( m_sizeFactor
+ * textStyleValues[ tstyle ].thinSpace( quad )
+ * factor
+ * zoom() / 100.0 );
+}
+
+luPixel ContextStyle::getMediumSpace( TextStyle tstyle, double factor ) const
+{
+ return ptToPixelX( m_sizeFactor
+ * textStyleValues[ tstyle ].mediumSpace( quad )
+ * factor
+ * zoom() / 100.0 );
+}
+
+luPixel ContextStyle::getThickSpace( TextStyle tstyle, double factor ) const
+{
+ return ptToPixelX( m_sizeFactor
+ * textStyleValues[ tstyle ].thickSpace( quad )
+ * factor
+ * zoom() / 100.0 );
+}
+
+luPixel ContextStyle::getQuadSpace( TextStyle tstyle, double factor ) const
+{
+ return ptToPixelX( m_sizeFactor
+ * textStyleValues[ tstyle ].quadSpace( quad )
+ * factor
+ * zoom() / 100.0 );
+}
+
+luPixel ContextStyle::axisHeight( TextStyle tstyle, double factor ) const
+{
+ //return ptToPixelY( textStyleValues[ tstyle ].axisHeight( m_axisHeight ) );
+ return static_cast<luPixel>( m_sizeFactor
+ * textStyleValues[ tstyle ].axisHeight( m_axisHeight )
+ * factor
+ * zoom() / 100.0 );
+}
+
+luPt ContextStyle::getBaseSize() const
+{
+ return static_cast<luPt>( ptToLayoutUnitPt( m_sizeFactor*m_baseSize ) );
+}
+
+void ContextStyle::setBaseSize( int size )
+{
+ //kdDebug( 40000 ) << "ContextStyle::setBaseSize" << endl;
+ if ( size != m_baseSize ) {
+ m_baseSize = size;
+ setup();
+ }
+}
+
+void ContextStyle::setSizeFactor( double factor )
+{
+ m_sizeFactor = factor;
+}
+
+
+luPixel ContextStyle::getLineWidth( double factor ) const
+{
+ return ptToLayoutUnitPixX( m_sizeFactor*lineWidth*factor*zoom() / 100.0 );
+}
+
+luPixel ContextStyle::getEmptyRectWidth( double factor ) const
+{
+ return ptToLayoutUnitPixX( m_sizeFactor*m_baseSize*factor*(zoom() / 100.0)/1.8 );
+}
+
+luPixel ContextStyle::getEmptyRectHeight( double factor ) const
+{
+ return ptToLayoutUnitPixX( m_sizeFactor*m_baseSize*factor*(zoom() / 100.0)/1.8 );
+}
+
+
+ContextStyle::TextStyle ContextStyle::convertTextStyleFraction( TextStyle tstyle ) const
+{
+ TextStyle result;
+
+ switch ( tstyle ){
+ case displayStyle:
+ result = textStyle;
+ break;
+ case textStyle:
+ result = scriptStyle;
+ break;
+ default:
+ result = scriptScriptStyle;
+ break;
+ }
+
+ return result;
+}
+
+
+ContextStyle::TextStyle ContextStyle::convertTextStyleIndex( TextStyle tstyle ) const
+{
+ TextStyle result;
+
+ switch ( tstyle ){
+ case displayStyle:
+ result = scriptStyle;
+ break;
+ case textStyle:
+ result = scriptStyle;
+ break;
+ default:
+ result = scriptScriptStyle;
+ break;
+ }
+
+ return result;
+}
+
+
+void ContextStyle::setup()
+{
+ luPt size = static_cast<luPt>( m_baseSize );
+ QFont font = symbolFont;
+ font.setPointSize( size );
+ QFontMetrics fm( font );
+
+ // Or better the real space required? ( boundingRect )
+ quad = ptToLayoutUnitPt( fm.width( 'M' ) );
+
+ font = QFont(defaultFont);
+ font.setPointSize( size );
+ QFontMetrics fm2( font );
+ //m_axisHeight = ptToLayoutUnitPt( fm2.strikeOutPos() );
+ //ptToLayoutUnitPixY
+ //m_axisHeight = ptToLayoutUnitPt( pixelYToPt( fm2.strikeOutPos() ) );
+ m_axisHeight = ptToLayoutUnitPixY( pixelYToPt( fm2.strikeOutPos() ) );
+}
+
+
+double StyleAttributes::sizeFactor() const
+{
+ if ( m_size.empty() ) {
+// kdWarning( DEBUGID ) << "SizeFactor stack is empty.\n";
+ return 1.0;
+ }
+ return m_size.top();
+}
+
+bool StyleAttributes::customMathVariant() const
+{
+ if ( m_customMathVariant.empty() ) {
+ return false;
+ }
+ return m_customMathVariant.top();
+}
+
+CharStyle StyleAttributes::charStyle() const
+{
+ if ( m_charStyle.empty() ) {
+// kdWarning( DEBUGID ) << "CharStyle stack is empty.\n";
+ return anyChar;
+ }
+ return m_charStyle.top();
+}
+
+CharFamily StyleAttributes::charFamily() const
+{
+ if ( m_charFamily.empty() ) {
+// kdWarning( DEBUGID ) << "CharFamily stack is empty.\n";
+ return anyFamily;
+ }
+ return m_charFamily.top();
+}
+
+QColor StyleAttributes::color() const
+{
+ if ( m_color.empty() ) {
+// kdWarning( DEBUGID ) << "Color stack is empty.\n";
+ return QColor( Qt::black );
+ //return getDefaultColor();
+ }
+ return m_color.top();
+}
+
+QColor StyleAttributes::background() const
+{
+ if ( m_background.empty() ) {
+// kdWarning( DEBUGID ) << "Background stack is empty.\n";
+ return QColor( Qt::color0 );
+ }
+ return m_background.top();
+}
+
+QFont StyleAttributes::font() const
+{
+ if ( m_font.empty() ) {
+ return QFont();
+ }
+ return m_font.top();
+}
+
+bool StyleAttributes::fontWeight() const
+{
+ if ( m_fontWeight.empty() ) {
+ return false;
+ }
+ return m_fontWeight.top();
+}
+
+bool StyleAttributes::customFontWeight() const
+{
+ if ( m_customFontWeight.empty() ) {
+ return false;
+ }
+ return m_customFontWeight.top();
+}
+
+bool StyleAttributes::fontStyle() const
+{
+ if ( m_fontStyle.empty() ) {
+ return false;
+ }
+ return m_fontStyle.top();
+}
+
+bool StyleAttributes::customFontStyle() const
+{
+ if ( m_customFontStyle.empty() ) {
+ return false;
+ }
+ return m_customFontStyle.top();
+}
+
+bool StyleAttributes::customFont() const
+{
+ if ( m_customFontFamily.empty() ) {
+ return false;
+ }
+ return m_customFontFamily.top();
+}
+
+int StyleAttributes::scriptLevel() const
+{
+ if ( m_scriptLevel.empty() ) {
+ return 0;
+ }
+ return m_scriptLevel.top();
+}
+
+double StyleAttributes::scriptSizeMultiplier() const
+{
+ if ( m_scriptSizeMultiplier.empty() ) {
+ return scriptsizemultiplier;
+ }
+ return m_scriptSizeMultiplier.top();
+}
+
+double StyleAttributes::scriptMinSize() const
+{
+ if ( m_scriptMinSize.empty() ) {
+ return scriptminsize;
+ }
+ return m_scriptMinSize.top();
+}
+
+double StyleAttributes::veryVeryThinMathSpace() const
+{
+ if ( m_veryVeryThinMathSpace.empty() ) {
+ return veryverythinmathspace;
+ }
+ return m_veryVeryThinMathSpace.top();
+}
+
+double StyleAttributes::veryThinMathSpace() const
+{
+ if ( m_veryThinMathSpace.empty() ) {
+ return verythinmathspace;
+ }
+ return m_veryThinMathSpace.top();
+}
+
+double StyleAttributes::thinMathSpace() const
+{
+ if ( m_thinMathSpace.empty() ) {
+ return thinmathspace;
+ }
+ return m_thinMathSpace.top();
+}
+
+double StyleAttributes::mediumMathSpace() const
+{
+ if ( m_mediumMathSpace.empty() ) {
+ return mediummathspace;
+ }
+ return m_mediumMathSpace.top();
+}
+
+double StyleAttributes::thickMathSpace() const
+{
+ if ( m_thickMathSpace.empty() ) {
+ return thickmathspace;
+ }
+ return m_thickMathSpace.top();
+}
+
+double StyleAttributes::veryThickMathSpace() const
+{
+ if ( m_veryThickMathSpace.empty() ) {
+ return verythickmathspace;
+ }
+ return m_veryThickMathSpace.top();
+}
+
+double StyleAttributes::veryVeryThickMathSpace() const
+{
+ if ( m_veryVeryThickMathSpace.empty() ) {
+ return veryverythickmathspace;
+ }
+ return m_veryVeryThickMathSpace.top();
+}
+
+bool StyleAttributes::displayStyle() const
+{
+ if ( m_displayStyle.empty() ) {
+ return true;
+ }
+ return m_displayStyle.top();
+}
+
+bool StyleAttributes::customDisplayStyle() const
+{
+ if ( m_customDisplayStyle.empty() ) {
+ return false;
+ }
+ return m_customDisplayStyle.top();
+}
+
+double StyleAttributes::getSpace( SizeType type, double length ) const
+{
+ switch ( type ) {
+ case NegativeVeryVeryThinMathSpace:
+ return - veryVeryThinMathSpace();
+ case NegativeVeryThinMathSpace:
+ return - veryThinMathSpace();
+ case NegativeThinMathSpace:
+ return - thinMathSpace();
+ case NegativeMediumMathSpace:
+ return - mediumMathSpace();
+ case NegativeThickMathSpace:
+ return - thickMathSpace();
+ case NegativeVeryThickMathSpace:
+ return - veryThickMathSpace();
+ case NegativeVeryVeryThickMathSpace:
+ return - veryVeryThickMathSpace();
+ case VeryVeryThinMathSpace:
+ return veryVeryThinMathSpace();
+ case VeryThinMathSpace:
+ return veryThinMathSpace();
+ case ThinMathSpace:
+ return thinMathSpace();
+ case MediumMathSpace:
+ return mediumMathSpace();
+ case ThickMathSpace:
+ return thickMathSpace();
+ case VeryThickMathSpace:
+ return veryThickMathSpace();
+ case VeryVeryThickMathSpace:
+ return veryVeryThickMathSpace();
+ default:
+ break;
+ }
+ return length;
+}
+
+void StyleAttributes::resetSize()
+{
+ if ( ! m_size.empty() ) {
+ m_size.pop();
+ }
+}
+
+void StyleAttributes::resetCharStyle()
+{
+ if ( ! m_charStyle.empty() ) {
+ m_charStyle.pop();
+ }
+}
+
+void StyleAttributes::resetCharFamily()
+{
+ if ( ! m_charFamily.empty() ) {
+ m_charFamily.pop();
+ }
+}
+
+void StyleAttributes::resetColor()
+{
+ if ( ! m_color.empty() ) {
+ m_color.pop();
+ }
+}
+
+void StyleAttributes::resetBackground()
+{
+ if ( ! m_background.empty() ) {
+ m_background.pop();
+ }
+}
+
+void StyleAttributes::resetFontFamily()
+{
+ if ( ! m_customFontFamily.empty() ) {
+ if ( m_customFontFamily.pop() ) {
+ if ( ! m_font.empty() ) {
+ m_font.pop();
+ }
+ }
+ }
+}
+
+void StyleAttributes::resetFontWeight()
+{
+ if ( ! m_customFontWeight.empty() ) {
+ if ( m_customFontWeight.pop() ) {
+ if ( ! m_fontWeight.empty() ) {
+ m_fontWeight.pop();
+ }
+ }
+ }
+}
+
+void StyleAttributes::resetFontStyle()
+{
+ if ( ! m_customFontStyle.empty() ) {
+ if ( m_customFontStyle.pop() ) {
+ if ( ! m_fontStyle.empty() ) {
+ m_fontStyle.pop();
+ }
+ }
+ }
+}
+
+void StyleAttributes::resetScriptLevel()
+{
+ if ( ! m_scriptLevel.empty() ) {
+ m_scriptLevel.pop();
+ }
+}
+
+void StyleAttributes::resetScriptSizeMultiplier()
+{
+ if ( ! m_scriptSizeMultiplier.empty() ) {
+ m_scriptSizeMultiplier.pop();
+ }
+}
+
+void StyleAttributes::resetScriptMinSize()
+{
+ if ( ! m_scriptMinSize.empty() ) {
+ m_scriptMinSize.pop();
+ }
+}
+
+void StyleAttributes::resetVeryVeryThinMathSpace()
+{
+ if ( ! m_veryVeryThinMathSpace.empty() ) {
+ m_veryVeryThinMathSpace.pop();
+ }
+}
+
+void StyleAttributes::resetVeryThinMathSpace()
+{
+ if ( ! m_veryThinMathSpace.empty() ) {
+ m_veryThinMathSpace.pop();
+ }
+}
+
+void StyleAttributes::resetThinMathSpace()
+{
+ if ( ! m_thinMathSpace.empty() ) {
+ m_thinMathSpace.pop();
+ }
+}
+
+void StyleAttributes::resetMediumMathSpace()
+{
+ if ( ! m_mediumMathSpace.empty() ) {
+ m_mediumMathSpace.pop();
+ }
+}
+
+void StyleAttributes::resetThickMathSpace()
+{
+ if ( ! m_thickMathSpace.empty() ) {
+ m_thickMathSpace.pop();
+ }
+}
+
+void StyleAttributes::resetVeryThickMathSpace()
+{
+ if ( ! m_veryThickMathSpace.empty() ) {
+ m_veryThickMathSpace.pop();
+ }
+}
+
+void StyleAttributes::resetVeryVeryThickMathSpace()
+{
+ if ( ! m_veryVeryThickMathSpace.empty() ) {
+ m_veryVeryThickMathSpace.pop();
+ }
+}
+
+void StyleAttributes::resetDisplayStyle()
+{
+ if ( ! m_customDisplayStyle.empty() ) {
+ if ( m_customDisplayStyle.pop() ) {
+ if ( ! m_displayStyle.empty() ) {
+ m_displayStyle.pop();
+ }
+ }
+ }
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/contextstyle.h b/lib/kformula/contextstyle.h
new file mode 100644
index 00000000..811c580a
--- /dev/null
+++ b/lib/kformula/contextstyle.h
@@ -0,0 +1,480 @@
+/* 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.
+*/
+
+#ifndef CONTEXTSTYLE_H
+#define CONTEXTSTYLE_H
+
+//Qt Include
+#include <qcolor.h>
+#include <qfont.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluestack.h>
+
+//KDE Include
+#include <kconfig.h>
+#include <KoTextZoomHandler.h>
+
+//Formula include
+#include "kformuladefs.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+class FontStyle;
+class SymbolTable;
+
+
+/**
+ * Contains all the style information for the formela. The idea
+ * is to change the values here (user configurable) and have
+ * the elements paint themselves with this information.
+ *
+ * All distances are stored in point. Most methods return pixel
+ * values.
+ */
+class ContextStyle : public KoTextZoomHandler
+{
+public:
+
+ enum Alignment { left, center, right };
+
+ /**
+ * Textstyles like in TeX. In the remaining documentation, the
+ * styles are abbreviated like this:
+ *
+ * displayStyle: D
+ *
+ * textStyle: T
+ *
+ * scriptStyle: S
+ *
+ * scriptScriptStyle: SS
+ **/
+ enum TextStyle {
+ displayStyle = 0,
+ textStyle = 1,
+ scriptStyle = 2,
+ scriptScriptStyle = 3
+ };
+
+ enum IndexStyle {normal, cramped};
+
+ /**
+ * Build a default context style
+ */
+ ContextStyle();
+ ~ContextStyle();
+
+ /**
+ * @param init if true fonts may be installed if needed.
+ */
+ void init( bool init = true );
+
+ /**
+ * @param init true if initialization may take place. This may cause font
+ * installation. Mark as false when this is not intended (i. e. creating
+ * configuration dialog from another component)
+ */
+ void readConfig( KConfig* config, bool init = true );
+
+ bool edit() const { return m_edit; }
+ void setEdit( bool e ) { m_edit = e; }
+
+ /**
+ * @returns our symbol table.
+ */
+ const SymbolTable& symbolTable() const;
+
+ const FontStyle& fontStyle() const { return *m_fontStyle; }
+
+
+ void setZoomAndResolution( int zoom, int dpiX, int dpiY );
+
+ /**
+ * Sets the zoom by hand. This is to be used in <code>paintContent</code>.
+ * @returns whether there was any change.
+ */
+ bool setZoomAndResolution( int zoom, double zoomX, double zoomY, bool updateViews, bool forPrint );
+
+ bool syntaxHighlighting() const { return m_syntaxHighlighting; }
+ void setSyntaxHighlighting( bool highlight ) { m_syntaxHighlighting = highlight; }
+
+ QColor getDefaultColor() const { return defaultColor; }
+ QColor getNumberColorPlain() const { return numberColor; }
+ QColor getOperatorColorPlain() const { return operatorColor; }
+ QColor getErrorColorPlain() const { return errorColor; }
+ QColor getEmptyColorPlain() const { return emptyColor; }
+ QColor getHelpColorPlain() const { return helpColor; }
+ QColor getNumberColor() const;
+ QColor getOperatorColor() const;
+ QColor getErrorColor() const;
+ QColor getEmptyColor() const;
+ QColor getHelpColor() const;
+
+ void setDefaultColor( const QColor& );
+ void setNumberColor( const QColor& );
+ void setOperatorColor( const QColor& );
+ void setErrorColor( const QColor& );
+ void setEmptyColor( const QColor& );
+ void setHelpColor( const QColor& );
+
+ QString getFontStyle() const { return m_fontStyleName; }
+ void setFontStyle( const QString& fontStyle, bool init = true );
+
+ QFont getMathFont() const { return mathFont; }
+ QFont getBracketFont() const { return bracketFont; }
+ QFont getDefaultFont() const { return defaultFont; }
+ QFont getNameFont() const { return nameFont; }
+ QFont getNumberFont() const { return numberFont; }
+ QFont getOperatorFont() const { return operatorFont; }
+ QFont getSymbolFont() const { return symbolFont; }
+
+ void setMathFont( QFont f ) { defaultFont = f; }
+ void setBracketFont( QFont f ) { bracketFont = f; }
+ void setDefaultFont( QFont f ) { defaultFont = f; }
+ void setNameFont( QFont f ) { nameFont = f; }
+ void setNumberFont( QFont f ) { numberFont = f; }
+ void setOperatorFont( QFont f ) { operatorFont = f; }
+
+ //const QStringList& requestedFonts() const;
+ //void setRequestedFonts( const QStringList& list );
+
+ double getReductionFactor( TextStyle tstyle ) const;
+
+ luPt getBaseSize() const;
+ int baseSize() const { return m_baseSize; }
+ void setBaseSize( int pointSize );
+ void setSizeFactor( double factor );
+
+ TextStyle getBaseTextStyle() const { return m_baseTextStyle; }
+ bool isScript( TextStyle tstyle ) const { return ( tstyle == scriptStyle ) ||
+ ( tstyle == scriptScriptStyle ); }
+
+ /**
+ * TeX like spacings.
+ */
+ luPixel getSpace( TextStyle tstyle, SpaceWidth space, double factor ) const;
+ luPixel getThinSpace( TextStyle tstyle, double factor ) const;
+ luPixel getMediumSpace( TextStyle tstyle, double factor ) const;
+ luPixel getThickSpace( TextStyle tstyle, double factor ) const;
+ luPixel getQuadSpace( TextStyle tstyle, double factor ) const;
+
+ luPixel axisHeight( TextStyle tstyle, double factor ) const;
+
+ /**
+ * Calculates the font size corresponding to the given TextStyle.
+ */
+ luPt getAdjustedSize( TextStyle tstyle, double factor ) const;
+
+ /**
+ * All simple lines like the one that makes up a fraction.
+ */
+ luPixel getLineWidth( double factor ) const;
+
+ luPixel getEmptyRectWidth( double factor ) const;
+ luPixel getEmptyRectHeight( double factor ) const;
+
+ Alignment getMatrixAlignment() const { return center; }
+
+ bool getCenterSymbol() const { return centerSymbol; }
+
+ /**
+ * Font-conversions a la TeX.
+ *
+ * For fractions (and also matrices), we have the following conversions:
+ * D->T, T->S, S,SS->SS
+ */
+ TextStyle convertTextStyleFraction( TextStyle tstyle ) const;
+
+ /**
+ * Font-conversions a la TeX.
+ *
+ * For indices, we have the following conversions:
+ * D->S, T->S, S,SS->SS
+ */
+ TextStyle convertTextStyleIndex( TextStyle tstyle ) const;
+
+ /**
+ * Index-style-conversions a la TeX.
+ *
+ * The function convertIndexStyleUpper is responsible for everything
+ * that ends 'up', like nominators of fractions, or upper indices.
+ *
+ * We have the following rule:
+ * normal->normal, cramped->cramped
+ */
+ IndexStyle convertIndexStyleUpper( IndexStyle istyle ) const {
+ return istyle; }
+
+
+ /**
+ * Index-style-conversions a la TeX.
+ *
+ * The function convertIndexStyleLower is responsible for everything
+ * that ends 'down', like nominators of fractions, or upper indices.
+ *
+ * We have the following rule:
+ * normal->cramped, cramped->cramped
+ */
+ IndexStyle convertIndexStyleLower( IndexStyle /*istyle*/ ) const {
+ return cramped; }
+
+private:
+
+ void setup();
+
+ struct TextStyleValues {
+
+ void setup( double reduction ) { reductionFactor = reduction; }
+
+ luPt thinSpace( luPt quad ) const { return static_cast<luPt>( reductionFactor*static_cast<double>( quad )/6. ); }
+ luPt mediumSpace( luPt quad ) const { return static_cast<luPt>( reductionFactor*static_cast<double>( quad )*2./9. ); }
+ luPt thickSpace( luPt quad ) const { return static_cast<luPt>( reductionFactor*static_cast<double>( quad )*5./18. ); }
+ luPt quadSpace( luPt quad ) const { return quad; }
+
+ luPixel axisHeight( luPixel height ) const { return static_cast<luPixel>( reductionFactor*height ); }
+ double reductionFactor;
+ };
+
+ TextStyleValues textStyleValues[ 4 ];
+
+ QFont mathFont;
+ QFont bracketFont;
+ QFont defaultFont;
+ QFont nameFont;
+ QFont numberFont;
+ QFont operatorFont;
+ QFont symbolFont;
+
+ //QStringList m_requestedFonts;
+
+ QColor defaultColor;
+ QColor numberColor;
+ QColor operatorColor;
+ QColor errorColor;
+ QColor emptyColor;
+ QColor helpColor;
+
+ /**
+ * The cursors movement style. You need to notify each cursor
+ * if you change this.
+ */
+ bool linearMovement;
+
+ /**
+ * The (font) size of the formula's main sequence.
+ */
+ int m_baseSize;
+
+ /**
+ * Hack! Each formula might set this to a value not too far from one
+ * to get a size different from the default one.
+ */
+ double m_sizeFactor;
+
+ /**
+ * The base text style of the formula.
+ **/
+ TextStyle m_baseTextStyle;
+
+ /**
+ * The thickness of our lines.
+ */
+ pt lineWidth;
+
+ /**
+ * Size of one quad.
+ */
+ luPt quad;
+
+ /**
+ * Distance between base line and axis.
+ */
+ luPixel m_axisHeight;
+
+ /**
+ * true means to center the symbol between its indexes.
+ * false means alignment to the right.
+ */
+ bool centerSymbol;
+
+ /**
+ * Whether we want coloured formulae.
+ */
+ bool m_syntaxHighlighting;
+
+ /**
+ * Whether we are in edit mode.
+ */
+ bool m_edit;
+
+ /**
+ * The symbols/names that are "known" to the system.
+ */
+ //SymbolTable table;
+
+ FontStyle* m_fontStyle;
+ QString m_fontStyleName;
+};
+
+// Section 3.3.4.2, default values
+const double scriptsizemultiplier = 0.71;
+const double scriptminsize = 8;
+const double veryverythinmathspace = 0.0555556;
+const double verythinmathspace = 0.111111;
+const double thinmathspace = 0.166667;
+const double mediummathspace = 0.222222;
+const double thickmathspace = 0.277778;
+const double verythickmathspace = 0.333333;
+const double veryverythickmathspace = 0.388889;
+
+class StyleAttributes {
+ public:
+ double sizeFactor() const ;
+ bool customMathVariant() const ;
+ CharStyle charStyle() const ;
+ CharFamily charFamily() const ;
+ QColor color() const ;
+ QColor background() const ;
+ QFont font() const ;
+ bool fontWeight() const ;
+ bool customFontWeight() const ;
+ bool fontStyle() const ;
+ bool customFontStyle() const ;
+ bool customFont() const ;
+
+ int scriptLevel() const ;
+ double scriptSizeMultiplier() const ;
+ double scriptMinSize() const ;
+ double veryVeryThinMathSpace() const ;
+ double veryThinMathSpace() const ;
+ double thinMathSpace() const ;
+ double mediumMathSpace() const ;
+ double thickMathSpace() const ;
+ double veryThickMathSpace() const ;
+ double veryVeryThickMathSpace() const ;
+ bool displayStyle() const ;
+ bool customDisplayStyle() const ;
+
+ double getSpace( SizeType type, double length ) const ;
+
+ void setSizeFactor( double s ) { m_size.push( s ); }
+ void setCustomMathVariant( bool cmv ) { m_customMathVariant.push( cmv ); }
+ void setCharStyle( CharStyle cs ) { m_charStyle.push( cs ); }
+ void setCharFamily( CharFamily cf ) { m_charFamily.push( cf ); }
+ void setColor( const QColor& c ) { m_color.push( c ); }
+ void setBackground( const QColor& bg ) { m_background.push( bg ); }
+ void setFont( const QFont& f ) { m_font.push( f ); }
+ void setCustomFont( bool cf ) { m_customFontFamily.push ( cf ); }
+ void setCustomFontWeight( bool cfw ) { m_customFontWeight.push( cfw ); }
+ void setFontWeight( bool fw ) { m_fontWeight.push( fw ); }
+ void setCustomFontStyle( bool cfs ) { m_customFontStyle.push( cfs ); }
+ void setFontStyle( bool fs ) { m_fontStyle.push( fs ); }
+
+ void setScriptLevel( int s ) { m_scriptLevel.push( s ); }
+ void setScriptSizeMultiplier( double s ) { m_scriptSizeMultiplier.push( s ); }
+ void setScriptMinSize( double s ) { m_scriptMinSize.push( s ); }
+ void setVeryVeryThinMathSpace( double s ) { m_veryVeryThinMathSpace.push( s ); }
+ void setVeryThinMathSpace( double s ) { m_veryThinMathSpace.push( s ); }
+ void setThinMathSpace( double s ) { m_thinMathSpace.push( s ); }
+ void setMediumMathSpace( double s ) { m_mediumMathSpace.push( s ); }
+ void setThickMathSpace( double s ) { m_thickMathSpace.push( s ); }
+ void setVeryThickMathSpace( double s ) { m_veryThickMathSpace.push( s ); }
+ void setVeryVeryThickMathSpace( double s ) { m_veryVeryThickMathSpace.push( s ); }
+ void setDisplayStyle( bool ds ) { m_displayStyle.push( ds ); }
+ void setCustomDisplayStyle( bool cds ) { m_customDisplayStyle.push( cds ); }
+
+ void reset();
+ void resetSize();
+ void resetCharStyle();
+ void resetCharFamily();
+ void resetColor();
+ void resetBackground();
+ void resetFontFamily();
+ void resetFontWeight();
+ void resetFontStyle();
+
+ void resetScriptLevel();
+ void resetScriptSizeMultiplier();
+ void resetScriptMinSize();
+ void resetVeryVeryThinMathSpace();
+ void resetVeryThinMathSpace();
+ void resetThinMathSpace();
+ void resetMediumMathSpace();
+ void resetThickMathSpace();
+ void resetVeryThickMathSpace();
+ void resetVeryVeryThickMathSpace();
+ void resetDisplayStyle();
+
+ private:
+ // Size of the font in points (mathsize / fontsize)
+ QValueStack<double> m_size;
+
+ // Whether a custom mathvariant attribute is in use
+ QValueStack<bool> m_customMathVariant;
+
+ // Font style (mathvariant, fontweight, fontstyle)
+ QValueStack<CharStyle> m_charStyle;
+
+ // Font family (mathvariant)
+ QValueStack<CharFamily> m_charFamily;
+
+ // Foreground color (mathcolor, color)
+ QValueStack<QColor> m_color;
+
+ // Background color (mathbackground)
+ QValueStack<QColor> m_background;
+
+ // Font family (fontfamily)
+ QValueStack<QFont> m_font;
+
+ // Whether a custom fontfamily attribute is in use (instead of CharFamily)
+ QValueStack<bool> m_customFontFamily;
+
+ // Font Weight (fontweight)
+ QValueStack<bool> m_fontWeight;
+
+ // Whether a custom fontweight attribute is in use
+ QValueStack<bool> m_customFontWeight;
+
+ // Font Style (fontstyle)
+ QValueStack<bool> m_fontStyle;
+
+ // Whether a custom fontstyle attribute is in use
+ QValueStack<bool> m_customFontStyle;
+
+ QValueStack<int> m_scriptLevel;
+ QValueStack<double> m_scriptSizeMultiplier;
+ QValueStack<double> m_scriptMinSize;
+ QValueStack<double> m_veryVeryThinMathSpace;
+ QValueStack<double> m_veryThinMathSpace;
+ QValueStack<double> m_thinMathSpace;
+ QValueStack<double> m_mediumMathSpace;
+ QValueStack<double> m_thickMathSpace;
+ QValueStack<double> m_veryThickMathSpace;
+ QValueStack<double> m_veryVeryThickMathSpace;
+ QValueStack<bool> m_displayStyle;
+ QValueStack<bool> m_customDisplayStyle;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // CONTEXTSTYLE_H
diff --git a/lib/kformula/creationstrategy.cc b/lib/kformula/creationstrategy.cc
new file mode 100644
index 00000000..2a1a8aa1
--- /dev/null
+++ b/lib/kformula/creationstrategy.cc
@@ -0,0 +1,144 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.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 <qdom.h>
+
+#include "bracketelement.h"
+#include "creationstrategy.h"
+#include "elementtype.h"
+#include "fractionelement.h"
+#include "identifierelement.h"
+#include "indexelement.h"
+#include "matrixelement.h"
+#include "operatorelement.h"
+#include "rootelement.h"
+#include "sequenceelement.h"
+#include "spaceelement.h"
+#include "symbolelement.h"
+#include "textelement.h"
+#include "numberelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+BasicElement* OrdinaryCreationStrategy::createElement( QString type, const QDomElement& )
+{
+ if ( type == "TEXT" ) return new TextElement();
+ else if ( type == "EMPTY" ) return new EmptyElement();
+ else if ( type == "SPACE" ) return new SpaceElement();
+ else if ( type == "ROOT" ) return new RootElement();
+ else if ( type == "BRACKET" ) return new BracketElement();
+ else if ( type == "MATRIX" ) return new MatrixElement();
+ else if ( type == "INDEX" ) return new IndexElement();
+ else if ( type == "FRACTION" ) return new FractionElement();
+ else if ( type == "SYMBOL" ) return new SymbolElement();
+ else if ( type == "NAMESEQUENCE" ) return new NameSequence();
+ else if ( type == "OVERLINE" ) return new OverlineElement();
+ else if ( type == "UNDERLINE" ) return new UnderlineElement();
+ else if ( type == "MULTILINE" ) return new MultilineElement();
+ else if ( type == "SEQUENCE" ) {
+ kdWarning() << "malformed data: sequence inside sequence." << endl;
+ return 0;
+ }
+ return 0;
+}
+
+
+TextElement* OrdinaryCreationStrategy::createTextElement( const QChar& ch, bool symbol )
+{
+ return new TextElement( ch, symbol );
+}
+
+EmptyElement* OrdinaryCreationStrategy::createEmptyElement()
+{
+ return new EmptyElement;
+}
+
+NameSequence* OrdinaryCreationStrategy::createNameSequence()
+{
+ return new NameSequence;
+}
+
+BracketElement* OrdinaryCreationStrategy::createBracketElement( SymbolType lhs, SymbolType rhs )
+{
+ return new BracketElement( lhs, rhs );
+}
+
+OverlineElement* OrdinaryCreationStrategy::createOverlineElement()
+{
+ return new OverlineElement;
+}
+
+UnderlineElement* OrdinaryCreationStrategy::createUnderlineElement()
+{
+ return new UnderlineElement;
+}
+
+MultilineElement* OrdinaryCreationStrategy::createMultilineElement()
+{
+ return new MultilineElement;
+}
+
+SpaceElement* OrdinaryCreationStrategy::createSpaceElement( SpaceWidth width )
+{
+ return new SpaceElement( width );
+}
+
+FractionElement* OrdinaryCreationStrategy::createFractionElement()
+{
+ return new FractionElement;
+}
+
+RootElement* OrdinaryCreationStrategy::createRootElement()
+{
+ return new RootElement;
+}
+
+SymbolElement* OrdinaryCreationStrategy::createSymbolElement( SymbolType type )
+{
+ return new SymbolElement( type );
+}
+
+MatrixElement* OrdinaryCreationStrategy::createMatrixElement( uint rows, uint columns )
+{
+ return new MatrixElement( rows, columns );
+}
+
+IndexElement* OrdinaryCreationStrategy::createIndexElement()
+{
+ return new IndexElement;
+}
+
+IdentifierElement* OrdinaryCreationStrategy::createIdentifierElement()
+{
+ return new IdentifierElement();
+}
+
+OperatorElement* OrdinaryCreationStrategy::createOperatorElement()
+{
+ return new OperatorElement();
+}
+
+NumberElement* OrdinaryCreationStrategy::createNumberElement()
+{
+ return new NumberElement();
+}
+
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/creationstrategy.h b/lib/kformula/creationstrategy.h
new file mode 100644
index 00000000..c6599eed
--- /dev/null
+++ b/lib/kformula/creationstrategy.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.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.
+*/
+
+
+#ifndef CREATIONSTRATEGY_H
+#define CREATIONSTRATEGY_H
+
+
+#include <qstring.h>
+#include <qdom.h>
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class BracketElement;
+class EmptyElement;
+class FractionElement;
+class IdentifierElement;
+class IndexElement;
+class MatrixElement;
+class MultilineElement;
+class NameSequence;
+class OperatorElement;
+class OverlineElement;
+class RootElement;
+class SpaceElement;
+class SymbolElement;
+class TextElement;
+class NumberElement;
+class UnderlineElement;
+
+/**
+ * An object of this type needs to be known by the SequenceElement.
+ * It decides what elements can be constructed.
+ */
+class ElementCreationStrategy {
+public:
+ virtual ~ElementCreationStrategy() {}
+
+ virtual BasicElement* createElement( QString type, const QDomElement& element ) = 0;
+
+ /// there must always be a TextElement, so this can never return 0
+ virtual TextElement* createTextElement( const QChar& ch, bool symbol=false ) = 0;
+
+ /// when this gets called the user has seen the matrix dialog and expects a matrix!
+ virtual MatrixElement* createMatrixElement( uint rows, uint columns ) = 0;
+
+ virtual EmptyElement* createEmptyElement() = 0;
+ virtual NameSequence* createNameSequence() = 0;
+ virtual BracketElement* createBracketElement( SymbolType lhs, SymbolType rhs ) = 0;
+ virtual OverlineElement* createOverlineElement() = 0;
+ virtual UnderlineElement* createUnderlineElement() = 0;
+ virtual MultilineElement* createMultilineElement() = 0;
+ virtual SpaceElement* createSpaceElement( SpaceWidth width ) = 0;
+ virtual FractionElement* createFractionElement() = 0;
+ virtual RootElement* createRootElement() = 0;
+ virtual SymbolElement* createSymbolElement( SymbolType type ) = 0;
+ virtual IndexElement* createIndexElement() = 0;
+ virtual IdentifierElement* createIdentifierElement() = 0;
+ virtual OperatorElement* createOperatorElement() = 0;
+ virtual NumberElement* createNumberElement() = 0;
+ virtual QString type() const = 0;
+};
+
+
+/**
+ * The ordinary strategy to be used for plain kformula.
+ */
+class OrdinaryCreationStrategy : public ElementCreationStrategy {
+public:
+ virtual BasicElement* createElement( QString type, const QDomElement& element = 0 );
+
+ virtual TextElement* createTextElement( const QChar& ch, bool symbol=false );
+ virtual EmptyElement* createEmptyElement();
+ virtual NameSequence* createNameSequence();
+ virtual BracketElement* createBracketElement( SymbolType lhs, SymbolType rhs );
+ virtual OverlineElement* createOverlineElement();
+ virtual UnderlineElement* createUnderlineElement();
+ virtual MultilineElement* createMultilineElement();
+ virtual SpaceElement* createSpaceElement( SpaceWidth width );
+ virtual FractionElement* createFractionElement();
+ virtual RootElement* createRootElement();
+ virtual SymbolElement* createSymbolElement( SymbolType type );
+ virtual MatrixElement* createMatrixElement( uint rows, uint columns );
+ virtual IndexElement* createIndexElement();
+ virtual IdentifierElement* createIdentifierElement();
+ virtual OperatorElement* createOperatorElement();
+ virtual NumberElement* createNumberElement();
+ virtual QString type() const { return "Ordinary"; }
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // CREATIONSTRATEGY_H
diff --git a/lib/kformula/dtd/Makefile.am b/lib/kformula/dtd/Makefile.am
new file mode 100644
index 00000000..e00eba35
--- /dev/null
+++ b/lib/kformula/dtd/Makefile.am
@@ -0,0 +1,4 @@
+dtd_DATA = kformula.dtd
+
+dtddir = $(kde_datadir)/kformula/dtd
+
diff --git a/lib/kformula/dtd/kformula.dtd b/lib/kformula/dtd/kformula.dtd
new file mode 100644
index 00000000..4becebbd
--- /dev/null
+++ b/lib/kformula/dtd/kformula.dtd
@@ -0,0 +1,95 @@
+<!-- $Id: kformula.dtd 202993 2003-01-26 21:30:12Z kuettler $
+
+This is an XML document type definition (DTD) for the KFormula 1.3 XML files
+
+ChangeLog:
+* Initial version by Heinrich Kuettler <heinrich.kuettler@gmx.de>.
+-->
+
+<!-- All but SEQUENCE: -->
+<!ENTITY % element "BRACKET | FRACTION | INDEX | MATRIX | ROOT |
+NAMESEQUENCE | SPACE | TEXT | EMPTY | SYMBOL | OVERLINE | UNDERLINE |
+MULTILINE">
+
+<!ELEMENT KFORMULA (FORMULASETTINGS?, FORMULA*)>
+<!ATTLIST KFORMULA
+ VERSION CDATA #IMPLIED
+ BASESIZE CDATA #IMPLIED
+>
+
+<!ELEMENT FORMULASETTINGS EMPTY>
+
+<!ELEMENT FORMULA (%element;)*>
+<!ATTLIST FORMULA
+ VERSION CDATA #IMPLIED
+ BASESIZE CDATA #IMPLIED
+>
+
+<!ELEMENT BRACKET (CONTENT)>
+<!ATTLIST BRACKET
+ LEFT CDATA #REQUIRED
+ RIGHT CDATA #REQUIRED
+>
+
+<!ELEMENT CONTENT (SEQUENCE)>
+
+<!ELEMENT FRACTION (NUMERATOR,DENOMINATOR)>
+<!ATTLIST FRACTION
+ NOLINE CDATA #IMPLIED
+>
+
+<!ELEMENT NUMERATOR (SEQUENCE)>
+<!ELEMENT DENOMINATOR (SEQUENCE)>
+
+<!ELEMENT INDEX (CONTENT,UPPERLEFT?,UPPERMIDDLE?,UPPERRIGHT?,LOWERLEFT?,LOWERMIDDLE?,LOWERRIGHT?)>
+
+<!ELEMENT UPPERLEFT (SEQUENCE)>
+<!ELEMENT UPPERMIDDLE (SEQUENCE)>
+<!ELEMENT UPPERRIGHT (SEQUENCE)>
+<!ELEMENT LOWERLEFT (SEQUENCE)>
+<!ELEMENT LOWERMIDDLE (SEQUENCE)>
+<!ELEMENT LOWERRIGHT (SEQUENCE)>
+
+<!ELEMENT MATRIX (%element;)*>
+<!ATTLIST MATRIX
+ ROWS CDATA #REQUIRED
+ COLUMNS CDATA #REQUIRED
+>
+
+<!ELEMENT ROOT (CONTENT,ROOTINDEX?)>
+
+<!ELEMENT ROOTINDEX (SEQUENCE)>
+
+<!ELEMENT SEQUENCE (%element;)*>
+
+<!ELEMENT NAMESEQUENCE (TEXT)*>
+
+<!ELEMENT SPACE EMPTY>
+<!ATTLIST SPACE
+ WIDTH CDATA #REQUIRED
+ TAB CDATA #IMPLIED
+>
+
+<!ELEMENT TEXT EMPTY>
+<!ATTLIST TEXT
+ CHAR CDATA #REQUIRED
+ SYMBOL CDATA #IMPLIED
+ STYLE CDATA #IMPLIED
+ FAMILY CDATA #IMPLIED
+>
+
+<!ELEMENT EMPTY EMPTY>
+
+<!ELEMENT SYMBOL (CONTENT,LOWER?,UPPER?)>
+<!ATTLIST SYMBOL
+ TYPE CDATA #REQUIRED
+>
+
+<!ELEMENT OVERLINE (CONTENT)>
+<!ELEMENT UNDERLINE (CONTENT)>
+
+<!ELEMENT MULTILINE (SEQUENCE*)>
+<!ATTLIST MULTILINE
+ LINES CDATA #REQUIRED
+>
+
diff --git a/lib/kformula/elementindex.h b/lib/kformula/elementindex.h
new file mode 100644
index 00000000..b493f432
--- /dev/null
+++ b/lib/kformula/elementindex.h
@@ -0,0 +1,33 @@
+/* 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.
+
+ 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.
+*/
+
+#ifndef ELEMENTINDEX_H
+#define ELEMENTINDEX_H
+
+#include <iostream>
+
+#include "basicelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // ELEMENTINDEX_H
diff --git a/lib/kformula/elementtype.cc b/lib/kformula/elementtype.cc
new file mode 100644
index 00000000..94ec0162
--- /dev/null
+++ b/lib/kformula/elementtype.cc
@@ -0,0 +1,765 @@
+/* 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 <qfont.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+
+#include "basicelement.h"
+#include "contextstyle.h"
+#include "elementtype.h"
+#include "sequenceelement.h"
+#include "sequenceparser.h"
+#include "textelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+int ElementType::evilDestructionCount = 0;
+
+/*
+ * Converts CharStyle and CharFamily to the MathML 'mathvariant'
+ * attribute (see MathML spec 3.2.2).
+ */
+QString format2variant( CharStyle style, CharFamily family )
+{
+ QString result;
+
+ switch( family ) {
+ case normalFamily:
+ case anyFamily:
+ switch( style ) {
+ case normalChar:
+ result = "normal"; break;
+ case boldChar:
+ result = "bold"; break;
+ case italicChar:
+ result = "italic"; break;
+ case boldItalicChar:
+ result = "bold-italic"; break;
+ case anyChar:
+ break;
+ }
+ break;
+ case scriptFamily:
+ result = "script";
+ if ( style == boldChar || style == boldItalicChar )
+ result = "bold-" + result;
+ break;
+ case frakturFamily:
+ result = "fraktur";
+ if ( style == boldChar || style == boldItalicChar )
+ result = "bold-" + result;
+ break;
+ case doubleStruckFamily:
+ result = "double-struck"; break;
+ }
+
+ return result;
+}
+
+ElementType::ElementType( SequenceParser* parser )
+ : from( parser->getStart() ), to( parser->getEnd() ), prev( 0 )
+{
+ evilDestructionCount++;
+}
+
+ElementType::~ElementType()
+{
+ delete prev;
+ evilDestructionCount--;
+}
+
+
+QString ElementType::text( SequenceElement* seq ) const
+{
+ QString str;
+ for ( uint i=start(); i<end(); ++i ) {
+ str.append( seq->getChild( i )->getCharacter() );
+ }
+ return str;
+}
+
+
+luPt ElementType::getSpaceBefore( const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::getSpaceAfter( MultiElementType*,
+ const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::getSpaceAfter( OperatorType*,
+ const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::getSpaceAfter( RelationType*,
+ const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::getSpaceAfter( PunctuationType*,
+ const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::getSpaceAfter( BracketType*,
+ const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::getSpaceAfter( ComplexElementType*,
+ const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::getSpaceAfter( InnerElementType*,
+ const ContextStyle&,
+ ContextStyle::TextStyle,
+ double )
+{
+ return 0;
+}
+
+luPt ElementType::thinSpaceIfNotScript( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( !context.isScript( tstyle ) ) {
+ return context.getThinSpace( tstyle, factor );
+ }
+ return 0;
+}
+
+luPt ElementType::mediumSpaceIfNotScript( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( !context.isScript( tstyle ) ) {
+ return context.getMediumSpace( tstyle, factor );
+ }
+ return 0;
+}
+
+luPt ElementType::thickSpaceIfNotScript( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( !context.isScript( tstyle ) ) {
+ return context.getThickSpace( tstyle, factor );
+ }
+ return 0;
+}
+
+
+QFont ElementType::getFont(const ContextStyle& context)
+{
+ return context.getDefaultFont();
+}
+
+void ElementType::setUpPainter(const ContextStyle& context, QPainter& painter)
+{
+ painter.setPen(context.getDefaultColor());
+}
+
+void ElementType::append( ElementType* element )
+{
+ element->prev = this;
+}
+
+void ElementType::output()
+{
+ kdDebug( DEBUGID ) << start() << " - " << end() << endl;
+}
+
+void ElementType::saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat )
+{
+ for ( uint i = from; i < to; ++i ) {
+ se->getChild( i )->writeMathML( doc, de, oasisFormat );
+ }
+}
+
+
+SequenceType::SequenceType( SequenceParser* parser )
+ : ElementType( parser ), last( 0 )
+{
+ while ( true ) {
+ parser->nextToken();
+ //cerr << "SequenceType::SequenceType(): " << parser->getTokenType() << " "
+ // << parser->getStart() << " " << parser->getEnd() << endl;
+ if ( parser->getTokenType() == END ) {
+ break;
+ }
+ ElementType* nextType = parser->getPrimitive();
+ if ( nextType == 0 ) {
+ break;
+ }
+ if ( last != 0 ) {
+ last->append( nextType );
+ }
+ last = nextType;
+ }
+}
+
+SequenceType::~SequenceType()
+{
+ delete last;
+}
+
+
+void SequenceType::output()
+{
+}
+
+
+MultiElementType::MultiElementType( SequenceParser* parser )
+ : ElementType( parser )
+{
+ for ( uint i = start(); i < end(); i++ ) {
+ parser->setElementType( i, this );
+ }
+ m_text = parser->text();
+}
+
+
+luPt MultiElementType::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( getPrev() != 0 ) {
+ return getPrev()->getSpaceAfter( this, context, tstyle, factor );
+ }
+ return 0;
+}
+
+luPt MultiElementType::getSpaceAfter( OperatorType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt MultiElementType::getSpaceAfter( RelationType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt MultiElementType::getSpaceAfter( InnerElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+
+TextType::TextType( SequenceParser* parser )
+ : MultiElementType( parser )
+{
+}
+
+void TextType::saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat )
+{
+ for ( uint i = start(); i < end(); ++i ) {
+ QDomElement text = doc.createElement( oasisFormat ? "math:mi" : "mi" );
+ BasicElement* be = se->getChild( i );
+ TextElement* te = static_cast<TextElement*>( be );
+ QString mathvariant = format2variant( te->getCharStyle(), te->getCharFamily());
+ if ( !mathvariant.isNull() )
+ text.setAttribute( "mathvariant", mathvariant );
+
+ text.appendChild( doc.createTextNode( be->getCharacter() ) );
+
+ de.appendChild( text );
+ if ( i != end() - 1 ) {
+ QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
+ op.appendChild( doc.createEntityReference( "InvisibleTimes" ) );
+ de.appendChild( op );
+ }
+ }
+}
+
+
+NameType::NameType( SequenceParser* parser )
+ : MultiElementType( parser )
+{
+}
+
+void NameType::saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat )
+{
+ se->getChild( start() )->writeMathML( doc, de, oasisFormat );
+
+ /*
+ QDomElement name = doc.createElement( "mi" );
+ QString value;
+ for ( uint i = start(); i < end(); ++i ) {
+ BasicElement* be = se->getChild( i );
+ //TextElement* te = static_cast<TextElement*>( be );
+ value += be->getCharacter();
+ }
+ name.appendChild( doc.createTextNode( value ) );
+ de.appendChild( name );*/
+}
+
+
+QFont NameType::getFont(const ContextStyle& context)
+{
+ return context.getNameFont();
+}
+
+NumberType::NumberType( SequenceParser* parser )
+ : MultiElementType( parser )
+{
+}
+
+QFont NumberType::getFont(const ContextStyle& context)
+{
+ return context.getNumberFont();
+}
+
+void NumberType::setUpPainter(const ContextStyle& context, QPainter& painter)
+{
+ painter.setPen(context.getNumberColor());
+}
+
+void NumberType::saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat )
+{
+ QDomElement name = doc.createElement( oasisFormat ? "math:mn" : "mn" );
+ QString value;
+ for ( uint i = start(); i < end(); ++i ) {
+ BasicElement* be = se->getChild( i );
+ value += be->getCharacter();
+ }
+ TextElement* te = static_cast<TextElement*>( se->getChild( start() ) );
+ QString mathvariant = format2variant( te->getCharStyle(), te->getCharFamily() );
+ if ( !mathvariant.isNull() )
+ name.setAttribute( "mathvariant", mathvariant );
+
+ name.appendChild( doc.createTextNode( value ) );
+ de.appendChild( name );
+}
+
+
+SingleElementType::SingleElementType( SequenceParser* parser )
+ : ElementType( parser )
+{
+ parser->setElementType( start(), this );
+}
+
+AbstractOperatorType::AbstractOperatorType( SequenceParser* parser )
+ : SingleElementType( parser )
+{
+}
+
+void AbstractOperatorType::saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat )
+{
+ QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
+ BasicElement* be = se->getChild( start() );
+ if ( be->getCharacter().latin1() != 0 ) {
+ // latin-1 char
+ op.appendChild( doc.createTextNode( be->getCharacter() ) );
+ }
+ else {
+ // unicode char
+ QString s;
+ op.appendChild( doc.createEntityReference( s.sprintf( "#x%05X", be->getCharacter().unicode() ) ) );
+ }
+ TextElement* te = static_cast<TextElement*>( be );
+ QString mathvariant = format2variant( te->getCharStyle(), te->getCharFamily() );
+ if ( !mathvariant.isNull() )
+ op.setAttribute( "mathvariant", mathvariant );
+
+ de.appendChild( op );
+}
+
+OperatorType::OperatorType( SequenceParser* parser )
+ : AbstractOperatorType( parser )
+{
+}
+
+luPt OperatorType::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( getPrev() != 0 ) {
+ return getPrev()->getSpaceAfter( this, context, tstyle, factor );
+ }
+ return 0;
+}
+
+luPt OperatorType::getSpaceAfter( MultiElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt OperatorType::getSpaceAfter( BracketType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt OperatorType::getSpaceAfter( ComplexElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt OperatorType::getSpaceAfter( InnerElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+
+QFont OperatorType::getFont(const ContextStyle& context)
+{
+ return context.getOperatorFont();
+}
+
+void OperatorType::setUpPainter(const ContextStyle& context, QPainter& painter)
+{
+ painter.setPen(context.getOperatorColor());
+}
+
+
+RelationType::RelationType( SequenceParser* parser )
+ : AbstractOperatorType( parser )
+{
+}
+
+luPt RelationType::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( getPrev() != 0 ) {
+ return getPrev()->getSpaceAfter( this, context, tstyle, factor );
+ }
+ return 0;
+}
+
+luPt RelationType::getSpaceAfter( MultiElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt RelationType::getSpaceAfter( BracketType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt RelationType::getSpaceAfter( ComplexElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt RelationType::getSpaceAfter( InnerElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+QFont RelationType::getFont( const ContextStyle& context )
+{
+ return context.getOperatorFont();
+}
+
+void RelationType::setUpPainter( const ContextStyle& context, QPainter& painter )
+{
+ painter.setPen(context.getOperatorColor());
+}
+
+
+
+PunctuationType::PunctuationType( SequenceParser* parser )
+ : AbstractOperatorType( parser )
+{
+}
+
+luPt PunctuationType::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( getPrev() != 0 ) {
+ return getPrev()->getSpaceAfter( this, context, tstyle, factor );
+ }
+ return 0;
+}
+
+luPt PunctuationType::getSpaceAfter( MultiElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt PunctuationType::getSpaceAfter( RelationType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt PunctuationType::getSpaceAfter( PunctuationType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt PunctuationType::getSpaceAfter( BracketType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt PunctuationType::getSpaceAfter( ComplexElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt PunctuationType::getSpaceAfter( InnerElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+QFont PunctuationType::getFont( const ContextStyle& context )
+{
+ return context.getOperatorFont();
+}
+
+void PunctuationType::setUpPainter( const ContextStyle& context, QPainter& painter )
+{
+ painter.setPen( context.getDefaultColor() );
+}
+
+
+BracketType::BracketType( SequenceParser* parser )
+ : SingleElementType( parser )
+{
+}
+
+luPt BracketType::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( getPrev() != 0 ) {
+ return getPrev()->getSpaceAfter( this, context, tstyle, factor );
+ }
+ return 0;
+}
+
+luPt BracketType::getSpaceAfter( OperatorType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt BracketType::getSpaceAfter( RelationType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt BracketType::getSpaceAfter( InnerElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+
+ComplexElementType::ComplexElementType( SequenceParser* parser )
+ : SingleElementType( parser )
+{
+}
+
+luPt ComplexElementType::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( getPrev() != 0 ) {
+ return getPrev()->getSpaceAfter( this, context, tstyle, factor );
+ }
+ return 0;
+}
+
+luPt ComplexElementType::getSpaceAfter( OperatorType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt ComplexElementType::getSpaceAfter( RelationType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt ComplexElementType::getSpaceAfter( InnerElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+
+InnerElementType::InnerElementType( SequenceParser* parser )
+ : SingleElementType( parser )
+{
+}
+
+luPt InnerElementType::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( getPrev() != 0 ) {
+ return getPrev()->getSpaceAfter( this, context, tstyle, factor );
+ }
+ return 0;
+}
+
+luPt InnerElementType::getSpaceAfter( MultiElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt InnerElementType::getSpaceAfter( OperatorType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return mediumSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt InnerElementType::getSpaceAfter( RelationType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thickSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt InnerElementType::getSpaceAfter( PunctuationType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt InnerElementType::getSpaceAfter( BracketType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt InnerElementType::getSpaceAfter( ComplexElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+luPt InnerElementType::getSpaceAfter( InnerElementType*,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ return thinSpaceIfNotScript( context, tstyle, factor );
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/elementtype.h b/lib/kformula/elementtype.h
new file mode 100644
index 00000000..18c55f25
--- /dev/null
+++ b/lib/kformula/elementtype.h
@@ -0,0 +1,503 @@
+/* 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.
+*/
+
+#ifndef ELEMENTTYPE_H
+#define ELEMENTTYPE_H
+
+#include <qfont.h>
+#include <qstring.h>
+#include <qdom.h>
+
+#include "contextstyle.h"
+#include "kformuladefs.h"
+
+class QPainter;
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class BracketType;
+class ComplexElementType;
+class InnerElementType;
+class MultiElementType;
+class OperatorType;
+class PunctuationType;
+class RelationType;
+class SequenceElement;
+class SequenceParser;
+class TextElement;
+
+
+/**
+ * Basis of all types. Types make up a hierarchy that describes
+ * the semantic of the sequence.
+ */
+class ElementType {
+public:
+ ElementType(SequenceParser* parser);
+ virtual ~ElementType();
+
+ /**
+ * @returns whether we want to see this element.
+ */
+ virtual bool isInvisible(const TextElement&) const { return false; }
+
+ /**
+ * @returns the spanned text. seq must be the original
+ * parent sequence.
+ */
+ virtual QString text( SequenceElement* seq ) const;
+
+ /**
+ * @returns the position of the first character
+ */
+ uint start() const { return from; }
+
+ /**
+ * @returns the position of the first character after the typed element
+ */
+ uint end() const { return to; }
+
+ /**
+ * @returns the space to be left before each char
+ * for the given style and font size.
+ */
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( MultiElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( OperatorType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( RelationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( PunctuationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( BracketType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( ComplexElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+
+ /**
+ * @returns the font to be used for this kind of element
+ */
+ virtual QFont getFont( const ContextStyle& context );
+
+ /**
+ * sets the painters pen to a appropriate value
+ */
+ virtual void setUpPainter( const ContextStyle& context, QPainter& painter );
+
+ // debug
+ static int getEvilDestructionCount() { return evilDestructionCount; }
+
+ virtual void output();
+
+ /**
+ * Adds a type at the end of the list.
+ */
+ void append( ElementType* );
+
+ ElementType* getPrev() const { return prev; }
+
+ virtual void saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat = false );
+
+ virtual bool multiElement() const { return false; }
+
+protected:
+
+ void setStart( uint start ) { from = start; }
+ void setEnd( uint end ) { to = end; }
+
+ luPt thinSpaceIfNotScript( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ luPt mediumSpaceIfNotScript( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ luPt thickSpaceIfNotScript( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+
+private:
+
+ /**
+ * the index of the first element that belongs
+ * to the name.
+ */
+ uint from;
+
+ /**
+ * the index of the first element that doesn't belong
+ * to the name.
+ */
+ uint to;
+
+ /**
+ * We implement this list ourselves because we need to know
+ * our neighbours.
+ */
+ ElementType* prev;
+
+ // debug
+ static int evilDestructionCount;
+};
+
+
+/**
+ * The token that belongs to a sequence. Contains all the
+ * other tokens.
+ */
+class SequenceType : public ElementType {
+public:
+ SequenceType( SequenceParser* parser );
+ ~SequenceType();
+
+ virtual void output();
+private:
+
+ /**
+ * The last token type of this sequences chain.
+ */
+ ElementType* last;
+};
+
+
+/**
+ * Basis for all tokens that run along several elements.
+ */
+class MultiElementType : public ElementType {
+public:
+ MultiElementType( SequenceParser* parser );
+
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( OperatorType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( RelationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+
+ virtual bool multiElement() const { return true; }
+
+ /**
+ * @returns the spanned text. seq must be the original
+ * parent sequence.
+ */
+ virtual QString text( SequenceElement* /*seq*/ ) const { return m_text; }
+
+private:
+
+ QString m_text;
+};
+
+
+/**
+ * A text element that doesn't belong to an name.
+ * This might be considered an error.
+ */
+class TextType : public MultiElementType {
+public:
+ TextType( SequenceParser* parser );
+ virtual void saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat = false );
+};
+
+
+/**
+ * A range of elements that make up a number.
+ */
+class NumberType : public MultiElementType {
+public:
+ NumberType(SequenceParser* parser);
+
+ /**
+ * @returns the font to be used for this kind of element
+ */
+ virtual QFont getFont(const ContextStyle& context);
+
+ /**
+ * sets the painters pen to a appropriate value
+ */
+ virtual void setUpPainter(const ContextStyle& context, QPainter& painter);
+
+ virtual void saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat = false );
+};
+
+
+/**
+ * Basis for all tokens that consist of one element only.
+ */
+class SingleElementType : public ElementType {
+public:
+ SingleElementType( SequenceParser* parser );
+};
+
+
+/**
+ * A recognized name.
+ */
+class NameType : public MultiElementType {
+public:
+ NameType( SequenceParser* parser );
+
+ /**
+ * @returns the font to be used for this kind of element
+ */
+ virtual QFont getFont( const ContextStyle& context );
+
+ virtual void saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat = false );
+
+private:
+};
+
+
+class AbstractOperatorType : public SingleElementType {
+public:
+ AbstractOperatorType( SequenceParser* parser );
+
+ void saveMathML( SequenceElement* se, QDomDocument& doc, QDomElement de, bool oasisFormat = false );
+};
+
+class OperatorType : public AbstractOperatorType {
+public:
+ OperatorType( SequenceParser* parser );
+
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( MultiElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( BracketType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( ComplexElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+
+ /**
+ * @returns the font to be used for this kind of element
+ */
+ virtual QFont getFont(const ContextStyle& context);
+
+ /**
+ * sets the painters pen to a appropriate value
+ */
+ virtual void setUpPainter(const ContextStyle& context, QPainter& painter);
+};
+
+
+class RelationType : public AbstractOperatorType {
+public:
+ RelationType( SequenceParser* parser );
+
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( MultiElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( BracketType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( ComplexElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+
+ /**
+ * @returns the font to be used for this kind of element
+ */
+ virtual QFont getFont( const ContextStyle& context );
+
+ /**
+ * sets the painters pen to a appropriate value
+ */
+ virtual void setUpPainter( const ContextStyle& context, QPainter& painter );
+};
+
+
+class PunctuationType : public AbstractOperatorType {
+public:
+ PunctuationType( SequenceParser* parser );
+
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( MultiElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( RelationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( PunctuationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( BracketType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( ComplexElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+
+ /**
+ * @returns the font to be used for this kind of element
+ */
+ virtual QFont getFont( const ContextStyle& context );
+
+ /**
+ * sets the painters pen to a appropriate value
+ */
+ virtual void setUpPainter( const ContextStyle& context, QPainter& painter );
+};
+
+
+class BracketType : public SingleElementType {
+public:
+ BracketType( SequenceParser* parser );
+
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( OperatorType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( RelationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+};
+
+
+class ComplexElementType : public SingleElementType {
+public:
+ ComplexElementType( SequenceParser* parser );
+
+ // these spacings are equal to the ones from MultiElementType
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( OperatorType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( RelationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+};
+
+
+class InnerElementType : public SingleElementType {
+public:
+ InnerElementType( SequenceParser* parser );
+
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( MultiElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( OperatorType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( RelationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( PunctuationType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( BracketType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( ComplexElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( InnerElementType* type,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // ELEMENTTYPE_H
diff --git a/lib/kformula/elementvisitor.h b/lib/kformula/elementvisitor.h
new file mode 100644
index 00000000..df7a753f
--- /dev/null
+++ b/lib/kformula/elementvisitor.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.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.
+*/
+
+#ifndef ELEMENTVISITOR_H
+#define ELEMENTVISITOR_H
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class BracketElement;
+class EmptyElement;
+class FractionElement;
+class IndexElement;
+class MatrixElement;
+class MultilineElement;
+class NameSequence;
+class OverlineElement;
+class RootElement;
+class SequenceElement;
+class SpaceElement;
+class SymbolElement;
+class TextElement;
+class UnderlineElement;
+
+
+/**
+ * Visitor. Provides a way to add new functionality to the element tree.
+ */
+class ElementVisitor {
+public:
+
+ virtual ~ElementVisitor() {}
+
+ virtual bool visit( BracketElement* ) { return true; }
+ virtual bool visit( EmptyElement* ) { return true; }
+ virtual bool visit( FractionElement* ) { return true; }
+ virtual bool visit( IndexElement* ) { return true; }
+ virtual bool visit( MatrixElement* ) { return true; }
+ virtual bool visit( MultilineElement* ) { return true; }
+ virtual bool visit( NameSequence* ) { return true; }
+ virtual bool visit( OverlineElement* ) { return true; }
+ virtual bool visit( RootElement* ) { return true; }
+ virtual bool visit( SequenceElement* ) { return true; }
+ virtual bool visit( SpaceElement* ) { return true; }
+ virtual bool visit( SymbolElement* ) { return true; }
+ virtual bool visit( TextElement* ) { return true; }
+ virtual bool visit( UnderlineElement* ) { return true; }
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // ELEMENTVISITOR_H
diff --git a/lib/kformula/encloseelement.cc b/lib/kformula/encloseelement.cc
new file mode 100644
index 00000000..384f6b92
--- /dev/null
+++ b/lib/kformula/encloseelement.cc
@@ -0,0 +1,44 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "encloseelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+EncloseElement::EncloseElement( BasicElement* parent ) : SequenceElement( parent ) {
+}
+
+bool EncloseElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ m_notation = element.attribute( "notation" );
+ return true;
+}
+
+void EncloseElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ if ( ! m_notation.isNull() ) {
+ element.setAttribute( "notation", m_notation );
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/encloseelement.h b/lib/kformula/encloseelement.h
new file mode 100644
index 00000000..9bec85b0
--- /dev/null
+++ b/lib/kformula/encloseelement.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef ENCLOSEELEMENT_H
+#define ENCLOSEELEMENT_H
+
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class EncloseElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+ EncloseElement( BasicElement* parent = 0 );
+
+private:
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+ virtual QString getElementName() const { return "menclose"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+
+ QString m_notation;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // ENCLOSEELEMENT_H
diff --git a/lib/kformula/entities.cc b/lib/kformula/entities.cc
new file mode 100644
index 00000000..c6696e1f
--- /dev/null
+++ b/lib/kformula/entities.cc
@@ -0,0 +1,2037 @@
+//
+// Created: Tue Aug 29 16:20:33 2006
+// by: bynames.py
+// from: byalpha.html
+//
+// WARNING! All changes made in this file will be lost!
+
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "entities.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+const entityMap entities[] = {
+ {"AElig", 0x000C6} ,
+ {"Aacute", 0x000C1} ,
+ {"Abreve", 0x00102} ,
+ {"Acirc", 0x000C2} ,
+ {"Acy", 0x00410} ,
+ {"Afr", 0x1D504} ,
+ {"Agrave", 0x000C0} ,
+ {"Amacr", 0x00100} ,
+ {"And", 0x02A53} ,
+ {"Aogon", 0x00104} ,
+ {"Aopf", 0x1D538} ,
+ {"ApplyFunction", 0x02061} ,
+ {"Aring", 0x000C5} ,
+ {"Ascr", 0x1D49C} ,
+ {"Assign", 0x02254} ,
+ {"Atilde", 0x000C3} ,
+ {"Auml", 0x000C4} ,
+ {"Backslash", 0x02216} ,
+ {"Barv", 0x02AE7} ,
+ {"Barwed", 0x02306} ,
+ {"Bcy", 0x00411} ,
+ {"Because", 0x02235} ,
+ {"Bernoullis", 0x0212C} ,
+ {"Bfr", 0x1D505} ,
+ {"Bopf", 0x1D539} ,
+ {"Breve", 0x002D8} ,
+ {"Bscr", 0x0212C} ,
+ {"Bumpeq", 0x0224E} ,
+ {"CHcy", 0x00427} ,
+ {"Cacute", 0x00106} ,
+ {"Cap", 0x022D2} ,
+ {"CapitalDifferentialD", 0x02145} ,
+ {"Cayleys", 0x0212D} ,
+ {"Ccaron", 0x0010C} ,
+ {"Ccedil", 0x000C7} ,
+ {"Ccirc", 0x00108} ,
+ {"Cconint", 0x02230} ,
+ {"Cdot", 0x0010A} ,
+ {"Cedilla", 0x000B8} ,
+ {"CenterDot", 0x000B7} ,
+ {"Cfr", 0x0212D} ,
+ {"CircleDot", 0x02299} ,
+ {"CircleMinus", 0x02296} ,
+ {"CirclePlus", 0x02295} ,
+ {"CircleTimes", 0x02297} ,
+ {"ClockwiseContourIntegral", 0x02232} ,
+ {"CloseCurlyDoubleQuote", 0x0201D} ,
+ {"CloseCurlyQuote", 0x02019} ,
+ {"Colon", 0x02237} ,
+ {"Colone", 0x02A74} ,
+ {"Congruent", 0x02261} ,
+ {"Conint", 0x0222F} ,
+ {"ContourIntegral", 0x0222E} ,
+ {"Copf", 0x02102} ,
+ {"Coproduct", 0x02210} ,
+ {"CounterClockwiseContourIntegral", 0x02233} ,
+ {"Cross", 0x02A2F} ,
+ {"Cscr", 0x1D49E} ,
+ {"Cup", 0x022D3} ,
+ {"CupCap", 0x0224D} ,
+ {"DD", 0x02145} ,
+ {"DDotrahd", 0x02911} ,
+ {"DJcy", 0x00402} ,
+ {"DScy", 0x00405} ,
+ {"DZcy", 0x0040F} ,
+ {"Dagger", 0x02021} ,
+ {"Dagger", 0x02021} ,
+ {"Darr", 0x021A1} ,
+ {"Dashv", 0x02AE4} ,
+ {"Dcaron", 0x0010E} ,
+ {"Dcy", 0x00414} ,
+ {"Del", 0x02207} ,
+ {"Delta", 0x00394} ,
+ {"Dfr", 0x1D507} ,
+ {"DiacriticalAcute", 0x000B4} ,
+ {"DiacriticalDot", 0x002D9} ,
+ {"DiacriticalDoubleAcute", 0x002DD} ,
+ {"DiacriticalGrave", 0x00060} ,
+ {"DiacriticalTilde", 0x002DC} ,
+ {"Diamond", 0x022C4} ,
+ {"DifferentialD", 0x02146} ,
+ {"Dopf", 0x1D53B} ,
+ {"Dot", 0x000A8} ,
+ {"DotDot", 0x020DC} ,
+ {"DotEqual", 0x02250} ,
+ {"DoubleContourIntegral", 0x0222F} ,
+ {"DoubleDot", 0x000A8} ,
+ {"DoubleDownArrow", 0x021D3} ,
+ {"DoubleLeftArrow", 0x021D0} ,
+ {"DoubleLeftRightArrow", 0x021D4} ,
+ {"DoubleLeftTee", 0x02AE4} ,
+ {"DoubleLongLeftArrow", 0x027F8} ,
+ {"DoubleLongLeftRightArrow", 0x027FA} ,
+ {"DoubleLongRightArrow", 0x027F9} ,
+ {"DoubleRightArrow", 0x021D2} ,
+ {"DoubleRightTee", 0x022A8} ,
+ {"DoubleUpArrow", 0x021D1} ,
+ {"DoubleUpDownArrow", 0x021D5} ,
+ {"DoubleVerticalBar", 0x02225} ,
+ {"DownArrow", 0x02193} ,
+ {"DownArrowBar", 0x02913} ,
+ {"DownArrowUpArrow", 0x021F5} ,
+ {"DownBreve", 0x00311} ,
+ {"DownLeftRightVector", 0x02950} ,
+ {"DownLeftTeeVector", 0x0295E} ,
+ {"DownLeftVector", 0x021BD} ,
+ {"DownLeftVectorBar", 0x02956} ,
+ {"DownRightTeeVector", 0x0295F} ,
+ {"DownRightVector", 0x021C1} ,
+ {"DownRightVectorBar", 0x02957} ,
+ {"DownTee", 0x022A4} ,
+ {"DownTeeArrow", 0x021A7} ,
+ {"Downarrow", 0x021D3} ,
+ {"Dscr", 0x1D49F} ,
+ {"Dstrok", 0x00110} ,
+ {"ENG", 0x0014A} ,
+ {"ETH", 0x000D0} ,
+ {"Eacute", 0x000C9} ,
+ {"Ecaron", 0x0011A} ,
+ {"Ecirc", 0x000CA} ,
+ {"Ecy", 0x0042D} ,
+ {"Edot", 0x00116} ,
+ {"Efr", 0x1D508} ,
+ {"Egrave", 0x000C8} ,
+ {"Element", 0x02208} ,
+ {"Emacr", 0x00112} ,
+ {"EmptySmallSquare", 0x025FB} ,
+ {"EmptyVerySmallSquare", 0x025AB} ,
+ {"Eogon", 0x00118} ,
+ {"Eopf", 0x1D53C} ,
+ {"Equal", 0x02A75} ,
+ {"EqualTilde", 0x02242} ,
+ {"Equilibrium", 0x021CC} ,
+ {"Escr", 0x02130} ,
+ {"Esim", 0x02A73} ,
+ {"Euml", 0x000CB} ,
+ {"Exists", 0x02203} ,
+ {"ExponentialE", 0x02147} ,
+ {"Fcy", 0x00424} ,
+ {"Ffr", 0x1D509} ,
+ {"FilledSmallSquare", 0x025FC} ,
+ {"FilledVerySmallSquare", 0x025AA} ,
+ {"Fopf", 0x1D53D} ,
+ {"ForAll", 0x02200} ,
+ {"Fouriertrf", 0x02131} ,
+ {"Fscr", 0x02131} ,
+ {"GJcy", 0x00403} ,
+ {"Gamma", 0x00393} ,
+ {"Gammad", 0x003DC} ,
+ {"Gbreve", 0x0011E} ,
+ {"Gcedil", 0x00122} ,
+ {"Gcirc", 0x0011C} ,
+ {"Gcy", 0x00413} ,
+ {"Gdot", 0x00120} ,
+ {"Gfr", 0x1D50A} ,
+ {"Gg", 0x022D9} ,
+ {"Gopf", 0x1D53E} ,
+ {"GreaterEqual", 0x02265} ,
+ {"GreaterEqualLess", 0x022DB} ,
+ {"GreaterFullEqual", 0x02267} ,
+ {"GreaterGreater", 0x02AA2} ,
+ {"GreaterLess", 0x02277} ,
+ {"GreaterSlantEqual", 0x02A7E} ,
+ {"GreaterTilde", 0x02273} ,
+ {"Gscr", 0x1D4A2} ,
+ {"Gt", 0x0226B} ,
+ {"HARDcy", 0x0042A} ,
+ {"Hacek", 0x002C7} ,
+ {"Hat", 0x0005E} ,
+ {"Hcirc", 0x00124} ,
+ {"Hfr", 0x0210C} ,
+ {"HilbertSpace", 0x0210B} ,
+ {"Hopf", 0x0210D} ,
+ {"HorizontalLine", 0x02500} ,
+ {"Hscr", 0x0210B} ,
+ {"Hstrok", 0x00126} ,
+ {"HumpDownHump", 0x0224E} ,
+ {"HumpEqual", 0x0224F} ,
+ {"IEcy", 0x00415} ,
+ {"IJlig", 0x00132} ,
+ {"IOcy", 0x00401} ,
+ {"Iacute", 0x000CD} ,
+ {"Icirc", 0x000CE} ,
+ {"Icy", 0x00418} ,
+ {"Idot", 0x00130} ,
+ {"Ifr", 0x02111} ,
+ {"Igrave", 0x000CC} ,
+ {"Im", 0x02111} ,
+ {"Imacr", 0x0012A} ,
+ {"ImaginaryI", 0x02148} ,
+ {"Implies", 0x021D2} ,
+ {"Int", 0x0222C} ,
+ {"Integral", 0x0222B} ,
+ {"Intersection", 0x022C2} ,
+ {"InvisibleComma", 0x02063} ,
+ {"InvisibleTimes", 0x02062} ,
+ {"Iogon", 0x0012E} ,
+ {"Iopf", 0x1D540} ,
+ {"Iscr", 0x02110} ,
+ {"Itilde", 0x00128} ,
+ {"Iukcy", 0x00406} ,
+ {"Iuml", 0x000CF} ,
+ {"Jcirc", 0x00134} ,
+ {"Jcy", 0x00419} ,
+ {"Jfr", 0x1D50D} ,
+ {"Jopf", 0x1D541} ,
+ {"Jscr", 0x1D4A5} ,
+ {"Jsercy", 0x00408} ,
+ {"Jukcy", 0x00404} ,
+ {"KHcy", 0x00425} ,
+ {"KJcy", 0x0040C} ,
+ {"Kcedil", 0x00136} ,
+ {"Kcy", 0x0041A} ,
+ {"Kfr", 0x1D50E} ,
+ {"Kopf", 0x1D542} ,
+ {"Kscr", 0x1D4A6} ,
+ {"LJcy", 0x00409} ,
+ {"Lacute", 0x00139} ,
+ {"Lambda", 0x0039B} ,
+ {"Lang", 0x0300A} ,
+ {"Laplacetrf", 0x02112} ,
+ {"Larr", 0x0219E} ,
+ {"Lcaron", 0x0013D} ,
+ {"Lcedil", 0x0013B} ,
+ {"Lcy", 0x0041B} ,
+ {"LeftAngleBracket", 0x02329} ,
+ {"LeftArrow", 0x02190} ,
+ {"LeftArrowBar", 0x021E4} ,
+ {"LeftArrowRightArrow", 0x021C6} ,
+ {"LeftCeiling", 0x02308} ,
+ {"LeftDoubleBracket", 0x0301A} ,
+ {"LeftDownTeeVector", 0x02961} ,
+ {"LeftDownVector", 0x021C3} ,
+ {"LeftDownVectorBar", 0x02959} ,
+ {"LeftFloor", 0x0230A} ,
+ {"LeftRightArrow", 0x02194} ,
+ {"LeftRightVector", 0x0294E} ,
+ {"LeftTee", 0x022A3} ,
+ {"LeftTeeArrow", 0x021A4} ,
+ {"LeftTeeVector", 0x0295A} ,
+ {"LeftTriangle", 0x022B2} ,
+ {"LeftTriangleBar", 0x029CF} ,
+ {"LeftTriangleEqual", 0x022B4} ,
+ {"LeftUpDownVector", 0x02951} ,
+ {"LeftUpTeeVector", 0x02960} ,
+ {"LeftUpVector", 0x021BF} ,
+ {"LeftUpVectorBar", 0x02958} ,
+ {"LeftVector", 0x021BC} ,
+ {"LeftVectorBar", 0x02952} ,
+ {"Leftarrow", 0x021D0} ,
+ {"Leftrightarrow", 0x021D4} ,
+ {"LessEqualGreater", 0x022DA} ,
+ {"LessFullEqual", 0x02266} ,
+ {"LessGreater", 0x02276} ,
+ {"LessLess", 0x02AA1} ,
+ {"LessSlantEqual", 0x02A7D} ,
+ {"LessTilde", 0x02272} ,
+ {"Lfr", 0x1D50F} ,
+ {"Ll", 0x022D8} ,
+ {"Lleftarrow", 0x021DA} ,
+ {"Lmidot", 0x0013F} ,
+ {"LongLeftArrow", 0x027F5} ,
+ {"LongLeftRightArrow", 0x027F7} ,
+ {"LongRightArrow", 0x027F6} ,
+ {"Longleftarrow", 0x027F8} ,
+ {"Longleftrightarrow", 0x027FA} ,
+ {"Longrightarrow", 0x027F9} ,
+ {"Lopf", 0x1D543} ,
+ {"LowerLeftArrow", 0x02199} ,
+ {"LowerRightArrow", 0x02198} ,
+ {"Lscr", 0x02112} ,
+ {"Lsh", 0x021B0} ,
+ {"Lstrok", 0x00141} ,
+ {"Lt", 0x0226A} ,
+ {"Map", 0x02905} ,
+ {"Mcy", 0x0041C} ,
+ {"MediumSpace", 0x0205F} ,
+ {"Mellintrf", 0x02133} ,
+ {"Mfr", 0x1D510} ,
+ {"MinusPlus", 0x02213} ,
+ {"Mopf", 0x1D544} ,
+ {"Mscr", 0x02133} ,
+ {"NJcy", 0x0040A} ,
+ {"Nacute", 0x00143} ,
+ {"Ncaron", 0x00147} ,
+ {"Ncedil", 0x00145} ,
+ {"Ncy", 0x0041D} ,
+ {"NegativeMediumSpace", 0x0200B} ,
+ {"NegativeThickSpace", 0x0200B} ,
+ {"NegativeThinSpace", 0x0200B} ,
+ {"NegativeVeryThinSpace", 0x0200B} ,
+ {"NestedGreaterGreater", 0x0226B} ,
+ {"NestedLessLess", 0x0226A} ,
+ {"NewLine", 0x0000A} ,
+ {"Nfr", 0x1D511} ,
+ {"NoBreak", 0x02060} ,
+ {"NonBreakingSpace", 0x000A0} ,
+ {"Nopf", 0x02115} ,
+ {"Not", 0x02AEC} ,
+ {"NotCongruent", 0x02262} ,
+ {"NotCupCap", 0x0226D} ,
+ {"NotDoubleVerticalBar", 0x02226} ,
+ {"NotElement", 0x02209} ,
+ {"NotEqual", 0x02260} ,
+ {"NotExists", 0x02204} ,
+ {"NotGreater", 0x0226F} ,
+ {"NotGreaterEqual", 0x02271} ,
+ {"NotGreaterLess", 0x02279} ,
+ {"NotGreaterTilde", 0x02275} ,
+ {"NotLeftTriangle", 0x022EA} ,
+ {"NotLeftTriangleEqual", 0x022EC} ,
+ {"NotLess", 0x0226E} ,
+ {"NotLessEqual", 0x02270} ,
+ {"NotLessGreater", 0x02278} ,
+ {"NotLessTilde", 0x02274} ,
+ {"NotPrecedes", 0x02280} ,
+ {"NotPrecedesSlantEqual", 0x022E0} ,
+ {"NotReverseElement", 0x0220C} ,
+ {"NotRightTriangle", 0x022EB} ,
+ {"NotRightTriangleEqual", 0x022ED} ,
+ {"NotSquareSubsetEqual", 0x022E2} ,
+ {"NotSquareSupersetEqual", 0x022E3} ,
+ {"NotSubsetEqual", 0x02288} ,
+ {"NotSucceeds", 0x02281} ,
+ {"NotSucceedsSlantEqual", 0x022E1} ,
+ {"NotSupersetEqual", 0x02289} ,
+ {"NotTilde", 0x02241} ,
+ {"NotTildeEqual", 0x02244} ,
+ {"NotTildeFullEqual", 0x02247} ,
+ {"NotTildeTilde", 0x02249} ,
+ {"NotVerticalBar", 0x02224} ,
+ {"Nscr", 0x1D4A9} ,
+ {"Ntilde", 0x000D1} ,
+ {"OElig", 0x00152} ,
+ {"Oacute", 0x000D3} ,
+ {"Ocirc", 0x000D4} ,
+ {"Ocy", 0x0041E} ,
+ {"Odblac", 0x00150} ,
+ {"Ofr", 0x1D512} ,
+ {"Ograve", 0x000D2} ,
+ {"Omacr", 0x0014C} ,
+ {"Omega", 0x003A9} ,
+ {"Oopf", 0x1D546} ,
+ {"OpenCurlyDoubleQuote", 0x0201C} ,
+ {"OpenCurlyQuote", 0x02018} ,
+ {"Or", 0x02A54} ,
+ {"Oscr", 0x1D4AA} ,
+ {"Oslash", 0x000D8} ,
+ {"Otilde", 0x000D5} ,
+ {"Otimes", 0x02A37} ,
+ {"Ouml", 0x000D6} ,
+ {"OverBar", 0x000AF} ,
+ {"OverBrace", 0x0FE37} ,
+ {"OverBracket", 0x023B4} ,
+ {"OverParenthesis", 0x0FE35} ,
+ {"PartialD", 0x02202} ,
+ {"Pcy", 0x0041F} ,
+ {"Pfr", 0x1D513} ,
+ {"Phi", 0x003A6} ,
+ {"Pi", 0x003A0} ,
+ {"PlusMinus", 0x000B1} ,
+ {"Poincareplane", 0x0210C} ,
+ {"Popf", 0x02119} ,
+ {"Pr", 0x02ABB} ,
+ {"Precedes", 0x0227A} ,
+ {"PrecedesEqual", 0x02AAF} ,
+ {"PrecedesSlantEqual", 0x0227C} ,
+ {"PrecedesTilde", 0x0227E} ,
+ {"Prime", 0x02033} ,
+ {"Product", 0x0220F} ,
+ {"Proportion", 0x02237} ,
+ {"Proportional", 0x0221D} ,
+ {"Pscr", 0x1D4AB} ,
+ {"Psi", 0x003A8} ,
+ {"Qfr", 0x1D514} ,
+ {"Qopf", 0x0211A} ,
+ {"Qscr", 0x1D4AC} ,
+ {"RBarr", 0x02910} ,
+ {"Racute", 0x00154} ,
+ {"Rang", 0x0300B} ,
+ {"Rarr", 0x021A0} ,
+ {"Rarrtl", 0x02916} ,
+ {"Rcaron", 0x00158} ,
+ {"Rcedil", 0x00156} ,
+ {"Rcy", 0x00420} ,
+ {"Re", 0x0211C} ,
+ {"ReverseElement", 0x0220B} ,
+ {"ReverseEquilibrium", 0x021CB} ,
+ {"ReverseUpEquilibrium", 0x0296F} ,
+ {"Rfr", 0x0211C} ,
+ {"RightAngleBracket", 0x0232A} ,
+ {"RightArrow", 0x02192} ,
+ {"RightArrowBar", 0x021E5} ,
+ {"RightArrowLeftArrow", 0x021C4} ,
+ {"RightCeiling", 0x02309} ,
+ {"RightDoubleBracket", 0x0301B} ,
+ {"RightDownTeeVector", 0x0295D} ,
+ {"RightDownVector", 0x021C2} ,
+ {"RightDownVectorBar", 0x02955} ,
+ {"RightFloor", 0x0230B} ,
+ {"RightTee", 0x022A2} ,
+ {"RightTeeArrow", 0x021A6} ,
+ {"RightTeeVector", 0x0295B} ,
+ {"RightTriangle", 0x022B3} ,
+ {"RightTriangleBar", 0x029D0} ,
+ {"RightTriangleEqual", 0x022B5} ,
+ {"RightUpDownVector", 0x0294F} ,
+ {"RightUpTeeVector", 0x0295C} ,
+ {"RightUpVector", 0x021BE} ,
+ {"RightUpVectorBar", 0x02954} ,
+ {"RightVector", 0x021C0} ,
+ {"RightVectorBar", 0x02953} ,
+ {"Rightarrow", 0x021D2} ,
+ {"Ropf", 0x0211D} ,
+ {"RoundImplies", 0x02970} ,
+ {"Rrightarrow", 0x021DB} ,
+ {"Rscr", 0x0211B} ,
+ {"Rsh", 0x021B1} ,
+ {"RuleDelayed", 0x029F4} ,
+ {"SHCHcy", 0x00429} ,
+ {"SHcy", 0x00428} ,
+ {"SOFTcy", 0x0042C} ,
+ {"Sacute", 0x0015A} ,
+ {"Sc", 0x02ABC} ,
+ {"Scaron", 0x00160} ,
+ {"Scedil", 0x0015E} ,
+ {"Scirc", 0x0015C} ,
+ {"Scy", 0x00421} ,
+ {"Sfr", 0x1D516} ,
+ {"ShortDownArrow", 0x02193} ,
+ {"ShortLeftArrow", 0x02190} ,
+ {"ShortRightArrow", 0x02192} ,
+ {"ShortUpArrow", 0x02191} ,
+ {"Sigma", 0x003A3} ,
+ {"SmallCircle", 0x02218} ,
+ {"Sopf", 0x1D54A} ,
+ {"Sqrt", 0x0221A} ,
+ {"Square", 0x025A1} ,
+ {"SquareIntersection", 0x02293} ,
+ {"SquareSubset", 0x0228F} ,
+ {"SquareSubsetEqual", 0x02291} ,
+ {"SquareSuperset", 0x02290} ,
+ {"SquareSupersetEqual", 0x02292} ,
+ {"SquareUnion", 0x02294} ,
+ {"Sscr", 0x1D4AE} ,
+ {"Star", 0x022C6} ,
+ {"Sub", 0x022D0} ,
+ {"Subset", 0x022D0} ,
+ {"SubsetEqual", 0x02286} ,
+ {"Succeeds", 0x0227B} ,
+ {"SucceedsEqual", 0x02AB0} ,
+ {"SucceedsSlantEqual", 0x0227D} ,
+ {"SucceedsTilde", 0x0227F} ,
+ {"SuchThat", 0x0220B} ,
+ {"Sum", 0x02211} ,
+ {"Sup", 0x022D1} ,
+ {"Superset", 0x02283} ,
+ {"SupersetEqual", 0x02287} ,
+ {"Supset", 0x022D1} ,
+ {"THORN", 0x000DE} ,
+ {"TSHcy", 0x0040B} ,
+ {"TScy", 0x00426} ,
+ {"Tab", 0x00009} ,
+ {"Tcaron", 0x00164} ,
+ {"Tcedil", 0x00162} ,
+ {"Tcy", 0x00422} ,
+ {"Tfr", 0x1D517} ,
+ {"Therefore", 0x02234} ,
+ {"Theta", 0x00398} ,
+ {"ThinSpace", 0x02009} ,
+ {"Tilde", 0x0223C} ,
+ {"TildeEqual", 0x02243} ,
+ {"TildeFullEqual", 0x02245} ,
+ {"TildeTilde", 0x02248} ,
+ {"Topf", 0x1D54B} ,
+ {"TripleDot", 0x020DB} ,
+ {"Tscr", 0x1D4AF} ,
+ {"Tstrok", 0x00166} ,
+ {"Uacute", 0x000DA} ,
+ {"Uarr", 0x0219F} ,
+ {"Uarrocir", 0x02949} ,
+ {"Ubrcy", 0x0040E} ,
+ {"Ubreve", 0x0016C} ,
+ {"Ucirc", 0x000DB} ,
+ {"Ucy", 0x00423} ,
+ {"Udblac", 0x00170} ,
+ {"Ufr", 0x1D518} ,
+ {"Ugrave", 0x000D9} ,
+ {"Umacr", 0x0016A} ,
+ {"UnderBar", 0x00332} ,
+ {"UnderBrace", 0x0FE38} ,
+ {"UnderBracket", 0x023B5} ,
+ {"UnderParenthesis", 0x0FE36} ,
+ {"Union", 0x022C3} ,
+ {"UnionPlus", 0x0228E} ,
+ {"Uogon", 0x00172} ,
+ {"Uopf", 0x1D54C} ,
+ {"UpArrow", 0x02191} ,
+ {"UpArrowBar", 0x02912} ,
+ {"UpArrowDownArrow", 0x021C5} ,
+ {"UpDownArrow", 0x02195} ,
+ {"UpEquilibrium", 0x0296E} ,
+ {"UpTee", 0x022A5} ,
+ {"UpTeeArrow", 0x021A5} ,
+ {"Uparrow", 0x021D1} ,
+ {"Updownarrow", 0x021D5} ,
+ {"UpperLeftArrow", 0x02196} ,
+ {"UpperRightArrow", 0x02197} ,
+ {"Upsi", 0x003D2} ,
+ {"Upsilon", 0x003A5} ,
+ {"Uring", 0x0016E} ,
+ {"Uscr", 0x1D4B0} ,
+ {"Utilde", 0x00168} ,
+ {"Uuml", 0x000DC} ,
+ {"VDash", 0x022AB} ,
+ {"Vbar", 0x02AEB} ,
+ {"Vcy", 0x00412} ,
+ {"Vdash", 0x022A9} ,
+ {"Vdashl", 0x02AE6} ,
+ {"Vee", 0x022C1} ,
+ {"Verbar", 0x02016} ,
+ {"Vert", 0x02016} ,
+ {"VerticalBar", 0x02223} ,
+ {"VerticalLine", 0x0007C} ,
+ {"VerticalSeparator", 0x02758} ,
+ {"VerticalTilde", 0x02240} ,
+ {"VeryThinSpace", 0x0200A} ,
+ {"Vfr", 0x1D519} ,
+ {"Vopf", 0x1D54D} ,
+ {"Vscr", 0x1D4B1} ,
+ {"Vvdash", 0x022AA} ,
+ {"Wcirc", 0x00174} ,
+ {"Wedge", 0x022C0} ,
+ {"Wfr", 0x1D51A} ,
+ {"Wopf", 0x1D54E} ,
+ {"Wscr", 0x1D4B2} ,
+ {"Xfr", 0x1D51B} ,
+ {"Xi", 0x0039E} ,
+ {"Xopf", 0x1D54F} ,
+ {"Xscr", 0x1D4B3} ,
+ {"YAcy", 0x0042F} ,
+ {"YIcy", 0x00407} ,
+ {"YUcy", 0x0042E} ,
+ {"Yacute", 0x000DD} ,
+ {"Ycirc", 0x00176} ,
+ {"Ycy", 0x0042B} ,
+ {"Yfr", 0x1D51C} ,
+ {"Yopf", 0x1D550} ,
+ {"Yscr", 0x1D4B4} ,
+ {"Yuml", 0x00178} ,
+ {"ZHcy", 0x00416} ,
+ {"Zacute", 0x00179} ,
+ {"Zcaron", 0x0017D} ,
+ {"Zcy", 0x00417} ,
+ {"Zdot", 0x0017B} ,
+ {"ZeroWidthSpace", 0x0200B} ,
+ {"Zfr", 0x02128} ,
+ {"Zopf", 0x02124} ,
+ {"Zscr", 0x1D4B5} ,
+ {"aacute", 0x000E1} ,
+ {"abreve", 0x00103} ,
+ {"ac", 0x0223E} ,
+ {"acd", 0x0223F} ,
+ {"acirc", 0x000E2} ,
+ {"acute", 0x000B4} ,
+ {"acy", 0x00430} ,
+ {"aelig", 0x000E6} ,
+ {"af", 0x02061} ,
+ {"afr", 0x1D51E} ,
+ {"agrave", 0x000E0} ,
+ {"aleph", 0x02135} ,
+ {"alpha", 0x003B1} ,
+ {"amacr", 0x00101} ,
+ {"amalg", 0x02A3F} ,
+ {"amp", 0x00026} ,
+ {"and", 0x02227} ,
+ {"andand", 0x02A55} ,
+ {"andd", 0x02A5C} ,
+ {"andslope", 0x02A58} ,
+ {"andv", 0x02A5A} ,
+ {"ang", 0x02220} ,
+ {"ange", 0x029A4} ,
+ {"angle", 0x02220} ,
+ {"angmsd", 0x02221} ,
+ {"angmsdaa", 0x029A8} ,
+ {"angmsdab", 0x029A9} ,
+ {"angmsdac", 0x029AA} ,
+ {"angmsdad", 0x029AB} ,
+ {"angmsdae", 0x029AC} ,
+ {"angmsdaf", 0x029AD} ,
+ {"angmsdag", 0x029AE} ,
+ {"angmsdah", 0x029AF} ,
+ {"angrt", 0x0221F} ,
+ {"angrtvb", 0x022BE} ,
+ {"angrtvbd", 0x0299D} ,
+ {"angsph", 0x02222} ,
+ {"angst", 0x0212B} ,
+ {"angzarr", 0x0237C} ,
+ {"aogon", 0x00105} ,
+ {"aopf", 0x1D552} ,
+ {"ap", 0x02248} ,
+ {"apE", 0x02A70} ,
+ {"apacir", 0x02A6F} ,
+ {"ape", 0x0224A} ,
+ {"apid", 0x0224B} ,
+ {"apos", 0x00027} ,
+ {"approx", 0x02248} ,
+ {"approxeq", 0x0224A} ,
+ {"aring", 0x000E5} ,
+ {"ascr", 0x1D4B6} ,
+ {"ast", 0x0002A} ,
+ {"asymp", 0x02248} ,
+ {"asympeq", 0x0224D} ,
+ {"atilde", 0x000E3} ,
+ {"auml", 0x000E4} ,
+ {"awconint", 0x02233} ,
+ {"awint", 0x02A11} ,
+ {"bNot", 0x02AED} ,
+ {"backcong", 0x0224C} ,
+ {"backepsilon", 0x003F6} ,
+ {"backprime", 0x02035} ,
+ {"backsim", 0x0223D} ,
+ {"backsimeq", 0x022CD} ,
+ {"barvee", 0x022BD} ,
+ {"barwed", 0x02305} ,
+ {"barwedge", 0x02305} ,
+ {"bbrk", 0x023B5} ,
+ {"bbrktbrk", 0x023B6} ,
+ {"bcong", 0x0224C} ,
+ {"bcy", 0x00431} ,
+ {"becaus", 0x02235} ,
+ {"because", 0x02235} ,
+ {"bemptyv", 0x029B0} ,
+ {"bepsi", 0x003F6} ,
+ {"bernou", 0x0212C} ,
+ {"beta", 0x003B2} ,
+ {"beth", 0x02136} ,
+ {"between", 0x0226C} ,
+ {"bfr", 0x1D51F} ,
+ {"bigcap", 0x022C2} ,
+ {"bigcirc", 0x025EF} ,
+ {"bigcup", 0x022C3} ,
+ {"bigodot", 0x02A00} ,
+ {"bigoplus", 0x02A01} ,
+ {"bigotimes", 0x02A02} ,
+ {"bigsqcup", 0x02A06} ,
+ {"bigstar", 0x02605} ,
+ {"bigtriangledown", 0x025BD} ,
+ {"bigtriangleup", 0x025B3} ,
+ {"biguplus", 0x02A04} ,
+ {"bigvee", 0x022C1} ,
+ {"bigwedge", 0x022C0} ,
+ {"bkarow", 0x0290D} ,
+ {"blacklozenge", 0x029EB} ,
+ {"blacksquare", 0x025AA} ,
+ {"blacktriangle", 0x025B4} ,
+ {"blacktriangledown", 0x025BE} ,
+ {"blacktriangleleft", 0x025C2} ,
+ {"blacktriangleright", 0x025B8} ,
+ {"blank", 0x02423} ,
+ {"blk12", 0x02592} ,
+ {"blk14", 0x02591} ,
+ {"blk34", 0x02593} ,
+ {"block", 0x02588} ,
+ {"bnot", 0x02310} ,
+ {"bopf", 0x1D553} ,
+ {"bot", 0x022A5} ,
+ {"bottom", 0x022A5} ,
+ {"bowtie", 0x022C8} ,
+ {"boxDL", 0x02557} ,
+ {"boxDR", 0x02554} ,
+ {"boxDl", 0x02556} ,
+ {"boxDr", 0x02553} ,
+ {"boxH", 0x02550} ,
+ {"boxHD", 0x02566} ,
+ {"boxHU", 0x02569} ,
+ {"boxHd", 0x02564} ,
+ {"boxHu", 0x02567} ,
+ {"boxUL", 0x0255D} ,
+ {"boxUR", 0x0255A} ,
+ {"boxUl", 0x0255C} ,
+ {"boxUr", 0x02559} ,
+ {"boxV", 0x02551} ,
+ {"boxVH", 0x0256C} ,
+ {"boxVL", 0x02563} ,
+ {"boxVR", 0x02560} ,
+ {"boxVh", 0x0256B} ,
+ {"boxVl", 0x02562} ,
+ {"boxVr", 0x0255F} ,
+ {"boxbox", 0x029C9} ,
+ {"boxdL", 0x02555} ,
+ {"boxdR", 0x02552} ,
+ {"boxdl", 0x02510} ,
+ {"boxdr", 0x0250C} ,
+ {"boxh", 0x02500} ,
+ {"boxhD", 0x02565} ,
+ {"boxhU", 0x02568} ,
+ {"boxhd", 0x0252C} ,
+ {"boxhu", 0x02534} ,
+ {"boxminus", 0x0229F} ,
+ {"boxplus", 0x0229E} ,
+ {"boxtimes", 0x022A0} ,
+ {"boxuL", 0x0255B} ,
+ {"boxuR", 0x02558} ,
+ {"boxul", 0x02518} ,
+ {"boxur", 0x02514} ,
+ {"boxv", 0x02502} ,
+ {"boxvH", 0x0256A} ,
+ {"boxvL", 0x02561} ,
+ {"boxvR", 0x0255E} ,
+ {"boxvh", 0x0253C} ,
+ {"boxvl", 0x02524} ,
+ {"boxvr", 0x0251C} ,
+ {"bprime", 0x02035} ,
+ {"breve", 0x002D8} ,
+ {"brvbar", 0x000A6} ,
+ {"bscr", 0x1D4B7} ,
+ {"bsemi", 0x0204F} ,
+ {"bsim", 0x0223D} ,
+ {"bsime", 0x022CD} ,
+ {"bsol", 0x0005C} ,
+ {"bsolb", 0x029C5} ,
+ {"bull", 0x02022} ,
+ {"bullet", 0x02022} ,
+ {"bump", 0x0224E} ,
+ {"bumpE", 0x02AAE} ,
+ {"bumpe", 0x0224F} ,
+ {"bumpeq", 0x0224F} ,
+ {"cacute", 0x00107} ,
+ {"cap", 0x02229} ,
+ {"capand", 0x02A44} ,
+ {"capbrcup", 0x02A49} ,
+ {"capcap", 0x02A4B} ,
+ {"capcup", 0x02A47} ,
+ {"capdot", 0x02A40} ,
+ {"caret", 0x02041} ,
+ {"caron", 0x002C7} ,
+ {"ccaps", 0x02A4D} ,
+ {"ccaron", 0x0010D} ,
+ {"ccedil", 0x000E7} ,
+ {"ccirc", 0x00109} ,
+ {"ccups", 0x02A4C} ,
+ {"ccupssm", 0x02A50} ,
+ {"cdot", 0x0010B} ,
+ {"cedil", 0x000B8} ,
+ {"cemptyv", 0x029B2} ,
+ {"cent", 0x000A2} ,
+ {"centerdot", 0x000B7} ,
+ {"cfr", 0x1D520} ,
+ {"chcy", 0x00447} ,
+ {"check", 0x02713} ,
+ {"checkmark", 0x02713} ,
+ {"chi", 0x003C7} ,
+ {"cir", 0x025CB} ,
+ {"cirE", 0x029C3} ,
+ {"circ", 0x002C6} ,
+ {"circeq", 0x02257} ,
+ {"circlearrowleft", 0x021BA} ,
+ {"circlearrowright", 0x021BB} ,
+ {"circledR", 0x000AE} ,
+ {"circledS", 0x024C8} ,
+ {"circledast", 0x0229B} ,
+ {"circledcirc", 0x0229A} ,
+ {"circleddash", 0x0229D} ,
+ {"cire", 0x02257} ,
+ {"cirfnint", 0x02A10} ,
+ {"cirmid", 0x02AEF} ,
+ {"cirscir", 0x029C2} ,
+ {"clubs", 0x02663} ,
+ {"clubsuit", 0x02663} ,
+ {"colon", 0x0003A} ,
+ {"colone", 0x02254} ,
+ {"coloneq", 0x02254} ,
+ {"comma", 0x0002C} ,
+ {"commat", 0x00040} ,
+ {"comp", 0x02201} ,
+ {"compfn", 0x02218} ,
+ {"complement", 0x02201} ,
+ {"complexes", 0x02102} ,
+ {"cong", 0x02245} ,
+ {"congdot", 0x02A6D} ,
+ {"conint", 0x0222E} ,
+ {"copf", 0x1D554} ,
+ {"coprod", 0x02210} ,
+ {"copy", 0x000A9} ,
+ {"copysr", 0x02117} ,
+ {"cross", 0x02717} ,
+ {"cscr", 0x1D4B8} ,
+ {"csub", 0x02ACF} ,
+ {"csube", 0x02AD1} ,
+ {"csup", 0x02AD0} ,
+ {"csupe", 0x02AD2} ,
+ {"ctdot", 0x022EF} ,
+ {"cudarrl", 0x02938} ,
+ {"cudarrr", 0x02935} ,
+ {"cuepr", 0x022DE} ,
+ {"cuesc", 0x022DF} ,
+ {"cularr", 0x021B6} ,
+ {"cularrp", 0x0293D} ,
+ {"cup", 0x0222A} ,
+ {"cupbrcap", 0x02A48} ,
+ {"cupcap", 0x02A46} ,
+ {"cupcup", 0x02A4A} ,
+ {"cupdot", 0x0228D} ,
+ {"cupor", 0x02A45} ,
+ {"curarr", 0x021B7} ,
+ {"curarrm", 0x0293C} ,
+ {"curlyeqprec", 0x022DE} ,
+ {"curlyeqsucc", 0x022DF} ,
+ {"curlyvee", 0x022CE} ,
+ {"curlywedge", 0x022CF} ,
+ {"curren", 0x000A4} ,
+ {"curvearrowleft", 0x021B6} ,
+ {"curvearrowright", 0x021B7} ,
+ {"cuvee", 0x022CE} ,
+ {"cuwed", 0x022CF} ,
+ {"cwconint", 0x02232} ,
+ {"cwint", 0x02231} ,
+ {"cylcty", 0x0232D} ,
+ {"dArr", 0x021D3} ,
+ {"dHar", 0x02965} ,
+ {"dagger", 0x02020} ,
+ {"dagger", 0x02020} ,
+ {"daleth", 0x02138} ,
+ {"darr", 0x02193} ,
+ {"dash", 0x02010} ,
+ {"dashv", 0x022A3} ,
+ {"dbkarow", 0x0290F} ,
+ {"dblac", 0x002DD} ,
+ {"dcaron", 0x0010F} ,
+ {"dcy", 0x00434} ,
+ {"dd", 0x02146} ,
+ {"ddagger", 0x02021} ,
+ {"ddarr", 0x021CA} ,
+ {"ddotseq", 0x02A77} ,
+ {"deg", 0x000B0} ,
+ {"delta", 0x003B4} ,
+ {"demptyv", 0x029B1} ,
+ {"dfisht", 0x0297F} ,
+ {"dfr", 0x1D521} ,
+ {"dharl", 0x021C3} ,
+ {"dharr", 0x021C2} ,
+ {"diam", 0x022C4} ,
+ {"diamond", 0x022C4} ,
+ {"diamondsuit", 0x02666} ,
+ {"diams", 0x02666} ,
+ {"die", 0x000A8} ,
+ {"digamma", 0x003DD} ,
+ {"disin", 0x022F2} ,
+ {"div", 0x000F7} ,
+ {"divide", 0x000F7} ,
+ {"divideontimes", 0x022C7} ,
+ {"divonx", 0x022C7} ,
+ {"djcy", 0x00452} ,
+ {"dlcorn", 0x0231E} ,
+ {"dlcrop", 0x0230D} ,
+ {"dollar", 0x00024} ,
+ {"dopf", 0x1D555} ,
+ {"dot", 0x002D9} ,
+ {"doteq", 0x02250} ,
+ {"doteqdot", 0x02251} ,
+ {"dotminus", 0x02238} ,
+ {"dotplus", 0x02214} ,
+ {"dotsquare", 0x022A1} ,
+ {"doublebarwedge", 0x02306} ,
+ {"downarrow", 0x02193} ,
+ {"downdownarrows", 0x021CA} ,
+ {"downharpoonleft", 0x021C3} ,
+ {"downharpoonright", 0x021C2} ,
+ {"drbkarow", 0x02910} ,
+ {"drcorn", 0x0231F} ,
+ {"drcrop", 0x0230C} ,
+ {"dscr", 0x1D4B9} ,
+ {"dscy", 0x00455} ,
+ {"dsol", 0x029F6} ,
+ {"dstrok", 0x00111} ,
+ {"dtdot", 0x022F1} ,
+ {"dtri", 0x025BF} ,
+ {"dtrif", 0x025BE} ,
+ {"duarr", 0x021F5} ,
+ {"duhar", 0x0296F} ,
+ {"dwangle", 0x029A6} ,
+ {"dzcy", 0x0045F} ,
+ {"dzigrarr", 0x027FF} ,
+ {"eDDot", 0x02A77} ,
+ {"eDot", 0x02251} ,
+ {"eacute", 0x000E9} ,
+ {"easter", 0x02A6E} ,
+ {"ecaron", 0x0011B} ,
+ {"ecir", 0x02256} ,
+ {"ecirc", 0x000EA} ,
+ {"ecolon", 0x02255} ,
+ {"ecy", 0x0044D} ,
+ {"edot", 0x00117} ,
+ {"ee", 0x02147} ,
+ {"efDot", 0x02252} ,
+ {"efr", 0x1D522} ,
+ {"eg", 0x02A9A} ,
+ {"egrave", 0x000E8} ,
+ {"egs", 0x02A96} ,
+ {"egsdot", 0x02A98} ,
+ {"el", 0x02A99} ,
+ {"elinters", 0x0FFFD} ,
+ {"ell", 0x02113} ,
+ {"els", 0x02A95} ,
+ {"elsdot", 0x02A97} ,
+ {"emacr", 0x00113} ,
+ {"empty", 0x02205} ,
+ {"emptyset", 0x02205} ,
+ {"emptyv", 0x02205} ,
+ {"emsp", 0x02003} ,
+ {"emsp13", 0x02004} ,
+ {"emsp14", 0x02005} ,
+ {"eng", 0x0014B} ,
+ {"ensp", 0x02002} ,
+ {"eogon", 0x00119} ,
+ {"eopf", 0x1D556} ,
+ {"epar", 0x022D5} ,
+ {"eparsl", 0x029E3} ,
+ {"eplus", 0x02A71} ,
+ {"epsi", 0x003F5} ,
+ {"epsiv", 0x003B5} ,
+ {"eqcirc", 0x02256} ,
+ {"eqcolon", 0x02255} ,
+ {"eqsim", 0x02242} ,
+ {"eqslantgtr", 0x02A96} ,
+ {"eqslantless", 0x02A95} ,
+ {"equals", 0x0003D} ,
+ {"equest", 0x0225F} ,
+ {"equiv", 0x02261} ,
+ {"equivDD", 0x02A78} ,
+ {"eqvparsl", 0x029E5} ,
+ {"erDot", 0x02253} ,
+ {"erarr", 0x02971} ,
+ {"escr", 0x0212F} ,
+ {"esdot", 0x02250} ,
+ {"esim", 0x02242} ,
+ {"eta", 0x003B7} ,
+ {"eth", 0x000F0} ,
+ {"euml", 0x000EB} ,
+ {"excl", 0x00021} ,
+ {"exist", 0x02203} ,
+ {"expectation", 0x02130} ,
+ {"exponentiale", 0x02147} ,
+ {"fallingdotseq", 0x02252} ,
+ {"fcy", 0x00444} ,
+ {"female", 0x02640} ,
+ {"ffilig", 0x0FB03} ,
+ {"fflig", 0x0FB00} ,
+ {"ffllig", 0x0FB04} ,
+ {"ffr", 0x1D523} ,
+ {"filig", 0x0FB01} ,
+ {"flat", 0x0266D} ,
+ {"fllig", 0x0FB02} ,
+ {"fltns", 0x025B1} ,
+ {"fnof", 0x00192} ,
+ {"fopf", 0x1D557} ,
+ {"forall", 0x02200} ,
+ {"fork", 0x022D4} ,
+ {"forkv", 0x02AD9} ,
+ {"fpartint", 0x02A0D} ,
+ {"frac12", 0x000BD} ,
+ {"frac13", 0x02153} ,
+ {"frac14", 0x000BC} ,
+ {"frac15", 0x02155} ,
+ {"frac16", 0x02159} ,
+ {"frac18", 0x0215B} ,
+ {"frac23", 0x02154} ,
+ {"frac25", 0x02156} ,
+ {"frac34", 0x000BE} ,
+ {"frac35", 0x02157} ,
+ {"frac38", 0x0215C} ,
+ {"frac45", 0x02158} ,
+ {"frac56", 0x0215A} ,
+ {"frac58", 0x0215D} ,
+ {"frac78", 0x0215E} ,
+ {"frown", 0x02322} ,
+ {"fscr", 0x1D4BB} ,
+ {"gE", 0x02267} ,
+ {"gEl", 0x02A8C} ,
+ {"gacute", 0x001F5} ,
+ {"gamma", 0x003B3} ,
+ {"gammad", 0x003DD} ,
+ {"gap", 0x02A86} ,
+ {"gbreve", 0x0011F} ,
+ {"gcirc", 0x0011D} ,
+ {"gcy", 0x00433} ,
+ {"gdot", 0x00121} ,
+ {"ge", 0x02265} ,
+ {"gel", 0x022DB} ,
+ {"geq", 0x02265} ,
+ {"geqq", 0x02267} ,
+ {"geqslant", 0x02A7E} ,
+ {"ges", 0x02A7E} ,
+ {"gescc", 0x02AA9} ,
+ {"gesdot", 0x02A80} ,
+ {"gesdoto", 0x02A82} ,
+ {"gesdotol", 0x02A84} ,
+ {"gesles", 0x02A94} ,
+ {"gfr", 0x1D524} ,
+ {"gg", 0x0226B} ,
+ {"ggg", 0x022D9} ,
+ {"gimel", 0x02137} ,
+ {"gjcy", 0x00453} ,
+ {"gl", 0x02277} ,
+ {"glE", 0x02A92} ,
+ {"gla", 0x02AA5} ,
+ {"glj", 0x02AA4} ,
+ {"gnE", 0x02269} ,
+ {"gnap", 0x02A8A} ,
+ {"gnapprox", 0x02A8A} ,
+ {"gne", 0x02A88} ,
+ {"gneq", 0x02A88} ,
+ {"gneqq", 0x02269} ,
+ {"gnsim", 0x022E7} ,
+ {"gopf", 0x1D558} ,
+ {"grave", 0x00060} ,
+ {"gscr", 0x0210A} ,
+ {"gsim", 0x02273} ,
+ {"gsime", 0x02A8E} ,
+ {"gsiml", 0x02A90} ,
+ {"gt", 0x0003E} ,
+ {"gtcc", 0x02AA7} ,
+ {"gtcir", 0x02A7A} ,
+ {"gtdot", 0x022D7} ,
+ {"gtlPar", 0x02995} ,
+ {"gtquest", 0x02A7C} ,
+ {"gtrapprox", 0x02A86} ,
+ {"gtrarr", 0x02978} ,
+ {"gtrdot", 0x022D7} ,
+ {"gtreqless", 0x022DB} ,
+ {"gtreqqless", 0x02A8C} ,
+ {"gtrless", 0x02277} ,
+ {"gtrsim", 0x02273} ,
+ {"hArr", 0x021D4} ,
+ {"hairsp", 0x0200A} ,
+ {"half", 0x000BD} ,
+ {"hamilt", 0x0210B} ,
+ {"hardcy", 0x0044A} ,
+ {"harr", 0x02194} ,
+ {"harrcir", 0x02948} ,
+ {"harrw", 0x021AD} ,
+ {"hbar", 0x0210F} ,
+ {"hcirc", 0x00125} ,
+ {"hearts", 0x02665} ,
+ {"heartsuit", 0x02665} ,
+ {"hellip", 0x02026} ,
+ {"hercon", 0x022B9} ,
+ {"hfr", 0x1D525} ,
+ {"hksearow", 0x02925} ,
+ {"hkswarow", 0x02926} ,
+ {"hoarr", 0x021FF} ,
+ {"homtht", 0x0223B} ,
+ {"hookleftarrow", 0x021A9} ,
+ {"hookrightarrow", 0x021AA} ,
+ {"hopf", 0x1D559} ,
+ {"horbar", 0x02015} ,
+ {"hscr", 0x1D4BD} ,
+ {"hslash", 0x0210F} ,
+ {"hstrok", 0x00127} ,
+ {"hybull", 0x02043} ,
+ {"hyphen", 0x02010} ,
+ {"iacute", 0x000ED} ,
+ {"ic", 0x02063} ,
+ {"icirc", 0x000EE} ,
+ {"icy", 0x00438} ,
+ {"iecy", 0x00435} ,
+ {"iexcl", 0x000A1} ,
+ {"iff", 0x021D4} ,
+ {"ifr", 0x1D526} ,
+ {"igrave", 0x000EC} ,
+ {"ii", 0x02148} ,
+ {"iiiint", 0x02A0C} ,
+ {"iiint", 0x0222D} ,
+ {"iinfin", 0x029DC} ,
+ {"iiota", 0x02129} ,
+ {"ijlig", 0x00133} ,
+ {"imacr", 0x0012B} ,
+ {"image", 0x02111} ,
+ {"imagline", 0x02110} ,
+ {"imagpart", 0x02111} ,
+ {"imath", 0x00131} ,
+ {"imof", 0x022B7} ,
+ {"imped", 0x001B5} ,
+ {"in", 0x02208} ,
+ {"incare", 0x02105} ,
+ {"infin", 0x0221E} ,
+ {"infintie", 0x029DD} ,
+ {"inodot", 0x00131} ,
+ {"int", 0x0222B} ,
+ {"intcal", 0x022BA} ,
+ {"integers", 0x02124} ,
+ {"intercal", 0x022BA} ,
+ {"intlarhk", 0x02A17} ,
+ {"intprod", 0x02A3C} ,
+ {"iocy", 0x00451} ,
+ {"iogon", 0x0012F} ,
+ {"iopf", 0x1D55A} ,
+ {"iota", 0x003B9} ,
+ {"iprod", 0x02A3C} ,
+ {"iquest", 0x000BF} ,
+ {"iscr", 0x1D4BE} ,
+ {"isin", 0x02208} ,
+ {"isinE", 0x022F9} ,
+ {"isindot", 0x022F5} ,
+ {"isins", 0x022F4} ,
+ {"isinsv", 0x022F3} ,
+ {"isinv", 0x02208} ,
+ {"it", 0x02062} ,
+ {"itilde", 0x00129} ,
+ {"iukcy", 0x00456} ,
+ {"iuml", 0x000EF} ,
+ {"jcirc", 0x00135} ,
+ {"jcy", 0x00439} ,
+ {"jfr", 0x1D527} ,
+ {"jmath", 0x0006A} ,
+ {"jopf", 0x1D55B} ,
+ {"jscr", 0x1D4BF} ,
+ {"jsercy", 0x00458} ,
+ {"jukcy", 0x00454} ,
+ {"kappa", 0x003BA} ,
+ {"kappav", 0x003F0} ,
+ {"kcedil", 0x00137} ,
+ {"kcy", 0x0043A} ,
+ {"kfr", 0x1D528} ,
+ {"kgreen", 0x00138} ,
+ {"khcy", 0x00445} ,
+ {"kjcy", 0x0045C} ,
+ {"kopf", 0x1D55C} ,
+ {"kscr", 0x1D4C0} ,
+ {"lAarr", 0x021DA} ,
+ {"lArr", 0x021D0} ,
+ {"lAtail", 0x0291B} ,
+ {"lBarr", 0x0290E} ,
+ {"lE", 0x02266} ,
+ {"lEg", 0x02A8B} ,
+ {"lHar", 0x02962} ,
+ {"lacute", 0x0013A} ,
+ {"laemptyv", 0x029B4} ,
+ {"lagran", 0x02112} ,
+ {"lambda", 0x003BB} ,
+ {"lang", 0x02329} ,
+ {"langd", 0x02991} ,
+ {"langle", 0x02329} ,
+ {"lap", 0x02A85} ,
+ {"laquo", 0x000AB} ,
+ {"larr", 0x02190} ,
+ {"larrb", 0x021E4} ,
+ {"larrbfs", 0x0291F} ,
+ {"larrfs", 0x0291D} ,
+ {"larrhk", 0x021A9} ,
+ {"larrlp", 0x021AB} ,
+ {"larrpl", 0x02939} ,
+ {"larrsim", 0x02973} ,
+ {"larrtl", 0x021A2} ,
+ {"lat", 0x02AAB} ,
+ {"latail", 0x02919} ,
+ {"late", 0x02AAD} ,
+ {"lbarr", 0x0290C} ,
+ {"lbbrk", 0x03014} ,
+ {"lbrace", 0x0007B} ,
+ {"lbrack", 0x0005B} ,
+ {"lbrke", 0x0298B} ,
+ {"lbrksld", 0x0298F} ,
+ {"lbrkslu", 0x0298D} ,
+ {"lcaron", 0x0013E} ,
+ {"lcedil", 0x0013C} ,
+ {"lceil", 0x02308} ,
+ {"lcub", 0x0007B} ,
+ {"lcy", 0x0043B} ,
+ {"ldca", 0x02936} ,
+ {"ldquo", 0x0201C} ,
+ {"ldquor", 0x0201E} ,
+ {"ldrdhar", 0x02967} ,
+ {"ldrushar", 0x0294B} ,
+ {"ldsh", 0x021B2} ,
+ {"le", 0x02264} ,
+ {"leftarrow", 0x02190} ,
+ {"leftarrowtail", 0x021A2} ,
+ {"leftharpoondown", 0x021BD} ,
+ {"leftharpoonup", 0x021BC} ,
+ {"leftleftarrows", 0x021C7} ,
+ {"leftrightarrow", 0x02194} ,
+ {"leftrightarrows", 0x021C6} ,
+ {"leftrightharpoons", 0x021CB} ,
+ {"leftrightsquigarrow", 0x021AD} ,
+ {"leftthreetimes", 0x022CB} ,
+ {"leg", 0x022DA} ,
+ {"leq", 0x02264} ,
+ {"leqq", 0x02266} ,
+ {"leqslant", 0x02A7D} ,
+ {"les", 0x02A7D} ,
+ {"lescc", 0x02AA8} ,
+ {"lesdot", 0x02A7F} ,
+ {"lesdoto", 0x02A81} ,
+ {"lesdotor", 0x02A83} ,
+ {"lesges", 0x02A93} ,
+ {"lessapprox", 0x02A85} ,
+ {"lessdot", 0x022D6} ,
+ {"lesseqgtr", 0x022DA} ,
+ {"lesseqqgtr", 0x02A8B} ,
+ {"lessgtr", 0x02276} ,
+ {"lesssim", 0x02272} ,
+ {"lfisht", 0x0297C} ,
+ {"lfloor", 0x0230A} ,
+ {"lfr", 0x1D529} ,
+ {"lg", 0x02276} ,
+ {"lgE", 0x02A91} ,
+ {"lhard", 0x021BD} ,
+ {"lharu", 0x021BC} ,
+ {"lharul", 0x0296A} ,
+ {"lhblk", 0x02584} ,
+ {"ljcy", 0x00459} ,
+ {"ll", 0x0226A} ,
+ {"llarr", 0x021C7} ,
+ {"llcorner", 0x0231E} ,
+ {"llhard", 0x0296B} ,
+ {"lltri", 0x025FA} ,
+ {"lmidot", 0x00140} ,
+ {"lmoust", 0x023B0} ,
+ {"lmoustache", 0x023B0} ,
+ {"lnE", 0x02268} ,
+ {"lnap", 0x02A89} ,
+ {"lnapprox", 0x02A89} ,
+ {"lne", 0x02A87} ,
+ {"lneq", 0x02A87} ,
+ {"lneqq", 0x02268} ,
+ {"lnsim", 0x022E6} ,
+ {"loang", 0x03018} ,
+ {"loarr", 0x021FD} ,
+ {"lobrk", 0x0301A} ,
+ {"longleftarrow", 0x027F5} ,
+ {"longleftrightarrow", 0x027F7} ,
+ {"longmapsto", 0x027FC} ,
+ {"longrightarrow", 0x027F6} ,
+ {"looparrowleft", 0x021AB} ,
+ {"looparrowright", 0x021AC} ,
+ {"lopar", 0x02985} ,
+ {"lopf", 0x1D55D} ,
+ {"loplus", 0x02A2D} ,
+ {"lotimes", 0x02A34} ,
+ {"lowast", 0x02217} ,
+ {"lowbar", 0x0005F} ,
+ {"loz", 0x025CA} ,
+ {"lozenge", 0x025CA} ,
+ {"lozf", 0x029EB} ,
+ {"lpar", 0x00028} ,
+ {"lparlt", 0x02993} ,
+ {"lrarr", 0x021C6} ,
+ {"lrcorner", 0x0231F} ,
+ {"lrhar", 0x021CB} ,
+ {"lrhard", 0x0296D} ,
+ {"lrtri", 0x022BF} ,
+ {"lscr", 0x1D4C1} ,
+ {"lsh", 0x021B0} ,
+ {"lsim", 0x02272} ,
+ {"lsime", 0x02A8D} ,
+ {"lsimg", 0x02A8F} ,
+ {"lsqb", 0x0005B} ,
+ {"lsquo", 0x02018} ,
+ {"lsquor", 0x0201A} ,
+ {"lstrok", 0x00142} ,
+ {"lt", 0x0003C} ,
+ {"ltcc", 0x02AA6} ,
+ {"ltcir", 0x02A79} ,
+ {"ltdot", 0x022D6} ,
+ {"lthree", 0x022CB} ,
+ {"ltimes", 0x022C9} ,
+ {"ltlarr", 0x02976} ,
+ {"ltquest", 0x02A7B} ,
+ {"ltrPar", 0x02996} ,
+ {"ltri", 0x025C3} ,
+ {"ltrie", 0x022B4} ,
+ {"ltrif", 0x025C2} ,
+ {"lurdshar", 0x0294A} ,
+ {"luruhar", 0x02966} ,
+ {"mDDot", 0x0223A} ,
+ {"macr", 0x000AF} ,
+ {"male", 0x02642} ,
+ {"malt", 0x02720} ,
+ {"maltese", 0x02720} ,
+ {"map", 0x021A6} ,
+ {"mapsto", 0x021A6} ,
+ {"mapstodown", 0x021A7} ,
+ {"mapstoleft", 0x021A4} ,
+ {"mapstoup", 0x021A5} ,
+ {"marker", 0x025AE} ,
+ {"mcomma", 0x02A29} ,
+ {"mcy", 0x0043C} ,
+ {"mdash", 0x02014} ,
+ {"measuredangle", 0x02221} ,
+ {"mfr", 0x1D52A} ,
+ {"mho", 0x02127} ,
+ {"micro", 0x000B5} ,
+ {"mid", 0x02223} ,
+ {"midast", 0x0002A} ,
+ {"midcir", 0x02AF0} ,
+ {"middot", 0x000B7} ,
+ {"minus", 0x02212} ,
+ {"minusb", 0x0229F} ,
+ {"minusd", 0x02238} ,
+ {"minusdu", 0x02A2A} ,
+ {"mlcp", 0x02ADB} ,
+ {"mldr", 0x02026} ,
+ {"mnplus", 0x02213} ,
+ {"models", 0x022A7} ,
+ {"mopf", 0x1D55E} ,
+ {"mp", 0x02213} ,
+ {"mscr", 0x1D4C2} ,
+ {"mstpos", 0x0223E} ,
+ {"mu", 0x003BC} ,
+ {"multimap", 0x022B8} ,
+ {"mumap", 0x022B8} ,
+ {"nLeftarrow", 0x021CD} ,
+ {"nLeftrightarrow", 0x021CE} ,
+ {"nRightarrow", 0x021CF} ,
+ {"nVDash", 0x022AF} ,
+ {"nVdash", 0x022AE} ,
+ {"nabla", 0x02207} ,
+ {"nacute", 0x00144} ,
+ {"nap", 0x02249} ,
+ {"napos", 0x00149} ,
+ {"napprox", 0x02249} ,
+ {"natur", 0x0266E} ,
+ {"natural", 0x0266E} ,
+ {"naturals", 0x02115} ,
+ {"nbsp", 0x000A0} ,
+ {"ncap", 0x02A43} ,
+ {"ncaron", 0x00148} ,
+ {"ncedil", 0x00146} ,
+ {"ncong", 0x02247} ,
+ {"ncup", 0x02A42} ,
+ {"ncy", 0x0043D} ,
+ {"ndash", 0x02013} ,
+ {"ne", 0x02260} ,
+ {"neArr", 0x021D7} ,
+ {"nearhk", 0x02924} ,
+ {"nearr", 0x02197} ,
+ {"nearrow", 0x02197} ,
+ {"nequiv", 0x02262} ,
+ {"nesear", 0x02928} ,
+ {"nexist", 0x02204} ,
+ {"nexists", 0x02204} ,
+ {"nfr", 0x1D52B} ,
+ {"nge", 0x02271} ,
+ {"ngeq", 0x02271} ,
+ {"ngsim", 0x02275} ,
+ {"ngt", 0x0226F} ,
+ {"ngtr", 0x0226F} ,
+ {"nhArr", 0x021CE} ,
+ {"nharr", 0x021AE} ,
+ {"nhpar", 0x02AF2} ,
+ {"ni", 0x0220B} ,
+ {"nis", 0x022FC} ,
+ {"nisd", 0x022FA} ,
+ {"niv", 0x0220B} ,
+ {"njcy", 0x0045A} ,
+ {"nlArr", 0x021CD} ,
+ {"nlarr", 0x0219A} ,
+ {"nldr", 0x02025} ,
+ {"nle", 0x02270} ,
+ {"nleftarrow", 0x0219A} ,
+ {"nleftrightarrow", 0x021AE} ,
+ {"nleq", 0x02270} ,
+ {"nless", 0x0226E} ,
+ {"nlsim", 0x02274} ,
+ {"nlt", 0x0226E} ,
+ {"nltri", 0x022EA} ,
+ {"nltrie", 0x022EC} ,
+ {"nmid", 0x02224} ,
+ {"nopf", 0x1D55F} ,
+ {"not", 0x000AC} ,
+ {"notin", 0x02209} ,
+ {"notinva", 0x02209} ,
+ {"notinvb", 0x022F7} ,
+ {"notinvc", 0x022F6} ,
+ {"notni", 0x0220C} ,
+ {"notniva", 0x0220C} ,
+ {"notnivb", 0x022FE} ,
+ {"notnivc", 0x022FD} ,
+ {"npar", 0x02226} ,
+ {"nparallel", 0x02226} ,
+ {"npolint", 0x02A14} ,
+ {"npr", 0x02280} ,
+ {"nprcue", 0x022E0} ,
+ {"nprec", 0x02280} ,
+ {"nrArr", 0x021CF} ,
+ {"nrarr", 0x0219B} ,
+ {"nrightarrow", 0x0219B} ,
+ {"nrtri", 0x022EB} ,
+ {"nrtrie", 0x022ED} ,
+ {"nsc", 0x02281} ,
+ {"nsccue", 0x022E1} ,
+ {"nscr", 0x1D4C3} ,
+ {"nshortmid", 0x02224} ,
+ {"nshortparallel", 0x02226} ,
+ {"nsim", 0x02241} ,
+ {"nsime", 0x02244} ,
+ {"nsimeq", 0x02244} ,
+ {"nsmid", 0x02224} ,
+ {"nspar", 0x02226} ,
+ {"nsqsube", 0x022E2} ,
+ {"nsqsupe", 0x022E3} ,
+ {"nsub", 0x02284} ,
+ {"nsube", 0x02288} ,
+ {"nsubseteq", 0x02288} ,
+ {"nsucc", 0x02281} ,
+ {"nsup", 0x02285} ,
+ {"nsupe", 0x02289} ,
+ {"nsupseteq", 0x02289} ,
+ {"ntgl", 0x02279} ,
+ {"ntilde", 0x000F1} ,
+ {"ntlg", 0x02278} ,
+ {"ntriangleleft", 0x022EA} ,
+ {"ntrianglelefteq", 0x022EC} ,
+ {"ntriangleright", 0x022EB} ,
+ {"ntrianglerighteq", 0x022ED} ,
+ {"nu", 0x003BD} ,
+ {"num", 0x00023} ,
+ {"numero", 0x02116} ,
+ {"numsp", 0x02007} ,
+ {"nvDash", 0x022AD} ,
+ {"nvHarr", 0x02904} ,
+ {"nvdash", 0x022AC} ,
+ {"nvinfin", 0x029DE} ,
+ {"nvlArr", 0x02902} ,
+ {"nvrArr", 0x02903} ,
+ {"nwArr", 0x021D6} ,
+ {"nwarhk", 0x02923} ,
+ {"nwarr", 0x02196} ,
+ {"nwarrow", 0x02196} ,
+ {"nwnear", 0x02927} ,
+ {"oS", 0x024C8} ,
+ {"oacute", 0x000F3} ,
+ {"oast", 0x0229B} ,
+ {"ocir", 0x0229A} ,
+ {"ocirc", 0x000F4} ,
+ {"ocy", 0x0043E} ,
+ {"odash", 0x0229D} ,
+ {"odblac", 0x00151} ,
+ {"odiv", 0x02A38} ,
+ {"odot", 0x02299} ,
+ {"odsold", 0x029BC} ,
+ {"oelig", 0x00153} ,
+ {"ofcir", 0x029BF} ,
+ {"ofr", 0x1D52C} ,
+ {"ogon", 0x002DB} ,
+ {"ograve", 0x000F2} ,
+ {"ogt", 0x029C1} ,
+ {"ohbar", 0x029B5} ,
+ {"ohm", 0x02126} ,
+ {"oint", 0x0222E} ,
+ {"olarr", 0x021BA} ,
+ {"olcir", 0x029BE} ,
+ {"olcross", 0x029BB} ,
+ {"olt", 0x029C0} ,
+ {"omacr", 0x0014D} ,
+ {"omega", 0x003C9} ,
+ {"omid", 0x029B6} ,
+ {"ominus", 0x02296} ,
+ {"oopf", 0x1D560} ,
+ {"opar", 0x029B7} ,
+ {"operp", 0x029B9} ,
+ {"oplus", 0x02295} ,
+ {"or", 0x02228} ,
+ {"orarr", 0x021BB} ,
+ {"ord", 0x02A5D} ,
+ {"order", 0x02134} ,
+ {"orderof", 0x02134} ,
+ {"ordf", 0x000AA} ,
+ {"ordm", 0x000BA} ,
+ {"origof", 0x022B6} ,
+ {"oror", 0x02A56} ,
+ {"orslope", 0x02A57} ,
+ {"orv", 0x02A5B} ,
+ {"oscr", 0x02134} ,
+ {"oslash", 0x000F8} ,
+ {"osol", 0x02298} ,
+ {"otilde", 0x000F5} ,
+ {"otimes", 0x02297} ,
+ {"otimesas", 0x02A36} ,
+ {"ouml", 0x000F6} ,
+ {"ovbar", 0x0233D} ,
+ {"par", 0x02225} ,
+ {"para", 0x000B6} ,
+ {"parallel", 0x02225} ,
+ {"parsim", 0x02AF3} ,
+ {"parsl", 0x02AFD} ,
+ {"part", 0x02202} ,
+ {"pcy", 0x0043F} ,
+ {"percnt", 0x00025} ,
+ {"period", 0x0002E} ,
+ {"permil", 0x02030} ,
+ {"perp", 0x022A5} ,
+ {"pertenk", 0x02031} ,
+ {"pfr", 0x1D52D} ,
+ {"phi", 0x003D5} ,
+ {"phiv", 0x003C6} ,
+ {"phmmat", 0x02133} ,
+ {"phone", 0x0260E} ,
+ {"pi", 0x003C0} ,
+ {"pitchfork", 0x022D4} ,
+ {"piv", 0x003D6} ,
+ {"planck", 0x0210F} ,
+ {"planckh", 0x0210E} ,
+ {"plankv", 0x0210F} ,
+ {"plus", 0x0002B} ,
+ {"plusacir", 0x02A23} ,
+ {"plusb", 0x0229E} ,
+ {"pluscir", 0x02A22} ,
+ {"plusdo", 0x02214} ,
+ {"plusdu", 0x02A25} ,
+ {"pluse", 0x02A72} ,
+ {"plusmn", 0x000B1} ,
+ {"plussim", 0x02A26} ,
+ {"plustwo", 0x02A27} ,
+ {"pm", 0x000B1} ,
+ {"pointint", 0x02A15} ,
+ {"popf", 0x1D561} ,
+ {"pound", 0x000A3} ,
+ {"pr", 0x0227A} ,
+ {"prE", 0x02AB3} ,
+ {"prap", 0x02AB7} ,
+ {"prcue", 0x0227C} ,
+ {"pre", 0x02AAF} ,
+ {"prec", 0x0227A} ,
+ {"precapprox", 0x02AB7} ,
+ {"preccurlyeq", 0x0227C} ,
+ {"preceq", 0x02AAF} ,
+ {"precnapprox", 0x02AB9} ,
+ {"precneqq", 0x02AB5} ,
+ {"precnsim", 0x022E8} ,
+ {"precsim", 0x0227E} ,
+ {"prime", 0x02032} ,
+ {"primes", 0x02119} ,
+ {"prnE", 0x02AB5} ,
+ {"prnap", 0x02AB9} ,
+ {"prnsim", 0x022E8} ,
+ {"prod", 0x0220F} ,
+ {"profalar", 0x0232E} ,
+ {"profline", 0x02312} ,
+ {"profsurf", 0x02313} ,
+ {"prop", 0x0221D} ,
+ {"propto", 0x0221D} ,
+ {"prsim", 0x0227E} ,
+ {"prurel", 0x022B0} ,
+ {"pscr", 0x1D4C5} ,
+ {"psi", 0x003C8} ,
+ {"puncsp", 0x02008} ,
+ {"qfr", 0x1D52E} ,
+ {"qint", 0x02A0C} ,
+ {"qopf", 0x1D562} ,
+ {"qprime", 0x02057} ,
+ {"qscr", 0x1D4C6} ,
+ {"quaternions", 0x0210D} ,
+ {"quatint", 0x02A16} ,
+ {"quest", 0x0003F} ,
+ {"questeq", 0x0225F} ,
+ {"quot", 0x00022} ,
+ {"rAarr", 0x021DB} ,
+ {"rArr", 0x021D2} ,
+ {"rAtail", 0x0291C} ,
+ {"rBarr", 0x0290F} ,
+ {"rHar", 0x02964} ,
+ {"race", 0x029DA} ,
+ {"racute", 0x00155} ,
+ {"radic", 0x0221A} ,
+ {"raemptyv", 0x029B3} ,
+ {"rang", 0x0232A} ,
+ {"rangd", 0x02992} ,
+ {"range", 0x029A5} ,
+ {"rangle", 0x0232A} ,
+ {"raquo", 0x000BB} ,
+ {"rarr", 0x02192} ,
+ {"rarrap", 0x02975} ,
+ {"rarrb", 0x021E5} ,
+ {"rarrbfs", 0x02920} ,
+ {"rarrc", 0x02933} ,
+ {"rarrfs", 0x0291E} ,
+ {"rarrhk", 0x021AA} ,
+ {"rarrlp", 0x021AC} ,
+ {"rarrpl", 0x02945} ,
+ {"rarrsim", 0x02974} ,
+ {"rarrtl", 0x021A3} ,
+ {"rarrw", 0x0219D} ,
+ {"ratail", 0x0291A} ,
+ {"ratio", 0x02236} ,
+ {"rationals", 0x0211A} ,
+ {"rbarr", 0x0290D} ,
+ {"rbbrk", 0x03015} ,
+ {"rbrace", 0x0007D} ,
+ {"rbrack", 0x0005D} ,
+ {"rbrke", 0x0298C} ,
+ {"rbrksld", 0x0298E} ,
+ {"rbrkslu", 0x02990} ,
+ {"rcaron", 0x00159} ,
+ {"rcedil", 0x00157} ,
+ {"rceil", 0x02309} ,
+ {"rcub", 0x0007D} ,
+ {"rcy", 0x00440} ,
+ {"rdca", 0x02937} ,
+ {"rdldhar", 0x02969} ,
+ {"rdquo", 0x0201D} ,
+ {"rdquor", 0x0201D} ,
+ {"rdsh", 0x021B3} ,
+ {"real", 0x0211C} ,
+ {"realine", 0x0211B} ,
+ {"realpart", 0x0211C} ,
+ {"reals", 0x0211D} ,
+ {"rect", 0x025AD} ,
+ {"reg", 0x000AE} ,
+ {"rfisht", 0x0297D} ,
+ {"rfloor", 0x0230B} ,
+ {"rfr", 0x1D52F} ,
+ {"rhard", 0x021C1} ,
+ {"rharu", 0x021C0} ,
+ {"rharul", 0x0296C} ,
+ {"rho", 0x003C1} ,
+ {"rhov", 0x003F1} ,
+ {"rightarrow", 0x02192} ,
+ {"rightarrowtail", 0x021A3} ,
+ {"rightharpoondown", 0x021C1} ,
+ {"rightharpoonup", 0x021C0} ,
+ {"rightleftarrows", 0x021C4} ,
+ {"rightleftharpoons", 0x021CC} ,
+ {"rightrightarrows", 0x021C9} ,
+ {"rightsquigarrow", 0x0219D} ,
+ {"rightthreetimes", 0x022CC} ,
+ {"ring", 0x002DA} ,
+ {"risingdotseq", 0x02253} ,
+ {"rlarr", 0x021C4} ,
+ {"rlhar", 0x021CC} ,
+ {"rmoust", 0x023B1} ,
+ {"rmoustache", 0x023B1} ,
+ {"rnmid", 0x02AEE} ,
+ {"roang", 0x03019} ,
+ {"roarr", 0x021FE} ,
+ {"robrk", 0x0301B} ,
+ {"ropar", 0x02986} ,
+ {"ropf", 0x1D563} ,
+ {"roplus", 0x02A2E} ,
+ {"rotimes", 0x02A35} ,
+ {"rpar", 0x00029} ,
+ {"rpargt", 0x02994} ,
+ {"rppolint", 0x02A12} ,
+ {"rrarr", 0x021C9} ,
+ {"rscr", 0x1D4C7} ,
+ {"rsh", 0x021B1} ,
+ {"rsqb", 0x0005D} ,
+ {"rsquo", 0x02019} ,
+ {"rsquor", 0x02019} ,
+ {"rthree", 0x022CC} ,
+ {"rtimes", 0x022CA} ,
+ {"rtri", 0x025B9} ,
+ {"rtrie", 0x022B5} ,
+ {"rtrif", 0x025B8} ,
+ {"rtriltri", 0x029CE} ,
+ {"ruluhar", 0x02968} ,
+ {"rx", 0x0211E} ,
+ {"sacute", 0x0015B} ,
+ {"sc", 0x0227B} ,
+ {"scE", 0x02AB4} ,
+ {"scap", 0x02AB8} ,
+ {"scaron", 0x00161} ,
+ {"sccue", 0x0227D} ,
+ {"sce", 0x02AB0} ,
+ {"scedil", 0x0015F} ,
+ {"scirc", 0x0015D} ,
+ {"scnE", 0x02AB6} ,
+ {"scnap", 0x02ABA} ,
+ {"scnsim", 0x022E9} ,
+ {"scpolint", 0x02A13} ,
+ {"scsim", 0x0227F} ,
+ {"scy", 0x00441} ,
+ {"sdot", 0x022C5} ,
+ {"sdotb", 0x022A1} ,
+ {"sdote", 0x02A66} ,
+ {"seArr", 0x021D8} ,
+ {"searhk", 0x02925} ,
+ {"searr", 0x02198} ,
+ {"searrow", 0x02198} ,
+ {"sect", 0x000A7} ,
+ {"semi", 0x0003B} ,
+ {"seswar", 0x02929} ,
+ {"setminus", 0x02216} ,
+ {"setmn", 0x02216} ,
+ {"sext", 0x02736} ,
+ {"sfr", 0x1D530} ,
+ {"sfrown", 0x02322} ,
+ {"sharp", 0x0266F} ,
+ {"shchcy", 0x00449} ,
+ {"shcy", 0x00448} ,
+ {"shortmid", 0x02223} ,
+ {"shortparallel", 0x02225} ,
+ {"shy", 0x000AD} ,
+ {"sigma", 0x003C3} ,
+ {"sigmav", 0x003C2} ,
+ {"sim", 0x0223C} ,
+ {"simdot", 0x02A6A} ,
+ {"sime", 0x02243} ,
+ {"simeq", 0x02243} ,
+ {"simg", 0x02A9E} ,
+ {"simgE", 0x02AA0} ,
+ {"siml", 0x02A9D} ,
+ {"simlE", 0x02A9F} ,
+ {"simne", 0x02246} ,
+ {"simplus", 0x02A24} ,
+ {"simrarr", 0x02972} ,
+ {"slarr", 0x02190} ,
+ {"smallsetminus", 0x02216} ,
+ {"smashp", 0x02A33} ,
+ {"smeparsl", 0x029E4} ,
+ {"smid", 0x02223} ,
+ {"smile", 0x02323} ,
+ {"smt", 0x02AAA} ,
+ {"smte", 0x02AAC} ,
+ {"softcy", 0x0044C} ,
+ {"sol", 0x0002F} ,
+ {"solb", 0x029C4} ,
+ {"solbar", 0x0233F} ,
+ {"sopf", 0x1D564} ,
+ {"spades", 0x02660} ,
+ {"spadesuit", 0x02660} ,
+ {"spar", 0x02225} ,
+ {"sqcap", 0x02293} ,
+ {"sqcup", 0x02294} ,
+ {"sqsub", 0x0228F} ,
+ {"sqsube", 0x02291} ,
+ {"sqsubset", 0x0228F} ,
+ {"sqsubseteq", 0x02291} ,
+ {"sqsup", 0x02290} ,
+ {"sqsupe", 0x02292} ,
+ {"sqsupset", 0x02290} ,
+ {"sqsupseteq", 0x02292} ,
+ {"squ", 0x025A1} ,
+ {"square", 0x025A1} ,
+ {"squarf", 0x025AA} ,
+ {"squf", 0x025AA} ,
+ {"srarr", 0x02192} ,
+ {"sscr", 0x1D4C8} ,
+ {"ssetmn", 0x02216} ,
+ {"ssmile", 0x02323} ,
+ {"sstarf", 0x022C6} ,
+ {"star", 0x02606} ,
+ {"starf", 0x02605} ,
+ {"straightepsilon", 0x003F5} ,
+ {"straightphi", 0x003D5} ,
+ {"strns", 0x000AF} ,
+ {"sub", 0x02282} ,
+ {"subE", 0x02AC5} ,
+ {"subdot", 0x02ABD} ,
+ {"sube", 0x02286} ,
+ {"subedot", 0x02AC3} ,
+ {"submult", 0x02AC1} ,
+ {"subnE", 0x02ACB} ,
+ {"subne", 0x0228A} ,
+ {"subplus", 0x02ABF} ,
+ {"subrarr", 0x02979} ,
+ {"subset", 0x02282} ,
+ {"subseteq", 0x02286} ,
+ {"subseteqq", 0x02AC5} ,
+ {"subsetneq", 0x0228A} ,
+ {"subsetneqq", 0x02ACB} ,
+ {"subsim", 0x02AC7} ,
+ {"subsub", 0x02AD5} ,
+ {"subsup", 0x02AD3} ,
+ {"succ", 0x0227B} ,
+ {"succapprox", 0x02AB8} ,
+ {"succcurlyeq", 0x0227D} ,
+ {"succeq", 0x02AB0} ,
+ {"succnapprox", 0x02ABA} ,
+ {"succneqq", 0x02AB6} ,
+ {"succnsim", 0x022E9} ,
+ {"succsim", 0x0227F} ,
+ {"sum", 0x02211} ,
+ {"sung", 0x0266A} ,
+ {"sup", 0x02283} ,
+ {"sup1", 0x000B9} ,
+ {"sup2", 0x000B2} ,
+ {"sup3", 0x000B3} ,
+ {"supE", 0x02AC6} ,
+ {"supdot", 0x02ABE} ,
+ {"supdsub", 0x02AD8} ,
+ {"supe", 0x02287} ,
+ {"supedot", 0x02AC4} ,
+ {"suphsub", 0x02AD7} ,
+ {"suplarr", 0x0297B} ,
+ {"supmult", 0x02AC2} ,
+ {"supnE", 0x02ACC} ,
+ {"supne", 0x0228B} ,
+ {"supplus", 0x02AC0} ,
+ {"supset", 0x02283} ,
+ {"supseteq", 0x02287} ,
+ {"supseteqq", 0x02AC6} ,
+ {"supsetneq", 0x0228B} ,
+ {"supsetneqq", 0x02ACC} ,
+ {"supsim", 0x02AC8} ,
+ {"supsub", 0x02AD4} ,
+ {"supsup", 0x02AD6} ,
+ {"swArr", 0x021D9} ,
+ {"swarhk", 0x02926} ,
+ {"swarr", 0x02199} ,
+ {"swarrow", 0x02199} ,
+ {"swnwar", 0x0292A} ,
+ {"szlig", 0x000DF} ,
+ {"target", 0x02316} ,
+ {"tau", 0x003C4} ,
+ {"tbrk", 0x023B4} ,
+ {"tcaron", 0x00165} ,
+ {"tcedil", 0x00163} ,
+ {"tcy", 0x00442} ,
+ {"tdot", 0x020DB} ,
+ {"telrec", 0x02315} ,
+ {"tfr", 0x1D531} ,
+ {"there4", 0x02234} ,
+ {"therefore", 0x02234} ,
+ {"theta", 0x003B8} ,
+ {"thetav", 0x003D1} ,
+ {"thickapprox", 0x02248} ,
+ {"thicksim", 0x0223C} ,
+ {"thinsp", 0x02009} ,
+ {"thkap", 0x02248} ,
+ {"thksim", 0x0223C} ,
+ {"thorn", 0x000FE} ,
+ {"tilde", 0x002DC} ,
+ {"times", 0x000D7} ,
+ {"timesb", 0x022A0} ,
+ {"timesbar", 0x02A31} ,
+ {"timesd", 0x02A30} ,
+ {"tint", 0x0222D} ,
+ {"toea", 0x02928} ,
+ {"top", 0x022A4} ,
+ {"topbot", 0x02336} ,
+ {"topcir", 0x02AF1} ,
+ {"topf", 0x1D565} ,
+ {"topfork", 0x02ADA} ,
+ {"tosa", 0x02929} ,
+ {"tprime", 0x02034} ,
+ {"trade", 0x02122} ,
+ {"triangle", 0x025B5} ,
+ {"triangledown", 0x025BF} ,
+ {"triangleleft", 0x025C3} ,
+ {"trianglelefteq", 0x022B4} ,
+ {"triangleq", 0x0225C} ,
+ {"triangleright", 0x025B9} ,
+ {"trianglerighteq", 0x022B5} ,
+ {"tridot", 0x025EC} ,
+ {"trie", 0x0225C} ,
+ {"triminus", 0x02A3A} ,
+ {"triplus", 0x02A39} ,
+ {"trisb", 0x029CD} ,
+ {"tritime", 0x02A3B} ,
+ {"trpezium", 0x0FFFD} ,
+ {"tscr", 0x1D4C9} ,
+ {"tscy", 0x00446} ,
+ {"tshcy", 0x0045B} ,
+ {"tstrok", 0x00167} ,
+ {"twixt", 0x0226C} ,
+ {"twoheadleftarrow", 0x0219E} ,
+ {"twoheadrightarrow", 0x021A0} ,
+ {"uArr", 0x021D1} ,
+ {"uHar", 0x02963} ,
+ {"uacute", 0x000FA} ,
+ {"uarr", 0x02191} ,
+ {"ubrcy", 0x0045E} ,
+ {"ubreve", 0x0016D} ,
+ {"ucirc", 0x000FB} ,
+ {"ucy", 0x00443} ,
+ {"udarr", 0x021C5} ,
+ {"udblac", 0x00171} ,
+ {"udhar", 0x0296E} ,
+ {"ufisht", 0x0297E} ,
+ {"ufr", 0x1D532} ,
+ {"ugrave", 0x000F9} ,
+ {"uharl", 0x021BF} ,
+ {"uharr", 0x021BE} ,
+ {"uhblk", 0x02580} ,
+ {"ulcorn", 0x0231C} ,
+ {"ulcorner", 0x0231C} ,
+ {"ulcrop", 0x0230F} ,
+ {"ultri", 0x025F8} ,
+ {"umacr", 0x0016B} ,
+ {"uml", 0x000A8} ,
+ {"uogon", 0x00173} ,
+ {"uopf", 0x1D566} ,
+ {"uparrow", 0x02191} ,
+ {"updownarrow", 0x02195} ,
+ {"upharpoonleft", 0x021BF} ,
+ {"upharpoonright", 0x021BE} ,
+ {"uplus", 0x0228E} ,
+ {"upsi", 0x003C5} ,
+ {"upsilon", 0x003C5} ,
+ {"upuparrows", 0x021C8} ,
+ {"urcorn", 0x0231D} ,
+ {"urcorner", 0x0231D} ,
+ {"urcrop", 0x0230E} ,
+ {"uring", 0x0016F} ,
+ {"urtri", 0x025F9} ,
+ {"uscr", 0x1D4CA} ,
+ {"utdot", 0x022F0} ,
+ {"utilde", 0x00169} ,
+ {"utri", 0x025B5} ,
+ {"utrif", 0x025B4} ,
+ {"uuarr", 0x021C8} ,
+ {"uuml", 0x000FC} ,
+ {"uwangle", 0x029A7} ,
+ {"vArr", 0x021D5} ,
+ {"vBar", 0x02AE8} ,
+ {"vBarv", 0x02AE9} ,
+ {"vDash", 0x022A8} ,
+ {"vangrt", 0x0299C} ,
+ {"varepsilon", 0x003B5} ,
+ {"varkappa", 0x003F0} ,
+ {"varnothing", 0x02205} ,
+ {"varphi", 0x003C6} ,
+ {"varpi", 0x003D6} ,
+ {"varpropto", 0x0221D} ,
+ {"varr", 0x02195} ,
+ {"varrho", 0x003F1} ,
+ {"varsigma", 0x003C2} ,
+ {"vartheta", 0x003D1} ,
+ {"vartriangleleft", 0x022B2} ,
+ {"vartriangleright", 0x022B3} ,
+ {"vcy", 0x00432} ,
+ {"vdash", 0x022A2} ,
+ {"vee", 0x02228} ,
+ {"veebar", 0x022BB} ,
+ {"veeeq", 0x0225A} ,
+ {"vellip", 0x022EE} ,
+ {"verbar", 0x0007C} ,
+ {"vert", 0x0007C} ,
+ {"vfr", 0x1D533} ,
+ {"vltri", 0x022B2} ,
+ {"vopf", 0x1D567} ,
+ {"vprop", 0x0221D} ,
+ {"vrtri", 0x022B3} ,
+ {"vscr", 0x1D4CB} ,
+ {"vzigzag", 0x0299A} ,
+ {"wcirc", 0x00175} ,
+ {"wedbar", 0x02A5F} ,
+ {"wedge", 0x02227} ,
+ {"wedgeq", 0x02259} ,
+ {"weierp", 0x02118} ,
+ {"wfr", 0x1D534} ,
+ {"wopf", 0x1D568} ,
+ {"wp", 0x02118} ,
+ {"wr", 0x02240} ,
+ {"wreath", 0x02240} ,
+ {"wscr", 0x1D4CC} ,
+ {"xcap", 0x022C2} ,
+ {"xcirc", 0x025EF} ,
+ {"xcup", 0x022C3} ,
+ {"xdtri", 0x025BD} ,
+ {"xfr", 0x1D535} ,
+ {"xhArr", 0x027FA} ,
+ {"xharr", 0x027F7} ,
+ {"xi", 0x003BE} ,
+ {"xlArr", 0x027F8} ,
+ {"xlarr", 0x027F5} ,
+ {"xmap", 0x027FC} ,
+ {"xnis", 0x022FB} ,
+ {"xodot", 0x02A00} ,
+ {"xopf", 0x1D569} ,
+ {"xoplus", 0x02A01} ,
+ {"xotime", 0x02A02} ,
+ {"xrArr", 0x027F9} ,
+ {"xrarr", 0x027F6} ,
+ {"xscr", 0x1D4CD} ,
+ {"xsqcup", 0x02A06} ,
+ {"xuplus", 0x02A04} ,
+ {"xutri", 0x025B3} ,
+ {"xvee", 0x022C1} ,
+ {"xwedge", 0x022C0} ,
+ {"yacute", 0x000FD} ,
+ {"yacy", 0x0044F} ,
+ {"ycirc", 0x00177} ,
+ {"ycy", 0x0044B} ,
+ {"yen", 0x000A5} ,
+ {"yfr", 0x1D536} ,
+ {"yicy", 0x00457} ,
+ {"yopf", 0x1D56A} ,
+ {"yscr", 0x1D4CE} ,
+ {"yucy", 0x0044E} ,
+ {"yuml", 0x000FF} ,
+ {"zacute", 0x0017A} ,
+ {"zcaron", 0x0017E} ,
+ {"zcy", 0x00437} ,
+ {"zdot", 0x0017C} ,
+ {"zeetrf", 0x02128} ,
+ {"zeta", 0x003B6} ,
+ {"zfr", 0x1D537} ,
+ {"zhcy", 0x00436} ,
+ {"zigrarr", 0x021DD} ,
+ {"zopf", 0x1D56B} ,
+ {"zscr", 0x1D4CF}
+};
+
+// Needed since sizeof is a macro and we cannot be used until size is known
+int entityMap::size()
+{
+ return sizeof( entities ) / sizeof( entityMap );
+}
+
+KFORMULA_NAMESPACE_END
+
diff --git a/lib/kformula/entities.h b/lib/kformula/entities.h
new file mode 100644
index 00000000..38a5a0e8
--- /dev/null
+++ b/lib/kformula/entities.h
@@ -0,0 +1,49 @@
+//
+// Created: Tue Aug 29 16:20:33 2006
+// by: bynames.py
+// from: byalpha.html
+//
+// WARNING! All changes made in this file will be lost!
+
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+
+#ifndef ENTITIES_H
+#define ENTITIES_H
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+struct entityMap {
+ static int size();
+ int operator<( const char* right ) const {
+ return strcmp( name, right ) < 0;
+ }
+ const char* name;
+ const uint unicode;
+};
+
+extern const entityMap entities[];
+
+KFORMULA_NAMESPACE_END
+
+#endif // ENTITIES_H
+
diff --git a/lib/kformula/errorelement.cc b/lib/kformula/errorelement.cc
new file mode 100644
index 00000000..f6141c4f
--- /dev/null
+++ b/lib/kformula/errorelement.cc
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qpainter.h>
+
+#include "errorelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+ErrorElement::ErrorElement( BasicElement* parent ) : SequenceElement( parent ) {
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void ErrorElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+
+ painter.fillRect( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y() ),
+ context.layoutUnitToPixelX( getWidth() ),
+ context.layoutUnitToPixelY( getHeight() ),
+ context.getErrorColor() );
+ inherited::draw( painter, r, context, tstyle, istyle, style, parentOrigin );
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/errorelement.h b/lib/kformula/errorelement.h
new file mode 100644
index 00000000..fa3b1e76
--- /dev/null
+++ b/lib/kformula/errorelement.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef ERRORELEMENT_H
+#define ERRORELEMENT_H
+
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class ErrorElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+ ErrorElement( BasicElement* parent = 0 );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+private:
+ virtual QString getElementName() const { return "merror"; }
+
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // ERRORELEMENT_H
diff --git a/lib/kformula/fonts/Arev.ttf b/lib/kformula/fonts/Arev.ttf
new file mode 100644
index 00000000..80ae5e82
--- /dev/null
+++ b/lib/kformula/fonts/Arev.ttf
Binary files differ
diff --git a/lib/kformula/fonts/ArevBI.ttf b/lib/kformula/fonts/ArevBI.ttf
new file mode 100644
index 00000000..bbec526a
--- /dev/null
+++ b/lib/kformula/fonts/ArevBI.ttf
Binary files differ
diff --git a/lib/kformula/fonts/ArevBd.ttf b/lib/kformula/fonts/ArevBd.ttf
new file mode 100644
index 00000000..481154ff
--- /dev/null
+++ b/lib/kformula/fonts/ArevBd.ttf
Binary files differ
diff --git a/lib/kformula/fonts/ArevIt.ttf b/lib/kformula/fonts/ArevIt.ttf
new file mode 100644
index 00000000..7501028f
--- /dev/null
+++ b/lib/kformula/fonts/ArevIt.ttf
Binary files differ
diff --git a/lib/kformula/fonts/LICENSE.AREV b/lib/kformula/fonts/LICENSE.AREV
new file mode 100644
index 00000000..8e56d5be
--- /dev/null
+++ b/lib/kformula/fonts/LICENSE.AREV
@@ -0,0 +1,47 @@
+ Modifications to the Bitstream Vera fonts.
+
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and
+associated documentation files (the "Font Software"), to reproduce
+and distribute the modifications to the Bitstream Vera Font Software,
+including without limitation the rights to use, copy, merge, publish,
+distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Tavmjong Bah" or the word "Arev".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the
+"Tavmjong Bah Arev" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the name of Tavmjong Bah shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Font Software without prior written authorization
+from Tavmjong Bah. For further information, contact: tavmjong @ free
+. fr.
+
diff --git a/lib/kformula/fonts/LICENSE.BAKOMA b/lib/kformula/fonts/LICENSE.BAKOMA
new file mode 100644
index 00000000..801e20cd
--- /dev/null
+++ b/lib/kformula/fonts/LICENSE.BAKOMA
@@ -0,0 +1,40 @@
+
+ BaKoMa Fonts Licence
+ --------------------
+
+ This licence covers two font packs (known as BaKoMa Fonts Colelction,
+ which is available at `CTAN:fonts/cm/ps-type1/bakoma/'):
+
+ 1) BaKoMa-CM (1.1/12-Nov-94)
+ Computer Modern Fonts in PostScript Type 1 and TrueType font formats.
+
+ 2) BaKoMa-AMS (1.2/19-Jan-95)
+ AMS TeX fonts in PostScript Type 1 and TrueType font formats.
+
+ Copyright (C) 1994, 1995, Basil K. Malyshev. All Rights Reserved.
+
+ Permission to copy and distribute these fonts for any purpose is
+ hereby granted without fee, provided that the above copyright notice,
+ author statement and this permission notice appear in all copies of
+ these fonts and related documentation.
+
+ Permission to modify and distribute modified fonts for any purpose is
+ hereby granted without fee, provided that the copyright notice,
+ author statement, this permission notice and location of original
+ fonts (http://www.ctan.org/tex-archive/fonts/cm/ps-type1/bakoma)
+ appear in all copies of modified fonts and related documentation.
+
+ Permission to use these fonts (embedding into PostScript, PDF, SVG
+ and printing by using any software) is hereby granted without fee.
+ It is not required to provide any notices about using these fonts.
+
+ Basil K. Malyshev
+ INSTITUTE FOR HIGH ENERGY PHYSICS
+ IHEP, OMVT
+ Moscow Region
+ 142281 PROTVINO
+ RUSSIA
+
+ E-Mail: bakoma@mail.ru
+ or malyshev@mail.ihep.ru
+
diff --git a/lib/kformula/fonts/LICENSE.BITSTREAM b/lib/kformula/fonts/LICENSE.BITSTREAM
new file mode 100644
index 00000000..4a5c136b
--- /dev/null
+++ b/lib/kformula/fonts/LICENSE.BITSTREAM
@@ -0,0 +1,42 @@
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a
+trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license (“Fonts”) and associated
+documentation files (the “Font Software”), to reproduce and distribute the
+Font Software, including without limitation the rights to use, copy, merge,
+publish, distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright and trademark notices and this permission notice shall be
+included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and
+additional glyphs or characters may be added to the Fonts, only if the fonts
+are renamed to names not containing either the words “Bitstream” or the
+word “Vera”.
+
+This License becomes null and void to the extent applicable to Fonts or Font
+Software that has been modified and is distributed under the “Bitstream Vera”
+names.
+
+The Font Software may be sold as part of a larger software package but no
+copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY
+GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
+INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
+SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome Foundation,
+and Bitstream Inc., shall not be used in advertising or otherwise to promote
+the sale, use or other dealings in this Font Software without prior written
+authorization from the Gnome Foundation or Bitstream Inc., respectively. For
+further information, contact: fonts at gnome dot org.
diff --git a/lib/kformula/fonts/Makefile.am b/lib/kformula/fonts/Makefile.am
new file mode 100644
index 00000000..a84b9e8d
--- /dev/null
+++ b/lib/kformula/fonts/Makefile.am
@@ -0,0 +1,11 @@
+fontdir = $(prefix)/share/apps/kformula/fonts
+font_DATA = cmex10.ttf Arev.ttf ArevIt.ttf ArevBd.ttf ArevBI.ttf
+
+EXTRA_DIST = $(font_DATA) README LICENSE.BAKOMA LICENSE.BITSTREAM LICENCE.AREV
+
+# This uses -hook instead of -local so that it is run after fonts are installed
+install-data-hook:
+ -mkfontscale $(DESTDIR)$(fontdir)
+ -mkfontdir $(DESTDIR)$(fontdir)
+
+
diff --git a/lib/kformula/fonts/README b/lib/kformula/fonts/README
new file mode 100644
index 00000000..8667f9e3
--- /dev/null
+++ b/lib/kformula/fonts/README
@@ -0,0 +1,10 @@
+This directory includes the fonts packaged with KFormula.
+
+From BaKoMa fonts cmex.ttf is included. Its license is included in
+LICENSE.BAKOMA. It's site at CTAN is:
+http://www.ctan.org/tex-archive/fonts/cm/ps-type1/bakoma/
+
+Arev fonts are also included. These fonts are derived from Bitstream Vera
+fonts and so both Bitstream Vera's license (included in LICENSE.BITSTREAM) and
+Arev license (included in LICENSE.AREV) apply. Arev fonts' homepage is:
+http://tavmjong.free.fr/FONTS/ \ No newline at end of file
diff --git a/lib/kformula/fonts/cmex10.ttf b/lib/kformula/fonts/cmex10.ttf
new file mode 100644
index 00000000..e4b468dc
--- /dev/null
+++ b/lib/kformula/fonts/cmex10.ttf
Binary files differ
diff --git a/lib/kformula/fontstyle.cc b/lib/kformula/fontstyle.cc
new file mode 100644
index 00000000..3287120c
--- /dev/null
+++ b/lib/kformula/fontstyle.cc
@@ -0,0 +1,891 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qpainter.h>
+#include <qpen.h>
+#include <qfontdatabase.h>
+#include <qapplication.h>
+
+#include <kstaticdeleter.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kio/netaccess.h>
+#include <kio/job.h>
+#include <kmessagebox.h>
+
+#include "fontstyle.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+#include "unicodetable.cc"
+
+bool FontStyle::m_installed = false;
+
+bool FontStyle::init( ContextStyle* style, bool install )
+{
+ if (!m_installed && install)
+ installFonts();
+ m_symbolTable.init( style->getMathFont() );
+
+ return true;
+}
+
+// Cache the family list from QFontDatabase after fixing it up (no foundry, lowercase)
+class FontList {
+public:
+ FontList() {
+ QFontDatabase db;
+ const QStringList lst = db.families();
+ for ( QStringList::const_iterator it = lst.begin(), end = lst.end() ; it != end ; ++it ) {
+ const QString name = *it;
+ int i = name.find('[');
+ QString family = name;
+ // Remove foundry
+ if ( i > -1 ) {
+ const int li = name.findRev(']');
+ if (i < li) {
+ if (name[i - 1] == ' ')
+ i--;
+ family = name.left(i);
+ }
+ }
+ m_fontNames.append( family.lower() );
+ }
+ }
+ bool hasFont( const QString& fontName ) const {
+ return m_fontNames.find( fontName ) != m_fontNames.end();
+ }
+ QStringList m_fontNames;
+};
+static FontList* s_fontList = 0;
+static KStaticDeleter<FontList> s_fontList_sd;
+
+void FontStyle::testFont( QStringList& missing, const QString& fontName ) {
+ if ( !s_fontList )
+ s_fontList_sd.setObject( s_fontList, new FontList() );
+ if ( !s_fontList->hasFont( fontName ) ) {
+ kdWarning(39001) << "Font '" << fontName << "' not found" << endl;
+ missing.append( fontName );
+ }
+}
+
+
+QStringList FontStyle::missingFonts( bool install )
+{
+ if (!m_installed && install)
+ installFonts();
+
+ QStringList missing = missingFontsInternal();
+ return missing;
+}
+
+QStringList FontStyle::missingFontsInternal()
+{
+ QStringList missing;
+
+ testFont( missing, "cmex10" );
+ testFont( missing, "arev sans");
+
+ return missing;
+}
+
+void FontStyle::installFonts()
+{
+ if (m_installed)
+ return;
+ QStringList missing = missingFontsInternal();
+ if (!missing.isEmpty())
+ {
+ QStringList urlList;
+ for (QStringList::iterator it = missing.begin(); it != missing.end(); ++it)
+ {
+ if ( *it == "arev sans" ) {
+ if (!KIO::NetAccess::exists("fonts:/Personal/Arev.ttf", true, NULL))
+ urlList.append(locate("data", "kformula/fonts/Arev.ttf"));
+ if (!KIO::NetAccess::exists("fonts:/Personal/ArevIt.ttf", true, NULL))
+ urlList.append(locate("data", "kformula/fonts/ArevIt.ttf"));
+ if (!KIO::NetAccess::exists("fonts:/Personal/ArevBd.ttf", true, NULL))
+ urlList.append(locate("data", "kformula/fonts/ArevBd.ttf"));
+ if (!KIO::NetAccess::exists("fonts:/Personal/ArevBI.ttf", true, NULL))
+ urlList.append(locate("data", "kformula/fonts/ArevBI.ttf"));
+ }
+ else {
+ if (!KIO::NetAccess::exists("fonts:/Personal/" + *it + ".ttf", true, NULL))
+ urlList.append(locate("data", "kformula/fonts/" + *it + ".ttf"));
+ }
+ }
+ KIO::copy(urlList, "fonts:/Personal/", false);
+ KMessageBox::information(qApp->mainWidget(),
+ i18n("Some fonts have been installed to assure that symbols in formulas are properly visualized. You must restart the application in order so that changes take effect"));
+ }
+ m_installed = true;
+}
+
+Artwork* FontStyle::createArtwork( SymbolType type ) const
+{
+ return new Artwork( type );
+}
+
+// We claim that all chars come from the same font.
+// It's up to the font tables to ensure this.
+const QChar leftRoundBracket[] = {
+ 0x30, // uppercorner
+ 0x40, // lowercorner
+ 0x42 // line
+};
+const QChar leftSquareBracket[] = {
+ 0x32, // uppercorner
+ 0x34, // lowercorner
+ 0x36 // line
+};
+const QChar leftCurlyBracket[] = {
+ 0x38, // uppercorner
+ 0x3A, // lowercorner
+ 0x3E, // line
+ 0x3C // middle
+};
+
+const QChar leftLineBracket[] = {
+ 0x36, // line
+ 0x36, // line
+ 0x36 // line
+};
+const QChar rightLineBracket[] = {
+ 0x37, // line
+ 0x37, // line
+ 0x37 // line
+};
+
+const QChar rightRoundBracket[] = {
+ 0x31, // uppercorner
+ 0x41, // lowercorner
+ 0x43 // line
+};
+const QChar rightSquareBracket[] = {
+ 0x33, // uppercorner
+ 0x35, // lowercorner
+ 0x37 // line
+};
+const QChar rightCurlyBracket[] = {
+ 0x39, // uppercorner
+ 0x3B, // lowercorner
+ 0x3E, // line
+ 0x3D // middle
+};
+
+
+static const char cmex_LeftSquareBracket = 163;
+static const char cmex_RightSquareBracket = 164;
+static const char cmex_LeftCurlyBracket = 169;
+static const char cmex_RightCurlyBracket = 170;
+static const char cmex_LeftCornerBracket = 173;
+static const char cmex_RightCornerBracket = 174;
+static const char cmex_LeftRoundBracket = 161;
+static const char cmex_RightRoundBracket = 162;
+static const char cmex_SlashBracket = 177;
+static const char cmex_BackSlashBracket = 178;
+//static const char cmex_LeftLineBracket = 0x4b;
+//static const char cmex_RightLineBracket = 0x4b;
+
+// use the big symbols here
+static const char cmex_Int = 90;
+static const char cmex_Sum = 88;
+static const char cmex_Prod = 89;
+
+
+// cmex is a special font with symbols in four sizes.
+static short cmex_nextchar( short ch )
+{
+ switch ( ch ) {
+ case 161: return 179;
+ case 162: return 180;
+ case 163: return 104;
+ case 164: return 105;
+ case 169: return 110;
+ case 170: return 111;
+ case 165: return 106;
+ case 166: return 107;
+ case 167: return 108;
+ case 168: return 109;
+ case 173: return 68;
+ case 174: return 69;
+ case 177: return 46;
+ case 178: return 47;
+
+ case 179: return 181;
+ case 180: return 182;
+ case 104: return 183;
+ case 105: return 184;
+ case 110: return 189;
+ case 111: return 190;
+ case 106: return 185;
+ case 107: return 186;
+ case 108: return 187;
+ case 109: return 188;
+ case 68: return 191;
+ case 69: return 192;
+ case 46: return 193;
+ case 47: return 194;
+
+ case 181: return 195;
+ case 182: return 33;
+ case 183: return 34;
+ case 184: return 35;
+ case 189: return 40;
+ case 190: return 41;
+ case 185: return 36;
+ case 186: return 37;
+ case 187: return 38;
+ case 188: return 39;
+ case 191: return 42;
+ case 192: return 43;
+ case 193: return 44;
+ case 194: return 45;
+ }
+ return 0;
+}
+
+bool Artwork::calcCMDelimiterSize( const ContextStyle& context,
+ uchar c,
+ luPt fontSize,
+ luPt parentSize )
+{
+ QFont f( "cmex10" );
+ f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
+ QFontMetrics fm( f );
+
+ for ( char i=1; c != 0; ++i ) {
+ LuPixelRect bound = fm.boundingRect( c );
+
+ luPt height = context.ptToLayoutUnitPt( bound.height() );
+ if ( height >= parentSize ) {
+ luPt width = context.ptToLayoutUnitPt( fm.width( c ) );
+ luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
+
+ cmChar = c;
+
+ setHeight( height );
+ setWidth( width );
+ setBaseline( baseline );
+
+ return true;
+ }
+ c = cmex_nextchar( c );
+ }
+
+ // Build it up from pieces.
+ return false;
+}
+
+
+void Artwork::calcLargest( const ContextStyle& context,
+ uchar c, luPt fontSize )
+{
+ QFont f( "cmex10" );
+ f.setPointSizeFloat( context.layoutUnitPtToPt( fontSize ) );
+ QFontMetrics fm( f );
+
+ cmChar = c;
+ for ( ;; ) {
+ c = cmex_nextchar( c );
+ if ( c == 0 ) {
+ break;
+ }
+ cmChar = c;
+ }
+
+ LuPixelRect bound = fm.boundingRect( cmChar );
+
+ luPt height = context.ptToLayoutUnitPt( bound.height() );
+ luPt width = context.ptToLayoutUnitPt( fm.width( cmChar ) );
+ luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
+
+ setHeight( height );
+ setWidth( width );
+ setBaseline( baseline );
+}
+
+
+void Artwork::drawCMDelimiter( QPainter& painter, const ContextStyle& style,
+ luPixel x, luPixel y,
+ luPt height )
+{
+ QFont f( "cmex10" );
+ f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );
+
+ painter.setFont( f );
+ painter.drawText( style.layoutUnitToPixelX( x ),
+ style.layoutUnitToPixelY( y + getBaseline() ),
+ QString( QChar( cmChar ) ) );
+
+ // Debug
+#if 0
+ QFontMetrics fm( f );
+ LuPixelRect bound = fm.boundingRect( cmChar );
+ painter.setBrush(Qt::NoBrush);
+ painter.setPen(Qt::green);
+ painter.drawRect( style.layoutUnitToPixelX( x ),
+ style.layoutUnitToPixelY( y ),
+ fm.width( cmChar ),
+ bound.height() );
+#endif
+}
+
+
+Artwork::Artwork(SymbolType t)
+ : baseline( -1 ), type(t)
+{
+}
+
+
+void Artwork::calcSizes( const ContextStyle& style,
+ ContextStyle::TextStyle tstyle,
+ double factor,
+ luPt parentSize )
+{
+ setBaseline( -1 );
+ cmChar = -1;
+ luPt mySize = style.getAdjustedSize( tstyle, factor );
+ switch (getType()) {
+ case LeftSquareBracket:
+ if ( calcCMDelimiterSize( style, cmex_LeftSquareBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcRoundBracket( style, leftSquareBracket, parentSize, mySize );
+ break;
+ case RightSquareBracket:
+ if ( calcCMDelimiterSize( style, cmex_RightSquareBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcRoundBracket( style, rightSquareBracket, parentSize, mySize );
+ break;
+ case LeftLineBracket:
+ calcRoundBracket( style, leftLineBracket, parentSize, mySize );
+ setWidth( getWidth()/2 );
+ break;
+ case RightLineBracket:
+ calcRoundBracket( style, rightLineBracket, parentSize, mySize );
+ setWidth( getWidth()/2 );
+ break;
+ case SlashBracket:
+ if ( calcCMDelimiterSize( style, cmex_SlashBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcLargest( style, cmex_SlashBracket, mySize );
+ break;
+ case BackSlashBracket:
+ if ( calcCMDelimiterSize( style, cmex_BackSlashBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcLargest( style, cmex_BackSlashBracket, mySize );
+ break;
+ case LeftCornerBracket:
+ if ( calcCMDelimiterSize( style, cmex_LeftCornerBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcLargest( style, cmex_LeftCornerBracket, mySize );
+ break;
+ case RightCornerBracket:
+ if ( calcCMDelimiterSize( style, cmex_RightCornerBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcLargest( style, cmex_RightCornerBracket, mySize );
+ break;
+ case LeftRoundBracket:
+ if ( calcCMDelimiterSize( style, cmex_LeftRoundBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcRoundBracket( style, leftRoundBracket, parentSize, mySize );
+ break;
+ case RightRoundBracket:
+ if ( calcCMDelimiterSize( style, cmex_RightRoundBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcRoundBracket( style, rightRoundBracket, parentSize, mySize );
+ break;
+ case EmptyBracket:
+ setHeight(parentSize);
+ //setWidth(style.getEmptyRectWidth());
+ setWidth(0);
+ break;
+ case LeftCurlyBracket:
+ if ( calcCMDelimiterSize( style, cmex_LeftCurlyBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcCurlyBracket( style, leftCurlyBracket, parentSize, mySize );
+ break;
+ case RightCurlyBracket:
+ if ( calcCMDelimiterSize( style, cmex_RightCurlyBracket,
+ mySize, parentSize ) ) {
+ return;
+ }
+ calcCurlyBracket( style, rightCurlyBracket, parentSize, mySize );
+ break;
+ case Integral:
+ calcCharSize( style, style.getBracketFont(), mySize, cmex_Int );
+ break;
+ case Sum:
+ calcCharSize( style, style.getBracketFont(), mySize, cmex_Sum );
+ break;
+ case Product:
+ calcCharSize( style, style.getBracketFont(), mySize, cmex_Prod );
+ break;
+ }
+}
+
+void Artwork::calcSizes( const ContextStyle& style,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ luPt mySize = style.getAdjustedSize( tstyle, factor );
+ switch (type) {
+ case LeftSquareBracket:
+ calcCharSize(style, mySize, leftSquareBracketChar);
+ break;
+ case RightSquareBracket:
+ calcCharSize(style, mySize, rightSquareBracketChar);
+ break;
+ case LeftLineBracket:
+ case RightLineBracket:
+ calcCharSize(style, mySize, verticalLineChar);
+ break;
+ case SlashBracket:
+ calcCharSize(style, mySize, slashChar);
+ break;
+ case BackSlashBracket:
+ calcCharSize(style, mySize, backSlashChar);
+ break;
+ case LeftCornerBracket:
+ calcCharSize(style, mySize, leftAngleBracketChar);
+ break;
+ case RightCornerBracket:
+ calcCharSize(style, mySize, rightAngleBracketChar);
+ break;
+ case LeftRoundBracket:
+ calcCharSize(style, mySize, leftParenthesisChar);
+ break;
+ case RightRoundBracket:
+ calcCharSize(style, mySize, rightParenthesisChar);
+ break;
+ case EmptyBracket:
+ //calcCharSize(style, mySize, spaceChar);
+ setHeight(0);
+ //setWidth(style.getEmptyRectWidth());
+ setWidth(0);
+ break;
+ case LeftCurlyBracket:
+ calcCharSize(style, mySize, leftCurlyBracketChar);
+ break;
+ case RightCurlyBracket:
+ calcCharSize(style, mySize, rightCurlyBracketChar);
+ break;
+ case Integral:
+ case Sum:
+ case Product:
+ break;
+ }
+}
+
+
+void Artwork::draw(QPainter& painter, const LuPixelRect& /*r*/,
+ const ContextStyle& context, ContextStyle::TextStyle tstyle,
+ StyleAttributes& style, const LuPixelPoint& parentOrigin)
+{
+ luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
+ luPixel myX = parentOrigin.x() + getX();
+ luPixel myY = parentOrigin.y() + getY();
+ /*
+ if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
+ return;
+ */
+
+ painter.setPen(context.getDefaultColor());
+
+ switch (type) {
+ case LeftSquareBracket:
+ drawCharacter(painter, context, myX, myY, mySize, leftSquareBracketChar);
+ break;
+ case RightSquareBracket:
+ drawCharacter(painter, context, myX, myY, mySize, rightSquareBracketChar);
+ break;
+ case LeftCurlyBracket:
+ drawCharacter(painter, context, myX, myY, mySize, leftCurlyBracketChar);
+ break;
+ case RightCurlyBracket:
+ drawCharacter(painter, context, myX, myY, mySize, rightCurlyBracketChar);
+ break;
+ case LeftLineBracket:
+ case RightLineBracket:
+ drawCharacter(painter, context, myX, myY, mySize, verticalLineChar);
+ break;
+ case SlashBracket:
+ drawCharacter(painter, context, myX, myY, mySize, slashChar);
+ break;
+ case BackSlashBracket:
+ drawCharacter(painter, context, myX, myY, mySize, backSlashChar);
+ break;
+ case LeftCornerBracket:
+ drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
+ break;
+ case RightCornerBracket:
+ drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
+ break;
+ case LeftRoundBracket:
+ drawCharacter(painter, context, myX, myY, mySize, leftParenthesisChar);
+ break;
+ case RightRoundBracket:
+ drawCharacter(painter, context, myX, myY, mySize, rightParenthesisChar);
+ break;
+ case EmptyBracket:
+ break;
+ case Integral:
+ case Sum:
+ case Product:
+ break;
+ }
+}
+
+void Artwork::draw(QPainter& painter, const LuPixelRect& ,
+ const ContextStyle& context, ContextStyle::TextStyle tstyle,
+ StyleAttributes& style, luPt , const LuPixelPoint& origin)
+{
+ luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
+ luPixel myX = origin.x() + getX();
+ luPixel myY = origin.y() + getY();
+ /*
+ if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
+ return;
+ */
+
+ painter.setPen(context.getDefaultColor());
+
+ switch (getType()) {
+ case LeftSquareBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else {
+ drawBigRoundBracket( painter, context, leftSquareBracket, myX, myY, mySize );
+ }
+ break;
+ case RightSquareBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else {
+ drawBigRoundBracket( painter, context, rightSquareBracket, myX, myY, mySize );
+ }
+ break;
+ case LeftCurlyBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else {
+ drawBigCurlyBracket( painter, context, leftCurlyBracket, myX, myY, mySize );
+ }
+ break;
+ case RightCurlyBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else {
+ drawBigCurlyBracket( painter, context, rightCurlyBracket, myX, myY, mySize );
+ }
+ break;
+ case LeftLineBracket: {
+ luPixel halfWidth = getWidth()/2;
+ drawBigRoundBracket( painter, context, leftLineBracket,
+ myX-halfWidth, myY, mySize );
+ }
+ break;
+ case RightLineBracket: {
+ luPixel halfWidth = getWidth()/2;
+ drawBigRoundBracket( painter, context, rightLineBracket,
+ myX-halfWidth, myY, mySize );
+ }
+ break;
+ case SlashBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ break;
+ case BackSlashBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ break;
+ case LeftCornerBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else drawCharacter(painter, context, myX, myY, mySize, leftAngleBracketChar);
+ break;
+ case RightCornerBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else drawCharacter(painter, context, myX, myY, mySize, rightAngleBracketChar);
+ break;
+ case LeftRoundBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else {
+ drawBigRoundBracket( painter, context, leftRoundBracket, myX, myY, mySize );
+ }
+ break;
+ case RightRoundBracket:
+ if ( cmChar != -1 ) {
+ drawCMDelimiter( painter, context, myX, myY, mySize );
+ }
+ else {
+ drawBigRoundBracket( painter, context, rightRoundBracket, myX, myY, mySize );
+ }
+ break;
+ case EmptyBracket:
+ break;
+ case Integral:
+ drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Int);
+ break;
+ case Sum:
+ drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Sum);
+ break;
+ case Product:
+ drawCharacter(painter, context, QFont( "cmex10" ), myX, myY, mySize, cmex_Prod);
+ break;
+ }
+
+ // debug
+// painter.setBrush(Qt::NoBrush);
+// painter.setPen(Qt::green);
+// painter.drawRect( context.layoutUnitToPixelX( myX ),
+// context.layoutUnitToPixelY( myY ),
+// context.layoutUnitToPixelX( getWidth() ),
+// context.layoutUnitToPixelY( getHeight() ) );
+}
+
+void Artwork::calcCharSize( const ContextStyle& style, luPt height, QChar ch )
+{
+ calcCharSize( style, style.getMathFont(), height, ch );
+}
+
+
+void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
+ luPixel x, luPixel y,
+ luPt height, QChar ch )
+{
+ drawCharacter( painter, style, style.getMathFont(), x, y, height, ch );
+}
+
+
+void Artwork::calcCharSize( const ContextStyle& style, QFont f,
+ luPt height, QChar c )
+{
+ f.setPointSizeFloat( style.layoutUnitPtToPt( height ) );
+ //f.setPointSize( height );
+ QFontMetrics fm(f);
+ setWidth( style.ptToLayoutUnitPt( fm.width( c ) ) );
+ LuPixelRect bound = fm.boundingRect( c );
+ setHeight( style.ptToLayoutUnitPt( bound.height() ) );
+ setBaseline( style.ptToLayoutUnitPt( -bound.top() ) );
+}
+
+
+void Artwork::drawCharacter( QPainter& painter, const ContextStyle& style,
+ QFont f,
+ luPixel x, luPixel y, luPt height, uchar c )
+{
+ f.setPointSizeFloat( style.layoutUnitToFontSize( height, false ) );
+
+ painter.setFont( f );
+ painter.drawText( style.layoutUnitToPixelX( x ),
+ style.layoutUnitToPixelY( y+getBaseline() ),
+ QString( QChar( c ) ) );
+}
+
+
+void Artwork::calcRoundBracket( const ContextStyle& style, const QChar chars[],
+ luPt height, luPt charHeight )
+{
+ uchar uppercorner = chars[0];
+ uchar lowercorner = chars[1];
+ //uchar line = style.symbolTable().character( chars[2] );
+
+ QFont f = style.getBracketFont();
+ f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
+ QFontMetrics fm( f );
+ LuPtRect upperBound = fm.boundingRect( uppercorner );
+ LuPtRect lowerBound = fm.boundingRect( lowercorner );
+ //LuPtRect lineBound = fm.boundingRect( line );
+
+ setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
+ luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+lowerBound.height() );
+ //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
+
+ //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
+ setHeight( QMAX( edgeHeight, height ) );
+}
+
+void Artwork::drawBigRoundBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
+ luPixel x, luPixel y, luPt charHeight )
+{
+ uchar uppercorner = chars[0];
+ uchar lowercorner = chars[1];
+ uchar line = chars[2];
+
+ QFont f = style.getBracketFont();
+ f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
+ p.setFont(f);
+
+ QFontMetrics fm(f);
+ QRect upperBound = fm.boundingRect(uppercorner);
+ QRect lowerBound = fm.boundingRect(lowercorner);
+ QRect lineBound = fm.boundingRect(line);
+
+ pixel ptX = style.layoutUnitToPixelX( x );
+ pixel ptY = style.layoutUnitToPixelY( y );
+ pixel height = style.layoutUnitToPixelY( getHeight() );
+
+// p.setPen( Qt::red );
+// //p.drawRect( ptX, ptY, upperBound.width(), upperBound.height() + lowerBound.height() );
+// p.drawRect( ptX, ptY, style.layoutUnitToPixelX( getWidth() ),
+// style.layoutUnitToPixelY( getHeight() ) );
+
+// p.setPen( Qt::black );
+ p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
+ p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
+ QString( QChar( lowercorner ) ) );
+
+ // for printing
+ //pt safety = lineBound.height() / 10.0;
+ pixel safety = 0;
+
+ pixel gap = height - upperBound.height() - lowerBound.height();
+ pixel lineHeight = lineBound.height() - safety;
+ int lineCount = qRound( static_cast<double>( gap ) / lineHeight );
+ pixel start = upperBound.height()-lineBound.top() - safety;
+
+ for (int i = 0; i < lineCount; i++) {
+ p.drawText( ptX, ptY+start+i*lineHeight, QString(QChar(line)));
+ }
+ pixel remaining = gap - lineCount*lineHeight;
+ pixel dist = ( lineHeight - remaining ) / 2;
+ p.drawText( ptX, ptY+height-upperBound.height()+dist-lineBound.height()-lineBound.top(),
+ QString( QChar( line ) ) );
+}
+
+void Artwork::calcCurlyBracket( const ContextStyle& style, const QChar chars[],
+ luPt height, luPt charHeight )
+{
+ uchar uppercorner = chars[0];
+ uchar lowercorner = chars[1];
+ //uchar line = style.symbolTable().character( chars[2] );
+ uchar middle = chars[3];
+
+ QFont f = style.getBracketFont();
+ f.setPointSizeFloat( style.layoutUnitPtToPt( charHeight ) );
+ QFontMetrics fm( f );
+ LuPtRect upperBound = fm.boundingRect( uppercorner );
+ LuPtRect lowerBound = fm.boundingRect( lowercorner );
+ //LuPtRect lineBound = fm.boundingRect( line );
+ LuPtRect middleBound = fm.boundingRect( middle );
+
+ setWidth( style.ptToLayoutUnitPt( fm.width( QChar( uppercorner ) ) ) );
+ luPt edgeHeight = style.ptToLayoutUnitPt( upperBound.height()+
+ lowerBound.height()+
+ middleBound.height() );
+ //luPt lineHeight = style.ptToLayoutUnitPt( lineBound.height() );
+
+ //setHeight( edgeHeight + ( ( height-edgeHeight-1 ) / lineHeight + 1 ) * lineHeight );
+ setHeight( QMAX( edgeHeight, height ) );
+}
+
+void Artwork::drawBigCurlyBracket( QPainter& p, const ContextStyle& style, const QChar chars[],
+ luPixel x, luPixel y, luPt charHeight )
+{
+ //QFont f = style.getSymbolFont();
+ QFont f = style.getBracketFont();
+ f.setPointSizeFloat( style.layoutUnitToFontSize( charHeight, false ) );
+ p.setFont(f);
+
+ uchar uppercorner = chars[0];
+ uchar lowercorner = chars[1];
+ uchar line = chars[2];
+ uchar middle = chars[3];
+
+ QFontMetrics fm(p.fontMetrics());
+ QRect upperBound = fm.boundingRect(uppercorner);
+ QRect lowerBound = fm.boundingRect(lowercorner);
+ QRect middleBound = fm.boundingRect(middle);
+ QRect lineBound = fm.boundingRect(line);
+
+ pixel ptX = style.layoutUnitToPixelX( x );
+ pixel ptY = style.layoutUnitToPixelY( y );
+ pixel height = style.layoutUnitToPixelY( getHeight() );
+
+ //p.setPen(Qt::gray);
+ //p.drawRect(x, y, upperBound.width() + offset, height);
+
+ p.drawText( ptX, ptY-upperBound.top(), QString( QChar( uppercorner ) ) );
+ p.drawText( ptX, ptY+(height-middleBound.height())/2-middleBound.top(),
+ QString( QChar( middle ) ) );
+ p.drawText( ptX, ptY+height-lowerBound.top()-lowerBound.height(),
+ QString( QChar( lowercorner ) ) );
+
+ // for printing
+ // If the world was perfect and the urw-symbol font correct
+ // this could be 0.
+ //lu safety = lineBound.height() / 10;
+ pixel safety = 0;
+
+ pixel lineHeight = lineBound.height() - safety;
+ pixel gap = height/2 - upperBound.height() - middleBound.height() / 2;
+
+ if (gap > 0) {
+ QString ch = QString(QChar(line));
+ int lineCount = qRound( gap / lineHeight ) + 1;
+
+ pixel start = (height - middleBound.height()) / 2 + safety;
+ for (int i = 0; i < lineCount; i++) {
+ p.drawText( ptX, ptY-lineBound.top()+QMAX( start-(i+1)*lineHeight,
+ upperBound.width() ),
+ ch );
+ }
+
+ start = (height + middleBound.height()) / 2 - safety;
+ for (int i = 0; i < lineCount; i++) {
+ p.drawText( ptX, ptY-lineBound.top()+QMIN( start+i*lineHeight,
+ height-upperBound.width()-lineBound.height() ),
+ ch );
+ }
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/fontstyle.h b/lib/kformula/fontstyle.h
new file mode 100644
index 00000000..52105821
--- /dev/null
+++ b/lib/kformula/fontstyle.h
@@ -0,0 +1,193 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef FONTSTYLE_H
+#define FONTSTYLE_H
+
+#include <qstring.h>
+#include <qfont.h>
+
+#include "contextstyle.h"
+#include "kformuladefs.h"
+#include "symboltable.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+class Artwork;
+class SymbolTable;
+
+
+/**
+ * Base class for all supported font styles.
+ */
+class FontStyle {
+public:
+ ~FontStyle() {}
+
+ /**
+ * lazy init support. Needs to be run before anything else.
+ * @param install if true fonts may be installed if needed
+ */
+ bool init( ContextStyle* context, bool install = true );
+
+ /// the table for ordinary symbols (those that have a unicode value)
+ const SymbolTable* symbolTable() const { return &m_symbolTable; }
+ SymbolTable* symbolTable() { return &m_symbolTable; }
+
+ Artwork* createArtwork(SymbolType type = EmptyBracket) const;
+
+ static QStringList missingFonts( bool install = true );
+
+ static bool m_installed;
+
+ static void testFont( QStringList& missing, const QString& fontName );
+
+private:
+
+ static QStringList missingFontsInternal();
+ static void installFonts();
+
+ SymbolTable m_symbolTable;
+
+};
+
+const QChar spaceChar = 0x0020;
+const QChar leftParenthesisChar = 0x0028;
+const QChar rightParenthesisChar = 0x0029;
+const QChar leftSquareBracketChar = 0x005B;
+const QChar rightSquareBracketChar = 0x005D;
+const QChar leftCurlyBracketChar = 0x007B;
+const QChar verticalLineChar = 0x007C;
+const QChar rightCurlyBracketChar = 0x007D;
+const QChar leftAngleBracketChar = 0x2329;
+const QChar rightAngleBracketChar = 0x232A;
+const QChar slashChar = 0x002F;
+const QChar backSlashChar = 0x005C;
+const QChar integralChar = 0x222B;
+const QChar summationChar = 0x2211;
+const QChar productChar = 0x220F;
+const QChar applyFunctionChar = 0x2061;
+const QChar invisibleTimes = 0x2062;
+const QChar invisibleComma = 0x2063;
+
+extern const QChar leftRoundBracket[];
+extern const QChar leftSquareBracket[];
+extern const QChar leftCurlyBracket[];
+
+extern const QChar leftLineBracket[];
+extern const QChar rightLineBracket[];
+
+extern const QChar rightRoundBracket[];
+extern const QChar rightSquareBracket[];
+extern const QChar rightCurlyBracket[];
+
+/*
+ * A piece of art that may be used by any element.
+ */
+class Artwork {
+public:
+
+ Artwork(SymbolType type = EmptyBracket);
+ virtual ~Artwork() {}
+
+ virtual void calcSizes( const ContextStyle& style,
+ ContextStyle::TextStyle tstyle,
+ double factor,
+ luPt parentSize );
+ virtual void calcSizes( const ContextStyle& style,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ StyleAttributes& style,
+ luPt parentSize, const LuPixelPoint& origin );
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ luPixel getWidth() const { return size.width(); }
+ luPixel getHeight() const { return size.height(); }
+
+ void setWidth( luPixel width ) { size.setWidth(width); }
+ void setHeight( luPixel height ) { size.setHeight(height); }
+
+ luPixel getBaseline() const { return baseline; }
+ void setBaseline( luPixel line ) { baseline = line; }
+
+ luPixel getX() const { return point.x(); }
+ luPixel getY() const { return point.y(); }
+
+ void setX( luPixel x ) { point.setX( x ); }
+ void setY( luPixel y ) { point.setY( y ); }
+
+ SymbolType getType() const { return type; }
+ void setType(SymbolType t) { type = t; }
+
+ virtual bool isNormalChar() const { return getBaseline() != -1 && ( cmChar == -1 ); }
+
+ virtual double slant() const { return 0; }
+
+protected:
+
+ void calcCharSize( const ContextStyle& style, luPt height, QChar ch );
+ void drawCharacter( QPainter& painter, const ContextStyle& style,
+ luPixel x, luPixel y, luPt height, QChar ch );
+
+ void calcCharSize( const ContextStyle& style, QFont f, luPt height, QChar c );
+ void drawCharacter( QPainter& painter, const ContextStyle& style,
+ QFont f,
+ luPixel x, luPixel y, luPt height, uchar c );
+
+ void calcRoundBracket( const ContextStyle& style, const QChar chars[], luPt height, luPt charHeight );
+ void calcCurlyBracket( const ContextStyle& style, const QChar chars[], luPt height, luPt charHeight );
+
+ void drawBigRoundBracket( QPainter& p, const ContextStyle& style, const QChar chars[], luPixel x, luPixel y, luPt charHeight );
+ void drawBigCurlyBracket( QPainter& p, const ContextStyle& style, const QChar chars[], luPixel x, luPixel y, luPt charHeight );
+
+private:
+
+ LuPixelSize size;
+ LuPixelPoint point;
+
+ /**
+ * Used if we are a character.
+ */
+ luPixel baseline;
+
+ SymbolType type;
+
+ bool calcCMDelimiterSize( const ContextStyle& context, uchar c,
+ luPt fontSize, luPt parentSize );
+ void calcLargest( const ContextStyle& context, uchar c, luPt fontSize );
+ void drawCMDelimiter( QPainter& painter, const ContextStyle& style,
+ luPixel x, luPixel y, luPt height );
+
+ short cmChar;
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif
diff --git a/lib/kformula/formulacursor.cc b/lib/kformula/formulacursor.cc
new file mode 100644
index 00000000..83b46e45
--- /dev/null
+++ b/lib/kformula/formulacursor.cc
@@ -0,0 +1,746 @@
+/* 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 <qpainter.h>
+
+#include <kdebug.h>
+#include <assert.h>
+
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "indexelement.h"
+#include "matrixelement.h"
+#include "rootelement.h"
+#include "sequenceelement.h"
+#include "symbolelement.h"
+#include "textelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+FormulaCursor::FormulaCursor(FormulaElement* element)
+ : selectionFlag(false), linearMovement(false),
+ hasChangedFlag(true), readOnly(false)
+{
+ //setTo(element, 0);
+ element->goInside( this );
+}
+
+void FormulaCursor::setTo(BasicElement* element, uint cursor, int mark)
+{
+ hasChangedFlag = true;
+ current = element;
+ cursorPos = cursor;
+ if ((mark == -1) && selectionFlag) {
+ return;
+ }
+ if (mark != -1) {
+ setSelection(true);
+ }
+ markPos = mark;
+}
+
+
+void FormulaCursor::setPos(uint pos)
+{
+ hasChangedFlag = true;
+ cursorPos = pos;
+}
+
+void FormulaCursor::setMark(int mark)
+{
+ hasChangedFlag = true;
+ markPos = mark;
+}
+
+void FormulaCursor::calcCursorSize( const ContextStyle& context, bool smallCursor )
+{
+ // We only draw the cursor if its normalized.
+ SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
+
+ if (sequence != 0) {
+ sequence->calcCursorSize( context, this, smallCursor );
+ }
+}
+
+void FormulaCursor::draw( QPainter& painter, const ContextStyle& context,
+ StyleAttributes& style, bool smallCursor, bool activeCursor )
+{
+ //if (readOnly && !isSelection())
+ //return;
+
+ // We only draw the cursor if its normalized.
+ SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
+
+ if (sequence != 0) {
+ sequence->drawCursor( painter, context, style, this, smallCursor, activeCursor );
+ }
+}
+
+
+void FormulaCursor::handleSelectState(int flag)
+{
+ if (flag & SelectMovement) {
+ if (!isSelection()) {
+ setMark(getPos());
+ setSelection(true);
+ }
+ }
+ else {
+ setSelection(false);
+ }
+}
+
+void FormulaCursor::moveLeft(int flag)
+{
+ BasicElement* element = getElement();
+ handleSelectState(flag);
+ if (flag & WordMovement) {
+ SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
+ if (sequence != 0) {
+ sequence->moveWordLeft(this);
+ }
+ else {
+ element->moveHome(this);
+ }
+ }
+ else {
+ element->moveLeft(this, element);
+ }
+}
+
+void FormulaCursor::moveRight(int flag)
+{
+ BasicElement* element = getElement();
+ handleSelectState(flag);
+ if (flag & WordMovement) {
+ SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
+ if (sequence != 0) {
+ sequence->moveWordRight(this);
+ }
+ else {
+ element->moveEnd(this);
+ }
+ }
+ else {
+ element->moveRight(this, element);
+ }
+}
+
+void FormulaCursor::moveUp(int flag)
+{
+ BasicElement* element = getElement();
+ handleSelectState(flag);
+ element->moveUp(this, element);
+}
+
+void FormulaCursor::moveDown(int flag)
+{
+ BasicElement* element = getElement();
+ handleSelectState(flag);
+ element->moveDown(this, element);
+}
+
+void FormulaCursor::moveHome(int flag)
+{
+ BasicElement* element = getElement();
+ handleSelectState(flag);
+ if (flag & WordMovement) {
+ element->formula()->moveHome(this);
+ }
+ else {
+ element->moveHome(this);
+ }
+}
+
+void FormulaCursor::moveEnd(int flag)
+{
+ BasicElement* element = getElement();
+ handleSelectState(flag);
+ if (flag & WordMovement) {
+ element->formula()->moveEnd(this);
+ }
+ else {
+ element->moveEnd(this);
+ }
+}
+
+bool FormulaCursor::isHome() const
+{
+ return ( getElement() == getElement()->formula() ) && ( getPos() == 0 );
+}
+
+bool FormulaCursor::isEnd() const
+{
+ return ( getElement() == getElement()->formula() ) &&
+ ( getPos() == normal()->countChildren() );
+}
+
+void FormulaCursor::mousePress( const LuPixelPoint& pos, int flag )
+{
+ FormulaElement* formula = getElement()->formula();
+ formula->goToPos( this, pos );
+ if (flag & SelectMovement) {
+ setSelection(true);
+ if (getMark() == -1) {
+ setMark(getPos());
+ }
+ }
+ else {
+ setSelection(false);
+ setMark(getPos());
+ }
+}
+
+void FormulaCursor::mouseMove( const LuPixelPoint& point, int )
+{
+ setSelection(true);
+ BasicElement* element = getElement();
+ int mark = getMark();
+
+ FormulaElement* formula = getElement()->formula();
+ formula->goToPos( this, point );
+ BasicElement* newElement = getElement();
+ int pos = getPos();
+
+ BasicElement* posChild = 0;
+ BasicElement* markChild = 0;
+ while (element != newElement) {
+ posChild = newElement;
+ newElement = newElement->getParent();
+ if (newElement == 0) {
+ posChild = 0;
+ newElement = getElement();
+ markChild = element;
+ element = element->getParent();
+ }
+ }
+
+ if (dynamic_cast<SequenceElement*>(element) == 0) {
+ element = element->getParent();
+ element->selectChild(this, newElement);
+ }
+ else {
+ if (posChild != 0) {
+ element->selectChild(this, posChild);
+ pos = getPos();
+ }
+ if (markChild != 0) {
+ element->selectChild(this, markChild);
+ mark = getMark();
+ }
+ if (pos == mark) {
+ if ((posChild == 0) && (markChild != 0)) {
+ mark++;
+ }
+ else if ((posChild != 0) && (markChild == 0)) {
+ mark--;
+ }
+ }
+ else if (pos < mark) {
+ if (posChild != 0) {
+ pos--;
+ }
+ }
+ setTo(element, pos, mark);
+ }
+}
+
+void FormulaCursor::mouseRelease( const LuPixelPoint&, int )
+{
+ //mouseSelectionFlag = false;
+}
+
+
+/**
+ * Moves the cursor inside the element. Selection is turned off.
+ */
+void FormulaCursor::goInsideElement(BasicElement* element)
+{
+ element->goInside(this);
+}
+
+
+/**
+ * Moves the cursor to a normal position. That is somewhere
+ * inside a SequenceElement.
+ * You need to call this after each removal because the cursor
+ * might point to some non existing place.
+ */
+void FormulaCursor::normalize(Direction direction)
+{
+ BasicElement* element = getElement();
+ element->normalize(this, direction);
+}
+
+
+/**
+ * Inserts the child at the current position.
+ * Ignores the selection.
+ */
+void FormulaCursor::insert(BasicElement* child, Direction direction)
+{
+ QPtrList<BasicElement> list;
+ list.append(child);
+ insert(list, direction);
+}
+
+void FormulaCursor::insert(QPtrList<BasicElement>& children,
+ Direction direction)
+{
+ assert( !isReadOnly() );
+ BasicElement* element = getElement();
+ element->insert(this, children, direction);
+}
+
+
+/**
+ * Removes the current selected children and returns them.
+ * The cursor needs to be normal (that is be inside a SequenceElement)
+ * for this to have any effect.
+ */
+void FormulaCursor::remove(QPtrList<BasicElement>& children,
+ Direction direction)
+{
+ assert( !isReadOnly() );
+ SequenceElement* sequence = normal();
+ if (sequence != 0) {
+
+ // If there is no child to remove in the sequence
+ // remove the sequence instead.
+ if (sequence->countChildren() == 0) {
+ BasicElement* parent = sequence->getParent();
+ if (parent != 0) {
+ parent->selectChild(this, sequence);
+ parent->remove(this, children, direction);
+ return;
+ }
+ }
+ else {
+ sequence->remove(this, children, direction);
+ }
+ }
+}
+
+
+/**
+ * Replaces the current selection with the supplied element.
+ * The replaced elements become the new element's main child's content.
+ */
+void FormulaCursor::replaceSelectionWith(BasicElement* element,
+ Direction direction)
+{
+ assert( !isReadOnly() );
+ QPtrList<BasicElement> list;
+ // we suppres deletion here to get an error if something
+ // was left in the list.
+ //list.setAutoDelete(true);
+
+ //remove(list, direction);
+ if (isSelection()) {
+ getElement()->remove(this, list, direction);
+ }
+
+ insert(element, direction);
+ SequenceElement* mainChild = element->getMainChild();
+ if (mainChild != 0) {
+ mainChild->goInside(this);
+ insert(list);
+ /*
+ BasicElement* parent = element->getParent();
+ if (direction == beforeCursor) {
+ parent->moveRight(this, element);
+ }
+ else {
+ parent->moveLeft(this, element);
+ }
+ */
+ element->selectChild(this, mainChild);
+ }
+}
+
+
+/**
+ * Replaces the element the cursor points to with its main child's
+ * content.
+ */
+BasicElement* FormulaCursor::replaceByMainChildContent(Direction direction)
+{
+ assert( !isReadOnly() );
+ QPtrList<BasicElement> childrenList;
+ QPtrList<BasicElement> list;
+ BasicElement* element = getElement();
+ SequenceElement* mainChild = element->getMainChild();
+ if ((mainChild != 0) && (mainChild->countChildren() > 0)) {
+ mainChild->selectAllChildren(this);
+ remove(childrenList);
+ }
+ element->getParent()->selectChild(this, element);
+ setSelection(false);
+ remove(list);
+ insert(childrenList, direction);
+ if (list.count() > 0) {
+ return list.take(0);
+ }
+ return 0;
+}
+
+
+/**
+ * Trys to find the element we are the main child of and replace
+ * it with our content.
+ *
+ * This is simply another form of replaceByMainChildContent. You
+ * use this one if the cursor is normalized and inside the main child.
+ */
+BasicElement* FormulaCursor::removeEnclosingElement(Direction direction)
+{
+ assert( !isReadOnly() );
+ BasicElement* parent = getElement()->getParent();
+ if (parent != 0) {
+ if (getElement() == parent->getMainChild()) {
+ parent->selectChild(this, getElement());
+ return replaceByMainChildContent(direction);
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Returns wether the element the cursor points to should be replaced.
+ * Elements are senseless as soon as they only contain a main child.
+ */
+bool FormulaCursor::elementIsSenseless()
+{
+ BasicElement* element = getElement();
+ return element->isSenseless();
+}
+
+
+/**
+ * Returns the child the cursor points to. Depending on the
+ * direction this might be the child before or after the
+ * cursor.
+ *
+ * Might be 0 is there is no such child.
+ */
+BasicElement* FormulaCursor::getActiveChild(Direction direction)
+{
+ return getElement()->getChild(this, direction);
+}
+
+BasicElement* FormulaCursor::getSelectedChild()
+{
+ if (isSelection()) {
+ if ((getSelectionEnd() - getSelectionStart()) > 1) {
+ return 0;
+ }
+ return getActiveChild((getPos() > getMark()) ?
+ beforeCursor :
+ afterCursor);
+ }
+ else {
+ return getActiveChild(beforeCursor);
+ }
+}
+
+
+void FormulaCursor::selectActiveElement()
+{
+ if ( !isSelection() && getPos() > 0 ) {
+ setSelection( true );
+ setMark( getPos() - 1 );
+ }
+}
+
+
+/**
+ * Tells whether we currently point to the given elements
+ * main child and to the place behind its last child.
+ */
+bool FormulaCursor::pointsAfterMainChild(BasicElement* element)
+{
+ if (element != 0) {
+ SequenceElement* mainChild = element->getMainChild();
+ return (getElement() == mainChild) &&
+ ((mainChild->countChildren() == getPos()) || (0 == getPos()));
+ }
+ return false;
+}
+
+
+/**
+ * Returns the IndexElement the cursor is on or 0
+ * if there is non.
+ */
+IndexElement* FormulaCursor::getActiveIndexElement()
+{
+ IndexElement* element = dynamic_cast<IndexElement*>(getSelectedChild());
+
+ if ((element == 0) && !isSelection()) {
+ element = dynamic_cast<IndexElement*>(getElement()->getParent());
+ if (!pointsAfterMainChild(element)) {
+ return 0;
+ }
+ }
+ return element;
+}
+
+
+/**
+ * Returns the RootElement the cursor is on or 0
+ * if there is non.
+ */
+RootElement* FormulaCursor::getActiveRootElement()
+{
+ RootElement* element = dynamic_cast<RootElement*>(getSelectedChild());
+
+ if ((element == 0) && !isSelection()) {
+ element = dynamic_cast<RootElement*>(getElement()->getParent());
+ if (!pointsAfterMainChild(element)) {
+ return 0;
+ }
+ }
+ return element;
+}
+
+
+/**
+ * @returns the SymbolElement the cursor is on or 0
+ * if there is non.
+ */
+SymbolElement* FormulaCursor::getActiveSymbolElement()
+{
+ SymbolElement* element = dynamic_cast<SymbolElement*>(getSelectedChild());
+
+ if ((element == 0) && !isSelection()) {
+ element = dynamic_cast<SymbolElement*>(getElement()->getParent());
+ if (!pointsAfterMainChild(element)) {
+ return 0;
+ }
+ }
+ return element;
+}
+
+/**
+ * @returns the NameSequence the cursor is on or 0
+ * if there is non.
+ */
+NameSequence* FormulaCursor::getActiveNameSequence()
+{
+ NameSequence* element = dynamic_cast<NameSequence*>( getSelectedChild() );
+
+ if ( ( element == 0 ) && !isSelection() ) {
+ element = dynamic_cast<NameSequence*>( getElement() );
+ if ( !pointsAfterMainChild( element ) ) {
+ return 0;
+ }
+ }
+ return element;
+}
+
+/**
+ * @returns the TextElement the cursor is on or 0.
+ */
+TextElement* FormulaCursor::getActiveTextElement()
+{
+ return dynamic_cast<TextElement*>(getSelectedChild());
+}
+
+
+MatrixElement* FormulaCursor::getActiveMatrixElement()
+{
+ MatrixElement* element = dynamic_cast<MatrixElement*>(getSelectedChild());
+
+ if ( ( element != 0 ) && !isSelection() ) {
+ normal()->selectChild( this, element );
+ }
+// if ((element == 0) && !isSelection()) {
+// element = dynamic_cast<MatrixElement*>(getElement()->getParent());
+// if (!pointsAfterMainChild(element)) {
+// return 0;
+// }
+// }
+ return element;
+}
+
+/**
+ * The element is going to leave the formula with and all its children.
+ */
+void FormulaCursor::elementWillVanish(BasicElement* element)
+{
+ BasicElement* child = getElement();
+ if (element && child == element->getParent()) {
+ child->childWillVanish(this, element);
+ return;
+ }
+ while (child != 0) {
+ if (child == element) {
+ // This is meant to catch all cursors that did not
+ // cause the deletion.
+ child->getParent()->moveLeft(this, child);
+ setSelection(false);
+ hasChangedFlag = true;
+ return;
+ }
+ child = child->getParent();
+ }
+}
+
+
+/**
+ * A new formula has been loaded. Our current element has to change.
+ */
+void FormulaCursor::formulaLoaded(FormulaElement* rootElement)
+{
+ //current = rootElement;
+ //setPos(0);
+ rootElement->goInside( this );
+ setMark(-1);
+ setSelection(false);
+}
+
+
+bool FormulaCursor::isReadOnly() const
+{
+ if ( readOnly ) {
+ return true;
+ }
+ const SequenceElement* sequence = normal();
+ if ( sequence != 0 ) {
+ bool ro = sequence->readOnly( this );
+ //kdDebug() << k_funcinfo << "readOnly=" << ro << endl;
+ return ro;
+ }
+ return false;
+}
+
+
+/**
+ * Stores the currently selected elements inside a dom.
+ */
+void FormulaCursor::copy( QDomDocument& doc )
+{
+ if (isSelection()) {
+ SequenceElement* sequence = normal();
+ if (sequence != 0) {
+ QDomElement root = doc.createElementNS( "http://www.w3.org/1998/Math/MathML",
+ "math" );
+ doc.appendChild( root );
+ QDomElement de = doc.createElement( "mrow" );
+ root.appendChild( de );
+ sequence->getChildrenMathMLDom(doc, de, getSelectionStart(), getSelectionEnd());
+ }
+ else {
+ // This must never happen.
+ qFatal("A not normalized cursor is selecting.");
+ }
+ }
+}
+
+/**
+ * Inserts the elements that could be read from the dom into
+ * the list. Returns true on success.
+ */
+bool FormulaCursor::buildElementsFromDom( QDomElement root, QPtrList<BasicElement>& list )
+{
+ assert( !isReadOnly() );
+ SequenceElement* sequence = normal();
+ if (sequence != 0) {
+ QDomElement e = root.firstChild().toElement();
+ if (sequence->buildChildrenFromDom(list, e.firstChild())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Inserts the elements that could be read from the MathML dom into
+ * the list. Returns true on success.
+ */
+bool FormulaCursor::buildElementsFromMathMLDom( QDomElement root, QPtrList<BasicElement>& list )
+{
+ assert( !isReadOnly() );
+ SequenceElement* sequence = normal();
+ if (sequence != 0) {
+ QDomElement e = root.firstChild().toElement();
+ if (sequence->buildChildrenFromMathMLDom(list, e.firstChild())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Creates a new CursorData object that describes the cursor.
+ * It's up to the caller to delete this object.
+ */
+FormulaCursor::CursorData* FormulaCursor::getCursorData()
+{
+ return new CursorData(current, cursorPos, markPos,
+ selectionFlag, linearMovement, readOnly);
+}
+
+
+// Keep in sync with 'setCursorData'
+FormulaCursor& FormulaCursor::operator= (const FormulaCursor& other)
+{
+ current = other.current;
+ cursorPos = other.cursorPos;
+ markPos = other.markPos;
+ selectionFlag = other.selectionFlag;
+ linearMovement = other.linearMovement;
+ readOnly = other.readOnly;
+ hasChangedFlag = true;
+ return *this;
+}
+
+
+/**
+ * Sets the cursor to where the CursorData points to. No checking is done
+ * so you better make sure the point exists.
+ */
+void FormulaCursor::setCursorData(FormulaCursor::CursorData* data)
+{
+ current = data->current;
+ cursorPos = data->cursorPos;
+ markPos = data->markPos;
+ selectionFlag = data->selectionFlag;
+ linearMovement = data->linearMovement;
+ readOnly = data->readOnly;
+ hasChangedFlag = true;
+}
+
+
+/**
+ * Returns the sequence the cursor is in if we are normal. If not returns 0.
+ */
+SequenceElement* FormulaCursor::normal()
+{
+ return dynamic_cast<SequenceElement*>(current);
+}
+
+const SequenceElement* FormulaCursor::normal() const
+{
+ return dynamic_cast<SequenceElement*>(current);
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/formulacursor.h b/lib/kformula/formulacursor.h
new file mode 100644
index 00000000..72cfb178
--- /dev/null
+++ b/lib/kformula/formulacursor.h
@@ -0,0 +1,465 @@
+/* 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.
+*/
+
+#ifndef FORMULACURSOR_H
+#define FORMULACURSOR_H
+
+#include <qstring.h>
+
+#include "basicelement.h"
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class FormulaElement;
+class IndexElement;
+class MatrixElement;
+class NameSequence;
+class RootElement;
+class SymbolElement;
+class TextElement;
+
+
+/**
+ * The selection. This might be a position selection or
+ * an area. Each view will need one FormulaCursor.
+ *
+ * The @ref Container always uses the cursor to operate on
+ * the element tree.
+ *
+ * Note that it is up to the elements to actually move the cursor.
+ * (The cursor has no chance to know how.)
+ */
+class FormulaCursor {
+
+ // Yes, we do have a friend.
+ friend class SequenceElement;
+
+public:
+
+ /**
+ * Creates a cursor and puts is at the beginning
+ * of the formula.
+ *
+ * @param element the formula the cursor point to. This must not be 0.
+ */
+ FormulaCursor(FormulaElement* element);
+
+ FormulaCursor& operator= (const FormulaCursor&);
+
+ // where the cursor and the mark are
+ uint getPos() const { return cursorPos; }
+ int getMark() const { return markPos; }
+
+ /**
+ * Tells whether the cursor has changed since last cleaning.
+ */
+ bool hasChanged() const { return hasChangedFlag; }
+
+ /**
+ * Resets the cursor's change flag. The widget calls this
+ * if it has drawn the cursor.
+ */
+ void clearChangedFlag() { hasChangedFlag = false; }
+
+ /**
+ * Returns wether we are in selection mode.
+ */
+ bool isSelectionMode() const { return selectionFlag; }
+
+ /**
+ * Returns wether there actually is a selection.
+ */
+ bool isSelection() const { return selectionFlag && (getPos() != getMark()); }
+
+ /**
+ * Sets the selection mode.
+ */
+ void setSelection(bool selection) { selectionFlag = selection; hasChangedFlag = true; }
+
+ /**
+ * Calculates the size of the cursor. Needs to be called before
+ * the cursor can be drawn.
+ */
+ void calcCursorSize( const ContextStyle& context, bool smallCursor );
+
+ /**
+ * Draws the cursor at its current position.
+ * The cursor will always be drawn in xor mode.
+ */
+ void draw( QPainter&, const ContextStyle& context, StyleAttributes& style,
+ bool smallCursor, bool activeCursor );
+
+
+ // simple cursor movement.
+
+ void moveLeft(int flag = NormalMovement);
+ void moveRight(int flag = NormalMovement);
+ void moveUp(int flag = NormalMovement);
+ void moveDown(int flag = NormalMovement);
+
+ void moveHome(int flag = NormalMovement);
+ void moveEnd(int flag = NormalMovement);
+
+ /** @returns whether the cursor is at the first position. */
+ bool isHome() const;
+
+ /** @returns whether the cursor is at the last position. */
+ bool isEnd() const;
+
+ // how to travel
+
+ bool getLinearMovement() const { return linearMovement; }
+
+ /**
+ * Sets the cursor in linear mode. This means you can visit every
+ * element just by moving left and right.
+ */
+ void setLinearMovement(bool linear) { linearMovement = linear; }
+
+ /**
+ * Moves the cursor inside the element. Selection is turned off.
+ */
+ void goInsideElement(BasicElement* element);
+
+ // mouse selection
+
+ void mousePress( const LuPixelPoint&, int flags );
+ void mouseMove( const LuPixelPoint&, int flags );
+ void mouseRelease( const LuPixelPoint&, int flags );
+
+ /**
+ * Inserts the child at the current position.
+ * Ignores the selection.
+ */
+ void insert(BasicElement*, Direction = beforeCursor);
+
+ /**
+ * Inserts the listed children at the current position.
+ * Ignores the selection.
+ * The list will be emptied.
+ */
+ void insert(QPtrList<BasicElement>&,
+ Direction = beforeCursor);
+
+ /**
+ * Removes the current selected children and returns them.
+ * The cursor needs to be normal (that is be inside a SequenceElement)
+ * for this to have any effect.
+ */
+ void remove(QPtrList<BasicElement>&,
+ Direction = beforeCursor);
+
+
+ /**
+ * Replaces the current selection with the supplied element.
+ * The replaced elements become the new element's main child's content.
+ */
+ void replaceSelectionWith(BasicElement*,
+ Direction = beforeCursor);
+
+ /**
+ * Replaces the element the cursor points to with its main child's
+ * content.
+ */
+ BasicElement* replaceByMainChildContent(Direction = beforeCursor);
+
+ /**
+ * Trys to find the element we are the main child of and replace
+ * it with our content.
+ *
+ * This is simply another form of replaceByMainChildContent. You
+ * use this one if the cursor is normalized and inside the main child.
+ */
+ BasicElement* removeEnclosingElement(Direction = beforeCursor);
+
+ /**
+ * Returns wether the element the cursor points to should be replaced.
+ * Elements are senseless as soon as they only contain a main child.
+ */
+ bool elementIsSenseless();
+
+
+ // The range that is selected. Makes no sense if there is
+ // no selection.
+
+ int getSelectionStart() const { return QMIN(getPos(), getMark()); }
+ int getSelectionEnd() const { return QMAX(getPos(), getMark()); }
+
+
+ /**
+ * Sets the cursor to a new position.
+ * This gets called from the element that wants
+ * to own the cursor. It is a mistake to call this if you aren't
+ * an element.
+ *
+ * If you provide a mark >= 0 the selection gets turned on.
+ * If there is a selection and you don't provide a mark the
+ * current mark won't change.
+ */
+ void setTo(BasicElement* element, uint cursor, int mark=-1);
+
+ void setPos(uint pos);
+ void setMark(int mark);
+
+
+ /**
+ * The element we are in. In most cases this is a SequenceElement.
+ * There is no way to place a cursor outside a SequenceElement by
+ * normal movement.
+ * But in special cases (e.g. if you remove an index from an
+ * IndexElement) the cursor can be placed to odd places. This is
+ * the reason why you have to normalize the cursor after each
+ * removal.
+ */
+ BasicElement* getElement() { return current; }
+ const BasicElement* getElement() const { return current; }
+
+
+ /**
+ * Moves the cursor to a normal position. That is somewhere
+ * inside a SequenceElement.
+ * You need to call this after each removal because the cursor
+ * might point to some non existing place.
+ */
+ void normalize(Direction direction = beforeCursor);
+
+
+ /**
+ * Returns the sequence the cursor is in if we are normal. If not returns 0.
+ */
+ SequenceElement* normal();
+ const SequenceElement* normal() const;
+
+ /**
+ * Returns the IndexElement the cursor is on or 0
+ * if there is non.
+ */
+ IndexElement* getActiveIndexElement();
+
+ /**
+ * Returns the RootElement the cursor is on or 0
+ * if there is non.
+ */
+ RootElement* getActiveRootElement();
+
+ /**
+ * Returns the SymbolElement the cursor is on or 0
+ * if there is non.
+ */
+ SymbolElement* getActiveSymbolElement();
+
+ /**
+ * @returns the NameSequence the cursor is on or 0
+ * if there is non.
+ */
+ NameSequence* getActiveNameSequence();
+
+ /**
+ * @returns the TextElement the cursor is on or 0.
+ */
+ TextElement* getActiveTextElement();
+
+ /**
+ * @returns the MatrixElement the cursor is on or 0.
+ */
+ MatrixElement* getActiveMatrixElement();
+
+ /**
+ * Selects the element the cursor points to (stands after)
+ * if there is such an element and if there is no selection.
+ */
+ void selectActiveElement();
+
+ /**
+ * Stores the currently selected elements inside a dom.
+ */
+ void copy( QDomDocument& doc );
+
+ /**
+ * Inserts the elements that could be read from the dom into
+ * the list. Returns true on success.
+ */
+ bool buildElementsFromDom( QDomElement root, QPtrList<BasicElement>& list );
+
+ /**
+ * Inserts the elements that could be read from the MathML dom into
+ * the list. Returns true on success.
+ */
+ bool buildElementsFromMathMLDom( QDomElement root, QPtrList<BasicElement>& list );
+
+ // undo/redo support
+
+ /**
+ * A black box that is supposed to contain everything
+ * which is needed to describe a cursor. Only the cursor
+ * itself is allowed to read it.
+ */
+ class CursorData {
+ friend class FormulaCursor;
+ BasicElement* current;
+ uint cursorPos;
+ int markPos;
+ bool selectionFlag;
+ bool linearMovement;
+ bool readOnly;
+
+ CursorData(BasicElement* c,
+ uint pos, int mark, bool selection, bool linear, bool ro)
+ : current(c), cursorPos(pos), markPos(mark),
+ selectionFlag(selection), linearMovement(linear),
+ readOnly(ro) {}
+ };
+
+ /**
+ * Creates a new CursorData object that describes the cursor.
+ * It's up to the caller to delete this object.
+ */
+ CursorData* getCursorData();
+
+ /**
+ * Sets the cursor to where the CursorData points to. No checking is done
+ * so you better make sure the point exists.
+ */
+ void setCursorData(CursorData* data);
+
+ /**
+ * The element is going to leave the formula with and all its children.
+ */
+ void elementWillVanish(BasicElement* element);
+
+ /**
+ * A new formula has been loaded. Our current element has to change.
+ */
+ void formulaLoaded(FormulaElement* rootElement);
+
+ /**
+ * @returns the point inside the formula widget where the cursor is.
+ */
+ const LuPixelPoint& getCursorPoint() const { return cursorPoint; }
+
+ /**
+ * @returns the area the cursor is currently on.
+ */
+ const LuPixelRect& getCursorSize() const { return cursorSize; }
+ void addCursorSize( const LuPixelRect& rect ) { cursorSize |= rect; }
+
+ /**
+ * @returns whether we are allowed to alter the document.
+ */
+ bool isReadOnly() const;
+
+ /**
+ * Puts the widget in read only mode.
+ */
+ void setReadOnly(bool ro) { readOnly = ro; }
+
+private:
+
+ /**
+ * Returns the child the cursor points to. Depending on the
+ * direction this might be the child before or after the
+ * cursor.
+ *
+ * Might be 0 is there is no such child.
+ */
+ BasicElement* getActiveChild(Direction direction);
+
+ /**
+ * Returns the child that is currently selected.
+ *
+ * Might be 0 is there is no such child. e.g. if there are more
+ * than one element selected.
+ */
+ BasicElement* getSelectedChild();
+
+ /**
+ * Tells whether we currently point to the given elements
+ * main child and to the place behind its last child.
+ */
+ bool pointsAfterMainChild(BasicElement*);
+
+ /**
+ * Sets the selection according to the shift key.
+ */
+ void handleSelectState(int flag);
+
+
+ /**
+ * The element the cursor is inside right now.
+ */
+ BasicElement* current;
+
+ /**
+ * The position the cursor in on inside the element.
+ * Might be anything from 0 to current->children->size().
+ *
+ * This is where new elements are put in.
+ */
+ uint cursorPos;
+
+ /**
+ * The position of the mark. If we are in selection mode this
+ * is the other side of the selected area.
+ * Note that the mark always belongs to the same SequenceElement
+ * as the cursor.
+ */
+ int markPos;
+
+ /**
+ * Tells whether there is a selection area.
+ * (This is not equal to (markPos != -1).)
+ */
+ bool selectionFlag;
+
+ /**
+ * Tells whether we want to travel through all elements by
+ * left and right movement.
+ */
+ bool linearMovement;
+
+ /**
+ * The point in the middle of the cursor. Gets updated
+ * each time the cursor is drawn.
+ */
+ LuPixelPoint cursorPoint;
+
+ /**
+ * The area that is covered by the cursor. Gets updated
+ * each time the cursor is drawn.
+ */
+ LuPixelRect cursorSize;
+
+ /**
+ * Tells whether the cursor has been changed. This is set
+ * by any of the setSomething methods. It's used by the
+ * widget the cursor belongs to.
+ */
+ bool hasChangedFlag;
+
+ /**
+ * Whether we are only allowed to read.
+ */
+ bool readOnly;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // FORMULACURSOR_H
diff --git a/lib/kformula/formulaelement.cc b/lib/kformula/formulaelement.cc
new file mode 100644
index 00000000..39349fd1
--- /dev/null
+++ b/lib/kformula/formulaelement.cc
@@ -0,0 +1,336 @@
+/* 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 <qpainter.h>
+
+#include <kdebug.h>
+
+#include "contextstyle.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+FormulaElement::FormulaElement(FormulaDocument* container)
+ : document( container ), baseSize( 20 ), ownBaseSize( false )
+{
+}
+
+
+void FormulaElement::setBaseSize( int size )
+{
+ if ( size > 0 ) {
+ baseSize = size;
+ ownBaseSize = true;
+ }
+ else {
+ ownBaseSize = false;
+ }
+ document->baseSizeChanged( size, ownBaseSize );
+}
+
+
+/**
+ * Returns the element the point is in.
+ */
+BasicElement* FormulaElement::goToPos( FormulaCursor* cursor, const LuPixelPoint& point )
+{
+ bool handled = false;
+ BasicElement* element = inherited::goToPos(cursor, handled, point, LuPixelPoint());
+ if (element == 0) {
+ //if ((point.x() > getWidth()) || (point.y() > getHeight())) {
+ cursor->setTo(this, countChildren());
+ //}
+ return this;
+ }
+ return element;
+}
+
+void FormulaElement::elementRemoval(BasicElement* child)
+{
+ document->elementRemoval(child);
+}
+
+void FormulaElement::changed()
+{
+ document->changed();
+}
+
+void FormulaElement::cursorHasMoved( FormulaCursor* cursor )
+{
+ document->cursorHasMoved( cursor );
+}
+
+void FormulaElement::moveOutLeft( FormulaCursor* cursor )
+{
+ document->moveOutLeft( cursor );
+}
+
+void FormulaElement::moveOutRight( FormulaCursor* cursor )
+{
+ document->moveOutRight( cursor );
+}
+
+void FormulaElement::moveOutBelow( FormulaCursor* cursor )
+{
+ document->moveOutBelow( cursor );
+}
+
+void FormulaElement::moveOutAbove( FormulaCursor* cursor )
+{
+ document->moveOutAbove( cursor );
+}
+
+void FormulaElement::tell( const QString& msg )
+{
+ document->tell( msg );
+}
+
+void FormulaElement::removeFormula( FormulaCursor* cursor )
+{
+ document->removeFormula( cursor );
+}
+
+void FormulaElement::insertFormula( FormulaCursor* cursor )
+{
+ document->insertFormula( cursor );
+}
+
+void FormulaElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ inherited::calcSizes( context, tstyle, istyle, style );
+}
+
+
+void FormulaElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ inherited::draw( painter, r, context, tstyle, istyle, style, parentOrigin );
+}
+
+
+/**
+ * Calculates the formulas sizes and positions.
+ */
+void FormulaElement::calcSizes( ContextStyle& context )
+{
+ //kdDebug( DEBUGID ) << "FormulaElement::calcSizes" << endl;
+ if ( ownBaseSize ) {
+ context.setSizeFactor( static_cast<double>( getBaseSize() )/context.baseSize() );
+ }
+ else {
+ context.setSizeFactor( 1 );
+ }
+ StyleAttributes style;
+ calcSizes( context, context.getBaseTextStyle(), ContextStyle::normal, style );
+}
+
+/**
+ * Draws the whole thing.
+ */
+void FormulaElement::draw( QPainter& painter, const LuPixelRect& r,
+ ContextStyle& context )
+{
+ //kdDebug( DEBUGID ) << "FormulaElement::draw" << endl;
+ if ( ownBaseSize ) {
+ context.setSizeFactor( static_cast<double>( getBaseSize() )/context.baseSize() );
+ }
+ else {
+ context.setSizeFactor( 1 );
+ }
+ StyleAttributes style;
+ draw( painter, r, context, context.getBaseTextStyle(),
+ ContextStyle::normal, style, LuPixelPoint() );
+}
+
+KCommand* FormulaElement::buildCommand( Container* container, Request* request )
+{
+ switch ( *request ) {
+ case req_compactExpression:
+ return 0;
+ default:
+ break;
+ }
+ return inherited::buildCommand( container, request );
+}
+
+const SymbolTable& FormulaElement::getSymbolTable() const
+{
+ return document->getSymbolTable();
+}
+
+
+QDomElement FormulaElement::emptyFormulaElement( QDomDocument& doc )
+{
+ QDomElement element = doc.createElement( getTagName() );
+ /*
+ element.setAttribute( "VERSION", "6" );
+ if ( ownBaseSize ) {
+ element.setAttribute( "BASESIZE", baseSize );
+ }
+ */
+ return element;
+}
+
+KCommand* FormulaElement::input( Container* container, QKeyEvent* event )
+{
+ QChar ch = event->text().at( 0 );
+ if ( !ch.isPrint() ) {
+ int action = event->key();
+ //int state = event->state();
+ //MoveFlag flag = movementFlag(state);
+
+ switch ( action ) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter: {
+ FormulaCursor* cursor = container->activeCursor();
+ insertFormula( cursor );
+ return 0;
+ }
+ }
+ }
+ return inherited::input( container, event );
+}
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void FormulaElement::writeDom(QDomElement element)
+{
+ inherited::writeDom(element);
+ element.setAttribute( "VERSION", "6" );
+ if ( ownBaseSize ) {
+ element.setAttribute( "BASESIZE", baseSize );
+ }
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool FormulaElement::readAttributesFromDom(QDomElement element)
+{
+ if (!inherited::readAttributesFromDom(element)) {
+ return false;
+ }
+ int version = -1;
+ QString versionStr = element.attribute( "VERSION" );
+ if ( !versionStr.isNull() ) {
+ version = versionStr.toInt();
+ }
+ if ( version > -1 ) {
+ // Version 6 added the MultilineElement (TabMarker)
+ // Version 5 added under- and overlines
+ if ( version < 4 ) {
+ convertNames( element );
+ }
+ }
+ QString baseSizeStr = element.attribute( "BASESIZE" );
+ if ( !baseSizeStr.isNull() ) {
+ ownBaseSize = true;
+ baseSize = baseSizeStr.toInt();
+ }
+ else {
+ ownBaseSize = false;
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool FormulaElement::readContentFromDom(QDomNode& node)
+{
+ return inherited::readContentFromDom(node);
+}
+
+void FormulaElement::convertNames( QDomNode node )
+{
+ if ( node.isElement() && ( node.nodeName().upper() == "TEXT" ) ) {
+ QDomNamedNodeMap attr = node.attributes();
+ QDomAttr ch = attr.namedItem( "CHAR" ).toAttr();
+ if ( ch.value() == "\\" ) {
+ QDomNode sequence = node.parentNode();
+ QDomDocument doc = sequence.ownerDocument();
+ QDomElement nameseq = doc.createElement( "NAMESEQUENCE" );
+ sequence.replaceChild( nameseq, node );
+
+ bool inName = true;
+ while ( inName ) {
+ inName = false;
+ QDomNode n = nameseq.nextSibling();
+ if ( n.isElement() && ( n.nodeName().upper() == "TEXT" ) ) {
+ attr = n.attributes();
+ ch = attr.namedItem( "CHAR" ).toAttr();
+ if ( ch.value().at( 0 ).isLetter() ) {
+ nameseq.appendChild( sequence.removeChild( n ) );
+ inName = true;
+ }
+ }
+ }
+ }
+ }
+ if ( node.hasChildNodes() ) {
+ QDomNode n = node.firstChild();
+ while ( !n.isNull() ) {
+ convertNames( n );
+ n = n.nextSibling();
+ }
+ }
+}
+
+QString FormulaElement::toLatex()
+{
+ return inherited::toLatex(); //Consider $$ sorround
+}
+
+void FormulaElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
+{
+ QDomElement de;
+ if ( !oasisFormat ) {
+ de = doc.createElementNS( "http://www.w3.org/1998/Math/MathML",
+ "math" );
+ parent.appendChild( de );
+ }
+ else {
+ QDomElement element = doc.createElement( "math:semantics" );
+ de = doc.createElement( "math:mrow" );
+ parent.appendChild( element );
+ element.appendChild( de );
+ }
+ for ( uint i = 0; i < countChildren(); ++i ) {
+ const BasicElement* e = getChild( i );
+ e->writeMathML( doc, de, oasisFormat );
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/formulaelement.h b/lib/kformula/formulaelement.h
new file mode 100644
index 00000000..fda89d79
--- /dev/null
+++ b/lib/kformula/formulaelement.h
@@ -0,0 +1,234 @@
+/* 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.
+*/
+
+#ifndef FORMULAELEMENT_H
+#define FORMULAELEMENT_H
+
+// Formula include
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class ContextStyle;
+class FormulaDocument;
+class SymbolTable;
+
+
+/**
+ * The main element.
+ * A formula consists of a FormulaElement and its children.
+ * The only element that has no parent.
+ */
+class FormulaElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ /**
+ * The container this FormulaElement belongs to must not be 0,
+ * except you really know what you are doing.
+ */
+ FormulaElement(FormulaDocument* container);
+
+ virtual FormulaElement* clone() { return 0; }
+
+ /**
+ * Returns the element the point is in.
+ */
+ BasicElement* goToPos( FormulaCursor*, const LuPixelPoint& point );
+
+ /**
+ * Ordinary formulas are not write protected.
+ */
+ virtual bool readOnly( const BasicElement* /*child*/ ) const { return false; }
+
+ /**
+ * @returns whether its prohibited to change the sequence with this cursor.
+ */
+ virtual bool readOnly( const FormulaCursor* ) const { return false; }
+
+ /**
+ * Provide fast access to the rootElement for each child.
+ */
+ virtual FormulaElement* formula() { return this; }
+
+ /**
+ * Provide fast access to the rootElement for each child.
+ */
+ virtual const FormulaElement* formula() const { return this; }
+
+ /**
+ * Gets called just before the child is removed from
+ * the element tree.
+ */
+ void elementRemoval(BasicElement* child);
+
+ /**
+ * Gets called whenever something changes and we need to
+ * recalc.
+ */
+ virtual void changed();
+
+ /**
+ * Gets called when a request has the side effect of moving the
+ * cursor. In the end any operation that moves the cursor should
+ * call this.
+ */
+ void cursorHasMoved( FormulaCursor* );
+
+ void moveOutLeft( FormulaCursor* );
+ void moveOutRight( FormulaCursor* );
+ void moveOutBelow( FormulaCursor* );
+ void moveOutAbove( FormulaCursor* );
+
+ /**
+ * Tell the user something has happened.
+ */
+ void tell( const QString& msg );
+
+ /**
+ * Gets called when the formula wants to vanish. The one who
+ * holds it should create an appropriate command and execute it.
+ */
+ void removeFormula( FormulaCursor* );
+
+ void insertFormula( FormulaCursor* );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Calculates the formulas sizes and positions.
+ */
+ void calcSizes( ContextStyle& context );
+
+ /**
+ * Draws the whole thing.
+ */
+ void draw( QPainter& painter, const LuPixelRect& r, ContextStyle& context );
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+
+ /**
+ * @returns our documents symbol table
+ */
+ const SymbolTable& getSymbolTable() const;
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ int getBaseSize() const { return baseSize; }
+ void setBaseSize( int size );
+
+ bool hasOwnBaseSize() const { return ownBaseSize; }
+
+ virtual KCommand* input( Container* container, QKeyEvent* event );
+
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ /**
+ * For copy&paste we need to create an empty XML element.
+ */
+ QDomElement emptyFormulaElement( QDomDocument& doc );
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "FORMULA"; }
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+
+private:
+
+ /**
+ * The introduction of 'NameSequence' changed the DOM.
+ * However, we need to read the old version.
+ */
+ void convertNames( QDomNode node );
+
+ /**
+ * The document that owns (is) this formula.
+ */
+ FormulaDocument* document;
+
+ /**
+ * The base font size.
+ */
+ int baseSize;
+
+ /**
+ * Whether we want to use the default base size.
+ */
+ bool ownBaseSize;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // FORMULAELEMENT_H
diff --git a/lib/kformula/fractionelement.cc b/lib/kformula/fractionelement.cc
new file mode 100644
index 00000000..8652bf66
--- /dev/null
+++ b/lib/kformula/fractionelement.cc
@@ -0,0 +1,657 @@
+/* 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 <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "elementvisitor.h"
+#include "formulaelement.h"
+#include "formulacursor.h"
+#include "fractionelement.h"
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+using namespace std;
+
+FractionElement::FractionElement(BasicElement* parent) : BasicElement(parent),
+ m_lineThicknessType( NoSize ),
+ m_numAlign( NoHorizontalAlign ),
+ m_denomAlign( NoHorizontalAlign ),
+ m_customBevelled( false )
+{
+ numerator = new SequenceElement(this);
+ denominator = new SequenceElement(this);
+}
+
+FractionElement::~FractionElement()
+{
+ delete denominator;
+ delete numerator;
+}
+
+FractionElement::FractionElement( const FractionElement& other )
+ : BasicElement( other ),
+ m_lineThicknessType( other.m_lineThicknessType ),
+ m_lineThickness( other.m_lineThickness ),
+ m_numAlign( other.m_numAlign ),
+ m_denomAlign( other.m_denomAlign ),
+ m_customBevelled( other.m_customBevelled ),
+ m_bevelled( other.m_bevelled )
+{
+ numerator = new SequenceElement( *( other.numerator ) );
+ denominator = new SequenceElement( *( other.denominator ) );
+ numerator->setParent( this );
+ denominator->setParent( this );
+}
+
+
+bool FractionElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+void FractionElement::entered( SequenceElement* child )
+{
+ if ( child == numerator ) {
+ formula()->tell( i18n( "Numerator" ) );
+ }
+ else {
+ formula()->tell( i18n( "Denominator" ) );
+ }
+}
+
+
+BasicElement* FractionElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+ e = numerator->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ e = denominator->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+
+ luPixel dx = point.x() - myPos.x();
+ luPixel dy = point.y() - myPos.y();
+
+ // the positions after the numerator / denominator
+ if ((dx > numerator->getX()) &&
+ (dy < numerator->getHeight())) {
+ numerator->moveLeft(cursor, this);
+ handled = true;
+ return numerator;
+ }
+ else if ((dx > denominator->getX()) &&
+ (dy > denominator->getY())) {
+ denominator->moveLeft(cursor, this);
+ handled = true;
+ return denominator;
+ }
+
+ return this;
+ }
+ return 0;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void FractionElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ ContextStyle::TextStyle i_tstyle = context.convertTextStyleFraction( tstyle );
+ ContextStyle::IndexStyle u_istyle = context.convertIndexStyleUpper( istyle );
+ ContextStyle::IndexStyle l_istyle = context.convertIndexStyleLower( istyle );
+ double factor = style.sizeFactor();
+
+ numerator->calcSizes( context, i_tstyle, u_istyle, style );
+ denominator->calcSizes( context, i_tstyle, l_istyle, style );
+
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+
+ double linethickness = lineThickness( context, factor );
+
+ setWidth( QMAX( numerator->getWidth(), denominator->getWidth() ) );
+ setHeight( numerator->getHeight() + denominator->getHeight() +
+ 2*distY + linethickness );
+ setBaseline( qRound( numerator->getHeight() + distY + .5*linethickness
+ + context.axisHeight( tstyle, factor ) ) );
+
+ numerator->setX( ( getWidth() - numerator->getWidth() ) / 2 );
+ denominator->setX( ( getWidth() - denominator->getWidth() ) / 2 );
+
+ numerator->setY( 0 );
+ denominator->setY( getHeight() - denominator->getHeight() );
+}
+
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void FractionElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ numerator->draw( painter, r, context,
+ context.convertTextStyleFraction( tstyle ),
+ context.convertIndexStyleUpper( istyle ), style, myPos);
+ if (denominator) { // Can be temporarily 0 see FractionElement::remove
+ denominator->draw( painter, r, context,
+ context.convertTextStyleFraction( tstyle ),
+ context.convertIndexStyleLower( istyle ), style,
+ myPos);
+ }
+
+ if ( withLine() ) {
+ // TODO: thickness
+ double factor = style.sizeFactor();
+ double linethickness = lineThickness( context, factor );
+ painter.setPen( QPen( style.color(),
+ context.layoutUnitToPixelY( linethickness ) ) );
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y() + axis( context, tstyle, factor ) ),
+ context.layoutUnitToPixelX( myPos.x() + getWidth() ),
+ context.layoutUnitToPixelY( myPos.y() + axis( context, tstyle, factor ) ) );
+ }
+}
+
+
+void FractionElement::dispatchFontCommand( FontCommand* cmd )
+{
+ numerator->dispatchFontCommand( cmd );
+ denominator->dispatchFontCommand( cmd );
+}
+
+/**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+void FractionElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ if (linear) {
+ denominator->moveLeft(cursor, this);
+ }
+ else {
+ numerator->moveLeft(cursor, this);
+ }
+ }
+ else if (from == denominator) {
+ numerator->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+}
+
+
+/**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+void FractionElement::moveRight(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ numerator->moveRight(cursor, this);
+ }
+ else if (from == numerator) {
+ if (linear) {
+ denominator->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ }
+}
+
+
+/**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+void FractionElement::moveUp(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveUp(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ denominator->moveRight(cursor, this);
+ }
+ else if (from == denominator) {
+ numerator->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveUp(cursor, this);
+ }
+ }
+}
+
+
+/**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+void FractionElement::moveDown(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveDown(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ numerator->moveRight(cursor, this);
+ }
+ else if (from == numerator) {
+ denominator->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveDown(cursor, this);
+ }
+ }
+}
+
+
+/**
+ * Reinserts the denominator if it has been removed.
+ */
+void FractionElement::insert(FormulaCursor* cursor,
+ QPtrList<BasicElement>& newChildren,
+ Direction direction)
+{
+ if (cursor->getPos() == denominatorPos) {
+ denominator = static_cast<SequenceElement*>(newChildren.take(0));
+ denominator->setParent(this);
+
+ if (direction == beforeCursor) {
+ denominator->moveLeft(cursor, this);
+ }
+ else {
+ denominator->moveRight(cursor, this);
+ }
+ cursor->setSelection(false);
+ formula()->changed();
+ }
+}
+
+
+/**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * We remove ourselve if we are requested to remove our numerator.
+ *
+ * It is possible to remove the denominator. But after this we
+ * are senseless and the caller is required to replace us.
+ */
+void FractionElement::remove(FormulaCursor* cursor,
+ QPtrList<BasicElement>& removedChildren,
+ Direction direction)
+{
+ switch (cursor->getPos()) {
+ case numeratorPos:
+ getParent()->selectChild(cursor, this);
+ getParent()->remove(cursor, removedChildren, direction);
+ break;
+ case denominatorPos:
+ removedChildren.append(denominator);
+ formula()->elementRemoval(denominator);
+ denominator = 0;
+ cursor->setTo(this, denominatorPos);
+ formula()->changed();
+ break;
+ }
+}
+
+
+/**
+ * Returns wether the element has no more useful
+ * children (except its main child) and should therefore
+ * be replaced by its main child's content.
+ */
+bool FractionElement::isSenseless()
+{
+ return denominator == 0;
+}
+
+
+// main child
+//
+// If an element has children one has to become the main one.
+
+SequenceElement* FractionElement::getMainChild()
+{
+ return numerator;
+}
+
+// void FractionElement::setMainChild(SequenceElement* child)
+// {
+// formula()->elementRemoval(numerator);
+// numerator = child;
+// numerator->setParent(this);
+// formula()->changed();
+// }
+
+
+/**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+void FractionElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ if (child == numerator) {
+ cursor->setTo(this, numeratorPos);
+ }
+ else if (child == denominator) {
+ cursor->setTo(this, denominatorPos);
+ }
+}
+
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void FractionElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ QDomDocument doc = element.ownerDocument();
+ if (!withLine()) element.setAttribute("NOLINE", 1);
+
+ QDomElement num = doc.createElement("NUMERATOR");
+ num.appendChild(numerator->getElementDom(doc));
+ element.appendChild(num);
+
+ QDomElement den = doc.createElement("DENOMINATOR");
+ den.appendChild(denominator->getElementDom(doc));
+ element.appendChild(den);
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool FractionElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ QString lineStr = element.attribute("NOLINE");
+ if(!lineStr.isNull()) {
+ m_lineThicknessType = RelativeSize;
+ m_lineThickness = lineStr.toInt();
+ }
+ return true;
+}
+
+/**
+ * Reads our attributes from the MathML element.
+ * Returns false if it failed.
+ */
+bool FractionElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+ QString linethicknessStr = element.attribute( "linethickness" ).lower();
+ if ( ! linethicknessStr.isNull() ) {
+ if ( linethicknessStr == "thin" ) {
+ m_lineThicknessType = RelativeSize;
+ m_lineThickness = 0.5; // ### Arbitrary size
+ }
+ else if ( linethicknessStr == "medium" ) {
+ m_lineThicknessType = RelativeSize;
+ m_lineThickness = 1.0;
+ }
+ else if ( linethicknessStr == "thick" ) {
+ m_lineThicknessType = RelativeSize;
+ m_lineThickness = 2.0; // ### Arbitrary size
+ }
+ else {
+ m_lineThickness = getSize( linethicknessStr, &m_lineThicknessType );
+ }
+ }
+ QString numalignStr = element.attribute( "numalign" ).lower();
+ if ( ! numalignStr.isNull() ) {
+ if ( numalignStr == "left" ) {
+ m_numAlign = LeftHorizontalAlign;
+ }
+ else if ( numalignStr == "center" ) {
+ m_numAlign = CenterHorizontalAlign;
+ }
+ else if ( numalignStr == "right" ) {
+ m_numAlign = RightHorizontalAlign;
+ }
+ }
+ QString denomalignStr = element.attribute( "denomalign" ).lower();
+ if ( ! denomalignStr.isNull() ) {
+ if ( denomalignStr == "left" ) {
+ m_denomAlign = LeftHorizontalAlign;
+ }
+ else if ( denomalignStr == "center" ) {
+ m_denomAlign = CenterHorizontalAlign;
+ }
+ else if ( denomalignStr == "right" ) {
+ m_denomAlign = RightHorizontalAlign;
+ }
+ }
+ QString bevelledStr = element.attribute( "bevelled" ).lower();
+ if ( ! bevelledStr.isNull() ) {
+ m_customBevelled = true;
+ if ( bevelledStr == "true" ) {
+ m_bevelled = true;
+ }
+ else {
+ m_bevelled = false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool FractionElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ if ( !buildChild( numerator, node, "NUMERATOR" ) ) {
+ kdWarning( DEBUGID ) << "Empty numerator in FractionElement." << endl;
+ return false;
+ }
+ node = node.nextSibling();
+
+ if ( !buildChild( denominator, node, "DENOMINATOR" ) ) {
+ kdWarning( DEBUGID ) << "Empty denominator in FractionElement." << endl;
+ return false;
+ }
+ node = node.nextSibling();
+
+ return true;
+}
+
+/**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+int FractionElement::readContentFromMathMLDom(QDomNode& node)
+{
+ if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
+ return -1;
+ }
+
+ int numeratorNumber = numerator->buildMathMLChild( node );
+ if ( numeratorNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty numerator in FractionElement." << endl;
+ return -1;
+ }
+ for (int i = 0; i < numeratorNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ if ( denominator->buildMathMLChild( node ) == -1 ) {
+ kdWarning( DEBUGID ) << "Empty denominator in FractionElement." << endl;
+ return -1;
+ }
+
+ return 1;
+}
+
+QString FractionElement::toLatex()
+{
+ if ( withLine() ) {
+ return "\\frac{" + numerator->toLatex() +"}{" + denominator->toLatex() + "}";
+ }
+ else {
+ return "{" + numerator->toLatex() + "\\atop " + denominator->toLatex() + "}";
+ }
+}
+
+QString FractionElement::formulaString()
+{
+ return "(" + numerator->formulaString() + ")/(" + denominator->formulaString() + ")";
+}
+
+void FractionElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ switch ( m_lineThicknessType ) {
+ case AbsoluteSize:
+ element.setAttribute( "linethickness", QString( "%1pt" ).arg( m_lineThickness ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "linethickness", QString( "%1%" ).arg( m_lineThickness * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "linethickness", QString( "%1px" ).arg( m_lineThickness ) );
+ break;
+ default:
+ break;
+ }
+
+ switch ( m_numAlign ) {
+ case LeftHorizontalAlign:
+ element.setAttribute( "numalign", "left" );
+ break;
+ case CenterHorizontalAlign:
+ element.setAttribute( "numalign", "center" );
+ break;
+ case RightHorizontalAlign:
+ element.setAttribute( "numalign", "right" );
+ break;
+ default:
+ break;
+ }
+
+ switch ( m_denomAlign ) {
+ case LeftHorizontalAlign:
+ element.setAttribute( "denomalign", "left" );
+ break;
+ case CenterHorizontalAlign:
+ element.setAttribute( "denomalign", "center" );
+ break;
+ case RightHorizontalAlign:
+ element.setAttribute( "denomalign", "right" );
+ break;
+ default:
+ break;
+ }
+
+ if ( m_customBevelled ) {
+ element.setAttribute( "bevelled", m_bevelled ? "true" : "false" );
+ }
+}
+
+void FractionElement::writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const
+{
+ numerator->writeMathML( doc, element, oasisFormat );
+ denominator->writeMathML( doc, element, oasisFormat );
+}
+
+double FractionElement::lineThickness( const ContextStyle& context, double factor )
+{
+ double linethickness = context.getLineWidth( factor );
+ switch ( m_lineThicknessType ) {
+ case AbsoluteSize:
+ linethickness = context.ptToLayoutUnitPixX( m_lineThickness );
+ break;
+ case RelativeSize:
+ linethickness *= m_lineThickness;
+ break;
+ case PixelSize:
+ linethickness = m_lineThickness;
+ break;
+ default:
+ break;
+ }
+ return linethickness;
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/fractionelement.h b/lib/kformula/fractionelement.h
new file mode 100644
index 00000000..8a49a719
--- /dev/null
+++ b/lib/kformula/fractionelement.h
@@ -0,0 +1,255 @@
+/* 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.
+*/
+
+#ifndef FRACTIONELEMENT_H
+#define FRACTIONELEMENT_H
+
+#include "basicelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+class SequenceElement;
+
+
+/**
+ * A fraction.
+ */
+class FractionElement : public BasicElement {
+ FractionElement& operator=( const FractionElement& ) { return *this; }
+public:
+
+ enum { numeratorPos, denominatorPos };
+
+ FractionElement(BasicElement* parent = 0);
+ ~FractionElement();
+
+ FractionElement( const FractionElement& );
+
+ virtual FractionElement* clone() {
+ return new FractionElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns the type of this element. Used for
+ * parsing a sequence.
+ */
+ virtual TokenType getTokenType() const { return INNER; }
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Reinserts the denominator if it has been removed.
+ */
+ virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * We remove ourselve if we are requested to remove our numerator.
+ *
+ * It is possible to remove the denominator. But after this we
+ * are senseless and the caller is required to replace us.
+ */
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+
+ // main child
+ //
+ // If an element has children one has to become the main one.
+
+ virtual SequenceElement* getMainChild();
+
+ SequenceElement* getNumerator() { return numerator; }
+ SequenceElement* getDenominator() { return denominator; }
+
+ /**
+ * Returns wether the element has no more useful
+ * children (except its main child) and should therefore
+ * be replaced by its main child's content.
+ */
+ virtual bool isSenseless();
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor* cursor, BasicElement* child);
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ //virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child) = 0;
+
+ /**
+ * Tells whether the fraction should be drawn with a line.
+ */
+ void showLine(bool line) {
+ m_lineThicknessType = RelativeSize;
+ if ( line ) {
+ m_lineThickness = 1.0;
+ }
+ else {
+ m_lineThickness = 0.0;
+ }
+ }
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "FRACTION"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ /**
+ * Reads our attributes from the MathML element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+
+ /**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual int readContentFromMathMLDom(QDomNode& node);
+
+private:
+ virtual QString getElementName() const { return "mfrac"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+ virtual void writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const ;
+
+ double lineThickness( const ContextStyle& context, double factor );
+
+ bool withLine() { return m_lineThicknessType == NoSize || m_lineThickness != 0.0; }
+
+ SequenceElement* numerator;
+ SequenceElement* denominator;
+
+ SizeType m_lineThicknessType;
+ double m_lineThickness;
+ HorizontalAlign m_numAlign;
+ HorizontalAlign m_denomAlign;
+ bool m_customBevelled;
+ bool m_bevelled;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // FRACTIONELEMENT_H
diff --git a/lib/kformula/glyphelement.cc b/lib/kformula/glyphelement.cc
new file mode 100644
index 00000000..798621a2
--- /dev/null
+++ b/lib/kformula/glyphelement.cc
@@ -0,0 +1,159 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qfontmetrics.h>
+#include <qpainter.h>
+
+#include "fontstyle.h"
+#include "glyphelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+GlyphElement::GlyphElement( BasicElement* parent ) : TextElement( ' ', false, parent ) {
+}
+
+bool GlyphElement::readAttributesFromMathMLDom( const QDomElement& element )
+{
+ if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ // MathML Section 3.2.9.2
+ m_fontFamily = element.attribute( "fontfamily" );
+ if ( m_fontFamily.isNull() ) {
+ kdWarning( DEBUGID ) << "Required attribute fontfamily not found in glyph element\n";
+ return false;
+ }
+ QString indexStr = element.attribute( "index" );
+ if ( indexStr.isNull() ) {
+ kdWarning( DEBUGID ) << "Required attribute index not found in glyph element\n";
+ return false;
+ }
+ bool ok;
+ ushort index = indexStr.toUShort( &ok );
+ if ( ! ok ) {
+ kdWarning( DEBUGID ) << "Invalid index value in glyph element\n";
+ return false;
+ }
+ m_char = QChar( index );
+
+ m_alt = element.attribute( "alt" );
+ if ( m_alt.isNull() ) {
+ kdWarning( DEBUGID ) << "Required attribute alt not found in glyph element\n";
+ return false;
+ }
+
+ QStringList missing;
+ FontStyle::testFont( missing, m_fontFamily.lower() );
+ m_hasFont = missing.isEmpty();
+
+ return true;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void GlyphElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ QRect bound;
+
+ if ( m_hasFont ) {
+ QFont font( m_fontFamily );
+ font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
+ QFontMetrics fm ( font );
+ bound = fm.boundingRect( m_char );
+ setWidth( context.ptToLayoutUnitPt( fm.width( m_char ) ) );
+ }
+ else {
+ QFont font( context.getDefaultFont() );
+ font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
+ QFontMetrics fm ( font );
+ bound = fm.boundingRect( m_alt );
+ setWidth( context.ptToLayoutUnitPt( fm.width( m_alt ) ) );
+ }
+ setHeight( context.ptToLayoutUnitPt( bound.height() ) );
+ setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
+
+ // There are some glyphs in TeX that have
+ // baseline==0. (\int, \sum, \prod)
+ if ( getBaseline() == 0 ) {
+ setBaseline( -1 );
+ }
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void GlyphElement::draw( QPainter& painter, const LuPixelRect& /*r*/,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ QFont font;
+ QString text;
+
+ if ( m_hasFont ) {
+ painter.setPen( style.color() );
+ setCharStyle( style.charStyle() );
+ setCharFamily( style.charFamily() );
+ font = QFont( m_fontFamily );
+ text = m_char;
+ painter.fillRect( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y() ),
+ context.layoutUnitToPixelX( getWidth() ),
+ context.layoutUnitToPixelY( getHeight() ),
+ style.background() );
+ }
+ else {
+ painter.setPen( context.getErrorColor() );
+ font = context.getDefaultFont();
+ text = m_alt;
+ }
+ font.setPointSizeFloat( context.layoutUnitToFontSize( mySize, false ) );
+ painter.setFont( font );
+ painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getBaseline() ),
+ text );
+}
+
+void GlyphElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ element.setAttribute( "fontfamily", m_fontFamily );
+ element.setAttribute( "index", m_char.unicode() );
+ element.setAttribute( "alt", m_alt );
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/glyphelement.h b/lib/kformula/glyphelement.h
new file mode 100644
index 00000000..425caf10
--- /dev/null
+++ b/lib/kformula/glyphelement.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef GLYPHELEMENT_H
+#define GLYPHELEMENT_H
+
+#include "textelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class GlyphElement : public TextElement {
+ typedef TextElement inherited;
+public:
+ GlyphElement( BasicElement* parent = 0 );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+protected:
+ virtual bool readAttributesFromMathMLDom( const QDomElement &element );
+
+private:
+ virtual QString getElementName() const { return "mglyph"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+
+ QChar m_char; // Char to be shown
+ QString m_fontFamily; // Font family to use
+ QString m_alt; // Alternative text if font family not found
+ bool m_hasFont; // Whether required font is available
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // GLYPHELEMENT_H
diff --git a/lib/kformula/identifierelement.cc b/lib/kformula/identifierelement.cc
new file mode 100644
index 00000000..a457403a
--- /dev/null
+++ b/lib/kformula/identifierelement.cc
@@ -0,0 +1,206 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <klocale.h>
+
+#include "kformuladefs.h"
+#include "textelement.h"
+#include "identifierelement.h"
+#include "operatorelement.h"
+#include "numberelement.h"
+#include "kformulacommand.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "formulaelement.h"
+#include "creationstrategy.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+IdentifierElement::IdentifierElement( BasicElement* parent ) : TokenElement( parent ) {}
+
+/*
+ * Token elements' content has to be of homogeneous type. Every token element
+ * must (TODO: check this) appear inside a non-token sequence, and thus, if
+ * the command asks for a different content, a new element has to be created in
+ * parent sequence.
+ */
+KCommand* IdentifierElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ formula()->tell( i18n( "write protection" ) );
+ return 0;
+ }
+
+ if ( *request == req_addText ) {
+ KFCReplace* command = new KFCReplace( i18n("Add Text"), container );
+ TextRequest* tr = static_cast<TextRequest*>( request );
+ for ( uint i = 0; i < tr->text().length(); i++ ) {
+ TextElement* element = creationStrategy->createTextElement( tr->text()[i] );
+ command->addElement( element );
+ }
+ return command;
+ }
+
+ else if ( *request == req_addTextChar ) {
+ KFCReplace* command = new KFCReplace( i18n("Add Text"), container );
+ TextCharRequest* tr = static_cast<TextCharRequest*>( request );
+ TextElement* element = creationStrategy->createTextElement( tr->ch(), tr->isSymbol() );
+ command->addElement( element );
+ return command;
+ }
+
+ if ( countChildren() == 0 || cursor->getPos() == countChildren() ) {
+ // We are in the last position, so it's easy, call the parent to
+ // create a new child
+ SequenceElement* parent = static_cast<SequenceElement*>( getParent() );
+ if ( parent ) {
+ uint pos = parent->childPos( this );
+ cursor->setTo( parent, pos + 1);
+ return parent->buildCommand( container, request );
+ }
+ }
+ if ( cursor->getPos() == 0 ) {
+ SequenceElement* parent = static_cast<SequenceElement*>( getParent() );
+ if ( parent ) {
+ uint pos = parent->childPos( this );
+ cursor->setTo( parent, pos );
+ return parent->buildCommand( container, request );
+ }
+ }
+
+ // We are in the middle of a token, so:
+ // a) Cut from mark to the end
+ // b) Create a new token and add an element from key pressed
+ // c) Create a new token and add elements cut previously
+ // d) Move cursor to parent so that it command execution works fine
+
+ switch( *request ) {
+ case req_addOperator: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Operator"), container );
+ OperatorRequest* opr = static_cast<OperatorRequest*>( request );
+ OperatorElement* op = creationStrategy->createOperatorElement();
+ TextElement* text = creationStrategy->createTextElement( opr->ch() );
+ command->addCursor( cursor );
+ command->addToken( op );
+ command->addContent( op, text );
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+ case req_addNumber: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Number"), container );
+ NumberRequest* nr = static_cast<NumberRequest*>( request );
+ NumberElement* num = creationStrategy->createNumberElement();
+ TextElement* text = creationStrategy->createTextElement( nr->ch() );
+ command->addCursor( cursor );
+ command->addToken( num );
+ command->addContent( num, text );
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+ case req_addEmptyBox:
+ case req_addNameSequence:
+ case req_addBracket:
+ case req_addSpace:
+ case req_addFraction:
+ case req_addRoot:
+ case req_addSymbol:
+ case req_addOneByTwoMatrix:
+ case req_addMatrix: {
+ uint pos = static_cast<SequenceElement*>(getParent())->childPos( this );
+ cursor->setTo( getParent(), pos + 1);
+ return getParent()->buildCommand( container, request );
+ }
+ default:
+ return SequenceElement::buildCommand( container, request );
+ }
+ return 0;
+}
+
+void IdentifierElement::setStyleVariant( StyleAttributes& style )
+{
+ if ( customMathVariant() ) {
+ style.setCustomMathVariant ( true );
+ style.setCustomFontWeight( false );
+ style.setCustomFontStyle( false );
+ style.setCustomFont( false );
+ if ( customMathVariant() ) {
+ style.setCharFamily ( charFamily() );
+ style.setCharStyle( charStyle() );
+ }
+ else {
+ style.setCharFamily( style.charFamily() );
+ style.setCharStyle( style.charStyle() );
+ }
+ }
+ else {
+ style.setCustomMathVariant( false );
+ if ( customFontFamily() ) {
+ style.setCustomFont( true );
+ style.setFont( QFont(fontFamily()) );
+ }
+
+ bool fontweight = false;
+ if ( customFontWeight() || style.customFontWeight() ) {
+ style.setCustomFontWeight( true );
+ if ( customFontWeight() ) {
+ fontweight = fontWeight();
+ }
+ else {
+ fontweight = style.customFontWeight();
+ }
+ style.setFontWeight( fontweight );
+ }
+ else {
+ style.setCustomFontWeight( false );
+ }
+
+ bool fontstyle;
+ if ( customFontStyle() ) {
+ fontstyle = fontStyle();
+ }
+ else if ( countChildren() == 1 ) {
+ fontstyle = true;
+ }
+ else {
+ fontstyle = false;
+ }
+
+ if ( fontweight && fontstyle ) {
+ style.setCharStyle( boldItalicChar );
+ }
+ else if ( fontweight && ! fontstyle ) {
+ style.setCharStyle( boldChar );
+ }
+ else if ( ! fontweight && fontstyle ) {
+ style.setCharStyle( italicChar );
+ }
+ else {
+ style.setCharStyle( normalChar );
+ }
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/identifierelement.h b/lib/kformula/identifierelement.h
new file mode 100644
index 00000000..9c84c2ab
--- /dev/null
+++ b/lib/kformula/identifierelement.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef IDENTIFIERELEMENT_H
+#define IDENTIFIERELEMENT_H
+
+#include "tokenelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class IdentifierElement : public TokenElement {
+ typedef TokenElement inherited;
+public:
+ IdentifierElement( BasicElement* parent = 0 );
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+
+ virtual QString getElementName() const { return "mi"; }
+protected:
+
+ virtual void setStyleVariant( StyleAttributes& style );
+ /**
+ * Space around sequence
+ */
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor ) { return 0; }
+ virtual luPt getSpaceAfter( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor ) { return 0; }
+
+private:
+
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // IDENTIFIERELEMENT_H
diff --git a/lib/kformula/indexelement.cc b/lib/kformula/indexelement.cc
new file mode 100644
index 00000000..76c25d28
--- /dev/null
+++ b/lib/kformula/indexelement.cc
@@ -0,0 +1,1763 @@
+/* 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 <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "elementvisitor.h"
+#include "indexelement.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "kformulacommand.h"
+#include "sequenceelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+class IndexSequenceElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ IndexSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
+ virtual IndexSequenceElement* clone() {
+ return new IndexSequenceElement( *this );
+ }
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+};
+
+
+KCommand* IndexSequenceElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ return 0;
+ }
+
+ switch ( *request ) {
+ case req_addIndex: {
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isSelection() ||
+ ( cursor->getPos() > 0 && cursor->getPos() < countChildren() ) ) {
+ break;
+ }
+ IndexElement* element = static_cast<IndexElement*>( getParent() );
+ IndexRequest* ir = static_cast<IndexRequest*>( request );
+ ElementIndexPtr index = element->getIndex( ir->index() );
+ if ( !index->hasIndex() ) {
+ KFCAddGenericIndex* command = new KFCAddGenericIndex( container, index );
+ return command;
+ }
+ else {
+ index->moveToIndex( cursor, afterCursor );
+ cursor->setSelection( false );
+ formula()->cursorHasMoved( cursor );
+ return 0;
+ }
+ }
+ default:
+ break;
+ }
+ return inherited::buildCommand( container, request );
+}
+
+
+IndexElement::IndexElement(BasicElement* parent)
+ : BasicElement(parent),
+ m_subScriptShiftType( NoSize ),
+ m_superScriptShiftType( NoSize ),
+ m_customAccentUnder( false ),
+ m_customAccent ( false )
+{
+ content = new IndexSequenceElement( this );
+
+ upperLeft = 0;
+ upperMiddle = 0;
+ upperRight = 0;
+ lowerLeft = 0;
+ lowerMiddle = 0;
+ lowerRight = 0;
+}
+
+IndexElement::~IndexElement()
+{
+ delete content;
+ delete upperLeft;
+ delete upperMiddle;
+ delete upperRight;
+ delete lowerLeft;
+ delete lowerMiddle;
+ delete lowerRight;
+}
+
+
+IndexElement::IndexElement( const IndexElement& other )
+ : BasicElement( other ),
+ m_subScriptShiftType( other.m_subScriptShiftType ),
+ m_subScriptShift( other.m_subScriptShift ),
+ m_superScriptShiftType( other.m_superScriptShiftType ),
+ m_superScriptShift( other.m_superScriptShift ),
+ m_customAccentUnder( other.m_customAccentUnder ),
+ m_accentUnder( other.m_accentUnder ),
+ m_customAccent ( other.m_customAccent ),
+ m_accent( other.m_accent )
+{
+ content = new IndexSequenceElement( *dynamic_cast<IndexSequenceElement*>( other.content ) );
+
+ if ( other.upperLeft ) {
+ upperLeft = new SequenceElement( *( other.upperLeft ) );
+ upperLeft->setParent( this );
+ }
+ else {
+ upperLeft = 0;
+ }
+ if ( other.upperMiddle ) {
+ upperMiddle = new SequenceElement( *( other.upperMiddle ) );
+ upperMiddle->setParent( this );
+ }
+ else {
+ upperMiddle = 0;
+ }
+ if ( other.upperRight ) {
+ upperRight = new SequenceElement( *( other.upperRight ) );
+ upperRight->setParent( this );
+ }
+ else {
+ upperRight = 0;
+ }
+
+ if ( other.lowerLeft ) {
+ lowerLeft = new SequenceElement( *( other.lowerLeft ) );
+ lowerLeft->setParent( this );
+ }
+ else {
+ lowerLeft = 0;
+ }
+ if ( other.lowerMiddle ) {
+ lowerMiddle = new SequenceElement( *( other.lowerMiddle ) );
+ lowerMiddle->setParent( this );
+ }
+ else {
+ lowerMiddle = 0;
+ }
+ if ( other.lowerRight ) {
+ lowerRight = new SequenceElement( *( other.lowerRight ) );
+ lowerRight->setParent( this );
+ }
+ else {
+ lowerRight = 0;
+ }
+}
+
+
+bool IndexElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+QChar IndexElement::getCharacter() const
+{
+ if ( !content->isTextOnly() ) {
+ return QChar::null;
+ }
+
+ if ( hasUpperRight() && !upperRight->isTextOnly() ) {
+ return QChar::null;
+ }
+ if ( hasUpperMiddle() && !upperMiddle->isTextOnly() ) {
+ return QChar::null;
+ }
+ if ( hasUpperLeft() && !upperLeft->isTextOnly() ) {
+ return QChar::null;
+ }
+ if ( hasLowerRight() && !lowerRight->isTextOnly() ) {
+ return QChar::null;
+ }
+ if ( hasLowerMiddle() && !lowerMiddle->isTextOnly() ) {
+ return QChar::null;
+ }
+ if ( hasLowerLeft() && !lowerLeft->isTextOnly() ) {
+ return QChar::null;
+ }
+
+ return ' ';
+}
+
+void IndexElement::entered( SequenceElement* child )
+{
+ if ( child == content ) {
+ formula()->tell( i18n( "Indexed list" ) );
+ }
+ else {
+ formula()->tell( i18n( "Index" ) );
+ }
+}
+
+
+/**
+ * Returns the element the point is in.
+ */
+BasicElement* IndexElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x()+getX(), parentOrigin.y()+getY());
+ e = content->goToPos(cursor, handled, point, myPos);
+ if (e != 0) return e;
+
+ if (hasUpperRight()) {
+ e = upperRight->goToPos(cursor, handled, point, myPos);
+ if (e != 0) return e;
+ }
+ if (hasUpperMiddle()) {
+ e = upperMiddle->goToPos(cursor, handled, point, myPos);
+ if (e != 0) return e;
+ }
+ if (hasUpperLeft()) {
+ e = upperLeft->goToPos(cursor, handled, point, myPos);
+ if (e != 0) return e;
+ }
+ if (hasLowerRight()) {
+ e = lowerRight->goToPos(cursor, handled, point, myPos);
+ if (e != 0) return e;
+ }
+ if (hasLowerMiddle()) {
+ e = lowerMiddle->goToPos(cursor, handled, point, myPos);
+ if (e != 0) return e;
+ }
+ if (hasLowerLeft()) {
+ e = lowerLeft->goToPos(cursor, handled, point, myPos);
+ if (e != 0) return e;
+ }
+
+ luPixel dx = point.x() - myPos.x();
+ luPixel dy = point.y() - myPos.y();
+
+ // the positions after the left indexes
+ if (dx < content->getX()+content->getWidth()) {
+ if (dy < content->getY()) {
+ if (hasUpperMiddle() && (dx > upperMiddle->getX())) {
+ upperMiddle->moveLeft(cursor, this);
+ handled = true;
+ return upperMiddle;
+ }
+ if (hasUpperLeft() && (dx > upperLeft->getX())) {
+ upperLeft->moveLeft(cursor, this);
+ handled = true;
+ return upperLeft;
+ }
+ }
+ else if (dy > content->getY()+content->getHeight()) {
+ if (hasLowerMiddle() && (dx > lowerMiddle->getX())) {
+ lowerMiddle->moveLeft(cursor, this);
+ handled = true;
+ return lowerMiddle;
+ }
+ if (hasLowerLeft() && (dx > lowerLeft->getX())) {
+ lowerLeft->moveLeft(cursor, this);
+ handled = true;
+ return lowerLeft;
+ }
+ }
+ }
+ // the positions after the left indexes
+ else {
+ if (dy < content->getY()) {
+ if (hasUpperRight()) {
+ upperRight->moveLeft(cursor, this);
+ handled = true;
+ return upperRight;
+ }
+ }
+ else if (dy > content->getY()+content->getHeight()) {
+ if (hasLowerRight()) {
+ lowerRight->moveLeft(cursor, this);
+ handled = true;
+ return lowerRight;
+ }
+ }
+ else {
+ content->moveLeft(cursor, this);
+ handled = true;
+ return content;
+ }
+ }
+
+ return this;
+ }
+ return 0;
+}
+
+
+// drawing
+//
+// Drawing depends on a context which knows the required properties like
+// fonts, spaces and such.
+// It is essential to calculate elements size with the same context
+// before you draw.
+
+
+void IndexElement::setMiddleX(int xOffset, int middleWidth)
+{
+ content->setX(xOffset + (middleWidth - content->getWidth()) / 2);
+ if (hasUpperMiddle()) {
+ upperMiddle->setX(xOffset + (middleWidth - upperMiddle->getWidth()) / 2);
+ }
+ if (hasLowerMiddle()) {
+ lowerMiddle->setX(xOffset + (middleWidth - lowerMiddle->getWidth()) / 2);
+ }
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void IndexElement::calcSizes(const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+
+ ContextStyle::TextStyle i_tstyle = context.convertTextStyleIndex(tstyle);
+ ContextStyle::IndexStyle u_istyle = context.convertIndexStyleUpper( istyle );
+ ContextStyle::IndexStyle l_istyle = context.convertIndexStyleLower( istyle );
+
+ // get the indexes size
+ luPixel ulWidth = 0, ulHeight = 0, ulMidline = 0;
+ if (hasUpperLeft()) {
+ upperLeft->calcSizes( context, i_tstyle, u_istyle, style );
+ ulWidth = upperLeft->getWidth();
+ ulHeight = upperLeft->getHeight();
+ ulMidline = upperLeft->axis( context, i_tstyle, factor );
+ }
+
+ luPixel umWidth = 0, umHeight = 0, umMidline = 0;
+ if (hasUpperMiddle()) {
+ upperMiddle->calcSizes( context, i_tstyle, u_istyle, style );
+ umWidth = upperMiddle->getWidth();
+ umHeight = upperMiddle->getHeight() + distY;
+ umMidline = upperMiddle->axis( context, i_tstyle, factor );
+ }
+
+ luPixel urWidth = 0, urHeight = 0, urMidline = 0;
+ if (hasUpperRight()) {
+ upperRight->calcSizes( context, i_tstyle, u_istyle, style );
+ urWidth = upperRight->getWidth();
+ urHeight = upperRight->getHeight();
+ urMidline = upperRight->axis( context, i_tstyle, factor );
+ }
+
+ luPixel llWidth = 0, llHeight = 0, llMidline = 0;
+ if (hasLowerLeft()) {
+ lowerLeft->calcSizes( context, i_tstyle, l_istyle, style );
+ llWidth = lowerLeft->getWidth();
+ llHeight = lowerLeft->getHeight();
+ llMidline = lowerLeft->axis( context, i_tstyle, factor );
+ }
+
+ luPixel lmWidth = 0, lmHeight = 0, lmMidline = 0;
+ if (hasLowerMiddle()) {
+ lowerMiddle->calcSizes( context, i_tstyle, l_istyle, style );
+ lmWidth = lowerMiddle->getWidth();
+ lmHeight = lowerMiddle->getHeight() + distY;
+ lmMidline = lowerMiddle->axis( context, i_tstyle, factor );
+ }
+
+ luPixel lrWidth = 0, lrHeight = 0, lrMidline = 0;
+ if (hasLowerRight()) {
+ lowerRight->calcSizes( context, i_tstyle, l_istyle, style );
+ lrWidth = lowerRight->getWidth();
+ lrHeight = lowerRight->getHeight();
+ lrMidline = lowerRight->axis( context, i_tstyle, factor );
+ }
+
+ // get the contents size
+ content->calcSizes( context, tstyle, istyle, style );
+ luPixel width = QMAX(content->getWidth(), QMAX(umWidth, lmWidth));
+ luPixel toMidline = content->axis( context, tstyle, factor );
+ luPixel fromMidline = content->getHeight() - toMidline;
+
+ // calculate the x offsets
+ if (ulWidth > llWidth) {
+ upperLeft->setX(0);
+ if (hasLowerLeft()) {
+ lowerLeft->setX(ulWidth - llWidth);
+ }
+ setMiddleX(ulWidth, width);
+ width += ulWidth;
+ }
+ else {
+ if (hasUpperLeft()) {
+ upperLeft->setX(llWidth - ulWidth);
+ }
+ if (hasLowerLeft()) {
+ lowerLeft->setX(0);
+ }
+ setMiddleX(llWidth, width);
+ width += llWidth;
+ }
+
+ if (hasUpperRight()) {
+ upperRight->setX(width);
+ }
+ if (hasLowerRight()) {
+ lowerRight->setX(width);
+ }
+ width += QMAX(urWidth, lrWidth);
+
+ // calculate the y offsets
+ luPixel ulOffset = 0;
+ luPixel urOffset = 0;
+ luPixel llOffset = 0;
+ luPixel lrOffset = 0;
+ if (content->isTextOnly()) {
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ QFont font = context.getDefaultFont();
+ font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
+
+ QFontMetrics fm(font);
+ LuPixelRect bound = fm.boundingRect('x');
+
+ luPixel exBaseline = context.ptToLayoutUnitPt( -bound.top() );
+
+ // the upper half
+ ulOffset = ulHeight + exBaseline - content->getBaseline();
+ urOffset = urHeight + exBaseline - content->getBaseline();
+
+ // the lower half
+ llOffset = lrOffset = content->getBaseline();
+ }
+ else {
+
+ // the upper half
+ ulOffset = QMAX(ulMidline, ulHeight-toMidline);
+ urOffset = QMAX(urMidline, urHeight-toMidline);
+
+ // the lower half
+ llOffset = QMAX(content->getHeight()-llMidline, toMidline);
+ lrOffset = QMAX(content->getHeight()-lrMidline, toMidline);
+ }
+
+ // Add more offset if defined in attributes
+ switch ( m_superScriptShiftType ) {
+ case AbsoluteSize:
+ urOffset += context.ptToLayoutUnitPt( m_superScriptShift );
+ break;
+ case RelativeSize:
+ urOffset += urOffset * m_superScriptShift;
+ break;
+ case PixelSize:
+ urOffset += context.pixelToLayoutUnitY( m_superScriptShift );
+ break;
+ default:
+ break;
+ }
+
+ switch ( m_subScriptShiftType ) {
+ case AbsoluteSize:
+ lrOffset += context.ptToLayoutUnitPt( m_subScriptShift );
+ break;
+ case RelativeSize:
+ lrOffset += lrOffset * m_subScriptShift;
+ break;
+ case PixelSize:
+ lrOffset += context.pixelToLayoutUnitY( m_subScriptShift );
+ break;
+ default:
+ break;
+ }
+
+ luPixel height = QMAX(umHeight, QMAX(ulOffset, urOffset));
+
+ // the upper half
+ content->setY(height);
+ toMidline += height;
+ if (hasUpperLeft()) {
+ upperLeft->setY(height-ulOffset);
+ }
+ if (hasUpperMiddle()) {
+ upperMiddle->setY(height-umHeight);
+ }
+ if (hasUpperRight()) {
+ upperRight->setY( height - urOffset );
+ }
+
+ // the lower half
+ if (hasLowerLeft()) {
+ lowerLeft->setY(height+llOffset);
+ }
+ if (hasLowerMiddle()) {
+ lowerMiddle->setY(height+content->getHeight()+distY);
+ }
+ if (hasLowerRight()) {
+ lowerRight->setY( height + lrOffset );
+ }
+
+ fromMidline += QMAX(QMAX(llHeight+llOffset, lrHeight+lrOffset) - content->getHeight(), lmHeight);
+
+ // set the result
+ setWidth(width);
+ setHeight(toMidline+fromMidline);
+ if (content->isTextOnly()) {
+ setBaseline(content->getY() + content->getBaseline());
+ //setMidline(content->getY() + content->getMidline());
+ }
+ else {
+ //setMidline(toMidline);
+ setBaseline(content->getBaseline() + content->getY());
+ }
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void IndexElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ ContextStyle::TextStyle i_tstyle = context.convertTextStyleIndex(tstyle);
+ ContextStyle::IndexStyle u_istyle = context.convertIndexStyleUpper( istyle );
+ ContextStyle::IndexStyle l_istyle = context.convertIndexStyleLower( istyle );
+
+ content->draw(painter, r, context, tstyle, istyle, style, myPos);
+ if (hasUpperLeft()) {
+ upperLeft->draw(painter, r, context, i_tstyle, u_istyle, style, myPos);
+ }
+ if (hasUpperMiddle()) {
+ upperMiddle->draw(painter, r, context, i_tstyle, u_istyle, style, myPos);
+ }
+ if (hasUpperRight()) {
+ upperRight->draw(painter, r, context, i_tstyle, u_istyle, style, myPos);
+ }
+ if (hasLowerLeft()) {
+ lowerLeft->draw(painter, r, context, i_tstyle, l_istyle, style, myPos);
+ }
+ if (hasLowerMiddle()) {
+ lowerMiddle->draw(painter, r, context, i_tstyle, l_istyle, style, myPos);
+ }
+ if (hasLowerRight()) {
+ lowerRight->draw(painter, r, context, i_tstyle, l_istyle, style, myPos);
+ }
+
+ // Debug
+ //painter.setBrush(Qt::NoBrush);
+ //painter.setPen(Qt::red);
+ //painter.drawRect(myPos.x(), myPos.y(), getWidth(), getHeight());
+ //painter.drawLine(myPos.x(), myPos.y()+getMidline(),
+ // myPos.x()+getWidth(), myPos.y()+getMidline());
+}
+
+
+void IndexElement::dispatchFontCommand( FontCommand* cmd )
+{
+ content->dispatchFontCommand( cmd );
+ if (hasUpperLeft()) {
+ upperLeft->dispatchFontCommand( cmd );
+ }
+ if (hasUpperMiddle()) {
+ upperMiddle->dispatchFontCommand( cmd );
+ }
+ if (hasUpperRight()) {
+ upperRight->dispatchFontCommand( cmd );
+ }
+ if (hasLowerLeft()) {
+ lowerLeft->dispatchFontCommand( cmd );
+ }
+ if (hasLowerMiddle()) {
+ lowerMiddle->dispatchFontCommand( cmd );
+ }
+ if (hasLowerRight()) {
+ lowerRight->dispatchFontCommand( cmd );
+ }
+}
+
+
+// navigation
+//
+// The elements are responsible to handle cursor movement themselves.
+// To do this they need to know the direction the cursor moves and
+// the element it comes from.
+//
+// The cursor might be in normal or in selection mode.
+
+int IndexElement::getFromPos(BasicElement* from)
+{
+ if (from == lowerRight) {
+ return lowerRightPos;
+ }
+ else if (from == upperRight) {
+ return upperRightPos;
+ }
+ else if (from == lowerMiddle) {
+ return lowerMiddlePos;
+ }
+ else if (from == content) {
+ return contentPos;
+ }
+ else if (from == upperMiddle) {
+ return upperMiddlePos;
+ }
+ else if (from == lowerLeft) {
+ return lowerLeftPos;
+ }
+ else if (from == upperLeft) {
+ return upperLeftPos;
+ }
+ return parentPos;
+}
+
+/**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+void IndexElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ int fromPos = getFromPos(from);
+ if (!linear) {
+ if ((fromPos == lowerRightPos) && hasLowerMiddle()) {
+ lowerMiddle->moveLeft(cursor, this);
+ return;
+ }
+ else if ((fromPos == upperRightPos) && hasUpperMiddle()) {
+ upperMiddle->moveLeft(cursor, this);
+ return;
+ }
+ else if ((fromPos == lowerMiddlePos) && hasLowerLeft()) {
+ lowerLeft->moveLeft(cursor, this);
+ return;
+ }
+ else if ((fromPos == upperMiddlePos) && hasUpperLeft()) {
+ upperLeft->moveLeft(cursor, this);
+ return;
+ }
+ }
+ switch (fromPos) {
+ case parentPos:
+ if (hasLowerRight() && linear) {
+ lowerRight->moveLeft(cursor, this);
+ break;
+ }
+ case lowerRightPos:
+ if (hasUpperRight() && linear) {
+ upperRight->moveLeft(cursor, this);
+ break;
+ }
+ case upperRightPos:
+ if (hasLowerMiddle() && linear) {
+ lowerMiddle->moveLeft(cursor, this);
+ break;
+ }
+ case lowerMiddlePos:
+ content->moveLeft(cursor, this);
+ break;
+ case contentPos:
+ if (hasUpperMiddle() && linear) {
+ upperMiddle->moveLeft(cursor, this);
+ break;
+ }
+ case upperMiddlePos:
+ if (hasLowerLeft() && linear) {
+ lowerLeft->moveLeft(cursor, this);
+ break;
+ }
+ case lowerLeftPos:
+ if (hasUpperLeft() && linear) {
+ upperLeft->moveLeft(cursor, this);
+ break;
+ }
+ case upperLeftPos:
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+void IndexElement::moveRight(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ int fromPos = getFromPos(from);
+ if (!linear) {
+ if ((fromPos == lowerLeftPos) && hasLowerMiddle()) {
+ lowerMiddle->moveRight(cursor, this);
+ return;
+ }
+ else if ((fromPos == upperLeftPos) && hasUpperMiddle()) {
+ upperMiddle->moveRight(cursor, this);
+ return;
+ }
+ else if ((fromPos == lowerMiddlePos) && hasLowerRight()) {
+ lowerRight->moveRight(cursor, this);
+ return;
+ }
+ else if ((fromPos == upperMiddlePos) && hasUpperRight()) {
+ upperRight->moveRight(cursor, this);
+ return;
+ }
+ }
+ switch (fromPos) {
+ case parentPos:
+ if (hasUpperLeft() && linear) {
+ upperLeft->moveRight(cursor, this);
+ break;
+ }
+ case upperLeftPos:
+ if (hasLowerLeft() && linear) {
+ lowerLeft->moveRight(cursor, this);
+ break;
+ }
+ case lowerLeftPos:
+ if (hasUpperMiddle() && linear) {
+ upperMiddle->moveRight(cursor, this);
+ break;
+ }
+ case upperMiddlePos:
+ content->moveRight(cursor, this);
+ break;
+ case contentPos:
+ if (hasLowerMiddle() && linear) {
+ lowerMiddle->moveRight(cursor, this);
+ break;
+ }
+ case lowerMiddlePos:
+ if (hasUpperRight() && linear) {
+ upperRight->moveRight(cursor, this);
+ break;
+ }
+ case upperRightPos:
+ if (hasLowerRight() && linear) {
+ lowerRight->moveRight(cursor, this);
+ break;
+ }
+ case lowerRightPos:
+ getParent()->moveRight(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+void IndexElement::moveUp(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveUp(cursor, this);
+ }
+ else {
+ if (from == content) {
+ if ((cursor->getPos() == 0) && (cursor->getElement() == from)) {
+ if (hasUpperLeft()) {
+ upperLeft->moveLeft(cursor, this);
+ return;
+ }
+ else if (hasUpperMiddle()) {
+ upperMiddle->moveRight(cursor, this);
+ return;
+ }
+ }
+ if (hasUpperRight()) {
+ upperRight->moveRight(cursor, this);
+ }
+ else if (hasUpperMiddle()) {
+ upperMiddle->moveLeft(cursor, this);
+ }
+ else if (hasUpperLeft()) {
+ upperLeft->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveUp(cursor, this);
+ }
+ }
+ else if ((from == upperLeft) || (from == upperMiddle) || (from == upperRight)) {
+ getParent()->moveUp(cursor, this);
+ }
+ else if ((from == getParent()) || (from == lowerLeft) || (from == lowerMiddle)) {
+ content->moveRight(cursor, this);
+ }
+ else if (from == lowerRight) {
+ content->moveLeft(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+void IndexElement::moveDown(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveDown(cursor, this);
+ }
+ else {
+ if (from == content) {
+ if ((cursor->getPos() == 0) && (cursor->getElement() == from)) {
+ if (hasLowerLeft()) {
+ lowerLeft->moveLeft(cursor, this);
+ return;
+ }
+ else if (hasLowerMiddle()) {
+ lowerMiddle->moveRight(cursor, this);
+ return;
+ }
+ }
+ if (hasLowerRight()) {
+ lowerRight->moveRight(cursor, this);
+ }
+ else if (hasLowerMiddle()) {
+ lowerMiddle->moveLeft(cursor, this);
+ }
+ else if (hasLowerLeft()) {
+ lowerLeft->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveDown(cursor, this);
+ }
+ }
+ else if ((from == lowerLeft) || (from == lowerMiddle) || (from == lowerRight)) {
+ getParent()->moveDown(cursor, this);
+ }
+ else if ((from == getParent()) || (from == upperLeft) || (from == upperMiddle)) {
+ content->moveRight(cursor, this);
+ }
+ if (from == upperRight) {
+ content->moveLeft(cursor, this);
+ }
+ }
+}
+
+
+// children
+
+
+// main child
+//
+// If an element has children one has to become the main one.
+
+// void IndexElement::setMainChild(SequenceElement* child)
+// {
+// formula()->elementRemoval(content);
+// content = child;
+// content->setParent(this);
+// formula()->changed();
+// }
+
+
+/**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction.
+ *
+ * You only can insert one index at a time. So the list must contain
+ * exactly on SequenceElement. And the index you want to insert
+ * must not exist already.
+ *
+ * The list will be emptied but stays the property of the caller.
+ */
+void IndexElement::insert(FormulaCursor* cursor,
+ QPtrList<BasicElement>& newChildren,
+ Direction direction)
+{
+ SequenceElement* index = static_cast<SequenceElement*>(newChildren.take(0));
+ index->setParent(this);
+
+ switch (cursor->getPos()) {
+ case upperLeftPos:
+ upperLeft = index;
+ break;
+ case lowerLeftPos:
+ lowerLeft = index;
+ break;
+ case upperMiddlePos:
+ upperMiddle = index;
+ break;
+ case lowerMiddlePos:
+ lowerMiddle = index;
+ break;
+ case upperRightPos:
+ upperRight = index;
+ break;
+ case lowerRightPos:
+ lowerRight = index;
+ break;
+ default:
+ // this is an error!
+ return;
+ }
+
+ if (direction == beforeCursor) {
+ index->moveLeft(cursor, this);
+ }
+ else {
+ index->moveRight(cursor, this);
+ }
+ cursor->setSelection(false);
+ formula()->changed();
+}
+
+
+/**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * The cursor has to be inside one of our indexes which is supposed
+ * to be empty. The index will be removed and the cursor will
+ * be placed to the removed index so it can be inserted again.
+ * This methode is called by SequenceElement::remove only.
+ *
+ * The ownership of the list is passed to the caller.
+ */
+void IndexElement::remove(FormulaCursor* cursor,
+ QPtrList<BasicElement>& removedChildren,
+ Direction direction)
+{
+ int pos = cursor->getPos();
+ switch (pos) {
+ case upperLeftPos:
+ removedChildren.append(upperLeft);
+ formula()->elementRemoval(upperLeft);
+ upperLeft = 0;
+ setToUpperLeft(cursor);
+ break;
+ case lowerLeftPos:
+ removedChildren.append(lowerLeft);
+ formula()->elementRemoval(lowerLeft);
+ lowerLeft = 0;
+ setToLowerLeft(cursor);
+ break;
+ case contentPos: {
+ BasicElement* parent = getParent();
+ parent->selectChild(cursor, this);
+ parent->remove(cursor, removedChildren, direction);
+ break;
+ }
+ case upperMiddlePos:
+ removedChildren.append(upperMiddle);
+ formula()->elementRemoval(upperMiddle);
+ upperMiddle = 0;
+ setToUpperMiddle(cursor);
+ break;
+ case lowerMiddlePos:
+ removedChildren.append(lowerMiddle);
+ formula()->elementRemoval(lowerMiddle);
+ lowerMiddle = 0;
+ setToLowerMiddle(cursor);
+ break;
+ case upperRightPos:
+ removedChildren.append(upperRight);
+ formula()->elementRemoval(upperRight);
+ upperRight = 0;
+ setToUpperRight(cursor);
+ break;
+ case lowerRightPos:
+ removedChildren.append(lowerRight);
+ formula()->elementRemoval(lowerRight);
+ lowerRight = 0;
+ setToLowerRight(cursor);
+ break;
+ }
+ formula()->changed();
+}
+
+/**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+void IndexElement::normalize(FormulaCursor* cursor, Direction direction)
+{
+ if (direction == beforeCursor) {
+ content->moveLeft(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+}
+
+/**
+ * Returns wether the element has no more useful
+ * children (except its main child) and should therefore
+ * be replaced by its main child's content.
+ */
+bool IndexElement::isSenseless()
+{
+ return !hasUpperLeft() && !hasUpperRight() && !hasUpperMiddle() &&
+ !hasLowerLeft() && !hasLowerRight() && !hasLowerMiddle();
+}
+
+
+/**
+ * Returns the child at the cursor.
+ */
+BasicElement* IndexElement::getChild(FormulaCursor* cursor, Direction)
+{
+ int pos = cursor->getPos();
+ /*
+ It makes no sense to care for the direction.
+ if (direction == beforeCursor) {
+ pos -= 1;
+ }
+ */
+ switch (pos) {
+ case contentPos:
+ return content;
+ case upperLeftPos:
+ return upperLeft;
+ case lowerLeftPos:
+ return lowerLeft;
+ case upperMiddlePos:
+ return upperMiddle;
+ case lowerMiddlePos:
+ return lowerMiddle;
+ case upperRightPos:
+ return upperRight;
+ case lowerRightPos:
+ return lowerRight;
+ }
+ return 0;
+}
+
+
+/**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+void IndexElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ if (child == content) {
+ setToContent(cursor);
+ }
+ else if (child == upperLeft) {
+ setToUpperLeft(cursor);
+ }
+ else if (child == lowerLeft) {
+ setToLowerLeft(cursor);
+ }
+ else if (child == upperMiddle) {
+ setToUpperMiddle(cursor);
+ }
+ else if (child == lowerMiddle) {
+ setToLowerMiddle(cursor);
+ }
+ else if (child == upperRight) {
+ setToUpperRight(cursor);
+ }
+ else if (child == lowerRight) {
+ setToLowerRight(cursor);
+ }
+}
+
+
+/**
+ * Sets the cursor to point to the place where the content is.
+ * There always is a content so this is not a useful place.
+ * No insertion or removal will succeed as long as the cursor is
+ * there.
+ */
+void IndexElement::setToContent(FormulaCursor* cursor)
+{
+ cursor->setTo(this, contentPos);
+}
+
+// point the cursor to a gap where an index is to be inserted.
+// this makes no sense if there is such an index already.
+
+void IndexElement::setToUpperLeft(FormulaCursor* cursor)
+{
+ cursor->setTo(this, upperLeftPos);
+}
+
+void IndexElement::setToUpperMiddle(FormulaCursor* cursor)
+{
+ cursor->setTo(this, upperMiddlePos);
+}
+
+void IndexElement::setToUpperRight(FormulaCursor* cursor)
+{
+ cursor->setTo(this, upperRightPos);
+}
+
+void IndexElement::setToLowerLeft(FormulaCursor* cursor)
+{
+ cursor->setTo(this, lowerLeftPos);
+}
+
+void IndexElement::setToLowerMiddle(FormulaCursor* cursor)
+{
+ cursor->setTo(this, lowerMiddlePos);
+}
+
+void IndexElement::setToLowerRight(FormulaCursor* cursor)
+{
+ cursor->setTo(this, lowerRightPos);
+}
+
+
+// move inside an index that exists already.
+
+void IndexElement::moveToUpperLeft(FormulaCursor* cursor, Direction direction)
+{
+ if (hasUpperLeft()) {
+ if (direction == beforeCursor) {
+ upperLeft->moveLeft(cursor, this);
+ }
+ else {
+ upperLeft->moveRight(cursor, this);
+ }
+ }
+}
+
+void IndexElement::moveToUpperMiddle(FormulaCursor* cursor, Direction direction)
+{
+ if (hasUpperMiddle()) {
+ if (direction == beforeCursor) {
+ upperMiddle->moveLeft(cursor, this);
+ }
+ else {
+ upperMiddle->moveRight(cursor, this);
+ }
+ }
+}
+
+void IndexElement::moveToUpperRight(FormulaCursor* cursor, Direction direction)
+{
+ if (hasUpperRight()) {
+ if (direction == beforeCursor) {
+ upperRight->moveLeft(cursor, this);
+ }
+ else {
+ upperRight->moveRight(cursor, this);
+ }
+ }
+}
+
+void IndexElement::moveToLowerLeft(FormulaCursor* cursor, Direction direction)
+{
+ if (hasLowerLeft()) {
+ if (direction == beforeCursor) {
+ lowerLeft->moveLeft(cursor, this);
+ }
+ else {
+ lowerLeft->moveRight(cursor, this);
+ }
+ }
+}
+
+void IndexElement::moveToLowerMiddle(FormulaCursor* cursor, Direction direction)
+{
+ if (hasLowerMiddle()) {
+ if (direction == beforeCursor) {
+ lowerMiddle->moveLeft(cursor, this);
+ }
+ else {
+ lowerMiddle->moveRight(cursor, this);
+ }
+ }
+}
+
+void IndexElement::moveToLowerRight(FormulaCursor* cursor, Direction direction)
+{
+ if (hasLowerRight()) {
+ if (direction == beforeCursor) {
+ lowerRight->moveLeft(cursor, this);
+ }
+ else {
+ lowerRight->moveRight(cursor, this);
+ }
+ }
+}
+
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void IndexElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ QDomDocument doc = element.ownerDocument();
+
+ QDomElement cont = doc.createElement("CONTENT");
+ cont.appendChild(content->getElementDom(doc));
+ element.appendChild(cont);
+
+ if (hasUpperLeft()) {
+ QDomElement ind = doc.createElement("UPPERLEFT");
+ ind.appendChild(upperLeft->getElementDom(doc));
+ element.appendChild(ind);
+ }
+ if (hasUpperMiddle()) {
+ QDomElement ind = doc.createElement("UPPERMIDDLE");
+ ind.appendChild(upperMiddle->getElementDom(doc));
+ element.appendChild(ind);
+ }
+ if (hasUpperRight()) {
+ QDomElement ind = doc.createElement("UPPERRIGHT");
+ ind.appendChild(upperRight->getElementDom(doc));
+ element.appendChild(ind);
+ }
+ if (hasLowerLeft()) {
+ QDomElement ind = doc.createElement("LOWERLEFT");
+ ind.appendChild(lowerLeft->getElementDom(doc));
+ element.appendChild(ind);
+ }
+ if (hasLowerMiddle()) {
+ QDomElement ind = doc.createElement("LOWERMIDDLE");
+ ind.appendChild(lowerMiddle->getElementDom(doc));
+ element.appendChild(ind);
+ }
+ if (hasLowerRight()) {
+ QDomElement ind = doc.createElement("LOWERRIGHT");
+ ind.appendChild(lowerRight->getElementDom(doc));
+ element.appendChild(ind);
+ }
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool IndexElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool IndexElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ if ( !buildChild( content, node, "CONTENT" ) ) {
+ kdWarning( DEBUGID ) << "Empty content in IndexElement." << endl;
+ return false;
+ }
+ node = node.nextSibling();
+
+ bool upperLeftRead = false;
+ bool upperMiddleRead = false;
+ bool upperRightRead = false;
+ bool lowerLeftRead = false;
+ bool lowerMiddleRead = false;
+ bool lowerRightRead = false;
+
+ while (!node.isNull() &&
+ !(upperLeftRead && upperMiddleRead && upperRightRead &&
+ lowerLeftRead && lowerMiddleRead && lowerRightRead)) {
+
+ if (!upperLeftRead && (node.nodeName().upper() == "UPPERLEFT")) {
+ upperLeftRead = buildChild( upperLeft=new SequenceElement( this ), node, "UPPERLEFT" );
+ if ( !upperLeftRead ) return false;
+ }
+
+ if (!upperMiddleRead && (node.nodeName().upper() == "UPPERMIDDLE")) {
+ upperMiddleRead = buildChild( upperMiddle=new SequenceElement( this ), node, "UPPERMIDDLE" );
+ if ( !upperMiddleRead ) return false;
+ }
+
+ if (!upperRightRead && (node.nodeName().upper() == "UPPERRIGHT")) {
+ upperRightRead = buildChild( upperRight=new SequenceElement( this ), node, "UPPERRIGHT" );
+ if ( !upperRightRead ) return false;
+ }
+
+ if (!lowerLeftRead && (node.nodeName().upper() == "LOWERLEFT")) {
+ lowerLeftRead = buildChild( lowerLeft=new SequenceElement( this ), node, "LOWERLEFT" );
+ if ( !lowerLeftRead ) return false;
+ }
+
+ if (!lowerMiddleRead && (node.nodeName().upper() == "LOWERMIDDLE")) {
+ lowerMiddleRead = buildChild( lowerMiddle=new SequenceElement( this ), node, "LOWERMIDDLE" );
+ if ( !lowerMiddleRead ) return false;
+ }
+
+ if (!lowerRightRead && (node.nodeName().upper() == "LOWERRIGHT")) {
+ lowerRightRead = buildChild( lowerRight=new SequenceElement( this ), node, "LOWERRIGHT" );
+ if ( !lowerRightRead ) return false;
+ }
+
+ node = node.nextSibling();
+ }
+ return upperLeftRead || upperMiddleRead || upperRightRead ||
+ lowerLeftRead || lowerMiddleRead || lowerRightRead;
+}
+
+bool IndexElement::readAttributesFromMathMLDom( const QDomElement& element )
+{
+ if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ QString tag = element.tagName().stripWhiteSpace().lower();
+ if ( tag == "msub" || tag == "msubsup" ) {
+ QString subscriptshiftStr = element.attribute( "subscriptshift" ).stripWhiteSpace().lower();
+ if ( ! subscriptshiftStr.isNull() ) {
+ m_subScriptShift = getSize( subscriptshiftStr, &m_subScriptShiftType );
+ }
+ }
+ if ( tag == "msup" || tag == "msubsup" ) {
+ QString superscriptshiftStr = element.attribute( "superscriptshift" ).stripWhiteSpace().lower();
+ if ( ! superscriptshiftStr.isNull() ) {
+ m_superScriptShift = getSize( superscriptshiftStr, &m_superScriptShiftType );
+ }
+ }
+
+ if ( tag == "munder" || tag == "munderover" ) {
+ QString accentunderStr = element.attribute( "accentunder" ).stripWhiteSpace().lower();
+ if ( ! accentunderStr.isNull() ) {
+ if ( accentunderStr == "true" ) {
+ m_customAccentUnder = true;
+ m_accentUnder = true;
+ }
+ else if ( accentunderStr == "false" ) {
+ m_customAccentUnder = true;
+ m_accentUnder = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `accentunder': "
+ << accentunderStr << endl;
+ }
+ }
+ }
+ if ( tag == "mover" || tag == "munderover" ) {
+ QString accentStr = element.attribute( "accent" ).stripWhiteSpace().lower();
+ if ( ! accentStr.isNull() ) {
+ if ( accentStr == "true" ) {
+ m_customAccent = true;
+ m_accent = true;
+ }
+ else if ( accentStr == "false" ) {
+ m_customAccent = true;
+ m_accent = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `accent': "
+ << accentStr << endl;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read. It is sometimes needed to read more than one node
+ * (e. g. for fence operators).
+ * Returns the number of nodes processed or -1 if it failed.
+ */
+int IndexElement::readContentFromMathMLDom( QDomNode& node )
+{
+ if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
+ return -1;
+ }
+
+ int contentNumber = content->buildMathMLChild( node );
+ if ( contentNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty base in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < contentNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ QString indexType = node.parentNode().toElement().tagName().lower();
+ if ( indexType == "msub" ) {
+ lowerRight = new SequenceElement( this );
+ int lowerRightNumber = lowerRight->buildMathMLChild( node );
+ if ( lowerRightNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty subscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < lowerRightNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ return 1;
+ }
+
+ if ( indexType == "msup" ) {
+ upperRight = new SequenceElement( this );
+ int upperRightNumber = upperRight->buildMathMLChild( node );
+ if ( upperRightNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty superscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < upperRightNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ return 1;
+ }
+
+ if ( indexType == "msubsup" ) {
+ lowerRight = new SequenceElement( this );
+ int lowerRightNumber = lowerRight->buildMathMLChild( node );
+ if ( lowerRightNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty subscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < lowerRightNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ upperRight = new SequenceElement( this );
+ int upperRightNumber = upperRight->buildMathMLChild( node );
+ if ( upperRightNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty superscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < upperRightNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ return 1;
+ }
+ if ( indexType == "munder" ) {
+ lowerMiddle = new SequenceElement( this );
+ int lowerMiddleNumber = lowerMiddle->buildMathMLChild( node );
+ if ( lowerMiddleNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty underscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < lowerMiddleNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ return 1;
+ }
+
+ if ( indexType == "mover" ) {
+ upperMiddle = new SequenceElement( this );
+ int upperMiddleNumber = upperMiddle->buildMathMLChild( node );
+ if ( upperMiddleNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty overscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < upperMiddleNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ return 1;
+ }
+
+ if ( indexType == "munderover" ) {
+ lowerMiddle = new SequenceElement( this );
+ int lowerMiddleNumber = lowerMiddle->buildMathMLChild( node );
+ if ( lowerMiddleNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty underscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < lowerMiddleNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+
+ upperMiddle = new SequenceElement( this );
+ int upperMiddleNumber = upperMiddle->buildMathMLChild( node );
+ if ( upperMiddleNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty overscript in Script" << endl;
+ return -1;
+ }
+ for (int i = 0; i < upperMiddleNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ return 1;
+ }
+ // TODO: mmultiscripts, section 3.4.7
+ return 1;
+}
+
+
+ElementIndexPtr IndexElement::getIndex( int position )
+{
+ switch (position) {
+ case upperRightPos:
+ return getUpperRight();
+ case lowerRightPos:
+ return getLowerRight();
+ case lowerMiddlePos:
+ return getLowerMiddle();
+ case upperMiddlePos:
+ return getUpperMiddle();
+ case lowerLeftPos:
+ return getLowerLeft();
+ case upperLeftPos:
+ return getUpperLeft();
+ }
+ return getUpperRight();
+}
+
+
+
+QString IndexElement::toLatex()
+{
+ QString index;
+
+ if ( hasUpperMiddle() ) {
+ index += "\\overset{" + upperMiddle->toLatex() + "}{";
+ }
+
+ if ( hasLowerMiddle() ) {
+ index += "\\underset{" + lowerMiddle->toLatex() + "}{";
+ }
+
+ if ( hasUpperLeft() || hasUpperRight() ) { //Not sure that this is possible in Latex!
+ /*index += "{}";
+ if ( hasUpperLeft() )
+ index += "^" + upperLeft->toLatex();
+ if ( hasLowerLeft() )
+ index += "_" + lowerLeft->toLatex();
+ */
+ }
+
+ index += content->toLatex();
+
+ if ( hasUpperRight() || hasLowerRight() ) {
+ if ( hasUpperRight() )
+ index += "^{" + upperRight->toLatex() + "}";
+ if ( hasLowerRight() )
+ index += "_{" + lowerRight->toLatex() + "}";
+ index += " ";
+ }
+
+ if ( hasLowerMiddle() ) {
+ index += "}";
+ }
+
+ if ( hasUpperMiddle() ) {
+ index += "}";
+ }
+
+ return index;
+}
+
+QString IndexElement::formulaString()
+{
+ QString index = "(" + content->formulaString() + ")";
+ if ( hasLowerRight() ) {
+ index += "_(" + lowerRight->formulaString() + ")";
+ }
+ if ( hasUpperRight() ) {
+ index += "**(" + upperRight->formulaString() + ")";
+ }
+ return index;
+}
+
+QString IndexElement::getElementName() const
+{
+ if ( hasUpperMiddle() && hasLowerMiddle() )
+ return "munderover";
+ if ( hasUpperMiddle() )
+ return "mover";
+ if ( hasLowerMiddle() )
+ return "munder";
+ if ( hasLowerLeft() || hasUpperLeft() )
+ return "mmultiscripts";
+ if ( hasLowerRight() || hasUpperRight() ) {
+ if ( ! hasUpperRight() )
+ return "msub";
+ if ( ! hasLowerRight() )
+ return "msup";
+ }
+ return "msubsup";
+}
+
+void IndexElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ QString tag = getElementName();
+ if ( tag == "msub" || tag == "msubsup" ) {
+ switch ( m_subScriptShiftType ) {
+ case AbsoluteSize:
+ element.setAttribute( "subscriptshift", QString( "%1pt" ).arg( m_subScriptShift ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "subscriptshift", QString( "%1%" ).arg( m_subScriptShift * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "subscriptshift", QString( "%1px" ).arg( m_subScriptShift ) );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( tag == "msup" || tag == "msubsup" ) {
+ switch ( m_superScriptShiftType ) {
+ case AbsoluteSize:
+ element.setAttribute( "superscriptshift", QString( "%1pt" ).arg( m_superScriptShift ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "superscriptshift", QString( "%1%" ).arg( m_superScriptShift * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "superscriptshift", QString( "%1px" ).arg( m_superScriptShift ) );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( tag == "munder" || tag == "munderover" ) {
+ if ( m_customAccentUnder ) {
+ element.setAttribute( "accentunder", m_accentUnder ? "true" : "false" );
+ }
+ }
+ if ( tag == "mover" || tag == "munderover" ) {
+ if ( m_customAccent ) {
+ element.setAttribute( "accent", m_accent ? "true" : "false" );
+ }
+ }
+}
+
+
+void IndexElement::writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const
+{
+ QDomElement de;
+
+ content->writeMathML( doc, element, oasisFormat ); // base
+ if ( hasUpperMiddle() && hasLowerMiddle() )
+ {
+ lowerMiddle->writeMathML( doc, element, oasisFormat );
+ upperMiddle->writeMathML( doc, element,oasisFormat );
+ }
+ else if ( hasUpperMiddle() )
+ {
+ upperMiddle->writeMathML( doc, element,oasisFormat );
+ }
+ else if ( hasLowerMiddle() )
+ {
+ lowerMiddle->writeMathML( doc, element,oasisFormat );
+ }
+
+ if ( hasLowerLeft() || hasUpperLeft() )
+ {
+ if ( hasLowerRight() )
+ lowerRight->writeMathML( doc, element, oasisFormat );
+ else
+ element.appendChild( doc.createElement( "none" ) );
+
+ if ( hasUpperRight() )
+ upperRight->writeMathML( doc, element, oasisFormat );
+ else
+ element.appendChild( doc.createElement( "none" ) );
+
+ element.appendChild( doc.createElement( "mprescripts" ) );
+
+ if ( hasLowerLeft() )
+ lowerLeft->writeMathML( doc, element, oasisFormat );
+ else
+ element.appendChild( doc.createElement( "none" ) );
+
+ if ( hasUpperLeft() )
+ upperLeft->writeMathML( doc, element, oasisFormat );
+ else
+ element.appendChild( doc.createElement( "none" ) );
+ }
+ else if ( hasLowerRight() || hasUpperRight() )
+ {
+ if ( !hasUpperRight() ) {
+ lowerRight->writeMathML( doc, element, oasisFormat );
+ }
+ else if ( !hasLowerRight() ) {
+ upperRight->writeMathML( doc, element, oasisFormat );
+ }
+ else // both
+ {
+ lowerRight->writeMathML( doc, element, oasisFormat );
+ upperRight->writeMathML( doc, element,oasisFormat );
+ }
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/indexelement.h b/lib/kformula/indexelement.h
new file mode 100644
index 00000000..06aac43d
--- /dev/null
+++ b/lib/kformula/indexelement.h
@@ -0,0 +1,442 @@
+/* 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.
+*/
+
+#ifndef INDEXELEMENT_H
+#define INDEXELEMENT_H
+
+// Formula include
+#include "basicelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+class SequenceElement;
+
+
+/**
+ * The element with up to four indexes in the four corners.
+ */
+class IndexElement : public BasicElement {
+ IndexElement& operator=( const IndexElement& ) { return *this; }
+public:
+
+ IndexElement(BasicElement* parent = 0);
+ ~IndexElement();
+
+ IndexElement( const IndexElement& );
+
+ virtual IndexElement* clone() {
+ return new IndexElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns the character that represents this element. Used for
+ * parsing a sequence.
+ * This is guaranteed to be QChar::null for all non-text elements.
+ */
+ virtual QChar getCharacter() const;
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ // drawing
+ //
+ // Drawing depends on a context which knows the required properties like
+ // fonts, spaces and such.
+ // It is essential to calculate elements size with the same context
+ // before you draw.
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ // navigation
+ //
+ // The elements are responsible to handle cursor movement themselves.
+ // To do this they need to know the direction the cursor moves and
+ // the element it comes from.
+ //
+ // The cursor might be in normal or in selection mode.
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor* cursor, BasicElement* from);
+
+ // children
+
+ /**
+ * Removes the child. If this was the main child this element might
+ * request its own removal.
+ * The cursor is the one that caused the removal. It has to be moved
+ * to the place any user expects the cursor after that particular
+ * element has been removed.
+ */
+ //virtual void removeChild(FormulaCursor* cursor, BasicElement* child);
+
+
+ // main child
+ //
+ // If an element has children one has to become the main one.
+
+ virtual SequenceElement* getMainChild() { return content; }
+ //SequenceElement* upperLeft;
+ //SequenceElement* upperMiddle;
+ SequenceElement* getExponent() { return upperRight; }
+ //SequenceElement* lowerLeft;
+ //SequenceElement* lowerMiddle;
+ //SequenceElement* lowerRight;
+
+
+ /**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction.
+ *
+ * You only can insert one index at a time. So the list must contain
+ * exactly on SequenceElement. And the index you want to insert
+ * must not exist already.
+ *
+ * The list will be emptied but stays the property of the caller.
+ */
+ virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * The cursor has to be inside one of our indexes which is supposed
+ * to be empty. The index will be removed and the cursor will
+ * be placed to the removed index so it can be inserted again.
+ * This methode is called by SequenceElement::remove only.
+ *
+ * The ownership of the list is passed to the caller.
+ */
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+ virtual void normalize(FormulaCursor*, Direction);
+
+ /**
+ * Returns the child at the cursor.
+ */
+ virtual BasicElement* getChild(FormulaCursor*, Direction = beforeCursor);
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor* cursor, BasicElement* child);
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ //virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child) = 0;
+
+ /**
+ * Returns wether the element has no more useful
+ * children (except its main child) and should therefore
+ * be replaced by its main child's content.
+ */
+ virtual bool isSenseless();
+
+
+ bool hasUpperLeft() const { return upperLeft != 0; }
+ bool hasUpperMiddle() const { return upperMiddle != 0; }
+ bool hasUpperRight() const { return upperRight != 0; }
+ bool hasLowerLeft() const { return lowerLeft != 0; }
+ bool hasLowerMiddle() const { return lowerMiddle != 0; }
+ bool hasLowerRight() const { return lowerRight != 0; }
+
+ // If we want to create an index we need a cursor that points there.
+
+ void setToUpperLeft(FormulaCursor* cursor);
+ void setToUpperMiddle(FormulaCursor* cursor);
+ void setToUpperRight(FormulaCursor* cursor);
+ void setToLowerLeft(FormulaCursor* cursor);
+ void setToLowerMiddle(FormulaCursor* cursor);
+ void setToLowerRight(FormulaCursor* cursor);
+
+ // If the index is there we need a way to move into it.
+
+ void moveToUpperLeft(FormulaCursor* cursor, Direction direction);
+ void moveToUpperMiddle(FormulaCursor* cursor, Direction direction);
+ void moveToUpperRight(FormulaCursor* cursor, Direction direction);
+ void moveToLowerLeft(FormulaCursor* cursor, Direction direction);
+ void moveToLowerMiddle(FormulaCursor* cursor, Direction direction);
+ void moveToLowerRight(FormulaCursor* cursor, Direction direction);
+
+ // Generic access to each index.
+
+ ElementIndexPtr getUpperLeft() { return ElementIndexPtr( new UpperLeftIndex( this ) ); }
+ ElementIndexPtr getLowerLeft() { return ElementIndexPtr( new LowerLeftIndex( this ) ); }
+ ElementIndexPtr getUpperMiddle() { return ElementIndexPtr( new UpperMiddleIndex( this ) ); }
+ ElementIndexPtr getLowerMiddle() { return ElementIndexPtr( new LowerMiddleIndex( this ) ); }
+ ElementIndexPtr getUpperRight() { return ElementIndexPtr( new UpperRightIndex( this ) ); }
+ ElementIndexPtr getLowerRight() { return ElementIndexPtr( new LowerRightIndex( this ) ); }
+
+ /**
+ * Returns the index at the position. Defaults to upperRight.
+ */
+ ElementIndexPtr getIndex( int position );
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ // the upper right index is the only one we show
+ virtual QString formulaString();
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "INDEX"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ virtual QString getElementName() const ;
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+ virtual void writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const ;
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ virtual bool readAttributesFromMathMLDom( const QDomElement& element );
+ /**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read. It is sometimes needed to read more than one node
+ * (e. g. for fence operators).
+ * Returns the number of nodes processed or -1 if it failed.
+ */
+ virtual int readContentFromMathMLDom( QDomNode& node );
+
+private:
+
+ /**
+ * An index that belongs to us.
+ */
+ class IndexElementIndex : public ElementIndex {
+ public:
+ IndexElementIndex(IndexElement* p) : parent(p) {}
+ virtual IndexElement* getElement() { return parent; }
+ protected:
+ IndexElement* parent;
+ };
+
+ // We have a (very simple) type for every index.
+
+ class UpperLeftIndex : public IndexElementIndex {
+ public:
+ UpperLeftIndex(IndexElement* parent) : IndexElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToUpperLeft(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToUpperLeft(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasUpperLeft(); }
+ };
+
+ class LowerLeftIndex : public IndexElementIndex {
+ public:
+ LowerLeftIndex(IndexElement* parent) : IndexElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToLowerLeft(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToLowerLeft(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasLowerLeft(); }
+ };
+
+ class UpperMiddleIndex : public IndexElementIndex {
+ public:
+ UpperMiddleIndex(IndexElement* parent) : IndexElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToUpperMiddle(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToUpperMiddle(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasUpperMiddle(); }
+ };
+
+ class LowerMiddleIndex : public IndexElementIndex {
+ public:
+ LowerMiddleIndex(IndexElement* parent) : IndexElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToLowerMiddle(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToLowerMiddle(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasLowerMiddle(); }
+ };
+
+ class UpperRightIndex : public IndexElementIndex {
+ public:
+ UpperRightIndex(IndexElement* parent) : IndexElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToUpperRight(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToUpperRight(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasUpperRight(); }
+ };
+
+ class LowerRightIndex : public IndexElementIndex {
+ public:
+ LowerRightIndex(IndexElement* parent) : IndexElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToLowerRight(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToLowerRight(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasLowerRight(); }
+ };
+
+
+ /**
+ * Sets the x value of the three middle elements. (Two indexes and the content.)
+ */
+ void setMiddleX(int xOffset, int middleWidth);
+
+ /**
+ * @returns the position describtion to the provided element.
+ */
+ int getFromPos(BasicElement* from);
+
+ /**
+ * Sets the cursor to point to the place where the content is.
+ * There always is a content so this is not a useful place.
+ * No insertion or removal will succeed as long as the cursor is
+ * there.
+ */
+ void setToContent(FormulaCursor* cursor);
+
+ /**
+ * Our main child. This is guaranteed not to be null.
+ */
+ SequenceElement* content;
+
+ /**
+ * The six indexes. Each one might be null.
+ * If the last one is removed the whole IndexElement
+ * should be replaced by its main child.
+ */
+ SequenceElement* upperLeft;
+ SequenceElement* upperMiddle;
+ SequenceElement* upperRight;
+ SequenceElement* lowerLeft;
+ SequenceElement* lowerMiddle;
+ SequenceElement* lowerRight;
+
+ /**
+ * MathML attributes.
+ */
+ SizeType m_subScriptShiftType;
+ double m_subScriptShift;
+ SizeType m_superScriptShiftType;
+ double m_superScriptShift;
+ bool m_accentUnder;
+ bool m_customAccentUnder;
+ bool m_accent;
+ bool m_customAccent;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // INDEXELEMENT_H
diff --git a/lib/kformula/kformulacommand.cc b/lib/kformula/kformulacommand.cc
new file mode 100644
index 00000000..24d49019
--- /dev/null
+++ b/lib/kformula/kformulacommand.cc
@@ -0,0 +1,625 @@
+/* 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 <klocale.h> //This is for undo descriptions
+
+#include <qvaluelist.h>
+
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "indexelement.h"
+#include "kformulacommand.h"
+#include "matrixelement.h"
+#include "sequenceelement.h"
+#include "textelement.h"
+#include "tokenelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+int PlainCommand::evilDestructionCount = 0;
+
+PlainCommand::PlainCommand( const QString& name )
+ : KNamedCommand(name)
+{
+ evilDestructionCount++;
+}
+
+PlainCommand::~PlainCommand()
+{
+ evilDestructionCount--;
+}
+
+Command::Command(const QString &name, Container* document)
+ : PlainCommand(name), cursordata(0), undocursor(0), doc(document)
+{
+}
+
+Command::~Command()
+{
+ delete undocursor;
+ delete cursordata;
+}
+
+FormulaCursor* Command::getExecuteCursor()
+{
+ FormulaCursor* cursor = getActiveCursor();
+ if (cursordata == 0) {
+ setExecuteCursor(getActiveCursor());
+ }
+ else {
+ cursor->setCursorData(cursordata);
+ }
+ return cursor;
+}
+
+void Command::setExecuteCursor(FormulaCursor* cursor)
+{
+ // assert(cursordata == 0);
+ cursordata = cursor->getCursorData();
+}
+
+FormulaCursor* Command::getUnexecuteCursor()
+{
+ FormulaCursor* cursor = getActiveCursor();
+ cursor->setCursorData(undocursor);
+ destroyUndoCursor();
+ return cursor;
+}
+
+void Command::setUnexecuteCursor(FormulaCursor* cursor)
+{
+ // assert(undocursor == 0);
+ undocursor = cursor->getCursorData();
+}
+
+
+// ****** Generic Add command
+
+KFCAdd::KFCAdd(const QString &name, Container *document)
+ : Command(name, document)
+{
+ addList.setAutoDelete( true );
+}
+
+
+void KFCAdd::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ cursor->insert(addList, beforeCursor);
+ setUnexecuteCursor(cursor);
+ cursor->setSelection(false);
+ testDirty();
+}
+
+
+void KFCAdd::unexecute()
+{
+ FormulaCursor* cursor = getUnexecuteCursor();
+ cursor->remove(addList, beforeCursor);
+ //cursor->setSelection(false);
+ cursor->normalize();
+ testDirty();
+}
+
+
+// ****** Remove selection command
+
+KFCRemoveSelection::KFCRemoveSelection(Container *document,
+ Direction direction)
+ : Command(i18n("Remove Selected Text"), document),
+ dir(direction)
+{
+ removedList.setAutoDelete( true );
+}
+
+void KFCRemoveSelection::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ cursor->remove(removedList, dir);
+ setUnexecuteCursor(cursor);
+ testDirty();
+}
+
+void KFCRemoveSelection::unexecute()
+{
+ FormulaCursor* cursor = getUnexecuteCursor();
+ cursor->insert(removedList);
+ cursor->setSelection(false);
+ testDirty();
+}
+
+
+
+KFCReplace::KFCReplace(const QString &name, Container* document)
+ : KFCAdd(name, document), removeSelection(0)
+{
+}
+
+KFCReplace::~KFCReplace()
+{
+ delete removeSelection;
+}
+
+void KFCReplace::execute()
+{
+ if (getActiveCursor()->isSelection() && (removeSelection == 0)) {
+ removeSelection = new KFCRemoveSelection(getDocument());
+ }
+ if (removeSelection != 0) {
+ removeSelection->execute();
+ }
+ KFCAdd::execute();
+}
+
+void KFCReplace::unexecute()
+{
+ KFCAdd::unexecute();
+ if (removeSelection != 0) {
+ removeSelection->unexecute();
+ }
+}
+
+
+// ****** Token Add command
+
+KFCAddToken::KFCAddToken(const QString &name, Container *document)
+ : Command(name, document)
+{
+}
+
+KFCAddToken::~KFCAddToken()
+{
+ QPtrDictIterator< QPtrList< BasicElement > > it( contentList );
+ QPtrList< BasicElement >* list;
+ while ( ( list = it.current() ) != 0 ) {
+ delete list;
+ ++it;
+ }
+}
+
+void KFCAddToken::execute()
+{
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ FormulaCursor* cursor = getExecuteCursor();
+ QPtrList<BasicElement> tokenListTmp = tokenList;
+ cursor->insert( tokenList, beforeCursor );
+ tokenList = tokenListTmp;
+ QPtrListIterator< BasicElement > it( tokenList );
+ BasicElement* element;
+ BasicElement* current = cursor->getElement();
+ while ( (element = it.current()) != 0 ) {
+ element->goInside( cursor );
+ cursor->insert( *contentList.find( element ), beforeCursor );
+ ++it;
+ }
+ setUnexecuteCursor( cursor );
+ cursor->setSelection(false);
+ testDirty();
+}
+
+
+void KFCAddToken::unexecute()
+{
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ FormulaCursor* cursor = getUnexecuteCursor();
+ SequenceElement* parent = static_cast<SequenceElement*>(cursor->getElement()->getParent());
+
+ for ( int i = 0; i < tokenList.count(); i++ ) {
+ SequenceElement* current = static_cast<SequenceElement*>(cursor->getElement());
+ QPtrList< BasicElement > list;
+ for ( uint i = 0; i < current->countChildren(); ++i ) {
+ cursor->remove( list, beforeCursor );
+ }
+ if ( parent ) {
+ int pos = parent->childPos( current );
+ cursor->setTo( parent, pos + 1);
+ cursor->remove( list, beforeCursor );
+ if ( pos > 0 ) {
+ BasicElement* element = parent->getChild( pos - 1 );
+ if (element)
+ element->moveEnd( cursor );
+ }
+ }
+ }
+ testDirty();
+}
+
+/**
+ * Collect all tokens that are to be added
+ */
+void KFCAddToken::addToken( BasicElement* element )
+{
+ tokenList.append( element );
+ contentList.insert( element, new QPtrList< BasicElement > );
+ contentList.find( element )->setAutoDelete( true );
+}
+
+KFCReplaceToken::KFCReplaceToken(const QString &name, Container* document)
+ : KFCAddToken(name, document), removeSelection(0)
+{
+}
+
+KFCReplaceToken::~KFCReplaceToken()
+{
+ delete removeSelection;
+}
+
+void KFCReplaceToken::execute()
+{
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ if (getActiveCursor()->isSelection() && (removeSelection == 0)) {
+ removeSelection = new KFCRemoveSelection(getDocument());
+ }
+ if (removeSelection != 0) {
+ removeSelection->execute();
+ }
+ KFCAddToken::execute();
+}
+
+void KFCReplaceToken::unexecute()
+{
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ KFCAddToken::unexecute();
+ if (removeSelection != 0) {
+ removeSelection->unexecute();
+ }
+}
+
+
+KFCSplitToken::KFCSplitToken(const QString &name, Container* document)
+ : KFCAddToken(name, document), removeSelection(0)
+{
+ splitList.setAutoDelete( true );
+}
+
+KFCSplitToken::~KFCSplitToken()
+{
+ delete splitCursor;
+ delete removeSelection;
+}
+
+void KFCSplitToken::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ if (getActiveCursor()->isSelection() && (removeSelection == 0)) {
+ removeSelection = new KFCRemoveSelection(getDocument());
+ }
+ if (removeSelection != 0) {
+ removeSelection->execute();
+ }
+ splitCursor = cursor->getCursorData();
+ SequenceElement* parent = static_cast<SequenceElement*>( cursor->getElement() );
+ if ( parent ) {
+ cursor->setMark( parent->countChildren() );
+ cursor->setSelection( true );
+ }
+ cursor->remove( splitList, afterCursor );
+ TokenElement *token = new TokenElement();// TODO
+ addToken( token );
+ QPtrListIterator< BasicElement > it ( splitList );
+ BasicElement* element;
+ while ( ( element = it.current() ) != 0 ) {
+ addContent( token, element );
+ ++it;
+ }
+ KFCAddToken::execute();
+ cursor = getExecuteCursor();
+ if ( parent ) {
+ BasicElement* child = parent->getChild( cursor->getPos() );
+ if ( child ) {
+ child->moveEnd( cursor );
+ }
+ }
+}
+
+void KFCSplitToken::unexecute()
+{
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ KFCAddToken::unexecute();
+ FormulaCursor *cursor = getUnexecuteCursor();
+ cursor->setCursorData( splitCursor );
+ cursor->insert( splitList, afterCursor );
+ if (removeSelection != 0) {
+ removeSelection->unexecute();
+ }
+ testDirty();
+}
+
+
+KFCRemove::KFCRemove(Container *document,
+ Direction direction)
+ : Command(i18n("Remove Selected Text"), document),
+ element(0), simpleRemoveCursor(0), dir(direction)
+{
+ removedList.setAutoDelete( true );
+}
+
+KFCRemove::~KFCRemove()
+{
+ delete simpleRemoveCursor;
+ delete element;
+}
+
+void KFCRemove::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ cursor->remove(removedList, dir);
+ if (cursor->elementIsSenseless()) {
+ simpleRemoveCursor = cursor->getCursorData();
+ element = cursor->replaceByMainChildContent();
+ }
+ setUnexecuteCursor(cursor);
+ cursor->normalize( dir );
+ testDirty();
+}
+
+void KFCRemove::unexecute()
+{
+ FormulaCursor* cursor = getUnexecuteCursor();
+ if (element != 0) {
+ cursor->replaceSelectionWith(element);
+ element = 0;
+
+ cursor->setCursorData(simpleRemoveCursor);
+ delete simpleRemoveCursor;
+ simpleRemoveCursor = 0;
+ }
+ cursor->insert(removedList, dir);
+ cursor->setSelection(false);
+ testDirty();
+}
+
+
+KFCRemoveEnclosing::KFCRemoveEnclosing(Container* document,
+ Direction dir)
+ : Command(i18n("Remove Enclosing Element"), document),
+ element(0), direction(dir)
+{
+}
+
+KFCRemoveEnclosing::~KFCRemoveEnclosing()
+{
+ delete element;
+}
+
+void KFCRemoveEnclosing::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ element = cursor->removeEnclosingElement(direction);
+ setUnexecuteCursor(cursor);
+ //cursor->normalize();
+ cursor->setSelection(false);
+ testDirty();
+}
+
+void KFCRemoveEnclosing::unexecute()
+{
+ FormulaCursor* cursor = getUnexecuteCursor();
+ if ( element ) {
+ cursor->replaceSelectionWith(element);
+ }
+ cursor->normalize();
+ cursor->setSelection(false);
+ element = 0;
+ testDirty();
+}
+
+
+// ****** Add root, bracket etc command
+
+KFCAddReplacing::KFCAddReplacing(const QString &name, Container* document)
+ : Command(name, document), element(0)
+{
+}
+
+KFCAddReplacing::~KFCAddReplacing()
+{
+ delete element;
+}
+
+
+void KFCAddReplacing::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ cursor->replaceSelectionWith(element);
+ setUnexecuteCursor(cursor);
+ cursor->goInsideElement(element);
+ element = 0;
+ testDirty();
+}
+
+
+void KFCAddReplacing::unexecute()
+{
+ FormulaCursor* cursor = getUnexecuteCursor();
+ element = cursor->replaceByMainChildContent();
+ cursor->normalize();
+ testDirty();
+}
+
+
+// ****** Add index command
+
+KFCAddGenericIndex::KFCAddGenericIndex(Container* document, ElementIndexPtr _index)
+ : KFCAdd(i18n("Add Index"), document), index(_index)
+{
+ addElement(new SequenceElement());
+}
+
+void KFCAddGenericIndex::execute()
+{
+ index->setToIndex(getActiveCursor());
+ KFCAdd::execute();
+}
+
+
+KFCAddIndex::KFCAddIndex(Container* document,
+ IndexElement* element, ElementIndexPtr index)
+ : KFCAddReplacing(i18n("Add Index"), document),
+ addIndex(document, index)
+{
+ setElement(element);
+}
+
+KFCAddIndex::~KFCAddIndex()
+{
+}
+
+void KFCAddIndex::execute()
+{
+ KFCAddReplacing::execute();
+ addIndex.execute();
+}
+
+void KFCAddIndex::unexecute()
+{
+ addIndex.unexecute();
+ KFCAddReplacing::unexecute();
+}
+
+
+KFCChangeBaseSize::KFCChangeBaseSize( const QString& name, Container* document,
+ FormulaElement* formula, int size )
+ : PlainCommand( name ), m_document( document ), m_formula( formula ), m_size( size )
+{
+ m_oldSize = formula->getBaseSize();
+}
+
+void KFCChangeBaseSize::execute()
+{
+ m_formula->setBaseSize( m_size );
+ m_document->recalc();
+}
+
+void KFCChangeBaseSize::unexecute()
+{
+ m_formula->setBaseSize( m_oldSize );
+ m_document->recalc();
+}
+
+
+FontCommand::FontCommand( const QString& name, Container* document )
+ : Command( name, document )
+{
+ list.setAutoDelete( false );
+ elementList.setAutoDelete( false );
+}
+
+
+void FontCommand::collectChildren()
+{
+ list.clear();
+ uint count = elementList.count();
+ for ( uint i=0; i<count; ++i ) {
+ elementList.at( i )->dispatchFontCommand( this );
+ }
+}
+
+
+void FontCommand::parseSequences( const QMap<SequenceElement*, int>& parents )
+{
+ QValueList<SequenceElement*> sequences = parents.keys();
+ for ( QValueList<SequenceElement*>::iterator i = sequences.begin();
+ i != sequences.end();
+ ++i ) {
+ ( *i )->parse();
+ }
+}
+
+
+CharStyleCommand::CharStyleCommand( CharStyle cs, const QString& name, Container* document )
+ : FontCommand( name, document ), charStyle( cs )
+{
+}
+
+void CharStyleCommand::execute()
+{
+ collectChildren();
+ QMap<SequenceElement*, int> parentCollector;
+
+ styleList.clear();
+ uint count = childrenList().count();
+ styleList.reserve( count );
+ for ( uint i=0; i<count; ++i ) {
+ TextElement* child = childrenList().at( i );
+ styleList[i] = child->getCharStyle();
+ child->setCharStyle( charStyle );
+ parentCollector[static_cast<SequenceElement*>( child->getParent() )] = 1;
+ }
+ parseSequences( parentCollector );
+ testDirty();
+}
+
+void CharStyleCommand::unexecute()
+{
+ QMap<SequenceElement*, int> parentCollector;
+ uint count = childrenList().count();
+ //styleList.reserve( count );
+ for ( uint i=0; i<count; ++i ) {
+ TextElement* child = childrenList().at( i );
+ child->setCharStyle( styleList[i] );
+ parentCollector[static_cast<SequenceElement*>( child->getParent() )] = 1;
+ }
+ parseSequences( parentCollector );
+ testDirty();
+}
+
+
+CharFamilyCommand::CharFamilyCommand( CharFamily cf, const QString& name, Container* document )
+ : FontCommand( name, document ), charFamily( cf )
+{
+}
+
+void CharFamilyCommand::execute()
+{
+ collectChildren();
+
+ QMap<SequenceElement*, int> parentCollector;
+
+ familyList.clear();
+ uint count = childrenList().count();
+ familyList.reserve( count );
+ for ( uint i=0; i<count; ++i ) {
+ TextElement* child = childrenList().at( i );
+ familyList[i] = child->getCharFamily();
+ child->setCharFamily( charFamily );
+ parentCollector[static_cast<SequenceElement*>( child->getParent() )] = 1;
+ }
+ parseSequences( parentCollector );
+ testDirty();
+}
+
+void CharFamilyCommand::unexecute()
+{
+ QMap<SequenceElement*, int> parentCollector;
+ uint count = childrenList().count();
+ //familyList.reserve( count );
+ for ( uint i=0; i<count; ++i ) {
+ TextElement* child = childrenList().at( i );
+ child->setCharFamily( familyList[i] );
+ parentCollector[static_cast<SequenceElement*>( child->getParent() )] = 1;
+ }
+ parseSequences( parentCollector );
+ testDirty();
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/kformulacommand.h b/lib/kformula/kformulacommand.h
new file mode 100644
index 00000000..0e13928e
--- /dev/null
+++ b/lib/kformula/kformulacommand.h
@@ -0,0 +1,562 @@
+/* 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.
+*/
+
+#ifndef KFORMULACOMMAND_H
+#define KFORMULACOMMAND_H
+
+#include <qmap.h>
+#include <qptrlist.h>
+#include <qptrdict.h>
+#include <qvaluevector.h>
+
+#include <kcommand.h>
+
+#include "fontstyle.h"
+#include "kformulacontainer.h"
+#include "formulacursor.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+/**
+ * Base for all kformula commands.
+ *
+ * Each command works in the same way. The constructor sets up
+ * everything. After the command is created you can execute
+ * it. To create a command doesn't mean to execute it. These are
+ * two different things.
+ *
+ * If the command execution fails or has nothing to do in the first place
+ * you must not put it in the command history. isSenseless()
+ * will return true then.
+ *
+ * If you don't like what you've done feel free to unexecute() .
+ */
+class PlainCommand : public KNamedCommand
+{
+public:
+
+ /**
+ * Sets up the command. Be careful not to change the cursor in
+ * the constructor of any command. Each command must use the selection
+ * it finds when it is executed for the first time. This way
+ * you can use the @ref KMacroCommand .
+ *
+ * @param name a description to be used as menu entry.
+ */
+ PlainCommand(const QString& name);
+ virtual ~PlainCommand();
+
+ /**
+ * debug only.
+ */
+ static int getEvilDestructionCount() { return evilDestructionCount; }
+
+private:
+
+ // debug
+ static int evilDestructionCount;
+};
+
+
+class Command : public PlainCommand
+{
+public:
+
+ /**
+ * Sets up the command. Be careful not to change the cursor in
+ * the constructor of any command. Each command must use the selection
+ * it finds when it is executed for the first time. This way
+ * you can use the @ref KMacroCommand .
+ *
+ * @param name a description to be used as menu entry.
+ * @param document the container we are working for.
+ */
+ Command(const QString& name, Container* document);
+ virtual ~Command();
+
+protected:
+
+ /**
+ * @returns the cursor that is to be used to @ref execute the
+ * command.
+ */
+ FormulaCursor* getExecuteCursor();
+
+ /**
+ * @returns the cursor that is to be used to @ref unexecute the
+ * command.
+ */
+ FormulaCursor* getUnexecuteCursor();
+
+ /**
+ * Saves the cursor that is used to execute the command.
+ */
+ void setExecuteCursor(FormulaCursor* cursor);
+
+ /**
+ * Sets the cursor that is to be used to @ref unexecute the
+ * command. This has to be called by @ref execute after the
+ * formula has been changed but before the cursor has been
+ * normalized.
+ */
+ void setUnexecuteCursor(FormulaCursor* cursor);
+
+ /**
+ * @returns the cursor that is active. It will be used to @ref execute
+ * the command.
+ */
+ FormulaCursor* getActiveCursor() { return doc->activeCursor(); }
+
+ /**
+ * Tells the document to check if the formula changed.
+ * Needs to be called by each @ref execute and @ref unexecute .
+ */
+ void testDirty() { doc->testDirty(); }
+
+ /**
+ * @returns our document.
+ */
+ Container* getDocument() const { return doc; }
+
+private:
+
+ void destroyUndoCursor() { delete undocursor; undocursor = 0; }
+
+ /**
+ * Cursor position before the command execution.
+ */
+ FormulaCursor::CursorData* cursordata;
+
+ /**
+ * Cursor position after the command execution.
+ */
+ FormulaCursor::CursorData* undocursor;
+
+ /**
+ * The container we belong to.
+ */
+ Container* doc;
+};
+
+
+/**
+ * Base for all commands that want to add a simple element.
+ */
+class KFCAdd : public Command
+{
+public:
+
+ KFCAdd(const QString &name, Container* document);
+
+ virtual void execute();
+ virtual void unexecute();
+
+ /**
+ * Collects all elements that are to be added.
+ */
+ void addElement(BasicElement* element) { addList.append(element); }
+
+private:
+
+ /**
+ * the list where all elements are stored that are removed
+ * from the tree.
+ */
+ QPtrList<BasicElement> addList;
+};
+
+
+/**
+ * Command that is used to remove the current selection
+ * if we want to replace it with another element.
+ */
+class KFCRemoveSelection : public Command
+{
+public:
+
+ /**
+ * generic add command, default implementation do nothing
+ */
+ KFCRemoveSelection(Container* document,
+ Direction dir = beforeCursor);
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+
+ /**
+ * the list where all elements are stored that are removed
+ * from the tree.
+ */
+ QPtrList<BasicElement> removedList;
+
+ Direction dir;
+};
+
+
+/**
+ * Removes the current selection and adds any new elements
+ * afterwards.
+ */
+class KFCReplace : public KFCAdd
+{
+public:
+
+ KFCReplace(const QString &name, Container* document);
+ ~KFCReplace();
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+
+ /**
+ * The command that needs to be executed first if there is a selection.
+ */
+ KFCRemoveSelection* removeSelection;
+};
+
+/**
+ * Command to add a token element, with content.
+ */
+class KFCAddToken : public Command
+{
+public:
+ KFCAddToken( const QString &name, Container *document);
+ ~KFCAddToken();
+
+ virtual void execute();
+ virtual void unexecute();
+
+ /**
+ * Collect all tokens that are to be added
+ */
+ void addToken( BasicElement* element );
+
+ /**
+ * Collect content for each token
+ */
+ void addContent( BasicElement* element, BasicElement* content ) {
+ contentList.find( element )->append( content );
+ }
+
+
+private:
+
+ /**
+ * List where all token elements are stored.
+ */
+ QPtrList< BasicElement > tokenList;
+
+ /**
+ * Dictionary where all content elements are stored
+ */
+ QPtrDict< QPtrList< BasicElement > > contentList;
+};
+
+/**
+ * Removes the current selection and adds any new tokens
+ * afterwards.
+ */
+class KFCReplaceToken : public KFCAddToken
+{
+public:
+
+ KFCReplaceToken(const QString &name, Container* document);
+ ~KFCReplaceToken();
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+
+ /**
+ * The command that needs to be executed first if there is a selection.
+ */
+ KFCRemoveSelection* removeSelection;
+
+};
+
+
+/**
+ * Add and remove arbitrary token elements and their contents. This command
+ * add needed flexibility in order to remove and insert new tokens in the
+ * middle of a token, that is, splitting the token and creating new ones.
+ */
+class KFCSplitToken : public KFCAddToken
+{
+public:
+
+ KFCSplitToken(const QString &name, Container* document);
+ ~KFCSplitToken();
+
+ virtual void execute();
+ virtual void unexecute();
+
+ /**
+ * Collect cursor data that will be needed to do the stuff properly
+ */
+ void addCursor( FormulaCursor* cursor ) { setExecuteCursor( cursor ); }
+
+private:
+
+ /**
+ * The command that needs to be executed first if there is a selection.
+ */
+ KFCRemoveSelection* removeSelection;
+
+ /**
+ * The list of elements that are splited into another token
+ */
+ QPtrList< BasicElement > splitList;
+
+ /**
+ * Information about cursor position where the split is made.
+ * Needed to restore splited elements.
+ */
+ FormulaCursor::CursorData* splitCursor;
+};
+
+
+/**
+ * Command that is used to remove the currently
+ * selected element.
+ */
+class KFCRemove : public Command
+{
+public:
+
+ /**
+ * generic add command, default implementation do nothing
+ */
+ KFCRemove(Container* document, Direction dir);
+ ~KFCRemove();
+
+ virtual void execute();
+ virtual void unexecute();
+
+ /**
+ * A command might have no effect.
+ * @returns true if nothing happened.
+ */
+ //virtual bool isSenseless() { return removedList.isEmpty(); }
+
+private:
+
+ /**
+ * the list where all elements are stored that are removed
+ * from the tree.
+ */
+ QPtrList<BasicElement> removedList;
+
+ /**
+ * The element we might have extracted.
+ */
+ BasicElement* element;
+
+ /**
+ * If this is a complex remove command we need to remember two
+ * cursor positions. The one after the first removal (this one)
+ * and another at the end.
+ */
+ FormulaCursor::CursorData* simpleRemoveCursor;
+
+ Direction dir;
+};
+
+
+/**
+ * Command to remove the parent element.
+ */
+class KFCRemoveEnclosing : public Command
+{
+public:
+ KFCRemoveEnclosing(Container* document, Direction dir);
+ ~KFCRemoveEnclosing();
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+ BasicElement* element;
+
+ Direction direction;
+};
+
+
+/**
+ * The command that takes the main child out of the selected
+ * element and replaces the element with it.
+ */
+class KFCAddReplacing : public Command
+{
+public:
+ KFCAddReplacing(const QString &name, Container* document);
+ ~KFCAddReplacing();
+
+ virtual void execute();
+ virtual void unexecute();
+
+ void setElement(BasicElement* e) { element = e; }
+
+private:
+
+ /**
+ * The element that is to be inserted.
+ */
+ BasicElement* element;
+};
+
+
+/**
+ * Add an index. The element that gets the index needs to be there
+ * already.
+ */
+class KFCAddGenericIndex : public KFCAdd
+{
+public:
+
+ KFCAddGenericIndex(Container* document, ElementIndexPtr index);
+
+ virtual void execute();
+
+private:
+ ElementIndexPtr index;
+};
+
+
+class IndexElement;
+
+/**
+ * Add an IndexElement.
+ */
+class KFCAddIndex : public KFCAddReplacing
+{
+public:
+
+ KFCAddIndex(Container* document, IndexElement* element, ElementIndexPtr index);
+ ~KFCAddIndex();
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+ KFCAddGenericIndex addIndex;
+};
+
+
+class FormulaElement;
+
+class KFCChangeBaseSize : public PlainCommand {
+public:
+ KFCChangeBaseSize( const QString& name, Container* document, FormulaElement* formula, int size );
+
+ void execute();
+ void unexecute();
+
+private:
+ Container* m_document;
+ FormulaElement* m_formula;
+ int m_size;
+ int m_oldSize;
+};
+
+
+/**
+ * Base for all font commands that act on the current selection.
+ * Implements the visitor pattern. (Really?)
+ */
+class FontCommand : public Command {
+public:
+ FontCommand( const QString& name, Container* document );
+
+ /**
+ * Collects all elements that are to be modified.
+ */
+ void addTextElement( TextElement* element ) { list.append(element); }
+
+ /**
+ * Collects all parent elements those children are to be changend.
+ */
+ void addElement( BasicElement* element ) { elementList.append( element ); }
+
+protected:
+
+ QPtrList<TextElement>& childrenList() { return list; }
+
+ void collectChildren();
+
+ void parseSequences( const QMap<SequenceElement*, int>& parents );
+
+private:
+
+ /**
+ * the list where all elements are stored that are removed
+ * from the tree.
+ */
+ QPtrList<TextElement> list;
+
+ QPtrList<BasicElement> elementList;
+};
+
+
+/**
+ * Changes the char style of a number of elements an their children.
+ */
+class CharStyleCommand : public FontCommand {
+public:
+ CharStyleCommand( CharStyle cs, const QString& name, Container* document );
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+
+ typedef QValueVector<CharStyle> StyleList;
+
+ StyleList styleList;
+ CharStyle charStyle;
+};
+
+
+/**
+ * Changes the char family of a number of elements an their children.
+ */
+class CharFamilyCommand : public FontCommand {
+public:
+ CharFamilyCommand( CharFamily cf, const QString& name, Container* document );
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+
+ typedef QValueVector<CharFamily> FamilyList;
+
+ FamilyList familyList;
+ CharFamily charFamily;
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // KFORMULACOMMAND_H
diff --git a/lib/kformula/kformulacompatibility.cc b/lib/kformula/kformulacompatibility.cc
new file mode 100644
index 00000000..70f77ed9
--- /dev/null
+++ b/lib/kformula/kformulacompatibility.cc
@@ -0,0 +1,402 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+
+ This file is based on the other kformula lib
+ Copyright (C) 1999 Ilya Baran (ibaran@mit.edu)
+
+ 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 <qvaluelist.h>
+
+#include <kdebug.h>
+#include "kformuladefs.h"
+#include "kformulacompatibility.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+const int SYMBOL_ABOVE = 20000;
+const int UNUSED_OFFSET = 1000;
+
+typedef int BoxType;
+
+//const BoxType PLUS = '+';
+//const BoxType MINUS = '-';
+//const BoxType TIMES = '*';
+const BoxType OF_DIVIDE = '\\' + UNUSED_OFFSET;
+const BoxType OF_POWER = '^' + UNUSED_OFFSET; //just a test to see if it works
+const BoxType OF_SQRT = '@' + UNUSED_OFFSET;
+//const BoxType TEXT = 't';
+//const BoxType CAT = '#' + UNUSED_OFFSET;
+const BoxType OF_SUB = '_' + UNUSED_OFFSET;
+const BoxType OF_LSUP = '6' + UNUSED_OFFSET;
+const BoxType OF_LSUB = '%' + UNUSED_OFFSET;
+//const BoxType PAREN = '(';
+//const BoxType EQUAL = '=';
+//const BoxType MORE = '>';
+//const BoxType LESS = '<';
+//const BoxType ABS = '|';
+//const BoxType BRACKET = '[';
+//const BoxType SLASH = '/';
+const BoxType OF_MATRIX = 'm' + UNUSED_OFFSET;
+const BoxType OF_SEPARATOR = '&' + UNUSED_OFFSET; // separator for matrices
+const BoxType OF_ABOVE = ')' + UNUSED_OFFSET; //something useless
+const BoxType OF_BELOW = ']' + UNUSED_OFFSET;
+const BoxType OF_SYMBOL = 's' + UNUSED_OFFSET; // whatever
+// char for keeping track of cursor position in undo/redo:
+//const BoxType CURSOR = 'c' + UNUSED_OFFSET;
+
+const int INTEGRAL = SYMBOL_ABOVE + 0; // symbols have values above that
+const int SUM = SYMBOL_ABOVE + 1;
+const int PRODUCT = SYMBOL_ABOVE + 2;
+const int ARROW = SYMBOL_ABOVE + 3;
+// elements of the symbol font are their own codes + SYMBOL_ABOVE
+
+
+Compatibility::Compatibility()
+{
+}
+
+
+QDomDocument Compatibility::buildDOM(QString text)
+{
+ QDomDocument doc("KFORMULA");
+ pos = 0;
+ formulaString = text;
+ QDomElement formula = readSequence(doc);
+ formula.setTagName("FORMULA");
+ doc.appendChild(formula);
+ return doc;
+}
+
+
+void Compatibility::appendNextSequence(const QDomDocument& doc, QDomElement element)
+{
+ if (hasNext() && nextToken() == '{') {
+ element.appendChild(readSequence(doc));
+ }
+ else {
+ pushback();
+ element.appendChild(doc.createElement("SEQUENCE"));
+ }
+}
+
+
+QDomElement Compatibility::getLastSequence(const QDomDocument& doc, QDomElement sequence)
+{
+ if (sequence.lastChild().nodeName() == "SEQUENCE") {
+ QDomNode child = sequence.removeChild(sequence.lastChild());
+ return child.toElement();
+ }
+ else {
+ QDomElement newSeq = doc.createElement("SEQUENCE");
+ if (!sequence.lastChild().isNull()) {
+ QDomNode child = sequence.removeChild(sequence.lastChild());
+ newSeq.appendChild(child);
+ }
+ return newSeq;
+ }
+}
+
+
+QDomElement Compatibility::findIndexNode(const QDomDocument& doc, QDomElement sequence)
+{
+ QDomElement element;
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ element = sequence.lastChild().toElement();
+ }
+ else {
+ element = doc.createElement("INDEX");
+ QDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ con.appendChild(getLastSequence(doc, sequence));
+ sequence.appendChild(element);
+ }
+ return element;
+}
+
+
+void Compatibility::appendToSequence(QDomElement sequence, QDomElement element, int leftIndexSeen)
+{
+ if (leftIndexSeen > 0) {
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ QDomElement index = sequence.lastChild().toElement();
+ if ((index.firstChild().nodeName() == "CONTENT") &&
+ (index.firstChild().firstChild().nodeName() == "SEQUENCE")) {
+ QDomElement seq = index.firstChild().firstChild().toElement();
+ if (element.nodeName() == "SEQUENCE") {
+ index.firstChild().replaceChild(element, seq);
+ }
+ else {
+ seq.appendChild(element);
+ }
+ return;
+ }
+ }
+ }
+ sequence.appendChild(element);
+}
+
+
+QDomElement Compatibility::readMatrix(const QDomDocument& doc)
+{
+ QDomElement element = doc.createElement("MATRIX");
+
+ uint cols = nextToken();
+ nextToken();
+ uint rows = nextToken();
+
+ element.setAttribute("ROWS", rows);
+ element.setAttribute("COLUMNS", cols);
+
+ if ((nextToken() == '}') && (nextToken() == OF_MATRIX) && (nextToken() == '{')) {
+ QValueList<QDomElement> matrix;
+ for (uint c = 0; c < cols; c++) {
+ for (uint r = 0; r < rows; r++) {
+ if (hasNext() && (nextToken() == '{')) {
+ QDomElement tmp = readSequence(doc);
+ matrix.append(tmp);
+ }
+ if (hasNext() && (nextToken() != OF_SEPARATOR)) {
+ pushback();
+ }
+ }
+ }
+ if (hasNext() && (nextToken() != '}')) {
+ pushback();
+ }
+
+ if (matrix.count() == rows*cols) {
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < cols; c++) {
+ element.appendChild(matrix[c*rows+r]);
+ }
+ }
+ }
+ }
+ else {
+ pushback();
+ }
+
+ return element;
+}
+
+
+QDomElement Compatibility::readSequence(const QDomDocument& doc)
+{
+ // matrizes start with something that isn't a sequence
+ if ((tokenLeft() > 6) && (lookAhead(1) == OF_SEPARATOR)) {
+ return readMatrix(doc);
+ }
+
+ int leftIndexSeen = 0;
+ QDomElement sequence = doc.createElement("SEQUENCE");
+
+ while (hasNext()) {
+ ushort ch = nextToken();
+
+ // Debug
+ //cout << "read: " << ch << " (" << static_cast<char>(ch) << ')' << endl;
+
+ if (leftIndexSeen > 0) leftIndexSeen--;
+
+ switch (ch) {
+ case '{':
+ appendToSequence(sequence, readSequence(doc), leftIndexSeen);
+ break;
+ case '}':
+ return sequence;
+ case '(':
+ case '[':
+ case '|': {
+ // There is an empty sequence we have to remove
+ if (!sequence.lastChild().isNull()) {
+ sequence.removeChild(sequence.lastChild());
+ }
+
+ QDomElement element = doc.createElement("BRACKET");
+ appendToSequence(sequence, element, leftIndexSeen);
+ element.setAttribute("LEFT", ch);
+ element.setAttribute("RIGHT", (ch=='(') ? ')' : ((ch=='[') ? ']' : '|'));
+
+ QDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ appendNextSequence(doc, con);
+ break;
+ }
+ case OF_DIVIDE: {
+ QDomElement element = doc.createElement("FRACTION");
+
+ QDomElement num = doc.createElement("NUMERATOR");
+ element.appendChild(num);
+ num.appendChild(getLastSequence(doc, sequence));
+
+ QDomElement den = doc.createElement("DENOMINATOR");
+ element.appendChild(den);
+ appendNextSequence(doc, den);
+
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ case OF_SQRT: {
+ QDomElement element = doc.createElement("ROOT");
+ QDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ appendNextSequence(doc, con);
+
+ QDomElement ind = doc.createElement("INDEX");
+ element.appendChild(ind);
+ ind.appendChild(getLastSequence(doc, sequence));
+
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ case OF_POWER: {
+ QDomElement element = findIndexNode(doc, sequence);
+ QDomElement upperRight = doc.createElement("UPPERRIGHT");
+ element.appendChild(upperRight);
+ appendNextSequence(doc, upperRight);
+ break;
+ }
+ case OF_SUB: {
+ QDomElement element = findIndexNode(doc, sequence);
+ QDomElement lowerRight = doc.createElement("LOWERRIGHT");
+ element.appendChild(lowerRight);
+ appendNextSequence(doc, lowerRight);
+ break;
+ }
+ case OF_LSUP: {
+ QDomElement upperLeft = doc.createElement("UPPERLEFT");
+ upperLeft.appendChild(getLastSequence(doc, sequence));
+ QDomElement element;
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ element = sequence.lastChild().toElement();
+ }
+ else {
+ element = doc.createElement("INDEX");
+ QDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ QDomElement seq = doc.createElement("SEQUENCE");
+ con.appendChild(seq);
+ appendToSequence(sequence, element, leftIndexSeen);
+ }
+ element.appendChild(upperLeft);
+ leftIndexSeen = 2;
+ break;
+ }
+ case OF_LSUB: {
+ QDomElement lowerLeft = doc.createElement("LOWERLEFT");
+ lowerLeft.appendChild(getLastSequence(doc, sequence));
+ QDomElement element;
+ if (sequence.lastChild().nodeName() == "INDEX") {
+ element = sequence.lastChild().toElement();
+ }
+ else {
+ element = doc.createElement("INDEX");
+ QDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ QDomElement seq = doc.createElement("SEQUENCE");
+ con.appendChild(seq);
+ appendToSequence(sequence, element, leftIndexSeen);
+ }
+ element.appendChild(lowerLeft);
+ leftIndexSeen = 2;
+ break;
+ }
+ case OF_ABOVE: {
+ if (sequence.lastChild().nodeName() == "SEQUENCE") {
+ QDomElement seq = sequence.lastChild().toElement();
+ if ((seq.childNodes().count() == 1) &&
+ ((seq.lastChild().nodeName() == "SYMBOL") ||
+ (seq.lastChild().nodeName() == "INDEX"))) {
+ sequence.removeChild(seq);
+
+ QDomElement element = seq.lastChild().toElement();
+ QDomElement upper = (element.nodeName() == "SYMBOL") ?
+ doc.createElement("UPPER") :
+ doc.createElement("UPPERMIDDLE");
+ element.appendChild(upper);
+ appendNextSequence(doc, upper);
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ }
+ QDomElement element = findIndexNode(doc, sequence);
+ QDomElement upper = doc.createElement("UPPERMIDDLE");
+ element.appendChild(upper);
+ appendNextSequence(doc, upper);
+ break;
+ }
+ case OF_BELOW: {
+ if (sequence.lastChild().nodeName() == "SEQUENCE") {
+ QDomElement seq = sequence.lastChild().toElement();
+ if ((seq.childNodes().count() == 1) &&
+ ((seq.lastChild().nodeName() == "SYMBOL") ||
+ (seq.lastChild().nodeName() == "INDEX"))) {
+ sequence.removeChild(seq);
+
+ QDomElement element = seq.lastChild().toElement();
+ QDomElement lower = (element.nodeName() == "SYMBOL") ?
+ doc.createElement("LOWER") :
+ doc.createElement("LOWERMIDDLE");
+ element.appendChild(lower);
+ appendNextSequence(doc, lower);
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ }
+ QDomElement element = findIndexNode(doc, sequence);
+ QDomElement lower = doc.createElement("LOWERMIDDLE");
+ element.appendChild(lower);
+ appendNextSequence(doc, lower);
+ break;
+ }
+ case OF_SYMBOL:
+ kdDebug() << "OF_SYMBOL" << endl;
+ break;
+ case INTEGRAL:
+ case SUM:
+ case PRODUCT: {
+ QDomElement element = doc.createElement("SYMBOL");
+ element.setAttribute("TYPE",
+ (ch==INTEGRAL) ? Integral :
+ ((ch==SUM) ? Sum : Product));
+
+ QDomElement con = doc.createElement("CONTENT");
+ element.appendChild(con);
+ con.appendChild(readSequence(doc));
+ pushback();
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ case ARROW: {
+ QDomElement element = doc.createElement("TEXT");
+ element.setAttribute("CHAR", QString(QChar(static_cast<char>(174))));
+ element.setAttribute("SYMBOL", "1");
+ appendToSequence(sequence, element, leftIndexSeen);
+ break;
+ }
+ default: {
+ QDomElement element = doc.createElement("TEXT");
+ element.setAttribute("CHAR", QString(formulaString[pos-1]));
+ appendToSequence(sequence, element, leftIndexSeen);
+ }
+ }
+ }
+ return sequence;
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/kformulacompatibility.h b/lib/kformula/kformulacompatibility.h
new file mode 100644
index 00000000..98c268cc
--- /dev/null
+++ b/lib/kformula/kformulacompatibility.h
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 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.
+*/
+
+#ifndef KFORMULACOMPATIBILITY_H
+#define KFORMULACOMPATIBILITY_H
+
+#include <qdom.h>
+#include <qstring.h>
+
+KFORMULA_NAMESPACE_BEGIN
+
+/**
+ * Converter from the other kformula lib string
+ * to a loadable dom.
+ */
+class Compatibility {
+public:
+
+ Compatibility();
+
+ /**
+ * Builds a kformula DOM from a old formula string.
+ */
+ QDomDocument buildDOM(QString text);
+
+private:
+
+ QDomElement readSequence(const QDomDocument& doc);
+ QDomElement readMatrix(const QDomDocument& doc);
+
+ void appendToSequence(QDomElement sequence, QDomElement element, int leftIndexSeen);
+
+ void appendNextSequence(const QDomDocument& doc, QDomElement element);
+ QDomElement getLastSequence(const QDomDocument& doc, QDomElement sequence);
+
+ QDomElement findIndexNode(const QDomDocument& doc, QDomElement sequence);
+
+ ushort nextToken() { return formulaString[pos++].unicode(); }
+ ushort lookAhead(uint i) const { return formulaString[pos+i].unicode(); }
+ void pushback() { pos--; }
+
+ bool hasNext() const { return pos < formulaString.length(); }
+ uint tokenLeft() const { return formulaString.length()-pos; }
+
+ /**
+ * the string we read
+ */
+ QString formulaString;
+
+ /**
+ * current pos
+ */
+ uint pos;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // KFORMULACOMPATIBILITY_H
diff --git a/lib/kformula/kformulaconfigpage.cc b/lib/kformula/kformulaconfigpage.cc
new file mode 100644
index 00000000..8037192f
--- /dev/null
+++ b/lib/kformula/kformulaconfigpage.cc
@@ -0,0 +1,543 @@
+/* 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 <qvariant.h> // first for gcc 2.7.2
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qmap.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qstringlist.h>
+#include <qvbox.h>
+#include <qwidget.h>
+
+//#include <algorithm>
+
+#include <kcolorbutton.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kfontdialog.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kpushbutton.h>
+
+#include "contextstyle.h"
+#include "kformulaconfigpage.h"
+#include "kformuladocument.h"
+#include "symboltable.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+ConfigurePage::ConfigurePage( Document* document, QWidget* view, KConfig* config, QVBox* box, char* name )
+ : QObject( box->parent(), name ), m_document( document ), m_view( view ), m_config( config ), m_changed( false )
+{
+ const ContextStyle& contextStyle = document->getContextStyle( true );
+
+ // fonts
+
+ QGroupBox *gbox = new QGroupBox( i18n( "Fonts" ), box );
+ gbox->setColumnLayout( 0, Qt::Horizontal );
+
+ QGridLayout* grid = new QGridLayout( gbox->layout(), 5, 3 );
+ grid->setSpacing( KDialog::spacingHint() );
+
+ grid->setColStretch(1, 1);
+
+ defaultFont = contextStyle.getDefaultFont();
+ nameFont = contextStyle.getNameFont();
+ numberFont = contextStyle.getNumberFont();
+ operatorFont = contextStyle.getOperatorFont();
+
+ connect( buildFontLine( gbox, grid, 0, defaultFont,
+ i18n( "Default font:" ), defaultFontName ),
+ SIGNAL( clicked() ), SLOT( selectNewDefaultFont() ) );
+
+ connect( buildFontLine( gbox, grid, 1, nameFont,
+ i18n( "Name font:" ), nameFontName ),
+ SIGNAL( clicked() ), SLOT( selectNewNameFont() ) );
+
+ connect( buildFontLine( gbox, grid, 2, numberFont,
+ i18n( "Number font:" ), numberFontName ),
+ SIGNAL( clicked() ), SLOT( selectNewNumberFont() ) );
+
+ connect( buildFontLine( gbox, grid, 3, operatorFont,
+ i18n( "Operator font:" ), operatorFontName ),
+ SIGNAL( clicked() ), SLOT( selectNewOperatorFont() ) );
+
+ QLabel* sizeTitle = new QLabel( i18n( "Default base size:" ), gbox );
+ grid->addWidget( sizeTitle, 4, 0 );
+
+ sizeSpin = new KIntNumInput( contextStyle.baseSize(), gbox );
+ sizeSpin->setRange( 8, 72, 1, true );
+
+ grid->addMultiCellWidget( sizeSpin, 4, 4, 1, 2 );
+
+ connect( sizeSpin, SIGNAL( valueChanged( int ) ),
+ SLOT( baseSizeChanged( int ) ) );
+
+ // syntax highlighting
+
+ syntaxHighlighting = new QCheckBox( i18n( "Use syntax highlighting" ),box );
+ syntaxHighlighting->setChecked( contextStyle.syntaxHighlighting() );
+
+// hlBox = new QGroupBox( i18n( "Highlight Colors" ), box );
+// hlBox->setColumnLayout( 0, Qt::Horizontal );
+
+// grid = new QGridLayout( hlBox->layout(), 5, 2 );
+// grid->setSpacing( KDialog::spacingHint() );
+
+// QLabel* defaultLabel = new QLabel( hlBox, "defaultLabel" );
+// defaultLabel->setText( i18n( "Default color:" ) );
+// grid->addWidget( defaultLabel, 0, 0 );
+
+// defaultColorBtn = new KColorButton( hlBox, "defaultColor" );
+// defaultColorBtn->setColor( contextStyle.getDefaultColor() );
+// grid->addWidget( defaultColorBtn, 0, 1 );
+
+
+// QLabel* numberLabel = new QLabel( hlBox, "numberLabel" );
+// numberLabel->setText( i18n( "Number color:" ) );
+// grid->addWidget( numberLabel, 1, 0 );
+
+// numberColorBtn = new KColorButton( hlBox, "numberColor" );
+// numberColorBtn->setColor( contextStyle.getNumberColorPlain() );
+// grid->addWidget( numberColorBtn, 1, 1 );
+
+
+// QLabel* operatorLabel = new QLabel( hlBox, "operatorLabel" );
+// operatorLabel->setText( i18n( "Operator color:" ) );
+// grid->addWidget( operatorLabel, 2, 0 );
+
+// operatorColorBtn = new KColorButton( hlBox, "operatorColor" );
+// operatorColorBtn->setColor( contextStyle.getOperatorColorPlain() );
+// grid->addWidget( operatorColorBtn, 2, 1 );
+
+
+// QLabel* emptyLabel = new QLabel( hlBox, "emptyLabel" );
+// emptyLabel->setText( i18n( "Empty color:" ) );
+// grid->addWidget( emptyLabel, 3, 0 );
+
+// emptyColorBtn = new KColorButton( hlBox, "emptyColor" );
+// emptyColorBtn->setColor( contextStyle.getEmptyColorPlain() );
+// grid->addWidget( emptyColorBtn, 3, 1 );
+
+
+// QLabel* errorLabel = new QLabel( hlBox, "errorLabel" );
+// errorLabel->setText( i18n( "Error color:" ) );
+// grid->addWidget( errorLabel, 4, 0 );
+
+// errorColorBtn = new KColorButton( hlBox, "errorColor" );
+// errorColorBtn->setColor( contextStyle.getErrorColorPlain() );
+// grid->addWidget( errorColorBtn, 4, 1 );
+
+ connect( syntaxHighlighting, SIGNAL( clicked() ),
+ SLOT( syntaxHighlightingClicked() ) );
+
+ syntaxHighlightingClicked();
+
+ connect( syntaxHighlighting, SIGNAL( clicked() ), this, SLOT( slotChanged() ) );
+ connect( sizeSpin, SIGNAL( valueChanged( int ) ), this, SLOT( slotChanged() ) );
+
+ Q_ASSERT( !m_changed );
+}
+
+
+QPushButton* ConfigurePage::buildFontLine( QWidget* parent,
+ QGridLayout* layout, int number, QFont font, QString name,
+ QLabel*& fontName )
+{
+ QLabel* fontTitle = new QLabel( name, parent );
+
+ QString labelName = font.family() + ' ' + QString::number( font.pointSize() );
+ fontName = new QLabel( labelName, parent );
+ fontName->setFont( font );
+ fontName->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+
+ QPushButton* chooseButton = new QPushButton( i18n( "Choose..." ), parent );
+
+ layout->addWidget( fontTitle, number, 0 );
+ layout->addWidget( fontName, number, 1 );
+ layout->addWidget( chooseButton, number, 2 );
+
+ return chooseButton;
+}
+
+
+void ConfigurePage::apply()
+{
+ if ( !m_changed )
+ return;
+
+ ContextStyle& contextStyle = m_document->getContextStyle( true );
+
+ contextStyle.setDefaultFont( defaultFont );
+ contextStyle.setNameFont( nameFont );
+ contextStyle.setNumberFont( numberFont );
+ contextStyle.setOperatorFont( operatorFont );
+ contextStyle.setBaseSize( sizeSpin->value() );
+
+ contextStyle.setSyntaxHighlighting( syntaxHighlighting->isChecked() );
+// contextStyle.setDefaultColor( defaultColorBtn->color() );
+// contextStyle.setNumberColor( numberColorBtn->color() );
+// contextStyle.setOperatorColor( operatorColorBtn->color() );
+// contextStyle.setEmptyColor( emptyColorBtn->color() );
+// contextStyle.setErrorColor( errorColorBtn->color() );
+
+ m_config->setGroup( "kformula Font" );
+ m_config->writeEntry( "defaultFont", defaultFont.toString() );
+ m_config->writeEntry( "nameFont", nameFont.toString() );
+ m_config->writeEntry( "numberFont", numberFont.toString() );
+ m_config->writeEntry( "operatorFont", operatorFont.toString() );
+ m_config->writeEntry( "baseSize", QString::number( sizeSpin->value() ) );
+
+// m_config->setGroup( "kformula Color" );
+// m_config->writeEntry( "syntaxHighlighting", syntaxHighlighting->isChecked() );
+// m_config->writeEntry( "defaultColor", defaultColorBtn->color() );
+// m_config->writeEntry( "numberColor", numberColorBtn->color() );
+// m_config->writeEntry( "operatorColor", operatorColorBtn->color() );
+// m_config->writeEntry( "emptyColor", emptyColorBtn->color() );
+// m_config->writeEntry( "errorColor", errorColorBtn->color() );
+
+ // notify!!!
+ m_document->updateConfig();
+ m_changed = false;
+}
+
+void ConfigurePage::slotDefault()
+{
+ defaultFont = QFont( "Times", 12, QFont::Normal, true );
+ nameFont = QFont( "Times" );
+ numberFont = nameFont;
+ operatorFont = nameFont;
+
+ sizeSpin->setValue( 20 );
+
+ updateFontLabel( defaultFont, defaultFontName );
+ updateFontLabel( nameFont, nameFontName );
+ updateFontLabel( numberFont, numberFontName );
+ updateFontLabel( operatorFont, operatorFontName );
+
+ syntaxHighlighting->setChecked( true );
+ syntaxHighlightingClicked();
+
+// defaultColorBtn->setColor( Qt::black );
+// numberColorBtn->setColor( Qt::blue );
+// operatorColorBtn->setColor( Qt::darkGreen );
+// emptyColorBtn->setColor( Qt::blue );
+// errorColorBtn->setColor( Qt::darkRed );
+ slotChanged();
+}
+
+void ConfigurePage::syntaxHighlightingClicked()
+{
+// bool checked = syntaxHighlighting->isChecked();
+// hlBox->setEnabled( checked );
+}
+
+void ConfigurePage::selectNewDefaultFont()
+{
+ if ( selectFont( defaultFont ) )
+ updateFontLabel( defaultFont, defaultFontName );
+}
+
+void ConfigurePage::selectNewNameFont()
+{
+ if ( selectFont( nameFont ) )
+ updateFontLabel( nameFont, nameFontName );
+}
+
+void ConfigurePage::selectNewNumberFont()
+{
+ if ( selectFont( numberFont ) )
+ updateFontLabel( numberFont, numberFontName );
+}
+
+void ConfigurePage::selectNewOperatorFont()
+{
+ if ( selectFont( operatorFont ) )
+ updateFontLabel( operatorFont, operatorFontName );
+}
+
+bool ConfigurePage::selectFont( QFont & font )
+{
+ QStringList list;
+
+ KFontChooser::getFontList( list, KFontChooser::SmoothScalableFonts );
+
+ KFontDialog dlg( m_view, 0, false, true, list );
+ dlg.setFont( font );
+
+ int result = dlg.exec();
+ if ( KDialog::Accepted == result ) {
+ font = dlg.font();
+ slotChanged();
+ return true;
+ }
+
+ return false;
+}
+
+void ConfigurePage::baseSizeChanged( int /*value*/ )
+{
+}
+
+void ConfigurePage::updateFontLabel( QFont font, QLabel* label )
+{
+ label->setText( font.family() + ' ' + QString::number( font.pointSize() ) );
+ label->setFont( font );
+}
+
+void ConfigurePage::slotChanged()
+{
+ m_changed = true;
+}
+
+// class UsedFontItem : public KListViewItem {
+// public:
+// UsedFontItem( MathFontsConfigurePage* page, QListView* parent, QString font )
+// : KListViewItem( parent, font ), m_page( page ) {}
+
+// int compare( QListViewItem* i, int col, bool ascending ) const;
+
+// private:
+// MathFontsConfigurePage* m_page;
+// };
+
+// int UsedFontItem::compare( QListViewItem* i, int, bool ) const
+// {
+// QValueVector<QString>::iterator lhsIt = m_page->findUsedFont( text( 0 ) );
+// QValueVector<QString>::iterator rhsIt = m_page->findUsedFont( i->text( 0 ) );
+// if ( lhsIt < rhsIt ) {
+// return -1;
+// }
+// else if ( lhsIt > rhsIt ) {
+// return 1;
+// }
+// return 0;
+// }
+
+// MathFontsConfigurePage::MathFontsConfigurePage( Document* document, QWidget* view,
+// KConfig* config, QVBox* box, char* name )
+// : QObject( box->parent(), name ), m_document( document ), m_view( view ), m_config( config )
+// {
+// QWidget* fontWidget = new QWidget( box );
+// QGridLayout* fontLayout = new QGridLayout( fontWidget, 1, 1, KDialog::marginHint(), KDialog::spacingHint() );
+
+// QHBoxLayout* hLayout = new QHBoxLayout( 0, 0, 6 );
+
+// availableFonts = new KListView( fontWidget );
+// availableFonts->addColumn( i18n( "Available Fonts" ) );
+// hLayout->addWidget( availableFonts );
+
+// QVBoxLayout* vLayout = new QVBoxLayout( 0, 0, 6 );
+// QSpacerItem* spacer1 = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding );
+// vLayout->addItem( spacer1 );
+
+// addFont = new KPushButton( fontWidget );
+// addFont->setText( "->" );
+// vLayout->addWidget( addFont );
+
+// removeFont = new KPushButton( fontWidget );
+// removeFont->setText( "<-" );
+// vLayout->addWidget( removeFont );
+
+// QSpacerItem* spacer2 = new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding );
+// vLayout->addItem( spacer2 );
+
+// hLayout->addLayout( vLayout );
+
+// vLayout = new QVBoxLayout( 0, 0, 6 );
+
+// moveUp = new KPushButton( fontWidget );
+// moveUp->setText( i18n( "Up" ) );
+// vLayout->addWidget( moveUp );
+
+// requestedFonts = new KListView( fontWidget );
+// requestedFonts->addColumn( i18n( "Used Fonts" ) );
+// vLayout->addWidget( requestedFonts );
+
+// moveDown = new KPushButton( fontWidget );
+// moveDown->setText( i18n( "Down" ) );
+// vLayout->addWidget( moveDown );
+
+// hLayout->addLayout( vLayout );
+
+// fontLayout->addLayout( hLayout, 0, 0 );
+
+// // connect( availableFonts, SIGNAL( executed( QListViewItem* ) ),
+// // this, SLOT( slotAddFont() ) );
+// // connect( requestedFonts, SIGNAL( executed( QListViewItem* ) ),
+// // this, SLOT( slotRemoveFont() ) );
+// connect( addFont, SIGNAL( clicked() ), this, SLOT( slotAddFont() ) );
+// connect( removeFont, SIGNAL( clicked() ), this, SLOT( slotRemoveFont() ) );
+// connect( moveUp, SIGNAL( clicked() ), this, SLOT( slotMoveUp() ) );
+// connect( moveDown, SIGNAL( clicked() ), this, SLOT( slotMoveDown() ) );
+
+// const ContextStyle& contextStyle = document->getContextStyle( true );
+// const SymbolTable& symbolTable = contextStyle.symbolTable();
+// const QStringList& usedFonts = contextStyle.requestedFonts();
+
+// QMap<QString, QString> fontMap;
+// // symbolTable.findAvailableFonts( &fontMap );
+
+// setupLists( usedFonts );
+// }
+
+// void MathFontsConfigurePage::apply()
+// {
+// QStringList strings;
+// std::copy( usedFontList.begin(), usedFontList.end(), std::back_inserter( strings ) );
+
+// m_config->setGroup( "kformula Font" );
+// m_config->writeEntry( "usedMathFonts", strings );
+
+// ContextStyle& contextStyle = m_document->getContextStyle( true );
+// contextStyle.setRequestedFonts( strings );
+// }
+
+// void MathFontsConfigurePage::slotDefault()
+// {
+// QStringList usedFonts;
+
+// usedFonts.push_back( "esstixone" );
+// usedFonts.push_back( "esstixtwo" );
+// usedFonts.push_back( "esstixthree" );
+// usedFonts.push_back( "esstixfour" );
+// usedFonts.push_back( "esstixfive" );
+// usedFonts.push_back( "esstixsix" );
+// usedFonts.push_back( "esstixseven" );
+// usedFonts.push_back( "esstixeight" );
+// usedFonts.push_back( "esstixnine" );
+// usedFonts.push_back( "esstixten" );
+// usedFonts.push_back( "esstixeleven" );
+// usedFonts.push_back( "esstixtwelve" );
+// usedFonts.push_back( "esstixthirteen" );
+// usedFonts.push_back( "esstixfourteen" );
+// usedFonts.push_back( "esstixfifteen" );
+// usedFonts.push_back( "esstixsixteen" );
+// usedFonts.push_back( "esstixseventeen" );
+
+// usedFontList.clear();
+// requestedFonts->clear();
+// availableFonts->clear();
+
+// setupLists( usedFonts );
+// }
+
+// QValueVector<QString>::iterator MathFontsConfigurePage::findUsedFont( QString name )
+// {
+// return std::find( usedFontList.begin(), usedFontList.end(), name );
+// }
+
+// void MathFontsConfigurePage::setupLists( const QStringList& usedFonts )
+// {
+// const ContextStyle& contextStyle = m_document->getContextStyle( true );
+// const SymbolTable& symbolTable = contextStyle.symbolTable();
+
+// QMap<QString, QString> fontMap;
+// // symbolTable.findAvailableFonts( &fontMap );
+
+// for ( QStringList::const_iterator it = usedFonts.begin(); it != usedFonts.end(); ++it ) {
+// QMap<QString, QString>::iterator font = fontMap.find( *it );
+// if ( font != fontMap.end() ) {
+// fontMap.erase( font );
+// new UsedFontItem( this, requestedFonts, *it );
+// usedFontList.push_back( *it );
+// }
+// }
+// for ( QMap<QString, QString>::iterator it = fontMap.begin(); it != fontMap.end(); ++it ) {
+// new KListViewItem( availableFonts, it.key() );
+// }
+// }
+
+// void MathFontsConfigurePage::slotAddFont()
+// {
+// QListViewItem* fontItem = availableFonts->selectedItem();
+// if ( fontItem ) {
+// QString fontName = fontItem->text( 0 );
+// //availableFonts->takeItem( fontItem );
+// delete fontItem;
+
+// new UsedFontItem( this, requestedFonts, fontName );
+// usedFontList.push_back( fontName );
+// }
+// }
+
+// void MathFontsConfigurePage::slotRemoveFont()
+// {
+// QListViewItem* fontItem = requestedFonts->selectedItem();
+// if ( fontItem ) {
+// QString fontName = fontItem->text( 0 );
+// QValueVector<QString>::iterator it = std::find( usedFontList.begin(), usedFontList.end(), fontName );
+// if ( it != usedFontList.end() ) {
+// usedFontList.erase( it );
+// }
+// //requestedFonts->takeItem( fontItem );
+// delete fontItem;
+// new KListViewItem( availableFonts, fontName );
+// }
+// }
+
+// void MathFontsConfigurePage::slotMoveUp()
+// {
+// QListViewItem* fontItem = requestedFonts->selectedItem();
+// if ( fontItem ) {
+// QString fontName = fontItem->text( 0 );
+// QValueVector<QString>::iterator it = std::find( usedFontList.begin(), usedFontList.end(), fontName );
+// if ( it != usedFontList.end() ) {
+// uint pos = it - usedFontList.begin();
+// if ( pos > 0 ) {
+// QValueVector<QString>::iterator before = it-1;
+// std::swap( *it, *before );
+// requestedFonts->sort();
+// }
+// }
+// }
+// }
+
+// void MathFontsConfigurePage::slotMoveDown()
+// {
+// QListViewItem* fontItem = requestedFonts->selectedItem();
+// if ( fontItem ) {
+// QString fontName = fontItem->text( 0 );
+// QValueVector<QString>::iterator it = std::find( usedFontList.begin(), usedFontList.end(), fontName );
+// if ( it != usedFontList.end() ) {
+// uint pos = it - usedFontList.begin();
+// if ( pos < usedFontList.size()-1 ) {
+// QValueVector<QString>::iterator after = it+1;
+// std::swap( *it, *after );
+// requestedFonts->sort();
+// }
+// }
+// }
+// }
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+#include "kformulaconfigpage.moc"
diff --git a/lib/kformula/kformulaconfigpage.h b/lib/kformula/kformulaconfigpage.h
new file mode 100644
index 00000000..c5bc9b73
--- /dev/null
+++ b/lib/kformula/kformulaconfigpage.h
@@ -0,0 +1,150 @@
+/* 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.
+*/
+
+#ifndef kfconfigpages_h
+#define kfconfigpages_h
+
+#include <qfont.h>
+#include <qvaluevector.h>
+
+#include <kdialogbase.h>
+
+#include "kformuladefs.h"
+
+class QButtonGroup;
+class QCheckBox;
+class QColor;
+class QGridLayout;
+class QLabel;
+class QPushButton;
+class QSpinBox;
+class QStringList;
+class QWidget;
+
+class KColorButton;
+class KConfig;
+class KListView;
+class KPushButton;
+class KIntNumInput;
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+class Document;
+
+class KOFORMULA_EXPORT ConfigurePage : public QObject
+{
+ Q_OBJECT
+public:
+
+ ConfigurePage( Document* document, QWidget* view, KConfig* config, QVBox* box, char* name = 0 );
+ void apply();
+ void slotDefault();
+
+protected:
+
+ bool selectFont( QFont & );
+
+protected slots:
+
+ void syntaxHighlightingClicked();
+ void selectNewDefaultFont();
+ void selectNewNameFont();
+ void selectNewNumberFont();
+ void selectNewOperatorFont();
+
+ void baseSizeChanged( int value );
+ void slotChanged();
+
+private:
+
+ QPushButton* buildFontLine( QWidget* fontWidget, QGridLayout* layout, int number,
+ QFont font, QString name, QLabel*& fontName );
+
+ void updateFontLabel( QFont font, QLabel* label );
+
+ Document* m_document;
+ QWidget* m_view;
+ KConfig* m_config;
+
+ QFont defaultFont;
+ QFont nameFont;
+ QFont numberFont;
+ QFont operatorFont;
+
+ KIntNumInput* sizeSpin;
+
+ QLabel* defaultFontName;
+ QLabel* nameFontName;
+ QLabel* numberFontName;
+ QLabel* operatorFontName;
+
+// KColorButton* defaultColorBtn;
+// KColorButton* numberColorBtn;
+// KColorButton* operatorColorBtn;
+// KColorButton* emptyColorBtn;
+// KColorButton* errorColorBtn;
+ QCheckBox* syntaxHighlighting;
+
+ bool m_changed;
+};
+
+
+// class MathFontsConfigurePage : public QObject
+// {
+// Q_OBJECT
+// public:
+
+// MathFontsConfigurePage( Document* document, QWidget* view, KConfig* config, QVBox* box, char* name = 0 );
+// void apply();
+// void slotDefault();
+
+// QValueVector<QString>::iterator findUsedFont( QString name );
+
+// protected slots:
+
+// void slotAddFont();
+// void slotRemoveFont();
+// void slotMoveUp();
+// void slotMoveDown();
+
+// private:
+
+// void setupLists( const QStringList& usedFonts );
+
+// Document* m_document;
+// QWidget* m_view;
+// KConfig* m_config;
+
+// KListView* availableFonts;
+// KListView* requestedFonts;
+
+// KPushButton* addFont;
+// KPushButton* removeFont;
+// KPushButton* moveUp;
+// KPushButton* moveDown;
+
+// QValueVector<QString> usedFontList;
+// };
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // kfconfigpages_h
diff --git a/lib/kformula/kformulacontainer.cc b/lib/kformula/kformulacontainer.cc
new file mode 100644
index 00000000..84471e1b
--- /dev/null
+++ b/lib/kformula/kformulacontainer.cc
@@ -0,0 +1,643 @@
+/* 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 <qapplication.h>
+#include <qdom.h>
+#include <qevent.h>
+#include <qfile.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kprinter.h>
+
+#include "KoGlobal.h"
+#include "bracketelement.h"
+#include "contextstyle.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "fractionelement.h"
+#include "indexelement.h"
+#include "kformulacommand.h"
+#include "kformulacompatibility.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "kformulamathmlread.h"
+#include "kformulamimesource.h"
+#include "matrixelement.h"
+#include "rootelement.h"
+#include "sequenceelement.h"
+#include "symbolelement.h"
+#include "symboltable.h"
+#include "spaceelement.h"
+#include "textelement.h"
+
+#include <assert.h>
+
+KFORMULA_NAMESPACE_BEGIN
+using namespace std;
+
+
+struct Container::Container_Impl {
+
+ Container_Impl( Document* doc )
+ : dirty( true ), cursorMoved( false ), document( doc )
+ {
+ }
+
+ ~Container_Impl()
+ {
+ delete internCursor;
+ delete rootElement;
+ document = 0;
+ }
+
+ /**
+ * If true we need to recalc the formula.
+ */
+ bool dirty;
+
+ /**
+ * Tells whether a request caused the cursor to move.
+ */
+ bool cursorMoved;
+
+ /**
+ * The element tree's root.
+ */
+ FormulaElement* rootElement;
+
+ /**
+ * The active cursor is the one that triggered the last command.
+ */
+ FormulaCursor* activeCursor;
+
+ /**
+ * The cursor that is used if there is no view.
+ */
+ FormulaCursor* internCursor;
+
+ /**
+ * The document we belong to.
+ */
+ Document* document;
+};
+
+
+FormulaElement* Container::rootElement() const { return impl->rootElement; }
+Document* Container::document() const { return impl->document; }
+
+Container::Container( Document* doc, int pos, bool registerMe )
+{
+ impl = new Container_Impl( doc );
+ impl->rootElement = 0;
+ if ( registerMe ) {
+ registerFormula( pos );
+ }
+}
+
+Container::~Container()
+{
+ unregisterFormula();
+ delete impl;
+ impl = 0;
+}
+
+
+void Container::initialize()
+{
+ assert( impl->rootElement == 0 );
+ impl->rootElement = createMainSequence();
+ impl->activeCursor = impl->internCursor = createCursor();
+ recalc();
+}
+
+
+FormulaElement* Container::createMainSequence()
+{
+ return new FormulaElement( this );
+}
+
+
+FormulaCursor* Container::createCursor()
+{
+ return new FormulaCursor(rootElement());
+}
+
+
+KoCommandHistory* Container::getHistory() const
+{
+ return document()->getHistory();
+}
+
+
+/**
+ * Gets called just before the child is removed from
+ * the element tree.
+ */
+void Container::elementRemoval(BasicElement* child)
+{
+ emit elementWillVanish(child);
+}
+
+/**
+ * Gets called whenever something changes and we need to
+ * recalc.
+ */
+void Container::changed()
+{
+ impl->dirty = true;
+}
+
+void Container::cursorHasMoved( FormulaCursor* )
+{
+ impl->cursorMoved = true;
+}
+
+void Container::moveOutLeft( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_LEFT );
+}
+
+void Container::moveOutRight( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_RIGHT );
+}
+
+void Container::moveOutAbove( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_ABOVE );
+}
+
+void Container::moveOutBelow( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_BELOW );
+}
+
+void Container::tell( const QString& msg )
+{
+ emit statusMsg( msg );
+}
+
+void Container::removeFormula( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, REMOVE_FORMULA );
+}
+
+
+void Container::registerFormula( int pos )
+{
+ document()->registerFormula( this, pos );
+}
+
+void Container::unregisterFormula()
+{
+ document()->unregisterFormula( this );
+}
+
+
+void Container::baseSizeChanged( int size, bool owned )
+{
+ if ( owned ) {
+ emit baseSizeChanged( size );
+ }
+ else {
+ const ContextStyle& context = document()->getContextStyle();
+ emit baseSizeChanged( context.baseSize() );
+ }
+}
+
+FormulaCursor* Container::activeCursor()
+{
+ return impl->activeCursor;
+}
+
+const FormulaCursor* Container::activeCursor() const
+{
+ return impl->activeCursor;
+}
+
+
+/**
+ * Tells the formula that a view got the focus and might want to
+ * edit the formula.
+ */
+void Container::setActiveCursor(FormulaCursor* cursor)
+{
+ document()->activate(this);
+ if (cursor != 0) {
+ impl->activeCursor = cursor;
+ }
+ else {
+ *(impl->internCursor) = *(impl->activeCursor);
+ impl->activeCursor = impl->internCursor;
+ }
+}
+
+
+bool Container::hasValidCursor() const
+{
+ return (impl->activeCursor != 0) && !impl->activeCursor->isReadOnly();
+}
+
+void Container::testDirty()
+{
+ if (impl->dirty) {
+ recalc();
+ }
+}
+
+void Container::recalc()
+{
+ impl->dirty = false;
+ ContextStyle& context = impl->document->getContextStyle();
+ rootElement()->calcSizes( context );
+
+ emit formulaChanged( context.layoutUnitToPixelX( rootElement()->getWidth() ),
+ context.layoutUnitToPixelY( rootElement()->getHeight() ) );
+ emit formulaChanged( context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) ),
+ context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) ) );
+ emit cursorMoved( activeCursor() );
+}
+
+bool Container::isEmpty()
+{
+ return rootElement()->countChildren() == 0;
+}
+
+
+const SymbolTable& Container::getSymbolTable() const
+{
+ return document()->getSymbolTable();
+}
+
+
+void Container::draw( QPainter& painter, const QRect& r, const QColorGroup& cg, bool edit )
+{
+ painter.fillRect( r, cg.base() );
+ draw( painter, r, edit );
+}
+
+
+void Container::draw( QPainter& painter, const QRect& r, bool edit )
+{
+ //ContextStyle& context = document()->getContextStyle( painter.device()->devType() == QInternal::Printer );
+ ContextStyle& context = document()->getContextStyle( edit );
+ rootElement()->draw( painter, context.pixelToLayoutUnit( r ), context );
+}
+
+
+void Container::checkCursor()
+{
+ if ( impl->cursorMoved ) {
+ impl->cursorMoved = false;
+ emit cursorMoved( activeCursor() );
+ }
+}
+
+void Container::input( QKeyEvent* event )
+{
+ //if ( !hasValidCursor() )
+ if ( impl->activeCursor == 0 ) {
+ return;
+ }
+ execute( activeCursor()->getElement()->input( this, event ) );
+ checkCursor();
+}
+
+
+void Container::performRequest( Request* request )
+{
+ if ( !hasValidCursor() )
+ return;
+ execute( activeCursor()->getElement()->buildCommand( this, request ) );
+ checkCursor();
+}
+
+
+void Container::paste()
+{
+ if (!hasValidCursor())
+ return;
+ QClipboard* clipboard = QApplication::clipboard();
+ const QMimeSource* source = clipboard->data();
+ if (source->provides( MimeSource::selectionMimeType() )) {
+ QByteArray data = source->encodedData( MimeSource::selectionMimeType() );
+ QDomDocument formula;
+ formula.setContent(data);
+ paste( formula, i18n("Paste") );
+ }
+}
+
+void Container::paste( const QDomDocument& document, QString desc )
+{
+ FormulaCursor* cursor = activeCursor();
+ QPtrList<BasicElement> list;
+ list.setAutoDelete( true );
+ if ( cursor->buildElementsFromMathMLDom( document.documentElement(), list ) ) {
+ uint count = list.count();
+ // You must not execute an add command that adds nothing.
+ if (count > 0) {
+ KFCReplace* command = new KFCReplace( desc, this );
+ for (uint i = 0; i < count; i++) {
+ command->addElement(list.take(0));
+ }
+ execute(command);
+ }
+ }
+}
+
+void Container::copy()
+{
+ // read-only cursors are fine for copying.
+ FormulaCursor* cursor = activeCursor();
+ if (cursor != 0) {
+ QDomDocument formula = document()->createMathMLDomDocument();
+ cursor->copy( formula );
+ QClipboard* clipboard = QApplication::clipboard();
+ clipboard->setData(new MimeSource(document(), formula));
+ }
+}
+
+void Container::cut()
+{
+ if (!hasValidCursor())
+ return;
+ FormulaCursor* cursor = activeCursor();
+ if (cursor->isSelection()) {
+ copy();
+ DirectedRemove r( req_remove, beforeCursor );
+ performRequest( &r );
+ }
+}
+
+
+void Container::emitErrorMsg( const QString& msg )
+{
+ emit errorMsg( msg );
+}
+
+void Container::execute(KCommand* command)
+{
+ if ( command != 0 ) {
+ getHistory()->addCommand(command);
+ }
+}
+
+
+QRect Container::boundingRect() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ return QRect( context.layoutUnitToPixelX( rootElement()->getX() ),
+ context.layoutUnitToPixelY( rootElement()->getY() ),
+ context.layoutUnitToPixelX( rootElement()->getWidth() ),
+ context.layoutUnitToPixelY( rootElement()->getHeight() ) );
+}
+
+QRect Container::coveredRect()
+{
+ if ( impl->activeCursor != 0 ) {
+ const ContextStyle& context = document()->getContextStyle();
+ const LuPixelRect& cursorRect = impl->activeCursor->getCursorSize();
+ return QRect( context.layoutUnitToPixelX( rootElement()->getX() ),
+ context.layoutUnitToPixelY( rootElement()->getY() ),
+ context.layoutUnitToPixelX( rootElement()->getWidth() ),
+ context.layoutUnitToPixelY( rootElement()->getHeight() ) ) |
+ QRect( context.layoutUnitToPixelX( cursorRect.x() ),
+ context.layoutUnitToPixelY( cursorRect.y() ),
+ context.layoutUnitToPixelX( cursorRect.width() ),
+ context.layoutUnitToPixelY( cursorRect.height() ) );
+ }
+ return boundingRect();
+}
+
+double Container::width() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ return context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) );
+}
+
+double Container::height() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) );
+}
+
+double Container::baseline() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ //return context.layoutUnitToPixelY( rootElement()->getBaseline() );
+ return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getBaseline() ) );
+}
+
+void Container::moveTo( int x, int y )
+{
+ const ContextStyle& context = document()->getContextStyle();
+ rootElement()->setX( context.pixelToLayoutUnitX( x ) );
+ rootElement()->setY( context.pixelToLayoutUnitY( y ) );
+}
+
+int Container::fontSize() const
+{
+ if ( rootElement()->hasOwnBaseSize() ) {
+ return rootElement()->getBaseSize();
+ }
+ else {
+ const ContextStyle& context = document()->getContextStyle();
+ return qRound( context.baseSize() );
+ }
+}
+
+void Container::setFontSize( int pointSize, bool /*forPrint*/ )
+{
+ if ( rootElement()->getBaseSize() != pointSize ) {
+ execute( new KFCChangeBaseSize( i18n( "Base Size Change" ), this, rootElement(), pointSize ) );
+ }
+}
+
+void Container::setFontSizeDirect( int pointSize )
+{
+ rootElement()->setBaseSize( pointSize );
+ recalc();
+}
+
+void Container::updateMatrixActions()
+{
+ BasicElement *currentElement = activeCursor()->getElement();
+ if ( ( currentElement = currentElement->getParent() ) != 0 )
+ document()->wrapper()->enableMatrixActions( dynamic_cast<MatrixElement*>(currentElement) );
+ else
+ document()->wrapper()->enableMatrixActions( false );
+}
+
+void Container::save( QDomElement &root )
+{
+ QDomDocument ownerDoc = root.ownerDocument();
+ root.appendChild(rootElement()->getElementDom(ownerDoc));
+}
+
+
+/**
+ * Loads a formula from the document.
+ */
+bool Container::load( const QDomElement &fe )
+{
+ if (!fe.isNull()) {
+ FormulaElement* root = createMainSequence();
+ if (root->buildFromDom(fe)) {
+ delete impl->rootElement;
+ impl->rootElement = root;
+ emit formulaLoaded(rootElement());
+
+ recalc();
+ return true;
+ }
+ else {
+ delete root;
+ kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
+ }
+ }
+ else {
+ kdWarning( DEBUGID ) << "Empty element." << endl;
+ }
+ return false;
+}
+
+
+void Container::saveMathML( QTextStream& stream, bool oasisFormat )
+{
+ QDomDocument doc;
+ if ( !oasisFormat ) {
+ doc = document()->createMathMLDomDocument();
+ }
+ rootElement()->writeMathML( doc, doc, oasisFormat );
+ stream << doc;
+}
+
+bool Container::loadMathML( const QDomDocument &doc, bool oasisFormat )
+{
+ return loadMathML( doc.documentElement(), oasisFormat );
+}
+
+/*
+bool Container::loadMathML( const QDomElement &element, bool oasisFormat )
+{
+ const ContextStyle& context = document()->getContextStyle();
+ MathML2KFormula filter( element, context, oasisFormat );
+ filter.startConversion();
+ if (filter.m_error) {
+ return false;
+ }
+
+ if ( load( filter.getKFormulaDom().documentElement() ) ) {
+ getHistory()->clear();
+ return true;
+ }
+ return false;
+}
+*/
+
+bool Container::loadMathML( const QDomElement &fe, bool /*oasisFormat*/ )
+{
+ kdDebug( DEBUGID ) << "loadMathML" << endl;
+ if (!fe.isNull()) {
+ FormulaElement* root = createMainSequence();
+ if ( root->buildFromMathMLDom( fe ) != - 1) {
+ delete impl->rootElement;
+ impl->rootElement = root;
+ emit formulaLoaded(rootElement());
+
+ recalc();
+ return true;
+ }
+ else {
+ delete root;
+ kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
+ }
+ }
+ else {
+ kdWarning( DEBUGID ) << "Empty element." << endl;
+ }
+ return false;
+}
+
+
+void Container::print(KPrinter& printer)
+{
+ //printer.setFullPage(true);
+ QPainter painter;
+ if (painter.begin(&printer)) {
+ rootElement()->draw( painter, LuPixelRect( rootElement()->getX(),
+ rootElement()->getY(),
+ rootElement()->getWidth(),
+ rootElement()->getHeight() ),
+ document()->getContextStyle( false ) );
+ }
+}
+
+QImage Container::drawImage( int width, int height )
+{
+ ContextStyle& context = document()->getContextStyle( false );
+ QRect rect(impl->rootElement->getX(), impl->rootElement->getY(),
+ impl->rootElement->getWidth(), impl->rootElement->getHeight());
+
+ int realWidth = context.layoutUnitToPixelX( impl->rootElement->getWidth() );
+ int realHeight = context.layoutUnitToPixelY( impl->rootElement->getHeight() );
+
+ double f = QMAX( static_cast<double>( width )/static_cast<double>( realWidth ),
+ static_cast<double>( height )/static_cast<double>( realHeight ) );
+
+ int oldZoom = context.zoom();
+ context.setZoomAndResolution( qRound( oldZoom*f ), KoGlobal::dpiX(), KoGlobal::dpiY() );
+
+ kdDebug( DEBUGID ) << "Container::drawImage "
+ << "(" << width << " " << height << ")"
+ << "(" << context.layoutUnitToPixelX( impl->rootElement->getWidth() )
+ << " " << context.layoutUnitToPixelY( impl->rootElement->getHeight() ) << ")"
+ << endl;
+
+ QPixmap pm( context.layoutUnitToPixelX( impl->rootElement->getWidth() ),
+ context.layoutUnitToPixelY( impl->rootElement->getHeight() ) );
+ pm.fill();
+ QPainter paint(&pm);
+ impl->rootElement->draw(paint, rect, context);
+ paint.end();
+ context.setZoomAndResolution( oldZoom, KoGlobal::dpiX(), KoGlobal::dpiY() );
+ //return pm.convertToImage().smoothScale( width, height );
+ return pm.convertToImage();
+}
+
+QString Container::texString()
+{
+ return rootElement()->toLatex();
+}
+
+QString Container::formulaString()
+{
+ return rootElement()->formulaString();
+}
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+#include "kformulacontainer.moc"
diff --git a/lib/kformula/kformulacontainer.h b/lib/kformula/kformulacontainer.h
new file mode 100644
index 00000000..4d4254ab
--- /dev/null
+++ b/lib/kformula/kformulacontainer.h
@@ -0,0 +1,439 @@
+/* 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.
+*/
+
+#ifndef KFORMULACONTAINER_H
+#define KFORMULACONTAINER_H
+
+#include <qclipboard.h>
+#include <qdom.h>
+#include <qimage.h>
+#include <qptrlist.h>
+#include <qobject.h>
+#include <qptrstack.h>
+#include <qstring.h>
+
+#include <kcommand.h>
+//#include <KoCommandHistory.h>
+#include "KoCommandHistory.h"
+#include "kformuladefs.h"
+
+class QColorGroup;
+class QKeyEvent;
+class QPainter;
+
+class KCommand;
+class KPrinter;
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class Document;
+class FormulaCursor;
+class FormulaElement;
+class IndexElement;
+class PlainCommand;
+class SymbolTable;
+
+
+/**
+ * The interface the elements expect from its document.
+ *
+ * Please don't mistake this class for Document.
+ * This one represents one formula, the other one provides
+ * the context in which the formulae exist.
+ */
+class FormulaDocument {
+ // not allowed
+ FormulaDocument( const FormulaDocument& ) {}
+ FormulaDocument& operator=( const FormulaDocument& ) { return *this; }
+public:
+
+ FormulaDocument() {}
+ virtual ~FormulaDocument() {}
+
+ virtual void elementRemoval(BasicElement* /*child*/) {}
+ virtual void changed() {}
+ virtual void cursorHasMoved( FormulaCursor* ) {}
+ virtual void moveOutLeft( FormulaCursor* ) {}
+ virtual void moveOutRight( FormulaCursor* ) {}
+ virtual void moveOutAbove( FormulaCursor* ) {}
+ virtual void moveOutBelow( FormulaCursor* ) {}
+ virtual void tell( const QString& /*msg*/ ) {}
+ virtual void insertFormula( FormulaCursor* ) {}
+ virtual void removeFormula( FormulaCursor* ) {}
+ virtual void baseSizeChanged( int, bool ) {}
+ virtual const SymbolTable& getSymbolTable() const = 0;
+};
+
+
+/**
+ * The document. Actually only one part of the whole.
+ * Provides everything to edit the formula.
+ */
+class KOFORMULA_EXPORT Container : public QObject, public FormulaDocument {
+ friend class MimeSource;
+ Q_OBJECT
+
+ // no copying
+ Container( const Container& );
+ Container& operator= ( const Container& );
+
+public:
+
+ enum ViewActions { EXIT_LEFT, EXIT_RIGHT,
+ EXIT_ABOVE, EXIT_BELOW,
+ INSERT_FORMULA, REMOVE_FORMULA };
+
+ /**
+ * Constructs a new formula and register it with the document.
+ *
+ * @param doc the document we belong to.
+ * @param pos the formulas position inside its document.
+ * @param registerMe whether the formula is to be registered
+ * with the document.
+ */
+ Container( Document* doc, int pos, bool registerMe=true );
+ ~Container();
+
+ /**
+ * Needs to be called before anything else can be done with a
+ * newly created formula! This is required to allow polymorphic
+ * formulas. (The virtual method problem.)
+ */
+ void initialize();
+
+ /**
+ * Returns a new cursor. It points to the beginning of the
+ * formula. The cursor gets no messages if the formula changes
+ * so use this with care!
+ */
+ FormulaCursor* createCursor();
+
+ /**
+ * Gets called just before the child is removed from
+ * the element tree.
+ */
+ void elementRemoval(BasicElement* child);
+
+ /**
+ * Gets called when ever something changes and we need to
+ * recalc.
+ */
+ void changed();
+
+ /**
+ * Gets called when a request has the side effect of moving the
+ * cursor. In the end any operation that moves the cursor should
+ * call this.
+ */
+ void cursorHasMoved( FormulaCursor* );
+
+ /**
+ * Inside the formula occurred an event that must be handled
+ * outside.
+ */
+ void moveOutLeft( FormulaCursor* );
+ void moveOutRight( FormulaCursor* );
+ void moveOutAbove( FormulaCursor* );
+ void moveOutBelow( FormulaCursor* );
+ void tell( const QString& msg );
+ void removeFormula( FormulaCursor* );
+
+ /**
+ * Register and unregister this formula with its document.
+ */
+ void registerFormula( int pos=-1 );
+ void unregisterFormula();
+
+ /**
+ * The base size changed. If not owned it uses the default one now.
+ */
+ void baseSizeChanged( int size, bool owned );
+
+ /**
+ * Draws the whole thing.
+ */
+ void draw( QPainter& painter, const QRect& r,
+ const QColorGroup& cg, bool edit=false );
+
+ /**
+ * Draws the whole thing.
+ */
+ void draw( QPainter& painter, const QRect& r, bool edit=false );
+
+ /**
+ * Saves the data into the document.
+ */
+ void save( QDomElement &root );
+
+ /**
+ * Save formula as MathML.
+ */
+ void saveMathML( QTextStream& stream, bool oasisFormat = false );
+
+ /**
+ * Load function.
+ * Load the formula from the specified file containing MathML .
+ */
+ bool loadMathML( const QDomDocument &doc, bool oasisFormat = false );
+
+ /**
+ * Load function.
+ * Load the formula from the specified file containing MathML .
+ */
+ bool loadMathML( const QDomElement &doc, bool oasisFormat = false );
+
+ /**
+ * Loads a formula from the document.
+ */
+ bool load( const QDomElement &fe );
+
+ /**
+ * @returns Tex string for the formula
+ */
+ QString texString();
+
+ QString formulaString();
+
+ /**
+ * Prints the formula.
+ */
+ void print(KPrinter& printer);
+
+ /**
+ * @returns an image that looks like out formula.
+ */
+ QImage drawImage( int width, int height );
+
+ /**
+ * @returns the cursor to be used for editing.
+ */
+ FormulaCursor* activeCursor();
+ const FormulaCursor* activeCursor() const;
+
+ /**
+ * Sets the cursor that is to be used for any editing.
+ *
+ * The active cursor might 0. In this case you must not
+ * request any change from the formula.
+ */
+ void setActiveCursor(FormulaCursor* cursor);
+
+ /**
+ * @returns the formula's size.
+ */
+ QRect boundingRect() const;
+
+ /**
+ * @returns the formula's size including its active cursor.
+ */
+ QRect coveredRect();
+
+ double width() const;
+ double height() const;
+
+ /**
+ * @returns the distance between the upper bound and the formulas
+ * base line.
+ */
+ double baseline() const;
+
+ /**
+ * Moves the formula to a new location. This location will be the
+ * upper left corner of the rectangle that is drawn by the painter.
+ */
+ void moveTo( int x, int y );
+
+ /**
+ * KWord uses a transformed painter to draw formulas, so every
+ * formula has the internal position (0,0). But we might need to
+ * sort our formulas according to their position inside the
+ * document. (This is only needed for math formulas.)
+ */
+ virtual double getDocumentX() const { return -1; }
+ virtual double getDocumentY() const { return -1; }
+ virtual void setDocumentPosition( double /*x*/, double /*y*/ ) {}
+
+ /**
+ * Start the documents evaluation at this formula. This must be the
+ * formula that changed. The formulas above it won't be affected
+ * by this change.
+ *
+ * This has no meaning in not evaluating formulas.
+ */
+ virtual void startEvaluation() {}
+
+ /**
+ * Recalcs the formula and emits the .*Changed signals if needed.
+ */
+ void testDirty();
+
+ /**
+ * Recalc the formula.
+ */
+ virtual void recalc();
+
+ /**
+ * @returns true if there is no element.
+ */
+ bool isEmpty();
+
+ /**
+ * @returns the document this formula belongs to.
+ */
+ virtual Document* document() const;
+
+ virtual const SymbolTable& getSymbolTable() const;
+
+ int fontSize() const;
+
+ /**
+ * Sets the base font size of this formula.
+ */
+ void setFontSize( int pointSize, bool forPrint = false );
+
+ void setFontSizeDirect( int pointSize );
+
+ /**
+ If the cursor is in a matrix, the matrix actions will be enabled, otherwise disabled.
+ */
+ void updateMatrixActions();
+
+signals:
+
+ /**
+ * The cursor has been moved but the formula hasn't been
+ * changed. The view that owns the cursor needs to know this.
+ */
+ void cursorMoved(FormulaCursor* cursor);
+
+ /**
+ * The cursor wants to leave this formula.
+ */
+ void leaveFormula( Container* formula, FormulaCursor* cursor, int cmd );
+
+ /**
+ * The formula has changed and needs to be redrawn.
+ */
+ void formulaChanged( int width, int height );
+ void formulaChanged( double width, double height );
+
+ /**
+ * A message that might be a useful hint. Meant for the statusbar.
+ */
+ void statusMsg( const QString& msg );
+
+ /**
+ * A message that describes an error. Meant for a message box. (?)
+ */
+ void errorMsg( const QString& );
+
+ /**
+ * The element is going to leave the formula with and all its children.
+ */
+ void elementWillVanish(BasicElement* element);
+
+ /**
+ * Tells the cursors that we have just loaded a new formula.
+ */
+ void formulaLoaded(FormulaElement*);
+
+ /**
+ * We've got a new base size.
+ */
+ void baseSizeChanged( int );
+
+public:
+
+ /**
+ * General input.
+ */
+ void input( QKeyEvent* event );
+
+ void performRequest( Request* request );
+
+ // There are a lot of thing we can do with the formula.
+
+ /**
+ * Insert data from the clipboard.
+ */
+ void paste();
+
+ /**
+ * Insert data from the document.
+ */
+ void paste( const QDomDocument& document, QString desc );
+
+ /**
+ * Copy the current selection to the clipboard.
+ */
+ void copy();
+
+ /**
+ * Copy and remove.
+ */
+ void cut();
+
+protected:
+
+ KoCommandHistory* getHistory() const;
+
+ /**
+ * @returns the root of our element tree. That's the formula's structure.
+ */
+ FormulaElement* rootElement() const;
+
+ /**
+ * Factory method.
+ */
+ virtual FormulaElement* createMainSequence();
+
+ void emitErrorMsg( const QString& );
+
+private:
+
+ /**
+ * Execute the command if it makes sense.
+ */
+ void execute(KCommand *command);
+
+ /**
+ * Emits a signal if the cursor had moved.
+ */
+ void checkCursor();
+
+ /**
+ * @returns true if there is a cursor that is allowed to edit the formula.
+ */
+ bool hasValidCursor() const;
+
+ struct Container_Impl;
+ Container_Impl* impl;
+
+ // debug
+ friend class TestFormulaCursor;
+ friend class TestFormulaElement;
+ friend class TestIndexElement;
+ friend class TestCommands;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // KFORMULACONTAINER_H
diff --git a/lib/kformula/kformuladefs.h b/lib/kformula/kformuladefs.h
new file mode 100644
index 00000000..d42d0b16
--- /dev/null
+++ b/lib/kformula/kformuladefs.h
@@ -0,0 +1,430 @@
+/* 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.
+*/
+
+#ifndef FORMULADEFS_H
+#define FORMULADEFS_H
+
+#include <memory>
+
+#include <qpoint.h>
+#include <qrect.h>
+#include <qstring.h>
+
+#include <KoPoint.h>
+#include <KoRect.h>
+
+
+#define KFORMULA_NAMESPACE_BEGIN namespace KFormula {
+#define KFORMULA_NAMESPACE_END }
+
+KFORMULA_NAMESPACE_BEGIN
+
+const int DEBUGID = 40000;
+
+// to make kdDebug a litte more interessting...
+//#define TERM_RESET ""
+//#define TERM_ERROR ""
+
+/**
+ * The type to be used for points.
+ */
+typedef double pt;
+typedef KoPoint PtPoint;
+typedef KoRect PtRect;
+//typedef KoSize PtSize;
+
+/**
+ * Pixels. At any zoom level.
+ */
+typedef int pixel;
+typedef QPoint PixelPoint;
+typedef QRect PixelRect;
+//typedef QSize PixelSize;
+
+/**
+ * Layout Unit. That's the values we store to get
+ * wysiwyg right.
+ */
+typedef int luPt;
+typedef QPoint LuPtPoint;
+typedef QRect LuPtRect;
+typedef QSize LuPtSize;
+
+typedef int luPixel;
+typedef QPoint LuPixelPoint;
+typedef QRect LuPixelRect;
+typedef QSize LuPixelSize;
+
+
+/**
+ * The symbols that are supported by our artwork.
+ */
+enum SymbolType {
+ LeftSquareBracket = '[',
+ RightSquareBracket = ']',
+ LeftCurlyBracket = '{',
+ RightCurlyBracket = '}',
+ LeftCornerBracket = '<',
+ RightCornerBracket = '>',
+ LeftRoundBracket = '(',
+ RightRoundBracket = ')',
+ SlashBracket = '/',
+ BackSlashBracket = '\\',
+ LeftLineBracket = 256,
+ RightLineBracket,
+ EmptyBracket = 1000,
+ Integral,
+ Sum,
+ Product
+};
+
+
+/**
+ * Flag for cursor movement functions.
+ * Select means move selecting the text (usually Shift key)
+ * Word means move by whole words (usually Control key)
+ */
+enum MoveFlag { NormalMovement = 0, SelectMovement = 1, WordMovement = 2 };
+
+inline MoveFlag movementFlag( int state )
+{
+ int flag = NormalMovement;
+ if ( state & Qt::ControlButton )
+ flag |= WordMovement;
+ if ( state & Qt::ShiftButton )
+ flag |= SelectMovement;
+ return static_cast<MoveFlag>( flag );
+}
+
+
+
+/**
+ * TeX like char classes
+ */
+enum CharClass {
+ ORDINARY = 0,
+ BINOP = 1,
+ RELATION = 2,
+ PUNCTUATION = 3,
+
+ NUMBER, NAME, ELEMENT, INNER, BRACKET, SEQUENCE, SEPARATOR, END
+};
+
+typedef CharClass TokenType;
+
+
+// there are four bits needed to store this
+enum CharStyle {
+ normalChar,
+ boldChar,
+ italicChar,
+ boldItalicChar, // is required to be (boldChar | italicChar)!
+ //slantChar,
+ anyChar
+};
+
+
+enum CharFamily {
+ normalFamily,
+ scriptFamily,
+ frakturFamily,
+ doubleStruckFamily,
+ sansSerifFamily, // TODO: Currently unsupported
+ monospaceFamily, // TODO: Currently unsupported
+ anyFamily
+};
+
+enum TokenElementType {
+ identifierElement,
+ operatorElement,
+ numberElement,
+ textElement,
+ anyElement
+};
+
+/**
+ * The struct used to store static font data.
+ */
+struct InternFontTable {
+ short unicode;
+ QChar pos;
+ CharClass cl;
+ CharStyle style;
+};
+
+
+/**
+ * Wether we want to insert to the left of the cursor
+ * or right of it.
+ * The same for deletion.
+ */
+enum Direction { beforeCursor, afterCursor };
+
+/**
+ * The types of space we know.
+ */
+enum SpaceWidth { THIN, MEDIUM, THICK, QUAD, NEGTHIN };
+
+/**
+ * The types of MathML horizontal or vertical sizes we know
+ */
+enum SizeType {
+ NoSize,
+ AutoSize,
+ FitSize,
+ InfinitySize,
+ RelativeSize,
+ AbsoluteSize,
+ PixelSize,
+ NegativeVeryVeryThinMathSpace,
+ NegativeVeryThinMathSpace,
+ NegativeThinMathSpace,
+ NegativeMediumMathSpace,
+ NegativeThickMathSpace,
+ NegativeVeryThickMathSpace,
+ NegativeVeryVeryThickMathSpace,
+ VeryVeryThinMathSpace,
+ VeryThinMathSpace,
+ ThinMathSpace,
+ MediumMathSpace,
+ ThickMathSpace,
+ VeryThickMathSpace,
+ VeryVeryThickMathSpace
+};
+
+/**
+ * The types of horizontal align
+ */
+enum HorizontalAlign {
+ NoHorizontalAlign,
+ LeftHorizontalAlign,
+ CenterHorizontalAlign,
+ RightHorizontalAlign
+};
+
+/**
+ * Type of forms in operators
+ */
+enum FormType { NoForm, PrefixForm, InfixForm, PostfixForm };
+
+/**
+ * each index has its own number.
+ */
+enum IndexPosition {
+ upperLeftPos,
+ lowerLeftPos,
+ upperMiddlePos,
+ contentPos,
+ lowerMiddlePos,
+ upperRightPos,
+ lowerRightPos,
+ parentPos
+};
+
+
+class BasicElement;
+class FormulaCursor;
+
+/**
+ * A type that describes an index. You can get one of those
+ * for each index from an element that owns indexes.
+ *
+ * This type is used to work on indexes in a generic way.
+ */
+class ElementIndex {
+public:
+
+ virtual ~ElementIndex() { /*cerr << "ElementIndex destroyed.\n";*/ }
+
+ /**
+ * Moves the cursor inside the index. The index has to exist.
+ */
+ virtual void moveToIndex(FormulaCursor*, Direction) = 0;
+
+ /**
+ * Sets the cursor to point to the place where the index normaly
+ * is. These functions are only used if there is no such index and
+ * we want to insert them.
+ */
+ virtual void setToIndex(FormulaCursor*) = 0;
+
+ /**
+ * Tells whether we own those indexes.
+ */
+ virtual bool hasIndex() const = 0;
+
+ /**
+ * Tells to which element the index belongs.
+ */
+ virtual BasicElement* getElement() = 0;
+};
+
+typedef std::auto_ptr<ElementIndex> ElementIndexPtr;
+
+enum RequestID {
+ req_addBracket,
+ req_addOverline,
+ req_addUnderline,
+ req_addFraction,
+ req_addIndex,
+ req_addMatrix,
+ req_addMultiline,
+ req_addNameSequence,
+ req_addNewline,
+ req_addOneByTwoMatrix,
+ req_addRoot,
+ req_addSpace,
+ req_addSymbol,
+ req_addTabMark,
+ req_addText,
+ req_addTextChar,
+ req_addOperator,
+ req_addNumber,
+ req_addEmptyBox,
+ req_appendColumn,
+ req_appendRow,
+ req_compactExpression,
+ req_copy,
+ req_cut,
+ req_insertColumn,
+ req_insertRow,
+ req_makeGreek,
+ req_paste,
+ req_remove,
+ req_removeEnclosing,
+ req_removeColumn,
+ req_removeRow,
+ req_formatBold,
+ req_formatItalic,
+ req_formatFamily,
+ req_formatTokenElement
+};
+
+
+class Request {
+ RequestID id;
+public:
+ Request( RequestID _id ) : id( _id ) {}
+ virtual ~Request() {}
+ operator RequestID() const { return id;}
+};
+
+
+class BracketRequest : public Request {
+ SymbolType m_left, m_right;
+public:
+ BracketRequest( SymbolType l, SymbolType r ) : Request( req_addBracket ), m_left( l ), m_right( r ) {}
+ SymbolType left() const { return m_left; }
+ SymbolType right() const { return m_right; }
+};
+
+class SymbolRequest : public Request {
+ SymbolType m_type;
+public:
+ SymbolRequest( SymbolType t ) : Request( req_addSymbol ), m_type( t ) {}
+ SymbolType type() const { return m_type; }
+};
+
+class IndexRequest : public Request {
+ IndexPosition m_index;
+public:
+ IndexRequest( IndexPosition i ) : Request( req_addIndex ), m_index( i ) {}
+ IndexPosition index() const { return m_index; }
+};
+
+class SpaceRequest : public Request {
+ SpaceWidth m_space;
+public:
+ SpaceRequest( SpaceWidth s ) : Request( req_addSpace ), m_space( s ) {}
+ SpaceWidth space() const { return m_space; }
+};
+
+class DirectedRemove : public Request {
+ Direction m_direction;
+public:
+ DirectedRemove( RequestID id, Direction d ) : Request( id ), m_direction( d ) {}
+ Direction direction() const { return m_direction; }
+};
+
+class TextCharRequest : public Request {
+ QChar m_ch;
+ bool m_isSymbol;
+public:
+ TextCharRequest( QChar ch, bool isSymbol=false ) : Request( req_addTextChar ), m_ch( ch ), m_isSymbol( isSymbol ) {}
+ QChar ch() const { return m_ch; }
+ bool isSymbol() const { return m_isSymbol; }
+};
+
+class OperatorRequest: public Request {
+ QChar m_ch;
+public:
+ OperatorRequest( QChar ch ) : Request( req_addOperator ), m_ch( ch ) {}
+ QChar ch() const { return m_ch; }
+};
+
+class NumberRequest: public Request {
+ QChar m_ch;
+public:
+ NumberRequest( QChar ch ) : Request( req_addNumber ), m_ch( ch ) {}
+ QChar ch() const { return m_ch; }
+};
+
+class TextRequest : public Request {
+ QString m_text;
+public:
+ TextRequest( QString text ) : Request( req_addText ), m_text( text ) {}
+ QString text() const { return m_text; }
+};
+
+class MatrixRequest : public Request {
+ uint m_rows, m_columns;
+public:
+ MatrixRequest( uint rows, uint columns ) : Request( req_addMatrix ), m_rows( rows ), m_columns( columns ) {}
+ uint rows() const { return m_rows; }
+ uint columns() const { return m_columns; }
+};
+
+class CharStyleRequest : public Request {
+ bool m_bold;
+ bool m_italic;
+public:
+ CharStyleRequest( RequestID id, bool bold, bool italic ) : Request( id ), m_bold( bold ), m_italic( italic ) {}
+ bool bold() const { return m_bold; }
+ bool italic() const { return m_italic; }
+};
+
+class CharFamilyRequest : public Request {
+ CharFamily m_charFamily;
+public:
+ CharFamilyRequest( CharFamily cf ) : Request( req_formatFamily ), m_charFamily( cf ) {}
+ CharFamily charFamily() const { return m_charFamily; }
+};
+
+class TokenElementRequest : public Request {
+ TokenElementType m_tokenElement;
+public:
+ TokenElementRequest( TokenElementType te ) : Request( req_formatTokenElement ), m_tokenElement( te ) {}
+ TokenElementType tokenElement() const { return m_tokenElement; }
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // FORMULADEFS_H
diff --git a/lib/kformula/kformuladocument.cc b/lib/kformula/kformuladocument.cc
new file mode 100644
index 00000000..57b5bc04
--- /dev/null
+++ b/lib/kformula/kformuladocument.cc
@@ -0,0 +1,1299 @@
+/* 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 <qptrlist.h>
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <ksimpleconfig.h>
+#include <kstandarddirs.h>
+
+#include <KoDocument.h>
+
+#include "contextstyle.h"
+#include "creationstrategy.h"
+#include "oasiscreationstrategy.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "sequenceelement.h"
+#include "symboltable.h"
+#include "symbolaction.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+static const int CURRENT_SYNTAX_VERSION = 1;
+// Make sure an appropriate DTD is available in www/koffice/DTD if changing this value
+static const char * CURRENT_DTD_VERSION = "1.3";
+
+int FormulaList::compareItems( QPtrCollection::Item a, QPtrCollection::Item b )
+{
+ double ya = static_cast<Container*>( a )->getDocumentY();
+ double yb = static_cast<Container*>( b )->getDocumentY();
+ if ( fabs( ya-yb ) < 1e-4 ) {
+ double xa = static_cast<Container*>( a )->getDocumentX();
+ double xb = static_cast<Container*>( b )->getDocumentX();
+ if ( xa < xb ) return -1;
+ if ( xa > xb ) return 1;
+ return 0;
+ }
+ if ( ya < yb ) return -1;
+ return 1;
+}
+
+
+Document::Document( QObject *parent, const char *name,
+ const QStringList &/*args*/ )
+ : QObject( parent, name ), m_wrapper( 0 ), m_formula( 0 ), creationStrategy( 0 )
+{
+ m_contextStyle = new ContextStyle;
+ setCreationStrategy( "Oasis" );
+ formulae.setAutoDelete( false );
+}
+
+
+Document::~Document()
+{
+ // Destroy remaining formulae. We do it backward because
+ // the formulae remove themselves from this document upon
+ // destruction.
+ int count = formulae.count();
+ for ( int i=count-1; i>=0; --i ) {
+ delete formulae.at( i );
+ }
+ delete m_contextStyle;
+}
+
+
+bool Document::hasFormula()
+{
+ return ( m_formula != 0 ) && ( m_formula->activeCursor() != 0 );
+}
+
+
+Container* Document::createFormula( int pos, bool registerMe )
+{
+ Container* formula = new Container( this, pos, registerMe );
+ formula->initialize();
+ return formula;
+}
+
+
+QPtrListIterator<Container> Document::formulas()
+{
+ return QPtrListIterator<Container>( formulae );
+}
+
+
+int Document::formulaPos( Container* formula )
+{
+ return formulae.find( formula );
+}
+
+
+Container* Document::formulaAt( uint pos )
+{
+ return formulae.at( pos );
+}
+
+
+int Document::formulaCount()
+{
+ return formulae.count();
+}
+
+
+bool Document::loadXML( const QDomDocument& doc )
+{
+ setCreationStrategy( "Ordinary" );
+
+ //clear();
+ QDomElement root = doc.documentElement();
+
+ // backward compatibility
+ if ( root.tagName() == "FORMULA" ) {
+ Container* formula = newFormula( 0 );
+ return formula->load( root );
+ }
+
+ QDomNode node = root.firstChild();
+ if ( node.isElement() ) {
+ QDomElement element = node.toElement();
+ if ( element.tagName() == "FORMULASETTINGS" ) {
+ if ( !loadDocumentPart( element ) ) {
+ return false;
+ }
+ }
+ node = node.nextSibling();
+ }
+ uint number = 0;
+ while ( !node.isNull() ) {
+ if ( node.isElement() ) {
+ QDomElement element = node.toElement();
+ Container* formula = newFormula( number );
+ if ( !formula->load( element ) ) {
+ return false;
+ }
+ number += 1;
+ }
+ node = node.nextSibling();
+ }
+ return formulae.count() > 0;
+}
+
+bool Document::loadOasis( const QDomDocument& doc )
+{
+ // ### TODO: not finished!
+ setCreationStrategy( "Oasis" );
+ KFormula::Container* formula = newFormula( 0 );
+ return formula->loadMathML( doc, true );
+}
+
+bool Document::loadDocumentPart( QDomElement /*node*/ )
+{
+ return true;
+}
+
+QDomDocument Document::saveXML()
+{
+ QDomDocument doc = createDomDocument();
+ QDomElement root = doc.documentElement();
+ root.appendChild( saveDocumentPart( doc ) );
+ uint count = formulae.count();
+ for ( uint i=0; i<count; ++i ) {
+ formulae.at( i )->save( root );
+ }
+ return doc;
+}
+
+
+QDomElement Document::saveDocumentPart( QDomDocument& doc )
+{
+ QDomElement settings = doc.createElement( "FORMULASETTINGS" );
+ return settings;
+}
+
+
+QDomDocument Document::createDomDocument()
+{
+ return KoDocument::createDomDocument( "kformula", "KFORMULA",
+ CURRENT_DTD_VERSION );
+}
+
+/**
+ * Create a MathML Dom Document, deprecates KFO Dom Document for internal layout
+ * TODO: Shouldn't this go to KoDocument ?
+ */
+QDomDocument Document::createMathMLDomDocument()
+{
+ QDomDocumentType dt =
+ QDomImplementation().createDocumentType( "math",
+ "-//W3C//DTD MathML 2.0//EN",
+ "http://www.w3.org/TR/MathML2/dtd/mathml2.dtd");
+ QDomDocument doc( dt );
+ doc.insertBefore( doc.createProcessingInstruction( "xml",
+ "version=\"1.0\" encoding=\"UTF-8\"" ),
+ doc.documentElement() );
+ return doc;
+}
+
+/**
+ * Set formula creation strategy: old KFormula or MathML/ODF.
+ * This tells which tags are valid during formula constructions
+ *
+ * @param strategy -- "Ordinary" for old Kformula, "Oasis" for MathML/ODF
+ */
+void Document::setCreationStrategy( QString strategy )
+{
+ if ( !creationStrategy || creationStrategy->type() != strategy ) {
+ delete creationStrategy;
+ if ( strategy == "Ordinary" )
+ creationStrategy = new OrdinaryCreationStrategy;
+ else
+ creationStrategy = new OasisCreationStrategy;
+ SequenceElement::setCreationStrategy( creationStrategy );
+ }
+}
+
+void Document::registerFormula( Container* f, int pos )
+{
+ if ( ( pos > -1 ) &&
+ ( static_cast<uint>( pos ) < formulae.count() ) ) {
+ formulae.insert( pos, f );
+ //emit sigInsertFormula( f, pos );
+ }
+ else {
+ formulae.append( f );
+ //emit sigInsertFormula( f, formulae.count()-1 );
+ }
+}
+
+void Document::unregisterFormula( Container* f )
+{
+ if ( m_formula == f ) {
+ m_formula = 0;
+ }
+ formulae.removeRef( f );
+}
+
+void Document::activate(Container* f)
+{
+ m_formula = f;
+}
+
+
+void Document::sortFormulaList()
+{
+ formulae.sort();
+}
+
+
+Container* Document::newFormula( uint number )
+{
+ if ( number < formulae.count() ) {
+ return formulae.at( number );
+ }
+ return createFormula();
+}
+
+
+double Document::getXResolution() const
+{
+ return m_contextStyle->zoomedResolutionX();
+}
+double Document::getYResolution() const
+{
+ return m_contextStyle->zoomedResolutionY();
+}
+
+const SymbolTable& Document::getSymbolTable() const
+{
+ return m_contextStyle->symbolTable();
+}
+
+ContextStyle& Document::getContextStyle( bool edit )
+{
+ m_contextStyle->setEdit( edit );
+ return *m_contextStyle;
+}
+
+void Document::setZoomAndResolution( int zoom, int dpiX, int dpiY )
+{
+ m_contextStyle->setZoomAndResolution( zoom, dpiX, dpiY );
+}
+
+void Document::newZoomAndResolution( bool updateViews, bool /*forPrint*/ )
+{
+ if ( updateViews ) {
+ recalc();
+ }
+}
+
+void Document::setZoomAndResolution( int zoom,
+ double zoomX, double zoomY,
+ bool updateViews, bool forPrint )
+{
+ if ( getContextStyle( !forPrint ).setZoomAndResolution( zoom, zoomX, zoomY, updateViews, forPrint ) && updateViews ) {
+ recalc();
+ }
+}
+
+
+SymbolType Document::leftBracketChar()
+{
+ return m_wrapper->leftBracketChar();
+}
+
+SymbolType Document::rightBracketChar()
+{
+ return m_wrapper->rightBracketChar();
+}
+
+
+void Document::setEnabled( bool enabled )
+{
+ m_wrapper->setEnabled( enabled );
+}
+
+
+KoCommandHistory* Document::getHistory() const
+{
+ return m_wrapper->getHistory();
+}
+
+
+void Document::recalc()
+{
+ for ( Container* f = formulae.first();
+ f != 0;
+ f=formulae.next() ) {
+ f->recalc();
+ }
+}
+
+
+void Document::updateConfig()
+{
+ m_wrapper->updateConfig();
+ recalc();
+}
+
+
+void Document::introduceWrapper( DocumentWrapper* wrapper, bool init )
+{
+ m_wrapper = wrapper;
+ m_contextStyle->readConfig( wrapper->config(), init );
+ m_contextStyle->init( init );
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+DocumentWrapper::DocumentWrapper( KConfig* config,
+ KActionCollection* collection,
+ KoCommandHistory* history )
+ : m_document( 0 ),
+ m_leftBracketChar( LeftRoundBracket ),
+ m_rightBracketChar( RightRoundBracket ),
+ m_config( config ),
+ m_hasActions( collection != 0 )
+{
+ if ( m_hasActions ) {
+ createActions( collection );
+ enableMatrixActions( false );
+ }
+ setCommandStack( history );
+}
+
+
+DocumentWrapper::~DocumentWrapper()
+{
+ delete m_document;
+ if ( m_ownHistory ) {
+ delete m_history;
+ }
+
+ if ( m_hasActions )
+ {
+ m_config->setGroup("General");
+ m_config->writeEntry("syntaxHighlighting", m_syntaxHighlightingAction->isChecked() );
+ }
+}
+
+
+void DocumentWrapper::document( Document* document, bool init )
+{
+ m_document = document;
+ m_document->introduceWrapper( this, init );
+ initSymbolNamesAction();
+ m_config->setGroup("General");
+ if ( m_hasActions )
+ {
+ m_syntaxHighlightingAction->setChecked( m_config->readBoolEntry("syntaxHighlighting", true ) );
+ if ( !m_syntaxHighlightingAction->isChecked() )
+ toggleSyntaxHighlighting();
+ }
+ else if ( m_config->readBoolEntry("syntaxHighlighting", true ) )
+ {
+ m_document->m_contextStyle->setSyntaxHighlighting( true );
+ // Only to notify all views. We don't expect to get new values.
+ m_document->recalc();
+ }
+}
+
+
+void DocumentWrapper::setCommandStack( KoCommandHistory* history )
+{
+ if ( history == 0 ) {
+ m_history = new KoCommandHistory;
+ m_ownHistory = true;
+ }
+ else {
+ m_history = history;
+ m_ownHistory = false;
+ }
+}
+
+
+void DocumentWrapper::createActions( KActionCollection* collection )
+{
+ KGlobal::dirs()->addResourceType( "toolbar",
+ KStandardDirs::kde_default("data") +
+ "kformula/pics/" );
+
+ m_addNegThinSpaceAction = new KAction( i18n( "Add Negative Thin Space" ),
+ 0,
+ this, SLOT( addNegThinSpace() ),
+ collection, "formula_addnegthinspace") ;
+ m_addThinSpaceAction = new KAction( i18n( "Add Thin Space" ),
+ 0,
+ this, SLOT( addThinSpace() ),
+ collection, "formula_addthinspace") ;
+ m_addMediumSpaceAction = new KAction( i18n( "Add Medium Space" ),
+ 0,
+ this, SLOT( addMediumSpace() ),
+ collection, "formula_addmediumspace" );
+ m_addThickSpaceAction = new KAction( i18n( "Add Thick Space" ),
+ 0,
+ this, SLOT( addThickSpace() ),
+ collection, "formula_addthickspace" );
+ m_addQuadSpaceAction = new KAction( i18n( "Add Quad Space" ),
+ 0,
+ this, SLOT( addQuadSpace() ),
+ collection, "formula_addquadspace" );
+
+ m_addIntegralAction = new KAction(i18n("Add Integral"),
+ "int",
+ 0,
+ this, SLOT(addIntegral()),
+ collection, "formula_addintegral");
+ m_addSumAction = new KAction(i18n("Add Sum"),
+ "sum",
+ 0,
+ this, SLOT(addSum()),
+ collection, "formula_addsum");
+ m_addProductAction = new KAction(i18n("Add Product"),
+ "prod",
+ 0,
+ this, SLOT(addProduct()),
+ collection, "formula_addproduct");
+ m_addRootAction = new KAction(i18n("Add Root"),
+ "sqrt",
+ 0,
+ this, SLOT(addRoot()),
+ collection, "formula_addroot");
+ m_addFractionAction = new KAction(i18n("Add Fraction"),
+ "frac",
+ 0,
+ this, SLOT(addFraction()),
+ collection, "formula_addfrac");
+ m_addBracketAction = new KAction(i18n("Add Bracket"),
+ "paren",
+ 0,
+ this, SLOT(addDefaultBracket()),
+ collection,"formula_addbra");
+ m_addSBracketAction = new KAction(i18n("Add Square Bracket"),
+ "brackets",
+ 0,
+ this, SLOT(addSquareBracket()),
+ collection,"formula_addsqrbra");
+ m_addCBracketAction = new KAction(i18n("Add Curly Bracket"),
+ "math_brace",
+ 0,
+ this, SLOT(addCurlyBracket()),
+ collection,"formula_addcurbra");
+ m_addAbsAction = new KAction(i18n("Add Abs"),
+ "abs",
+ 0,
+ this, SLOT(addLineBracket()),
+ collection,"formula_addabsbra");
+
+ m_addMatrixAction = new KAction(i18n("Add Matrix..."),
+ "matrix",
+ 0,
+ this, SLOT(addMatrix()),
+ collection, "formula_addmatrix");
+
+ m_addOneByTwoMatrixAction = new KAction(i18n("Add 1x2 Matrix"),
+ "onetwomatrix",
+ 0,
+ this, SLOT(addOneByTwoMatrix()),
+ collection, "formula_add_one_by_two_matrix");
+
+
+ m_addUpperLeftAction = new KAction(i18n("Add Upper Left Index"),
+ "lsup",
+ 0,
+ this, SLOT(addUpperLeftIndex()),
+ collection, "formula_addupperleft");
+ m_addLowerLeftAction = new KAction(i18n("Add Lower Left Index"),
+ "lsub",
+ 0,
+ this, SLOT(addLowerLeftIndex()),
+ collection, "formula_addlowerleft");
+ m_addUpperRightAction = new KAction(i18n("Add Upper Right Index"),
+ "rsup",
+ 0,
+ this, SLOT(addUpperRightIndex()),
+ collection, "formula_addupperright");
+ m_addLowerRightAction = new KAction(i18n("Add Lower Right Index"),
+ "rsub",
+ 0,
+ this, SLOT(addLowerRightIndex()),
+ collection, "formula_addlowerright");
+
+ m_addGenericUpperAction = new KAction(i18n("Add Upper Index"),
+ "gsup",
+ /*CTRL + Key_U*/0,
+ this, SLOT(addGenericUpperIndex()),
+ collection, "formula_addupperindex");
+ m_addGenericLowerAction = new KAction(i18n("Add Lower Index"),
+ "gsub",
+ 0,
+ this, SLOT(addGenericLowerIndex()),
+ collection, "formula_addlowerindex");
+
+ m_addOverlineAction = new KAction(i18n("Add Overline"),
+ "over",
+ 0,
+ this, SLOT(addOverline()),
+ collection, "formula_addoverline");
+ m_addUnderlineAction = new KAction(i18n("Add Underline"),
+ "under",
+ 0,
+ this, SLOT(addUnderline()),
+ collection, "formula_addunderline");
+
+ m_addMultilineAction = new KAction(i18n("Add Multiline"),
+ "multiline",
+ 0,
+ this, SLOT(addMultiline()),
+ collection, "formula_addmultiline");
+
+ m_removeEnclosingAction = new KAction(i18n("Remove Enclosing Element"),
+ 0,
+ this, SLOT(removeEnclosing()),
+ collection, "formula_removeenclosing");
+
+ m_makeGreekAction = new KAction(i18n("Convert to Greek"),
+ 0,
+ this, SLOT(makeGreek()),
+ collection, "formula_makegreek");
+
+ m_appendColumnAction = new KAction( i18n( "Append Column" ),
+ "inscol",
+ 0,
+ this, SLOT( appendColumn() ),
+ collection, "formula_appendcolumn" );
+ m_insertColumnAction = new KAction( i18n( "Insert Column" ),
+ "inscol",
+ 0,
+ this, SLOT( insertColumn() ),
+ collection, "formula_insertcolumn" );
+ m_removeColumnAction = new KAction( i18n( "Remove Column" ),
+ "remcol",
+ 0,
+ this, SLOT( removeColumn() ),
+ collection, "formula_removecolumn" );
+ m_appendRowAction = new KAction( i18n( "Append Row" ),
+ "insrow",
+ 0,
+ this, SLOT( appendRow() ),
+ collection, "formula_appendrow" );
+ m_insertRowAction = new KAction( i18n( "Insert Row" ),
+ "insrow",
+ 0,
+ this, SLOT( insertRow() ),
+ collection, "formula_insertrow" );
+ m_removeRowAction = new KAction( i18n( "Remove Row" ),
+ "remrow",
+ 0,
+ this, SLOT( removeRow() ),
+ collection, "formula_removerow" );
+
+ m_syntaxHighlightingAction = new KToggleAction(i18n("Syntax Highlighting"),
+ 0,
+ this, SLOT(toggleSyntaxHighlighting()),
+ collection, "formula_syntaxhighlighting");
+ //m_syntaxHighlightingAction->setChecked( m_contextStyle->syntaxHighlighting() );
+
+ m_formatBoldAction = new KToggleAction( i18n( "&Bold" ), "text_bold",
+ 0, //CTRL + Key_B,
+ this, SLOT( textBold() ),
+ collection, "formula_format_bold" );
+ m_formatItalicAction = new KToggleAction( i18n( "&Italic" ), "text_italic",
+ 0, //CTRL + Key_I,
+ this, SLOT( textItalic() ),
+ collection, "formula_format_italic" );
+ m_formatBoldAction->setEnabled( false );
+ m_formatItalicAction->setEnabled( false );
+
+ QStringList delimiter;
+ delimiter.append(QString("("));
+ delimiter.append(QString("["));
+ delimiter.append(QString("{"));
+ delimiter.append(QString("<"));
+ delimiter.append(QString("/"));
+ delimiter.append(QString("\\"));
+ delimiter.append(QString("|"));
+ delimiter.append(QString(" "));
+ delimiter.append(QString(")"));
+ delimiter.append(QString("]"));
+ delimiter.append(QString("}"));
+ delimiter.append(QString(">"));
+ m_leftBracket = new KSelectAction(i18n("Left Delimiter"),
+ 0, this, SLOT(delimiterLeft()),
+ collection, "formula_typeleft");
+ m_leftBracket->setItems(delimiter);
+ //leftBracket->setCurrentItem(0);
+
+ delimiter.clear();
+ delimiter.append(QString(")"));
+ delimiter.append(QString("]"));
+ delimiter.append(QString("}"));
+ delimiter.append(QString(">"));
+ delimiter.append(QString("/"));
+ delimiter.append(QString("\\"));
+ delimiter.append(QString("|"));
+ delimiter.append(QString(" "));
+ delimiter.append(QString("("));
+ delimiter.append(QString("["));
+ delimiter.append(QString("{"));
+ delimiter.append(QString("<"));
+ m_rightBracket = new KSelectAction(i18n("Right Delimiter"),
+ 0, this, SLOT(delimiterRight()),
+ collection, "formula_typeright");
+ m_rightBracket->setItems(delimiter);
+ //rightBracket->setCurrentItem(0);
+
+ m_insertSymbolAction = new KAction(i18n("Insert Symbol"),
+ "key_enter",
+ /*CTRL + Key_I*/0,
+ this, SLOT(insertSymbol()),
+ collection, "formula_insertsymbol");
+ m_symbolNamesAction = new SymbolAction(i18n("Symbol Names"),
+ 0, this, SLOT(symbolNames()),
+ collection, "formula_symbolnames");
+
+ QStringList ff;
+ ff.append( i18n( "Normal" ) );
+ ff.append( i18n( "Script" ) );
+ ff.append( i18n( "Fraktur" ) );
+ ff.append( i18n( "Double Struck" ) );
+ m_fontFamily = new KSelectAction(i18n("Font Family"),
+ 0, this, SLOT(fontFamily()),
+ collection, "formula_fontfamily");
+ m_fontFamily->setItems( ff );
+ m_fontFamily->setEnabled( false );
+
+ QStringList et;
+ et.append( i18n( "Identifier" ) );
+ et.append( i18n( "Operator" ) );
+ et.append( i18n( "Number" ) );
+ et.append( i18n( "Text" ) );
+ m_tokenElement = new KSelectAction( i18n( "Token Type" ),
+ 0, this, SLOT( tokenElement() ),
+ collection, "formula_tokenelement" );
+ m_tokenElement->setItems( et );
+// m_tokenElements->setEnabled( true );
+}
+
+
+void DocumentWrapper::paste()
+{
+ if (hasFormula()) {
+ formula()->paste();
+ }
+}
+
+void DocumentWrapper::copy()
+{
+ if (hasFormula()) {
+ formula()->copy();
+ }
+}
+
+void DocumentWrapper::cut()
+{
+ if (hasFormula()) {
+ formula()->cut();
+ }
+}
+
+void DocumentWrapper::undo()
+{
+ m_history->undo();
+}
+
+void DocumentWrapper::redo()
+{
+ m_history->redo();
+}
+
+void DocumentWrapper::addNegThinSpace()
+{
+ if (hasFormula()) {
+ SpaceRequest r( NEGTHIN );
+ formula()->performRequest( &r );
+ }
+}
+void DocumentWrapper::addThinSpace()
+{
+ if (hasFormula()) {
+ SpaceRequest r( THIN );
+ formula()->performRequest( &r );
+ }
+}
+void DocumentWrapper::addMediumSpace()
+{
+ if (hasFormula()) {
+ SpaceRequest r( MEDIUM );
+ formula()->performRequest( &r );
+ }
+}
+void DocumentWrapper::addThickSpace()
+{
+ if (hasFormula()) {
+ SpaceRequest r( THICK );
+ formula()->performRequest( &r );
+ }
+}
+void DocumentWrapper::addQuadSpace()
+{
+ if (hasFormula()) {
+ SpaceRequest r( QUAD );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addDefaultBracket()
+{
+ if (hasFormula()) {
+ BracketRequest r( m_leftBracketChar, m_rightBracketChar );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addBracket( SymbolType left, SymbolType right )
+{
+ if (hasFormula()) {
+ BracketRequest r( left, right );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addParenthesis()
+{
+ if (hasFormula()) {
+ BracketRequest r( LeftRoundBracket, RightRoundBracket );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addSquareBracket()
+{
+ if (hasFormula()) {
+ BracketRequest r( LeftSquareBracket, RightSquareBracket );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addCurlyBracket()
+{
+ if (hasFormula()) {
+ BracketRequest r( LeftCurlyBracket, RightCurlyBracket );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addLineBracket()
+{
+ if (hasFormula()) {
+ BracketRequest r( LeftLineBracket, RightLineBracket );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addFraction()
+{
+ if (hasFormula()) {
+ Request r( req_addFraction );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addRoot()
+{
+ if (hasFormula()) {
+ Request r( req_addRoot );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addIntegral()
+{
+ if (hasFormula()) {
+ SymbolRequest r( Integral );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addProduct()
+{
+ if (hasFormula()) {
+ SymbolRequest r( Product );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addSum()
+{
+ if (hasFormula()) {
+ SymbolRequest r( Sum );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addMatrix( uint rows, uint columns )
+{
+ if (hasFormula()) {
+ MatrixRequest r( rows, columns );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addOneByTwoMatrix()
+{
+ if (hasFormula()) {
+ Request r( req_addOneByTwoMatrix );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addNameSequence()
+{
+ if (hasFormula()) {
+ Request r( req_addNameSequence );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addLowerLeftIndex()
+{
+ if (hasFormula()) {
+ IndexRequest r( lowerLeftPos );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addUpperLeftIndex()
+{
+ if (hasFormula()) {
+ IndexRequest r( upperLeftPos );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addLowerRightIndex()
+{
+ if (hasFormula()) {
+ IndexRequest r( lowerRightPos );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addUpperRightIndex()
+{
+ if (hasFormula()) {
+ IndexRequest r( upperRightPos );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addGenericLowerIndex()
+{
+ if (hasFormula()) {
+ IndexRequest r( lowerMiddlePos );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addGenericUpperIndex()
+{
+ if (hasFormula()) {
+ IndexRequest r( upperMiddlePos );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addOverline()
+{
+ if (hasFormula()) {
+ Request r( req_addOverline );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addUnderline()
+{
+ if (hasFormula()) {
+ Request r( req_addUnderline );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::addMultiline()
+{
+ if (hasFormula()) {
+ Request r( req_addMultiline );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::removeEnclosing()
+{
+ if (hasFormula()) {
+ DirectedRemove r( req_removeEnclosing, beforeCursor );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::makeGreek()
+{
+ if (hasFormula()) {
+ Request r( req_makeGreek );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::insertSymbol()
+{
+ if ( hasFormula() &&
+ m_document->m_contextStyle->symbolTable().contains( m_selectedName ) ) {
+ QChar ch = m_document->m_contextStyle->symbolTable().unicode( m_selectedName );
+ if ( ch != QChar::null ) {
+ TextCharRequest r( ch, true );
+ formula()->performRequest( &r );
+ }
+ else {
+ TextRequest r( m_selectedName );
+ formula()->performRequest( &r );
+ }
+ }
+}
+
+void DocumentWrapper::insertSymbol( QString name )
+{
+ if ( hasFormula() ) {
+ if ( m_document->m_contextStyle->symbolTable().contains( name ) ) {
+ QChar ch = m_document->m_contextStyle->symbolTable().unicode( name );
+ if ( ch != QChar::null ) {
+ TextCharRequest r( ch, true );
+ formula()->performRequest( &r );
+ return;
+ }
+ }
+ TextRequest r( name );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::appendColumn()
+{
+ if ( hasFormula() ) {
+ Request r( req_appendColumn );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::insertColumn()
+{
+ if ( hasFormula() ) {
+ Request r( req_insertColumn );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::removeColumn()
+{
+ if ( hasFormula() ) {
+ Request r( req_removeColumn );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::appendRow()
+{
+ if ( hasFormula() ) {
+ Request r( req_appendRow );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::insertRow()
+{
+ if ( hasFormula() ) {
+ Request r( req_insertRow );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::removeRow()
+{
+ if ( hasFormula() ) {
+ Request r( req_removeRow );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::toggleSyntaxHighlighting()
+{
+ m_document->m_contextStyle->setSyntaxHighlighting( m_syntaxHighlightingAction->isChecked() );
+ // Only to notify all views. We don't expect to get new values.
+ m_document->recalc();
+}
+
+void DocumentWrapper::textBold()
+{
+ if ( hasFormula() ) {
+ CharStyleRequest r( req_formatBold,
+ getFormatBoldAction()->isChecked(),
+ getFormatItalicAction()->isChecked() );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::textItalic()
+{
+ if ( hasFormula() ) {
+ CharStyleRequest r( req_formatItalic,
+ getFormatBoldAction()->isChecked(),
+ getFormatItalicAction()->isChecked() );
+ formula()->performRequest( &r );
+ }
+}
+
+void DocumentWrapper::delimiterLeft()
+{
+ QString left = m_leftBracket->currentText();
+ switch ( left.at(0).latin1() ) {
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ case '/':
+ case '\\':
+ m_leftBracketChar = static_cast<SymbolType>( left.at(0).latin1() );
+ break;
+ case '|':
+ m_leftBracketChar = LeftLineBracket;
+ break;
+ case ' ':
+ m_leftBracketChar = EmptyBracket;
+ break;
+ }
+}
+
+void DocumentWrapper::delimiterRight()
+{
+ QString right = m_rightBracket->currentText();
+ switch ( right.at(0).latin1() ) {
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ case '/':
+ case '\\':
+ m_rightBracketChar = static_cast<SymbolType>( right.at(0).latin1() );
+ break;
+ case '|':
+ m_rightBracketChar = RightLineBracket;
+ break;
+ case ' ':
+ m_rightBracketChar = EmptyBracket;
+ break;
+ }
+}
+
+void DocumentWrapper::symbolNames()
+{
+ m_selectedName = m_symbolNamesAction->currentText();
+}
+
+
+void DocumentWrapper::fontFamily()
+{
+ if ( hasFormula() ) {
+ int i = m_fontFamily->currentItem();
+ CharFamily cf = anyFamily;
+ switch( i ) {
+ case 0: cf = normalFamily; break;
+ case 1: cf = scriptFamily; break;
+ case 2: cf = frakturFamily; break;
+ case 3: cf = doubleStruckFamily; break;
+ }
+ CharFamilyRequest r( cf );
+ formula()->performRequest( &r );
+ }
+}
+
+
+void DocumentWrapper::tokenElement()
+{
+ if ( hasFormula() ) {
+ int i = m_tokenElement->currentItem();
+ TokenElementType te = anyElement;
+ switch( i ) {
+ case 0: te = identifierElement; break;
+ case 1: te = operatorElement; break;
+ case 2: te = numberElement; break;
+ case 3: te = textElement; break;
+ }
+ TokenElementRequest r( te );
+ formula()->performRequest( &r );
+ }
+}
+
+
+void DocumentWrapper::initSymbolNamesAction()
+{
+ if ( m_hasActions ) {
+ const SymbolTable& st = m_document->m_contextStyle->symbolTable();
+ QStringList names = st.allNames();
+ QFont font( m_document->m_contextStyle->getFontStyle() );
+ QMemArray<QChar> chars( names.count() );
+
+ uint i = 0;
+ for ( QStringList::Iterator it = names.begin();
+ it != names.end();
+ ++it, ++i ) {
+ chars[ i ] = st.unicode( *it );
+ }
+ m_symbolNamesAction->setSymbols( names, m_document->m_contextStyle->getMathFont(), chars );
+ m_selectedName = names[0];
+ }
+}
+
+
+void DocumentWrapper::setEnabled( bool enabled )
+{
+ kdDebug( DEBUGID ) << "DocumentWrapper::setEnabled " << enabled << endl;
+ getAddNegThinSpaceAction()->setEnabled( enabled );
+ getMakeGreekAction()->setEnabled( enabled );
+ getAddGenericUpperAction()->setEnabled( enabled );
+ getAddGenericLowerAction()->setEnabled( enabled );
+ getAddOverlineAction()->setEnabled( enabled );
+ getAddUnderlineAction()->setEnabled( enabled );
+ getRemoveEnclosingAction()->setEnabled( enabled );
+ getInsertSymbolAction()->setEnabled( enabled );
+ getAddThinSpaceAction()->setEnabled( enabled );
+ getAddMediumSpaceAction()->setEnabled( enabled );
+ getAddThickSpaceAction()->setEnabled( enabled );
+ getAddQuadSpaceAction()->setEnabled( enabled );
+ getAddBracketAction()->setEnabled( enabled );
+ getAddSBracketAction()->setEnabled( enabled );
+ getAddCBracketAction()->setEnabled( enabled );
+ getAddAbsAction()->setEnabled(enabled);
+ getAddFractionAction()->setEnabled( enabled );
+ getAddRootAction()->setEnabled( enabled );
+ getAddSumAction()->setEnabled( enabled );
+ getAddProductAction()->setEnabled( enabled );
+ getAddIntegralAction()->setEnabled( enabled );
+ getAddMatrixAction()->setEnabled( enabled );
+ getAddOneByTwoMatrixAction()->setEnabled( enabled );
+ getAddUpperLeftAction()->setEnabled( enabled );
+ getAddLowerLeftAction()->setEnabled( enabled );
+ getAddUpperRightAction()->setEnabled( enabled );
+ getAddLowerRightAction()->setEnabled( enabled );
+
+ getAddGenericUpperAction()->setEnabled( enabled );
+ getAddGenericLowerAction()->setEnabled( enabled );
+
+
+ if ( enabled ) {
+ getAddGenericUpperAction()->
+ setShortcut( KShortcut( CTRL + Key_U ) );
+ getAddGenericLowerAction()->
+ setShortcut( KShortcut( CTRL + Key_L ) );
+ getRemoveEnclosingAction()->
+ setShortcut( KShortcut( CTRL + Key_R ) );
+ getMakeGreekAction()->
+ setShortcut( KShortcut( CTRL + Key_G ) );
+ getInsertSymbolAction()->
+ setShortcut( KShortcut( CTRL + Key_I ) );
+ getAddOverlineAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_O ) );
+ getAddUnderlineAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_U ) );
+ getAddBracketAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_B ) );
+ getAddSBracketAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_D ) );
+ getAddCBracketAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_C ) );
+ getAddAbsAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_A ) );
+ getAddFractionAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_F ) );
+ getAddRootAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_R ) );
+ getAddSumAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_S ) );
+ getAddProductAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_P ) );
+ getAddIntegralAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_I ) );
+ getAddMatrixAction()->
+ setShortcut( KShortcut( CTRL + SHIFT + Key_M ) );
+
+ }
+ else {
+ getAddGenericUpperAction()->setShortcut( KShortcut() );
+ getAddGenericLowerAction()->setShortcut( KShortcut() );
+ getRemoveEnclosingAction()->setShortcut( KShortcut() );
+ getMakeGreekAction()->setShortcut( KShortcut() );
+ getInsertSymbolAction()->setShortcut( KShortcut() );
+ getAddOverlineAction()->setShortcut( KShortcut() );
+ getAddUnderlineAction()->setShortcut( KShortcut() );
+ getAddBracketAction()->setShortcut( KShortcut() );
+ getAddSBracketAction()->setShortcut( KShortcut() );
+ getAddCBracketAction()->setShortcut( KShortcut() );
+ getAddAbsAction()->setShortcut( KShortcut() );
+ getAddFractionAction()->setShortcut( KShortcut() );
+ getAddRootAction()->setShortcut( KShortcut() );
+ getAddSumAction()->setShortcut( KShortcut() );
+ getAddProductAction()->setShortcut( KShortcut() );
+ getAddIntegralAction()->setShortcut( KShortcut() );
+ getAddMatrixAction()->setShortcut( KShortcut() );
+ }
+}
+
+void DocumentWrapper::enableMatrixActions( bool b)
+{
+ getAppendColumnAction()->setEnabled( b );
+ getInsertColumnAction()->setEnabled( b );
+ getRemoveColumnAction()->setEnabled( b );
+ getAppendRowAction()->setEnabled( b );
+ getInsertRowAction()->setEnabled( b );
+ getRemoveRowAction()->setEnabled( b );
+}
+
+void DocumentWrapper::updateConfig()
+{
+ m_syntaxHighlightingAction->
+ setChecked( m_document->m_contextStyle->syntaxHighlighting() );
+ initSymbolNamesAction();
+}
+
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+#include "kformuladocument.moc"
diff --git a/lib/kformula/kformuladocument.h b/lib/kformula/kformuladocument.h
new file mode 100644
index 00000000..26d6bdd7
--- /dev/null
+++ b/lib/kformula/kformuladocument.h
@@ -0,0 +1,510 @@
+/* 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.
+*/
+
+#ifndef KFORMULADOCUMENT_H
+#define KFORMULADOCUMENT_H
+
+#include <qdom.h>
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <kaction.h>
+#include <kcommand.h>
+#include <kconfig.h>
+#include <KoCommandHistory.h>
+//#include "KoCommandHistory.h"
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class Container;
+class ContextStyle;
+class SymbolAction;
+class SymbolTable;
+class DocumentWrapper;
+class ElementCreationStrategy;
+
+
+/**
+ * small utility class representing a sortable (by x,y position) list
+ * of formulas you can use sort() and inSort(item)
+ **/
+class FormulaList: public QPtrList<Container>
+{
+protected:
+ virtual int compareItems( QPtrCollection::Item a, QPtrCollection::Item b );
+};
+
+
+/**
+ * A document that can contain a lot of formulas (container).
+ *
+ * The relationship between the document and its formulas is an
+ * open one. The document sure owns the formulas and when it
+ * vanishes the formulas will be destroyed, too. But the user
+ * will most often work with those formulas directly and not
+ * bother to ask the document. It's legal to directly create
+ * or destroy a Container object.
+ */
+class KOFORMULA_EXPORT Document : public QObject {
+ Q_OBJECT
+
+ friend class DocumentWrapper;
+ friend class Container;
+
+public:
+
+ /**
+ * Creates a formula document.
+ */
+ Document( QObject *parent=0, const char *name=0,
+ const QStringList &args=QStringList() );
+ ~Document();
+
+ /**
+ * Factory method.
+ */
+ virtual Container* createFormula( int pos=-1, bool registerMe=true );
+
+ /**
+ * Registers a new formula to be part of this document. Each formula
+ * must be part of exactly one document.
+ */
+ virtual void registerFormula( Container*, int pos=-1 );
+
+ /**
+ * Removes a formula from this document. The formula will stay
+ * alive and might be registered again.
+ */
+ virtual void unregisterFormula( Container* );
+
+ /**
+ * Triggers the evaluation of the whole document. This obviously
+ * required evaluation support.
+ */
+ virtual void evaluateFormulas() {}
+ virtual void enableEvaluation( bool ) {}
+
+ /**
+ * Load a kformula DomDocument with all its formulas.
+ * This must only be called on a virgin document.
+ */
+ bool loadXML( const QDomDocument& doc );
+
+ /**
+ * Load a OASIS content.xml DomDocument
+ * @since 1.4
+ */
+ bool loadOasis( const QDomDocument& doc );
+
+ /**
+ * Load the document settings.
+ */
+ bool loadDocumentPart( QDomElement node );
+
+ /**
+ * Save the document with all its formulae.
+ */
+ QDomDocument saveXML();
+
+ /**
+ * Save the document settings.
+ */
+ QDomElement saveDocumentPart( QDomDocument& doc );
+
+
+ /**
+ * @returns the documents context style.
+ */
+ ContextStyle& getContextStyle( bool edit=false );
+
+ /**
+ * Change the zoom factor to @p z (e.g. 150 for 150%)
+ * and/or change the resolution, given in DPI.
+ * Uses the KoTextZoomHandler.
+ */
+ void setZoomAndResolution( int zoom, int dpiX, int dpiY );
+
+ void newZoomAndResolution( bool updateViews, bool forPrint );
+
+ /**
+ * Sets the zoom by hand. This is to be used in <code>paintContent</code>.
+ */
+ void setZoomAndResolution( int zoom, double zoomX, double zoomY,
+ bool updateViews=false, bool forPrint=false );
+
+ double getXResolution() const;
+ double getYResolution() const;
+
+ /**
+ * Sets a new formula.
+ */
+ void activate(Container* formula);
+
+ /**
+ * Enables our action according to enabled.
+ */
+ void setEnabled( bool enabled );
+
+ /**
+ * @returns our undo stack so the formulas can use it.
+ */
+ KoCommandHistory* getHistory() const;
+
+ /**
+ * @returns the documents symbol table
+ */
+ const SymbolTable& getSymbolTable() const;
+
+ /**
+ * Gets called when the configuration changed.
+ * (Maybe we can find a better solution.)
+ */
+ void updateConfig();
+
+ /**
+ * Return a kformula DomDocument.
+ */
+ static QDomDocument createDomDocument();
+
+ /**
+ * Create a MathML Dom Document, deprecates KFO Dom Document for internal layout
+ * TODO: Shouldn't this go to KoDocument ?
+ */
+ QDomDocument createMathMLDomDocument();
+
+ /**
+ * Set formula creation strategy: old KFormula or MathML/ODF.
+ * This tells which tags are valid during formula constructions
+ *
+ * @param strategy -- "Ordinary" for old Kformula, "Oasis" for MathML/ODF
+ */
+ void setCreationStrategy( QString strategy );
+
+public:
+
+ /**
+ * @returns an iterator for the collection of formulas.
+ */
+ QPtrListIterator<Container> formulas();
+
+ SymbolType leftBracketChar();
+ SymbolType rightBracketChar();
+
+ DocumentWrapper* wrapper() { return m_wrapper; }
+
+protected:
+
+ /**
+ * @returns the internal position of this formula or -1 if it
+ * doesn't belong to us.
+ */
+ int formulaPos( Container* formula );
+
+ /**
+ * @returns the formula at position pos.
+ */
+ Container* formulaAt( uint pos );
+
+ /**
+ * @returns the number of formulas in this document.
+ */
+ int formulaCount();
+
+ /**
+ * Sorts the list of formulas according to their screen positions.
+ */
+ void sortFormulaList();
+
+private:
+
+ /**
+ * Return the formula with the given number or create a new one
+ * if there is no such formula.
+ */
+ Container* newFormula( uint number );
+
+ /**
+ * @returns whether we have a formula that can get requests.
+ */
+ bool hasFormula();
+
+ /**
+ * recalc all formulae.
+ */
+ void recalc();
+
+ void introduceWrapper( DocumentWrapper* wrapper, bool init );
+
+ /**
+ * The Wrapper we belong to.
+ */
+ DocumentWrapper* m_wrapper;
+
+ /**
+ * The active formula.
+ */
+ Container* m_formula;
+
+ /**
+ * The documents context style. This is the place where all
+ * the user configurable informations are stored.
+ */
+ ContextStyle* m_contextStyle;
+
+ /**
+ * All formulae that belong to this document.
+ */
+ FormulaList formulae;
+
+ /**
+ * Creation strategy to use in this document.
+ */
+ ElementCreationStrategy* creationStrategy;
+};
+
+
+
+/**
+ * A Wrapper that constracts the actions and must be given a real
+ * document to work with.
+ */
+class KOFORMULA_EXPORT DocumentWrapper : public QObject {
+ Q_OBJECT
+
+public:
+
+ DocumentWrapper( KConfig* config,
+ KActionCollection* collection,
+ KoCommandHistory* history = 0 );
+ ~DocumentWrapper();
+
+ KConfig* config() { return m_config; }
+ KoCommandHistory* history() { return m_history; }
+
+ /**
+ * @return the document we are using.
+ */
+ Document* document() const { return m_document; }
+
+ /**
+ * Enables our action according to enabled.
+ */
+ void setEnabled( bool enabled );
+
+ /**
+ * Inserts the document we are wrapping. This must be called once
+ * before the wrapper can be used.
+ */
+ void document( Document* document, bool init = true );
+
+ KAction* getAddNegThinSpaceAction() { return m_addNegThinSpaceAction; }
+ KAction* getAddThinSpaceAction() { return m_addThinSpaceAction; }
+ KAction* getAddMediumSpaceAction() { return m_addMediumSpaceAction; }
+ KAction* getAddThickSpaceAction() { return m_addThickSpaceAction; }
+ KAction* getAddQuadSpaceAction() { return m_addQuadSpaceAction; }
+ KAction* getAddBracketAction() { return m_addBracketAction; }
+ KAction* getAddSBracketAction() { return m_addSBracketAction;}
+ KAction* getAddCBracketAction() { return m_addCBracketAction;}
+ KAction* getAddAbsAction() { return m_addAbsAction;}
+ KAction* getAddFractionAction() { return m_addFractionAction; }
+ KAction* getAddRootAction() { return m_addRootAction; }
+ KAction* getAddSumAction() { return m_addSumAction; }
+ KAction* getAddProductAction() { return m_addProductAction; }
+ KAction* getAddIntegralAction() { return m_addIntegralAction; }
+ KAction* getAddMatrixAction() { return m_addMatrixAction; }
+ KAction* getAddOneByTwoMatrixAction(){ return m_addOneByTwoMatrixAction; }
+ KAction* getAddUpperLeftAction() { return m_addUpperLeftAction; }
+ KAction* getAddLowerLeftAction() { return m_addLowerLeftAction; }
+ KAction* getAddUpperRightAction() { return m_addUpperRightAction; }
+ KAction* getAddLowerRightAction() { return m_addLowerRightAction; }
+ KAction* getAddGenericUpperAction() { return m_addGenericUpperAction; }
+ KAction* getAddGenericLowerAction() { return m_addGenericLowerAction; }
+ KAction* getAddOverlineAction() { return m_addOverlineAction; }
+ KAction* getAddUnderlineAction() { return m_addUnderlineAction; }
+ KAction* getAddMultilineAction() { return m_addMultilineAction; }
+ KAction* getRemoveEnclosingAction() { return m_removeEnclosingAction; }
+ KAction* getMakeGreekAction() { return m_makeGreekAction; }
+ KAction* getInsertSymbolAction() { return m_insertSymbolAction; }
+
+ KAction* getAppendColumnAction() { return m_appendColumnAction; }
+ KAction* getInsertColumnAction() { return m_insertColumnAction; }
+ KAction* getRemoveColumnAction() { return m_removeColumnAction; }
+ KAction* getAppendRowAction() { return m_appendRowAction; }
+ KAction* getInsertRowAction() { return m_insertRowAction; }
+ KAction* getRemoveRowAction() { return m_removeRowAction; }
+
+ void enableMatrixActions(bool);
+ KSelectAction* getLeftBracketAction() { return m_leftBracket; }
+ KSelectAction* getRightBracketAction() { return m_rightBracket; }
+ SymbolAction* getSymbolNamesAction() { return m_symbolNamesAction; }
+ KToggleAction* getSyntaxHighlightingAction()
+ { return m_syntaxHighlightingAction; }
+ KToggleAction* getFormatBoldAction() { return m_formatBoldAction; }
+ KToggleAction* getFormatItalicAction() { return m_formatItalicAction; }
+
+ KSelectAction* getFontFamilyAction() { return m_fontFamily; }
+ KSelectAction* getTokenElementAction() { return m_tokenElement; }
+
+ SymbolType leftBracketChar() const { return m_leftBracketChar; }
+ SymbolType rightBracketChar() const { return m_rightBracketChar; }
+
+ void updateConfig();
+
+ KoCommandHistory* getHistory() const { return m_history; }
+
+ void undo();
+ void redo();
+
+public slots:
+
+ void paste();
+ void copy();
+ void cut();
+
+ void addNegThinSpace();
+ void addThinSpace();
+ void addMediumSpace();
+ void addThickSpace();
+ void addQuadSpace();
+ void addDefaultBracket();
+ void addBracket( SymbolType left, SymbolType right );
+ void addParenthesis();
+ void addSquareBracket();
+ void addCurlyBracket();
+ void addLineBracket();
+ void addFraction();
+ void addRoot();
+ void addIntegral();
+ void addProduct();
+ void addSum();
+ void addMatrix( uint rows=0, uint columns=0 );
+ void addOneByTwoMatrix();
+ void addNameSequence();
+ void addLowerLeftIndex();
+ void addUpperLeftIndex();
+ void addLowerRightIndex();
+ void addUpperRightIndex();
+ void addGenericLowerIndex();
+ void addGenericUpperIndex();
+ void addOverline();
+ void addUnderline();
+ void addMultiline();
+ void removeEnclosing();
+ void makeGreek();
+ void insertSymbol();
+ void insertSymbol( QString name );
+
+ void appendColumn();
+ void insertColumn();
+ void removeColumn();
+ void appendRow();
+ void insertRow();
+ void removeRow();
+
+ void toggleSyntaxHighlighting();
+ void textBold();
+ void textItalic();
+ void delimiterLeft();
+ void delimiterRight();
+ void symbolNames();
+
+ void fontFamily();
+ void tokenElement();
+
+private:
+
+ void createActions( KActionCollection* collection );
+ void initSymbolNamesAction();
+ void setCommandStack( KoCommandHistory* history );
+
+ bool hasFormula() { return m_document->hasFormula(); }
+ Container* formula() { return m_document->m_formula; }
+
+ Document* m_document;
+
+ KAction* m_addNegThinSpaceAction;
+ KAction* m_addThinSpaceAction;
+ KAction* m_addMediumSpaceAction;
+ KAction* m_addThickSpaceAction;
+ KAction* m_addQuadSpaceAction;
+ KAction* m_addBracketAction;
+ KAction* m_addSBracketAction;
+ KAction* m_addCBracketAction;
+ KAction* m_addAbsAction;
+ KAction* m_addFractionAction;
+ KAction* m_addRootAction;
+ KAction* m_addSumAction;
+ KAction* m_addProductAction;
+ KAction* m_addIntegralAction;
+ KAction* m_addMatrixAction;
+ KAction* m_addOneByTwoMatrixAction;
+ KAction* m_addUpperLeftAction;
+ KAction* m_addLowerLeftAction;
+ KAction* m_addUpperRightAction;
+ KAction* m_addLowerRightAction;
+ KAction* m_addGenericUpperAction;
+ KAction* m_addGenericLowerAction;
+ KAction* m_addOverlineAction;
+ KAction* m_addUnderlineAction;
+ KAction* m_addMultilineAction;
+ KAction* m_removeEnclosingAction;
+ KAction* m_makeGreekAction;
+ KAction* m_insertSymbolAction;
+
+ KAction* m_appendColumnAction;
+ KAction* m_insertColumnAction;
+ KAction* m_removeColumnAction;
+ KAction* m_appendRowAction;
+ KAction* m_insertRowAction;
+ KAction* m_removeRowAction;
+
+ KToggleAction* m_syntaxHighlightingAction;
+ KToggleAction* m_formatBoldAction;
+ KToggleAction* m_formatItalicAction;
+
+ KSelectAction* m_leftBracket;
+ KSelectAction* m_rightBracket;
+ SymbolAction* m_symbolNamesAction;
+
+ KSelectAction* m_fontFamily;
+ KSelectAction* m_tokenElement;
+
+ SymbolType m_leftBracketChar;
+ SymbolType m_rightBracketChar;
+ QString m_selectedName;
+
+ KConfig* m_config;
+ KoCommandHistory* m_history;
+
+ /**
+ * Tells whether we are responsible to remove our history.
+ */
+ bool m_ownHistory;
+
+ bool m_hasActions;
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // KFORMULADOCUMENT_H
diff --git a/lib/kformula/kformulainputfilter.cc b/lib/kformula/kformulainputfilter.cc
new file mode 100644
index 00000000..a2675271
--- /dev/null
+++ b/lib/kformula/kformulainputfilter.cc
@@ -0,0 +1,24 @@
+/* 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 "kformulainputfilter.h"
+
+using namespace KFormula;
+#include "kformulainputfilter.moc"
diff --git a/lib/kformula/kformulainputfilter.h b/lib/kformula/kformulainputfilter.h
new file mode 100644
index 00000000..f91efe8c
--- /dev/null
+++ b/lib/kformula/kformulainputfilter.h
@@ -0,0 +1,57 @@
+/* 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.
+*/
+
+#ifndef KFORMULAINPUTFILTER_H
+#define KFORMULAINPUTFILTER_H
+
+#include <qobject.h>
+#include <qdom.h>
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class KFInputFilter : public QObject
+{
+Q_OBJECT
+ public:
+ /*
+ * Get the just created DOM.
+ */
+ virtual QDomDocument getKFormulaDom() =0;
+
+ bool isDone() {return done; }
+
+
+ public slots:
+ virtual void startConversion() =0;
+
+ signals:
+ void conversionFinished();
+
+ protected:
+
+ bool done;
+ bool conversion;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif //
diff --git a/lib/kformula/kformulalib.h b/lib/kformula/kformulalib.h
new file mode 100644
index 00000000..0348b78d
--- /dev/null
+++ b/lib/kformula/kformulalib.h
@@ -0,0 +1,32 @@
+/**
+ * @libdoc A formula editor library.
+ *
+ * The kformula editor library. There are three classes you might be interested in.
+ * First there is the @ref Document . It is, you guess it, the document.
+ * Next there is the @ref Container . It represents one formula. Each
+ * formula belongs to a document and a document might have any number of formulas.
+ * For this reason the formula should be considered as part of the document.
+ * The last class is
+ * @ref KFormulaWidget . This one is a widget that serves as view.
+ * You can create any number of views for each formula.
+ *
+ * The document contains functions like load/save and the undo stack as well as
+ * everything you need to edit the formula.
+ * The view provides the interface for cursor movement. Additional there is basic
+ * key handling (for keys that probably shouldn't be actions). However every function
+ * is a slot so you can use actions as well.
+ *
+ * That's all you need to know to use it. But anyway:
+ * At its heart this library contains formula elements. Each element is a child
+ * of @ref BasicElement . The elements are meant to be selfcontained and thus
+ * extendable.
+ * A formula consists of a tree of those elements.
+ *
+ * To be able to work on the element tree in a generic way there is a
+ * @ref FormulaCursor . Every edit operation goes through it. This way
+ * the cursor separetes the element tree from the outside world.
+ *
+ * If you want to edit the formula you ask the document (@ref Container )
+ * to create and execute a @ref Command . The commands use the currently
+ * active cursor to do their editing. Each command can be undone.
+ */
diff --git a/lib/kformula/kformulamathmlread.cc b/lib/kformula/kformulamathmlread.cc
new file mode 100644
index 00000000..1bee8550
--- /dev/null
+++ b/lib/kformula/kformulamathmlread.cc
@@ -0,0 +1,1794 @@
+/* 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 <qstring.h>
+#include <qfontmetrics.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 QDomDocument& formuladoc );
+ ~MathML2KFormulaPrivate();
+
+ void math( QDomElement element );
+
+ // Token Elements
+ void mi( QDomElement element, QDomNode docnode );
+ void mn( QDomElement element, QDomNode docnode );
+ void mo( QDomElement element, QDomNode docnode );
+ void mtext( QDomElement element, QDomNode docnode );
+ void mspace( QDomElement element, QDomNode docnode );
+ void ms( QDomElement element, QDomNode docnode );
+ // mglyph not supported
+
+ // General Layout Schemata
+ void mrow( QDomElement element, QDomNode docnode );
+ void mfrac( QDomElement element, QDomNode docnode );
+ void msqrt( QDomElement element, QDomNode docnode );
+ void mroot( QDomElement element, QDomNode docnode );
+ void mstyle( QDomElement element, QDomNode docnode );
+ // merror not supported
+ // mpadded not supported
+ // mphantom not supported
+ void mfenced( QDomElement element, QDomNode docnode );
+ // menclose not supported
+
+ // Script and Limit Schemata
+ void msub_msup( QDomElement element, QDomNode docnode );
+ void msubsup( QDomElement element, QDomNode docnode );
+ void munder( QDomElement element, QDomNode docnode, bool oasisFormat );
+ void mover( QDomElement element, QDomNode docnode, bool oasisFormat );
+ void munderover( QDomElement element, QDomNode docnode, bool oasisFormat );
+ // mmultiscripts not supported
+
+ // Tables and Matrices
+ void mtable( QDomElement element, QDomNode docnode );
+ // not much supported
+
+ // Enlivening Expressions
+ // maction not supported
+
+protected:
+ void createTextElements( QString text, QDomNode docnode );
+ void createNameSequence( QString text, QDomNode docnode );
+ double convertToPoint( QString value, bool* ok );
+ bool isEmbellishedOperator( QDomNode node, QDomElement* mo, bool oasisFormat );
+ bool isSpaceLike( QDomNode 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( QDomElement 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( QDomElement 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;
+ QDomDocument doc;
+
+private:
+ const ContextStyle& context;
+ MathML2KFormula* filter;
+};
+
+MathML2KFormulaPrivate::MathML2KFormulaPrivate( MathML2KFormula* mml_filter, const ContextStyle& cs, const QDomDocument& formuladoc )
+ : doc( formuladoc ), context( cs ), filter( mml_filter )
+{
+}
+
+MathML2KFormulaPrivate::~MathML2KFormulaPrivate()
+{
+}
+
+void MathML2KFormulaPrivate::math( QDomElement element )
+{
+ QDomElement formula = doc.createElement( "FORMULA" );
+ QDomNode n = element.firstChild();
+
+ QString 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( QDomElement element, QDomNode docnode )
+{
+ MathStyle previousStyle( style );
+ QString 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( QDomElement element, QDomNode docnode )
+{
+ MathStyle previousStyle( style );
+ style.readStyles( element );
+
+ QString text = element.text().stripWhiteSpace();
+ createTextElements( text, docnode );
+
+ style = previousStyle;
+}
+
+void MathML2KFormulaPrivate::mn( QDomElement element, QDomNode docnode )
+{
+ MathStyle previousStyle( style );
+ style.readStyles( element );
+
+ QString text = element.text().stripWhiteSpace();
+ createTextElements( text, docnode );
+
+ style = previousStyle;
+}
+
+void MathML2KFormulaPrivate::mtext( QDomElement element, QDomNode docnode )
+{
+ MathStyle previousStyle( style );
+ style.readStyles( element );
+
+ QDomNode n = element.firstChild();
+
+ while ( !n.isNull() ) {
+ if ( n.isText() ) {
+ QString 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( QDomElement element, QDomNode docnode )
+{
+ QString lquote = element.attribute( "lquote", "\"" );
+ QString rquote = element.attribute( "rquote", "\"" );
+ QString text;
+
+ text = lquote;
+ text += element.text().stripWhiteSpace();
+ text += rquote;
+
+ createTextElements( text, docnode );
+}
+
+void MathML2KFormulaPrivate::mspace( QDomElement element, QDomNode docnode )
+{
+ // we support only horizontal space
+ QString width = element.attribute( "width" );
+
+ QDomElement 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 ) {
+ QFontMetrics 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( QDomElement element, QDomNode docnode )
+{
+ QDomNode n = element.firstChild();
+ while ( !n.isNull() ) {
+ if ( n.isElement () ) {
+ QDomElement 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( QDomElement element, QDomNode docnode )
+{
+ QDomNode n = element.firstChild();
+ QDomElement 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
+ QDomElement numerator =
+ doc.createElement( "NUMERATOR" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ numerator.appendChild( sequence );
+ QDomElement e = n.toElement();
+ filter->processElement( e, doc, sequence );
+ fraction.appendChild( numerator );
+
+ }
+ else {
+ QDomElement denominator =
+ doc.createElement( "DENOMINATOR" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ denominator.appendChild( sequence );
+ QDomElement 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( QDomElement element, QDomNode docnode )
+{
+ QDomNode n = element.firstChild();
+ int i = 0;
+ QDomElement root = doc.createElement( "ROOT" );
+
+ while ( !n.isNull() && i < 2 ) {
+ if ( n.isElement() ) {
+ ++i;
+ if ( i == 1 ) { //first is content (base)
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ content.appendChild( sequence );
+ QDomElement e = n.toElement();
+ filter->processElement( e, doc, sequence );
+
+ root.appendChild(content);
+ }
+ else { // index
+ MathStyle previousStyle( style );
+ style.scriptlevel += 2;
+ style.displaystyle = false;
+ style.styleChange();
+
+ QDomElement index = doc.createElement( "INDEX" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement 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( QDomElement element, QDomNode docnode )
+{
+ QDomNode n = element.firstChild();
+ QDomElement root = doc.createElement( "ROOT" );
+
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement 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( QDomElement element, QDomNode docnode )
+{
+ bool ok;
+
+ MathStyle previousStyle( style );
+ style.readStyles( element );
+
+ if ( element.hasAttribute( "scriptlevel" ) ) {
+ QString 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" ) ) {
+ QString 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" ) ) {
+ QString scriptminsize = element.attribute( "scriptminsize" );
+ style.scriptminsize = convertToPoint( scriptminsize, &ok );
+ if ( !ok )
+ style.scriptminsize = previousStyle.scriptminsize;
+ }
+
+ if ( element.hasAttribute( "veryverythinmathspace" ) ) {
+ QString vvthinmspace = element.attribute( "veryverythinmathspace" );
+ style.veryverythinmathspace = convertToPoint( vvthinmspace, &ok );
+ if ( !ok )
+ style.veryverythinmathspace = previousStyle.veryverythinmathspace;
+ }
+ if ( element.hasAttribute( "verythinmathspace" ) ) {
+ QString vthinmspace = element.attribute( "verythinmathspace" );
+ style.verythinmathspace = convertToPoint( vthinmspace, &ok );
+ if ( !ok )
+ style.verythinmathspace = previousStyle.verythinmathspace;
+ }
+ if ( element.hasAttribute( "thinmathspace" ) ) {
+ QString thinmathspace = element.attribute( "thinmathspace" );
+ style.thinmathspace = convertToPoint( thinmathspace, &ok );
+ if ( !ok )
+ style.thinmathspace = previousStyle.thinmathspace;
+ }
+ if ( element.hasAttribute( "mediummathspace" ) ) {
+ QString mediummathspace = element.attribute( "mediummathspace" );
+ style.mediummathspace = convertToPoint( mediummathspace, &ok );
+ if ( !ok )
+ style.mediummathspace = previousStyle.mediummathspace;
+ }
+ if ( element.hasAttribute( "thickmathspace" ) ) {
+ QString thickmathspace = element.attribute( "thickmathspace" );
+ style.thickmathspace = convertToPoint( thickmathspace, &ok );
+ if ( !ok )
+ style.thickmathspace = previousStyle.thickmathspace;
+ }
+ if ( element.hasAttribute( "verythickmathspace" ) ) {
+ QString vthickmspace = element.attribute( "verythickmathspace" );
+ style.verythickmathspace = convertToPoint( vthickmspace, &ok );
+ if ( !ok )
+ style.verythickmathspace = previousStyle.verythickmathspace;
+ }
+ if ( element.hasAttribute( "veryverythickmathspace" ) ) {
+ QString vvthickmspace = element.attribute( "veryverythickmathspace" );
+ style.veryverythickmathspace = convertToPoint( vvthickmspace, &ok );
+ if ( !ok )
+ style.veryverythickmathspace =
+ previousStyle.veryverythickmathspace;
+ }
+
+ style.styleChange();
+
+ QDomNode n = element.firstChild();
+ while ( !n.isNull() ) {
+ filter->processElement( n, doc, docnode );
+ n = n.nextSibling();
+ }
+
+ style = previousStyle;
+}
+
+void MathML2KFormulaPrivate::mfenced( QDomElement element, QDomNode docnode )
+{
+ QDomElement bracket = doc.createElement( "BRACKET" );
+ QString value = element.attribute( "open", "(" );
+ bracket.setAttribute( "LEFT", QString::number( value.at( 0 ).latin1() ) );
+ value = element.attribute( "close", ")" );
+ bracket.setAttribute( "RIGHT", QString::number( value.at( 0 ).latin1() ) );
+
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ content.appendChild( sequence );
+
+ QString separators = element.attribute( "separators", "," );
+
+ QDomNode n = element.firstChild();
+ uint i = 0;
+ while ( !n.isNull() ) {
+ if ( n.isElement() ) {
+ if ( i != 0 && !separators.isEmpty() ) {
+ QDomElement textelement = doc.createElement( "TEXT" );
+ if ( i > separators.length() )
+ i = separators.length();
+ textelement.setAttribute( "CHAR", QString( separators.at( i - 1 ) ) );
+ //style.setStyles( textelement );
+ sequence.appendChild( textelement );
+ }
+ ++i;
+ QDomElement 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( QDomElement element, QDomNode docnode )
+{
+ MathStyle previousStyle( style );
+ QString 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();
+
+ QString subtag;
+ int rows = 0; int cols = 0;
+ QDomNode n = element.firstChild();
+
+ while ( !n.isNull() ) {
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ subtag = e.tagName();
+ if (subtag == "mtr")
+ {
+ ++rows;
+
+ /* Determins the number of columns */
+
+ QDomNode 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();
+ QDomElement matrix = doc.createElement( "MATRIX" );
+ matrix.setAttribute( "COLUMNS", cols );
+ matrix.setAttribute( "ROWS", rows );
+
+ while ( !n.isNull() ) {
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ subtag = e.tagName();
+ if ( subtag == "mtr" ) {
+ QDomNode cellnode = e.firstChild();
+ int cc = 0;
+ while ( !cellnode.isNull() ) {
+ if ( cellnode.isElement() ) {
+ ++cc;
+ QDomElement cell = doc.createElement( "SEQUENCE" );
+ QDomElement cellelement = cellnode.toElement();
+ filter->processElement( cellelement, doc, cell );
+ matrix.appendChild( cell );
+ }
+ cellnode = cellnode.nextSibling();
+ }
+
+ /* Add empty elements */
+ for(; cc < cols; cc++ ) {
+ QDomElement cell = doc.createElement( "SEQUENCE" );
+ matrix.appendChild( cell );
+ }
+ }
+ }
+ n = n.nextSibling();
+ }
+
+ style = previousStyle;
+ docnode.appendChild(matrix);
+}
+
+void MathML2KFormulaPrivate::msub_msup( QDomElement element, QDomNode docnode )
+{
+ QDomNode n = element.firstChild();
+ int i = 0;
+ QDomElement root = doc.createElement( "INDEX" );
+
+ while ( !n.isNull() && i < 2 ) {
+ if ( n.isElement() ) {
+ ++i;
+ if ( i == 1 ) { // first is content (base)
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ content.appendChild( sequence );
+ QDomElement e = n.toElement();
+ filter->processElement( e, doc, sequence );
+
+ root.appendChild( content );
+ }
+ else {
+ QDomElement 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();
+
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement 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( QDomElement element, QDomNode docnode, bool oasisFormat )
+{
+ bool accentunder;
+
+ QString au = element.attribute( "accentunder" );
+ if ( au == "true" )
+ accentunder = true;
+ else if ( au == "false" )
+ accentunder = false;
+ else {
+ // use default
+
+ QDomElement 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;
+ }
+
+ QDomNode n = element.firstChild();
+ int i = 0;
+ QDomElement root = doc.createElement( "INDEX" );
+
+ while ( !n.isNull() && i < 2 ) {
+ if ( n.isElement() ) {
+ ++i;
+ if ( i == 1 ) { // first is content (base)
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ content.appendChild( sequence );
+ QDomElement 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();
+ }
+
+ QDomElement mo; QDomElement index;
+ if ( isEmbellishedOperator( n.previousSibling(), &mo, oasisFormat ) &&
+ !previousStyle.displaystyle &&
+ mo.attribute( "movablelimits" ) == "true" )
+ {
+ index = doc.createElement( "LOWERRIGHT" );
+ }
+ else {
+ index = doc.createElement( "LOWERMIDDLE" );
+ }
+
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement 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( QDomElement element, QDomNode docnode, bool oasisFormat )
+{
+ bool accent;
+
+ QString ac = element.attribute( "accent" );
+ if ( ac == "true" )
+ accent = true;
+ else if ( ac == "false" )
+ accent = false;
+ else {
+ // use default
+
+ QDomElement 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;
+ }
+
+ QDomNode n = element.firstChild();
+ int i = 0;
+ QDomElement root = doc.createElement( "INDEX" );
+
+ while ( !n.isNull() && i < 2 ) {
+ if ( n.isElement() ) {
+ ++i;
+ if ( i == 1 ) { // first is content (base)
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ content.appendChild( sequence );
+ QDomElement 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();
+ }
+
+ QDomElement mo; QDomElement index;
+ if ( isEmbellishedOperator( n.previousSibling(), &mo, oasisFormat ) &&
+ !previousStyle.displaystyle &&
+ mo.attribute( "movablelimits" ) == "true" )
+ {
+ index = doc.createElement( "UPPERRIGHT" );
+ }
+ else {
+ index = doc.createElement( "UPPERMIDDLE" );
+ }
+
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement 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( QDomElement element, QDomNode docnode, bool oasisFormat )
+{
+ bool accent;
+ bool accentunder;
+
+ QString value = element.attribute( "accentunder" );
+ if ( value == "true" )
+ accentunder = true;
+ else if ( value == "false" )
+ accentunder = false;
+ else {
+ // use default
+
+ QDomElement 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
+
+ QDomElement 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;
+
+ QDomNode n = element.firstChild();
+ int i = 0;
+ QDomElement root = doc.createElement( "INDEX" );
+
+ while ( !n.isNull() && i < 3 ) {
+ if ( n.isElement() ) {
+ ++i;
+ if ( i == 1 ) { // base
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ content.appendChild( sequence );
+ QDomElement 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();
+ }
+
+ QDomElement mo; QDomElement 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" );
+ }
+
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement 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();
+ }
+
+ QDomElement mo; QDomElement index;
+ if ( isEmbellishedOperator( element.firstChild(), &mo, oasisFormat ) &&
+ !previousStyle.displaystyle &&
+ mo.attribute( "movablelimits" ) == "true" )
+ {
+ index = doc.createElement( "UPPERRIGHT" );
+ }
+ else {
+ index = doc.createElement( "UPPERMIDDLE" );
+ }
+
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement 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( QDomElement element, QDomNode docnode )
+{
+ QDomNode n = element.firstChild();
+ int i = 0;
+ QDomElement root = doc.createElement("INDEX");
+ MathStyle previousStyle( style );
+
+ while ( !n.isNull() && i < 2 ) {
+ if ( n.isElement() ) {
+ ++i;
+ if ( i == 1 ) { // base
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ content.appendChild( sequence );
+ QDomElement e = n.toElement();
+ filter->processElement( e, doc, sequence );
+
+ root.appendChild( content );
+ }
+ else if ( i == 2 ) { // subscript
+ style.scriptlevel += 1;
+ style.displaystyle = false;
+ style.styleChange();
+
+ QDomElement index;
+ index = doc.createElement( "LOWERRIGHT" );
+
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement e = n.toElement();
+ filter->processElement( e, doc, sequence );
+ root.appendChild( index );
+ }
+ else { // superscript
+ QDomElement index;
+ index = doc.createElement( "UPPERRIGHT" );
+
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ index.appendChild( sequence );
+ QDomElement 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( QString text, QDomNode docnode )
+{
+ for ( uint i = 0; i < text.length(); ++i ) {
+ QDomElement textelement = doc.createElement( "TEXT" );
+ textelement.setAttribute( "CHAR", QString( 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( QString text, QDomNode docnode )
+{
+ QDomElement namesequence = doc.createElement( "NAMESEQUENCE" );
+ for ( uint i = 0; i < text.length(); ++i ) {
+ QDomElement textelement = doc.createElement( "TEXT" );
+ textelement.setAttribute( "CHAR", QString( 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( QString value, bool* ok )
+{
+ double pt = 0;
+
+ if ( value.endsWith( "em" ) ) {
+ // See MathML specification, Appendix H
+ pt = context.getDefaultFont().pointSize();
+ if ( pt == -1 ) {
+ QFontMetrics fm( context.getDefaultFont() );
+ pt = fm.width( 'M' );
+ // PIXELS!
+ }
+ pt = pt * value.remove( value.length() - 2, 2 ).toDouble( ok );
+ }
+ else if ( value.endsWith( "ex" ) ) {
+ QFontMetrics 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( QDomNode node,
+ QDomElement* mo, bool oasisFormat )
+{
+ // See MathML 2.0 specification: 3.2.5.7
+
+ if ( !node.isElement() )
+ return false;
+
+ QDomElement element = node.toElement();
+ QString 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" ) {
+ QDomNode 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( QDomNode node, bool oasisFormat )
+{
+ // See MathML 2.0 specification: 3.2.7.3
+
+ if ( !node.isElement() )
+ return false;
+
+ QDomElement element = node.toElement();
+ QString tag = element.tagName();
+
+ if ( tag == "mtext" || tag == "mspace" ||
+ tag == "maligngroup" || tag == "malignmark" ) {
+ return true;
+ }
+ if ( tag == "mstyle" || tag == "mphantom" || tag == "mpadded" || tag == "mrow" ) {
+ QDomNode 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 QDomDocument& mmldoc, const ContextStyle &contextStyle, bool _oasisFormat )
+ : m_error( false ), oasisFormat( _oasisFormat ), context( contextStyle )
+{
+ orig_element = mmldoc.documentElement();
+ done = false;
+}
+
+MathML2KFormula::MathML2KFormula( const QDomElement& mmlelm, const ContextStyle &contextStyle, bool _oasisFormat )
+ : m_error( false ), orig_element( mmlelm ), oasisFormat( _oasisFormat ), context( contextStyle )
+{
+ done = false;
+}
+
+QDomDocument MathML2KFormula::getKFormulaDom()
+{
+ return formuladoc;
+}
+
+
+
+void MathML2KFormula::startConversion()
+{
+ //TODO:let it be async
+ //kdDebug() << origdoc.toString() << endl;
+ done = false;
+ formuladoc = QDomDocument( "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( QDomNode node, QDomDocument& doc, QDomNode docnode )
+{
+
+ //QDomElement *element;
+ Type type = UNKNOWN;
+
+ if ( node.isElement() ) {
+ QDomElement element = node.toElement();
+ QString 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;
+ QDomNode n = element.firstChild();
+ QDomElement op = n.toElement();
+ uint count = element.childNodes().count();
+ //adding explicit brackets to replace "apply"s implicit ones
+ QDomElement brackets = doc.createElement("BRACKET");
+ brackets.setAttribute("RIGHT", "41");
+ brackets.setAttribute("LEFT", "40");
+ QDomElement content = doc.createElement("CONTENT");
+ brackets.appendChild(content);
+ QDomElement 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 ) {
+ QDomElement text = doc.createElement( "TEXT" );
+ QString 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;
+ QDomElement e = n.toElement();
+ processElement( e, doc, base );
+ }
+ n = n.nextSibling();
+ }
+ }
+
+ else if ( op.tagName() == "factorial" ) {
+ QDomElement 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 );
+ QDomElement e = n.toElement();
+ processElement( e, doc, base );
+ }
+ else if ( count == 3 ) { // binary
+ QDomElement 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();
+ QDomElement 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();
+ QDomElement e = n.toElement();
+ QDomElement index = doc.createElement("INDEX");
+ base.appendChild(index);
+ QDomElement content = doc.createElement("CONTENT");
+ index.appendChild(content);
+ QDomElement sequence = doc.createElement("SEQUENCE");
+ content.appendChild(sequence);
+ processElement(e, doc, sequence);
+ QDomElement 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();
+ QDomElement e = n.toElement();
+ QDomElement bracket = doc.createElement("BRACKET");
+ bracket.setAttribute("RIGHT", "257");
+ bracket.setAttribute("LEFT", "256");
+ base.appendChild(bracket);
+ QDomElement content = doc.createElement("CONTENT");
+ bracket.appendChild(content);
+ QDomElement sequence = doc.createElement("SEQUENCE");
+ content.appendChild(sequence);
+ processElement(e, doc, sequence);
+ }
+ else if ( op.tagName() == "not" && count == 2) {
+ n = n.nextSibling();
+ QDomElement e = n.toElement();
+ impl->createTextElements(QString(QChar(0xAC)), base);
+ processElement(e, doc, base);
+ }
+ else if ( op.tagName() == "implies" && count == 3 ) {
+ n = n.nextSibling();
+ QDomElement e = n.toElement();
+ processElement( e, doc, base );
+ impl->createTextElements(QString(QChar(0x21D2)), base);
+ n = n.nextSibling();
+ e = n.toElement();
+ processElement( e, doc, base );
+ }
+ // many, many more...
+
+ }
+
+ else if ( tag == "cn" ) {
+ type = CONTENT;
+ QString type = element.attribute( "type", "real" );
+
+ if ( type == "real" || type == "constant" ) {
+ impl->createTextElements( element.text().stripWhiteSpace(),
+ docnode );
+ }
+ else if ( type == "integer" ) {
+ QString base = element.attribute( "base" );
+ if ( !base ) {
+ impl->createTextElements( element.text().stripWhiteSpace(),
+ docnode );
+ }
+ else {
+ QDomElement index = doc.createElement( "INDEX" );
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ impl->createTextElements( element.text().stripWhiteSpace(),
+ sequence );
+ content.appendChild( sequence );
+ index.appendChild( content );
+
+ QDomElement 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" ) {
+ QDomNode 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" ) {
+ QDomNode 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" ) {
+ QDomNode n = element.firstChild();
+ impl->createTextElements( n.toText().data().stripWhiteSpace(),
+ docnode );
+
+ n = n.nextSibling(); // <sep/>
+ QDomElement index = doc.createElement( "INDEX" );
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+ QDomElement textelement = doc.createElement( "TEXT" );
+ textelement.setAttribute( "CHAR", "e" );
+ sequence.appendChild( textelement );
+ content.appendChild( sequence );
+ index.appendChild( content );
+
+ QDomElement 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;
+ QDomNode n = element.firstChild();
+
+ if ( n.isText() ) {
+ impl->createTextElements( n.toText().data().stripWhiteSpace(),
+ docnode );
+ }
+ else if ( n.isElement() ) {
+ QDomElement 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;
+ QDomNode n = element.firstChild();
+
+ QDomElement bracket = doc.createElement( "BRACKET" );
+ bracket.setAttribute( "LEFT", 91 ); // [
+ bracket.setAttribute( "RIGHT", 93 ); // ]
+ QDomElement content = doc.createElement( "CONTENT" );
+ QDomElement sequence = doc.createElement( "SEQUENCE" );
+
+ bool first = true;
+
+ while ( !n.isNull() ) {
+ if ( n.isElement() ) {
+ if ( !first ) {
+ QDomElement textelement = doc.createElement( "TEXT" );
+ textelement.setAttribute( "CHAR", "," );
+ sequence.appendChild( textelement );
+ }
+ first = false;
+ QDomElement e = n.toElement();
+ processElement( e, doc, sequence );
+ }
+ n = n.nextSibling();
+ }
+
+ content.appendChild( sequence );
+ bracket.appendChild( content );
+ docnode.appendChild( bracket );
+ }
+ }
+
+ if ( type == UNKNOWN && node.nodeType() != QDomNode::AttributeNode ) {
+ kdDebug() << "Not an element: " << node.nodeName() << endl;
+ QDomNode n = node.firstChild();
+ while ( !n.isNull() ) {
+ processElement( n, doc, docnode );
+ n = n.nextSibling();
+ }
+ }
+
+ return true;
+}
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+#include "kformulamathmlread.moc"
diff --git a/lib/kformula/kformulamathmlread.h b/lib/kformula/kformulamathmlread.h
new file mode 100644
index 00000000..2a3cb2a5
--- /dev/null
+++ b/lib/kformula/kformulamathmlread.h
@@ -0,0 +1,100 @@
+/* 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.
+*/
+
+#ifndef KFORMULAMATHMLREAD_H
+#define KFORMULAMATHMLREAD_H
+
+#include <qobject.h>
+#include <qdom.h>
+#include "kformulainputfilter.h"
+#include "contextstyle.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class MathML2KFormulaPrivate;
+
+/**
+ * This class converts MathML to KFormula XML.
+ * Right now are only parts of the Presentation Markup implemented.
+ */
+class MathML2KFormula : public KFInputFilter
+{
+ Q_OBJECT
+
+ friend class MathML2KFormulaPrivate;
+
+public:
+
+ /**
+ * Build a MathML 2 KFormula converter.
+ * call startConversion() to convert and wait for
+ * a conversionFinished() signal, then call
+ * getKFormulaDom() to get the converted DOM
+ */
+ MathML2KFormula( const QDomDocument& mmldoc, const ContextStyle &contextStyle, bool oasisFormat = false );
+
+ /**
+ * Build a MathML 2 KFormula converter.
+ * A DOM Element is required instead of a full Document, useful for embedded MathML
+ */
+ MathML2KFormula( const QDomElement& mmelm, const ContextStyle &contextStyle, bool oasisFormat = false );
+
+ /*
+ * Get the just created DOM.
+ */
+ virtual QDomDocument getKFormulaDom();
+
+
+public slots:
+ virtual void startConversion();
+
+public:
+ /// Has an error happened while converting?
+ bool m_error;
+
+private:
+
+ bool processElement( QDomNode node, QDomDocument& doc,
+ QDomNode docnode );
+
+ QDomElement orig_element;
+ QDomDocument formuladoc;
+ bool oasisFormat;
+ const ContextStyle& context;
+
+ MathML2KFormulaPrivate* impl;
+
+ enum Type {
+ // Presentation Markup
+ UNKNOWN = 1,
+ TOKEN = 2, // Token Elements
+ LAYOUT = 3, // General Layout Schemata
+ SCRIPT = 4, // Script and Limit Schemata
+ TABLE = 5, // Tables and Matrices
+ EE = 6, // Enlivening Expressions
+
+ // Content Markup
+ CONTENT = 12
+ };
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // KFORMULAMATHMLREAD_H
diff --git a/lib/kformula/kformulamimesource.cc b/lib/kformula/kformulamimesource.cc
new file mode 100644
index 00000000..a0438e5e
--- /dev/null
+++ b/lib/kformula/kformulamimesource.cc
@@ -0,0 +1,154 @@
+/* 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 <qpopupmenu.h>
+#include <qbuffer.h>
+#include <qcolor.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <kcommand.h>
+
+#include "contextstyle.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "kformuladocument.h"
+#include "kformulamimesource.h"
+
+KFORMULA_NAMESPACE_BEGIN
+using namespace std;
+
+
+MimeSource::MimeSource(Document* doc, const QDomDocument& formula)
+ : formulaDocument( doc ), document(formula)
+{
+ // The query for text/plain comes very often. So make sure
+ // it's fast.
+
+ rootElement = new FormulaElement(this);
+ FormulaCursor cursor(rootElement);
+
+ QPtrList<BasicElement> list;
+ list.setAutoDelete(true);
+ if ( cursor.buildElementsFromDom( document.documentElement(), list ) ) {
+ cursor.insert(list);
+ latexString = rootElement->toLatex().utf8();
+ if (latexString.size() > 0) {
+ latexString.truncate(latexString.size()-1);
+ }
+ }
+}
+
+MimeSource::~MimeSource()
+{
+ delete rootElement;
+}
+
+const char * MimeSource::selectionMimeType()
+{
+ return "application/x-kformula";
+}
+
+const char* MimeSource::format( int n ) const
+{
+ switch (n) {
+ case 0:
+ return selectionMimeType();
+ case 1:
+ return "image/ppm";
+ case 2:
+ return "text/plain";
+ case 3:
+ return "text/x-tex";
+ }
+ return NULL;
+}
+
+bool MimeSource::provides( const char * format) const
+{
+//This is not completed
+ if(QString(format)==selectionMimeType())
+ return true;
+ else if(QString(format)=="image/ppm")
+ return true;
+ else if(QString(format)=="text/plain")
+ return true;
+ else if(QString(format)=="text/x-tex")
+ return true;
+ else
+ return false;
+}
+
+QByteArray MimeSource::encodedData ( const char *format ) const
+{
+ QString fmt=format; //case sensitive?
+
+ if ((fmt=="text/plain") || (fmt=="text/x-tex"))
+ return latexString;
+
+ if (fmt==selectionMimeType()) {
+ QByteArray d=document.toCString();
+ d.truncate(d.size()-1);
+ return d;
+ }
+
+ if (fmt=="image/ppm") {
+
+ //cerr << "asking image" << endl;
+ ContextStyle& context = formulaDocument->getContextStyle( false );
+ //context.setResolution(5, 5);
+
+ rootElement->calcSizes(context);
+ QRect rect(rootElement->getX(), rootElement->getY(),
+ rootElement->getWidth(), rootElement->getHeight());
+
+ QPixmap pm( context.layoutUnitToPixelX( rootElement->getWidth() ),
+ context.layoutUnitToPixelY( rootElement->getHeight() ) );
+ pm.fill();
+ QPainter paint(&pm);
+ rootElement->draw(paint, rect, context);
+ paint.end();
+
+ QByteArray d;
+ QBuffer buff(d);
+ buff.open(IO_WriteOnly);
+ QImageIO io(&buff,"PPM");
+ QImage ima=pm.convertToImage();
+ ima.detach();
+ io.setImage(ima);
+ if(!io.write())
+ return QByteArray();
+
+ buff.close();
+ return d;
+ }
+
+ return QByteArray();
+}
+
+const SymbolTable& MimeSource::getSymbolTable() const
+{
+ return formulaDocument->getContextStyle( false ).symbolTable();
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/kformulamimesource.h b/lib/kformula/kformulamimesource.h
new file mode 100644
index 00000000..5619e43b
--- /dev/null
+++ b/lib/kformula/kformulamimesource.h
@@ -0,0 +1,60 @@
+/* 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.
+*/
+
+#ifndef KFORMULAMIMESOURCE_H
+#define KFORMULAMIMESOURCE_H
+
+#include <qmime.h>
+#include <qdom.h>
+
+#include "kformulacontainer.h"
+#include <koffice_export.h>
+
+KFORMULA_NAMESPACE_BEGIN
+class FormulaElement;
+
+
+class KOFORMULA_EXPORT MimeSource : public QMimeSource, public FormulaDocument
+{
+public:
+ MimeSource(Document* doc, const QDomDocument& formula);
+ ~MimeSource();
+
+ virtual const char* format ( int n = 0 ) const;
+ virtual bool provides ( const char * ) const;
+ virtual QByteArray encodedData ( const char * ) const;
+
+ virtual const SymbolTable& getSymbolTable() const;
+
+ static const char* selectionMimeType();
+
+private:
+
+ Document* formulaDocument;
+
+ QDomDocument document;
+ QByteArray latexString;
+
+ FormulaElement* rootElement;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // KFORMULAMIMESOURCE_H
diff --git a/lib/kformula/kformulaview.cc b/lib/kformula/kformulaview.cc
new file mode 100644
index 00000000..543bc727
--- /dev/null
+++ b/lib/kformula/kformulaview.cc
@@ -0,0 +1,413 @@
+/* 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 <qpainter.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+
+#include "basicelement.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "kformulaview.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+struct View::View_Impl {
+
+ View_Impl(Container* doc, View* view)
+ : smallCursor(false), activeCursor(true), cursorHasChanged(true),
+ document(doc)
+ {
+ connect(document, SIGNAL(elementWillVanish(BasicElement*)),
+ view, SLOT(slotElementWillVanish(BasicElement*)));
+ connect(document, SIGNAL(formulaLoaded(FormulaElement*)),
+ view, SLOT(slotFormulaLoaded(FormulaElement*)));
+ connect(document, SIGNAL(cursorMoved(FormulaCursor*)),
+ view, SLOT(slotCursorMoved(FormulaCursor*)));
+
+ cursor = document->createCursor();
+ blinkTimer = new QTimer( view );
+ connect( blinkTimer, SIGNAL( timeout() ),
+ view, SLOT( slotBlinkCursor() ) );
+ if ( QApplication::cursorFlashTime() > 0 )
+ blinkTimer->start( QApplication::cursorFlashTime() / 2 );
+ }
+
+ void startTimer()
+ {
+ if ( QApplication::cursorFlashTime() > 0 )
+ blinkTimer->start( QApplication::cursorFlashTime() / 2 );
+ }
+
+ void stopTimer()
+ {
+ blinkTimer->stop();
+ }
+
+ ~View_Impl()
+ {
+ if ( document->activeCursor() == cursor ) {
+ document->setActiveCursor( 0 );
+ }
+ delete cursor;
+ delete blinkTimer;
+ }
+
+ /**
+ * If set the cursor will never be bigger that the formula.
+ */
+ bool smallCursor;
+
+ /**
+ * Whether the cursor is visible (for blinking)
+ */
+ bool activeCursor;
+
+ /**
+ * Whether the cursor changed since the last time
+ * we emitted a cursorChanged signal.
+ */
+ bool cursorHasChanged;
+
+ /**
+ * Timer for cursor blinking
+ */
+ QTimer *blinkTimer;
+
+ /**
+ * The formula we show.
+ */
+ Container* document;
+
+ /**
+ * Out cursor.
+ */
+ FormulaCursor* cursor;
+};
+
+
+FormulaCursor* View::cursor() const { return impl->cursor; }
+bool& View::cursorHasChanged() { return impl->cursorHasChanged; }
+bool& View::smallCursor() { return impl->smallCursor; }
+bool& View::activeCursor() { return impl->activeCursor; }
+Container* View::container() const { return impl->document; }
+void View::startCursorTimer() { impl->startTimer(); }
+void View::stopCursorTimer() { impl->stopTimer(); }
+
+
+View::View(Container* doc)
+{
+ impl = new View_Impl(doc, this);
+ cursor()->calcCursorSize( contextStyle(), smallCursor() );
+}
+
+View::~View()
+{
+ delete impl;
+}
+
+
+QPoint View::getCursorPoint() const
+{
+ return contextStyle().layoutUnitToPixel( cursor()->getCursorPoint() );
+}
+
+void View::setReadOnly(bool ro)
+{
+ cursor()->setReadOnly(ro);
+}
+
+
+void View::calcCursor()
+{
+ cursor()->calcCursorSize( contextStyle(), smallCursor() );
+}
+
+
+void View::draw(QPainter& painter, const QRect& rect, const QColorGroup& cg)
+{
+// kdDebug( DEBUGID ) << "View::draw: " << rect.x() << " " << rect.y() << " "
+// << rect.width() << " " << rect.height() << endl;
+ container()->draw( painter, rect, cg, true );
+ if ( cursorVisible() ) {
+ StyleAttributes style;
+ cursor()->draw( painter, contextStyle(), style, smallCursor(), activeCursor() );
+ }
+}
+
+void View::draw(QPainter& painter, const QRect& rect)
+{
+ container()->draw( painter, rect, true );
+ if ( cursorVisible() ) {
+ StyleAttributes style;
+ cursor()->draw( painter, contextStyle(), style, smallCursor(), activeCursor() );
+ }
+}
+
+void View::keyPressEvent( QKeyEvent* event )
+{
+ container()->input( event );
+}
+
+
+void View::focusInEvent(QFocusEvent*)
+{
+ //cursor()->calcCursorSize( contextStyle(), smallCursor() );
+ container()->setActiveCursor(cursor());
+ activeCursor() = true;
+ startCursorTimer();
+ smallCursor() = false;
+ emitCursorChanged();
+}
+
+void View::focusOutEvent(QFocusEvent*)
+{
+ //container()->setActiveCursor(0);
+ activeCursor() = false;
+ stopCursorTimer();
+ smallCursor() = true;
+ emitCursorChanged();
+}
+
+void View::mousePressEvent( QMouseEvent* event )
+{
+ const ContextStyle& context = contextStyle();
+ mousePressEvent( event, context.pixelToLayoutUnit( event->pos() ) );
+}
+
+void View::mouseReleaseEvent( QMouseEvent* event )
+{
+ const ContextStyle& context = contextStyle();
+ mouseReleaseEvent( event, context.pixelToLayoutUnit( event->pos() ) );
+}
+
+void View::mouseDoubleClickEvent( QMouseEvent* event )
+{
+ const ContextStyle& context = contextStyle();
+ mouseDoubleClickEvent( event, context.pixelToLayoutUnit( event->pos() ) );
+}
+
+void View::mouseMoveEvent( QMouseEvent* event )
+{
+ const ContextStyle& context = contextStyle();
+ mouseMoveEvent( event, context.pixelToLayoutUnit( event->pos() ) );
+}
+
+void View::wheelEvent( QWheelEvent* event )
+{
+ const ContextStyle& context = contextStyle();
+ wheelEvent( event, context.pixelToLayoutUnit( event->pos() ) );
+}
+
+void View::mousePressEvent( QMouseEvent* event, const PtPoint& pos )
+{
+ const ContextStyle& context = contextStyle();
+ mousePressEvent( event, context.ptToLayoutUnitPix( pos ) );
+}
+
+void View::mouseReleaseEvent( QMouseEvent* event, const PtPoint& pos )
+{
+ const ContextStyle& context = contextStyle();
+ mouseReleaseEvent( event, context.ptToLayoutUnitPix( pos ) );
+}
+
+void View::mouseDoubleClickEvent( QMouseEvent* event, const PtPoint& pos )
+{
+ const ContextStyle& context = contextStyle();
+ mouseDoubleClickEvent( event, context.ptToLayoutUnitPix( pos ) );
+}
+
+void View::mouseMoveEvent( QMouseEvent* event, const PtPoint& pos )
+{
+ const ContextStyle& context = contextStyle();
+ mouseMoveEvent( event, context.ptToLayoutUnitPix( pos ) );
+}
+
+void View::wheelEvent( QWheelEvent* event, const PtPoint& pos )
+{
+ const ContextStyle& context = contextStyle();
+ wheelEvent( event, context.ptToLayoutUnitPix( pos ) );
+}
+
+
+void View::mousePressEvent( QMouseEvent* event, const LuPixelPoint& pos )
+{
+ int flags = movementFlag( event->state() );
+ cursor()->mousePress( pos, flags );
+ emitCursorChanged();
+}
+
+void View::mouseReleaseEvent( QMouseEvent* event, const LuPixelPoint& pos )
+{
+ int flags = movementFlag( event->state() );
+ cursor()->mouseRelease( pos, flags );
+ emitCursorChanged();
+}
+
+void View::mouseDoubleClickEvent( QMouseEvent*, const LuPixelPoint& )
+{
+ cursor()->moveRight( WordMovement );
+ cursor()->moveLeft( SelectMovement | WordMovement );
+ emitCursorChanged();
+}
+
+void View::mouseMoveEvent( QMouseEvent* event, const LuPixelPoint& pos )
+{
+ int flags = movementFlag( event->state() );
+ cursor()->mouseMove( pos, flags );
+ emitCursorChanged();
+}
+
+void View::wheelEvent( QWheelEvent*, const LuPixelPoint& )
+{
+}
+
+
+void View::slotCursorMoved(FormulaCursor* c)
+{
+ if (c == cursor()) {
+ cursorHasChanged() = true;
+ emitCursorChanged();
+ }
+}
+
+void View::slotFormulaLoaded(FormulaElement* formula)
+{
+ cursor()->formulaLoaded(formula);
+}
+
+void View::slotElementWillVanish(BasicElement* element)
+{
+ cursor()->elementWillVanish(element);
+ emitCursorChanged();
+}
+
+void View::slotBlinkCursor()
+{
+ activeCursor() = ! activeCursor();
+ emitCursorChanged();
+}
+
+void View::slotSelectAll()
+{
+ cursor()->moveHome(WordMovement);
+ cursor()->moveEnd(SelectMovement | WordMovement);
+ emitCursorChanged();
+}
+
+
+void View::moveLeft( int flag )
+{
+ cursor()->moveLeft( flag );
+ emitCursorChanged();
+}
+
+void View::moveRight( int flag )
+{
+ cursor()->moveRight( flag );
+ emitCursorChanged();
+}
+
+void View::moveUp( int flag )
+{
+ cursor()->moveUp( flag );
+ emitCursorChanged();
+}
+
+void View::moveDown( int flag )
+{
+ cursor()->moveDown( flag );
+ emitCursorChanged();
+}
+
+
+void View::moveHome( int flag )
+{
+ cursor()->moveHome( flag );
+ emitCursorChanged();
+}
+
+void View::moveEnd( int flag )
+{
+ cursor()->moveEnd( flag );
+ emitCursorChanged();
+}
+
+
+void View::setSmallCursor(bool small)
+{
+ smallCursor() = small;
+}
+
+bool View::isHome() const
+{
+ return cursor()->isHome();
+}
+
+bool View::isEnd() const
+{
+ return cursor()->isEnd();
+}
+
+void View::eraseSelection( Direction direction )
+{
+ DirectedRemove r( req_remove, direction );
+ container()->performRequest( &r );
+}
+
+void View::addText( QString str )
+{
+ TextRequest r( str );
+ container()->performRequest( &r );
+}
+
+void View::emitCursorChanged()
+{
+ if (cursor()->hasChanged() || cursorHasChanged()) {
+ getDocument()->updateMatrixActions();
+ cursor()->clearChangedFlag();
+ cursorHasChanged() = false;
+ cursor()->calcCursorSize( contextStyle(), smallCursor() );
+ activeCursor() = true;
+ startCursorTimer();
+ }
+ emit cursorChanged(cursorVisible(), cursor()->isSelection());
+}
+
+const ContextStyle& View::contextStyle() const
+{
+ return container()->document()->getContextStyle();
+}
+
+bool View::cursorVisible()
+{
+ return !cursor()->isReadOnly() || cursor()->isSelection();
+}
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+#include "kformulaview.moc"
diff --git a/lib/kformula/kformulaview.h b/lib/kformula/kformulaview.h
new file mode 100644
index 00000000..f93b491f
--- /dev/null
+++ b/lib/kformula/kformulaview.h
@@ -0,0 +1,189 @@
+/* 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.
+*/
+
+#ifndef KFORMULAVIEW_H
+#define KFORMULAVIEW_H
+
+#include <qevent.h>
+#include <qobject.h>
+#include <qrect.h>
+
+#include "kformuladefs.h"
+#include "contextstyle.h"
+
+class QColorGroup;
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class FormulaCursor;
+class FormulaElement;
+class Container;
+
+
+/**
+ * The view that shows the formula. Its main purpose is to handle
+ * the cursor. There are methods
+ * to move the cursor around. To edit the formula use the document.
+ *
+ * The view is meant to be easy embeddable into a widget or
+ * to be used alone if there is a bigger widget the formula
+ * is to be drawn into.
+ */
+class KOFORMULA_EXPORT View : public QObject {
+ Q_OBJECT
+
+public:
+
+ View(Container*);
+ virtual ~View();
+
+ /**
+ * @returns the point inside the formula view where the cursor is.
+ */
+ QPoint getCursorPoint() const;
+
+ /**
+ * Puts the widget in read only mode.
+ */
+ void setReadOnly(bool ro);
+
+ void mousePressEvent(QMouseEvent* event);
+ void mouseReleaseEvent(QMouseEvent* event);
+ void mouseDoubleClickEvent(QMouseEvent* event);
+ void mouseMoveEvent(QMouseEvent* event);
+ void wheelEvent(QWheelEvent* event);
+
+ // the mouse event happened at a certain point
+ void mousePressEvent( QMouseEvent* event, const PtPoint& pos );
+ void mouseReleaseEvent( QMouseEvent* event, const PtPoint& pos );
+ void mouseDoubleClickEvent( QMouseEvent* event, const PtPoint& pos );
+ void mouseMoveEvent( QMouseEvent* event, const PtPoint& pos );
+ void wheelEvent( QWheelEvent* event, const PtPoint& pos );
+
+ // the mouse event happened at a certain point
+ void mousePressEvent( QMouseEvent* event, const LuPixelPoint& pos );
+ void mouseReleaseEvent( QMouseEvent* event, const LuPixelPoint& pos );
+ void mouseDoubleClickEvent( QMouseEvent* event, const LuPixelPoint& pos );
+ void mouseMoveEvent( QMouseEvent* event, const LuPixelPoint& pos );
+ void wheelEvent( QWheelEvent* event, const LuPixelPoint& pos );
+
+ void keyPressEvent(QKeyEvent* event);
+ virtual void focusInEvent(QFocusEvent* event);
+ virtual void focusOutEvent(QFocusEvent* event);
+
+ void calcCursor();
+
+ void draw(QPainter& painter, const QRect& rect, const QColorGroup& cg);
+ void draw(QPainter& painter, const QRect& rect);
+
+ /**
+ * The document we show.
+ */
+ virtual Container* getDocument() const { return container(); }
+
+ /**
+ * Our cursor.
+ */
+ FormulaCursor* getCursor() const { return cursor(); }
+
+ void setSmallCursor(bool small);
+
+ // simple cursor movement.
+
+ void moveLeft( int flag = NormalMovement );
+ void moveRight( int flag = NormalMovement );
+ void moveUp( int flag = NormalMovement );
+ void moveDown( int flag = NormalMovement );
+
+ void moveHome( int flag = NormalMovement );
+ void moveEnd( int flag = NormalMovement );
+
+ /** @returns whether the cursor is at the first position. */
+ bool isHome() const;
+
+ /** @returns whether the cursor is at the last position. */
+ bool isEnd() const;
+
+ void eraseSelection( Direction direction = beforeCursor );
+ void addText( QString str );
+
+signals:
+
+ /**
+ * Is emitted every time the cursor might have changed.
+ */
+ void cursorChanged(bool visible, bool selecting);
+
+public slots:
+
+ void slotSelectAll();
+
+protected slots:
+
+ /**
+ * The cursor has been moved by the container.
+ * We need to repaint if it was ours.
+ */
+ void slotCursorMoved(FormulaCursor* cursor);
+
+ /**
+ * A new formula has been loaded.
+ */
+ void slotFormulaLoaded(FormulaElement*);
+
+ /**
+ * There is an element that will disappear from the tree.
+ * our cursor must not be inside it.
+ */
+ void slotElementWillVanish(BasicElement*);
+
+ /**
+ * Tell the cursor to change its visibility status
+ */
+ void slotBlinkCursor();
+
+protected:
+
+ virtual bool cursorVisible();
+
+private:
+
+ /**
+ * Tell everybody that our cursor has changed if so.
+ */
+ void emitCursorChanged();
+
+ bool& cursorHasChanged();
+ bool& smallCursor();
+ bool& activeCursor();
+ Container* container() const;
+ void startCursorTimer();
+ void stopCursorTimer();
+ const ContextStyle& contextStyle() const;
+ FormulaCursor* cursor() const;
+
+ struct View_Impl;
+ View_Impl* impl;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // KFORMULAVIEW_H
diff --git a/lib/kformula/kformulawidget.cc b/lib/kformula/kformulawidget.cc
new file mode 100644
index 00000000..15295392
--- /dev/null
+++ b/lib/kformula/kformulawidget.cc
@@ -0,0 +1,171 @@
+/* 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 <qpainter.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+//#include <klocale.h>
+//#include <kstdaction.h>
+
+#include "basicelement.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "kformulawidget.h"
+
+
+KFormulaWidget::KFormulaWidget(Container* doc, QWidget* parent, const char* name, WFlags f)
+ : QWidget(parent, name, f | WRepaintNoErase | WResizeNoErase),
+ formulaView(doc)
+{
+ connect(doc, SIGNAL(formulaChanged(int, int)),
+ this, SLOT(slotFormulaChanged(int, int)));
+ connect(&formulaView, SIGNAL(cursorChanged(bool, bool)),
+ this, SLOT(slotCursorChanged(bool, bool)));
+
+ setFocusPolicy(QWidget::StrongFocus);
+ setBackgroundMode(NoBackground/*QWidget::PaletteBase*/);
+
+ QRect rect = doc->boundingRect();
+ slotFormulaChanged(rect.width(), rect.height());
+}
+
+KFormulaWidget::~KFormulaWidget()
+{
+}
+
+
+QPoint KFormulaWidget::getCursorPoint() const
+{
+ return formulaView.getCursorPoint();
+}
+
+void KFormulaWidget::setReadOnly(bool ro)
+{
+ formulaView.setReadOnly(ro);
+}
+
+
+void KFormulaWidget::paintEvent(QPaintEvent* event)
+{
+ // Always repaint the buffer. This is not so much more work
+ // than it seems to be as each cursor movement requires a repaint.
+ QPainter p( &buffer );
+ //p.translate( -fr.x(), -fr.y() );
+ formulaView.draw( p, event->rect(), colorGroup() );
+
+ QPainter painter;
+ painter.begin(this);
+ painter.drawPixmap( event->rect().x(), event->rect().y(),
+ buffer, event->rect().x(), event->rect().y(), event->rect().width(), event->rect().height() );
+ painter.end();
+}
+
+void KFormulaWidget::keyPressEvent(QKeyEvent* event)
+{
+ formulaView.keyPressEvent(event);
+}
+
+
+void KFormulaWidget::focusInEvent(QFocusEvent* event)
+{
+ formulaView.focusInEvent(event);
+}
+
+void KFormulaWidget::focusOutEvent(QFocusEvent* event)
+{
+ formulaView.focusOutEvent(event);
+}
+
+void KFormulaWidget::mousePressEvent(QMouseEvent* event)
+{
+ formulaView.mousePressEvent(event);
+}
+
+void KFormulaWidget::mouseReleaseEvent(QMouseEvent* event)
+{
+ formulaView.mouseReleaseEvent(event);
+}
+
+void KFormulaWidget::mouseDoubleClickEvent(QMouseEvent* event)
+{
+ formulaView.mouseDoubleClickEvent(event);
+}
+
+void KFormulaWidget::mouseMoveEvent(QMouseEvent* event)
+{
+ formulaView.mouseMoveEvent(event);
+}
+
+void KFormulaWidget::wheelEvent(QWheelEvent* event)
+{
+ formulaView.wheelEvent(event);
+}
+
+void KFormulaWidget::slotFormulaChanged(int width, int height)
+{
+ // Magic numbers just to see the cursor.
+ resize(width + 5, height + 5);
+ buffer.resize(width + 5, height + 5);
+ // repaint is needed even if the size doesn't change.
+ //update();
+}
+
+/**
+ * The document we show.
+ */
+Container* KFormulaWidget::getDocument()
+{
+ return formulaView.getDocument();
+}
+
+/**
+ * Our cursor.
+ */
+FormulaCursor* KFormulaWidget::getCursor()
+{
+ return formulaView.getCursor();
+}
+
+
+void KFormulaWidget::slotSelectAll()
+{
+ formulaView.slotSelectAll();
+}
+
+void KFormulaWidget::slotCursorChanged(bool visible, bool selecting)
+{
+ emit cursorChanged(visible, selecting);
+// kdDebug( 40000 ) << "KFormulaWidget::slotCursorChanged "
+// << formulaView.getDirtyArea().x() << " "
+// << formulaView.getDirtyArea().y() << " "
+// << formulaView.getDirtyArea().width() << " "
+// << formulaView.getDirtyArea().height() << " "
+// << endl;
+ // sadly this doesn't work
+ //update(formulaView.getDirtyArea());
+ update();
+}
+
+#include "kformulawidget.moc"
diff --git a/lib/kformula/kformulawidget.h b/lib/kformula/kformulawidget.h
new file mode 100644
index 00000000..99079e1d
--- /dev/null
+++ b/lib/kformula/kformulawidget.h
@@ -0,0 +1,119 @@
+/* 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.
+*/
+
+#ifndef KFORMULAWIDGET_H
+#define KFORMULAWIDGET_H
+
+#include <qdom.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qwidget.h>
+
+#include "kformuladefs.h"
+#include "kformulaview.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class FormulaCursor;
+class FormulaElement;
+class Container;
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+
+
+/**
+ * The view. A widget that shows the formula. There are methods
+ * to move the cursor around. To edit the formula use the document.
+ */
+class KFormulaWidget : public QWidget {
+ Q_OBJECT
+
+public:
+ KFormulaWidget(Container*, QWidget* parent=0, const char* name=0, WFlags f=0);
+ ~KFormulaWidget();
+
+
+ /**
+ * @returns the point inside the formula widget where the cursor is.
+ */
+ QPoint getCursorPoint() const;
+
+ /**
+ * Puts the widget in read only mode.
+ */
+ void setReadOnly(bool ro);
+
+public slots:
+
+ void slotSelectAll();
+
+signals:
+
+ /**
+ * Is emitted every time the cursor might have changed.
+ */
+ void cursorChanged(bool visible, bool selecting);
+
+protected slots:
+
+ /**
+ * The formula has changed and needs to be redrawn.
+ */
+ void slotFormulaChanged(int width, int height);
+
+ void slotCursorChanged(bool visible, bool selecting);
+
+protected:
+
+ virtual void mousePressEvent(QMouseEvent* event);
+ virtual void mouseReleaseEvent(QMouseEvent* event);
+ virtual void mouseDoubleClickEvent(QMouseEvent* event);
+ virtual void mouseMoveEvent(QMouseEvent* event);
+ virtual void wheelEvent(QWheelEvent* event);
+
+ virtual void paintEvent(QPaintEvent* event);
+ virtual void keyPressEvent(QKeyEvent* event);
+ virtual void focusInEvent(QFocusEvent* event);
+ virtual void focusOutEvent(QFocusEvent* event);
+
+ /**
+ * The document we show.
+ */
+ Container* getDocument();
+
+ /**
+ * Our cursor.
+ */
+ FormulaCursor* getCursor();
+
+private:
+
+ /**
+ * This widget is a wrapper around the actual view.
+ */
+ View formulaView;
+
+ QPixmap buffer;
+};
+
+#endif // KFORMULAWIDGET_H
diff --git a/lib/kformula/main.cc b/lib/kformula/main.cc
new file mode 100644
index 00000000..bbab2bbb
--- /dev/null
+++ b/lib/kformula/main.cc
@@ -0,0 +1,298 @@
+
+#include <iostream>
+#include <memory>
+
+#include <qaccel.h>
+#include <qdom.h>
+#include <qfile.h>
+#include <qlayout.h>
+#include <qptrlist.h>
+#include <qmainwindow.h>
+#include <qpainter.h>
+#include <qstring.h>
+#include <qtextstream.h>
+#include <qwidget.h>
+#include <qfileinfo.h>
+
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kcommand.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+
+#include "elementtype.h"
+#include "kformulacommand.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "kformulawidget.h"
+#include "scrollview.h"
+
+using namespace KFormula;
+
+
+class TestWidget : public KFormulaWidget {
+public:
+ TestWidget(Container* doc, QWidget* parent=0, const char* name=0, WFlags f=0)
+ : KFormulaWidget(doc, parent, name, f) {}
+
+protected:
+ virtual void keyPressEvent(QKeyEvent* event);
+
+private:
+};
+
+
+void save( const QString &filename, const QDomDocument& doc )
+{
+ QFile f( filename );
+ if(!f.open(IO_Truncate | IO_ReadWrite)) {
+ kdWarning( DEBUGID ) << "Error opening file " << filename.latin1() << endl;
+ return;
+ }
+
+ QTextStream stream(&f);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ doc.save(stream, 2);
+ f.close();
+}
+
+
+void load( KFormula::Document* document, const QString &filename )
+{
+ QFile f(filename);
+ if (!f.open(IO_ReadOnly)) {
+ kdWarning( DEBUGID ) << "Error opening file " << filename.latin1() << endl;
+ return;
+ }
+ QTextStream stream(&f);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+ QString content = stream.read();
+ f.close();
+ //kdDebug( DEBUGID ) << content << endl;
+ QDomDocument doc;
+ if ( !doc.setContent( content ) ) {
+ return;
+ }
+ if ( !document->loadXML( doc ) ) {
+ kdWarning( DEBUGID ) << "Failed." << endl;
+ }
+}
+
+
+void saveMathML( KFormula::Container* formula, const QString &filename, bool oasisFormat )
+{
+ QFile f( filename );
+ if ( !f.open( IO_Truncate | IO_ReadWrite ) ) {
+ kdWarning( DEBUGID ) << "Error opening file " << filename.latin1() << endl;
+ return;
+ }
+
+ QTextStream stream( &f );
+ stream.setEncoding( QTextStream::UnicodeUTF8 );
+ formula->saveMathML( stream, oasisFormat );
+ f.close();
+}
+
+
+void loadMathML( KFormula::Container* formula, const QString &filename )
+{
+ QFile f( filename );
+ if ( !f.open( IO_ReadOnly ) ) {
+ kdWarning( DEBUGID ) << "Error opening file " << filename.latin1() << endl;
+ return;
+ }
+ QTextStream stream( &f );
+ stream.setEncoding( QTextStream::UnicodeUTF8 );
+ QString content = stream.read();
+
+ QDomDocument doc;
+ QString errorMsg;
+ int errorLine;
+ int errorColumn;
+ if ( !doc.setContent( content, true,
+ &errorMsg, &errorLine, &errorColumn ) ) {
+ kdWarning( DEBUGID ) << "MathML built error: " << errorMsg
+ << " at line " << errorLine
+ << " and column " << errorColumn << endl;
+ f.close();
+ return;
+ }
+
+ /*kdDebug( DEBUGID ) << "Container::loadMathML\n"
+ << doc.toCString() << endl;*/
+
+ if ( !formula->loadMathML( doc ) ) {
+ kdWarning( DEBUGID ) << "Failed." << endl;
+ }
+ f.close();
+}
+
+
+void TestWidget::keyPressEvent(QKeyEvent* event)
+{
+ Container* document = getDocument();
+
+ //int action = event->key();
+ int state = event->state();
+ //MoveFlag flag = movementFlag(state);
+
+ if ( ( state & Qt::ShiftButton ) && ( state & Qt::ControlButton ) ) {
+ switch (event->key()) {
+ case Qt::Key_B: document->document()->wrapper()->appendColumn(); return;
+ case Qt::Key_I: document->document()->wrapper()->insertColumn(); return;
+ case Qt::Key_R: document->document()->wrapper()->removeColumn(); return;
+ case Qt::Key_Z: document->document()->wrapper()->redo(); return;
+ case Qt::Key_F: saveMathML( document, "test.mml", true/*save to oasis format*/ ); return;
+ case Qt::Key_M: saveMathML( document, "test.mml", false ); return;
+ case Qt::Key_O: {
+ QString file = KFileDialog::getOpenFileName();
+ kdDebug( DEBUGID ) << file << endl;
+ if( !file.isEmpty() ) {
+ QFileInfo fi( file );
+ if ( fi.extension() == "mml" ) {
+ loadMathML( document, file );
+ }
+ else if ( fi.extension() == "xml" ) {
+ load( document->document(), file );
+ }
+ }
+ return;
+ }
+ }
+ }
+ else if (state & Qt::ControlButton) {
+ switch (event->key()) {
+ case Qt::Key_1: document->document()->wrapper()->addSum(); return;
+ case Qt::Key_2: document->document()->wrapper()->addProduct(); return;
+ case Qt::Key_3: document->document()->wrapper()->addIntegral(); return;
+ case Qt::Key_4: document->document()->wrapper()->addRoot(); return;
+ case Qt::Key_5: document->document()->wrapper()->addFraction(); return;
+ case Qt::Key_6: document->document()->wrapper()->addMatrix(); return;
+ case Qt::Key_7: document->document()->wrapper()->addOneByTwoMatrix(); return;
+ case Qt::Key_8: document->document()->wrapper()->addOverline(); return;
+ case Qt::Key_9: document->document()->wrapper()->addUnderline(); return;
+ case Qt::Key_A: slotSelectAll(); return;
+ case Qt::Key_B: document->document()->wrapper()->appendRow(); return;
+ case Qt::Key_C: document->document()->wrapper()->copy(); return;
+ case Qt::Key_D: document->document()->wrapper()->removeEnclosing(); return;
+ case Qt::Key_G: document->document()->wrapper()->makeGreek(); return;
+ case Qt::Key_I: document->document()->wrapper()->insertRow(); return;
+ case Qt::Key_R: document->document()->wrapper()->removeRow(); return;
+ case Qt::Key_K: document->document()->wrapper()->addMultiline(); return;
+ case Qt::Key_L: document->document()->wrapper()->addGenericLowerIndex(); return;
+ case Qt::Key_M: loadMathML( document, "test.mml" ); return;
+ case Qt::Key_O: load( document->document(), "test.xml" ); return;
+ case Qt::Key_Q: kapp->quit(); return;
+ case Qt::Key_S: save( "test.xml", document->document()->saveXML() ); return;
+ case Qt::Key_T: std::cout << document->texString().latin1() << std::endl; return;
+ case Qt::Key_U: document->document()->wrapper()->addGenericUpperIndex(); return;
+ case Qt::Key_V: document->document()->wrapper()->paste(); return;
+ case Qt::Key_X: document->document()->wrapper()->cut(); return;
+ case Qt::Key_Z: document->document()->wrapper()->undo(); return;
+ default:
+ //std::cerr << "Key: " << event->key() << std::endl;
+ break;
+ }
+ }
+
+ KFormulaWidget::keyPressEvent(event);
+}
+
+
+ScrollView::ScrollView()
+ : QScrollView(), child(0)
+{
+}
+
+void ScrollView::addChild(KFormulaWidget* c, int x, int y)
+{
+ QScrollView::addChild(c, x, y);
+ child = c;
+ connect(child, SIGNAL(cursorChanged(bool, bool)),
+ this, SLOT(cursorChanged(bool, bool)));
+}
+
+void ScrollView::focusInEvent(QFocusEvent*)
+{
+ if (child != 0) child->setFocus();
+}
+
+
+void ScrollView::cursorChanged(bool visible, bool /*selecting*/)
+{
+ if (visible) {
+ int x = child->getCursorPoint().x();
+ int y = child->getCursorPoint().y();
+ ensureVisible(x, y);
+ }
+}
+
+
+static const KCmdLineOptions options[]= {
+ { "+file", "File to open", 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char** argv)
+{
+ KAboutData aboutData("math test", "KFormula test",
+ "0.01", "test", KAboutData::License_GPL,
+ "(c) 2003, Ulrich Kuettler");
+ aboutData.addAuthor("Ulrich Kuettler",0, "ulrich.kuettler@gmx.de");
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions(options);
+
+ KApplication app;
+
+ app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
+
+ DocumentWrapper* wrapper = new DocumentWrapper( kapp->config(), 0 );
+ Document* document = new Document;
+ wrapper->document( document );
+ Container* container1 = document->createFormula();
+
+ ScrollView* scrollview1a = new ScrollView;
+
+ KFormulaWidget* mw1a = new TestWidget(container1, scrollview1a, "test1a");
+
+ scrollview1a->addChild(mw1a);
+ scrollview1a->setCaption("Test1a of the formula engine");
+ scrollview1a->show();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ for ( int i = 0; i < args->count(); ++i ) {
+ QFileInfo fi( args->url( i ).path() );
+ if ( fi.extension() == "mml" )
+ loadMathML( container1, args->url( i ).path() );
+ else if ( fi.extension() == "xml" )
+ load( container1->document(), args->url( i ).path() );
+ }
+
+ int result = app.exec();
+
+ delete container1;
+ delete wrapper;
+
+ // Make sure there are no elements in the clipboard.
+ // Okey for a debug app.
+ QApplication::clipboard()->clear();
+
+ int destruct = BasicElement::getEvilDestructionCount();
+ if (destruct != 0) {
+ std::cerr << "BasicElement::EvilDestructionCount: " << destruct << std::endl;
+ }
+ destruct = PlainCommand::getEvilDestructionCount();
+ if (destruct != 0) {
+ std::cerr << "PlainCommand::EvilDestructionCount: " << destruct << std::endl;
+ }
+ destruct = ElementType::getEvilDestructionCount();
+ if (destruct != 0) {
+ std::cerr << "ElementType::EvilDestructionCount: " << destruct << std::endl;
+ }
+
+ return result;
+}
+
+#include "scrollview.moc"
diff --git a/lib/kformula/mathml.xml b/lib/kformula/mathml.xml
new file mode 100644
index 00000000..0618f080
--- /dev/null
+++ b/lib/kformula/mathml.xml
@@ -0,0 +1,25 @@
+<mrow>
+
+ <mtable>
+ <mtr> <mn>1</mn> <mn>0</mn> <mn>0</mn> </mtr>
+ <mtr> <mn>0</mn> <mn>1</mn> <mn>0</mn> </mtr>
+ <mtr> <mn>0</mn> <mn>0</mn> <mn>1</mn> </mtr>
+ </mtable>
+
+
+ <mi> x </mi>
+ <mo> + </mo>
+ <mrow>
+ <mfrac>
+ <mi> y </mi>
+ <mroot>
+ <munder>
+ <mi> lim </mi>
+ <mtext>x->0</mtext>
+ </munder>
+ <mn> 4 </mn>
+ </mroot>
+ </mfrac>
+ </mrow>
+</mrow>
+
diff --git a/lib/kformula/matrixelement.cc b/lib/kformula/matrixelement.cc
new file mode 100644
index 00000000..88a59081
--- /dev/null
+++ b/lib/kformula/matrixelement.cc
@@ -0,0 +1,2692 @@
+/* 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 <qmemarray.h>
+#include <qpainter.h>
+#include <qptrlist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "MatrixDialog.h"
+#include "elementvisitor.h"
+#include "formulaelement.h"
+#include "formulacursor.h"
+#include "kformulacontainer.h"
+#include "kformulacommand.h"
+#include "matrixelement.h"
+#include "sequenceelement.h"
+#include "spaceelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+class MatrixSequenceElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ MatrixSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
+ virtual MatrixSequenceElement* clone() {
+ return new MatrixSequenceElement( *this );
+ }
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+};
+
+
+class KFCRemoveRow : public Command {
+public:
+ KFCRemoveRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
+ ~KFCRemoveRow();
+
+ virtual void execute();
+ virtual void unexecute();
+
+protected:
+ MatrixElement* matrix;
+ uint rowPos;
+ uint colPos;
+
+ QPtrList<MatrixSequenceElement>* row;
+};
+
+
+class KFCInsertRow : public KFCRemoveRow {
+public:
+ KFCInsertRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
+
+ virtual void execute() { KFCRemoveRow::unexecute(); }
+ virtual void unexecute() { KFCRemoveRow::execute(); }
+};
+
+
+class KFCRemoveColumn : public Command {
+public:
+ KFCRemoveColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
+ ~KFCRemoveColumn();
+
+ virtual void execute();
+ virtual void unexecute();
+
+protected:
+ MatrixElement* matrix;
+ uint rowPos;
+ uint colPos;
+
+ QPtrList<MatrixSequenceElement>* column;
+};
+
+
+class KFCInsertColumn : public KFCRemoveColumn {
+public:
+ KFCInsertColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
+
+ virtual void execute() { KFCRemoveColumn::unexecute(); }
+ virtual void unexecute() { KFCRemoveColumn::execute(); }
+};
+
+
+KCommand* MatrixSequenceElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ return 0;
+ }
+
+ switch ( *request ) {
+ case req_appendColumn:
+ case req_appendRow:
+ case req_insertColumn:
+ case req_removeColumn:
+ case req_insertRow:
+ case req_removeRow: {
+ MatrixElement* matrix = static_cast<MatrixElement*>( getParent() );
+ FormulaCursor* cursor = container->activeCursor();
+ for ( uint row = 0; row < matrix->getRows(); row++ ) {
+ for ( uint col = 0; col < matrix->getColumns(); col++ ) {
+ if ( matrix->getElement( row, col ) == cursor->getElement() ) {
+ switch ( *request ) {
+ case req_appendColumn:
+ return new KFCInsertColumn( i18n( "Append Column" ), container, matrix, row, matrix->getColumns() );
+ case req_appendRow:
+ return new KFCInsertRow( i18n( "Append Row" ), container, matrix, matrix->getRows(), col );
+ case req_insertColumn:
+ return new KFCInsertColumn( i18n( "Insert Column" ), container, matrix, row, col );
+ case req_removeColumn:
+ if ( matrix->getColumns() > 1 ) {
+ return new KFCRemoveColumn( i18n( "Remove Column" ), container, matrix, row, col );
+ }
+ break;
+ case req_insertRow:
+ return new KFCInsertRow( i18n( "Insert Row" ), container, matrix, row, col );
+ case req_removeRow:
+ if ( matrix->getRows() > 1 ) {
+ return new KFCRemoveRow( i18n( "Remove Row" ), container, matrix, row, col );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ kdWarning( DEBUGID ) << "MatrixSequenceElement::buildCommand: Sequence not found." << endl;
+ break;
+ }
+ default:
+ break;
+ }
+ return inherited::buildCommand( container, request );
+}
+
+
+KFCRemoveRow::KFCRemoveRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
+ : Command( name, document ), matrix( m ), rowPos( r ), colPos( c ), row( 0 )
+{
+}
+
+KFCRemoveRow::~KFCRemoveRow()
+{
+ delete row;
+}
+
+void KFCRemoveRow::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ row = matrix->content.at( rowPos );
+ FormulaElement* formula = matrix->formula();
+ for ( uint i = matrix->getColumns(); i > 0; i-- ) {
+ formula->elementRemoval( row->at( i-1 ) );
+ }
+ matrix->content.take( rowPos );
+ formula->changed();
+ if ( rowPos < matrix->getRows() ) {
+ matrix->getElement( rowPos, colPos )->goInside( cursor );
+ }
+ else {
+ matrix->getElement( rowPos-1, colPos )->goInside( cursor );
+ }
+ testDirty();
+}
+
+void KFCRemoveRow::unexecute()
+{
+ matrix->content.insert( rowPos, row );
+ row = 0;
+ FormulaCursor* cursor = getExecuteCursor();
+ matrix->getElement( rowPos, colPos )->goInside( cursor );
+ matrix->formula()->changed();
+ testDirty();
+}
+
+
+KFCInsertRow::KFCInsertRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
+ : KFCRemoveRow( name, document, m, r, c )
+{
+ row = new QPtrList< MatrixSequenceElement >;
+ row->setAutoDelete( true );
+ for ( uint i = 0; i < matrix->getColumns(); i++ ) {
+ row->append( new MatrixSequenceElement( matrix ) );
+ }
+}
+
+
+KFCRemoveColumn::KFCRemoveColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
+ : Command( name, document ), matrix( m ), rowPos( r ), colPos( c )
+{
+ column = new QPtrList< MatrixSequenceElement >;
+ column->setAutoDelete( true );
+}
+
+KFCRemoveColumn::~KFCRemoveColumn()
+{
+ delete column;
+}
+
+void KFCRemoveColumn::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ FormulaElement* formula = matrix->formula();
+ for ( uint i = 0; i < matrix->getRows(); i++ ) {
+ column->append( matrix->getElement( i, colPos ) );
+ formula->elementRemoval( column->at( i ) );
+ matrix->content.at( i )->take( colPos );
+ }
+ formula->changed();
+ if ( colPos < matrix->getColumns() ) {
+ matrix->getElement( rowPos, colPos )->goInside( cursor );
+ }
+ else {
+ matrix->getElement( rowPos, colPos-1 )->goInside( cursor );
+ }
+ testDirty();
+}
+
+void KFCRemoveColumn::unexecute()
+{
+ for ( uint i = 0; i < matrix->getRows(); i++ ) {
+ matrix->content.at( i )->insert( colPos, column->take( 0 ) );
+ }
+ FormulaCursor* cursor = getExecuteCursor();
+ matrix->getElement( rowPos, colPos )->goInside( cursor );
+ matrix->formula()->changed();
+ testDirty();
+}
+
+
+KFCInsertColumn::KFCInsertColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
+ : KFCRemoveColumn( name, document, m, r, c )
+{
+ for ( uint i = 0; i < matrix->getRows(); i++ ) {
+ column->append( new MatrixSequenceElement( matrix ) );
+ }
+}
+
+
+MatrixElement::MatrixElement(uint rows, uint columns, BasicElement* parent)
+ : BasicElement(parent),
+ m_rowNumber( 0 ),
+ m_align( NoAlign ),
+ m_widthType( NoSize ),
+ m_frame( NoLine ),
+ m_frameHSpacing( NoSize ),
+ m_frameVSpacing( NoSize ),
+ m_side( NoSide ),
+ m_minLabelSpacingType( NoSize ),
+ m_customEqualRows( false ),
+ m_customEqualColumns( false ),
+ m_customDisplayStyle( false )
+{
+ for (uint r = 0; r < rows; r++) {
+ QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
+ list->setAutoDelete(true);
+ for (uint c = 0; c < columns; c++) {
+ list->append(new MatrixSequenceElement(this));
+ }
+ content.append(list);
+ }
+ content.setAutoDelete(true);
+}
+
+MatrixElement::~MatrixElement()
+{
+}
+
+
+MatrixElement::MatrixElement( const MatrixElement& other )
+ : BasicElement( other )
+{
+ uint rows = other.getRows();
+ uint columns = other.getColumns();
+
+ QPtrListIterator< QPtrList< MatrixSequenceElement > > rowIter( other.content );
+ for (uint r = 0; r < rows; r++) {
+ ++rowIter;
+ QPtrListIterator< MatrixSequenceElement > colIter( *rowIter.current() );
+
+ QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
+ list->setAutoDelete(true);
+ for (uint c = 0; c < columns; c++) {
+ ++colIter;
+ MatrixSequenceElement *mse =
+ //new MatrixSequenceElement( *( other.getElement( r, c ) ) );
+ new MatrixSequenceElement( *colIter.current() );
+ list->append( mse );
+ mse->setParent( this );
+ }
+ content.append(list);
+ }
+ content.setAutoDelete(true);
+}
+
+
+bool MatrixElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void MatrixElement::entered( SequenceElement* /*child*/ )
+{
+ formula()->tell( i18n( "Matrix element" ) );
+}
+
+
+BasicElement* MatrixElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+
+ uint rows = getRows();
+ uint columns = getColumns();
+
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < columns; c++) {
+ BasicElement* element = getElement(r, c);
+ e = element->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ }
+ }
+
+ // We are in one of those gaps.
+ luPixel dx = point.x() - myPos.x();
+ luPixel dy = point.y() - myPos.y();
+
+ uint row = rows;
+ for (uint r = 0; r < rows; r++) {
+ BasicElement* element = getElement(r, 0);
+ if (element->getY() > dy) {
+ row = r;
+ break;
+ }
+ }
+ if (row == 0) {
+ BasicElement* element = getParent();
+ element->moveLeft(cursor, this);
+ handled = true;
+ return element;
+ }
+ row--;
+
+ uint column = columns;
+ for (uint c = 0; c < columns; c++) {
+ BasicElement* element = getElement(row, c);
+ if (element->getX() > dx) {
+ column = c;
+ break;
+ }
+ }
+ if (column == 0) {
+ BasicElement* element = getParent();
+ element->moveLeft(cursor, this);
+ handled = true;
+ return element;
+ }
+ column--;
+
+ // Rescan the rows with the actual colums required.
+ row = rows;
+ for (uint r = 0; r < rows; r++) {
+ BasicElement* element = getElement(r, column);
+ if (element->getY() > dy) {
+ row = r;
+ break;
+ }
+ }
+ if (row == 0) {
+ BasicElement* element = getParent();
+ element->moveLeft(cursor, this);
+ handled = true;
+ return element;
+ }
+ row--;
+
+ BasicElement* element = getElement(row, column);
+ element->moveLeft(cursor, this);
+ handled = true;
+ return element;
+ }
+ return 0;
+}
+
+
+// drawing
+//
+// Drawing depends on a context which knows the required properties like
+// fonts, spaces and such.
+// It is essential to calculate elements size with the same context
+// before you draw.
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void MatrixElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ QMemArray<luPixel> toMidlines(getRows());
+ QMemArray<luPixel> fromMidlines(getRows());
+ QMemArray<luPixel> widths(getColumns());
+
+ toMidlines.fill(0);
+ fromMidlines.fill(0);
+ widths.fill(0);
+
+ uint rows = getRows();
+ uint columns = getColumns();
+
+ ContextStyle::TextStyle i_tstyle = context.convertTextStyleFraction(tstyle);
+ ContextStyle::IndexStyle i_istyle = context.convertIndexStyleUpper(istyle);
+ double factor = style.sizeFactor();
+
+ for (uint r = 0; r < rows; r++) {
+ QPtrList< MatrixSequenceElement >* list = content.at(r);
+ for (uint c = 0; c < columns; c++) {
+ SequenceElement* element = list->at(c);
+ element->calcSizes( context, i_tstyle, i_istyle, style );
+ toMidlines[r] = QMAX(toMidlines[r], element->axis( context, i_tstyle, factor ));
+ fromMidlines[r] = QMAX(fromMidlines[r],
+ element->getHeight()-element->axis( context, i_tstyle, factor ));
+ widths[c] = QMAX(widths[c], element->getWidth());
+ }
+ }
+
+ luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+
+ luPixel yPos = 0;
+ for (uint r = 0; r < rows; r++) {
+ QPtrList< MatrixSequenceElement >* list = content.at(r);
+ luPixel xPos = 0;
+ yPos += toMidlines[r];
+ for (uint c = 0; c < columns; c++) {
+ SequenceElement* element = list->at(c);
+ switch (context.getMatrixAlignment()) {
+ case ContextStyle::left:
+ element->setX(xPos);
+ break;
+ case ContextStyle::center:
+ element->setX(xPos + (widths[c] - element->getWidth())/2);
+ break;
+ case ContextStyle::right:
+ element->setX(xPos + widths[c] - element->getWidth());
+ break;
+ }
+ element->setY(yPos - element->axis( context, i_tstyle, factor ));
+ xPos += widths[c] + distX;
+ }
+ yPos += fromMidlines[r] + distY;
+ }
+
+ luPixel width = distX * (columns - 1);
+ luPixel height = distY * (rows - 1);
+
+ for (uint r = 0; r < rows; r++) height += toMidlines[r] + fromMidlines[r];
+ for (uint c = 0; c < columns; c++) width += widths[c];
+
+ setWidth(width);
+ setHeight(height);
+ if ((rows == 2) && (columns == 1)) {
+ setBaseline( getMainChild()->getHeight() + distY / 2 + context.axisHeight( tstyle, factor ) );
+ }
+ else {
+ setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
+ }
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void MatrixElement::draw( QPainter& painter, const LuPixelRect& rect,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( rect ) )
+ // return;
+
+ uint rows = getRows();
+ uint columns = getColumns();
+
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < columns; c++) {
+ getElement(r, c)->draw(painter, rect, context,
+ context.convertTextStyleFraction(tstyle),
+ context.convertIndexStyleUpper(istyle),
+ style,
+ myPos);
+ }
+ }
+
+ // Debug
+ //painter.setPen(Qt::red);
+ //painter.drawRect(myPos.x(), myPos.y(), getWidth(), getHeight());
+}
+
+
+void MatrixElement::dispatchFontCommand( FontCommand* cmd )
+{
+ uint rows = getRows();
+ uint columns = getColumns();
+
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < columns; c++) {
+ getElement(r, c)->dispatchFontCommand( cmd );
+ }
+ }
+}
+
+
+// navigation
+//
+// The elements are responsible to handle cursor movement themselves.
+// To do this they need to know the direction the cursor moves and
+// the element it comes from.
+//
+// The cursor might be in normal or in selection mode.
+
+/**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+void MatrixElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ getElement(getRows()-1, getColumns()-1)->moveLeft(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ uint row = 0;
+ uint column = 0;
+ if (searchElement(from, row, column)) {
+ if (column > 0) {
+ getElement(row, column-1)->moveLeft(cursor, this);
+ }
+ else if (linear && (row > 0)) {
+ getElement(row-1, getColumns()-1)->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+ }
+}
+
+/**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+void MatrixElement::moveRight(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ getElement(0, 0)->moveRight(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ uint row = 0;
+ uint column = 0;
+ if (searchElement(from, row, column)) {
+ if (column < getColumns()-1) {
+ getElement(row, column+1)->moveRight(cursor, this);
+ }
+ else if (linear && (row < getRows()-1)) {
+ getElement(row+1, 0)->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ }
+ }
+}
+
+/**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+void MatrixElement::moveUp(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveUp(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ getElement(0, 0)->moveRight(cursor, this);
+ }
+ else {
+ uint row = 0;
+ uint column = 0;
+ if (searchElement(from, row, column)) {
+ if (row > 0) {
+ getElement(row-1, column)->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveUp(cursor, this);
+ }
+ }
+ else {
+ getParent()->moveUp(cursor, this);
+ }
+ }
+ }
+}
+
+/**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+void MatrixElement::moveDown(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveDown(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ getElement(0, 0)->moveRight(cursor, this);
+ }
+ else {
+ uint row = 0;
+ uint column = 0;
+ if (searchElement(from, row, column)) {
+ if (row < getRows()-1) {
+ getElement(row+1, column)->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveDown(cursor, this);
+ }
+ }
+ else {
+ getParent()->moveDown(cursor, this);
+ }
+ }
+ }
+}
+
+/**
+ * Sets the cursor inside this element to its start position.
+ * For most elements that is the main child.
+ */
+void MatrixElement::goInside(FormulaCursor* cursor)
+{
+ getElement(0, 0)->goInside(cursor);
+}
+
+
+// If there is a main child we must provide the insert/remove semantics.
+SequenceElement* MatrixElement::getMainChild()
+{
+ return content.at(0)->at(0);
+}
+
+void MatrixElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ uint rows = getRows();
+ uint columns = getColumns();
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < columns; c++) {
+ if (child == getElement(r, c)) {
+ cursor->setTo(this, r*columns+c);
+ }
+ }
+ }
+}
+
+const MatrixSequenceElement* MatrixElement::getElement( uint row, uint column ) const
+{
+ QPtrListIterator< QPtrList < MatrixSequenceElement > > rows( content );
+ rows += row;
+ if ( ! rows.current() )
+ return 0;
+
+ QPtrListIterator< MatrixSequenceElement > cols ( *rows.current() );
+ cols += column;
+ return cols.current();
+}
+
+
+bool MatrixElement::searchElement(BasicElement* element, uint& row, uint& column)
+{
+ uint rows = getRows();
+ uint columns = getColumns();
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < columns; c++) {
+ if (element == getElement(r, c)) {
+ row = r;
+ column = c;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void MatrixElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ uint rows = getRows();
+ uint cols = getColumns();
+
+ element.setAttribute("ROWS", rows);
+ element.setAttribute("COLUMNS", cols);
+
+ QDomDocument doc = element.ownerDocument();
+
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < cols; c++) {
+ QDomElement tmp = getElement(r,c)->getElementDom(doc);
+ element.appendChild(tmp);
+ }
+ element.appendChild(doc.createComment("end of row"));
+ }
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool MatrixElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ uint rows = 0;
+ QString rowStr = element.attribute("ROWS");
+ if(!rowStr.isNull()) {
+ rows = rowStr.toInt();
+ }
+ if (rows == 0) {
+ kdWarning( DEBUGID ) << "Rows <= 0 in MatrixElement." << endl;
+ return false;
+ }
+
+ QString columnStr = element.attribute("COLUMNS");
+ uint cols = 0;
+ if(!columnStr.isNull()) {
+ cols = columnStr.toInt();
+ }
+ if (cols == 0) {
+ kdWarning( DEBUGID ) << "Columns <= 0 in MatrixElement." << endl;
+ return false;
+ }
+
+ content.clear();
+ for (uint r = 0; r < rows; r++) {
+ QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
+ list->setAutoDelete(true);
+ content.append(list);
+ for (uint c = 0; c < cols; c++) {
+ MatrixSequenceElement* element = new MatrixSequenceElement(this);
+ list->append(element);
+ }
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool MatrixElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ uint rows = getRows();
+ uint cols = getColumns();
+
+ uint r = 0;
+ uint c = 0;
+ while ( !node.isNull() && r < rows ) {
+ if ( node.isElement() ) {
+ SequenceElement* element = getElement( r, c );
+ QDomElement e = node.toElement();
+ if ( !element->buildFromDom( e ) ) {
+ return false;
+ }
+ c++;
+ if ( c == cols ) {
+ c = 0;
+ r++;
+ }
+ }
+ node = node.nextSibling();
+ }
+ return true;
+}
+
+bool MatrixElement::readAttributesFromMathMLDom( const QDomElement& element )
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ QString alignStr = element.attribute( "align" ).lower();
+ if ( ! alignStr.isNull() ) {
+ if ( alignStr.find( "top" ) != -1 ) {
+ m_align = TopAlign;
+ }
+ else if ( alignStr.find( "bottom" ) != -1 ) {
+ m_align = BottomAlign;
+ }
+ else if ( alignStr.find( "center" ) != -1 ) {
+ m_align = CenterAlign;
+ }
+ else if ( alignStr.find( "baseline" ) != -1 ) {
+ m_align = BaselineAlign;
+ }
+ else if ( alignStr.find( "axis" ) != -1 ) {
+ m_align = AxisAlign;
+ }
+ int index = alignStr.findRev( ' ' );
+ if ( index != -1 ) {
+ m_rowNumber = alignStr.right( index + 1 ).toInt();
+ }
+ }
+ QString rowalignStr = element.attribute( "rowalign" ).lower();
+ if ( ! rowalignStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', rowalignStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ if ( *it == "top" ) {
+ m_rowAlign.append( TopAlign );
+ }
+ else if ( *it == "bottom" ) {
+ m_rowAlign.append( BottomAlign );
+ }
+ else if ( *it == "center" ) {
+ m_rowAlign.append( CenterAlign );
+ }
+ else if ( *it == "baseline" ) {
+ m_rowAlign.append( BaselineAlign );
+ }
+ else if ( *it == "axis" ) {
+ m_rowAlign.append( AxisAlign );
+ }
+ }
+ }
+ QString columnalignStr = element.attribute( "columnalign" ).lower();
+ if ( ! columnalignStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', columnalignStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ if ( *it == "left" ) {
+ m_columnAlign.append( LeftHorizontalAlign );
+ }
+ else if ( *it == "center" ) {
+ m_columnAlign.append( CenterHorizontalAlign );
+ }
+ else if ( *it == "right" ) {
+ m_columnAlign.append( RightHorizontalAlign );
+ }
+ }
+ }
+ QString alignmentscopeStr = element.attribute( "alignmentscope" ).lower();
+ if ( ! alignmentscopeStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', alignmentscopeStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ if ( *it == "true" ) {
+ m_alignmentScope.append( true );
+ }
+ else if ( *it == "false" ) {
+ m_alignmentScope.append( false );
+ }
+ }
+ }
+ QString columnwidthStr = element.attribute( "columnwidth" ).lower();
+ if ( columnwidthStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', columnwidthStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ SizeType type = NoSize;
+ double length;
+ if ( *it == "auto" ) {
+ type = AutoSize;
+ }
+ else if ( *it == "fit" ) {
+ type = FitSize;
+ }
+ else {
+ length = getSize( columnwidthStr, &type );
+ if ( type == NoSize ) {
+ type = getSpace( columnwidthStr );
+ }
+ }
+ if ( type != NoSize ) {
+ m_columnWidthType.append( type );
+ if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
+ m_columnWidth.append( length );
+ }
+ }
+ }
+ }
+ QString widthStr = element.attribute( "width" ).lower();
+ if ( ! widthStr.isNull() ) {
+ if ( widthStr == "auto" ) {
+ m_widthType = AutoSize;
+ }
+ else {
+ m_width = getSize( widthStr, &m_widthType );
+ }
+ }
+ QString rowspacingStr = element.attribute( "rowspacing" ).lower();
+ if ( ! rowspacingStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', rowspacingStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ SizeType type;
+ double length = getSize( *it, &type );
+ if ( type != NoSize ) {
+ m_rowSpacingType.append( type );
+ m_rowSpacing.append( length );
+ }
+ }
+ }
+ QString columnspacingStr = element.attribute( "columnspacing" ).lower();
+ if ( ! columnspacingStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', columnspacingStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ SizeType type;
+ double length = getSize( *it, &type );
+ if ( type == NoSize ) {
+ type = getSpace( columnspacingStr );
+ }
+ if ( type != NoSize ) {
+ m_columnSpacingType.append( type );
+ if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
+ m_columnSpacing.append( length );
+ }
+ }
+ }
+ }
+ QString rowlinesStr = element.attribute( "rowlines" ).lower();
+ if ( ! rowlinesStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', rowlinesStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ if ( *it == "none" ) {
+ m_rowLines.append( NoneLine );
+ }
+ else if ( *it == "solid" ) {
+ m_rowLines.append( SolidLine );
+ }
+ else if ( *it == "dashed" ) {
+ m_rowLines.append( DashedLine );
+ }
+ }
+ }
+ QString columnlinesStr = element.attribute( "columnlines" ).lower();
+ if ( ! columnlinesStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', columnlinesStr );
+ for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
+ if ( *it == "none" ) {
+ m_columnLines.append( NoneLine );
+ }
+ else if ( *it == "solid" ) {
+ m_columnLines.append( SolidLine );
+ }
+ else if ( *it == "dashed" ) {
+ m_columnLines.append( DashedLine );
+ }
+ }
+ }
+ QString frameStr = element.attribute( "frame" ).stripWhiteSpace().lower();
+ if ( ! frameStr.isNull() ) {
+ if ( frameStr == "none" ) {
+ m_frame = NoneLine;
+ }
+ else if ( frameStr == "solid" ) {
+ m_frame = SolidLine;
+ }
+ else if ( frameStr == "dashed" ) {
+ m_frame = DashedLine;
+ }
+ }
+ QString framespacingStr = element.attribute( "framespacing" );
+ if ( ! framespacingStr.isNull() ) {
+ QStringList list = QStringList::split( ' ', framespacingStr );
+ m_frameHSpacing = getSize( list[0], &m_frameHSpacingType );
+ if ( m_frameHSpacingType == NoSize ) {
+ m_frameHSpacingType = getSpace( list[0] );
+ }
+ if ( list.count() > 1 ) {
+ m_frameVSpacing = getSize( list[1], &m_frameVSpacingType );
+ if ( m_frameVSpacingType == NoSize ) {
+ m_frameVSpacingType = getSpace( list[1] );
+ }
+ }
+ }
+ QString equalrowsStr = element.attribute( "equalrows" ).stripWhiteSpace().lower();
+ if ( ! equalrowsStr.isNull() ) {
+ m_customEqualRows = true;
+ if ( equalrowsStr == "false" ) {
+ m_equalRows = false;
+ }
+ else {
+ m_equalRows = true;
+ }
+ }
+ QString equalcolumnsStr = element.attribute( "equalcolumns" ).stripWhiteSpace().lower();
+ if ( ! equalcolumnsStr.isNull() ) {
+ m_customEqualColumns = true;
+ if ( equalcolumnsStr == "false" ) {
+ m_equalColumns = false;
+ }
+ else {
+ m_equalColumns = true;
+ }
+ }
+ QString displaystyleStr = element.attribute( "displaystyle" ).stripWhiteSpace().lower();
+ if ( ! displaystyleStr.isNull() ) {
+ m_customDisplayStyle = true;
+ if ( displaystyleStr == "false" ) {
+ m_displayStyle = false;
+ }
+ else {
+ m_displayStyle = true;
+ }
+ }
+ QString sideStr = element.attribute( "side" ).stripWhiteSpace().lower();
+ if ( ! sideStr.isNull() ) {
+ if ( sideStr == "left" ) {
+ m_side = LeftSide;
+ }
+ else if ( sideStr == "right" ) {
+ m_side = RightSide;
+ }
+ else if ( sideStr == "leftoverlap" ) {
+ m_side = LeftOverlapSide;
+ }
+ else if ( sideStr == "rightoverlap" ) {
+ m_side = RightOverlapSide;
+ }
+ }
+ QString minlabelspacingStr = element.attribute( "minlabelspacing" ).stripWhiteSpace().lower();
+ if ( ! minlabelspacingStr.isNull() ) {
+ m_minLabelSpacing = getSize( minlabelspacingStr, &m_minLabelSpacingType );
+ if ( m_minLabelSpacingType == NoSize ) {
+ m_minLabelSpacingType = getSpace( minlabelspacingStr );
+ }
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read. It is sometimes needed to read more than one node
+ * (e. g. for fence operators).
+ * Returns the number of nodes processed or -1 if it failed.
+ */
+int MatrixElement::readContentFromMathMLDom( QDomNode& node )
+{
+ // We have twice, since there may be empty elements and we need to know how
+ // many of them we have. So, first pass, get number of rows and columns
+
+ if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
+ return -1;
+ }
+
+ uint rows = 0;
+ uint cols = 0;
+ QDomNode n = node;
+ while ( !n.isNull() ) {
+ if ( n.isElement() ) {
+ QDomElement e = n.toElement();
+ if ( e.tagName().lower() == "mtr" || e.tagName().lower() == "mlabeledtr" )
+ {
+ rows++;
+
+ /* Determins the number of columns */
+ QDomNode cellnode = e.firstChild();
+ int cc = 0;
+
+ while ( !cellnode.isNull() ) {
+ if ( cellnode.isElement() )
+ cc++;
+ cellnode = cellnode.nextSibling();
+ }
+ if ( cc > 0 && e.tagName().lower() == "mlabeledtr" )
+ cc--;
+ if ( cc > cols )
+ cols = cc;
+ }
+ }
+ n = n.nextSibling();
+ }
+
+ // Create elements
+ content.clear();
+ for (uint r = 0; r < rows; r++) {
+ QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
+ list->setAutoDelete(true);
+ content.append(list);
+ for (uint c = 0; c < cols; c++) {
+ MatrixSequenceElement* element = new MatrixSequenceElement(this);
+ list->append(element);
+ }
+ }
+
+ // Second pass, read elements now
+ uint r = 0;
+ uint c = 0;
+ while ( !node.isNull() ) {
+ if ( node.isElement() ) {
+ QDomElement e = node.toElement();
+ if ( e.tagName().lower() == "mtr" || e.tagName().lower() == "mlabeledtr" ) {
+ QDomNode cellnode = e.firstChild();
+ if ( e.tagName().lower() == "mlabeledtr" ) {
+ while ( ! cellnode.isNull() && ! cellnode.isElement() )
+ cellnode = cellnode.nextSibling();
+ if ( ! cellnode.isNull() )
+ cellnode = cellnode.nextSibling();
+ }
+ while ( !cellnode.isNull() ) {
+ if ( cellnode.isElement() ) {
+ QDomElement cellelement = cellnode.toElement();
+ if ( cellelement.tagName().lower() != "mtd" ) {
+ // TODO: Inferred mtd. Deprecated in MathML 2.0
+ kdWarning( DEBUGID ) << "Unsupported tag "
+ << cellelement.tagName()
+ << " inside matrix row\n";
+ }
+ else {
+ SequenceElement* element = getElement(r, c);
+ if ( element->buildFromMathMLDom( cellelement ) == -1 )
+ return -1;
+ c++;
+ }
+ }
+ cellnode = cellnode.nextSibling();
+ }
+ c = 0;
+ r++;
+ }
+ }
+ node = node.nextSibling();
+ }
+ return 1;
+}
+
+QString MatrixElement::toLatex()
+{
+ //All the border handling must be implemented here too
+
+ QString matrix;
+ uint cols=getColumns();
+ uint rows=getRows();
+
+ matrix="\\begin{array}{ ";
+ for(uint i=0;i<cols;i++)
+ matrix+="c ";
+
+ matrix+="} ";
+
+ for (uint r = 0; r < rows; r++) {
+ for (uint c = 0; c < cols; c++) {
+ matrix+=getElement(r, c)->toLatex();
+ if( c < cols-1) matrix+=" & ";
+ }
+ if(r < rows-1 ) matrix+=" \\\\ ";
+ }
+
+ matrix+=" \\end{array}";
+
+ return matrix;
+}
+
+QString MatrixElement::formulaString()
+{
+ QString matrix = "[";
+ uint cols=getColumns();
+ uint rows=getRows();
+ for (uint r = 0; r < rows; r++) {
+ matrix += "[";
+ for (uint c = 0; c < cols; c++) {
+ matrix+=getElement(r, c)->formulaString();
+ if ( c < cols-1 ) matrix+=", ";
+ }
+ matrix += "]";
+ if ( r < rows-1 ) matrix += ", ";
+ }
+ matrix += "]";
+ return matrix;
+}
+
+
+SequenceElement* MatrixElement::elementAt(uint row, uint column)
+{
+ return getElement( row, column );
+}
+
+void MatrixElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ QString rownumber;
+ if ( m_rowNumber ) {
+ rownumber = QString( " %1" ).arg( m_rowNumber );
+ }
+ switch ( m_align ) {
+ case TopAlign:
+ element.setAttribute( "align", "top" + rownumber );
+ break;
+ case BottomAlign:
+ element.setAttribute( "align", "bottom" + rownumber );
+ break;
+ case CenterAlign:
+ element.setAttribute( "align", "center" + rownumber );
+ break;
+ case BaselineAlign:
+ element.setAttribute( "align", "baseline" + rownumber );
+ break;
+ case AxisAlign:
+ element.setAttribute( "align", "axis" + rownumber );
+ break;
+ default:
+ break;
+ }
+ QString rowalign;
+ for ( QValueList< VerticalAlign >::const_iterator it = m_rowAlign.begin(); it != m_rowAlign.end(); it++ )
+ {
+ switch ( *it ) {
+ case TopAlign:
+ rowalign.append( "top " );
+ break;
+ case BottomAlign:
+ rowalign.append( "bottom " );
+ break;
+ case CenterAlign:
+ rowalign.append( "center " );
+ break;
+ case BaselineAlign:
+ rowalign.append( "baseline " );
+ break;
+ case AxisAlign:
+ rowalign.append( "axis " );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( ! rowalign.isNull() ) {
+ element.setAttribute( "rowalign", rowalign.stripWhiteSpace() );
+ }
+ QString columnalign;
+ for ( QValueList< HorizontalAlign >::const_iterator it = m_columnAlign.begin(); it != m_columnAlign.end(); it++ )
+ {
+ switch ( *it ) {
+ case LeftHorizontalAlign:
+ rowalign.append( "left " );
+ break;
+ case CenterHorizontalAlign:
+ rowalign.append( "center " );
+ break;
+ case RightHorizontalAlign:
+ rowalign.append( "right " );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( ! columnalign.isNull() ) {
+ element.setAttribute( "columnalign", columnalign.stripWhiteSpace() );
+ }
+ QString alignmentscope;
+ for ( QValueList< bool >::const_iterator it = m_alignmentScope.begin(); it != m_alignmentScope.end(); it++ )
+ {
+ if ( *it ) {
+ alignmentscope.append( "true " );
+ }
+ else {
+ alignmentscope.append( "false " );
+ }
+ }
+ if ( ! alignmentscope.isNull() ) {
+ element.setAttribute( "alignmentscope", alignmentscope.stripWhiteSpace() );
+ }
+ QString columnwidth;
+ QValueList< double >::const_iterator lengthIt = m_columnWidth.begin();
+ for ( QValueList< SizeType >::const_iterator typeIt = m_columnWidthType.begin();
+ typeIt != m_columnWidthType.end(); typeIt ++ ) {
+ switch ( *typeIt ) {
+ case AutoSize:
+ columnwidth.append( "auto " );
+ break;
+ case FitSize:
+ columnwidth.append( "fit " );
+ break;
+ case AbsoluteSize:
+ columnwidth.append( QString( "%1pt " ).arg( *lengthIt ) );
+ lengthIt++;
+ break;
+ case RelativeSize:
+ columnwidth.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
+ lengthIt++;
+ break;
+ case PixelSize:
+ columnwidth.append( QString( "%1px " ).arg( *lengthIt ) );
+ lengthIt++;
+ break;
+ case NegativeVeryVeryThinMathSpace:
+ columnwidth.append( "negativeveryverythinmathspace " );
+ break;
+ case NegativeVeryThinMathSpace:
+ columnwidth.append( "negativeverythinmathspace " );
+ break;
+ case NegativeThinMathSpace:
+ columnwidth.append( "negativethinmathspace " );
+ break;
+ case NegativeMediumMathSpace:
+ columnwidth.append( "negativemediummathspace " );
+ break;
+ case NegativeThickMathSpace:
+ columnwidth.append( "negativethickmathspace " );
+ break;
+ case NegativeVeryThickMathSpace:
+ columnwidth.append( "negativeverythickmathspace " );
+ break;
+ case NegativeVeryVeryThickMathSpace:
+ columnwidth.append( "negativeveryverythickmathspace " );
+ break;
+ case VeryVeryThinMathSpace:
+ columnwidth.append( "veryverythinmathspace " );
+ break;
+ case VeryThinMathSpace:
+ columnwidth.append( "verythinmathspace " );
+ break;
+ case ThinMathSpace:
+ columnwidth.append( "thinmathspace " );
+ break;
+ case MediumMathSpace:
+ columnwidth.append( "mediummathspace " );
+ break;
+ case ThickMathSpace:
+ columnwidth.append( "thickmathspace " );
+ break;
+ case VeryThickMathSpace:
+ columnwidth.append( "verythickmathspace " );
+ break;
+ case VeryVeryThickMathSpace:
+ columnwidth.append( "veryverythickmathspace " );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( ! columnwidth.isNull() ) {
+ element.setAttribute( "columnwidth", columnwidth.stripWhiteSpace() );
+ }
+ switch ( m_widthType ) {
+ case AutoSize:
+ element.setAttribute( "width", "auto" );
+ break;
+ case AbsoluteSize:
+ element.setAttribute( "width", QString( "%1pt" ).arg( m_width ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "width", QString( "%1% " ).arg( m_width * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "width", QString( "%1px " ).arg( m_width ) );
+ break;
+ default:
+ break;
+ }
+ QString rowspacing;
+ lengthIt = m_rowSpacing.begin();
+ for ( QValueList< SizeType >::const_iterator typeIt = m_rowSpacingType.begin();
+ typeIt != m_rowSpacingType.end(); typeIt++, lengthIt++ ) {
+ switch ( *typeIt ) {
+ case AbsoluteSize:
+ rowspacing.append( QString( "%1pt " ).arg( *lengthIt ) );
+ break;
+ case RelativeSize:
+ rowspacing.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
+ break;
+ case PixelSize:
+ rowspacing.append( QString( "%1px " ).arg( *lengthIt ) );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( ! rowspacing.isNull() ) {
+ element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
+ }
+ QString columnspacing;
+ lengthIt = m_columnSpacing.begin();
+ for ( QValueList< SizeType >::const_iterator typeIt = m_columnSpacingType.begin();
+ typeIt != m_columnSpacingType.end(); typeIt++ ) {
+ switch ( *typeIt ) {
+ case AbsoluteSize:
+ columnspacing.append( QString( "%1pt " ).arg( *lengthIt ) );
+ lengthIt++;
+ break;
+ case RelativeSize:
+ columnspacing.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
+ lengthIt++;
+ break;
+ case PixelSize:
+ columnspacing.append( QString( "%1px " ).arg( *lengthIt ) );
+ lengthIt++;
+ break;
+ case NegativeVeryVeryThinMathSpace:
+ columnspacing.append( "negativeveryverythinmathspace " );
+ break;
+ case NegativeVeryThinMathSpace:
+ columnspacing.append( "negativeverythinmathspace " );
+ break;
+ case NegativeThinMathSpace:
+ columnspacing.append( "negativethinmathspace " );
+ break;
+ case NegativeMediumMathSpace:
+ columnspacing.append( "negativemediummathspace " );
+ break;
+ case NegativeThickMathSpace:
+ columnspacing.append( "negativethickmathspace " );
+ break;
+ case NegativeVeryThickMathSpace:
+ columnspacing.append( "negativeverythickmathspace " );
+ break;
+ case NegativeVeryVeryThickMathSpace:
+ columnspacing.append( "negativeveryverythickmathspace " );
+ break;
+ case VeryVeryThinMathSpace:
+ columnspacing.append( "veryverythinmathspace " );
+ break;
+ case VeryThinMathSpace:
+ columnspacing.append( "verythinmathspace " );
+ break;
+ case ThinMathSpace:
+ columnspacing.append( "thinmathspace " );
+ break;
+ case MediumMathSpace:
+ columnspacing.append( "mediummathspace " );
+ break;
+ case ThickMathSpace:
+ columnspacing.append( "thickmathspace " );
+ break;
+ case VeryThickMathSpace:
+ columnspacing.append( "verythickmathspace " );
+ break;
+ case VeryVeryThickMathSpace:
+ columnspacing.append( "veryverythickmathspace " );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( ! rowspacing.isNull() ) {
+ element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
+ }
+ QString rowlines;
+ for ( QValueList< LineType >::const_iterator it = m_rowLines.begin(); it != m_rowLines.end(); it++ )
+ {
+ switch ( *it ) {
+ case NoneLine:
+ rowlines.append( "none " );
+ break;
+ case SolidLine:
+ rowlines.append( "solid " );
+ break;
+ case DashedLine:
+ rowlines.append( "dashed " );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( ! rowlines.isNull() ) {
+ element.setAttribute( "rowlines", rowlines.stripWhiteSpace() );
+ }
+ QString columnlines;
+ for ( QValueList< LineType >::const_iterator it = m_columnLines.begin(); it != m_columnLines.end(); it++ )
+ {
+ switch ( *it ) {
+ case NoneLine:
+ columnlines.append( "none " );
+ break;
+ case SolidLine:
+ columnlines.append( "solid " );
+ break;
+ case DashedLine:
+ columnlines.append( "dashed " );
+ break;
+ default:
+ break;
+ }
+ }
+ if ( ! columnlines.isNull() ) {
+ element.setAttribute( "columnlines", columnlines.stripWhiteSpace() );
+ }
+ switch ( m_frame ) {
+ case NoneLine:
+ element.setAttribute( "frame", "none" );
+ break;
+ case SolidLine:
+ element.setAttribute( "frame", "solid" );
+ break;
+ case DashedLine:
+ element.setAttribute( "frame", "dashed" );
+ break;
+ default:
+ break;
+ }
+ QString framespacing;
+ switch ( m_frameHSpacingType ) {
+ case AbsoluteSize:
+ framespacing.append( QString( "%1pt " ).arg( m_frameHSpacing ) );
+ break;
+ case RelativeSize:
+ framespacing.append( QString( "%1% " ).arg( m_frameHSpacing * 100.0 ) );
+ break;
+ case PixelSize:
+ framespacing.append( QString( "%1px " ).arg( m_frameHSpacing ) );
+ break;
+ case NegativeVeryVeryThinMathSpace:
+ framespacing.append( "negativeveryverythinmathspace " );
+ break;
+ case NegativeVeryThinMathSpace:
+ framespacing.append( "negativeverythinmathspace " );
+ break;
+ case NegativeThinMathSpace:
+ framespacing.append( "negativethinmathspace " );
+ break;
+ case NegativeMediumMathSpace:
+ framespacing.append( "negativemediummathspace " );
+ break;
+ case NegativeThickMathSpace:
+ framespacing.append( "negativethickmathspace " );
+ break;
+ case NegativeVeryThickMathSpace:
+ framespacing.append( "negativeverythickmathspace " );
+ break;
+ case NegativeVeryVeryThickMathSpace:
+ framespacing.append( "negativeveryverythickmathspace " );
+ break;
+ case VeryVeryThinMathSpace:
+ framespacing.append( "veryverythinmathspace " );
+ break;
+ case VeryThinMathSpace:
+ framespacing.append( "verythinmathspace " );
+ break;
+ case ThinMathSpace:
+ framespacing.append( "thinmathspace " );
+ break;
+ case MediumMathSpace:
+ framespacing.append( "mediummathspace " );
+ break;
+ case ThickMathSpace:
+ framespacing.append( "thickmathspace " );
+ break;
+ case VeryThickMathSpace:
+ framespacing.append( "verythickmathspace " );
+ break;
+ case VeryVeryThickMathSpace:
+ framespacing.append( "veryverythickmathspace " );
+ break;
+ default:
+ break;
+ }
+ switch ( m_frameVSpacingType ) {
+ case AbsoluteSize:
+ framespacing.append( QString( "%1pt " ).arg( m_frameVSpacing ) );
+ break;
+ case RelativeSize:
+ framespacing.append( QString( "%1% " ).arg( m_frameVSpacing * 100.0 ) );
+ break;
+ case PixelSize:
+ framespacing.append( QString( "%1px " ).arg( m_frameVSpacing ) );
+ break;
+ case NegativeVeryVeryThinMathSpace:
+ framespacing.append( "negativeveryverythinmathspace " );
+ break;
+ case NegativeVeryThinMathSpace:
+ framespacing.append( "negativeverythinmathspace " );
+ break;
+ case NegativeThinMathSpace:
+ framespacing.append( "negativethinmathspace " );
+ break;
+ case NegativeMediumMathSpace:
+ framespacing.append( "negativemediummathspace " );
+ break;
+ case NegativeThickMathSpace:
+ framespacing.append( "negativethickmathspace " );
+ break;
+ case NegativeVeryThickMathSpace:
+ framespacing.append( "negativeverythickmathspace " );
+ break;
+ case NegativeVeryVeryThickMathSpace:
+ framespacing.append( "negativeveryverythickmathspace " );
+ break;
+ case VeryVeryThinMathSpace:
+ framespacing.append( "veryverythinmathspace " );
+ break;
+ case VeryThinMathSpace:
+ framespacing.append( "verythinmathspace " );
+ break;
+ case ThinMathSpace:
+ framespacing.append( "thinmathspace " );
+ break;
+ case MediumMathSpace:
+ framespacing.append( "mediummathspace " );
+ break;
+ case ThickMathSpace:
+ framespacing.append( "thickmathspace " );
+ break;
+ case VeryThickMathSpace:
+ framespacing.append( "verythickmathspace " );
+ break;
+ case VeryVeryThickMathSpace:
+ framespacing.append( "veryverythickmathspace " );
+ break;
+ default:
+ break;
+ }
+ if ( ! framespacing.isNull() ) {
+ element.setAttribute( "framespacing", framespacing.stripWhiteSpace() );
+ }
+ if ( m_customEqualRows ) {
+ element.setAttribute( "equalrows", m_equalRows ? "true" : "false" );
+ }
+ if ( m_customEqualColumns ) {
+ element.setAttribute( "equalcolumns", m_equalColumns ? "true" : "false" );
+ }
+ if ( m_customDisplayStyle ) {
+ element.setAttribute( "displaystyle", m_displayStyle ? "true" : "false" );
+ }
+ switch ( m_side ) {
+ case LeftSide:
+ element.setAttribute( "side", "left" );
+ break;
+ case RightSide:
+ element.setAttribute( "side", "right" );
+ break;
+ case LeftOverlapSide:
+ element.setAttribute( "side", "leftoverlap" );
+ break;
+ case RightOverlapSide:
+ element.setAttribute( "side", "rightoverlap" );
+ break;
+ default:
+ break;
+ }
+ switch ( m_minLabelSpacingType ) {
+ case AbsoluteSize:
+ element.setAttribute( "minlabelspacing", QString( "%1pt" ).arg( m_minLabelSpacing ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "minlabelspacing", QString( "%1%" ).arg( m_minLabelSpacing * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "minlabelspacing", QString( "%1px" ).arg( m_minLabelSpacing ) );
+ break;
+ case NegativeVeryVeryThinMathSpace:
+ element.setAttribute( "minlabelspacing", "negativeveryverythinmathspace" );
+ break;
+ case NegativeVeryThinMathSpace:
+ element.setAttribute( "minlabelspacing", "negativeverythinmathspace" );
+ break;
+ case NegativeThinMathSpace:
+ element.setAttribute( "minlabelspacing", "negativethinmathspace" );
+ break;
+ case NegativeMediumMathSpace:
+ element.setAttribute( "minlabelspacing", "negativemediummathspace" );
+ break;
+ case NegativeThickMathSpace:
+ element.setAttribute( "minlabelspacing", "negativethickmathspace" );
+ break;
+ case NegativeVeryThickMathSpace:
+ element.setAttribute( "minlabelspacing", "negativeverythickmathspace" );
+ break;
+ case NegativeVeryVeryThickMathSpace:
+ element.setAttribute( "minlabelspacing", "negativeveryverythickmathspace" );
+ break;
+ case VeryVeryThinMathSpace:
+ element.setAttribute( "minlabelspacing", "veryverythinmathspace" );
+ break;
+ case VeryThinMathSpace:
+ element.setAttribute( "minlabelspacing", "verythinmathspace" );
+ break;
+ case ThinMathSpace:
+ element.setAttribute( "minlabelspacing", "thinmathspace" );
+ break;
+ case MediumMathSpace:
+ element.setAttribute( "minlabelspacing", "mediummathspace" );
+ break;
+ case ThickMathSpace:
+ element.setAttribute( "minlabelspacing", "thickmathspace" );
+ break;
+ case VeryThickMathSpace:
+ element.setAttribute( "minlabelspacing", "verythickmathspace" );
+ break;
+ case VeryVeryThickMathSpace:
+ element.setAttribute( "minlabelspacing", "veryverythickmathspace" );
+ break;
+ default:
+ break;
+ }
+}
+
+void MatrixElement::writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const
+{
+ QDomElement row;
+ QDomElement cell;
+
+ uint rows = getRows();
+ uint cols = getColumns();
+
+ for ( uint r = 0; r < rows; r++ )
+ {
+ row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
+ element.appendChild( row );
+ for ( uint c = 0; c < cols; c++ )
+ {
+ cell = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
+ row.appendChild( cell );
+ getElement(r,c)->writeMathML( doc, cell, oasisFormat );
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * The lines behaviour is (a little) different from that
+ * of ordinary sequences.
+ */
+class MultilineSequenceElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ MultilineSequenceElement( BasicElement* parent = 0 );
+
+ virtual MultilineSequenceElement* clone() {
+ return new MultilineSequenceElement( *this );
+ }
+
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ virtual void registerTab( BasicElement* tab );
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+
+ virtual KCommand* input( Container* container, QKeyEvent* event );
+
+ virtual KCommand* input( Container* container, QChar ch );
+
+ uint tabCount() const { return tabs.count(); }
+
+ BasicElement* tab( uint i ) { return tabs.at( i ); }
+
+ /// Change the width of tab i and move all elements after it.
+ void moveTabTo( uint i, luPixel pos );
+
+ /// Return the greatest tab number less than pos.
+ int tabBefore( uint pos );
+
+ /// Return the position of tab i.
+ int tabPos( uint i );
+
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
+
+private:
+
+ QPtrList<BasicElement> tabs;
+};
+
+
+// Split the line at position pos.
+class KFCNewLine : public Command {
+public:
+ KFCNewLine( const QString& name, Container* document,
+ MultilineSequenceElement* line, uint pos );
+
+ virtual ~KFCNewLine();
+
+ virtual void execute();
+ virtual void unexecute();
+
+private:
+ MultilineSequenceElement* m_line;
+ MultilineSequenceElement* m_newline;
+ uint m_pos;
+};
+
+
+KFCNewLine::KFCNewLine( const QString& name, Container* document,
+ MultilineSequenceElement* line, uint pos )
+ : Command( name, document ),
+ m_line( line ), m_pos( pos )
+{
+ m_newline = new MultilineSequenceElement( m_line->getParent() );
+}
+
+
+KFCNewLine::~KFCNewLine()
+{
+ delete m_newline;
+}
+
+
+void KFCNewLine::execute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
+ int linePos = parent->content.find( m_line );
+ parent->content.insert( linePos+1, m_newline );
+
+ // If there are children to be moved.
+ if ( m_line->countChildren() > static_cast<int>( m_pos ) ) {
+
+ // Remove anything after position pos from the current line
+ m_line->selectAllChildren( cursor );
+ cursor->setMark( m_pos );
+ QPtrList<BasicElement> elementList;
+ m_line->remove( cursor, elementList, beforeCursor );
+
+ // Insert the removed stuff into the new line
+ m_newline->goInside( cursor );
+ m_newline->insert( cursor, elementList, beforeCursor );
+ cursor->setPos( cursor->getMark() );
+ }
+ else {
+ m_newline->goInside( cursor );
+ }
+
+ // The command no longer owns the new line.
+ m_newline = 0;
+
+ // Tell that something changed
+ FormulaElement* formula = m_line->formula();
+ formula->changed();
+ testDirty();
+}
+
+
+void KFCNewLine::unexecute()
+{
+ FormulaCursor* cursor = getExecuteCursor();
+ MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
+ int linePos = parent->content.find( m_line );
+
+ // Now the command owns the new line again.
+ m_newline = parent->content.at( linePos+1 );
+
+ // Tell all cursors to leave this sequence
+ FormulaElement* formula = m_line->formula();
+ formula->elementRemoval( m_newline );
+
+ // If there are children to be moved.
+ if ( m_newline->countChildren() > 0 ) {
+
+ // Remove anything from the line to be deleted
+ m_newline->selectAllChildren( cursor );
+ QPtrList<BasicElement> elementList;
+ m_newline->remove( cursor, elementList, beforeCursor );
+
+ // Insert the removed stuff into the previous line
+ m_line->moveEnd( cursor );
+ m_line->insert( cursor, elementList, beforeCursor );
+ cursor->setPos( cursor->getMark() );
+ }
+ else {
+ m_line->moveEnd( cursor );
+ }
+ parent->content.take( linePos+1 );
+
+ // Tell that something changed
+ formula->changed();
+ testDirty();
+}
+
+
+MultilineSequenceElement::MultilineSequenceElement( BasicElement* parent )
+ : SequenceElement( parent )
+{
+ tabs.setAutoDelete( false );
+}
+
+
+BasicElement* MultilineSequenceElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ //LuPixelPoint myPos(parentOrigin.x() + getX(),
+ // parentOrigin.y() + getY());
+ BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
+
+ if (e == 0) {
+ // If the mouse was behind this line put the cursor to the last position.
+ if ( ( point.x() > getX()+getWidth() ) &&
+ ( point.y() >= getY() ) &&
+ ( point.y() < getY()+getHeight() ) ) {
+ cursor->setTo(this, countChildren());
+ handled = true;
+ return this;
+ }
+ }
+ return e;
+}
+
+
+void MultilineSequenceElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ tabs.clear();
+ inherited::calcSizes( context, tstyle, istyle, style );
+}
+
+
+void MultilineSequenceElement::registerTab( BasicElement* tab )
+{
+ tabs.append( tab );
+}
+
+
+KCommand* MultilineSequenceElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ return 0;
+ }
+
+ switch ( *request ) {
+ case req_remove: {
+ // Remove this line if its empty.
+ // Remove the formula if this line was the only one.
+ break;
+ }
+ case req_addNewline: {
+ FormulaCursor* cursor = container->activeCursor();
+ return new KFCNewLine( i18n( "Add Newline" ), container, this, cursor->getPos() );
+ }
+ case req_addTabMark: {
+ KFCReplace* command = new KFCReplace( i18n("Add Tabmark"), container );
+ SpaceElement* element = new SpaceElement( THIN, true );
+ command->addElement( element );
+ return command;
+ }
+ default:
+ break;
+ }
+ return inherited::buildCommand( container, request );
+}
+
+
+KCommand* MultilineSequenceElement::input( Container* container, QKeyEvent* event )
+{
+ int action = event->key();
+ //int state = event->state();
+ //MoveFlag flag = movementFlag(state);
+
+ switch ( action ) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return: {
+ Request newline( req_addNewline );
+ return buildCommand( container, &newline );
+ }
+ case Qt::Key_Tab: {
+ Request r( req_addTabMark );
+ return buildCommand( container, &r );
+ }
+ }
+ return inherited::input( container, event );
+}
+
+
+KCommand* MultilineSequenceElement::input( Container* container, QChar ch )
+{
+ int latin1 = ch.latin1();
+ switch (latin1) {
+ case '&': {
+ Request r( req_addTabMark );
+ return buildCommand( container, &r );
+ }
+ }
+ return inherited::input( container, ch );
+}
+
+
+void MultilineSequenceElement::moveTabTo( uint i, luPixel pos )
+{
+ BasicElement* marker = tab( i );
+ luPixel diff = pos - marker->getX();
+ marker->setWidth( marker->getWidth() + diff );
+
+ for ( int p = childPos( marker )+1; p < countChildren(); ++p ) {
+ BasicElement* child = getChild( p );
+ child->setX( child->getX() + diff );
+ }
+
+ setWidth( getWidth()+diff );
+}
+
+
+int MultilineSequenceElement::tabBefore( uint pos )
+{
+ if ( tabs.isEmpty() ) {
+ return -1;
+ }
+ uint tabNum = 0;
+ for ( uint i=0; i<pos; ++i ) {
+ BasicElement* child = getChild( i );
+ if ( tabs.at( tabNum ) == child ) {
+ if ( tabNum+1 == tabs.count() ) {
+ return tabNum;
+ }
+ ++tabNum;
+ }
+ }
+ return static_cast<int>( tabNum )-1;
+}
+
+
+int MultilineSequenceElement::tabPos( uint i )
+{
+ if ( i < tabs.count() ) {
+ return childPos( tabs.at( i ) );
+ }
+ return -1;
+}
+
+
+void MultilineSequenceElement::writeMathML( QDomDocument& doc,
+ QDomNode& parent, bool oasisFormat ) const
+{
+ // parent is required to be a <mtr> tag
+
+ QDomElement tmp = doc.createElement( "TMP" );
+
+ inherited::writeMathML( doc, tmp, oasisFormat );
+
+ /* Now we re-parse the Dom tree, because of the TabMarkers
+ * that have no direct representation in MathML but mark the
+ * end of a <mtd> tag.
+ */
+
+ QDomElement mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
+
+ // The mrow, if it exists.
+ QDomNode n = tmp.firstChild().firstChild();
+ while ( !n.isNull() ) {
+ // the illegal TabMarkers are children of the mrow, child of tmp.
+ if ( n.isElement() && n.toElement().tagName() == "TAB" ) {
+ parent.appendChild( mtd );
+ mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
+ }
+ else {
+ mtd.appendChild( n.cloneNode() ); // cloneNode needed?
+ }
+ n = n.nextSibling();
+ }
+
+ parent.appendChild( mtd );
+}
+
+
+MultilineElement::MultilineElement( BasicElement* parent )
+ : BasicElement( parent )
+{
+ content.setAutoDelete( true );
+ content.append( new MultilineSequenceElement( this ) );
+}
+
+MultilineElement::~MultilineElement()
+{
+}
+
+MultilineElement::MultilineElement( const MultilineElement& other )
+ : BasicElement( other )
+{
+ content.setAutoDelete( true );
+ uint count = other.content.count();
+ for (uint i = 0; i < count; i++) {
+ MultilineSequenceElement* line = content.at(i)->clone();
+ line->setParent( this );
+ content.append( line );
+ }
+}
+
+
+bool MultilineElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void MultilineElement::entered( SequenceElement* /*child*/ )
+{
+ formula()->tell( i18n( "Multi line element" ) );
+}
+
+
+/**
+ * Returns the element the point is in.
+ */
+BasicElement* MultilineElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
+ if ( e != 0 ) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+
+ uint count = content.count();
+ for ( uint i = 0; i < count; ++i ) {
+ MultilineSequenceElement* line = content.at(i);
+ e = line->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ }
+ return this;
+ }
+ return 0;
+}
+
+void MultilineElement::goInside( FormulaCursor* cursor )
+{
+ content.at( 0 )->goInside( cursor );
+}
+
+void MultilineElement::moveLeft( FormulaCursor* cursor, BasicElement* from )
+{
+ // If you want to select more than one line you'll have to
+ // select the whole element.
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ // Coming from the parent (sequence) we go to
+ // the very last position
+ if (from == getParent()) {
+ content.at( content.count()-1 )->moveLeft(cursor, this);
+ }
+ else {
+ // Coming from one of the lines we go to the previous line
+ // or to the parent if there is none.
+ int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
+ if ( pos > -1 ) {
+ if ( pos > 0 ) {
+ content.at( pos-1 )->moveLeft( cursor, this );
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+ else {
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
+ }
+ }
+ }
+}
+
+void MultilineElement::moveRight( FormulaCursor* cursor, BasicElement* from )
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ content.at( 0 )->moveRight(cursor, this);
+ }
+ else {
+ int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
+ if ( pos > -1 ) {
+ uint upos = pos;
+ if ( upos < content.count() ) {
+ if ( upos < content.count()-1 ) {
+ content.at( upos+1 )->moveRight( cursor, this );
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ return;
+ }
+ }
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
+ }
+ }
+}
+
+void MultilineElement::moveUp( FormulaCursor* cursor, BasicElement* from )
+{
+ // If you want to select more than one line you'll have to
+ // select the whole element.
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ // Coming from the parent (sequence) we go to
+ // the very last position
+ if (from == getParent()) {
+ content.at( content.count()-1 )->moveLeft(cursor, this);
+ }
+ else {
+ // Coming from one of the lines we go to the previous line
+ // or to the parent if there is none.
+ int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
+ if ( pos > -1 ) {
+ if ( pos > 0 ) {
+ //content.at( pos-1 )->moveLeft( cursor, this );
+ // This is rather hackish.
+ // But we know what elements we have here.
+ int cursorPos = cursor->getPos();
+ MultilineSequenceElement* current = content.at( pos );
+ MultilineSequenceElement* newLine = content.at( pos-1 );
+ int tabNum = current->tabBefore( cursorPos );
+ if ( tabNum > -1 ) {
+ int oldTabPos = current->tabPos( tabNum );
+ int newTabPos = newLine->tabPos( tabNum );
+ if ( newTabPos > -1 ) {
+ cursorPos += newTabPos-oldTabPos;
+ int nextNewTabPos = newLine->tabPos( tabNum+1 );
+ if ( nextNewTabPos > -1 ) {
+ cursorPos = QMIN( cursorPos, nextNewTabPos );
+ }
+ }
+ else {
+ cursorPos = newLine->countChildren();
+ }
+ }
+ else {
+ int nextNewTabPos = newLine->tabPos( 0 );
+ if ( nextNewTabPos > -1 ) {
+ cursorPos = QMIN( cursorPos, nextNewTabPos );
+ }
+ }
+ cursor->setTo( newLine,
+ QMIN( cursorPos,
+ newLine->countChildren() ) );
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+ else {
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
+ }
+ }
+ }
+}
+
+void MultilineElement::moveDown( FormulaCursor* cursor, BasicElement* from )
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ content.at( 0 )->moveRight(cursor, this);
+ }
+ else {
+ int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
+ if ( pos > -1 ) {
+ uint upos = pos;
+ if ( upos < content.count() ) {
+ if ( upos < content.count()-1 ) {
+ //content.at( upos+1 )->moveRight( cursor, this );
+ // This is rather hackish.
+ // But we know what elements we have here.
+ int cursorPos = cursor->getPos();
+ MultilineSequenceElement* current = content.at( upos );
+ MultilineSequenceElement* newLine = content.at( upos+1 );
+ int tabNum = current->tabBefore( cursorPos );
+ if ( tabNum > -1 ) {
+ int oldTabPos = current->tabPos( tabNum );
+ int newTabPos = newLine->tabPos( tabNum );
+ if ( newTabPos > -1 ) {
+ cursorPos += newTabPos-oldTabPos;
+ int nextNewTabPos = newLine->tabPos( tabNum+1 );
+ if ( nextNewTabPos > -1 ) {
+ cursorPos = QMIN( cursorPos, nextNewTabPos );
+ }
+ }
+ else {
+ cursorPos = newLine->countChildren();
+ }
+ }
+ else {
+ int nextNewTabPos = newLine->tabPos( 0 );
+ if ( nextNewTabPos > -1 ) {
+ cursorPos = QMIN( cursorPos, nextNewTabPos );
+ }
+ }
+ cursor->setTo( newLine,
+ QMIN( cursorPos,
+ newLine->countChildren() ) );
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ return;
+ }
+ }
+ kdDebug( DEBUGID ) << k_funcinfo << endl;
+ kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
+ }
+ }
+}
+
+
+void MultilineElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ QFont font = context.getDefaultFont();
+ font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
+ QFontMetrics fm( font );
+ luPixel leading = context.ptToLayoutUnitPt( fm.leading() );
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+
+ uint count = content.count();
+ luPixel height = -leading;
+ luPixel width = 0;
+ uint tabCount = 0;
+ for ( uint i = 0; i < count; ++i ) {
+ MultilineSequenceElement* line = content.at(i);
+ line->calcSizes( context, tstyle, istyle, style );
+ tabCount = QMAX( tabCount, line->tabCount() );
+
+ height += leading;
+ line->setX( 0 );
+ line->setY( height );
+ height += line->getHeight() + distY;
+ width = QMAX( line->getWidth(), width );
+ }
+
+ // calculate the tab positions
+ for ( uint t = 0; t < tabCount; ++t ) {
+ luPixel pos = 0;
+ for ( uint i = 0; i < count; ++i ) {
+ MultilineSequenceElement* line = content.at(i);
+ if ( t < line->tabCount() ) {
+ pos = QMAX( pos, line->tab( t )->getX() );
+ }
+ else {
+ pos = QMAX( pos, line->getWidth() );
+ }
+ }
+ for ( uint i = 0; i < count; ++i ) {
+ MultilineSequenceElement* line = content.at(i);
+ if ( t < line->tabCount() ) {
+ line->moveTabTo( t, pos );
+ width = QMAX( width, line->getWidth() );
+ }
+ }
+ }
+
+ setHeight( height );
+ setWidth( width );
+ if ( count == 1 ) {
+ setBaseline( content.at( 0 )->getBaseline() );
+ }
+ else {
+ // There's always a first line. No formulas without lines.
+ setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
+ }
+}
+
+void MultilineElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x() + getX(), parentOrigin.y() + getY() );
+ uint count = content.count();
+
+ if ( context.edit() ) {
+ uint tabCount = 0;
+ painter.setPen( context.getHelpColor() );
+ for ( uint i = 0; i < count; ++i ) {
+ MultilineSequenceElement* line = content.at(i);
+ if ( tabCount < line->tabCount() ) {
+ for ( uint t = tabCount; t < line->tabCount(); ++t ) {
+ BasicElement* marker = line->tab( t );
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
+ context.layoutUnitToPixelY( myPos.y() ),
+ context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
+ }
+ tabCount = line->tabCount();
+ }
+ }
+ }
+
+ for ( uint i = 0; i < count; ++i ) {
+ MultilineSequenceElement* line = content.at(i);
+ line->draw( painter, r, context, tstyle, istyle, style, myPos );
+ }
+}
+
+
+void MultilineElement::dispatchFontCommand( FontCommand* cmd )
+{
+ uint count = content.count();
+ for ( uint i = 0; i < count; ++i ) {
+ MultilineSequenceElement* line = content.at(i);
+ line->dispatchFontCommand( cmd );
+ }
+}
+
+void MultilineElement::insert( FormulaCursor* cursor,
+ QPtrList<BasicElement>& newChildren,
+ Direction direction )
+{
+ MultilineSequenceElement* e = static_cast<MultilineSequenceElement*>(newChildren.take(0));
+ e->setParent(this);
+ content.insert( cursor->getPos(), e );
+
+ if (direction == beforeCursor) {
+ e->moveLeft(cursor, this);
+ }
+ else {
+ e->moveRight(cursor, this);
+ }
+ cursor->setSelection(false);
+ formula()->changed();
+}
+
+void MultilineElement::remove( FormulaCursor* cursor,
+ QPtrList<BasicElement>& removedChildren,
+ Direction direction )
+{
+ if ( content.count() == 1 ) { //&& ( cursor->getPos() == 0 ) ) {
+ getParent()->selectChild(cursor, this);
+ getParent()->remove(cursor, removedChildren, direction);
+ }
+ else {
+ MultilineSequenceElement* e = content.take( cursor->getPos() );
+ removedChildren.append( e );
+ formula()->elementRemoval( e );
+ //cursor->setTo( this, denominatorPos );
+ formula()->changed();
+ }
+}
+
+void MultilineElement::normalize( FormulaCursor* cursor, Direction direction )
+{
+ int pos = cursor->getPos();
+ if ( ( cursor->getElement() == this ) &&
+ ( pos > -1 ) && ( static_cast<unsigned>( pos ) <= content.count() ) ) {
+ switch ( direction ) {
+ case beforeCursor:
+ if ( pos > 0 ) {
+ content.at( pos-1 )->moveLeft( cursor, this );
+ break;
+ }
+ // no break! intended!
+ case afterCursor:
+ if ( static_cast<unsigned>( pos ) < content.count() ) {
+ content.at( pos )->moveRight( cursor, this );
+ }
+ else {
+ content.at( pos-1 )->moveLeft( cursor, this );
+ }
+ break;
+ }
+ }
+ else {
+ inherited::normalize( cursor, direction );
+ }
+}
+
+SequenceElement* MultilineElement::getMainChild()
+{
+ return content.at( 0 );
+}
+
+void MultilineElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ int pos = content.find( dynamic_cast<MultilineSequenceElement*>( child ) );
+ if ( pos > -1 ) {
+ cursor->setTo( this, pos );
+ //content.at( pos )->moveRight( cursor, this );
+ }
+}
+
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void MultilineElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ uint lineCount = content.count();
+ element.setAttribute( "LINES", lineCount );
+
+ QDomDocument doc = element.ownerDocument();
+ for ( uint i = 0; i < lineCount; ++i ) {
+ QDomElement tmp = content.at( i )->getElementDom(doc);
+ element.appendChild(tmp);
+ }
+}
+
+void MultilineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
+{
+ QDomElement de = doc.createElement( oasisFormat ? "math:mtable" : "mtable" );
+ QDomElement row; QDomElement cell;
+
+ for ( QPtrListIterator < MultilineSequenceElement > it( content ); it.current(); ++it ) {
+ row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
+ de.appendChild( row );
+ //cell = doc.createElement( "mtd" );
+ //row.appendChild( cell );
+
+ //content.at( i )->writeMathML( doc, cell );
+ it.current()->writeMathML( doc, row, oasisFormat );
+ }
+
+ parent.appendChild( de );
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool MultilineElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ uint lineCount = 0;
+ QString lineCountStr = element.attribute("LINES");
+ if(!lineCountStr.isNull()) {
+ lineCount = lineCountStr.toInt();
+ }
+ if (lineCount == 0) {
+ kdWarning( DEBUGID ) << "lineCount <= 0 in MultilineElement." << endl;
+ return false;
+ }
+
+ content.clear();
+ for ( uint i = 0; i < lineCount; ++i ) {
+ MultilineSequenceElement* element = new MultilineSequenceElement(this);
+ content.append(element);
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool MultilineElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ uint lineCount = content.count();
+ uint i = 0;
+ while ( !node.isNull() && i < lineCount ) {
+ if ( node.isElement() ) {
+ SequenceElement* element = content.at( i );
+ QDomElement e = node.toElement();
+ if ( !element->buildFromDom( e ) ) {
+ return false;
+ }
+ ++i;
+ }
+ node = node.nextSibling();
+ }
+ return true;
+}
+
+QString MultilineElement::toLatex()
+{
+ uint lineCount = content.count();
+ QString muliline = "\\begin{split} ";
+ for ( uint i = 0; i < lineCount; ++i ) {
+ muliline += content.at( i )->toLatex();
+ muliline += " \\\\ ";
+ }
+ muliline += "\\end{split}";
+ return muliline;
+}
+
+// Does this make any sense at all?
+QString MultilineElement::formulaString()
+{
+ uint lineCount = content.count();
+ QString muliline = "";
+ for ( uint i = 0; i < lineCount; ++i ) {
+ muliline += content.at( i )->formulaString();
+ muliline += "\n";
+ }
+ //muliline += "";
+ return muliline;
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/matrixelement.h b/lib/kformula/matrixelement.h
new file mode 100644
index 00000000..5f7eec4d
--- /dev/null
+++ b/lib/kformula/matrixelement.h
@@ -0,0 +1,464 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
+ Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef MATRIXELEMENT_H
+#define MATRIXELEMENT_H
+
+#include <qptrlist.h>
+
+#include "basicelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+class MatrixSequenceElement;
+
+
+/**
+ * A matrix.
+ */
+class MatrixElement : public BasicElement {
+ friend class KFCRemoveColumn;
+ friend class KFCRemoveRow;
+ friend class MatrixSequenceElement;
+
+ enum VerticalAlign { NoAlign, TopAlign, BottomAlign, CenterAlign, BaselineAlign, AxisAlign };
+ enum LineType { NoLine, NoneLine, SolidLine, DashedLine };
+ enum SideType { NoSide, LeftSide, RightSide, LeftOverlapSide, RightOverlapSide };
+ MatrixElement& operator=( const MatrixElement& ) { return *this; }
+public:
+ MatrixElement(uint rows = 1, uint columns = 1, BasicElement* parent = 0);
+ ~MatrixElement();
+
+ MatrixElement( const MatrixElement& );
+
+ virtual MatrixElement* clone() {
+ return new MatrixElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ // drawing
+ //
+ // Drawing depends on a context which knows the required properties like
+ // fonts, spaces and such.
+ // It is essential to calculate elements size with the same context
+ // before you draw.
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ // navigation
+ //
+ // The elements are responsible to handle cursor movement themselves.
+ // To do this they need to know the direction the cursor moves and
+ // the element it comes from.
+ //
+ // The cursor might be in normal or in selection mode.
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor*, BasicElement*);
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor*, BasicElement*);
+
+ /**
+ * Sets the cursor inside this element to its start position.
+ * For most elements that is the main child.
+ */
+ virtual void goInside(FormulaCursor* cursor);
+
+ /**
+ * We define the Main Child of a matrix to be the first row/column.
+ **/
+ // If there is a main child we must provide the insert/remove semantics.
+ virtual SequenceElement* getMainChild();
+
+ /**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction.
+ */
+ //virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ */
+ //virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+ //virtual void normalize(FormulaCursor*, Direction);
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor*, BasicElement*);
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ //virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child) = 0;
+
+ /**
+ * Returns wether the element has no more useful
+ * children (except its main child) and should therefore
+ * be replaced by its main child's content.
+ */
+ //virtual bool isSenseless();
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+ uint getRows() const { return content.count(); }
+ uint getColumns() const { return content.getFirst()->count(); }
+
+ SequenceElement* elementAt(uint row, uint column);
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "MATRIX"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ virtual QString getElementName() const { return "mtable"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const;
+ virtual void writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const;
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ virtual bool readAttributesFromMathMLDom( const QDomElement& element );
+
+ /**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read. It is sometimes needed to read more than one node
+ * (e. g. for fence operators).
+ * Returns the number of nodes processed or -1 if it failed.
+ */
+ virtual int readContentFromMathMLDom(QDomNode& node);
+
+private:
+ void writeMathMLAttributes( QDomElement& element );
+
+ MatrixSequenceElement* getElement(uint row, uint column)
+ { return content.at(row)->at(column); }
+
+ const MatrixSequenceElement* getElement( uint row, uint column ) const;
+
+ /**
+ * Searches through the matrix for the element. Sets the
+ * row and column if found.
+ * Returns true if the element was found. false otherwise.
+ */
+ bool searchElement(BasicElement* element, uint& row, uint& column);
+
+ /**
+ * The elements we contain.
+ */
+ QPtrList< QPtrList< MatrixSequenceElement > > content;
+
+ /**
+ * MathML Attributes. See Section 3.5.1.2
+ */
+ int m_rowNumber;
+ VerticalAlign m_align;
+ QValueList< VerticalAlign > m_rowAlign;
+ QValueList< HorizontalAlign > m_columnAlign;
+ QValueList< bool > m_alignmentScope;
+ QValueList< SizeType > m_columnWidthType;
+ QValueList< double > m_columnWidth;
+ SizeType m_widthType;
+ double m_width;
+ QValueList< SizeType > m_rowSpacingType;
+ QValueList< double > m_rowSpacing;
+ QValueList< SizeType > m_columnSpacingType;
+ QValueList< double > m_columnSpacing;
+ QValueList< LineType > m_rowLines;
+ QValueList< LineType > m_columnLines;
+ LineType m_frame;
+ SizeType m_frameHSpacingType;
+ double m_frameHSpacing;
+ SizeType m_frameVSpacingType;
+ double m_frameVSpacing;
+ SideType m_side;
+ SizeType m_minLabelSpacingType;
+ double m_minLabelSpacing;
+ bool m_equalRows;
+ bool m_customEqualRows;
+ bool m_equalColumns;
+ bool m_customEqualColumns;
+ bool m_displayStyle;
+ bool m_customDisplayStyle;
+};
+
+
+
+class MultilineSequenceElement;
+
+
+/**
+ * Any number of lines.
+ */
+class MultilineElement : public BasicElement {
+ friend class KFCNewLine;
+
+ typedef BasicElement inherited;
+public:
+
+ /**
+ * The container this FormulaElement belongs to must not be 0,
+ * except you really know what you are doing.
+ */
+ MultilineElement( BasicElement* parent = 0 );
+ ~MultilineElement();
+
+ MultilineElement( const MultilineElement& );
+
+ virtual MultilineElement* clone() {
+ return new MultilineElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Returns the element the point is in.
+ */
+ BasicElement* goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ /**
+ * Sets the cursor inside this element to its start position.
+ * For most elements that is the main child.
+ */
+ virtual void goInside(FormulaCursor* cursor);
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft( FormulaCursor* cursor, BasicElement* from );
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight( FormulaCursor* cursor, BasicElement* from );
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp( FormulaCursor* cursor, BasicElement* from );
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown( FormulaCursor* cursor, BasicElement* from );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ virtual void normalize(FormulaCursor*, Direction);
+
+ virtual SequenceElement* getMainChild();
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor* cursor, BasicElement* child);
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "MULTILINE"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+
+private:
+
+ /**
+ * The list of sequences. Each one is a line.
+ */
+ QPtrList< MultilineSequenceElement > content;
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // MATRIXELEMENT_H
diff --git a/lib/kformula/numberelement.cc b/lib/kformula/numberelement.cc
new file mode 100644
index 00000000..41ddc179
--- /dev/null
+++ b/lib/kformula/numberelement.cc
@@ -0,0 +1,153 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <klocale.h>
+
+#include "numberelement.h"
+#include "kformuladefs.h"
+#include "textelement.h"
+#include "identifierelement.h"
+#include "operatorelement.h"
+#include "kformulacommand.h"
+#include "kformulacontainer.h"
+#include "formulaelement.h"
+#include "creationstrategy.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+NumberElement::NumberElement( BasicElement* parent ) : TokenElement( parent ) {}
+
+/*
+ * Token elements' content has to be of homogeneous type. Every token element
+ * must (TODO: check this) appear inside a non-token sequence, and thus, if
+ * the command asks for a different content, a new element has to be created in
+ * parent sequence.
+ */
+KCommand* NumberElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ formula()->tell( i18n( "write protection" ) );
+ return 0;
+ }
+
+ if ( *request == req_addNumber ) {
+ KFCReplace* command = new KFCReplace( i18n("Add Number"), container );
+ NumberRequest* nr = static_cast<NumberRequest*>( request );
+ TextElement* element = creationStrategy->createTextElement( nr->ch(), false );
+ command->addElement( element );
+ return command;
+ }
+
+ if ( countChildren() == 0 || cursor->getPos() == countChildren() ) {
+ // We are in the last position, so it's easy, call the parent to
+ // create a new child
+ SequenceElement* parent = static_cast<SequenceElement*>( getParent() );
+ if ( parent ) {
+ uint pos = parent->childPos( this );
+ cursor->setTo( parent, pos + 1);
+ return parent->buildCommand( container, request );
+ }
+ }
+ if ( cursor->getPos() == 0 ) {
+ SequenceElement* parent = static_cast<SequenceElement*>( getParent() );
+ if ( parent ) {
+ uint pos = parent->childPos( this );
+ cursor->setTo( parent, pos );
+ return parent->buildCommand( container, request );
+ }
+ }
+
+ // We are in the middle of a token, so:
+ // a) Cut from mark to the end
+ // b) Create a new token and add an element from key pressed
+ // c) Create a new token and add elements cut previously
+ // d) Move cursor to parent so that it command execution works fine
+
+ switch( *request ) {
+ case req_addTextChar: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Text"), container );
+ TextCharRequest* tr = static_cast<TextCharRequest*>( request );
+ IdentifierElement* id = creationStrategy->createIdentifierElement();
+ TextElement* text = creationStrategy->createTextElement( tr->ch() );
+ command->addCursor( cursor );
+ command->addToken( id );
+ command->addContent( id, text );
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+
+ case req_addText: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Text"), container );
+ TextRequest* tr = static_cast<TextRequest*>( request );
+ IdentifierElement* id = creationStrategy->createIdentifierElement();
+ command->addCursor( cursor );
+ command->addToken( id );
+ for ( uint i = 0; i < tr->text().length(); i++ ) {
+ TextElement* text = creationStrategy->createTextElement( tr->text()[i] );
+ command->addContent( id, text );
+ }
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+
+ case req_addOperator: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Operator"), container );
+ OperatorRequest* opr = static_cast<OperatorRequest*>( request );
+ OperatorElement* op = creationStrategy->createOperatorElement();
+ TextElement* text = creationStrategy->createTextElement( opr->ch() );
+ command->addCursor( cursor );
+ command->addToken( op );
+ command->addContent( op, text );
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+ case req_addEmptyBox:
+ case req_addNameSequence:
+ case req_addBracket:
+ case req_addSpace:
+ case req_addFraction:
+ case req_addRoot:
+ case req_addSymbol:
+ case req_addOneByTwoMatrix:
+ case req_addMatrix: {
+ SequenceElement* parent = static_cast<SequenceElement*>( getParent() );
+ if ( parent ) {
+ uint pos = parent->childPos( this );
+ cursor->setTo( parent, pos + 1);
+ return parent->buildCommand( container, request );
+ }
+ }
+ default:
+ return SequenceElement::buildCommand( container, request );
+ }
+ return 0;
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/numberelement.h b/lib/kformula/numberelement.h
new file mode 100644
index 00000000..21342fe2
--- /dev/null
+++ b/lib/kformula/numberelement.h
@@ -0,0 +1,47 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef NUMBERELEMENT_H
+#define NUMBERELEMENT_H
+
+#include "tokenelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class NumberElement : public TokenElement {
+ typedef TokenElement inherited;
+public:
+ NumberElement( BasicElement* parent = 0 );
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+
+ virtual QString getElementName() const { return "mn"; }
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // NUMBERELEMENT_H
diff --git a/lib/kformula/oasiscreationstrategy.cc b/lib/kformula/oasiscreationstrategy.cc
new file mode 100644
index 00000000..637bd695
--- /dev/null
+++ b/lib/kformula/oasiscreationstrategy.cc
@@ -0,0 +1,210 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qdom.h>
+
+#include "bracketelement.h"
+#include "elementtype.h"
+#include "fractionelement.h"
+#include "indexelement.h"
+#include "matrixelement.h"
+#include "rootelement.h"
+#include "sequenceelement.h"
+#include "spaceelement.h"
+#include "symbolelement.h"
+#include "textelement.h"
+#include "glyphelement.h"
+#include "styleelement.h"
+#include "numberelement.h"
+#include "identifierelement.h"
+#include "operatorelement.h"
+#include "stringelement.h"
+#include "paddedelement.h"
+#include "errorelement.h"
+#include "phantomelement.h"
+#include "actionelement.h"
+#include "encloseelement.h"
+
+#include "oasiscreationstrategy.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+BasicElement* OasisCreationStrategy::createElement( QString type, const QDomElement& element )
+{
+
+ // TODO
+ // mlabeledtr
+ // maligngroup
+ // malignmark
+ // Content elements
+ // mtr and mtd are currently managed inside MatrixElement
+ kdDebug( DEBUGID ) << type << endl;
+
+ // Token Elements ( Section 3.1.6.1 )
+ if ( type == "mi" ) return new IdentifierElement();
+ else if ( type == "mo" ) return createOperatorElement( element );
+ else if ( type == "mn" ) return new NumberElement();
+ else if ( type == "mtext" ) return new TokenElement();
+ else if ( type == "ms" ) return new StringElement();
+ else if ( type == "mspace" ) return new SpaceElement();
+ else if ( type == "mglyph" ) return new GlyphElement();
+
+ // General Layout Schemata ( Section 3.1.6.2 )
+ else if ( type == "mrow" ) return new SequenceElement();
+ else if ( type == "mfrac" ) return new FractionElement();
+ else if ( type == "msqrt"
+ || type == "mroot" ) return new RootElement();
+ else if ( type == "mstyle" ) return new StyleElement();
+ else if ( type == "merror" ) return new ErrorElement();
+ else if ( type == "mpadded" ) return new PaddedElement();
+ else if ( type == "mphantom" ) return new PhantomElement();
+ else if ( type == "mfenced" ) return new BracketElement();
+ else if ( type == "menclose" ) return new EncloseElement();
+
+ // Script and Limit Schemata ( Section 3.1.6.3 )
+ else if ( type == "msub"
+ || type == "msup"
+ || type == "msubsup"
+ || type == "munder"
+ || type == "mover"
+ || type == "munderover"
+ || type == "mmultiscripts" ) return new IndexElement();
+
+ // Tables and Matrices ( Section 3.1.6.4 )
+ else if ( type == "mtable" ) return new MatrixElement();
+
+ // Enlivening Expressions ( Section 3.1.6.5 )
+ else if ( type == "maction" ) return new ActionElement();
+ return 0;
+}
+
+
+TextElement* OasisCreationStrategy::createTextElement( const QChar& ch, bool symbol )
+{
+ return new TextElement( ch, symbol );
+}
+
+EmptyElement* OasisCreationStrategy::createEmptyElement()
+{
+ return new EmptyElement;
+}
+
+NameSequence* OasisCreationStrategy::createNameSequence()
+{
+ return new NameSequence;
+}
+
+BracketElement* OasisCreationStrategy::createBracketElement( SymbolType lhs, SymbolType rhs )
+{
+ return new BracketElement( lhs, rhs );
+}
+
+OverlineElement* OasisCreationStrategy::createOverlineElement()
+{
+ return new OverlineElement;
+}
+
+UnderlineElement* OasisCreationStrategy::createUnderlineElement()
+{
+ return new UnderlineElement;
+}
+
+MultilineElement* OasisCreationStrategy::createMultilineElement()
+{
+ return new MultilineElement;
+}
+
+SpaceElement* OasisCreationStrategy::createSpaceElement( SpaceWidth width )
+{
+ return new SpaceElement( width );
+}
+
+FractionElement* OasisCreationStrategy::createFractionElement()
+{
+ return new FractionElement;
+}
+
+RootElement* OasisCreationStrategy::createRootElement()
+{
+ return new RootElement;
+}
+
+SymbolElement* OasisCreationStrategy::createSymbolElement( SymbolType type )
+{
+ return new SymbolElement( type );
+}
+
+MatrixElement* OasisCreationStrategy::createMatrixElement( uint rows, uint columns )
+{
+ return new MatrixElement( rows, columns );
+}
+
+IndexElement* OasisCreationStrategy::createIndexElement()
+{
+ return new IndexElement;
+}
+
+BasicElement* OasisCreationStrategy::createOperatorElement( const QDomElement& element )
+{
+ QDomNode n = element.firstChild();
+ if ( n.isNull() )
+ return 0;
+ if ( n.isEntityReference() ) {
+ QString name = n.nodeName();
+ if ( name == "CloseCurlyDoubleQuote"
+ || name == "CloseCurlyQuote"
+ || name == "LeftAngleBracket"
+ || name == "LeftCeiling"
+ || name == "LeftDoubleBracket"
+ || name == "LeftFloor"
+ || name == "OpenCurlyDoubleQuote"
+ || name == "OpenCurlyQuote"
+ || name == "RightAngleBracket"
+ || name == "RightCeiling"
+ || name == "RightDoubleBracket"
+ || name == "RightFloor" ) {
+ return new BracketElement();
+ }
+ return new OperatorElement();
+ }
+ if ( n.isText() ) {
+ QString text = n.toText().data();
+ if ( text.length() == 1 && QString("()[]{}").contains(text[0]) ) {
+ return new BracketElement();
+ }
+ }
+ return new OperatorElement();
+}
+
+IdentifierElement* OasisCreationStrategy::createIdentifierElement()
+{
+ return new IdentifierElement();
+}
+
+OperatorElement* OasisCreationStrategy::createOperatorElement()
+{
+ return new OperatorElement();
+}
+
+NumberElement* OasisCreationStrategy::createNumberElement()
+{
+ return new NumberElement();
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/oasiscreationstrategy.h b/lib/kformula/oasiscreationstrategy.h
new file mode 100644
index 00000000..276749f0
--- /dev/null
+++ b/lib/kformula/oasiscreationstrategy.h
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+
+#ifndef OASISCREATIONSTRATEGY_H
+#define OASISCREATIONSTRATEGY_H
+
+
+#include <qstring.h>
+
+#include "kformuladefs.h"
+#include "creationstrategy.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class BracketElement;
+class EmptyElement;
+class FractionElement;
+class IndexElement;
+class MatrixElement;
+class MultilineElement;
+class NameSequence;
+class OverlineElement;
+class RootElement;
+class SpaceElement;
+class SymbolElement;
+class TextElement;
+class UnderlineElement;
+
+/**
+ * The strategy to be used for OASIS OpenDocument / MathML.
+ */
+class OasisCreationStrategy : public ElementCreationStrategy {
+public:
+ virtual BasicElement* createElement( QString type, const QDomElement& element );
+
+ virtual TextElement* createTextElement( const QChar& ch, bool symbol=false );
+ virtual EmptyElement* createEmptyElement();
+ virtual NameSequence* createNameSequence();
+ virtual BracketElement* createBracketElement( SymbolType lhs, SymbolType rhs );
+ virtual OverlineElement* createOverlineElement();
+ virtual UnderlineElement* createUnderlineElement();
+ virtual MultilineElement* createMultilineElement();
+ virtual SpaceElement* createSpaceElement( SpaceWidth width );
+ virtual FractionElement* createFractionElement();
+ virtual RootElement* createRootElement();
+ virtual SymbolElement* createSymbolElement( SymbolType type );
+ virtual MatrixElement* createMatrixElement( uint rows, uint columns );
+ virtual IndexElement* createIndexElement();
+ virtual IdentifierElement* createIdentifierElement();
+ virtual OperatorElement* createOperatorElement();
+ virtual NumberElement* createNumberElement();
+ virtual QString type() const { return "Oasis"; }
+
+ BasicElement* createOperatorElement( const QDomElement& element );
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // OASISCREATIONSTRATEGY_H
diff --git a/lib/kformula/oldformula b/lib/kformula/oldformula
new file mode 100644
index 00000000..13415c4a
--- /dev/null
+++ b/lib/kformula/oldformula
Binary files differ
diff --git a/lib/kformula/operatordictionary.cc b/lib/kformula/operatordictionary.cc
new file mode 100644
index 00000000..787a58b5
--- /dev/null
+++ b/lib/kformula/operatordictionary.cc
@@ -0,0 +1,4266 @@
+//
+// Created: Sat Aug 26 20:12:37 2006
+// by: oper-dict.py
+// from: appendixf.html
+//
+// WARNING! All changes made in this file will be lost!
+
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "operatordictionary.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+const OperatorDictionary operators[] = {
+ { {"!!", "postfix"},
+ "verythinmathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"!", "postfix"},
+ "verythinmathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"!", "prefix"},
+ "0em" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"!=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"&", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"&", "postfix"},
+ "thickmathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"&", "prefix"},
+ "0em" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"&&", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"'", "postfix"},
+ "verythinmathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"(", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"(", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {")", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"*", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"**", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"*=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"+", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"+", "prefix"},
+ "0em" ,
+ "veryverythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"++", "postfix"},
+ "verythinmathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"++", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"+=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {",", "infix"},
+ "0em" ,
+ "verythickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ true ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"-", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"-", "prefix"},
+ "0em" ,
+ "veryverythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"--", "postfix"},
+ "verythinmathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"--", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"-=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"->", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {".", "infix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"..", "postfix"},
+ "mediummathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"...", "postfix"},
+ "mediummathspace" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"/", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"//", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"/=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {":", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {":=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {";", "infix"},
+ "0em" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ true ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {";", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ true ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"<", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"<=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"<>", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"==", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {">", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {">=", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"?", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"@", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"[", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"]", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"^", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"^", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"_", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"`", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"lim", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ true ,
+ false } ,
+
+ { {"max", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ true ,
+ false } ,
+
+ { {"min", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ true ,
+ false } ,
+
+ { {"{", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"|", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"|", "infix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "0" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"||", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"}", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"~", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"¨", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"¯", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"±", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"±", "prefix"},
+ "0em" ,
+ "veryverythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"´", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"·", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"¸", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"ˇ", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"˘", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"˙", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"˜", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"˝", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"̑", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"̲", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"‘", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"’", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"“", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"”", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⁡", "infix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⁢", "infix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⁣", "infix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ true ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⃛", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"ⅅ", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"ⅆ", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"←", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"←", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"←", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"↑", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↑", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"→", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"→", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"→", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"↓", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↓", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↔", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↔", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"↕", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↖", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↗", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↘", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↙", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↤", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↥", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↦", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↧", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↼", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↼", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"↽", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↾", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"↿", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇀", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇀", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"⇁", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇂", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇃", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇄", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇅", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇆", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇋", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇌", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇐", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇑", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇒", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇒", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇓", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇔", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇕", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇤", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇥", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⇵", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∀", "prefix"},
+ "0em" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∂", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∃", "prefix"},
+ "0em" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∄", "prefix"},
+ "0em" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∇", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∈", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∉", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∋", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∋", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∌", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∏", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"∐", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∐", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"∑", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"∓", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∓", "prefix"},
+ "0em" ,
+ "veryverythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∖", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∘", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"√", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∝", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∣", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∤", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∥", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∦", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∫", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false ,
+ false } ,
+
+ { {"∮", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false ,
+ false } ,
+
+ { {"∯", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false ,
+ false } ,
+
+ { {"∲", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false ,
+ false } ,
+
+ { {"∳", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false ,
+ false } ,
+
+ { {"∴", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∵", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∷", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∷", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"∼", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≀", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≁", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≂", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≃", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≄", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≅", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≇", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≈", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≉", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≍", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≎", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≏", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≐", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≔", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≠", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≡", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≢", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≤", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≥", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≦", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≧", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≪", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≫", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≭", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≮", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≯", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≰", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≱", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≲", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≳", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≴", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≵", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≶", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≷", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≸", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≹", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≺", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≻", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≼", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≽", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≾", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"≿", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊀", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊁", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊃", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊆", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊇", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊈", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊉", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊎", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊎", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⊏", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊐", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊑", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊒", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊓", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊔", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊕", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊕", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⊖", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊖", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⊗", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊗", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⊙", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊙", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⊢", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊣", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊤", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊥", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊨", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊲", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊳", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊴", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⊵", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋀", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋀", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⋁", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋁", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⋂", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋂", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⋃", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋃", "prefix"},
+ "0em" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ true ,
+ true ,
+ false } ,
+
+ { {"⋄", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋆", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋐", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋒", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋓", "infix"},
+ "thinmathspace" ,
+ "thinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋚", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋛", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋠", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋡", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋢", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋣", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋪", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋫", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋬", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⋭", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⌈", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⌉", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⌊", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⌋", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"〈", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"〉", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⎴", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"⎵", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"─", "infix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "0" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"□", "prefix"},
+ "0em" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"❘", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⟵", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⟶", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⟷", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⟸", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⟹", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⟺", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⤒", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⤓", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥎", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥎", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"⥏", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥐", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥑", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥒", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥓", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥔", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥕", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥖", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥗", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥘", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥙", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥚", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥛", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥜", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥝", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥞", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥟", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥠", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥡", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥮", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥯", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⥰", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⧏", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⧐", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⨯", "infix"},
+ "verythinmathspace" ,
+ "verythinmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⩓", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⩔", "infix"},
+ "mediummathspace" ,
+ "mediummathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⩵", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⩽", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⩾", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⪡", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⪢", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⪯", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⪰", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⫤", "infix"},
+ "thickmathspace" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"⫬", "prefix"},
+ "0em" ,
+ "thickmathspace" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ false ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"〚", "prefix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"〛", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ true ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ false } ,
+
+ { {"︵", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"︶", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"︷", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true } ,
+
+ { {"︸", "postfix"},
+ "0em" ,
+ "0em" ,
+ "infinity" ,
+ "1" ,
+ false ,
+ false ,
+ true ,
+ true ,
+ false ,
+ false ,
+ true }
+};
+
+// Needed since sizeof is a macro and we cannot be used until size is known
+int OperatorDictionary::size()
+{
+ return sizeof( operators ) / sizeof( OperatorDictionary );
+}
+
+KFORMULA_NAMESPACE_END
+
diff --git a/lib/kformula/operatordictionary.h b/lib/kformula/operatordictionary.h
new file mode 100644
index 00000000..d6a39669
--- /dev/null
+++ b/lib/kformula/operatordictionary.h
@@ -0,0 +1,75 @@
+//
+// Created: Sat Aug 26 20:12:37 2006
+// by: oper-dict.py
+// from: appendixf.html
+//
+// WARNING! All changes made in this file will be lost!
+
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+
+#ifndef OPERATORDICTIONARY_H
+#define OPERATORDICTIONARY_H
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+struct DictionaryKey
+{
+ int operator==( const DictionaryKey& right ) const {
+ if ( qstrcmp( name, right.name ) || qstrcmp( form, right.form ) ) {
+ return false;
+ }
+ return true;
+ }
+ const char* name;
+ const char* form;
+};
+
+struct OperatorDictionary {
+ static int size();
+ int operator<( const DictionaryKey& right ) const {
+ int equal = qstrcmp( key.name, right.name );
+ if ( equal != 0 ) {
+ return equal < 0;
+ }
+ return qstrcmp( key.form, right.form ) < 0;
+ }
+ const DictionaryKey key;
+ const char* lspace;
+ const char* rspace;
+ const char* maxsize;
+ const char* minsize;
+ bool fence;
+ bool separator;
+ bool stretchy;
+ bool symmetric;
+ bool largeop;
+ bool movablelimits;
+ bool accent;
+};
+
+extern const OperatorDictionary operators[];
+
+KFORMULA_NAMESPACE_END
+
+#endif // OPERATORDICTIONARY_H
+
diff --git a/lib/kformula/operatorelement.cc b/lib/kformula/operatorelement.cc
new file mode 100644
index 00000000..534c093e
--- /dev/null
+++ b/lib/kformula/operatorelement.cc
@@ -0,0 +1,547 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <algorithm>
+
+#include <qpainter.h>
+
+#include <klocale.h>
+
+#include "elementtype.h"
+#include "sequenceelement.h"
+#include "textelement.h"
+#include "fontstyle.h"
+#include "operatordictionary.h"
+#include "operatorelement.h"
+#include "identifierelement.h"
+#include "numberelement.h"
+#include "kformulacommand.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "formulaelement.h"
+#include "creationstrategy.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+OperatorElement::OperatorElement( BasicElement* parent ) : TokenElement( parent ),
+ m_form( NoForm ),
+ m_lspaceType( ThickMathSpace ),
+ m_rspaceType( ThickMathSpace ),
+ m_maxSizeType( InfinitySize ),
+ m_minSizeType( RelativeSize ),
+ m_minSize( 1 ),
+ m_fence( false ),
+ m_separator( false ),
+ m_stretchy( false ),
+ m_symmetric( true ),
+ m_largeOp( false ),
+ m_movableLimits( false ),
+ m_accent( false ),
+ m_customForm( false ),
+ m_customFence( false ),
+ m_customSeparator( false ),
+ m_customLSpace( false ),
+ m_customRSpace( false ),
+ m_customStretchy( false ),
+ m_customSymmetric( false ),
+ m_customMaxSize( false ),
+ m_customMinSize( false ),
+ m_customLargeOp( false ),
+ m_customMovableLimits( false ),
+ m_customAccent( false )
+{
+}
+
+void OperatorElement::setForm( FormType type )
+{
+ if ( ! m_customForm ) { // Set by an attribute has higher priority
+ m_form = type;
+ }
+
+ if ( ! isTextOnly() ) { // Only text content can be dictionary keys
+ return;
+ }
+ QString text;
+ for ( uint i = 0; i < countChildren(); i++ ) {
+ text.append( getChild( i )->getCharacter() );
+ }
+ QString form;
+ switch ( m_form ) {
+ case PrefixForm:
+ form = "prefix";
+ break;
+ case InfixForm:
+ form = "infix";
+ break;
+ case PostfixForm:
+ form = "postfix";
+ break;
+ default:
+ // Should not happen
+ kdWarning( DEBUGID ) << "Invalid `form' attribute value\n";
+ return;
+ }
+ DictionaryKey key = { text.utf8(), form.ascii() };
+ const OperatorDictionary* begin = operators;
+ const OperatorDictionary* end = operators + OperatorDictionary::size();
+ const OperatorDictionary* pos = std::lower_bound( begin, end, key );
+ if ( pos != end && pos->key == key ) { // Entry found !
+ if ( ! m_customFence ) {
+ m_fence = pos->fence;
+ }
+ if ( ! m_customSeparator ) {
+ m_separator = pos->separator;
+ }
+ if ( ! m_customLSpace ) {
+ m_lspace = getSize( pos->lspace, &m_lspaceType );
+ if ( m_lspaceType == NoSize ) {
+ m_lspaceType = getSpace( pos->lspace );
+ }
+ }
+ if ( ! m_customRSpace ) {
+ m_rspace = getSize( pos->rspace, &m_rspaceType );
+ if ( m_rspaceType == NoSize ) {
+ m_rspaceType = getSpace( pos->rspace );
+ }
+ }
+ if ( ! m_customStretchy ) {
+ m_stretchy = pos->stretchy;
+ }
+ if ( ! m_customSymmetric ) {
+ m_symmetric = pos->symmetric;
+ }
+ if ( ! m_customMaxSize ) {
+ if ( qstrcmp( pos->maxsize, "infinity" ) == 0 ) {
+ m_maxSizeType = InfinitySize;
+ }
+ else {
+ m_maxSize = getSize( pos->maxsize, &m_maxSizeType );
+ if ( m_maxSizeType == NoSize ) {
+ m_maxSizeType = getSpace( pos->maxsize );
+ }
+ }
+ }
+ if ( ! m_customMinSize ) {
+ m_minSize = getSize( pos->minsize, &m_minSizeType );
+ if ( m_minSizeType == NoSize ) {
+ m_minSizeType = getSpace( pos->minsize );
+ }
+ }
+ if ( ! m_customLargeOp ) {
+ m_largeOp = pos->largeop;
+ }
+ if ( ! m_customMovableLimits ) {
+ m_movableLimits = pos->movablelimits;
+ }
+ if ( ! m_customAccent ) {
+ m_accent = pos->accent;
+ }
+ }
+}
+
+/*
+ * Token elements' content has to be of homogeneous type. Every token element
+ * must (TODO: check this) appear inside a non-token sequence, and thus, if
+ * the command asks for a different content, a new element has to be created in
+ * parent sequence.
+ */
+KCommand* OperatorElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ formula()->tell( i18n( "write protection" ) );
+ return 0;
+ }
+
+ if ( *request == req_addOperator ) {
+ KFCReplace* command = new KFCReplace( i18n("Add Operator"), container );
+ OperatorRequest* opr = static_cast<OperatorRequest*>( request );
+ TextElement* element = creationStrategy->createTextElement( opr->ch(), true );
+ command->addElement( element );
+ return command;
+ }
+
+ if ( countChildren() == 0 || cursor->getPos() == countChildren() ) {
+ // We are in the last position, so it's easy, call the parent to
+ // create a new child
+ SequenceElement* parent = static_cast<SequenceElement*>( getParent() );
+ if ( parent ) {
+ uint pos = parent->childPos( this );
+ cursor->setTo( parent, pos + 1);
+ return parent->buildCommand( container, request );
+ }
+ }
+ if ( cursor->getPos() == 0 ) {
+ SequenceElement* parent = static_cast<SequenceElement*>( getParent() );
+ if ( parent ) {
+ uint pos = parent->childPos( this );
+ cursor->setTo( parent, pos );
+ return parent->buildCommand( container, request );
+ }
+ }
+
+ // We are in the middle of a token, so:
+ // a) Cut from mark to the end
+ // b) Create a new token and add an element from key pressed
+ // c) Create a new token and add elements cut previously
+ // d) Move cursor to parent so that it command execution works fine
+
+ switch( *request ) {
+ case req_addTextChar: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Text"), container );
+ TextCharRequest* tr = static_cast<TextCharRequest*>( request );
+ IdentifierElement* id = creationStrategy->createIdentifierElement();
+ TextElement* text = creationStrategy->createTextElement( tr->ch() );
+ command->addCursor( cursor );
+ command->addToken( id );
+ command->addContent( id, text );
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+
+ case req_addText: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Text"), container );
+ TextRequest* tr = static_cast<TextRequest*>( request );
+ IdentifierElement* id = creationStrategy->createIdentifierElement();
+ command->addCursor( cursor );
+ command->addToken( id );
+ for ( uint i = 0; i < tr->text().length(); i++ ) {
+ TextElement* text = creationStrategy->createTextElement( tr->text()[i] );
+ command->addContent( id, text );
+ }
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+
+ case req_addNumber: {
+ KFCSplitToken* command = new KFCSplitToken( i18n("Add Number"), container );
+ NumberRequest* nr = static_cast<NumberRequest*>( request );
+ NumberElement* num = creationStrategy->createNumberElement();
+ TextElement* text = creationStrategy->createTextElement( nr->ch() );
+ command->addCursor( cursor );
+ command->addToken( num );
+ command->addContent( num, text );
+ SequenceElement* parent = static_cast< SequenceElement* >( getParent() );
+ if ( parent ) {
+ cursor->setTo( parent, parent->childPos( this ) + 1 );
+ }
+ return command;
+ }
+ case req_addEmptyBox:
+ case req_addNameSequence:
+ case req_addBracket:
+ case req_addSpace:
+ case req_addFraction:
+ case req_addRoot:
+ case req_addSymbol:
+ case req_addOneByTwoMatrix:
+ case req_addMatrix: {
+ uint pos = static_cast<SequenceElement*>(getParent())->childPos( this );
+ cursor->setTo( getParent(), pos + 1);
+ return getParent()->buildCommand( container, request );
+ }
+ default:
+ return SequenceElement::buildCommand( container, request );
+ }
+ return 0;
+}
+
+
+bool OperatorElement::readAttributesFromMathMLDom( const QDomElement &element )
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ QString formStr = element.attribute( "form" ).stripWhiteSpace().lower();
+ if ( ! formStr.isNull() ) {
+ m_customForm = true;
+ if ( formStr == "prefix" ) {
+ m_form = PrefixForm;
+ }
+ else if ( formStr == "infix" ) {
+ m_form = InfixForm;
+ }
+ else if ( formStr == "postfix" ) {
+ m_form = PostfixForm;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `form': " << formStr << endl;
+ m_customForm = false;
+ }
+ }
+ QString fenceStr = element.attribute( "fence" ).stripWhiteSpace().lower();
+ if ( ! fenceStr.isNull() ) {
+ m_customFence = true;
+ if ( fenceStr == "true" ) {
+ m_fence = true;
+ }
+ else if ( fenceStr == "false" ) {
+ m_fence = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `fence': " << fenceStr << endl;
+ m_customFence = false;
+ }
+ }
+ QString separatorStr = element.attribute( "separator" ).stripWhiteSpace().lower();
+ if ( ! separatorStr.isNull() ) {
+ m_customSeparator = true;
+ if ( separatorStr == "true" ) {
+ m_separator = true;
+ }
+ else if ( separatorStr == "false" ) {
+ m_separator = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `separator': " << separatorStr << endl;
+ m_customSeparator = false;
+ }
+ }
+ QString lspaceStr = element.attribute( "lspace" ).stripWhiteSpace().lower();
+ if ( ! lspaceStr.isNull() ) {
+ m_customLSpace = true;
+ m_lspace = getSize( lspaceStr, &m_lspaceType );
+ if ( m_lspaceType == NoSize ) {
+ m_lspaceType = getSpace( lspaceStr );
+ }
+ }
+ QString rspaceStr = element.attribute( "rspace" ).stripWhiteSpace().lower();
+ if ( ! rspaceStr.isNull() ) {
+ m_customRSpace = true;
+ m_rspace = getSize( rspaceStr, &m_rspaceType );
+ if ( m_rspaceType == NoSize ) {
+ m_rspaceType = getSpace( rspaceStr );
+ }
+ }
+ QString stretchyStr = element.attribute( "stretchy" ).stripWhiteSpace().lower();
+ if ( ! stretchyStr.isNull() ) {
+ m_customStretchy = true;
+ if ( stretchyStr == "true" ) {
+ m_stretchy = true;
+ }
+ else if ( stretchyStr == "false" ) {
+ m_stretchy = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `stretchy': " << stretchyStr << endl;
+ m_customStretchy = false;
+ }
+ }
+ QString symmetricStr = element.attribute( "symmetric" ).stripWhiteSpace().lower();
+ if ( ! symmetricStr.isNull() ) {
+ m_customSymmetric = true;
+ if ( symmetricStr == "true" ) {
+ m_symmetric = true;
+ }
+ else if ( symmetricStr == "false" ) {
+ m_symmetric = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `symmetric': " << symmetricStr << endl;
+ m_customSymmetric = false;
+ }
+ }
+ QString maxsizeStr = element.attribute( "maxsize" ).stripWhiteSpace().lower();
+ if ( ! maxsizeStr.isNull() ) {
+ m_customMaxSize = true;
+ if ( maxsizeStr == "infinity" ) {
+ m_maxSizeType = InfinitySize;
+ }
+ else {
+ m_maxSize = getSize( maxsizeStr, &m_maxSizeType );
+ if ( m_maxSizeType == NoSize ) {
+ m_maxSizeType = getSpace( maxsizeStr );
+ }
+ }
+ }
+ QString minsizeStr = element.attribute( "minsize" ).stripWhiteSpace().lower();
+ if ( ! minsizeStr.isNull() ) {
+ m_customMinSize = true;
+ m_minSize = getSize( minsizeStr, &m_minSizeType );
+ if ( m_minSizeType == NoSize ) {
+ m_minSizeType = getSpace( minsizeStr );
+ }
+ }
+ QString largeopStr = element.attribute( "largeop" ).stripWhiteSpace().lower();
+ if ( ! largeopStr.isNull() ) {
+ m_customLargeOp = true;
+ if ( largeopStr == "true" ) {
+ m_largeOp = true;
+ }
+ else if ( largeopStr == "false" ) {
+ m_largeOp = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `largeop': " << largeopStr << endl;
+ m_customLargeOp = false;
+ }
+ }
+ QString movablelimitsStr = element.attribute( "movablelimits" ).stripWhiteSpace().lower();
+ if ( ! movablelimitsStr.isNull() ) {
+ m_customMovableLimits = true;
+ if ( movablelimitsStr == "true" ) {
+ m_movableLimits = true;
+ }
+ else if ( movablelimitsStr == "false" ) {
+ m_movableLimits = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `movablelimits': " << movablelimitsStr << endl;
+ m_customMovableLimits = false;
+ }
+ }
+ QString accentStr = element.attribute( "accent" ).stripWhiteSpace().lower();
+ if ( ! accentStr.isNull() ) {
+ m_customAccent = true;
+ if ( accentStr == "true" ) {
+ m_accent = true;
+ }
+ else if ( accentStr == "false" ) {
+ m_accent = false;
+ }
+ else {
+ kdWarning( DEBUGID ) << "Invalid value for attribute `accent': " << accentStr << endl;
+ m_customAccent = false;
+ }
+ }
+ return true;
+}
+
+void OperatorElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ if ( m_customForm ) {
+ switch ( m_form ) {
+ case PrefixForm:
+ element.setAttribute( "form", "prefix" );
+ break;
+ case InfixForm:
+ element.setAttribute( "form", "infix" );
+ break;
+ case PostfixForm:
+ element.setAttribute( "form", "postfix" );
+ default:
+ break;
+ }
+ }
+ if ( m_customFence ) {
+ element.setAttribute( "fence", m_fence ? "true" : "false" );
+ }
+ if ( m_customSeparator ) {
+ element.setAttribute( "separator", m_separator ? "true" : "false" );
+ }
+ if ( m_customLSpace ) {
+ writeSizeAttribute( element, "lspace", m_lspaceType, m_lspace );
+ }
+ if ( m_customRSpace ) {
+ writeSizeAttribute( element, "rspace", m_rspaceType, m_rspace );
+ }
+ if ( m_customStretchy ) {
+ element.setAttribute( "stretchy", m_stretchy ? "true" : "false" );
+ }
+ if ( m_customSymmetric ) {
+ element.setAttribute( "symmetric", m_symmetric ? "true" : "false" );
+ }
+ if ( m_customMaxSize ) {
+ writeSizeAttribute( element, "maxsize", m_maxSizeType, m_maxSize );
+ }
+ if ( m_customMinSize ) {
+ writeSizeAttribute( element, "minsize", m_minSizeType, m_minSize );
+ }
+ if ( m_customLargeOp ) {
+ element.setAttribute( "largeop", m_largeOp ? "true" : "false" );
+ }
+ if ( m_customMovableLimits ) {
+ element.setAttribute( "movablelimits", m_movableLimits ? "true" : "false" );
+ }
+ if ( m_customAccent ) {
+ element.setAttribute( "accent", m_accent ? "true" : "false" );
+ }
+}
+
+void OperatorElement::writeSizeAttribute( QDomElement& element, const QString &attr, SizeType type, double length ) const
+{
+ switch ( type ) {
+ case InfinitySize:
+ element.setAttribute( attr, "infinity" );
+ break;
+ case AbsoluteSize:
+ element.setAttribute( attr, QString( "%1pt" ).arg( length ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( attr, QString( "%1% " ).arg( length * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( attr, QString( "%1px " ).arg( length ) );
+ break;
+ case NegativeVeryVeryThinMathSpace:
+ element.setAttribute( attr, "negativeveryverythinmathspace" );
+ break;
+ case NegativeVeryThinMathSpace:
+ element.setAttribute( attr, "negativeverythinmathspace" );
+ break;
+ case NegativeThinMathSpace:
+ element.setAttribute( attr, "negativethinmathspace" );
+ break;
+ case NegativeMediumMathSpace:
+ element.setAttribute( attr, "negativemediummathspace" );
+ break;
+ case NegativeThickMathSpace:
+ element.setAttribute( attr, "negativethickmathspace" );
+ break;
+ case NegativeVeryThickMathSpace:
+ element.setAttribute( attr, "negativeverythickmathspace" );
+ break;
+ case NegativeVeryVeryThickMathSpace:
+ element.setAttribute( attr, "negativeveryverythickmathspace" );
+ break;
+ case VeryVeryThinMathSpace:
+ element.setAttribute( attr, "veryverythinmathspace" );
+ break;
+ case VeryThinMathSpace:
+ element.setAttribute( attr, "verythinmathspace" );
+ break;
+ case ThinMathSpace:
+ element.setAttribute( attr, "thinmathspace" );
+ break;
+ case MediumMathSpace:
+ element.setAttribute( attr, "mediummathspace" );
+ break;
+ case ThickMathSpace:
+ element.setAttribute( attr, "thickmathspace" );
+ break;
+ case VeryThickMathSpace:
+ element.setAttribute( attr, "verythickmathspace" );
+ break;
+ case VeryVeryThickMathSpace:
+ element.setAttribute( attr, "veryverythickmathspace" );
+ break;
+ default:
+ break;
+ }
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/operatorelement.h b/lib/kformula/operatorelement.h
new file mode 100644
index 00000000..476b6e99
--- /dev/null
+++ b/lib/kformula/operatorelement.h
@@ -0,0 +1,83 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef OPERATORELEMENT_H
+#define OPERATORELEMENT_H
+
+#include "tokenelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class OperatorElement : public TokenElement {
+ typedef TokenElement inherited;
+public:
+ OperatorElement( BasicElement* parent = 0 );
+ void setForm( FormType type );
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+
+ virtual QString getElementName() const { return "mo"; }
+private:
+ virtual bool readAttributesFromMathMLDom( const QDomElement &element );
+ void writeMathMLAttributes( QDomElement& element ) const ;
+ void writeSizeAttribute( QDomElement& element, const QString &attr, SizeType type, double length ) const ;
+
+ FormType m_form;
+ SizeType m_lspaceType;
+ double m_lspace;
+ SizeType m_rspaceType;
+ double m_rspace;
+ SizeType m_maxSizeType;
+ double m_maxSize;
+ SizeType m_minSizeType;
+ double m_minSize;
+ bool m_fence;
+ bool m_separator;
+ bool m_stretchy;
+ bool m_symmetric;
+ bool m_largeOp;
+ bool m_movableLimits;
+ bool m_accent;
+
+ bool m_customForm;
+ bool m_customFence;
+ bool m_customSeparator;
+ bool m_customLSpace;
+ bool m_customRSpace;
+ bool m_customStretchy;
+ bool m_customSymmetric;
+ bool m_customMaxSize;
+ bool m_customMinSize;
+ bool m_customLargeOp;
+ bool m_customMovableLimits;
+ bool m_customAccent;
+
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // OPERATORELEMENT_H
diff --git a/lib/kformula/paddedelement.cc b/lib/kformula/paddedelement.cc
new file mode 100644
index 00000000..f48d4503
--- /dev/null
+++ b/lib/kformula/paddedelement.cc
@@ -0,0 +1,296 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "elementtype.h"
+#include "paddedelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+PaddedElement::PaddedElement( BasicElement* parent ) : SequenceElement( parent ),
+ m_widthType( NoSize ),
+ m_lspaceType( NoSize ),
+ m_heightType( NoSize ),
+ m_depthType( NoSize ),
+ m_widthRelative( false ),
+ m_lspaceRelative( false ),
+ m_heightRelative( false ),
+ m_depthRelative( false )
+{
+}
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void PaddedElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+
+ luPixel width = 0;
+ luPixel height = 0;
+ luPixel depth = 0;
+
+ if ( !isEmpty() ) {
+ // First, get content height and width
+ for ( iterator it = begin(); it != end(); ++it ) {
+ luPixel spaceBefore = 0;
+ if ( it == begin() ) {
+ spaceBefore = context.ptToPixelX( getSpaceBefore( context, tstyle, factor ) );
+ }
+ it->calcSizes( context, tstyle, istyle, style );
+ width += it->getWidth() + spaceBefore;
+ luPixel baseline = it->getBaseline();
+ if ( baseline > -1 ) {
+ height = QMAX( height, baseline );
+ depth = QMAX( depth, it->getHeight() - baseline );
+ }
+ else {
+ luPixel bl = it->getHeight()/2 + context.axisHeight( tstyle, factor );
+ height = QMAX( height, bl );
+ depth = QMAX( depth, it->getHeight() - bl );
+ }
+ }
+ }
+ else {
+ width = context.getEmptyRectWidth( factor );
+ height = context.getEmptyRectHeight( factor );
+ depth = 0;
+ }
+
+ luPixel left = calcSize( context, m_lspaceType, m_lspaceRelative, m_lspace, width, height, 0 );
+ luPixel right = calcSize( context, m_widthType, m_widthRelative, m_width, width, height, width ) + left;
+ luPixel down = calcSize( context, m_depthType, m_depthRelative, m_depth, width, height, depth );
+ luPixel up = calcSize( context, m_heightType, m_heightRelative, m_height, width, height, height );
+
+ // Check borders
+ if ( right < 0 ) right = 0;
+ if ( up + down < 0 ) up = down = 0;
+
+ if ( ! isEmpty() ) {
+ width = left;
+ // Let's do all normal elements that have a base line.
+ for ( iterator it = begin(); it != end(); ++it ) {
+ luPixel spaceBefore = 0;
+ if ( it == begin() ) {
+ spaceBefore = context.ptToPixelX( getSpaceBefore( context, tstyle, factor ) );
+ }
+ it->calcSizes( context, tstyle, istyle, style );
+ it->setX( width + spaceBefore );
+ width += it->getWidth() + spaceBefore;
+ }
+
+ setWidth( right );
+ setHeight( up + down );
+ setBaseline( up );
+ setChildrenPositions();
+ }
+ else {
+ setWidth( right );
+ setHeight( up + down );
+ setBaseline( up );
+ }
+}
+
+bool PaddedElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ QString widthStr = element.attribute( "width" ).stripWhiteSpace().lower();
+ if ( ! widthStr.isNull() ) {
+ m_width = readSizeAttribute( widthStr, &m_widthType, &m_widthRelative );
+ }
+ QString lspaceStr = element.attribute( "lspace" ).stripWhiteSpace().lower();
+ if ( ! lspaceStr.isNull() ) {
+ m_lspace = readSizeAttribute( lspaceStr, &m_lspaceType, &m_lspaceRelative );
+ }
+ QString heightStr = element.attribute( "height" ).stripWhiteSpace().lower();
+ if ( ! heightStr.isNull() ) {
+ m_height = readSizeAttribute( heightStr, &m_heightType, &m_heightRelative );
+ }
+ QString depthStr = element.attribute( "depth" ).stripWhiteSpace().lower();
+ if ( ! depthStr.isNull() ) {
+ m_depth = readSizeAttribute( depthStr, &m_depthType, &m_depthRelative );
+ }
+
+ return true;
+}
+
+void PaddedElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ writeSizeAttribute( element, "width", m_widthType, m_width, m_widthRelative );
+ writeSizeAttribute( element, "lspace", m_lspaceType, m_lspace, m_lspaceRelative );
+ writeSizeAttribute( element, "height", m_heightType, m_height, m_heightRelative );
+ writeSizeAttribute( element, "depth", m_depthType, m_depth, m_depthRelative );
+}
+
+double PaddedElement::readSizeAttribute( const QString& str, SizeType* st, bool* relative )
+{
+ if ( st == 0 ){
+ return -1;
+ }
+ if ( str[0] == '+' || str[0] == '-' ) {
+ *relative = true;
+ }
+ int index = str.find( "width" );
+ if ( index != -1 ) {
+ int index2 = str.find( "%" );
+ if ( index2 != -1 ) {
+ return str2size( str.left( index2 ).stripWhiteSpace(), st, WidthRelativeSize ) / 100.0;
+ }
+ return str2size( str.left( index ).stripWhiteSpace(), st, WidthRelativeSize );
+ }
+ index = str.find( "height" );
+ if ( index != -1 ) {
+ int index2 = str.find( "%" );
+ if ( index2 != -1 ) {
+ return str2size( str.left( index2 ).stripWhiteSpace(), st, HeightRelativeSize ) / 100.0;
+ }
+ return str2size( str.left( index ).stripWhiteSpace(), st, HeightRelativeSize );
+ }
+ index = str.find( "%" );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, RelativeSize ) / 100.0;
+ }
+ index = str.find( "pt", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, AbsoluteSize );
+ }
+ index = str.find( "mm", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, AbsoluteSize ) * 72.0 / 20.54;
+ }
+ index = str.find( "cm", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, AbsoluteSize ) * 72.0 / 2.54;
+ }
+ index = str.find( "in", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, AbsoluteSize ) * 72.0;
+ }
+ index = str.find( "em", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, RelativeSize );
+ }
+ index = str.find( "ex", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, RelativeSize );
+ }
+ index = str.find( "pc", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, AbsoluteSize ) * 12.0;
+ }
+ index = str.find( "px", 0, false );
+ if ( index != -1 ) {
+ return str2size( str.left( index ).stripWhiteSpace(), st, PixelSize );
+ }
+ // If there's no unit, assume 'pt'
+ return str2size( str, st, AbsoluteSize );
+}
+
+double PaddedElement::str2size( const QString& str, SizeType *st, SizeType type )
+{
+ bool ok;
+ double size = str.toDouble( &ok );
+ if ( ok ) {
+ if ( st ) {
+ *st = type;
+ }
+ return size;
+ }
+ if ( st ) {
+ *st = NoSize;
+ }
+ return -1;
+}
+
+void PaddedElement::writeSizeAttribute( QDomElement element, const QString& str,
+ SizeType st, bool relative, double s ) const
+{
+ QString prefix;
+ if ( relative ) {
+ s < 0 ? prefix = "-" : prefix = "+" ;
+ }
+ switch ( st ) {
+ case WidthRelativeSize:
+ element.setAttribute( str, prefix + QString( "%1 width" ).arg( s ) );
+ break;
+ case HeightRelativeSize:
+ element.setAttribute( str, prefix + QString( "%1 height" ).arg( s ) );
+ case AbsoluteSize:
+ element.setAttribute( str, prefix + QString( "%1pt" ).arg( s ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( str, prefix + QString( "%1%" ).arg( s * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( str, prefix + QString( "%1px" ).arg( s ) );
+ break;
+ default:
+ break;
+ }
+}
+
+luPixel PaddedElement::calcSize( const ContextStyle& context, SizeType type,
+ bool relative, double length, luPixel width,
+ luPixel height, luPixel defvalue )
+{
+ luPixel value = defvalue;
+ switch ( type ) {
+ case AbsoluteSize:
+ if ( relative )
+ value += context.ptToLayoutUnitPt ( length );
+ else
+ value = context.ptToLayoutUnitPt( length );
+ break;
+ case RelativeSize:
+ if ( relative )
+ value += length * value;
+ else
+ value *= length;
+ break;
+ case WidthRelativeSize:
+ if ( relative )
+ value += length * width;
+ else
+ value = length * width;
+ break;
+ case HeightRelativeSize:
+ if ( relative )
+ value += length * height;
+ else
+ value = length * height;
+ break;
+ case PixelSize:
+ if ( relative )
+ value += context.pixelToLayoutUnitX( length );
+ else
+ value = context.pixelToLayoutUnitX( length );
+ break;
+ default:
+ break;
+ }
+ return value;
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/paddedelement.h b/lib/kformula/paddedelement.h
new file mode 100644
index 00000000..591f87bf
--- /dev/null
+++ b/lib/kformula/paddedelement.h
@@ -0,0 +1,75 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef PADDEDELEMENT_H
+#define PADDEDELEMENT_H
+
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class PaddedElement : public SequenceElement {
+ typedef SequenceElement inherited;
+ enum SizeType { NoSize, RelativeSize, AbsoluteSize, PixelSize, WidthRelativeSize, HeightRelativeSize };
+public:
+ PaddedElement( BasicElement* parent = 0 );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+protected:
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+
+private:
+ virtual QString getElementName() const { return "mpadded"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+
+ double readSizeAttribute( const QString& str, SizeType* st, bool* relative );
+ double getSize( const QString& str, SizeType* st );
+ double str2size( const QString& str, SizeType* st, SizeType type );
+ void writeSizeAttribute( QDomElement element, const QString& str,
+ SizeType st, bool relative, double s ) const ;
+ luPixel calcSize( const ContextStyle& context, SizeType type,
+ bool relative, double length, luPixel width,
+ luPixel height, luPixel defvalue );
+
+ SizeType m_widthType;
+ double m_width;
+ SizeType m_lspaceType;
+ double m_lspace;
+ SizeType m_heightType;
+ double m_height;
+ SizeType m_depthType;
+ double m_depth;
+
+ bool m_widthRelative;
+ bool m_lspaceRelative;
+ bool m_heightRelative;
+ bool m_depthRelative;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // PADDEDELEMENT_H
diff --git a/lib/kformula/phantomelement.cc b/lib/kformula/phantomelement.cc
new file mode 100644
index 00000000..2aff0dcd
--- /dev/null
+++ b/lib/kformula/phantomelement.cc
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "phantomelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+PhantomElement::PhantomElement( BasicElement* parent ) : SequenceElement( parent )
+{
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void PhantomElement::draw( QPainter&, const LuPixelRect&, const ContextStyle&,
+ ContextStyle::TextStyle, ContextStyle::IndexStyle,
+ StyleAttributes&, const LuPixelPoint& )
+{
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/phantomelement.h b/lib/kformula/phantomelement.h
new file mode 100644
index 00000000..01880d7b
--- /dev/null
+++ b/lib/kformula/phantomelement.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef PHANTOMELEMENT_H
+#define PHANTOMELEMENT_H
+
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class PhantomElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+ PhantomElement( BasicElement* parent = 0 );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+private:
+ virtual QString getElementName() const { return "mphantom"; }
+
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // PHANTOMELEMENT_H
diff --git a/lib/kformula/pics/Makefile.am b/lib/kformula/pics/Makefile.am
new file mode 100644
index 00000000..ae148b63
--- /dev/null
+++ b/lib/kformula/pics/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = crystalsvg
diff --git a/lib/kformula/pics/crystalsvg/Makefile.am b/lib/kformula/pics/crystalsvg/Makefile.am
new file mode 100644
index 00000000..eeba02ce
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/Makefile.am
@@ -0,0 +1,5 @@
+KDE_ICON=AUTO
+
+hicolordir=$(kde_icondir)/hicolor
+
+
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-abs.png b/lib/kformula/pics/crystalsvg/cr16-action-abs.png
new file mode 100644
index 00000000..67bd6c47
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-abs.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-brackets.png b/lib/kformula/pics/crystalsvg/cr16-action-brackets.png
new file mode 100644
index 00000000..bb9cd45b
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-brackets.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-frac.png b/lib/kformula/pics/crystalsvg/cr16-action-frac.png
new file mode 100644
index 00000000..c6f6ba88
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-frac.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-gsub.png b/lib/kformula/pics/crystalsvg/cr16-action-gsub.png
new file mode 100644
index 00000000..76b3ac78
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-gsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-gsup.png b/lib/kformula/pics/crystalsvg/cr16-action-gsup.png
new file mode 100644
index 00000000..0508bc09
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-gsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-int.png b/lib/kformula/pics/crystalsvg/cr16-action-int.png
new file mode 100644
index 00000000..466688eb
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-int.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-lsub.png b/lib/kformula/pics/crystalsvg/cr16-action-lsub.png
new file mode 100644
index 00000000..559e2c26
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-lsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-lsup.png b/lib/kformula/pics/crystalsvg/cr16-action-lsup.png
new file mode 100644
index 00000000..b7b6a493
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-lsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-matrix.png b/lib/kformula/pics/crystalsvg/cr16-action-matrix.png
new file mode 100644
index 00000000..73052f50
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-matrix.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-multiline.png b/lib/kformula/pics/crystalsvg/cr16-action-multiline.png
new file mode 100644
index 00000000..2f7d152e
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-multiline.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-onetwomatrix.png b/lib/kformula/pics/crystalsvg/cr16-action-onetwomatrix.png
new file mode 100644
index 00000000..23480f19
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-onetwomatrix.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-over.png b/lib/kformula/pics/crystalsvg/cr16-action-over.png
new file mode 100644
index 00000000..df10be73
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-over.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-paren.png b/lib/kformula/pics/crystalsvg/cr16-action-paren.png
new file mode 100644
index 00000000..e0513a07
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-paren.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-prod.png b/lib/kformula/pics/crystalsvg/cr16-action-prod.png
new file mode 100644
index 00000000..6bdafd79
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-prod.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-rsub.png b/lib/kformula/pics/crystalsvg/cr16-action-rsub.png
new file mode 100644
index 00000000..f616d8b2
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-rsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-rsup.png b/lib/kformula/pics/crystalsvg/cr16-action-rsup.png
new file mode 100644
index 00000000..1d2f8aad
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-rsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-sqrt.png b/lib/kformula/pics/crystalsvg/cr16-action-sqrt.png
new file mode 100644
index 00000000..c28906ed
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-sqrt.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-sum.png b/lib/kformula/pics/crystalsvg/cr16-action-sum.png
new file mode 100644
index 00000000..599135d4
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-sum.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr16-action-under.png b/lib/kformula/pics/crystalsvg/cr16-action-under.png
new file mode 100644
index 00000000..c9f425b5
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr16-action-under.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-abs.png b/lib/kformula/pics/crystalsvg/cr22-action-abs.png
new file mode 100644
index 00000000..030e8fba
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-abs.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-brackets.png b/lib/kformula/pics/crystalsvg/cr22-action-brackets.png
new file mode 100644
index 00000000..bb67db9e
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-brackets.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-frac.png b/lib/kformula/pics/crystalsvg/cr22-action-frac.png
new file mode 100644
index 00000000..2cbce42b
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-frac.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-gsub.png b/lib/kformula/pics/crystalsvg/cr22-action-gsub.png
new file mode 100644
index 00000000..e1cbcb14
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-gsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-gsup.png b/lib/kformula/pics/crystalsvg/cr22-action-gsup.png
new file mode 100644
index 00000000..69f9a6f1
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-gsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-inscol.png b/lib/kformula/pics/crystalsvg/cr22-action-inscol.png
new file mode 100644
index 00000000..d00db768
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-inscol.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-insrow.png b/lib/kformula/pics/crystalsvg/cr22-action-insrow.png
new file mode 100644
index 00000000..90603888
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-insrow.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-int.png b/lib/kformula/pics/crystalsvg/cr22-action-int.png
new file mode 100644
index 00000000..691742f1
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-int.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-lsub.png b/lib/kformula/pics/crystalsvg/cr22-action-lsub.png
new file mode 100644
index 00000000..151d3235
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-lsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-lsup.png b/lib/kformula/pics/crystalsvg/cr22-action-lsup.png
new file mode 100644
index 00000000..f42d3b33
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-lsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-matrix.png b/lib/kformula/pics/crystalsvg/cr22-action-matrix.png
new file mode 100644
index 00000000..a5320a90
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-matrix.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-multiline.png b/lib/kformula/pics/crystalsvg/cr22-action-multiline.png
new file mode 100644
index 00000000..44585275
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-multiline.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-onetwomatrix.png b/lib/kformula/pics/crystalsvg/cr22-action-onetwomatrix.png
new file mode 100644
index 00000000..e2320742
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-onetwomatrix.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-over.png b/lib/kformula/pics/crystalsvg/cr22-action-over.png
new file mode 100644
index 00000000..012fd3f8
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-over.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-paren.png b/lib/kformula/pics/crystalsvg/cr22-action-paren.png
new file mode 100644
index 00000000..98a3b98c
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-paren.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-prod.png b/lib/kformula/pics/crystalsvg/cr22-action-prod.png
new file mode 100644
index 00000000..1e6e691e
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-prod.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-remcol.png b/lib/kformula/pics/crystalsvg/cr22-action-remcol.png
new file mode 100644
index 00000000..343af86e
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-remcol.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-remrow.png b/lib/kformula/pics/crystalsvg/cr22-action-remrow.png
new file mode 100644
index 00000000..6af59af7
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-remrow.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-rsub.png b/lib/kformula/pics/crystalsvg/cr22-action-rsub.png
new file mode 100644
index 00000000..9dc6741b
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-rsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-rsup.png b/lib/kformula/pics/crystalsvg/cr22-action-rsup.png
new file mode 100644
index 00000000..77dd5c36
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-rsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-sqrt.png b/lib/kformula/pics/crystalsvg/cr22-action-sqrt.png
new file mode 100644
index 00000000..a63d5d2a
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-sqrt.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-sum.png b/lib/kformula/pics/crystalsvg/cr22-action-sum.png
new file mode 100644
index 00000000..9ffd657d
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-sum.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr22-action-under.png b/lib/kformula/pics/crystalsvg/cr22-action-under.png
new file mode 100644
index 00000000..a16d6e0a
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr22-action-under.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-abs.png b/lib/kformula/pics/crystalsvg/cr32-action-abs.png
new file mode 100644
index 00000000..c11a8b0d
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-abs.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-brackets.png b/lib/kformula/pics/crystalsvg/cr32-action-brackets.png
new file mode 100644
index 00000000..a0cec66e
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-brackets.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-frac.png b/lib/kformula/pics/crystalsvg/cr32-action-frac.png
new file mode 100644
index 00000000..a962f701
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-frac.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-gsub.png b/lib/kformula/pics/crystalsvg/cr32-action-gsub.png
new file mode 100644
index 00000000..42e05816
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-gsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-gsup.png b/lib/kformula/pics/crystalsvg/cr32-action-gsup.png
new file mode 100644
index 00000000..86db0f8c
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-gsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-int.png b/lib/kformula/pics/crystalsvg/cr32-action-int.png
new file mode 100644
index 00000000..df684d64
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-int.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-lsub.png b/lib/kformula/pics/crystalsvg/cr32-action-lsub.png
new file mode 100644
index 00000000..dccd32b5
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-lsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-lsup.png b/lib/kformula/pics/crystalsvg/cr32-action-lsup.png
new file mode 100644
index 00000000..440ef334
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-lsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-matrix.png b/lib/kformula/pics/crystalsvg/cr32-action-matrix.png
new file mode 100644
index 00000000..45a57805
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-matrix.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-multiline.png b/lib/kformula/pics/crystalsvg/cr32-action-multiline.png
new file mode 100644
index 00000000..3ca06a77
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-multiline.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-onetwomatrix.png b/lib/kformula/pics/crystalsvg/cr32-action-onetwomatrix.png
new file mode 100644
index 00000000..ebe7d639
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-onetwomatrix.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-over.png b/lib/kformula/pics/crystalsvg/cr32-action-over.png
new file mode 100644
index 00000000..3eadf6d3
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-over.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-paren.png b/lib/kformula/pics/crystalsvg/cr32-action-paren.png
new file mode 100644
index 00000000..42ad7eac
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-paren.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-prod.png b/lib/kformula/pics/crystalsvg/cr32-action-prod.png
new file mode 100644
index 00000000..a0a0ed0e
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-prod.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-rsub.png b/lib/kformula/pics/crystalsvg/cr32-action-rsub.png
new file mode 100644
index 00000000..298d4aa8
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-rsub.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-rsup.png b/lib/kformula/pics/crystalsvg/cr32-action-rsup.png
new file mode 100644
index 00000000..c2282e0a
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-rsup.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-sqrt.png b/lib/kformula/pics/crystalsvg/cr32-action-sqrt.png
new file mode 100644
index 00000000..028f4a92
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-sqrt.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-sum.png b/lib/kformula/pics/crystalsvg/cr32-action-sum.png
new file mode 100644
index 00000000..6d7dc2b1
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-sum.png
Binary files differ
diff --git a/lib/kformula/pics/crystalsvg/cr32-action-under.png b/lib/kformula/pics/crystalsvg/cr32-action-under.png
new file mode 100644
index 00000000..a7d6500a
--- /dev/null
+++ b/lib/kformula/pics/crystalsvg/cr32-action-under.png
Binary files differ
diff --git a/lib/kformula/prototype/README b/lib/kformula/prototype/README
new file mode 100644
index 00000000..c4cf4486
--- /dev/null
+++ b/lib/kformula/prototype/README
@@ -0,0 +1,9 @@
+
+A small prototype of the kformula engine. Needs:
+
+python2.0 (http://www.python.org)
+PyQt2.2 (http://www.thekompany.com/projects/pykde/)
+
+Please see file ../DESIGN for details. Any feedback is welcome.
+
+Uli
diff --git a/lib/kformula/prototype/engine.py b/lib/kformula/prototype/engine.py
new file mode 100644
index 00000000..f1391069
--- /dev/null
+++ b/lib/kformula/prototype/engine.py
@@ -0,0 +1,1180 @@
+"""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.
+"""
+
+from qt import *
+
+
+class BasicElement:
+ """The interface for every element."""
+
+ def __init__(self, parent):
+ self.parent = parent
+ self.size = QSize()
+ self.pos = QPoint()
+
+
+ def x(self): return self.pos.x()
+ def y(self): return self.pos.y()
+ def setX(self, x): self.pos.setX(x)
+ def setY(self, y): self.pos.setY(y)
+
+ def width(self): return self.size.width()
+ def height(self): return self.size.height()
+ def setWidth(self, w): self.size.setWidth(w)
+ def setHeight(self, h): self.size.setHeight(h)
+
+ def globalPos(self):
+ """Returns the pos in global Coords."""
+ x = y = 0
+ element = self
+ while element != None:
+ x += element.x()
+ y += element.y()
+ element = element.parent
+ return QPoint(x, y)
+
+ def elementAt(self, point, startPoint):
+ """Returns the element that is at position point.
+ `None' if there is no element there."""
+ x = point.x() - startPoint.x()
+ if x >= 0 and x < self.width():
+ y = point.y() - startPoint.y()
+ if y >= 0 and y < self.height():
+ return self
+
+ def moveLeft(self, cursor, fromElement):
+ """Enters this element while moving to the left from
+ the element `fromElement'. Searched for cursor position inside
+ this element of left of it."""
+ pass
+
+ def moveRight(self, cursor, fromElement):
+ """Enters this element while moving to the right from
+ the element `fromElement'. Searched for cursor position inside
+ this element of right of it."""
+ pass
+
+ def moveUp(self, cursor, fromElement):
+ pass
+
+ def moveDown(self, cursor, fromElement):
+ pass
+
+ def formula(self):
+ """Returns the FormulaElement we are a child of."""
+ return self.parent.formula()
+
+ def draw(self, painter, styleContext, startPoint):
+ """Draws the whole thing. Including its children."""
+ pass
+
+ def calcSizes(self, styleContext):
+ """Recalculates the size.
+ position (relative our to parent), width and height
+ will be stored in self.size,
+ the midline offset in self.midline.
+
+ Please note: It's up to a parent to store its children's position."""
+ pass
+
+ def mainChild(self):
+ """Returns the most important child. `None' if there is None
+ child at all."""
+ return None
+
+ def setMainChild(self, sequenceElement):
+ """Defines the main child."""
+ pass
+
+ def makeSequence(self):
+ """Packs the element into a new SequenceElement."""
+ return SequenceElement(self)
+
+ def removeChild(self, cursor, element):
+ """Removes the given child. If this happens to be the main
+ child we remove ourself, too.
+ The cursor has to be inside the child which is going to be
+ removed."""
+ pass
+
+
+class SequenceElement (BasicElement):
+ """The element that contains a number of children.
+ The children are aligned in one line."""
+
+ def __init__(self, parent):
+ BasicElement.__init__(self, parent)
+ self.children = []
+
+ def elementAtCursor(self, cursor):
+ """Returns the element before the cursor."""
+ if cursor.pos() > 0:
+ return self.children[cursor.pos()-1]
+
+ def elementAt(self, point, startPoint):
+ r = BasicElement.elementAt(self, point, startPoint)
+ if r != None:
+ for child in self.children:
+ r = child.elementAt(point, QPoint(startPoint.x()+child.x(),
+ startPoint.y()+child.y()))
+ if r != None:
+ return r
+ return self
+
+
+ def moveLeft(self, cursor, fromElement):
+
+ # Our parent asks us for a cursor position. Found.
+ if fromElement == self.parent:
+ cursor.set(self, len(self.children))
+
+ # We already owned the cursor. Ask next child then.
+ elif fromElement == self:
+ if cursor.pos() > 0:
+ if cursor.isSelection():
+ cursor.set (self, cursor.pos()-1)
+ else:
+ self.children[cursor.pos()-1].moveLeft(cursor, self)
+ else:
+ # Needed because FormulaElement derives this.
+ if self.parent != None:
+ self.parent.moveLeft(cursor, self)
+
+ # The cursor came from one of our children or
+ # something is wrong.
+ else:
+ fromPos = self.children.index(fromElement)
+ cursor.set(self, fromPos)
+ if cursor.isSelection():
+ if not cursor.mouseMark():
+ cursor.setMarkPos(fromPos+1)
+
+
+ def moveRight(self, cursor, fromElement):
+
+ # Our parent asks us for a cursor position. Found.
+ if fromElement == self.parent:
+ cursor.set(self, 0)
+
+ # We already owned the cursor. Ask next child then.
+ elif fromElement == self:
+ if cursor.pos() < len(self.children):
+ if cursor.isSelection():
+ cursor.set (self, cursor.pos()+1)
+ else:
+ self.children[cursor.pos()].moveRight(cursor, self)
+ else:
+ # Needed because FormulaElement derives this.
+ if self.parent != None:
+ self.parent.moveRight(cursor, self)
+
+ # The cursor came from one of our children or
+ # something is wrong.
+ else:
+ fromPos = self.children.index(fromElement)
+ cursor.set(self, fromPos+1)
+ if cursor.isSelection():
+ if not cursor.mouseMark():
+ cursor.setMarkPos(fromPos)
+
+
+ def moveUp(self, cursor, fromElement):
+ if fromElement == self.parent:
+ self.moveRight(cursor, self)
+ else:
+ if self.parent != None:
+ self.parent.moveUp(cursor, self)
+
+
+ def moveDown(self, cursor, fromElement):
+ if fromElement == self.parent:
+ self.moveRight(cursor, self)
+ else:
+ if self.parent != None:
+ self.parent.moveDown(cursor, self)
+
+
+ def moveHome(self, cursor):
+ if cursor.isSelection():
+ element = cursor.element()
+ if element != self:
+ while element.parent != self:
+ element = element.parent
+ cursor.setMarkPos(self.children.index(element)+1)
+ cursor.set(self, 0)
+
+ def moveEnd(self, cursor):
+ if cursor.isSelection():
+ element = cursor.element()
+ if element != self:
+ while element.parent != self:
+ element = element.parent
+ cursor.setMarkPos(self.children.index(element))
+ cursor.set(self, len(self.children))
+
+
+ def draw(self, painter, styleContext, startPoint):
+ x, y = startPoint.x(), startPoint.y()
+ if len(self.children) > 0:
+ for child in self.children:
+ cX = child.x()
+ cY = child.y()
+ child.draw(painter, styleContext, QPoint(x+cX, y+cY))
+
+ # Debug
+ #painter.setPen(Qt.green)
+ #painter.drawRect(x, y, self.width(), self.height())
+ else:
+ painter.setPen(Qt.blue)
+ painter.drawRect(x, y, self.width(), self.height())
+
+ def calcSizes(self, styleContext):
+ if len(self.children) > 0:
+ x = self.x()
+ y = self.y()
+ width = toMidline = fromMidline = 0
+ for child in self.children:
+ child.calcSizes(styleContext)
+ child.setX(width)
+ width += child.width()
+ if child.midline > toMidline:
+ toMidline = child.midline
+ if child.height()-child.midline > fromMidline:
+ fromMidline = child.height() - child.midline
+
+ self.setWidth(width)
+ self.setHeight(toMidline+fromMidline)
+ self.midline = toMidline
+
+ for child in self.children:
+ child.setY(self.midline - child.midline)
+
+ else:
+ self.setWidth(10)
+ self.setHeight(10)
+ self.midline = 5
+
+ def mainChild(self):
+ if len(self.children) > 0:
+ return self.children[0]
+ return None
+
+ def setMainChild(self, sequenceElement):
+ if len(self.children) > 0:
+ self.children[0] = sequenceElement
+ sequenceElement.parent = self
+ else:
+ self.addChild(sequenceElement)
+
+ def makeSequence(self):
+ return self
+
+
+ def replaceCurrentSelection(self, cursor, element):
+ """Replaces the currently selected sequence (the child before
+ the cursor) with the given element. The replaced sequence
+ becomes the main child of the new element."""
+
+ # it is essential to set up the parent pointer for
+ # the notification to work.
+ element.parent = self
+
+ seq = element.makeSequence()
+ if cursor.isSelection():
+ f = min(cursor.pos(), cursor.markPos())
+ t = max(cursor.pos(), cursor.markPos())
+ for i in range(f, t):
+ child = self.children.pop(f)
+ self.formula().elementRemoved(child)
+ seq.addChild(child)
+ self.children.insert(f, element)
+ cursor.setMarkPos(-1)
+ cursor.set(self, f+1)
+ elif cursor.pos() > 0:
+ seq.addChild(self.children[cursor.pos()-1])
+ self.replaceChild(cursor, element)
+ else:
+ self.insertChild(cursor, element)
+
+ element.setMainChild(seq)
+
+
+ def replaceElementByMainChild(self, cursor, element):
+ """Replaces the given element with the content of its main child.
+ (The main child is always a SequenceElement.)"""
+ assert element.parent == self
+ self.formula().elementRemoved(element)
+
+ seq = element.mainChild()
+ pos = self.children.index(element)
+ self.children.remove(element)
+ for child in seq.children:
+ self.children.insert(pos, child)
+ child.parent = self
+ pos += 1
+ cursor.set(self, pos)
+ self.formula().changed()
+
+
+ def addChild(self, element):
+ self.children.append(element)
+ element.parent = self
+ self.formula().changed()
+
+ def insertChild(self, cursor, element):
+ """Inserts the new element at the cursor position.
+ The cursor is placed behind the new element."""
+ pos = cursor.pos()
+ self.children.insert(pos, element)
+ element.parent = self
+ cursor.set(self, pos+1)
+ self.formula().changed()
+
+ def replaceChild(self, cursor, element):
+ """Replaces the element before the cursor with the new one.
+ No range checking. Be careful."""
+ self.children[cursor.pos()-1] = element
+ element.parent = self
+ self.formula().changed()
+
+ def removeChild(self, cursor, element):
+ self.formula().elementRemoved(element)
+ cursor.set(self, self.children.index(element))
+ self.children.remove(element)
+ if len(self.children) == 0:
+ if self.parent != None:
+ self.parent.removeChild(cursor, self)
+ return
+ self.formula().changed()
+
+ def removeChildAt(self, cursor):
+ pos = cursor.pos()
+ if cursor.isSelection():
+ f = min(cursor.pos(), cursor.markPos())
+ t = max(cursor.pos(), cursor.markPos())
+ for i in range(f, t):
+ child = self.children.pop(f)
+ self.formula().elementRemoved(child)
+ cursor.setMarkPos(-1)
+ cursor.set(self, f)
+ self.formula().changed()
+ elif pos < len(self.children):
+ self.children.pop(pos)
+ self.formula().changed()
+ else:
+ if len(self.children) == 0:
+ if self.parent != None:
+ self.parent.removeChild(cursor, self)
+
+ def removeChildBefore(self, cursor):
+ pos = cursor.pos()-1
+ if cursor.isSelection():
+ f = min(cursor.pos(), cursor.markPos())
+ t = max(cursor.pos(), cursor.markPos())
+ for i in range(f, t):
+ child = self.children.pop(f)
+ self.formula().elementRemoved(child)
+ cursor.setMarkPos(-1)
+ cursor.set(self, f)
+ self.formula().changed()
+ elif pos >= 0:
+ self.children.pop(pos)
+ cursor.set(self, pos)
+ self.formula().changed()
+ else:
+ if len(self.children) == 0:
+ if self.parent != None:
+ self.parent.removeChild(cursor, self)
+
+
+ def globalCursorPos(self, pos):
+ """Returns the position after the child at the position
+ in global Coords."""
+ point = self.globalPos()
+ if pos < len(self.children):
+ d = self.children[pos].x()
+ else:
+ if len(self.children) > 0:
+ d = self.width()
+ else:
+ d = 2
+
+ point.setX(point.x()+d)
+ return point
+
+ def countChildren(self):
+ return len(self.children)
+
+
+class FormulaElement (SequenceElement):
+ """The main element.
+ A formula consists of a FormulaElement and its children.
+ The only element that has no parent."""
+
+ def __init__(self, document):
+ SequenceElement.__init__(self, None)
+ self.document = document
+
+ def formula(self):
+ return self
+
+ def changed(self):
+ """Is called by its children if the formula changed in any way."""
+ self.document.changed()
+
+ def elementRemoved(self, element):
+ """Gets called just before the element is removed from the
+ tree. We need this to ensure that no cursor is left in the
+ leaf that gets cut off.
+
+ Caution! The object tree must still contain the element by the time
+ you call this methode."""
+ self.document.elementRemoved(element)
+
+
+class TextElement (BasicElement):
+ """One char."""
+
+ def __init__(self, parent, char):
+ BasicElement.__init__(self, parent)
+ self.char = char
+
+ def moveLeft(self, cursor, fromElement):
+ self.parent.moveLeft(cursor, self)
+
+ def moveRight(self, cursor, fromElement):
+ self.parent.moveRight(cursor, self)
+
+ def draw(self, painter, styleContext, startPoint):
+ styleContext.setupPainter(painter)
+ painter.drawText(startPoint.x(), startPoint.y()+self.baseline, self.char)
+ #painter.drawRect(startPoint.x(), startPoint.y(), self.width(), self.height())
+
+ def calcSizes(self, styleContext):
+ fm = styleContext.fontMetrics()
+ self.setWidth(fm.width(self.char))
+ self.setHeight(fm.height())
+ self.midline = self.height() / 2
+ self.baseline = fm.ascent()
+
+
+class IndexElement (BasicElement):
+ """Up to four indexes in the four corners."""
+
+ def __init__(self, contentElement):
+ if contentElement != None:
+ BasicElement.__init__(self, contentElement.parent)
+ contentElement.parent = self
+ else:
+ BasicElement.__init__(self, None)
+
+ self.content = contentElement
+ self.upperLeft = self.upperRight = None
+ self.lowerLeft = self.lowerRight = None
+
+
+ def elementAt(self, point, startPoint):
+ r = BasicElement.elementAt(self, point, startPoint)
+ if r != None:
+ x, y = startPoint.x(), startPoint.y()
+ r = self.content.elementAt(point, QPoint(x+self.content.x(),
+ y+self.content.y()))
+ if r != None: return r
+
+ if self.upperRight != None:
+ r = self.upperRight.elementAt(point, QPoint(x+self.upperRight.x(),
+ y+self.upperRight.y()))
+ if r != None: return r
+
+ if self.upperLeft != None:
+ r = self.upperLeft.elementAt(point, QPoint(x+self.upperLeft.x(),
+ y+self.upperLeft.y()))
+ if r != None: return r
+
+ if self.lowerRight != None:
+ r = self.lowerRight.elementAt(point, QPoint(x+self.lowerRight.x(),
+ y+self.lowerRight.y()))
+ if r != None: return r
+
+ if self.lowerLeft != None:
+ r = self.lowerLeft.elementAt(point, QPoint(x+self.lowerLeft.x(),
+ y+self.lowerLeft.y()))
+ if r != None: return r
+
+ return self
+
+
+ def moveLeft(self, cursor, fromElement):
+ assert fromElement != None
+
+ if cursor.isSelection():
+ self.parent.moveLeft(cursor, self)
+
+ elif fromElement == self.parent:
+ if self.lowerRight != None:
+ self.lowerRight.moveLeft(cursor, self)
+ elif self.upperRight != None:
+ self.upperRight.moveLeft(cursor, self)
+ else:
+ self.content.moveLeft(cursor, self)
+
+ elif fromElement == self.lowerRight:
+ if self.upperRight != None:
+ self.upperRight.moveLeft(cursor, self)
+ else:
+ self.content.moveLeft(cursor, self)
+
+ elif fromElement == self.upperRight:
+ self.content.moveLeft(cursor, self)
+
+ elif fromElement == self.content:
+ if self.lowerLeft != None:
+ self.lowerLeft.moveLeft(cursor, self)
+ elif self.upperLeft != None:
+ self.upperLeft.moveLeft(cursor, self)
+ else:
+ self.parent.moveLeft(cursor, self)
+
+ elif fromElement == self.lowerLeft:
+ if self.upperLeft != None:
+ self.upperLeft.moveLeft(cursor, self)
+ else:
+ self.parent.moveLeft(cursor, self)
+
+ else:
+ self.parent.moveLeft(cursor, self)
+
+
+ def moveRight(self, cursor, fromElement):
+ assert fromElement != None
+
+ if cursor.isSelection():
+ self.parent.moveRight(cursor, self)
+
+ elif fromElement == self.parent:
+ if self.upperLeft != None:
+ self.upperLeft.moveRight(cursor, self)
+ elif self.lowerLeft != None:
+ self.lowerLeft.moveRight(cursor, self)
+ else:
+ self.content.moveRight(cursor, self)
+
+ elif fromElement == self.upperLeft:
+ if self.lowerLeft != None:
+ self.lowerLeft.moveRight(cursor, self)
+ else:
+ self.content.moveRight(cursor, self)
+
+ elif fromElement == self.lowerLeft:
+ self.content.moveRight(cursor, self)
+
+ elif fromElement == self.content:
+ if self.upperRight != None:
+ self.upperRight.moveRight(cursor, self)
+ elif self.lowerRight != None:
+ self.lowerRight.moveRight(cursor, self)
+ else:
+ self.parent.moveRight(cursor, self)
+
+ elif fromElement == self.upperRight:
+ if self.lowerRight != None:
+ self.lowerRight.moveRight(cursor, self)
+ else:
+ self.parent.moveRight(cursor, self)
+
+ else:
+ self.parent.moveRight(cursor, self)
+
+
+ def moveUp(self, cursor, fromElement):
+ assert fromElement != None
+
+ if fromElement == self.parent:
+ self.content.moveRight(cursor, self)
+
+ elif fromElement == self.upperLeft or fromElement == self.upperRight:
+ self.parent.moveUp(cursor, self)
+
+ elif fromElement == self.content:
+ if self.upperRight != None:
+ self.upperRight.moveRight(cursor, self)
+ elif self.upperLeft != None:
+ #self.upperLeft.moveRight(cursor, self)
+ self.upperLeft.moveLeft(cursor, self)
+ else:
+ self.parent.moveUp(cursor, self)
+
+ elif fromElement == self.lowerLeft:
+ self.content.moveRight(cursor, self)
+
+ elif fromElement == self.lowerRight:
+ self.content.moveLeft(cursor, self)
+
+ else: # should never happen.
+ self.parent.moveUp(cursor, self)
+
+
+ def moveDown(self, cursor, fromElement):
+ assert fromElement != None
+
+ if fromElement == self.parent:
+ self.content.moveRight(cursor, self)
+
+ elif fromElement == self.lowerLeft or fromElement == self.lowerRight:
+ self.parent.moveDown(cursor, fromElement)
+
+ elif fromElement == self.content:
+ if self.lowerRight != None:
+ self.lowerRight.moveRight(cursor, self)
+ elif self.lowerLeft != None:
+ #self.lowerLeft.moveRight(cursor, self)
+ self.lowerLeft.moveLeft(cursor, self)
+ else:
+ self.parent.moveDown(cursor, self)
+
+ elif fromElement == self.upperLeft:
+ self.content.moveRight(cursor, self)
+
+ elif fromElement == self.upperRight:
+ self.content.moveLeft(cursor, self)
+
+ else: # should never happen.
+ self.parent.moveDown(cursor, self)
+
+
+ def draw(self, painter, styleContext, startPoint):
+ x, y = startPoint.x(), startPoint.y()
+ self.content.draw(painter, styleContext,
+ QPoint(x+self.content.x(),
+ y+self.content.y()))
+ if self.upperLeft != None:
+ self.upperLeft.draw(painter, styleContext,
+ QPoint(x+self.upperLeft.x(),
+ y+self.upperLeft.y()))
+ if self.upperRight != None:
+ self.upperRight.draw(painter, styleContext,
+ QPoint(x+self.upperRight.x(),
+ y+self.upperRight.y()))
+ if self.lowerLeft != None:
+ self.lowerLeft.draw(painter, styleContext,
+ QPoint(x+self.lowerLeft.x(),
+ y+self.lowerLeft.y()))
+ if self.lowerRight != None:
+ self.lowerRight.draw(painter, styleContext,
+ QPoint(x+self.lowerRight.x(),
+ y+self.lowerRight.y()))
+
+ # Debug
+ painter.setPen(Qt.red)
+ painter.drawRect(x, y, self.width(), self.height())
+
+
+ def calcSizes(self, styleContext):
+
+ # get the indexes size
+ if self.upperLeft != None:
+ self.upperLeft.calcSizes(styleContext)
+ ulWidth = self.upperLeft.width()
+ ulHeight = self.upperLeft.height()
+ ulMidline = self.upperLeft.midline
+ else:
+ ulWidth = ulHeight = ulMidline = 0
+
+ if self.upperRight != None:
+ self.upperRight.calcSizes(styleContext)
+ urWidth = self.upperRight.width()
+ urHeight = self.upperRight.height()
+ urMidline = self.upperRight.midline
+ else:
+ urWidth = urHeight = urMidline = 0
+
+ if self.lowerLeft != None:
+ self.lowerLeft.calcSizes(styleContext)
+ llWidth = self.lowerLeft.width()
+ llHeight = self.lowerLeft.height()
+ llMidline = self.lowerLeft.midline
+ else:
+ llWidth = llHeight = llMidline = 0
+
+ if self.lowerRight != None:
+ self.lowerRight.calcSizes(styleContext)
+ lrWidth = self.lowerRight.width()
+ lrHeight = self.lowerRight.height()
+ lrMidline = self.lowerRight.midline
+ else:
+ lrWidth = lrHeight = lrMidline = 0
+
+ # get the contents size
+ self.content.calcSizes(styleContext)
+ width = self.content.width()
+ toMidline = self.content.midline
+ fromMidline = self.content.height() - toMidline
+
+ # calculate the x offsets
+ if ulWidth > llWidth:
+ self.upperLeft.setX(0)
+ if self.lowerLeft != None:
+ self.lowerLeft.setX(ulWidth - llWidth)
+ self.content.setX(ulWidth)
+ width += ulWidth
+ else:
+ if self.upperLeft != None:
+ self.upperLeft.setX(llWidth - ulWidth)
+ if self.lowerLeft != None:
+ self.lowerLeft.setX(0)
+ self.content.setX(llWidth)
+ width += llWidth
+
+ if self.upperRight != None:
+ self.upperRight.setX(width)
+ if self.lowerRight != None:
+ self.lowerRight.setX(width)
+
+ width += max(urWidth, lrWidth)
+
+ # calculate the y offsets
+ if ulHeight > urHeight:
+ self.upperLeft.setY(0)
+ if self.upperRight != None:
+ self.upperRight.setY(ulHeight - urHeight)
+ self.content.setY(max(ulHeight - toMidline/2, 0))
+ toMidline += self.content.y()
+ else:
+ if self.upperLeft != None:
+ self.upperLeft.setY(urHeight - ulHeight)
+ if self.upperRight != None:
+ self.upperRight.setY(0)
+ self.content.setY(max(urHeight - toMidline/2, 0))
+ toMidline += self.content.y()
+
+ if self.lowerLeft != None:
+ self.lowerLeft.setY(toMidline + fromMidline/2)
+ if self.lowerRight != None:
+ self.lowerRight.setY(toMidline + fromMidline/2)
+
+ fromMidline += max(max(llHeight, lrHeight) - fromMidline/2, 0)
+
+ # set the result
+ self.setWidth(width)
+ self.setHeight(toMidline+fromMidline)
+ #self.midline = self.height()/2
+ self.midline = toMidline
+
+
+ def mainChild(self):
+ return self.content
+
+ def setMainChild(self, sequenceElement):
+ self.content = sequenceElement
+ self.content.parent = self
+ self.formula().changed()
+
+ def removeChild(self, cursor, element):
+ if element == self.upperLeft:
+ self.formula().elementRemoved(self.upperLeft)
+ self.content.moveRight(cursor, self)
+ self.upperLeft = None
+ elif element == self.lowerLeft:
+ self.formula().elementRemoved(self.lowerLeft)
+ self.content.moveRight(cursor, self)
+ self.lowerLeft = None
+ elif element == self.upperRight:
+ self.formula().elementRemoved(self.upperRight)
+ self.content.moveLeft(cursor, self)
+ self.upperRight = None
+ elif element == self.lowerRight:
+ self.formula().elementRemoved(self.lowerRight)
+ self.content.moveLeft(cursor, self)
+ self.lowerRight = None
+ elif element == self.content:
+ self.parent.removeChild(cursor, self)
+ return
+
+ if self.upperLeft == None and self.lowerLeft == None and \
+ self.upperRight == None and self.lowerRight == None:
+ self.parent.replaceElementByMainChild(cursor, self)
+ else:
+ self.formula().changed()
+
+
+ def requireUpperLeft(self):
+ if self.upperLeft == None:
+ self.upperLeft = SequenceElement(self)
+ self.formula().changed()
+ return self.upperLeft
+
+ def requireUpperRight(self):
+ if self.upperRight == None:
+ self.upperRight = SequenceElement(self)
+ self.formula().changed()
+ return self.upperRight
+
+ def requireLowerLeft(self):
+ if self.lowerLeft == None:
+ self.lowerLeft = SequenceElement(self)
+ self.formula().changed()
+ return self.lowerLeft
+
+ def requireLowerRight(self):
+ if self.lowerRight == None:
+ self.lowerRight = SequenceElement(self)
+ self.formula().changed()
+ return self.lowerRight
+
+
+class Cursor:
+ """The selection. This might be a one position selection or
+ an area. Handles user input and object creation.
+
+ Note that it is up to the elements to actually move the cursor.
+ (The cursor has no chance to know how.)"""
+
+ def __init__(self, formulaElement):
+ self.sequenceElement = formulaElement
+ self.currentPos = 0
+ self.currentMarkPos = -1
+ self.selectionFlag = 0
+ self.mouseMarkFlag = 0
+
+ def isSelection(self):
+ return self.selectionFlag
+
+ def mouseMark(self):
+ return self.mouseMarkFlag
+
+ def set(self, sequenceElement, pos):
+ """Set the cursor to a new position."""
+ if self.isSelection():
+ if self.currentMarkPos == -1:
+ self.currentMarkPos = self.currentPos
+ if self.currentMarkPos == pos:
+ self.selectionFlag = 0
+ else:
+ self.currentMarkPos = -1
+
+ self.sequenceElement = sequenceElement
+ self.currentPos = pos
+
+ def markPos(self):
+ return self.currentMarkPos
+
+ def setMarkPos(self, markPos):
+ """Gets called by elements if the cursor moves up to the parent."""
+ self.selectionFlag = (markPos != -1)
+ self.currentMarkPos = markPos
+
+ def pos(self):
+ return self.currentPos
+
+ def element(self):
+ return self.sequenceElement
+
+
+ def draw(self, painter):
+ point = self.sequenceElement.globalCursorPos(self.pos())
+ height = self.sequenceElement.height()
+
+ if self.isSelection():
+ markPoint = self.sequenceElement.globalCursorPos(self.markPos())
+
+ x = min(point.x(), markPoint.x())
+ width = abs(point.x() - markPoint.x())
+ painter.setRasterOp(Qt.XorROP)
+ #painter.setRasterOp(Qt.OrROP)
+ painter.fillRect(x, point.y(), width, height, QBrush(Qt.white))
+ #painter.drawLine(point.x(), point.y()-2,
+ # point.x(), point.y()+height+2)
+ painter.setRasterOp(Qt.CopyROP)
+ else:
+ painter.setPen(Qt.blue)
+ painter.drawLine(point.x(), point.y()-2,
+ point.x(), point.y()+height+2)
+
+
+
+ def findIndexElement(self):
+ """Looks if we are just behind an IndexElement or at the last
+ position of an IndexElement's content and returns the element then."""
+ element = self.sequenceElement.elementAtCursor(self)
+ if isinstance(element, IndexElement):
+ return element
+ if self.pos() == self.sequenceElement.countChildren():
+ parent = self.sequenceElement.parent
+ if isinstance(parent, IndexElement):
+ if self.sequenceElement == parent.mainChild():
+ return parent
+
+
+ def addUpperRightIndex(self):
+ indexElement = self.findIndexElement()
+ if indexElement == None:
+ indexElement = IndexElement(None)
+ self.sequenceElement.replaceCurrentSelection(self, indexElement)
+ index = indexElement.requireUpperRight()
+
+ index.moveRight(self, index.parent)
+
+
+ def addLowerRightIndex(self):
+ indexElement = self.findIndexElement()
+ if indexElement == None:
+ indexElement = IndexElement(None)
+ self.sequenceElement.replaceCurrentSelection(self, indexElement)
+ index = indexElement.requireLowerRight()
+
+ index.moveRight(self, index.parent)
+
+
+ def addTextElement(self, char):
+ textElement = TextElement(self.sequenceElement, QString(char))
+ self.sequenceElement.insertChild(self, textElement)
+
+
+ def handleKey(self, keyEvent):
+ action = keyEvent.key()
+ state = keyEvent.state()
+ char = keyEvent.text().at(0)
+
+ self.mouseMarkFlag = 0
+
+ if char.isPrint():
+ #self.sequenceElement.handleKey(self, char)
+ latin1 = char.latin1()
+ if latin1 == '[':
+ #addBracketElement("[]")
+ pass
+ elif latin1 == '(':
+ #addBracketElement(DEFAULT_DELIMITER)
+ pass
+ elif latin1 == '|':
+ #addBracketElement("||")
+ pass
+ elif latin1 == '/':
+ #addFractionElement(DEFAULT_FRACTION)
+ pass
+ elif latin1 == '@':
+ #addRootElement()
+ pass
+ elif latin1 == '^':
+ self.addUpperRightIndex()
+ elif latin1 == '_':
+ self.addLowerRightIndex()
+ elif latin1 == ' ':
+ # no space allowed.
+ pass
+ else:
+ self.addTextElement(char)
+
+ else:
+
+ if Qt.Key_BackSpace == action:
+ self.sequenceElement.removeChildBefore(self)
+ return
+ elif Qt.Key_Delete == action:
+ self.sequenceElement.removeChildAt(self)
+ return
+
+ self.selectionFlag = state & Qt.ShiftButton
+ if Qt.Key_Left == action:
+ if state & Qt.ControlButton:
+ self.sequenceElement.moveHome(self)
+ else:
+ self.sequenceElement.moveLeft(self, self.sequenceElement)
+ elif Qt.Key_Right == action:
+ if state & Qt.ControlButton:
+ self.sequenceElement.moveEnd(self)
+ else:
+ self.sequenceElement.moveRight(self, self.sequenceElement)
+ elif Qt.Key_Up == action:
+ self.sequenceElement.moveUp(self, self.sequenceElement)
+ elif Qt.Key_Down == action:
+ self.sequenceElement.moveDown(self, self.sequenceElement)
+ elif Qt.Key_Home == action:
+ self.sequenceElement.formula().moveHome(self)
+ elif Qt.Key_End == action:
+ self.sequenceElement.formula().moveEnd(self)
+
+ # Qt.Key_PageUp, Qt.Key_PageDown,
+
+
+ def handleMousePress(self, mouseEvent):
+ formula = self.sequenceElement.formula()
+ element = formula.elementAt(mouseEvent.pos(), QPoint(0, 0))
+ if element != None:
+ if element.parent != None:
+ element.moveLeft(self, element.parent)
+ self.selectionFlag = 0
+ self.mouseMarkFlag = 1
+ self.setMarkPos(self.pos())
+ #else:
+ # self.set(formula, 0)
+
+ def handleMouseRelease(self, mouseEvent):
+ self.mouseMarkFlag = 0
+
+ def handleMouseMove(self, mouseEvent):
+ self.selectionFlag = 1
+ formula = self.sequenceElement.formula()
+ element = formula.elementAt(mouseEvent.pos(), QPoint(0, 0))
+ if element != None:
+ if element.parent != None:
+ element.parent.moveLeft(self, element)
+
+
+ def elementRemoved(self, element):
+ """The cursor must not be inside a leaf which gets cut off.
+ We assume the FormulaElement will never be removed."""
+ e = self.sequenceElement
+ while e != None:
+ if e == element:
+ # This is meant to catch all cursors that did not
+ # cause the deletion.
+ e.parent.moveRight(self, e)
+ self.sequenceElement.moveHome(self)
+ return
+ e = e.parent
+
+
+class StyleContext:
+ """Contains all variable information that are needed to
+ draw a formula."""
+
+ def __init__(self):
+ self.font = QFont("helvetica", 18)
+
+ def setupPainter(self, painter):
+ painter.setFont(self.font)
+ painter.setPen(Qt.black)
+
+ def fontMetrics(self):
+ return QFontMetrics(self.font)
+
+
+class Widget(QWidget):
+ """The widget that contains a formula."""
+
+ def __init__(self):
+ QWidget.__init__(self)
+ f = self.formula = FormulaElement(self)
+ self.cursor = Cursor(self.formula)
+ self.styleContext = StyleContext()
+
+ # Test data
+ f.addChild(TextElement(f, "y"))
+ f.addChild(TextElement(f, "="))
+
+ s1 = SequenceElement(f)
+ s1.addChild(TextElement(s1, "e"))
+
+ i1 = IndexElement(s1)
+ f.addChild(i1)
+
+ s2 = i1.requireUpperRight()
+ s2.addChild(TextElement(s2, "-"))
+ s2.addChild(TextElement(s2, "o"))
+ s2.addChild(TextElement(s2, "t"))
+
+ f.addChild(TextElement(f, "("))
+ f.addChild(TextElement(f, "s"))
+ f.addChild(TextElement(f, "i"))
+ f.addChild(TextElement(f, "n"))
+ f.addChild(TextElement(f, "("))
+ f.addChild(TextElement(f, "x"))
+ f.addChild(TextElement(f, ")"))
+ f.addChild(TextElement(f, ")"))
+
+ s3 = SequenceElement(f)
+ s3.addChild(TextElement(s3, "+"))
+ s3.addChild(TextElement(s3, "f"))
+ s3.addChild(TextElement(s3, "u"))
+ s3.addChild(TextElement(s3, "n"))
+
+ i2 = IndexElement(s3)
+ i2.requireUpperLeft()
+ i2.requireUpperRight()
+ i2.requireLowerLeft()
+ i2.requireLowerRight()
+
+ f.addChild(i2)
+
+ f.addChild(TextElement(f, ":"))
+ f.addChild(TextElement(f, "-"))
+ f.addChild(TextElement(f, ")"))
+
+ s4 = SequenceElement(f)
+ s4.addChild(TextElement(s4, "#"))
+
+ i3 = IndexElement(s4)
+
+ s5 = i3.requireUpperLeft()
+ s5.addChild(TextElement(s5, "u"))
+ s6 = i3.requireLowerLeft()
+ s6.addChild(TextElement(s6, "d"))
+
+ f.addChild(i3)
+
+ self.changedFlag = 1
+
+
+ def changed(self):
+ """Gets called each time the formula changes."""
+ self.changedFlag = 1
+
+
+ def elementRemoved(self, element):
+ """The element is going to go real soon."""
+ self.cursor.elementRemoved(element)
+
+
+ def paintEvent (self, e):
+
+ if self.changedFlag:
+ # You need to use the same StyleContext you use for drawing.
+ self.formula.calcSizes(self.styleContext)
+ self.changedFlag = 0
+
+ painter = QPainter()
+ painter.begin(self)
+ try:
+ self.formula.draw(painter, self.styleContext, QPoint(0, 0))
+ self.cursor.draw(painter)
+ finally:
+ painter.end()
+
+
+ def keyPressEvent(self, e):
+ self.cursor.handleKey(e)
+ self.update()
+
+ def mousePressEvent(self, e):
+ self.cursor.handleMousePress(e)
+ self.update()
+
+ def mouseReleaseEvent(self, e):
+ self.cursor.handleMouseRelease(e)
+ self.update()
+
+ def mouseDoubleClickEvent(self, e):
+ pass
+
+ def mouseMoveEvent(self, e):
+ self.cursor.handleMouseMove(e)
+ self.update()
+
diff --git a/lib/kformula/prototype/gensymbolfontmap.py b/lib/kformula/prototype/gensymbolfontmap.py
new file mode 100644
index 00000000..a1373815
--- /dev/null
+++ b/lib/kformula/prototype/gensymbolfontmap.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python
+
+import time
+from xml.sax import saxutils, handler, make_parser
+
+unicodetable = { "normal":{}, "bold":{}, "italic":{},
+ "slant":{}, "boldItalic":{} }
+fonttable = {}
+
+class ContentGenerator(handler.ContentHandler):
+
+ def __init__(self):
+ handler.ContentHandler.__init__(self)
+ self.font = None
+
+ def startElement(self, name, attrs):
+ if name == 'unicodetable':
+ self.font = None
+ for (name, value) in attrs.items():
+ if name == "font" and value:
+ self.font = value
+ if value not in fonttable:
+ fonttable[value] = []
+ elif self.font and name == 'entry':
+ number = ''
+ for (name, value) in attrs.items():
+ if name == "key": key = int(value)
+ elif name == "number": number = value
+ elif name == "name": latexName = value
+ elif name == "class": charClass = value
+ elif name == "style": style = value
+
+ if number != '':
+ unicodetable[style][number] = (latexName, charClass)
+ fonttable[self.font].append((key, number, style))
+
+def fontkey(font, style, number):
+ for mapping in fonttable[font]:
+ k, n, s = mapping
+ if s == style and n == number:
+ return k
+
+
+def writeFontTable(fontname, f):
+ f.write('\n\nstatic InternFontTable ' + fontname + 'Map[] = {\n')
+ for style in unicodetable:
+ for key in unicodetable[style]:
+ latexName, charClass = unicodetable[style][key]
+ pos = fontkey(fontname, style, key)
+ if pos:
+ f.write(' { ' + key + ', ' + hex(pos) + ', ' + charClass + ', ' + style + 'Char },\n')
+ f.write(' { 0, 0, ORDINARY, normalChar }\n};\n\n')
+
+
+def write_header(f):
+ print >>f, '''//
+// Created: ''' + time.ctime(time.time()) + '''
+// by: gensymbolfontmap.py
+// from: symbol.xml
+//
+// WARNING! All changes made in this file will be lost!
+'''
+
+def main():
+ f = open('../symbolfontmapping.cc', 'w')
+ write_header(f)
+ writeFontTable("symbol", f)
+ f.close()
+
+ f = open('../esstixfontmapping.cc', 'w')
+ write_header(f)
+ fontnames = [ "esstixnine",
+ "esstixthirteen",
+ "esstixeleven",
+ "esstixfourteen",
+ "esstixfive",
+ "esstixfifteen",
+ "esstixeight",
+ "esstixthree",
+ "esstixten",
+ "esstixsixteen",
+ "esstixone",
+ "esstixtwo",
+ "esstixsix",
+ "esstixseven",
+ "esstixtwelve",
+ "esstixseventeen",
+ "esstixfour" ]
+ for fn in fontnames:
+ writeFontTable(fn, f)
+ f.close()
+
+ f = open('../cmmapping.cc', 'w')
+ write_header(f)
+ fontnames = [ "cmbx10",
+ "cmex10",
+ "cmmi10",
+ "cmr10",
+ #"cmsl10",
+ "cmsy10",
+ #"cmti10",
+ #"cmtt10",
+ "msam10",
+ "msbm10"
+ ]
+ for fn in fontnames:
+ writeFontTable(fn, f)
+ f.close()
+
+ f = open('../unicodenames.cc', 'w')
+ write_header(f)
+ print >>f, 'struct UnicodeNameTable { short unicode; const char* name; };'
+ print >>f, 'static UnicodeNameTable nameTable[] = {'
+ nameDir = {}
+ table = {}
+ for style in unicodetable:
+ table.update(unicodetable[style])
+
+ for key in table:
+ latexName, charClass = table[key]
+ if len(latexName) > 0:
+ #for fn in fontnames:
+ # if fontkey(fn, style, key):
+ print >>f, ' { ' + key + ', "' + latexName + '" },'
+ #break
+ print >>f, ' { 0, 0 }\n};'
+ f.close()
+
+
+
+def make_unicode_table():
+ header = []
+ codes = {}
+ f = open('../config/unicode.tbl', 'r')
+ for line in f.xreadlines():
+ if line[0] == '#':
+ header.append(line.strip())
+ else:
+ break
+ for line in f.xreadlines():
+ if len(line) > 0:
+ codes[line.split(',')[0].strip()] = line
+ f.close()
+
+ for key in unicodetable:
+ latexName, charClass = unicodetable[key]
+ if len(latexName) > 0:
+ codes[key] = key + ', ' + charClass + ', ' + latexName.replace('\\', '')
+ else:
+ codes[key] = key + ', ' + charClass
+
+ f = open('../config/unicode.tbl', 'w')
+ for line in header:
+ print >> f, line
+ for key in codes:
+ print >> f, codes[key]
+ f.close()
+
+def make_font_table(font):
+## header = []
+## try:
+## f = open('../config/' + font + '.font', 'r')
+## for line in f.xreadlines():
+## if line[0] == '#':
+## header.append(line.strip())
+## else:
+## break
+## f.close()
+## except IOError:
+## pass
+
+ #f = open('../config/' + font + '.font', 'w')
+ f = open(font + '.font', 'w')
+## for line in header:
+## print >> f, line
+ #print >> f, "name = " + font
+ for key in unicodetable:
+ latexName, charClass = unicodetable[key]
+ pos = fontkey(font, key)
+ if pos:
+ print >> f, str(pos), key, charClass, latexName
+ f.close()
+
+def make_all_font_tables():
+ for font in fonttable:
+ make_font_table(font)
+
+
+def symbol_entry(pos, unicode, charClass, name):
+ return ' <entry key="%d" number="%s" name="%s" class="%s"/>' % \
+ (pos, unicode, name, charClass)
+
+
+def compare_font(font):
+ for line in file(font+".font"):
+ list = line.split()
+ pos = int(list[0])
+ unicode = list[1]
+ charClass = list[2]
+ if len(list)>3:
+ name = list[3]
+ else:
+ name = ""
+
+ if (pos, unicode) not in fonttable[font]:
+ print "not in font", font, (pos, unicode)
+ print symbol_entry(pos, unicode, charClass, name)
+ if unicode not in unicodetable:
+ print font, unicode, (name, charClass)
+ print symbol_entry(pos, unicode, charClass, name)
+ elif unicodetable[unicode] != (name, charClass):
+ print font, unicode, pos, unicodetable[unicode], "!=", (name, charClass)
+
+def compare():
+ fontnames = [ "symbol",
+ "esstixnine",
+ "esstixthirteen",
+ "esstixeleven",
+ "esstixfourteen",
+ "esstixfive",
+ "esstixfifteen",
+ "esstixeight",
+ "esstixthree",
+ "esstixten",
+ "esstixsixteen",
+ "esstixone",
+ "esstixtwo",
+ "esstixsix",
+ "esstixseven",
+ "esstixtwelve",
+ "esstixseventeen",
+ "esstixfour" ]
+
+ for font in fontnames:
+ compare_font(font)
+
+
+if __name__ == '__main__':
+ parser = make_parser()
+ parser.setContentHandler(ContentGenerator())
+ parser.parse("symbol.xml")
+
+ #print fonttable
+ #print unicodetable
+
+ #compare()
+
+ main()
+ #make_unicode_table()
+ #make_all_font_tables()
diff --git a/lib/kformula/prototype/main.py b/lib/kformula/prototype/main.py
new file mode 100755
index 00000000..49425b92
--- /dev/null
+++ b/lib/kformula/prototype/main.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+import sys
+from qt import *
+
+from engine import Widget
+
+a = QApplication(sys.argv)
+mw = Widget()
+mw.setCaption('Prototype of the formula engine')
+mw.show()
+a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()'))
+a.exec_loop()
diff --git a/lib/kformula/prototype/symbol.xml b/lib/kformula/prototype/symbol.xml
new file mode 100644
index 00000000..b18c5a26
--- /dev/null
+++ b/lib/kformula/prototype/symbol.xml
@@ -0,0 +1,2375 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<table>
+ <unicodetable font="cmbx10">
+ <entry key="161" number="0x0393" class="ORDINARY" name="Gamma" style="bold"/>
+ <entry key="162" number="0x0394" class="ORDINARY" name="Delta" style="bold"/>
+ <entry key="163" number="0x0398" class="ORDINARY" name="Theta" style="bold"/>
+ <entry key="164" number="0x039B" class="ORDINARY" name="Lambda" style="bold"/>
+ <entry key="165" number="0x039E" class="ORDINARY" name="Xi" style="bold"/>
+ <entry key="166" number="0x03A0" class="ORDINARY" name="Pi" style="bold"/>
+ <entry key="167" number="0x03A3" class="ORDINARY" name="Sigma" style="bold"/>
+ <entry key="168" number="0x03D2" class="ORDINARY" name="Upsilon" style="bold"/>
+ <entry key="169" number="0x03A6" class="ORDINARY" name="Phi" style="bold"/>
+ <entry key="170" number="0x03A8" class="ORDINARY" name="Psi" style="bold"/>
+ <entry key="173" number="0x03A9" class="ORDINARY" name="Omega" style="bold"/>
+ </unicodetable>
+ <unicodetable font="cmex10">
+ <entry key="48" number="0xF8EB" class="ORDINARY" name="" style="normal"/>
+ <entry key="49" number="0xF8F6" class="ORDINARY" name="" style="normal"/>
+ <entry key="50" number="0xF8EE" class="ORDINARY" name="" style="normal"/>
+ <entry key="51" number="0xF8F9" class="ORDINARY" name="" style="normal"/>
+ <entry key="52" number="0xF8F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="53" number="0xF8FB" class="ORDINARY" name="" style="normal"/>
+ <entry key="54" number="0xF8EF" class="ORDINARY" name="" style="normal"/>
+ <entry key="55" number="0xF8FA" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0xF8F1" class="ORDINARY" name="" style="normal"/>
+ <entry key="57" number="0xF8FC" class="ORDINARY" name="" style="normal"/>
+ <entry key="58" number="0xF8F3" class="ORDINARY" name="" style="normal"/>
+ <entry key="59" number="0xF8FE" class="ORDINARY" name="" style="normal"/>
+ <entry key="60" number="0xF8F2" class="ORDINARY" name="" style="normal"/>
+ <entry key="61" number="0xF8FD" class="ORDINARY" name="" style="normal"/>
+ <entry key="62" number="0xF8F4" class="ORDINARY" name="" style="normal"/>
+ <entry key="64" number="0xF8ED" class="ORDINARY" name="" style="normal"/>
+ <entry key="65" number="0xF8F8" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0xF8EC" class="ORDINARY" name="" style="normal"/>
+ <entry key="67" number="0xF8F7" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x2211" class="ORDINARY" name="sum" style="normal"/>
+ <entry key="81" number="0x220F" class="ORDINARY" name="prod" style="normal"/>
+ <entry key="82" number="0x222B" class="ORDINARY" name="int" style="normal"/>
+ </unicodetable>
+ <unicodetable font="cmmi10">
+ <entry key="32" number="0x0020" class="ORDINARY" name="" style="italic"/>
+ <entry key="33" number="0x03C9" class="ORDINARY" name="omega" style="italic"/>
+ <entry key="34" number="0x03B5" class="ORDINARY" name="varepsilon" style="italic"/>
+ <entry key="35" number="0x03D1" class="ORDINARY" name="vartheta" style="italic"/>
+ <entry key="36" number="0x03D6" class="ORDINARY" name="varpi" style="italic"/>
+ <entry key="37" number="0x03F1" class="ORDINARY" name="varrho" style="italic"/>
+ <entry key="38" number="0x03C2" class="ORDINARY" name="varsigma" style="italic"/>
+ <entry key="39" number="0x03D5" class="ORDINARY" name="varphi" style="italic"/>
+ <entry key="40" number="0x21BC" class="ORDINARY" name="leftharpoonup" style="italic"/>
+ <entry key="41" number="0x21BD" class="ORDINARY" name="leftharpoondown" style="italic"/>
+ <entry key="42" number="0x21C0" class="ORDINARY" name="rightharpoonup" style="italic"/>
+ <entry key="43" number="0x21C1" class="ORDINARY" name="rightharpoondown" style="italic"/>
+ <entry key="44" number="0x02BF" class="ORDINARY" name="" style="italic"/>
+ <entry key="45" number="0x02BE" class="ORDINARY" name="" style="italic"/>
+ <entry key="46" number="0x22B3" class="ORDINARY" name="vartriangleright" style="italic"/>
+ <entry key="47" number="0x22B2" class="ORDINARY" name="vartriangleleft" style="italic"/>
+ <entry key="48" number="0x0030" class="ORDINARY" name="" style="italic"/>
+ <entry key="49" number="0x0031" class="ORDINARY" name="" style="italic"/>
+ <entry key="50" number="0x0032" class="ORDINARY" name="" style="italic"/>
+ <entry key="51" number="0x0033" class="ORDINARY" name="" style="italic"/>
+ <entry key="52" number="0x0034" class="ORDINARY" name="" style="italic"/>
+ <entry key="53" number="0x0035" class="ORDINARY" name="" style="italic"/>
+ <entry key="54" number="0x0036" class="ORDINARY" name="" style="italic"/>
+ <entry key="55" number="0x0037" class="ORDINARY" name="" style="italic"/>
+ <entry key="56" number="0x0038" class="ORDINARY" name="" style="italic"/>
+ <entry key="57" number="0x0039" class="ORDINARY" name="" style="italic"/>
+ <entry key="58" number="0x002E" class="ORDINARY" name="" style="italic"/>
+ <entry key="59" number="0x002C" class="ORDINARY" name="" style="italic"/>
+ <entry key="60" number="0x003C" class="ORDINARY" name="less" style="italic"/>
+ <entry key="61" number="0x002F" class="ORDINARY" name="" style="italic"/>
+ <entry key="62" number="0x003E" class="ORDINARY" name="greater" style="italic"/>
+ <entry key="63" number="0x22C6" class="ORDINARY" name="star" style="italic"/>
+ <entry key="64" number="0x2202" class="ORDINARY" name="partial" style="italic"/>
+ <entry key="65" number="0x0041" class="ORDINARY" name="" style="italic"/>
+ <entry key="66" number="0x0042" class="ORDINARY" name="" style="italic"/>
+ <entry key="67" number="0x0043" class="ORDINARY" name="" style="italic"/>
+ <entry key="68" number="0x0044" class="ORDINARY" name="" style="italic"/>
+ <entry key="69" number="0x0045" class="ORDINARY" name="" style="italic"/>
+ <entry key="70" number="0x0046" class="ORDINARY" name="" style="italic"/>
+ <entry key="71" number="0x0047" class="ORDINARY" name="" style="italic"/>
+ <entry key="72" number="0x0048" class="ORDINARY" name="" style="italic"/>
+ <entry key="73" number="0x0049" class="ORDINARY" name="" style="italic"/>
+ <entry key="74" number="0x004A" class="ORDINARY" name="" style="italic"/>
+ <entry key="75" number="0x004B" class="ORDINARY" name="" style="italic"/>
+ <entry key="76" number="0x004C" class="ORDINARY" name="" style="italic"/>
+ <entry key="77" number="0x004D" class="ORDINARY" name="" style="italic"/>
+ <entry key="78" number="0x004E" class="ORDINARY" name="" style="italic"/>
+ <entry key="79" number="0x004F" class="ORDINARY" name="" style="italic"/>
+ <entry key="80" number="0x0050" class="ORDINARY" name="" style="italic"/>
+ <entry key="81" number="0x0051" class="ORDINARY" name="" style="italic"/>
+ <entry key="82" number="0x0052" class="ORDINARY" name="" style="italic"/>
+ <entry key="83" number="0x0053" class="ORDINARY" name="" style="italic"/>
+ <entry key="84" number="0x0054" class="ORDINARY" name="" style="italic"/>
+ <entry key="85" number="0x0055" class="ORDINARY" name="" style="italic"/>
+ <entry key="86" number="0x0056" class="ORDINARY" name="" style="italic"/>
+ <entry key="87" number="0x0057" class="ORDINARY" name="" style="italic"/>
+ <entry key="88" number="0x0058" class="ORDINARY" name="" style="italic"/>
+ <entry key="89" number="0x0059" class="ORDINARY" name="" style="italic"/>
+ <entry key="90" number="0x005A" class="ORDINARY" name="" style="italic"/>
+ <entry key="91" number="0x266D" class="ORDINARY" name="flat" style="italic"/>
+ <entry key="92" number="0x266E" class="ORDINARY" name="natural" style="italic"/>
+ <entry key="93" number="0x266F" class="ORDINARY" name="sharp" style="italic"/>
+ <entry key="94" number="0x2323" class="ORDINARY" name="" style="italic"/>
+ <entry key="95" number="0x2322" class="ORDINARY" name="" style="italic"/>
+ <entry key="96" number="0x2113" class="ORDINARY" name="" style="italic"/>
+ <entry key="97" number="0x0061" class="ORDINARY" name="" style="italic"/>
+ <entry key="98" number="0x0062" class="ORDINARY" name="" style="italic"/>
+ <entry key="99" number="0x0063" class="ORDINARY" name="" style="italic"/>
+ <entry key="100" number="0x0064" class="ORDINARY" name="" style="italic"/>
+ <entry key="101" number="0x0065" class="ORDINARY" name="" style="italic"/>
+ <entry key="102" number="0x0066" class="ORDINARY" name="" style="italic"/>
+ <entry key="103" number="0x0067" class="ORDINARY" name="" style="italic"/>
+ <entry key="104" number="0x0068" class="ORDINARY" name="" style="italic"/>
+ <entry key="105" number="0x0069" class="ORDINARY" name="" style="italic"/>
+ <entry key="106" number="0x006A" class="ORDINARY" name="" style="italic"/>
+ <entry key="107" number="0x006B" class="ORDINARY" name="" style="italic"/>
+ <entry key="108" number="0x006C" class="ORDINARY" name="" style="italic"/>
+ <entry key="109" number="0x006D" class="ORDINARY" name="" style="italic"/>
+ <entry key="110" number="0x006E" class="ORDINARY" name="" style="italic"/>
+ <entry key="111" number="0x006F" class="ORDINARY" name="" style="italic"/>
+ <entry key="112" number="0x0070" class="ORDINARY" name="" style="italic"/>
+ <entry key="113" number="0x0071" class="ORDINARY" name="" style="italic"/>
+ <entry key="114" number="0x0072" class="ORDINARY" name="" style="italic"/>
+ <entry key="115" number="0x0073" class="ORDINARY" name="" style="italic"/>
+ <entry key="116" number="0x0074" class="ORDINARY" name="" style="italic"/>
+ <entry key="117" number="0x0075" class="ORDINARY" name="" style="italic"/>
+ <entry key="118" number="0x0076" class="ORDINARY" name="" style="italic"/>
+ <entry key="119" number="0x0077" class="ORDINARY" name="" style="italic"/>
+ <entry key="120" number="0x0078" class="ORDINARY" name="" style="italic"/>
+ <entry key="121" number="0x0079" class="ORDINARY" name="" style="italic"/>
+ <entry key="122" number="0x007A" class="ORDINARY" name="" style="italic"/>
+ <entry key="123" number="0x0131" class="ORDINARY" name="" style="italic"/>
+ <entry key="124" number="0xED02" class="ORDINARY" name="" style="italic"/>
+ <entry key="125" number="0x2118" class="ORDINARY" name="wp" style="italic"/>
+ <entry key="126" number="0x20D7" class="ORDINARY" name="vec" style="italic"/>
+ <entry key="160" number="0x00A0" class="ORDINARY" name="" style="italic"/>
+ <entry key="161" number="0x0393" class="ORDINARY" name="Gamma" style="italic"/>
+ <entry key="162" number="0x0394" class="ORDINARY" name="Delta" style="italic"/>
+ <entry key="163" number="0x0398" class="ORDINARY" name="Theta" style="italic"/>
+ <entry key="164" number="0x039B" class="ORDINARY" name="Lambda" style="italic"/>
+ <entry key="165" number="0x039E" class="ORDINARY" name="Xi" style="italic"/>
+ <entry key="166" number="0x03A0" class="ORDINARY" name="Pi" style="italic"/>
+ <entry key="167" number="0x03A3" class="ORDINARY" name="Sigma" style="italic"/>
+ <entry key="168" number="0x03D2" class="ORDINARY" name="Upsilon" style="italic"/>
+ <entry key="169" number="0x03A6" class="ORDINARY" name="Phi" style="italic"/>
+ <entry key="170" number="0x03A8" class="ORDINARY" name="Psi" style="italic"/>
+ <entry key="173" number="0x03A9" class="ORDINARY" name="Omega" style="italic"/>
+ <entry key="174" number="0x03B1" class="ORDINARY" name="alpha" style="italic"/>
+ <entry key="175" number="0x03B2" class="ORDINARY" name="beta" style="italic"/>
+ <entry key="176" number="0x03B3" class="ORDINARY" name="gamma" style="italic"/>
+ <entry key="177" number="0x03B4" class="ORDINARY" name="delta" style="italic"/>
+ <entry key="179" number="0x03B6" class="ORDINARY" name="zeta" style="italic"/>
+ <entry key="180" number="0x03B7" class="ORDINARY" name="eta" style="italic"/>
+ <entry key="181" number="0x03B8" class="ORDINARY" name="theta" style="italic"/>
+ <entry key="182" number="0x03B9" class="ORDINARY" name="iota" style="italic"/>
+ <entry key="183" number="0x03BA" class="ORDINARY" name="kappa" style="italic"/>
+ <entry key="184" number="0x03BB" class="ORDINARY" name="lambda" style="italic"/>
+ <entry key="185" number="0x03BC" class="ORDINARY" name="mu" style="italic"/>
+ <entry key="186" number="0x03BD" class="ORDINARY" name="nu" style="italic"/>
+ <entry key="187" number="0x03BE" class="ORDINARY" name="xi" style="italic"/>
+ <entry key="188" number="0x03C0" class="ORDINARY" name="pi" style="italic"/>
+ <entry key="189" number="0x03C1" class="ORDINARY" name="rho" style="italic"/>
+ <entry key="190" number="0x03C3" class="ORDINARY" name="sigma" style="italic"/>
+ <entry key="191" number="0x03C4" class="ORDINARY" name="tau" style="italic"/>
+ <entry key="192" number="0x03C5" class="ORDINARY" name="upsilon" style="italic"/>
+ <entry key="193" number="0x03C6" class="ORDINARY" name="phi" style="italic"/>
+ <entry key="194" number="0x03C7" class="ORDINARY" name="chi" style="italic"/>
+ <entry key="195" number="0x03C8" class="ORDINARY" name="psi" style="italic"/>
+ <entry key="196" number="0x2040" class="ORDINARY" name="" style="italic"/>
+ </unicodetable>
+ <unicodetable font="cmr10">
+ <entry key="32" number="0x0020" class="ORDINARY" name="" style="normal"/>
+ <entry key="33" number="0x0021" class="ORDINARY" name="" style="normal"/>
+ <entry key="34" number="0x201D" class="ORDINARY" name="" style="normal"/>
+ <entry key="35" number="0x0023" class="ORDINARY" name="" style="normal"/>
+ <entry key="36" number="0x0024" class="ORDINARY" name="" style="normal"/>
+ <entry key="37" number="0x0025" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0x0026" class="ORDINARY" name="" style="normal"/>
+ <entry key="39" number="0x2019" class="ORDINARY" name="" style="normal"/>
+ <entry key="40" number="0x0028" class="ORDINARY" name="" style="normal"/>
+ <entry key="41" number="0x0029" class="ORDINARY" name="" style="normal"/>
+ <entry key="42" number="0x002A" class="ORDINARY" name="" style="normal"/>
+ <entry key="43" number="0x002B" class="ORDINARY" name="" style="normal"/>
+ <entry key="44" number="0x002C" class="ORDINARY" name="" style="normal"/>
+ <entry key="45" number="0x002D" class="ORDINARY" name="" style="normal"/>
+ <entry key="46" number="0x002E" class="ORDINARY" name="" style="normal"/>
+ <entry key="47" number="0x002F" class="ORDINARY" name="" style="normal"/>
+ <entry key="48" number="0x0030" class="ORDINARY" name="" style="normal"/>
+ <entry key="49" number="0x0031" class="ORDINARY" name="" style="normal"/>
+ <entry key="50" number="0x0032" class="ORDINARY" name="" style="normal"/>
+ <entry key="51" number="0x0033" class="ORDINARY" name="" style="normal"/>
+ <entry key="52" number="0x0034" class="ORDINARY" name="" style="normal"/>
+ <entry key="53" number="0x0035" class="ORDINARY" name="" style="normal"/>
+ <entry key="54" number="0x0036" class="ORDINARY" name="" style="normal"/>
+ <entry key="55" number="0x0037" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0x0038" class="ORDINARY" name="" style="normal"/>
+ <entry key="57" number="0x0039" class="ORDINARY" name="" style="normal"/>
+ <entry key="58" number="0x003A" class="ORDINARY" name="colon" style="normal"/>
+ <entry key="59" number="0x003B" class="ORDINARY" name="" style="normal"/>
+ <entry key="60" number="0x00A1" class="ORDINARY" name="textexclamdown" style="normal"/>
+ <entry key="61" number="0x003D" class="ORDINARY" name="" style="normal"/>
+ <entry key="62" number="0x00BF" class="ORDINARY" name="textquestiondown" style="normal"/>
+ <entry key="63" number="0x003F" class="ORDINARY" name="" style="normal"/>
+ <entry key="64" number="0x0040" class="ORDINARY" name="" style="normal"/>
+ <entry key="65" number="0x0041" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0x0042" class="ORDINARY" name="" style="normal"/>
+ <entry key="67" number="0x0043" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0x0044" class="ORDINARY" name="" style="normal"/>
+ <entry key="69" number="0x0045" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0x0046" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0x0047" class="ORDINARY" name="" style="normal"/>
+ <entry key="72" number="0x0048" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x0049" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0x004A" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0x004B" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0x004C" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0x004D" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0x004E" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0x004F" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x0050" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0x0051" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0x0052" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0x0053" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0x0054" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0x0055" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0x0056" class="ORDINARY" name="" style="normal"/>
+ <entry key="87" number="0x0057" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0x0058" class="ORDINARY" name="" style="normal"/>
+ <entry key="89" number="0x0059" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0x005A" class="ORDINARY" name="" style="normal"/>
+ <entry key="91" number="0x005B" class="ORDINARY" name="" style="normal"/>
+ <entry key="92" number="0x201C" class="ORDINARY" name="" style="normal"/>
+ <entry key="93" number="0x005D" class="ORDINARY" name="" style="normal"/>
+ <entry key="94" number="0x005E" class="ORDINARY" name="textasciicircum" style="normal"/>
+ <entry key="95" number="0x0307" class="ORDINARY" name="" style="normal"/>
+ <entry key="96" number="0x2018" class="ORDINARY" name="" style="normal"/>
+ <entry key="97" number="0x0061" class="ORDINARY" name="" style="normal"/>
+ <entry key="98" number="0x0062" class="ORDINARY" name="" style="normal"/>
+ <entry key="99" number="0x0063" class="ORDINARY" name="" style="normal"/>
+ <entry key="100" number="0x0064" class="ORDINARY" name="" style="normal"/>
+ <entry key="101" number="0x0065" class="ORDINARY" name="" style="normal"/>
+ <entry key="102" number="0x0066" class="ORDINARY" name="" style="normal"/>
+ <entry key="103" number="0x0067" class="ORDINARY" name="" style="normal"/>
+ <entry key="104" number="0x0068" class="ORDINARY" name="" style="normal"/>
+ <entry key="105" number="0x0069" class="ORDINARY" name="" style="normal"/>
+ <entry key="106" number="0x006A" class="ORDINARY" name="" style="normal"/>
+ <entry key="107" number="0x006B" class="ORDINARY" name="" style="normal"/>
+ <entry key="108" number="0x006C" class="ORDINARY" name="" style="normal"/>
+ <entry key="109" number="0x006D" class="ORDINARY" name="" style="normal"/>
+ <entry key="110" number="0x006E" class="ORDINARY" name="" style="normal"/>
+ <entry key="111" number="0x006F" class="ORDINARY" name="" style="normal"/>
+ <entry key="112" number="0x0070" class="ORDINARY" name="" style="normal"/>
+ <entry key="113" number="0x0071" class="ORDINARY" name="" style="normal"/>
+ <entry key="114" number="0x0072" class="ORDINARY" name="" style="normal"/>
+ <entry key="115" number="0x0073" class="ORDINARY" name="" style="normal"/>
+ <entry key="116" number="0x0074" class="ORDINARY" name="" style="normal"/>
+ <entry key="117" number="0x0075" class="ORDINARY" name="" style="normal"/>
+ <entry key="118" number="0x0076" class="ORDINARY" name="" style="normal"/>
+ <entry key="119" number="0x0077" class="ORDINARY" name="" style="normal"/>
+ <entry key="120" number="0x0078" class="ORDINARY" name="" style="normal"/>
+ <entry key="121" number="0x0079" class="ORDINARY" name="" style="normal"/>
+ <entry key="122" number="0x007A" class="ORDINARY" name="" style="normal"/>
+ <entry key="123" number="0x2013" class="ORDINARY" name="endash" style="normal"/>
+ <entry key="124" number="0x2014" class="ORDINARY" name="emdash" style="normal"/>
+ <entry key="125" number="0x2033" class="ORDINARY" name="" style="normal"/>
+ <entry key="126" number="0x0303" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0x0393" class="ORDINARY" name="Gamma" style="normal"/>
+ <entry key="162" number="0x0394" class="ORDINARY" name="Delta" style="normal"/>
+ <entry key="163" number="0x0398" class="ORDINARY" name="Theta" style="normal"/>
+ <entry key="164" number="0x039B" class="ORDINARY" name="Lambda" style="normal"/>
+ <entry key="165" number="0x039E" class="ORDINARY" name="Xi" style="normal"/>
+ <entry key="166" number="0x03A0" class="ORDINARY" name="Pi" style="normal"/>
+ <entry key="167" number="0x03A3" class="ORDINARY" name="Sigma" style="normal"/>
+ <entry key="168" number="0x03D2" class="ORDINARY" name="Upsilon" style="normal"/>
+ <entry key="169" number="0x03A6" class="ORDINARY" name="Phi" style="normal"/>
+ <entry key="170" number="0x03A8" class="ORDINARY" name="Psi" style="normal"/>
+ <entry key="173" number="0x03A9" class="ORDINARY" name="Omega" style="normal"/>
+ <entry key="174" number="0xFB00" class="ORDINARY" name="" style="normal"/>
+ <entry key="175" number="0xFB01" class="ORDINARY" name="" style="normal"/>
+ <entry key="176" number="0xFB02" class="ORDINARY" name="" style="normal"/>
+ <entry key="177" number="0xFB03" class="ORDINARY" name="" style="normal"/>
+ <entry key="178" number="0xFB04" class="ORDINARY" name="" style="normal"/>
+ <entry key="179" number="0x0131" class="ORDINARY" name="" style="normal"/>
+ <entry key="180" number="0xED02" class="ORDINARY" name="" style="normal"/>
+ <entry key="181" number="0x0301" class="ORDINARY" name="acute" style="normal"/>
+ <entry key="182" number="0x0302" class="ORDINARY" name="hat" style="normal"/>
+ <entry key="183" number="0x030C" class="ORDINARY" name="" style="normal"/>
+ <entry key="184" number="0x0306" class="ORDINARY" name="" style="normal"/>
+ <entry key="185" number="0x0304" class="ORDINARY" name="bar" style="normal"/>
+ <entry key="186" number="0x030A" class="ORDINARY" name="ocirc" style="normal"/>
+ <entry key="187" number="0x0327" class="ORDINARY" name="" style="normal"/>
+ <entry key="188" number="0x00DF" class="ORDINARY" name="" style="normal"/>
+ <entry key="189" number="0x00E6" class="ORDINARY" name="" style="normal"/>
+ <entry key="190" number="0x0153" class="ORDINARY" name="" style="normal"/>
+ <entry key="191" number="0x00F8" class="ORDINARY" name="o" style="normal"/>
+ <entry key="192" number="0x00C6" class="ORDINARY" name="" style="normal"/>
+ <entry key="193" number="0x0152" class="ORDINARY" name="" style="normal"/>
+ <entry key="194" number="0x00D8" class="ORDINARY" name="O" style="normal"/>
+ <entry key="196" number="0x0308" class="ORDINARY" name="" style="normal"/>
+ </unicodetable>
+ <unicodetable font="cmsl10">
+ <entry key="33" number="0x0021" class="ORDINARY" name="" style="slant"/>
+ <entry key="34" number="0x201D" class="ORDINARY" name="" style="slant"/>
+ <entry key="35" number="0x0023" class="ORDINARY" name="" style="slant"/>
+ <entry key="36" number="0x0024" class="ORDINARY" name="" style="slant"/>
+ <entry key="37" number="0x0025" class="ORDINARY" name="" style="slant"/>
+ <entry key="38" number="0x0026" class="ORDINARY" name="" style="slant"/>
+ <entry key="39" number="0x2019" class="ORDINARY" name="" style="slant"/>
+ <entry key="40" number="0x0028" class="ORDINARY" name="" style="slant"/>
+ <entry key="41" number="0x0029" class="ORDINARY" name="" style="slant"/>
+ <entry key="42" number="0x002A" class="ORDINARY" name="" style="slant"/>
+ <entry key="43" number="0x002B" class="ORDINARY" name="" style="slant"/>
+ <entry key="44" number="0x002C" class="ORDINARY" name="" style="slant"/>
+ <entry key="45" number="0x002D" class="ORDINARY" name="" style="slant"/>
+ <entry key="46" number="0x002E" class="ORDINARY" name="" style="slant"/>
+ <entry key="47" number="0x002F" class="ORDINARY" name="" style="slant"/>
+ <entry key="48" number="0x0030" class="ORDINARY" name="" style="slant"/>
+ <entry key="49" number="0x0031" class="ORDINARY" name="" style="slant"/>
+ <entry key="50" number="0x0032" class="ORDINARY" name="" style="slant"/>
+ <entry key="51" number="0x0033" class="ORDINARY" name="" style="slant"/>
+ <entry key="52" number="0x0034" class="ORDINARY" name="" style="slant"/>
+ <entry key="53" number="0x0035" class="ORDINARY" name="" style="slant"/>
+ <entry key="54" number="0x0036" class="ORDINARY" name="" style="slant"/>
+ <entry key="55" number="0x0037" class="ORDINARY" name="" style="slant"/>
+ <entry key="56" number="0x0038" class="ORDINARY" name="" style="slant"/>
+ <entry key="57" number="0x0039" class="ORDINARY" name="" style="slant"/>
+ <entry key="58" number="0x003A" class="ORDINARY" name="colon" style="slant"/>
+ <entry key="59" number="0x003B" class="ORDINARY" name="" style="slant"/>
+ <entry key="60" number="0x003C" class="ORDINARY" name="less" style="slant"/>
+ <entry key="61" number="0x003D" class="ORDINARY" name="" style="slant"/>
+ <entry key="62" number="0x003E" class="ORDINARY" name="greater" style="slant"/>
+ <entry key="63" number="0x003F" class="ORDINARY" name="" style="slant"/>
+ <entry key="64" number="0x0040" class="ORDINARY" name="" style="slant"/>
+ <entry key="65" number="0x0041" class="ORDINARY" name="" style="slant"/>
+ <entry key="66" number="0x0042" class="ORDINARY" name="" style="slant"/>
+ <entry key="67" number="0x0043" class="ORDINARY" name="" style="slant"/>
+ <entry key="68" number="0x0044" class="ORDINARY" name="" style="slant"/>
+ <entry key="69" number="0x0045" class="ORDINARY" name="" style="slant"/>
+ <entry key="70" number="0x0046" class="ORDINARY" name="" style="slant"/>
+ <entry key="71" number="0x0047" class="ORDINARY" name="" style="slant"/>
+ <entry key="72" number="0x0048" class="ORDINARY" name="" style="slant"/>
+ <entry key="73" number="0x0049" class="ORDINARY" name="" style="slant"/>
+ <entry key="74" number="0x004A" class="ORDINARY" name="" style="slant"/>
+ <entry key="75" number="0x004B" class="ORDINARY" name="" style="slant"/>
+ <entry key="76" number="0x004C" class="ORDINARY" name="" style="slant"/>
+ <entry key="77" number="0x004D" class="ORDINARY" name="" style="slant"/>
+ <entry key="78" number="0x004E" class="ORDINARY" name="" style="slant"/>
+ <entry key="79" number="0x004F" class="ORDINARY" name="" style="slant"/>
+ <entry key="80" number="0x0050" class="ORDINARY" name="" style="slant"/>
+ <entry key="81" number="0x0051" class="ORDINARY" name="" style="slant"/>
+ <entry key="82" number="0x0052" class="ORDINARY" name="" style="slant"/>
+ <entry key="83" number="0x0053" class="ORDINARY" name="" style="slant"/>
+ <entry key="84" number="0x0054" class="ORDINARY" name="" style="slant"/>
+ <entry key="85" number="0x0055" class="ORDINARY" name="" style="slant"/>
+ <entry key="86" number="0x0056" class="ORDINARY" name="" style="slant"/>
+ <entry key="87" number="0x0057" class="ORDINARY" name="" style="slant"/>
+ <entry key="88" number="0x0058" class="ORDINARY" name="" style="slant"/>
+ <entry key="89" number="0x0059" class="ORDINARY" name="" style="slant"/>
+ <entry key="90" number="0x005A" class="ORDINARY" name="" style="slant"/>
+ <entry key="91" number="0x005B" class="ORDINARY" name="" style="slant"/>
+ <entry key="92" number="0x201C" class="ORDINARY" name="" style="slant"/>
+ <entry key="93" number="0x005D" class="ORDINARY" name="" style="slant"/>
+ <entry key="94" number="0x005E" class="ORDINARY" name="textasciicircum" style="slant"/>
+ <entry key="95" number="0x0307" class="ORDINARY" name="" style="slant"/>
+ <entry key="96" number="0x2018" class="ORDINARY" name="" style="slant"/>
+ <entry key="97" number="0xF180" class="ORDINARY" name="" style="slant"/>
+ <entry key="98" number="0x0299" class="ORDINARY" name="" style="slant"/>
+ <entry key="99" number="0xF182" class="ORDINARY" name="" style="slant"/>
+ <entry key="100" number="0xF183" class="ORDINARY" name="" style="slant"/>
+ <entry key="101" number="0xF184" class="ORDINARY" name="" style="slant"/>
+ <entry key="102" number="0xF185" class="ORDINARY" name="" style="slant"/>
+ <entry key="103" number="0x0262" class="ORDINARY" name="" style="slant"/>
+ <entry key="104" number="0x029C" class="ORDINARY" name="" style="slant"/>
+ <entry key="105" number="0x026A" class="ORDINARY" name="" style="slant"/>
+ <entry key="106" number="0xF189" class="ORDINARY" name="" style="slant"/>
+ <entry key="107" number="0xF18A" class="ORDINARY" name="" style="slant"/>
+ <entry key="108" number="0x029F" class="ORDINARY" name="" style="slant"/>
+ <entry key="109" number="0xF18C" class="ORDINARY" name="" style="slant"/>
+ <entry key="110" number="0x0274" class="ORDINARY" name="" style="slant"/>
+ <entry key="111" number="0xF18E" class="ORDINARY" name="" style="slant"/>
+ <entry key="112" number="0xF18F" class="ORDINARY" name="" style="slant"/>
+ <entry key="113" number="0xF190" class="ORDINARY" name="" style="slant"/>
+ <entry key="114" number="0x0280" class="ORDINARY" name="" style="slant"/>
+ <entry key="115" number="0xF192" class="ORDINARY" name="" style="slant"/>
+ <entry key="116" number="0xF193" class="ORDINARY" name="" style="slant"/>
+ <entry key="117" number="0xF194" class="ORDINARY" name="" style="slant"/>
+ <entry key="118" number="0xF195" class="ORDINARY" name="" style="slant"/>
+ <entry key="119" number="0xF196" class="ORDINARY" name="" style="slant"/>
+ <entry key="120" number="0xF197" class="ORDINARY" name="" style="slant"/>
+ <entry key="121" number="0x028F" class="ORDINARY" name="" style="slant"/>
+ <entry key="122" number="0xF199" class="ORDINARY" name="" style="slant"/>
+ <entry key="123" number="0x2013" class="ORDINARY" name="endash" style="slant"/>
+ <entry key="124" number="0x2014" class="ORDINARY" name="emdash" style="slant"/>
+ <entry key="125" number="0x2033" class="ORDINARY" name="" style="slant"/>
+ <entry key="126" number="0x0303" class="ORDINARY" name="" style="slant"/>
+ <entry key="160" number="0x0020" class="ORDINARY" name="" style="slant"/>
+ <entry key="161" number="0x0393" class="ORDINARY" name="Gamma" style="slant"/>
+ <entry key="162" number="0x0394" class="ORDINARY" name="Delta" style="slant"/>
+ <entry key="163" number="0x0398" class="ORDINARY" name="Theta" style="slant"/>
+ <entry key="164" number="0x039B" class="ORDINARY" name="Lambda" style="slant"/>
+ <entry key="165" number="0x039E" class="ORDINARY" name="Xi" style="slant"/>
+ <entry key="166" number="0x03A0" class="ORDINARY" name="Pi" style="slant"/>
+ <entry key="167" number="0x03A3" class="ORDINARY" name="Sigma" style="slant"/>
+ <entry key="168" number="0x03D2" class="ORDINARY" name="Upsilon" style="slant"/>
+ <entry key="169" number="0x03A6" class="ORDINARY" name="Phi" style="slant"/>
+ <entry key="170" number="0x03A8" class="ORDINARY" name="Psi" style="slant"/>
+ <entry key="173" number="0x03A9" class="ORDINARY" name="Omega" style="slant"/>
+ <entry key="179" number="0x0131" class="ORDINARY" name="" style="slant"/>
+ <entry key="180" number="0xED02" class="ORDINARY" name="" style="slant"/>
+ <entry key="181" number="0x0300" class="ORDINARY" name="grave" style="slant"/>
+ <entry key="182" number="0x0301" class="ORDINARY" name="acute" style="slant"/>
+ <entry key="183" number="0x030C" class="ORDINARY" name="" style="slant"/>
+ <entry key="184" number="0x0306" class="ORDINARY" name="" style="slant"/>
+ <entry key="185" number="0x0305" class="ORDINARY" name="" style="slant"/>
+ <entry key="186" number="0x030A" class="ORDINARY" name="ocirc" style="slant"/>
+ <entry key="187" number="0x0327" class="ORDINARY" name="" style="slant"/>
+ <entry key="188" number="0xF19B" class="ORDINARY" name="" style="slant"/>
+ <entry key="189" number="0xF19A" class="ORDINARY" name="" style="slant"/>
+ <entry key="190" number="0x0276" class="ORDINARY" name="" style="slant"/>
+ <entry key="191" number="0xF19C" class="ORDINARY" name="" style="slant"/>
+ <entry key="192" number="0x00C6" class="ORDINARY" name="" style="slant"/>
+ <entry key="193" number="0x0152" class="ORDINARY" name="" style="slant"/>
+ <entry key="194" number="0x00D8" class="ORDINARY" name="O" style="slant"/>
+ <entry key="195" number="0xF700" class="ORDINARY" name="" style="slant"/>
+ <entry key="196" number="0x0308" class="ORDINARY" name="" style="slant"/>
+ </unicodetable>
+ <unicodetable font="cmsy10">
+ <entry key="32" number="0x0020" class="ORDINARY" name="" style="normal"/>
+ <entry key="33" number="0x2192" class="RELATION" name="rightarrow" style="normal"/>
+ <entry key="34" number="0x2191" class="RELATION" name="uparrow" style="normal"/>
+ <entry key="35" number="0x2193" class="RELATION" name="downarrow" style="normal"/>
+ <entry key="36" number="0x2194" class="RELATION" name="leftrightarrow" style="normal"/>
+ <entry key="37" number="0x2197" class="ORDINARY" name="nearrow" style="normal"/>
+ <entry key="38" number="0x2198" class="ORDINARY" name="searrow" style="normal"/>
+ <entry key="39" number="0x2243" class="RELATION" name="simeq" style="normal"/>
+ <entry key="40" number="0x21D0" class="RELATION" name="Leftarrow" style="normal"/>
+ <entry key="41" number="0x21D2" class="RELATION" name="Rightarrow" style="normal"/>
+ <entry key="42" number="0x21D1" class="RELATION" name="Uparrow" style="normal"/>
+ <entry key="43" number="0x21D3" class="RELATION" name="Downarrow" style="normal"/>
+ <entry key="44" number="0x21D4" class="RELATION" name="Leftrightarrow" style="normal"/>
+ <entry key="45" number="0x2196" class="ORDINARY" name="nwarrow" style="normal"/>
+ <entry key="46" number="0x2199" class="ORDINARY" name="swarrow" style="normal"/>
+ <entry key="47" number="0x221D" class="RELATION" name="propto" style="normal"/>
+ <entry key="48" number="0x2032" class="ORDINARY" name="prime" style="normal"/>
+ <entry key="49" number="0x221E" class="ORDINARY" name="infty" style="normal"/>
+ <entry key="50" number="0x2208" class="RELATION" name="in" style="normal"/>
+ <entry key="51" number="0x220B" class="RELATION" name="ni" style="normal"/>
+ <entry key="52" number="0x25B3" class="ORDINARY" name="bigtriangleup" style="normal"/>
+ <entry key="53" number="0x25BD" class="ORDINARY" name="bigtriangledown" style="normal"/>
+ <entry key="54" number="0x0338" class="ORDINARY" name="not" style="normal"/>
+ <entry key="55" number="0x22A6" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0x2200" class="ORDINARY" name="forall" style="normal"/>
+ <entry key="57" number="0x2203" class="ORDINARY" name="exists" style="normal"/>
+ <entry key="58" number="0x00AC" class="ORDINARY" name="neg" style="normal"/>
+ <entry key="59" number="0x2205" class="BINOP" name="oslash" style="normal"/>
+ <entry key="60" number="0x211C" class="ORDINARY" name="Re" style="normal"/>
+ <entry key="61" number="0x2111" class="ORDINARY" name="Im" style="normal"/>
+ <entry key="62" number="0x22A4" class="ORDINARY" name="top" style="normal"/>
+ <entry key="63" number="0x22A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="64" number="0x2135" class="ORDINARY" name="aleph" style="normal"/>
+ <entry key="65" number="0xF100" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0x212C" class="ORDINARY" name="" style="normal"/>
+ <entry key="67" number="0xF102" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0xF103" class="ORDINARY" name="" style="normal"/>
+ <entry key="69" number="0x2130" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0x2131" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0xF106" class="ORDINARY" name="" style="normal"/>
+ <entry key="72" number="0x210B" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x2110" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0xF109" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0xF10A" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0x2112" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0x2133" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0xF10D" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0xF10E" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x2118" class="ORDINARY" name="wp" style="normal"/>
+ <entry key="81" number="0xF110" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0x211B" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0xF112" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0xF113" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0xF114" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0xF115" class="ORDINARY" name="" style="normal"/>
+ <entry key="87" number="0xF116" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0xF117" class="ORDINARY" name="" style="normal"/>
+ <entry key="89" number="0xF118" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0xF119" class="ORDINARY" name="" style="normal"/>
+ <entry key="91" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="92" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="93" number="0x228E" class="ORDINARY" name="uplus" style="normal"/>
+ <entry key="94" number="0x2227" class="BINOP" name="wedge" style="normal"/>
+ <entry key="95" number="0x2228" class="BINOP" name="vee" style="normal"/>
+ <entry key="96" number="0x22A2" class="ORDINARY" name="" style="normal"/>
+ <entry key="97" number="0x22A3" class="ORDINARY" name="dashv" style="normal"/>
+ <entry key="98" number="0x230A" class="ORDINARY" name="lfloor" style="normal"/>
+ <entry key="99" number="0x230B" class="ORDINARY" name="rfloor" style="normal"/>
+ <entry key="100" number="0x2308" class="ORDINARY" name="lceil" style="normal"/>
+ <entry key="101" number="0x2309" class="ORDINARY" name="rceil" style="normal"/>
+ <entry key="102" number="0x007B" class="ORDINARY" name="lbrace" style="normal"/>
+ <entry key="103" number="0x007D" class="ORDINARY" name="rbrace" style="normal"/>
+ <entry key="104" number="0x2329" class="ORDINARY" name="langle" style="normal"/>
+ <entry key="105" number="0x232A" class="ORDINARY" name="rangle" style="normal"/>
+ <entry key="106" number="0x2223" class="ORDINARY" name="" style="normal"/>
+ <entry key="107" number="0x2225" class="ORDINARY" name="" style="normal"/>
+ <entry key="108" number="0x2195" class="ORDINARY" name="updownarrow" style="normal"/>
+ <entry key="109" number="0x21D5" class="ORDINARY" name="Updownarrow" style="normal"/>
+ <entry key="110" number="0x005C" class="ORDINARY" name="backslash" style="normal"/>
+ <entry key="111" number="0x2240" class="ORDINARY" name="wr" style="normal"/>
+ <entry key="112" number="0x221A" class="ORDINARY" name="surd" style="normal"/>
+ <entry key="113" number="0x2210" class="ORDINARY" name="coprod" style="normal"/>
+ <entry key="114" number="0x2207" class="ORDINARY" name="nabla" style="normal"/>
+ <entry key="116" number="0x2294" class="ORDINARY" name="sqcup" style="normal"/>
+ <entry key="117" number="0x2293" class="ORDINARY" name="sqcap" style="normal"/>
+ <entry key="118" number="0x2291" class="RELATION" name="sqsubseteq" style="normal"/>
+ <entry key="119" number="0x2292" class="ORDINARY" name="sqsupseteq" style="normal"/>
+ <entry key="120" number="0x00A7" class="ORDINARY" name="S" style="normal"/>
+ <entry key="121" number="0x2020" class="ORDINARY" name="" style="normal"/>
+ <entry key="122" number="0x2021" class="ORDINARY" name="" style="normal"/>
+ <entry key="123" number="0x00B6" class="ORDINARY" name="P" style="normal"/>
+ <entry key="124" number="0x2663" class="ORDINARY" name="clubsuit" style="normal"/>
+ <entry key="125" number="0x2666" class="ORDINARY" name="diamondsuit" style="normal"/>
+ <entry key="126" number="0x2665" class="ORDINARY" name="heartsuit" style="normal"/>
+ <entry key="160" number="0x00A0" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0x2212" class="BINOP" name="minus" style="normal"/>
+ <entry key="162" number="0x22C5" class="BINOP" name="cdot" style="normal"/>
+ <entry key="163" number="0x00D7" class="BINOP" name="times" style="normal"/>
+ <entry key="164" number="0x2217" class="BINOP" name="ast" style="normal"/>
+ <entry key="165" number="0x00F7" class="BINOP" name="div" style="normal"/>
+ <entry key="166" number="0x22C4" class="ORDINARY" name="diamond" style="normal"/>
+ <entry key="167" number="0x00B1" class="BINOP" name="pm" style="normal"/>
+ <entry key="168" number="0x2213" class="ORDINARY" name="mp" style="normal"/>
+ <entry key="169" number="0x2295" class="BINOP" name="oplus" style="normal"/>
+ <entry key="170" number="0x2296" class="BINOP" name="ominus" style="normal"/>
+ <entry key="173" number="0x2297" class="BINOP" name="otimes" style="normal"/>
+ <entry key="174" number="0x2298" class="BINOP" name="oslash" style="normal"/>
+ <entry key="175" number="0x2299" class="ORDINARY" name="odot" style="normal"/>
+ <entry key="176" number="0x25CB" class="ORDINARY" name="bigcirc" style="normal"/>
+ <entry key="177" number="0x2218" class="ORDINARY" name="circ" style="normal"/>
+ <entry key="178" number="0x2219" class="BINOP" name="bullet" style="normal"/>
+ <entry key="179" number="0x224D" class="ORDINARY" name="asymp" style="normal"/>
+ <entry key="180" number="0x2261" class="RELATION" name="equiv" style="normal"/>
+ <entry key="181" number="0x2286" class="RELATION" name="subseteq" style="normal"/>
+ <entry key="182" number="0x2287" class="RELATION" name="supseteq" style="normal"/>
+ <entry key="183" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="184" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="185" number="0x227C" class="ORDINARY" name="preccurlyeq" style="normal"/>
+ <entry key="186" number="0x227D" class="ORDINARY" name="succcurlyeq" style="normal"/>
+ <entry key="187" number="0x223C" class="RELATION" name="sim" style="normal"/>
+ <entry key="188" number="0x2248" class="RELATION" name="approx" style="normal"/>
+ <entry key="189" number="0x2282" class="RELATION" name="subset" style="normal"/>
+ <entry key="190" number="0x2283" class="RELATION" name="supset" style="normal"/>
+ <entry key="191" number="0x226A" class="RELATION" name="ll" style="normal"/>
+ <entry key="192" number="0x226B" class="RELATION" name="gg" style="normal"/>
+ <entry key="193" number="0x227A" class="ORDINARY" name="prec" style="normal"/>
+ <entry key="194" number="0x227B" class="ORDINARY" name="succ" style="normal"/>
+ <entry key="195" number="0x2190" class="RELATION" name="leftarrow" style="normal"/>
+ <entry key="196" number="0x2660" class="ORDINARY" name="spadesuit" style="normal"/>
+ </unicodetable>
+ <unicodetable font="cmti10">
+ </unicodetable>
+ <unicodetable font="cmtt10">
+ <entry key="121" number="0x0079" class="ORDINARY" name="" style="normal"/>
+ <entry key="120" number="0x0078" class="ORDINARY" name="" style="normal"/>
+ <entry key="115" number="0x0073" class="ORDINARY" name="" style="normal"/>
+ <entry key="114" number="0x0072" class="ORDINARY" name="" style="normal"/>
+ <entry key="113" number="0x0071" class="ORDINARY" name="" style="normal"/>
+ <entry key="112" number="0x0070" class="ORDINARY" name="" style="normal"/>
+ <entry key="119" number="0x0077" class="ORDINARY" name="" style="normal"/>
+ <entry key="118" number="0x0076" class="ORDINARY" name="" style="normal"/>
+ <entry key="117" number="0x0075" class="ORDINARY" name="" style="normal"/>
+ <entry key="116" number="0x0074" class="ORDINARY" name="" style="normal"/>
+ <entry key="167" number="0x2208" class="RELATION" name="in" style="normal"/>
+ <entry key="178" number="0x2202" class="ORDINARY" name="partial" style="normal"/>
+ <entry key="184" number="0x2203" class="ORDINARY" name="exists" style="normal"/>
+ <entry key="183" number="0x2200" class="ORDINARY" name="forall" style="normal"/>
+ <entry key="124" number="0x007C" class="ORDINARY" name="vert" style="normal"/>
+ <entry key="123" number="0x007B" class="ORDINARY" name="lbrace" style="normal"/>
+ <entry key="122" number="0x007A" class="ORDINARY" name="" style="normal"/>
+ <entry key="126" number="0x007E" class="ORDINARY" name="textasciitilde" style="normal"/>
+ <entry key="125" number="0x007D" class="ORDINARY" name="rbrace" style="normal"/>
+ <entry key="175" number="0x00B1" class="BINOP" name="pm" style="normal"/>
+ <entry key="169" number="0x03BB" class="ORDINARY" name="lambda" style="normal"/>
+ <entry key="76" number="0x004C" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0x004A" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0x004F" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0x004D" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0x004E" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0x0042" class="ORDINARY" name="" style="normal"/>
+ <entry key="67" number="0x0043" class="ORDINARY" name="" style="normal"/>
+ <entry key="64" number="0x0040" class="ORDINARY" name="" style="normal"/>
+ <entry key="65" number="0x0041" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0x0046" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0x0047" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0x0044" class="ORDINARY" name="" style="normal"/>
+ <entry key="69" number="0x0045" class="ORDINARY" name="" style="normal"/>
+ <entry key="72" number="0x0048" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x0049" class="ORDINARY" name="" style="normal"/>
+ <entry key="173" number="0x03B4" class="ORDINARY" name="delta" style="normal"/>
+ <entry key="170" number="0x03B3" class="ORDINARY" name="gamma" style="normal"/>
+ <entry key="164" number="0x03B2" class="ORDINARY" name="beta" style="normal"/>
+ <entry key="163" number="0x03B1" class="ORDINARY" name="alpha" style="normal"/>
+ <entry key="180" number="0x2283" class="RELATION" name="supset" style="normal"/>
+ <entry key="188" number="0x2192" class="RELATION" name="rightarrow" style="normal"/>
+ <entry key="52" number="0x0034" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0x22C5" class="BINOP" name="cdot" style="normal"/>
+ <entry key="190" number="0x22C4" class="ORDINARY" name="diamond" style="normal"/>
+ <entry key="81" number="0x0051" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x0050" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0x0053" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0x0052" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0x0055" class="ORDINARY" name="" style="normal"/>
+ <entry key="87" number="0x0057" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0x0056" class="ORDINARY" name="" style="normal"/>
+ <entry key="89" number="0x0059" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0x0058" class="ORDINARY" name="" style="normal"/>
+ <entry key="189" number="0x2260" class="RELATION" name="neq" style="normal"/>
+ <entry key="193" number="0x2261" class="RELATION" name="equiv" style="normal"/>
+ <entry key="191" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="192" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="46" number="0x002E" class="ORDINARY" name="" style="normal"/>
+ <entry key="47" number="0x002F" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0x005A" class="ORDINARY" name="" style="normal"/>
+ <entry key="92" number="0x005C" class="ORDINARY" name="backslash" style="normal"/>
+ <entry key="91" number="0x005B" class="ORDINARY" name="" style="normal"/>
+ <entry key="94" number="0x005E" class="ORDINARY" name="textasciicircum" style="normal"/>
+ <entry key="93" number="0x005D" class="ORDINARY" name="" style="normal"/>
+ <entry key="95" number="0x005F" class="ORDINARY" name="" style="normal"/>
+ <entry key="179" number="0x2282" class="RELATION" name="subset" style="normal"/>
+ <entry key="176" number="0x2295" class="BINOP" name="oplus" style="normal"/>
+ <entry key="185" number="0x2297" class="BINOP" name="otimes" style="normal"/>
+ <entry key="162" number="0x2193" class="RELATION" name="downarrow" style="normal"/>
+ <entry key="187" number="0x2190" class="RELATION" name="leftarrow" style="normal"/>
+ <entry key="174" number="0x2191" class="RELATION" name="uparrow" style="normal"/>
+ <entry key="165" number="0x2227" class="BINOP" name="wedge" style="normal"/>
+ <entry key="42" number="0x002A" class="ORDINARY" name="" style="normal"/>
+ <entry key="43" number="0x002B" class="ORDINARY" name="" style="normal"/>
+ <entry key="44" number="0x002C" class="ORDINARY" name="" style="normal"/>
+ <entry key="194" number="0x2228" class="BINOP" name="vee" style="normal"/>
+ <entry key="181" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="177" number="0x221E" class="ORDINARY" name="infty" style="normal"/>
+ <entry key="40" number="0x0028" class="ORDINARY" name="" style="normal"/>
+ <entry key="41" number="0x0029" class="ORDINARY" name="" style="normal"/>
+ <entry key="182" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="196" number="0x222B" class="ORDINARY" name="int" style="normal"/>
+ <entry key="32" number="0x0020" class="ORDINARY" name="" style="normal"/>
+ <entry key="33" number="0x0021" class="ORDINARY" name="" style="normal"/>
+ <entry key="34" number="0x0022" class="ORDINARY" name="" style="normal"/>
+ <entry key="35" number="0x0023" class="ORDINARY" name="" style="normal"/>
+ <entry key="36" number="0x0024" class="ORDINARY" name="" style="normal"/>
+ <entry key="37" number="0x0025" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0x0026" class="ORDINARY" name="" style="normal"/>
+ <entry key="39" number="0x2019" class="ORDINARY" name="" style="normal"/>
+ <entry key="96" number="0x2018" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0x0054" class="ORDINARY" name="" style="normal"/>
+ <entry key="186" number="0x21C6" class="RELATION" name="leftrightarrows" style="normal"/>
+ <entry key="109" number="0x006D" class="ORDINARY" name="" style="normal"/>
+ <entry key="110" number="0x006E" class="ORDINARY" name="" style="normal"/>
+ <entry key="111" number="0x006F" class="ORDINARY" name="" style="normal"/>
+ <entry key="106" number="0x006A" class="ORDINARY" name="" style="normal"/>
+ <entry key="107" number="0x006B" class="ORDINARY" name="" style="normal"/>
+ <entry key="108" number="0x006C" class="ORDINARY" name="" style="normal"/>
+ <entry key="104" number="0x0068" class="ORDINARY" name="" style="normal"/>
+ <entry key="105" number="0x0069" class="ORDINARY" name="" style="normal"/>
+ <entry key="100" number="0x0064" class="ORDINARY" name="" style="normal"/>
+ <entry key="101" number="0x0065" class="ORDINARY" name="" style="normal"/>
+ <entry key="102" number="0x0066" class="ORDINARY" name="" style="normal"/>
+ <entry key="103" number="0x0067" class="ORDINARY" name="" style="normal"/>
+ <entry key="97" number="0x0061" class="ORDINARY" name="" style="normal"/>
+ <entry key="98" number="0x0062" class="ORDINARY" name="" style="normal"/>
+ <entry key="99" number="0x0063" class="ORDINARY" name="" style="normal"/>
+ <entry key="166" number="0x00AC" class="ORDINARY" name="neg" style="normal"/>
+ <entry key="45" number="0x002D" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0x004B" class="ORDINARY" name="" style="normal"/>
+ <entry key="55" number="0x0037" class="ORDINARY" name="" style="normal"/>
+ <entry key="54" number="0x0036" class="ORDINARY" name="" style="normal"/>
+ <entry key="53" number="0x0035" class="ORDINARY" name="" style="normal"/>
+ <entry key="51" number="0x0033" class="ORDINARY" name="" style="normal"/>
+ <entry key="50" number="0x0032" class="ORDINARY" name="" style="normal"/>
+ <entry key="49" number="0x0031" class="ORDINARY" name="" style="normal"/>
+ <entry key="48" number="0x0030" class="ORDINARY" name="" style="normal"/>
+ <entry key="57" number="0x0039" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0x0038" class="ORDINARY" name="" style="normal"/>
+ <entry key="168" number="0x03C0" class="ORDINARY" name="pi" style="normal"/>
+ <entry key="63" number="0x003F" class="ORDINARY" name="" style="normal"/>
+ <entry key="62" number="0x003E" class="ORDINARY" name="greater" style="normal"/>
+ <entry key="61" number="0x003D" class="ORDINARY" name="" style="normal"/>
+ <entry key="60" number="0x003C" class="ORDINARY" name="less" style="normal"/>
+ <entry key="59" number="0x003B" class="ORDINARY" name="" style="normal"/>
+ <entry key="58" number="0x003A" class="ORDINARY" name="colon" style="normal"/>
+ </unicodetable>
+ <unicodetable font="msam10">
+ <entry key="33" number="0x21AD" class="ORDINARY" name="leftrightsquigarrow" style="normal"/>
+ <entry key="34" number="0x21AB" class="ORDINARY" name="looparrowleft" style="normal"/>
+ <entry key="35" number="0x21AC" class="ORDINARY" name="looparrowright" style="normal"/>
+ <entry key="36" number="0x2257" class="RELATION" name="circeq" style="normal"/>
+ <entry key="37" number="0x227F" class="RELATION" name="succsim" style="normal"/>
+ <entry key="38" number="0x2273" class="RELATION" name="gtrsim" style="normal"/>
+ <entry key="39" number="0xE933" class="RELATION" name="gtrapprox" style="normal"/>
+ <entry key="40" number="0x22B8" class="ORDINARY" name="multimap" style="normal"/>
+ <entry key="41" number="0x2234" class="BINOP" name="therefore" style="normal"/>
+ <entry key="42" number="0x2235" class="BINOP" name="because" style="normal"/>
+ <entry key="43" number="0x2251" class="RELATION" name="Doteq" style="normal"/>
+ <entry key="44" number="0x225C" class="RELATION" name="triangleq" style="normal"/>
+ <entry key="45" number="0x2272" class="RELATION" name="lesssim" style="normal"/>
+ <entry key="46" number="0x2273" class="RELATION" name="gtrsim" style="normal"/>
+ <entry key="47" number="0xE932" class="RELATION" name="lessapprox" style="normal"/>
+ <entry key="48" number="0x22DC" class="RELATION" name="eqless" style="normal"/>
+ <entry key="49" number="0x22DD" class="RELATION" name="eqgtr" style="normal"/>
+ <entry key="50" number="0x22DE" class="RELATION" name="curlyeqprec" style="normal"/>
+ <entry key="51" number="0x22DF" class="RELATION" name="curlyeqsucc" style="normal"/>
+ <entry key="52" number="0x227C" class="RELATION" name="preccurlyeq" style="normal"/>
+ <entry key="53" number="0x2266" class="RELATION" name="leqq" style="normal"/>
+ <entry key="54" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="55" number="0x2276" class="RELATION" name="lessgtr" style="normal"/>
+ <entry key="56" number="0x2035" class="ORDINARY" name="backprime" style="normal"/>
+ <entry key="57" number="0xF8E7" class="ORDINARY" name="" style="normal"/>
+ <entry key="58" number="0x2253" class="RELATION" name="risingdotseq" style="normal"/>
+ <entry key="59" number="0x2252" class="RELATION" name="fallingdotseq" style="normal"/>
+ <entry key="60" number="0x227D" class="RELATION" name="succcurlyeq" style="normal"/>
+ <entry key="61" number="0x2267" class="RELATION" name="geqq" style="normal"/>
+ <entry key="62" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="63" number="0x2277" class="RELATION" name="gtrless" style="normal"/>
+ <entry key="64" number="0x228F" class="RELATION" name="sqsubset" style="normal"/>
+ <entry key="65" number="0x2290" class="RELATION" name="sqsupset" style="normal"/>
+ <entry key="66" number="0x22B3" class="RELATION" name="vartriangleright" style="normal"/>
+ <entry key="67" number="0x22B2" class="RELATION" name="vartriangleleft" style="normal"/>
+ <entry key="68" number="0x22B5" class="RELATION" name="trianglerighteq" style="normal"/>
+ <entry key="69" number="0x22B4" class="RELATION" name="trianglelefteq" style="normal"/>
+ <entry key="70" number="0x2605" class="ORDINARY" name="bigstar" style="normal"/>
+ <entry key="71" number="0x226C" class="BINOP" name="between" style="normal"/>
+ <entry key="72" number="0x25BC" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x25B6" class="RELATION" name="blacktriangleright" style="normal"/>
+ <entry key="74" number="0x25C0" class="RELATION" name="blacktriangleleft" style="normal"/>
+ <entry key="75" number="0xEB0E" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0xEB0D" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0x25B3" class="ORDINARY" name="bigtriangleup" style="normal"/>
+ <entry key="78" number="0x25B2" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0x25BD" class="ORDINARY" name="bigtriangledown" style="normal"/>
+ <entry key="80" number="0x2256" class="RELATION" name="eqcirc" style="normal"/>
+ <entry key="81" number="0x22DA" class="RELATION" name="lesseqgtr" style="normal"/>
+ <entry key="82" number="0x22DB" class="RELATION" name="gtreqless" style="normal"/>
+ <entry key="83" number="0xE922" class="RELATION" name="" style="normal"/>
+ <entry key="84" number="0xE92D" class="RELATION" name="" style="normal"/>
+ <entry key="85" number="0x00A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0x21DB" class="ORDINARY" name="Rrightarrow" style="normal"/>
+ <entry key="87" number="0x21DA" class="ORDINARY" name="Lleftarrow" style="normal"/>
+ <entry key="88" number="0x2713" class="ORDINARY" name="checkmark" style="normal"/>
+ <entry key="89" number="0x22BD" class="RELATION" name="" style="normal"/>
+ <entry key="90" number="0x22BC" class="RELATION" name="barwedge" style="normal"/>
+ <entry key="91" number="0x2306" class="RELATION" name="doublebarwedge ?" style="normal"/>
+ <entry key="92" number="0x2220" class="ORDINARY" name="angle" style="normal"/>
+ <entry key="93" number="0x2221" class="ORDINARY" name="measuredangle" style="normal"/>
+ <entry key="94" number="0x2222" class="ORDINARY" name="" style="normal"/>
+ <entry key="95" number="0x221D" class="RELATION" name="propto" style="normal"/>
+ <entry key="96" number="0x2323" class="ORDINARY" name="" style="normal"/>
+ <entry key="97" number="0x2322" class="ORDINARY" name="" style="normal"/>
+ <entry key="98" number="0x22D0" class="ORDINARY" name="Subset" style="normal"/>
+ <entry key="99" number="0x22D1" class="ORDINARY" name="Supset" style="normal"/>
+ <entry key="100" number="0x22D3" class="ORDINARY" name="Cup" style="normal"/>
+ <entry key="101" number="0x22D2" class="ORDINARY" name="Cap" style="normal"/>
+ <entry key="102" number="0x22CF" class="ORDINARY" name="curlywedge" style="normal"/>
+ <entry key="103" number="0x22CE" class="ORDINARY" name="curlyvee" style="normal"/>
+ <entry key="104" number="0x22CB" class="ORDINARY" name="leftthreetimes" style="normal"/>
+ <entry key="105" number="0x22CC" class="ORDINARY" name="rightthreetimes" style="normal"/>
+ <entry key="106" number="0xE90C" class="RELATION" name="" style="normal"/>
+ <entry key="107" number="0xE90B" class="RELATION" name="" style="normal"/>
+ <entry key="108" number="0x224F" class="RELATION" name="bumpeq" style="normal"/>
+ <entry key="109" number="0x224E" class="RELATION" name="Bumpeq" style="normal"/>
+ <entry key="110" number="0x22D8" class="RELATION" name="lll" style="normal"/>
+ <entry key="111" number="0x22D9" class="RELATION" name="ggg" style="normal"/>
+ <entry key="112" number="0x231C" class="ORDINARY" name="ulcorner" style="normal"/>
+ <entry key="113" number="0x231D" class="ORDINARY" name="urcorner" style="normal"/>
+ <entry key="114" number="0x00AE" class="ORDINARY" name="" style="normal"/>
+ <entry key="115" number="0x24C8" class="ORDINARY" name="circledS" style="normal"/>
+ <entry key="116" number="0x22D4" class="ORDINARY" name="pitchfork" style="normal"/>
+ <entry key="117" number="0x2214" class="BINOP" name="dotplus" style="normal"/>
+ <entry key="118" number="0x223D" class="RELATION" name="backsim" style="normal"/>
+ <entry key="119" number="0x22CD" class="RELATION" name="backsimeq" style="normal"/>
+ <entry key="120" number="0x231E" class="ORDINARY" name="llcorner" style="normal"/>
+ <entry key="121" number="0x231F" class="ORDINARY" name="lrcorner" style="normal"/>
+ <entry key="122" number="0x2720" class="ORDINARY" name="maltese" style="normal"/>
+ <entry key="123" number="0x2201" class="ORDINARY" name="complement" style="normal"/>
+ <entry key="124" number="0x22BA" class="ORDINARY" name="intercal" style="normal"/>
+ <entry key="125" number="0x229A" class="BINOP" name="circledcirc" style="normal"/>
+ <entry key="126" number="0x229B" class="BINOP" name="circledast" style="normal"/>
+ <entry key="161" number="0x22A1" class="BINOP" name="boxdot" style="normal"/>
+ <entry key="162" number="0x229E" class="BINOP" name="boxplus" style="normal"/>
+ <entry key="163" number="0x22A0" class="BINOP" name="boxtimes" style="normal"/>
+ <entry key="164" number="0x22A1" class="BINOP" name="boxdot" style="normal"/>
+ <entry key="165" number="0x25A0" class="BINOP" name="blacksquare" style="normal"/>
+ <entry key="166" number="0x25AA" class="ORDINARY" name="" style="normal"/>
+ <entry key="167" number="0x2662" class="BINOP" name="diamondsuit" style="normal"/>
+ <entry key="168" number="0x2666" class="BINOP" name="" style="normal"/>
+ <entry key="169" number="0x21BB" class="ORDINARY" name="cwopencirclearrow" style="normal"/>
+ <entry key="170" number="0x21BA" class="ORDINARY" name="acwopencirclearrow" style="normal"/>
+ <entry key="173" number="0x21CB" class="ORDINARY" name="leftrightharpoons" style="normal"/>
+ <entry key="174" number="0x21CA" class="ORDINARY" name="downdownarrows" style="normal"/>
+ <entry key="175" number="0x229F" class="BINOP" name="boxminus" style="normal"/>
+ <entry key="176" number="0x22A9" class="ORDINARY" name="Vdash" style="normal"/>
+ <entry key="177" number="0x22AA" class="ORDINARY" name="Vvdash" style="normal"/>
+ <entry key="178" number="0x22AB" class="ORDINARY" name="" style="normal"/>
+ <entry key="179" number="0x21A0" class="ORDINARY" name="twoheadrightarrow" style="normal"/>
+ <entry key="180" number="0x219E" class="ORDINARY" name="twoheadleftarrow" style="normal"/>
+ <entry key="181" number="0x21C7" class="ORDINARY" name="leftleftarrows" style="normal"/>
+ <entry key="182" number="0x21C9" class="ORDINARY" name="rightrightarrows" style="normal"/>
+ <entry key="183" number="0x21C8" class="ORDINARY" name="upuparrows" style="normal"/>
+ <entry key="184" number="0x21CA" class="ORDINARY" name="downdownarrows" style="normal"/>
+ <entry key="185" number="0x21BE" class="ORDINARY" name="upharpoonright" style="normal"/>
+ <entry key="186" number="0x21C2" class="ORDINARY" name="downharpoonright" style="normal"/>
+ <entry key="187" number="0x21BF" class="ORDINARY" name="upharpoonleft" style="normal"/>
+ <entry key="188" number="0x21C3" class="ORDINARY" name="downharpoonleft" style="normal"/>
+ <entry key="189" number="0x21A3" class="ORDINARY" name="rightarrowtail" style="normal"/>
+ <entry key="190" number="0x21A2" class="ORDINARY" name="leftarrowtail" style="normal"/>
+ <entry key="191" number="0x21C6" class="ORDINARY" name="leftrightarrows" style="normal"/>
+ <entry key="192" number="0x21C4" class="ORDINARY" name="rightleftarrows" style="normal"/>
+ <entry key="193" number="0x21B0" class="ORDINARY" name="Lsh" style="normal"/>
+ <entry key="194" number="0x21B1" class="ORDINARY" name="Rsh" style="normal"/>
+ <entry key="195" number="0x21DD" class="ORDINARY" name="rightzigzagarrow" style="normal"/>
+ <entry key="196" number="0x229D" class="BINOP" name="circleddash" style="normal"/>
+ </unicodetable>
+ <unicodetable font="msbm10">
+ <entry key="33" number="0xEA43" class="ORDINARY" name="" style="normal"/>
+ <entry key="34" number="0xEA0C" class="ORDINARY" name="" style="normal"/>
+ <entry key="35" number="0xEA0B" class="ORDINARY" name="" style="normal"/>
+ <entry key="36" number="0xEA44" class="ORDINARY" name="" style="normal"/>
+ <entry key="37" number="0xEA45" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0xEA46" class="ORDINARY" name="" style="normal"/>
+ <entry key="39" number="0xEA47" class="ORDINARY" name="" style="normal"/>
+ <entry key="40" number="0x228A" class="ORDINARY" name="subsetneq" style="normal"/>
+ <entry key="41" number="0x228B" class="ORDINARY" name="supsetneq" style="normal"/>
+ <entry key="42" number="0x2288" class="ORDINARY" name="nsubseteq" style="normal"/>
+ <entry key="43" number="0x2289" class="ORDINARY" name="nsupseteq" style="normal"/>
+ <entry key="44" number="0x2226" class="ORDINARY" name="" style="normal"/>
+ <entry key="45" number="0x2224" class="ORDINARY" name="" style="normal"/>
+ <entry key="46" number="0xEA2E" class="ORDINARY" name="" style="normal"/>
+ <entry key="47" number="0xEA2F" class="ORDINARY" name="" style="normal"/>
+ <entry key="48" number="0x22AC" class="ORDINARY" name="nvdash" style="normal"/>
+ <entry key="49" number="0x22AE" class="ORDINARY" name="nVdash" style="normal"/>
+ <entry key="50" number="0x22AD" class="ORDINARY" name="nvDash" style="normal"/>
+ <entry key="51" number="0x22AF" class="ORDINARY" name="nVDash" style="normal"/>
+ <entry key="52" number="0x22ED" class="ORDINARY" name="ntrianglerighteq" style="normal"/>
+ <entry key="53" number="0x22EC" class="ORDINARY" name="ntrianglelefteq" style="normal"/>
+ <entry key="54" number="0x22EA" class="ORDINARY" name="ntriangleleft" style="normal"/>
+ <entry key="55" number="0x22EB" class="ORDINARY" name="ntriangleright" style="normal"/>
+ <entry key="56" number="0x219A" class="ORDINARY" name="nleftarrow" style="normal"/>
+ <entry key="57" number="0x219B" class="ORDINARY" name="nrightarrow" style="normal"/>
+ <entry key="58" number="0x21CD" class="ORDINARY" name="nLeftarrow" style="normal"/>
+ <entry key="59" number="0x21CF" class="ORDINARY" name="nRightarrow" style="normal"/>
+ <entry key="60" number="0x21CE" class="ORDINARY" name="nLeftrightarrow" style="normal"/>
+ <entry key="61" number="0xEB0F" class="ORDINARY" name="" style="normal"/>
+ <entry key="62" number="0x22C7" class="ORDINARY" name="divideontimes" style="normal"/>
+ <entry key="63" number="0x2205" class="ORDINARY" name="" style="normal"/>
+ <entry key="64" number="0x2204" class="ORDINARY" name="nexists" style="normal"/>
+ <entry key="65" number="0xF080" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0xF081" class="ORDINARY" name="" style="normal"/>
+ <entry key="67" number="0x2102" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0xF083" class="ORDINARY" name="" style="normal"/>
+ <entry key="69" number="0xF084" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0xF085" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0xF086" class="ORDINARY" name="" style="normal"/>
+ <entry key="72" number="0x210D" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0xF088" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0xF089" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0xF08A" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0xF08B" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0xF08C" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0x2115" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0xF08E" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x2119" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0x211A" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0x211D" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0xF092" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0xF093" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0xF094" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0xF095" class="ORDINARY" name="" style="normal"/>
+ <entry key="87" number="0xF096" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0xF097" class="ORDINARY" name="" style="normal"/>
+ <entry key="89" number="0xF098" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0x2124" class="ORDINARY" name="" style="normal"/>
+ <entry key="91" number="0xEE08" class="ORDINARY" name="" style="normal"/>
+ <entry key="92" number="0xEE09" class="ORDINARY" name="" style="normal"/>
+ <entry key="93" number="0xEE05" class="ORDINARY" name="" style="normal"/>
+ <entry key="94" number="0xEE06" class="ORDINARY" name="" style="normal"/>
+ <entry key="96" number="0x2132" class="ORDINARY" name="Finv" style="normal"/>
+ <entry key="97" number="0xED01" class="ORDINARY" name="" style="normal"/>
+ <entry key="102" number="0x2127" class="ORDINARY" name="mho" style="normal"/>
+ <entry key="103" number="0x00F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="104" number="0x2242" class="ORDINARY" name="eqsim" style="normal"/>
+ <entry key="105" number="0x2136" class="ORDINARY" name="beth" style="normal"/>
+ <entry key="106" number="0x2137" class="ORDINARY" name="gimel" style="normal"/>
+ <entry key="107" number="0x2138" class="ORDINARY" name="daleth" style="normal"/>
+ <entry key="108" number="0x22D6" class="ORDINARY" name="lessdot" style="normal"/>
+ <entry key="109" number="0x22D7" class="ORDINARY" name="gtrdot" style="normal"/>
+ <entry key="110" number="0x22C9" class="ORDINARY" name="ltimes" style="normal"/>
+ <entry key="111" number="0x22CA" class="ORDINARY" name="rtimes" style="normal"/>
+ <entry key="112" number="0xE92E" class="ORDINARY" name="" style="normal"/>
+ <entry key="113" number="0xE92F" class="ORDINARY" name="" style="normal"/>
+ <entry key="114" number="0xFE68" class="ORDINARY" name="" style="normal"/>
+ <entry key="115" number="0x223C" class="ORDINARY" name="" style="normal"/>
+ <entry key="116" number="0x2248" class="ORDINARY" name="" style="normal"/>
+ <entry key="117" number="0x224A" class="ORDINARY" name="approxeq" style="normal"/>
+ <entry key="118" number="0xE93B" class="ORDINARY" name="" style="normal"/>
+ <entry key="119" number="0xE93A" class="ORDINARY" name="" style="normal"/>
+ <entry key="120" number="0x21B6" class="ORDINARY" name="curvearrowleft" style="normal"/>
+ <entry key="121" number="0x21B7" class="ORDINARY" name="curvearrowright" style="normal"/>
+ <entry key="122" number="0x03DC" class="ORDINARY" name="" style="normal"/>
+ <entry key="123" number="0x03F0" class="ORDINARY" name="varkappa" style="normal"/>
+ <entry key="124" number="0xF0A4" class="ORDINARY" name="" style="normal"/>
+ <entry key="125" number="0x210F" class="ORDINARY" name="" style="normal"/>
+ <entry key="126" number="0x210F" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0x2268" class="RELATION" name="" style="normal"/>
+ <entry key="162" number="0x2269" class="RELATION" name="" style="normal"/>
+ <entry key="163" number="0x2270" class="RELATION" name="nleq" style="normal"/>
+ <entry key="164" number="0x2271" class="RELATION" name="ngeq" style="normal"/>
+ <entry key="165" number="0x226E" class="RELATION" name="nless" style="normal"/>
+ <entry key="166" number="0x226F" class="RELATION" name="ngtr" style="normal"/>
+ <entry key="167" number="0x2280" class="RELATION" name="nprec" style="normal"/>
+ <entry key="168" number="0x2281" class="RELATION" name="nsucc" style="normal"/>
+ <entry key="169" number="0x2268" class="RELATION" name="" style="normal"/>
+ <entry key="170" number="0x2269" class="RELATION" name="" style="normal"/>
+ <entry key="173" number="0x2270" class="RELATION" name="nleq" style="normal"/>
+ <entry key="174" number="0x2271" class="RELATION" name="ngeq" style="normal"/>
+ <entry key="175" number="0xEA34" class="RELATION" name="" style="normal"/>
+ <entry key="176" number="0xEA35" class="RELATION" name="" style="normal"/>
+ <entry key="177" number="0xEA38" class="RELATION" name="" style="normal"/>
+ <entry key="178" number="0xEA39" class="RELATION" name="" style="normal"/>
+ <entry key="179" number="0x22E8" class="RELATION" name="precnsim" style="normal"/>
+ <entry key="180" number="0x22E9" class="RELATION" name="succnsim" style="normal"/>
+ <entry key="181" number="0x22E6" class="RELATION" name="lnsim" style="normal"/>
+ <entry key="182" number="0x22E7" class="RELATION" name="gnsim" style="normal"/>
+ <entry key="183" number="0xEA06" class="RELATION" name="" style="normal"/>
+ <entry key="184" number="0xEA07" class="RELATION" name="" style="normal"/>
+ <entry key="185" number="0xEA40" class="RELATION" name="" style="normal"/>
+ <entry key="186" number="0xEA41" class="RELATION" name="" style="normal"/>
+ <entry key="187" number="0xEA3A" class="RELATION" name="" style="normal"/>
+ <entry key="188" number="0xEA3B" class="RELATION" name="" style="normal"/>
+ <entry key="189" number="0xEA32" class="RELATION" name="" style="normal"/>
+ <entry key="190" number="0xEA33" class="RELATION" name="" style="normal"/>
+ <entry key="191" number="0x2241" class="RELATION" name="" style="normal"/>
+ <entry key="192" number="0x2247" class="RELATION" name="ncong" style="normal"/>
+ <entry key="193" number="0x2215" class="ORDINARY" name="slash" style="normal"/>
+ <entry key="194" number="0x2216" class="ORDINARY" name="" style="normal"/>
+ <entry key="195" number="0xEA42" class="RELATION" name="" style="normal"/>
+ <entry key="196" number="0x220D" class="ORDINARY" name="" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixeight">
+ <entry key="33" number="0xE201" class="RELATION" name="longleftarrow" style="normal"/>
+ <entry key="37" number="0xE205" class="RELATION" name="longrightarrow" style="normal"/>
+ <entry key="73" number="0xF8EE" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0xF8EF" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0xF8F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0xF8F9" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0xF8FA" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0xF8FB" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0xF8F1" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0xF8F4" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0xF8F2" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0xF8F3" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0xF8FC" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0xF8FD" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0xF8FE" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0xF8EB" class="ORDINARY" name="" style="normal"/>
+ <entry key="91" number="0xF8EC" class="ORDINARY" name="" style="normal"/>
+ <entry key="92" number="0xF8ED" class="ORDINARY" name="" style="normal"/>
+ <entry key="93" number="0xF8F6" class="ORDINARY" name="" style="normal"/>
+ <entry key="94" number="0xF8F7" class="ORDINARY" name="" style="normal"/>
+ <entry key="95" number="0xF8F8" class="ORDINARY" name="" style="normal"/>
+ <entry key="97" number="0x2320" class="ORDINARY" name="" style="normal"/>
+ <entry key="98" number="0xF8F5" class="ORDINARY" name="" style="normal"/>
+ <entry key="99" number="0x2321" class="ORDINARY" name="" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixeleven">
+ <entry key="50" number="0x03C2" class="ORDINARY" name="" style="boldItalic"/>
+ <entry key="51" number="0x03B5" class="ORDINARY" name="varepsilon" style="boldItalic"/>
+ <entry key="52" number="0x03D5" class="ORDINARY" name="varphi" style="boldItalic"/>
+ <entry key="54" number="0x03D6" class="ORDINARY" name="varpi" style="boldItalic"/>
+ <entry key="56" number="0x03F0" class="ORDINARY" name="varkappa" style="boldItalic"/>
+ <entry key="57" number="0x03F1" class="ORDINARY" name="varrho" style="boldItalic"/>
+ <entry key="68" number="0x0394" class="ORDINARY" name="Delta" style="boldItalic"/>
+ <entry key="70" number="0x03A6" class="ORDINARY" name="Phi" style="boldItalic"/>
+ <entry key="71" number="0x0393" class="ORDINARY" name="Gamma" style="boldItalic"/>
+ <entry key="74" number="0x03A8" class="ORDINARY" name="Psi" style="boldItalic"/>
+ <entry key="76" number="0x039B" class="ORDINARY" name="Lambda" style="boldItalic"/>
+ <entry key="80" number="0x03A0" class="ORDINARY" name="Pi" style="boldItalic"/>
+ <entry key="81" number="0x0398" class="ORDINARY" name="Theta" style="boldItalic"/>
+ <entry key="83" number="0x03A3" class="ORDINARY" name="Sigma" style="boldItalic"/>
+ <entry key="85" number="0x03A9" class="ORDINARY" name="Omega" style="boldItalic"/>
+ <entry key="86" number="0x2207" class="ORDINARY" name="nabla" style="boldItalic"/>
+ <entry key="88" number="0x039E" class="ORDINARY" name="Xi" style="boldItalic"/>
+ <entry key="89" number="0xE663" class="ORDINARY" name="Upsilon" style="boldItalic"/>
+ <entry key="91" number="0x2127" class="ORDINARY" name="mho" style="boldItalic"/>
+ <entry key="97" number="0x03B1" class="ORDINARY" name="alpha" style="boldItalic"/>
+ <entry key="98" number="0x03B2" class="ORDINARY" name="beta" style="boldItalic"/>
+ <entry key="99" number="0x03C7" class="ORDINARY" name="chi" style="boldItalic"/>
+ <entry key="100" number="0x03B4" class="ORDINARY" name="delta" style="boldItalic"/>
+ <entry key="101" number="0x03F5" class="ORDINARY" name="epsilon" style="boldItalic"/>
+ <entry key="102" number="0x03C6" class="ORDINARY" name="phi" style="boldItalic"/>
+ <entry key="103" number="0x03B3" class="ORDINARY" name="gamma" style="boldItalic"/>
+ <entry key="104" number="0x03B7" class="ORDINARY" name="eta" style="boldItalic"/>
+ <entry key="105" number="0x03B9" class="ORDINARY" name="iota" style="boldItalic"/>
+ <entry key="106" number="0x03C8" class="ORDINARY" name="psi" style="boldItalic"/>
+ <entry key="107" number="0x03BA" class="ORDINARY" name="kappa" style="boldItalic"/>
+ <entry key="108" number="0x03BB" class="ORDINARY" name="lambda" style="boldItalic"/>
+ <entry key="109" number="0x03BC" class="ORDINARY" name="mu" style="boldItalic"/>
+ <entry key="110" number="0x03BD" class="ORDINARY" name="nu" style="boldItalic"/>
+ <entry key="112" number="0x03C0" class="ORDINARY" name="pi" style="boldItalic"/>
+ <entry key="113" number="0x03B8" class="ORDINARY" name="theta" style="boldItalic"/>
+ <entry key="114" number="0x03C1" class="ORDINARY" name="rho" style="boldItalic"/>
+ <entry key="115" number="0x03C3" class="ORDINARY" name="sigma" style="boldItalic"/>
+ <entry key="116" number="0x03C4" class="ORDINARY" name="tau" style="boldItalic"/>
+ <entry key="117" number="0x03C9" class="ORDINARY" name="omega" style="boldItalic"/>
+ <entry key="118" number="0x2202" class="ORDINARY" name="partial" style="boldItalic"/>
+ <entry key="119" number="0x03D1" class="ORDINARY" name="" style="boldItalic"/>
+ <entry key="120" number="0x03BE" class="ORDINARY" name="xi" style="boldItalic"/>
+ <entry key="121" number="0x03C5" class="ORDINARY" name="upsilon" style="boldItalic"/>
+ <entry key="122" number="0x03B6" class="ORDINARY" name="zeta" style="boldItalic"/>
+ </unicodetable>
+ <unicodetable font="esstixfifteen">
+ <entry key="73" number="0x2111" class="ORDINARY" name="Im" style="normal"/>
+ <entry key="78" number="0x211C" class="ORDINARY" name="Re" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixfive">
+ <entry key="35" number="0x00D7" class="BINOP" name="times" style="normal"/>
+ <entry key="37" number="0x22C5" class="BINOP" name="cdot" style="normal"/>
+ <entry key="47" number="0x2298" class="BINOP" name="oslash" style="normal"/>
+ <entry key="49" number="0x2299" class="ORDINARY" name="odot" style="normal"/>
+ <entry key="50" number="0x2296" class="BINOP" name="ominus" style="normal"/>
+ <entry key="52" number="0x2295" class="BINOP" name="oplus" style="normal"/>
+ <entry key="53" number="0x2297" class="BINOP" name="otimes" style="normal"/>
+ <entry key="71" number="0x00B1" class="BINOP" name="pm" style="normal"/>
+ <entry key="72" number="0x2213" class="ORDINARY" name="mp" style="normal"/>
+ <entry key="79" number="0x00F7" class="BINOP" name="div" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixfour">
+ <entry key="46" number="0x2026" class="ORDINARY" name="ldots" style="normal"/>
+ <entry key="47" number="0x22EF" class="ORDINARY" name="cdots" style="normal"/>
+ <entry key="49" number="0x22F1" class="ORDINARY" name="ddots" style="normal"/>
+ <entry key="50" number="0x220A" class="RELATION" name="in" style="normal"/>
+ <entry key="51" number="0x2282" class="RELATION" name="subset" style="normal"/>
+ <entry key="52" number="0x2286" class="RELATION" name="subseteq" style="normal"/>
+ <entry key="53" number="0xE304" class="RELATION" name="subseteqq" style="normal"/>
+ <entry key="54" number="0x22D0" class="RELATION" name="Subset" style="normal"/>
+ <entry key="55" number="0x228F" class="RELATION" name="sqsubset" style="normal"/>
+ <entry key="56" number="0x2291" class="RELATION" name="sqsubseteq" style="normal"/>
+ <entry key="60" number="0x2284" class="RELATION" name="nsubset" style="normal"/>
+ <entry key="61" number="0x228A" class="RELATION" name="subsetneq" style="normal"/>
+ <entry key="62" number="0xE2B9" class="RELATION" name="varsubsetneq" style="normal"/>
+ <entry key="63" number="0x2288" class="RELATION" name="nsubseteq" style="normal"/>
+ <entry key="64" number="0xE2B6" class="RELATION" name="subsetneqq" style="normal"/>
+ <entry key="65" number="0xE2B8" class="RELATION" name="varsubsetneqq" style="normal"/>
+ <entry key="72" number="0x220B" class="RELATION" name="ni" style="normal"/>
+ <entry key="73" number="0x2283" class="RELATION" name="supset" style="normal"/>
+ <entry key="74" number="0x2287" class="RELATION" name="supseteq" style="normal"/>
+ <entry key="75" number="0xE305" class="RELATION" name="supseteqq" style="normal"/>
+ <entry key="76" number="0x22D1" class="RELATION" name="Supset" style="normal"/>
+ <entry key="77" number="0x2290" class="RELATION" name="sqsupset" style="normal"/>
+ <entry key="81" number="0x228B" class="RELATION" name="supsetneq" style="normal"/>
+ <entry key="82" number="0xE2BA" class="RELATION" name="varsupsetneq" style="normal"/>
+ <entry key="83" number="0x2289" class="RELATION" name="nsupseteq" style="normal"/>
+ <entry key="84" number="0xE2B7" class="RELATION" name="supsetneqq" style="normal"/>
+ <entry key="85" number="0xE2BB" class="RELATION" name="varsupsetneqq" style="normal"/>
+ <entry key="86" number="0xE2B0" class="RELATION" name="nsupseteqq" style="normal"/>
+ <entry key="94" number="0x2250" class="RELATION" name="doteq" style="normal"/>
+ <entry key="105" number="0x2253" class="RELATION" name="risingdotseq" style="normal"/>
+ <entry key="106" number="0x2252" class="RELATION" name="fallingdotseq" style="normal"/>
+ <entry key="108" number="0x00AC" class="ORDINARY" name="neg" style="normal"/>
+ <entry key="115" number="0x2260" class="RELATION" name="neq" style="normal"/>
+ <entry key="121" number="0x2245" class="RELATION" name="cong" style="normal"/>
+ <entry key="162" number="0x223C" class="RELATION" name="sim" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixfourteen">
+ <entry key="97" number="0x2135" class="ORDINARY" name="aleph" style="normal"/>
+ <entry key="98" number="0x2136" class="ORDINARY" name="beth" style="normal"/>
+ <entry key="99" number="0x2138" class="ORDINARY" name="daleth" style="normal"/>
+ <entry key="100" number="0x2137" class="ORDINARY" name="gimel" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixnine">
+ <entry key="50" number="0x03C2" class="ORDINARY" name="" style="italic"/>
+ <entry key="51" number="0x03B5" class="ORDINARY" name="varepsilon" style="italic"/>
+ <entry key="52" number="0x03D5" class="ORDINARY" name="varphi" style="italic"/>
+ <entry key="54" number="0x03D6" class="ORDINARY" name="varpi" style="italic"/>
+ <entry key="56" number="0x03F0" class="ORDINARY" name="varkappa" style="italic"/>
+ <entry key="57" number="0x03F1" class="ORDINARY" name="varrho" style="italic"/>
+ <entry key="68" number="0x0394" class="ORDINARY" name="Delta" style="italic"/>
+ <entry key="70" number="0x03A6" class="ORDINARY" name="Phi" style="italic"/>
+ <entry key="71" number="0x0393" class="ORDINARY" name="Gamma" style="italic"/>
+ <entry key="74" number="0x03A8" class="ORDINARY" name="Psi" style="italic"/>
+ <entry key="76" number="0x039B" class="ORDINARY" name="Lambda" style="italic"/>
+ <entry key="80" number="0x03A0" class="ORDINARY" name="Pi" style="italic"/>
+ <entry key="81" number="0x0398" class="ORDINARY" name="Theta" style="italic"/>
+ <entry key="83" number="0x03A3" class="ORDINARY" name="Sigma" style="italic"/>
+ <entry key="85" number="0x03A9" class="ORDINARY" name="Omega" style="italic"/>
+ <entry key="86" number="0x2207" class="ORDINARY" name="nabla" style="italic"/>
+ <entry key="88" number="0x039E" class="ORDINARY" name="Xi" style="italic"/>
+ <entry key="89" number="0xE663" class="ORDINARY" name="Upsilon" style="italic"/>
+ <entry key="91" number="0x2127" class="ORDINARY" name="mho" style="italic"/>
+ <entry key="97" number="0x03B1" class="ORDINARY" name="alpha" style="italic"/>
+ <entry key="98" number="0x03B2" class="ORDINARY" name="beta" style="italic"/>
+ <entry key="99" number="0x03C7" class="ORDINARY" name="chi" style="italic"/>
+ <entry key="100" number="0x03B4" class="ORDINARY" name="delta" style="italic"/>
+ <entry key="101" number="0x03F5" class="ORDINARY" name="epsilon" style="italic"/>
+ <entry key="102" number="0x03C6" class="ORDINARY" name="phi" style="italic"/>
+ <entry key="103" number="0x03B3" class="ORDINARY" name="gamma" style="italic"/>
+ <entry key="104" number="0x03B7" class="ORDINARY" name="eta" style="italic"/>
+ <entry key="105" number="0x03B9" class="ORDINARY" name="iota" style="italic"/>
+ <entry key="106" number="0x03C8" class="ORDINARY" name="psi" style="italic"/>
+ <entry key="107" number="0x03BA" class="ORDINARY" name="kappa" style="italic"/>
+ <entry key="108" number="0x03BB" class="ORDINARY" name="lambda" style="italic"/>
+ <entry key="109" number="0x03BC" class="ORDINARY" name="mu" style="italic"/>
+ <entry key="110" number="0x03BD" class="ORDINARY" name="nu" style="italic"/>
+ <entry key="112" number="0x03C0" class="ORDINARY" name="pi" style="italic"/>
+ <entry key="113" number="0x03B8" class="ORDINARY" name="theta" style="italic"/>
+ <entry key="114" number="0x03C1" class="ORDINARY" name="rho" style="italic"/>
+ <entry key="115" number="0x03C3" class="ORDINARY" name="sigma" style="italic"/>
+ <entry key="116" number="0x03C4" class="ORDINARY" name="tau" style="italic"/>
+ <entry key="117" number="0x03C9" class="ORDINARY" name="omega" style="italic"/>
+ <entry key="118" number="0x2202" class="ORDINARY" name="partial" style="italic"/>
+ <entry key="119" number="0x03D1" class="ORDINARY" name="" style="italic"/>
+ <entry key="120" number="0x03BE" class="ORDINARY" name="xi" style="italic"/>
+ <entry key="121" number="0x03C5" class="ORDINARY" name="upsilon" style="italic"/>
+ <entry key="122" number="0x03B6" class="ORDINARY" name="zeta" style="italic"/>
+ </unicodetable>
+ <unicodetable font="esstixone">
+ <entry key="33" number="0x21CB" class="RELATION" name="leftrightharpoons" style="normal"/>
+ <entry key="35" number="0x21CC" class="ORDINARY" name="rightleftharpoons" style="normal"/>
+ <entry key="36" number="0x21C6" class="RELATION" name="leftrightarrows" style="normal"/>
+ <entry key="37" number="0x21C4" class="ORDINARY" name="rightleftarrows" style="normal"/>
+ <entry key="38" number="0x21A9" class="RELATION" name="hookleftarrow" style="normal"/>
+ <entry key="40" number="0x21BC" class="ORDINARY" name="leftharpoonup" style="normal"/>
+ <entry key="41" number="0x2190" class="RELATION" name="leftarrow" style="normal"/>
+ <entry key="42" number="0x21D0" class="RELATION" name="Leftarrow" style="normal"/>
+ <entry key="43" number="0x21AD" class="RELATION" name="leftrightsquigarrow" style="normal"/>
+ <entry key="44" number="0x219D" class="RELATION" name="rightsquigarrow" style="normal"/>
+ <entry key="45" number="0x21AA" class="RELATION" name="hookrightarrow" style="normal"/>
+ <entry key="46" number="0x21C0" class="ORDINARY" name="rightharpoonup" style="normal"/>
+ <entry key="47" number="0x2192" class="RELATION" name="rightarrow" style="normal"/>
+ <entry key="48" number="0x21D2" class="RELATION" name="Rightarrow" style="normal"/>
+ <entry key="52" number="0x2194" class="RELATION" name="leftrightarrow" style="normal"/>
+ <entry key="53" number="0x21D4" class="RELATION" name="Leftrightarrow" style="normal"/>
+ <entry key="56" number="0x219E" class="RELATION" name="twoheadleftarrow" style="normal"/>
+ <entry key="57" number="0x21A0" class="RELATION" name="twoheadrightarrow" style="normal"/>
+ <entry key="59" number="0x21A2" class="RELATION" name="leftarrowtail" style="normal"/>
+ <entry key="60" number="0x21A3" class="RELATION" name="rightarrowtail" style="normal"/>
+ <entry key="69" number="0x21BD" class="ORDINARY" name="leftharpoondown" style="normal"/>
+ <entry key="70" number="0x219A" class="RELATION" name="nleftarrow" style="normal"/>
+ <entry key="71" number="0x21CD" class="RELATION" name="nLeftarrow" style="normal"/>
+ <entry key="72" number="0x21C1" class="ORDINARY" name="rightharpoondown" style="normal"/>
+ <entry key="73" number="0x21AC" class="RELATION" name="looparrowright" style="normal"/>
+ <entry key="75" number="0x219B" class="RELATION" name="nrightarrow" style="normal"/>
+ <entry key="76" number="0x21CF" class="RELATION" name="nRightarrow" style="normal"/>
+ <entry key="79" number="0x21AE" class="RELATION" name="nleftrightarrow" style="normal"/>
+ <entry key="80" number="0x21CE" class="RELATION" name="nLeftrightarrow" style="normal"/>
+ <entry key="81" number="0x21B0" class="RELATION" name="Lsh" style="normal"/>
+ <entry key="87" number="0x21C3" class="RELATION" name="downharpoonleft" style="normal"/>
+ <entry key="88" number="0x21C2" class="RELATION" name="downharpoonright" style="normal"/>
+ <entry key="89" number="0x2193" class="RELATION" name="downarrow" style="normal"/>
+ <entry key="90" number="0x21D3" class="RELATION" name="Downarrow" style="normal"/>
+ <entry key="91" number="0x2191" class="RELATION" name="uparrow" style="normal"/>
+ <entry key="92" number="0x21D1" class="RELATION" name="Uparrow" style="normal"/>
+ <entry key="93" number="0x21BF" class="RELATION" name="upharpoonleft" style="normal"/>
+ <entry key="94" number="0x21BE" class="RELATION" name="upharpoonright" style="normal"/>
+ <entry key="95" number="0x2196" class="ORDINARY" name="nwarrow" style="normal"/>
+ <entry key="97" number="0x2198" class="ORDINARY" name="searrow" style="normal"/>
+ <entry key="98" number="0x2197" class="ORDINARY" name="nearrow" style="normal"/>
+ <entry key="99" number="0x2199" class="ORDINARY" name="swarrow" style="normal"/>
+ <entry key="102" number="0x21B6" class="RELATION" name="curvearrowleft" style="normal"/>
+ <entry key="103" number="0x21B7" class="RELATION" name="curvearrowright" style="normal"/>
+ <entry key="104" number="0x2195" class="ORDINARY" name="updownarrow" style="normal"/>
+ <entry key="105" number="0x21D5" class="ORDINARY" name="Updownarrow" style="normal"/>
+ <entry key="106" number="0x21C8" class="RELATION" name="upuparrows" style="normal"/>
+ <entry key="107" number="0x21CA" class="RELATION" name="downdownarrows" style="normal"/>
+ <entry key="108" number="0x21B1" class="RELATION" name="Rsh" style="normal"/>
+ <entry key="171" number="0x22EE" class="ORDINARY" name="vdots" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixseven">
+ <entry key="61" number="0x0028" class="ORDINARY" name="" style="normal"/>
+ <entry key="62" number="0x0029" class="ORDINARY" name="" style="normal"/>
+ <entry key="63" number="0x005B" class="ORDINARY" name="" style="normal"/>
+ <entry key="64" number="0x005D" class="ORDINARY" name="" style="normal"/>
+ <entry key="65" number="0x007B" class="ORDINARY" name="lbrace" style="normal"/>
+ <entry key="66" number="0x007D" class="ORDINARY" name="rbrace" style="normal"/>
+ <entry key="67" number="0x2329" class="ORDINARY" name="langle" style="normal"/>
+ <entry key="68" number="0x232A" class="ORDINARY" name="rangle" style="normal"/>
+ <entry key="75" number="0x007C" class="ORDINARY" name="vert" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixseventeen">
+ </unicodetable>
+ <unicodetable font="esstixsix">
+ <entry key="69" number="0x222B" class="ORDINARY" name="int" style="normal"/>
+ <entry key="70" number="0x222E" class="ORDINARY" name="oint" style="normal"/>
+ <entry key="72" number="0x222F" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x2230" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0x2233" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0x2232" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0x2231" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0x221A" class="ORDINARY" name="surd" style="normal"/>
+ <entry key="83" number="0x2211" class="ORDINARY" name="sum" style="normal"/>
+ <entry key="84" number="0x220F" class="ORDINARY" name="prod" style="normal"/>
+ <entry key="85" number="0x2210" class="ORDINARY" name="coprod" style="normal"/>
+ <entry key="87" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="88" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="89" number="0x2227" class="BINOP" name="wedge" style="normal"/>
+ <entry key="90" number="0x2228" class="BINOP" name="vee" style="normal"/>
+ <entry key="91" number="0x2294" class="ORDINARY" name="sqcup" style="normal"/>
+ <entry key="92" number="0x2293" class="ORDINARY" name="sqcap" style="normal"/>
+ <entry key="93" number="0x228E" class="ORDINARY" name="uplus" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixsixteen">
+ </unicodetable>
+ <unicodetable font="esstixten">
+ <entry key="50" number="0x03C2" class="ORDINARY" name="" style="normal"/>
+ <entry key="51" number="0x03B5" class="ORDINARY" name="varepsilon" style="normal"/>
+ <entry key="52" number="0x03D5" class="ORDINARY" name="varphi" style="normal"/>
+ <entry key="54" number="0x03D6" class="ORDINARY" name="varpi" style="normal"/>
+ <entry key="56" number="0x03F0" class="ORDINARY" name="varkappa" style="normal"/>
+ <entry key="57" number="0x03F1" class="ORDINARY" name="varrho" style="normal"/>
+ <entry key="68" number="0x0394" class="ORDINARY" name="Delta" style="normal"/>
+ <entry key="70" number="0x03A6" class="ORDINARY" name="Phi" style="normal"/>
+ <entry key="71" number="0x0393" class="ORDINARY" name="Gamma" style="normal"/>
+ <entry key="74" number="0x03A8" class="ORDINARY" name="Psi" style="normal"/>
+ <entry key="76" number="0x039B" class="ORDINARY" name="Lambda" style="normal"/>
+ <entry key="80" number="0x03A0" class="ORDINARY" name="Pi" style="normal"/>
+ <entry key="81" number="0x0398" class="ORDINARY" name="Theta" style="normal"/>
+ <entry key="83" number="0x03A3" class="ORDINARY" name="Sigma" style="normal"/>
+ <entry key="85" number="0x03A9" class="ORDINARY" name="Omega" style="normal"/>
+ <entry key="86" number="0x2207" class="ORDINARY" name="nabla" style="normal"/>
+ <entry key="88" number="0x039E" class="ORDINARY" name="Xi" style="normal"/>
+ <entry key="89" number="0xE663" class="ORDINARY" name="Upsilon" style="normal"/>
+ <entry key="91" number="0x2127" class="ORDINARY" name="mho" style="normal"/>
+ <entry key="97" number="0x03B1" class="ORDINARY" name="alpha" style="normal"/>
+ <entry key="98" number="0x03B2" class="ORDINARY" name="beta" style="normal"/>
+ <entry key="99" number="0x03C7" class="ORDINARY" name="chi" style="normal"/>
+ <entry key="100" number="0x03B4" class="ORDINARY" name="delta" style="normal"/>
+ <entry key="101" number="0x03F5" class="ORDINARY" name="epsilon" style="normal"/>
+ <entry key="102" number="0x03C6" class="ORDINARY" name="phi" style="normal"/>
+ <entry key="103" number="0x03B3" class="ORDINARY" name="gamma" style="normal"/>
+ <entry key="104" number="0x03B7" class="ORDINARY" name="eta" style="normal"/>
+ <entry key="105" number="0x03B9" class="ORDINARY" name="iota" style="normal"/>
+ <entry key="106" number="0x03C8" class="ORDINARY" name="psi" style="normal"/>
+ <entry key="107" number="0x03BA" class="ORDINARY" name="kappa" style="normal"/>
+ <entry key="108" number="0x03BB" class="ORDINARY" name="lambda" style="normal"/>
+ <entry key="109" number="0x03BC" class="ORDINARY" name="mu" style="normal"/>
+ <entry key="110" number="0x03BD" class="ORDINARY" name="nu" style="normal"/>
+ <entry key="112" number="0x03C0" class="ORDINARY" name="pi" style="normal"/>
+ <entry key="113" number="0x03B8" class="ORDINARY" name="theta" style="normal"/>
+ <entry key="114" number="0x03C1" class="ORDINARY" name="rho" style="normal"/>
+ <entry key="115" number="0x03C3" class="ORDINARY" name="sigma" style="normal"/>
+ <entry key="116" number="0x03C4" class="ORDINARY" name="tau" style="normal"/>
+ <entry key="117" number="0x03C9" class="ORDINARY" name="omega" style="normal"/>
+ <entry key="118" number="0x2202" class="ORDINARY" name="partial" style="normal"/>
+ <entry key="119" number="0x03D1" class="ORDINARY" name="" style="normal"/>
+ <entry key="120" number="0x03BE" class="ORDINARY" name="xi" style="normal"/>
+ <entry key="121" number="0x03C5" class="ORDINARY" name="upsilon" style="normal"/>
+ <entry key="122" number="0x03B6" class="ORDINARY" name="zeta" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixthirteen">
+ </unicodetable>
+ <unicodetable font="esstixthree">
+ <entry key="35" number="0xE2FA" class="RELATION" name="leqslant" style="normal"/>
+ <entry key="36" number="0xE5CF" class="RELATION" name="eqslantless" style="normal"/>
+ <entry key="37" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="38" number="0x2266" class="ORDINARY" name="leqq" style="normal"/>
+ <entry key="40" number="0x2272" class="ORDINARY" name="lesssim" style="normal"/>
+ <entry key="41" number="0xE2F8" class="RELATION" name="lessapprox" style="normal"/>
+ <entry key="43" number="0x2276" class="ORDINARY" name="lessgtr" style="normal"/>
+ <entry key="44" number="0x22DA" class="ORDINARY" name="lesseqgtr" style="normal"/>
+ <entry key="45" number="0xE2F9" class="RELATION" name="lesseqqgtr" style="normal"/>
+ <entry key="46" number="0x2243" class="RELATION" name="simeq" style="normal"/>
+ <entry key="47" number="0x226A" class="RELATION" name="ll" style="normal"/>
+ <entry key="48" number="0x22D8" class="ORDINARY" name="lll" style="normal"/>
+ <entry key="49" number="0x22D6" class="ORDINARY" name="lessdot" style="normal"/>
+ <entry key="51" number="0x227A" class="ORDINARY" name="prec" style="normal"/>
+ <entry key="52" number="0x227E" class="ORDINARY" name="precsim" style="normal"/>
+ <entry key="53" number="0xE2FD" class="RELATION" name="precapprox" style="normal"/>
+ <entry key="54" number="0xE2FE" class="RELATION" name="preceq" style="normal"/>
+ <entry key="55" number="0x227C" class="ORDINARY" name="preccurlyeq" style="normal"/>
+ <entry key="56" number="0x22DE" class="ORDINARY" name="curlyeqprec" style="normal"/>
+ <entry key="58" number="0x2220" class="ORDINARY" name="angle" style="normal"/>
+ <entry key="62" number="0x226E" class="ORDINARY" name="nless" style="normal"/>
+ <entry key="63" number="0xE2A7" class="RELATION" name="nleqslant" style="normal"/>
+ <entry key="64" number="0xE2A3" class="RELATION" name="lneq" style="normal"/>
+ <entry key="65" number="0x2268" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0x22E6" class="ORDINARY" name="lnsim" style="normal"/>
+ <entry key="67" number="0xE2A2" class="RELATION" name="lnapprox" style="normal"/>
+ <entry key="70" number="0x2270" class="ORDINARY" name="nleq" style="normal"/>
+ <entry key="71" number="0xE2A8" class="RELATION" name="nleqq" style="normal"/>
+ <entry key="72" number="0x226C" class="RELATION" name="between" style="normal"/>
+ <entry key="73" number="0x2280" class="ORDINARY" name="nprec" style="normal"/>
+ <entry key="74" number="0x22E8" class="ORDINARY" name="precnsim" style="normal"/>
+ <entry key="75" number="0xE2B2" class="RELATION" name="precnapprox" style="normal"/>
+ <entry key="77" number="0xE5DC" class="RELATION" name="npreceq" style="normal"/>
+ <entry key="78" number="0x221E" class="ORDINARY" name="infty" style="normal"/>
+ <entry key="80" number="0xE2F6" class="RELATION" name="geqslant" style="normal"/>
+ <entry key="81" number="0xE5DF" class="RELATION" name="eqslantgtr" style="normal"/>
+ <entry key="82" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="83" number="0x2267" class="ORDINARY" name="geqq" style="normal"/>
+ <entry key="84" number="0x2273" class="ORDINARY" name="gtrsim" style="normal"/>
+ <entry key="85" number="0xE2F4" class="RELATION" name="gtrapprox" style="normal"/>
+ <entry key="87" number="0x2277" class="ORDINARY" name="gtrless" style="normal"/>
+ <entry key="88" number="0x22DB" class="ORDINARY" name="gtreqless" style="normal"/>
+ <entry key="89" number="0xE2F5" class="RELATION" name="gtreqqless" style="normal"/>
+ <entry key="91" number="0x226B" class="RELATION" name="gg" style="normal"/>
+ <entry key="92" number="0x22D9" class="ORDINARY" name="ggg" style="normal"/>
+ <entry key="93" number="0x22D7" class="ORDINARY" name="gtrdot" style="normal"/>
+ <entry key="95" number="0x227B" class="ORDINARY" name="succ" style="normal"/>
+ <entry key="97" number="0x227F" class="ORDINARY" name="succsim" style="normal"/>
+ <entry key="98" number="0xE2FF" class="RELATION" name="succapprox" style="normal"/>
+ <entry key="99" number="0xE300" class="RELATION" name="succeq" style="normal"/>
+ <entry key="100" number="0x227D" class="ORDINARY" name="succcurlyeq" style="normal"/>
+ <entry key="101" number="0x22DF" class="ORDINARY" name="curlyeqsucc" style="normal"/>
+ <entry key="102" number="0x221D" class="RELATION" name="propto" style="normal"/>
+ <entry key="103" number="0x2323" class="ORDINARY" name="" style="normal"/>
+ <entry key="104" number="0x2322" class="ORDINARY" name="" style="normal"/>
+ <entry key="105" number="0x22D4" class="ORDINARY" name="pitchfork" style="normal"/>
+ <entry key="106" number="0x226F" class="ORDINARY" name="ngtr" style="normal"/>
+ <entry key="107" number="0xE2A6" class="RELATION" name="ngeqslant" style="normal"/>
+ <entry key="108" number="0xE2A0" class="RELATION" name="gneq" style="normal"/>
+ <entry key="109" number="0x2269" class="ORDINARY" name="" style="normal"/>
+ <entry key="110" number="0x22E7" class="ORDINARY" name="gnsim" style="normal"/>
+ <entry key="111" number="0xE29F" class="RELATION" name="gnapprox" style="normal"/>
+ <entry key="114" number="0x2271" class="ORDINARY" name="ngeq" style="normal"/>
+ <entry key="116" number="0x2281" class="ORDINARY" name="nsucc" style="normal"/>
+ <entry key="117" number="0x22E9" class="ORDINARY" name="succnsim" style="normal"/>
+ <entry key="118" number="0xE2B4" class="RELATION" name="succnapprox" style="normal"/>
+ <entry key="120" number="0xE5F1" class="RELATION" name="nsucceq" style="normal"/>
+ </unicodetable>
+ <unicodetable font="esstixtwelve">
+ <entry key="50" number="0x03C2" class="ORDINARY" name="" style="bold"/>
+ <entry key="51" number="0x03B5" class="ORDINARY" name="varepsilon" style="bold"/>
+ <entry key="52" number="0x03D5" class="ORDINARY" name="varphi" style="bold"/>
+ <entry key="54" number="0x03D6" class="ORDINARY" name="varpi" style="bold"/>
+ <entry key="56" number="0x03F0" class="ORDINARY" name="varkappa" style="bold"/>
+ <entry key="57" number="0x03F1" class="ORDINARY" name="varrho" style="bold"/>
+ <entry key="68" number="0x0394" class="ORDINARY" name="Delta" style="bold"/>
+ <entry key="70" number="0x03A6" class="ORDINARY" name="Phi" style="bold"/>
+ <entry key="71" number="0x0393" class="ORDINARY" name="Gamma" style="bold"/>
+ <entry key="74" number="0x03A8" class="ORDINARY" name="Psi" style="bold"/>
+ <entry key="76" number="0x039B" class="ORDINARY" name="Lambda" style="bold"/>
+ <entry key="80" number="0x03A0" class="ORDINARY" name="Pi" style="bold"/>
+ <entry key="81" number="0x0398" class="ORDINARY" name="Theta" style="bold"/>
+ <entry key="83" number="0x03A3" class="ORDINARY" name="Sigma" style="bold"/>
+ <entry key="85" number="0x03A9" class="ORDINARY" name="Omega" style="bold"/>
+ <entry key="86" number="0x2207" class="ORDINARY" name="nabla" style="bold"/>
+ <entry key="88" number="0x039E" class="ORDINARY" name="Xi" style="bold"/>
+ <entry key="89" number="0xE663" class="ORDINARY" name="Upsilon" style="bold"/>
+ <entry key="91" number="0x2127" class="ORDINARY" name="mho" style="bold"/>
+ <entry key="97" number="0x03B1" class="ORDINARY" name="alpha" style="bold"/>
+ <entry key="98" number="0x03B2" class="ORDINARY" name="beta" style="bold"/>
+ <entry key="99" number="0x03C7" class="ORDINARY" name="chi" style="bold"/>
+ <entry key="100" number="0x03B4" class="ORDINARY" name="delta" style="bold"/>
+ <entry key="101" number="0x03F5" class="ORDINARY" name="epsilon" style="bold"/>
+ <entry key="102" number="0x03C6" class="ORDINARY" name="phi" style="bold"/>
+ <entry key="103" number="0x03B3" class="ORDINARY" name="gamma" style="bold"/>
+ <entry key="104" number="0x03B7" class="ORDINARY" name="eta" style="bold"/>
+ <entry key="105" number="0x03B9" class="ORDINARY" name="iota" style="bold"/>
+ <entry key="106" number="0x03C8" class="ORDINARY" name="psi" style="bold"/>
+ <entry key="107" number="0x03BA" class="ORDINARY" name="kappa" style="bold"/>
+ <entry key="108" number="0x03BB" class="ORDINARY" name="lambda" style="bold"/>
+ <entry key="109" number="0x03BC" class="ORDINARY" name="mu" style="bold"/>
+ <entry key="110" number="0x03BD" class="ORDINARY" name="nu" style="bold"/>
+ <entry key="112" number="0x03C0" class="ORDINARY" name="pi" style="bold"/>
+ <entry key="113" number="0x03B8" class="ORDINARY" name="theta" style="bold"/>
+ <entry key="114" number="0x03C1" class="ORDINARY" name="rho" style="bold"/>
+ <entry key="115" number="0x03C3" class="ORDINARY" name="sigma" style="bold"/>
+ <entry key="116" number="0x03C4" class="ORDINARY" name="tau" style="bold"/>
+ <entry key="117" number="0x03C9" class="ORDINARY" name="omega" style="bold"/>
+ <entry key="118" number="0x2202" class="ORDINARY" name="partial" style="bold"/>
+ <entry key="119" number="0x03D1" class="ORDINARY" name="" style="bold"/>
+ <entry key="120" number="0x03BE" class="ORDINARY" name="xi" style="bold"/>
+ <entry key="121" number="0x03C5" class="ORDINARY" name="upsilon" style="bold"/>
+ <entry key="122" number="0x03B6" class="ORDINARY" name="zeta" style="bold"/>
+ </unicodetable>
+ <unicodetable font="esstixtwo">
+ <entry key="37" number="0x2662" class="ORDINARY" name="diamondsuit" style="normal"/>
+ <entry key="38" number="0x2661" class="ORDINARY" name="heartsuit" style="normal"/>
+ <entry key="40" number="0x2660" class="ORDINARY" name="spadesuit" style="normal"/>
+ <entry key="41" number="0x2663" class="ORDINARY" name="clubsuit" style="normal"/>
+ <entry key="43" number="0x2605" class="ORDINARY" name="bigstar" style="normal"/>
+ <entry key="54" number="0x25B5" class="ORDINARY" name="vartriangle" style="normal"/>
+ <entry key="56" number="0x22B3" class="ORDINARY" name="vartriangleright" style="normal"/>
+ <entry key="57" number="0x22B2" class="ORDINARY" name="vartriangleleft" style="normal"/>
+ <entry key="58" number="0x25B4" class="ORDINARY" name="blacktriangle" style="normal"/>
+ <entry key="59" number="0x25BE" class="ORDINARY" name="blacktriangledown" style="normal"/>
+ <entry key="60" number="0x25B6" class="ORDINARY" name="blacktriangleright" style="normal"/>
+ <entry key="61" number="0x25C0" class="ORDINARY" name="blacktriangleleft" style="normal"/>
+ <entry key="99" number="0x2200" class="ORDINARY" name="forall" style="normal"/>
+ <entry key="100" number="0x2203" class="ORDINARY" name="exists" style="normal"/>
+ <entry key="102" number="0x2201" class="ORDINARY" name="complement" style="normal"/>
+ <entry key="103" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="104" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="105" number="0x22D3" class="ORDINARY" name="Cup" style="normal"/>
+ <entry key="106" number="0x22D2" class="ORDINARY" name="Cap" style="normal"/>
+ <entry key="107" number="0x2294" class="ORDINARY" name="sqcup" style="normal"/>
+ <entry key="108" number="0x2293" class="ORDINARY" name="sqcap" style="normal"/>
+ <entry key="109" number="0x228E" class="ORDINARY" name="uplus" style="normal"/>
+ <entry key="110" number="0x2228" class="BINOP" name="vee" style="normal"/>
+ <entry key="111" number="0x2227" class="BINOP" name="wedge" style="normal"/>
+ <entry key="118" number="0x22BB" class="ORDINARY" name="veebar" style="normal"/>
+ <entry key="119" number="0x22BC" class="ORDINARY" name="barwedge" style="normal"/>
+ <entry key="121" number="0x2306" class="ORDINARY" name="doublebarwedge" style="normal"/>
+ <entry key="167" number="0x2118" class="ORDINARY" name="wp" style="normal"/>
+ </unicodetable>
+ <unicodetable font="euclid%20math%20one">
+ <entry key="190" number="0x21CD" class="RELATION" name="nLeftarrow" style="normal"/>
+ <entry key="240" number="0x2201" class="ORDINARY" name="complement" style="normal"/>
+ <entry key="243" number="0x2204" class="ORDINARY" name="nexists" style="normal"/>
+ <entry key="139" number="0xEA2F" class="ORDINARY" name="" style="normal"/>
+ <entry key="138" number="0xEA2E" class="ORDINARY" name="" style="normal"/>
+ <entry key="162" number="0x2256" class="ORDINARY" name="eqcirc" style="normal"/>
+ <entry key="41" number="0x22A0" class="ORDINARY" name="boxtimes" style="normal"/>
+ <entry key="164" number="0x2251" class="ORDINARY" name="Doteq" style="normal"/>
+ <entry key="163" number="0x2253" class="RELATION" name="risingdotseq" style="normal"/>
+ <entry key="165" number="0x2252" class="RELATION" name="fallingdotseq" style="normal"/>
+ <entry key="137" number="0xE92F" class="ORDINARY" name="" style="normal"/>
+ <entry key="136" number="0xE92E" class="ORDINARY" name="" style="normal"/>
+ <entry key="250" number="0x22BA" class="ORDINARY" name="intercal" style="normal"/>
+ <entry key="79" number="0xF10E" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0xF10D" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0xF10A" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0xF106" class="ORDINARY" name="" style="normal"/>
+ <entry key="65" number="0xF100" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0xF103" class="ORDINARY" name="" style="normal"/>
+ <entry key="67" number="0xF102" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0xF109" class="ORDINARY" name="" style="normal"/>
+ <entry key="168" number="0x22B8" class="ORDINARY" name="multimap" style="normal"/>
+ <entry key="72" number="0x210B" class="ORDINARY" name="" style="normal"/>
+ <entry key="255" number="0x210F" class="ORDINARY" name="" style="normal"/>
+ <entry key="177" number="0x21A2" class="RELATION" name="leftarrowtail" style="normal"/>
+ <entry key="176" number="0x21A3" class="RELATION" name="rightarrowtail" style="normal"/>
+ <entry key="35" number="0x229B" class="ORDINARY" name="circledast" style="normal"/>
+ <entry key="205" number="0x21AB" class="ORDINARY" name="looparrowleft" style="normal"/>
+ <entry key="204" number="0x21AC" class="RELATION" name="looparrowright" style="normal"/>
+ <entry key="161" number="0x2257" class="ORDINARY" name="circeq" style="normal"/>
+ <entry key="207" number="0x21AD" class="RELATION" name="leftrightsquigarrow" style="normal"/>
+ <entry key="192" number="0x21AE" class="RELATION" name="nleftrightarrow" style="normal"/>
+ <entry key="242" number="0x03B5" class="ORDINARY" name="varepsilon" style="normal"/>
+ <entry key="195" number="0x21C9" class="ORDINARY" name="rightrightarrows" style="normal"/>
+ <entry key="254" number="0x00F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="128" number="0xFE68" class="ORDINARY" name="" style="normal"/>
+ <entry key="187" number="0x21C3" class="RELATION" name="downharpoonleft" style="normal"/>
+ <entry key="228" number="0x2720" class="ORDINARY" name="maltese" style="normal"/>
+ <entry key="206" number="0x21DD" class="ORDINARY" name="rightzigzagarrow" style="normal"/>
+ <entry key="201" number="0x21DA" class="ORDINARY" name="Lleftarrow" style="normal"/>
+ <entry key="200" number="0x21DB" class="ORDINARY" name="Rrightarrow" style="normal"/>
+ <entry key="241" number="0x03F1" class="ORDINARY" name="varrho" style="normal"/>
+ <entry key="249" number="0x03F0" class="ORDINARY" name="varkappa" style="normal"/>
+ <entry key="52" number="0x0034" class="ORDINARY" name="" style="normal"/>
+ <entry key="253" number="0x2138" class="ORDINARY" name="daleth" style="normal"/>
+ <entry key="251" number="0x2136" class="ORDINARY" name="beth" style="normal"/>
+ <entry key="252" number="0x2137" class="ORDINARY" name="gimel" style="normal"/>
+ <entry key="69" number="0x2130" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0x2131" class="ORDINARY" name="" style="normal"/>
+ <entry key="245" number="0x2132" class="ORDINARY" name="Finv" style="normal"/>
+ <entry key="77" number="0x2133" class="ORDINARY" name="" style="normal"/>
+ <entry key="132" number="0x231C" class="ORDINARY" name="ulcorner" style="normal"/>
+ <entry key="134" number="0x231D" class="ORDINARY" name="urcorner" style="normal"/>
+ <entry key="133" number="0x231E" class="ORDINARY" name="llcorner" style="normal"/>
+ <entry key="135" number="0x231F" class="ORDINARY" name="lrcorner" style="normal"/>
+ <entry key="230" number="0x22C7" class="ORDINARY" name="divideontimes" style="normal"/>
+ <entry key="229" number="0x22C6" class="ORDINARY" name="star" style="normal"/>
+ <entry key="226" number="0x22C9" class="ORDINARY" name="ltimes" style="normal"/>
+ <entry key="43" number="0x25A0" class="ORDINARY" name="" style="normal"/>
+ <entry key="44" number="0x25A1" class="ORDINARY" name="" style="normal"/>
+ <entry key="45" number="0x25AA" class="ORDINARY" name="" style="normal"/>
+ <entry key="225" number="0x22CC" class="ORDINARY" name="rightthreetimes" style="normal"/>
+ <entry key="224" number="0x22CB" class="ORDINARY" name="leftthreetimes" style="normal"/>
+ <entry key="227" number="0x22CA" class="ORDINARY" name="rtimes" style="normal"/>
+ <entry key="194" number="0x21C7" class="ORDINARY" name="leftleftarrows" style="normal"/>
+ <entry key="199" number="0x21CB" class="RELATION" name="leftrightharpoons" style="normal"/>
+ <entry key="129" number="0x005C" class="ORDINARY" name="backslash" style="normal"/>
+ <entry key="189" number="0x219B" class="RELATION" name="nrightarrow" style="normal"/>
+ <entry key="188" number="0x219A" class="RELATION" name="nleftarrow" style="normal"/>
+ <entry key="179" number="0x219E" class="RELATION" name="twoheadleftarrow" style="normal"/>
+ <entry key="34" number="0x229A" class="ORDINARY" name="circledcirc" style="normal"/>
+ <entry key="40" number="0x229E" class="ORDINARY" name="boxplus" style="normal"/>
+ <entry key="39" number="0x229F" class="ORDINARY" name="boxminus" style="normal"/>
+ <entry key="33" number="0x2296" class="BINOP" name="ominus" style="normal"/>
+ <entry key="37" number="0x2298" class="BINOP" name="oslash" style="normal"/>
+ <entry key="246" number="0xED01" class="ORDINARY" name="" style="normal"/>
+ <entry key="248" number="0xED02" class="ORDINARY" name="" style="normal"/>
+ <entry key="140" number="0x2224" class="ORDINARY" name="" style="normal"/>
+ <entry key="141" number="0x2226" class="ORDINARY" name="" style="normal"/>
+ <entry key="32" number="0x0020" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0x211B" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0x24C8" class="ORDINARY" name="circledS" style="normal"/>
+ <entry key="66" number="0x212C" class="ORDINARY" name="" style="normal"/>
+ <entry key="244" number="0x03DC" class="ORDINARY" name="" style="normal"/>
+ <entry key="196" number="0x21C8" class="RELATION" name="upuparrows" style="normal"/>
+ <entry key="198" number="0x21C6" class="RELATION" name="leftrightarrows" style="normal"/>
+ <entry key="182" number="0x21C0" class="ORDINARY" name="rightharpoonup" style="normal"/>
+ <entry key="185" number="0x21C2" class="RELATION" name="downharpoonright" style="normal"/>
+ <entry key="193" number="0x21CE" class="RELATION" name="nLeftrightarrow" style="normal"/>
+ <entry key="191" number="0x21CF" class="RELATION" name="nRightarrow" style="normal"/>
+ <entry key="197" number="0x21CA" class="RELATION" name="downdownarrows" style="normal"/>
+ <entry key="231" number="0x266D" class="ORDINARY" name="flat" style="normal"/>
+ <entry key="232" number="0x266E" class="ORDINARY" name="natural" style="normal"/>
+ <entry key="233" number="0x266F" class="ORDINARY" name="sharp" style="normal"/>
+ <entry key="160" number="0x00A0" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0x2112" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x2110" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x2118" class="ORDINARY" name="wp" style="normal"/>
+ <entry key="178" number="0x21A0" class="RELATION" name="twoheadrightarrow" style="normal"/>
+ <entry key="87" number="0xF116" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0xF117" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0xF114" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0xF115" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0xF112" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0xF113" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0xF110" class="ORDINARY" name="" style="normal"/>
+ <entry key="131" number="0x2215" class="ORDINARY" name="slash" style="normal"/>
+ <entry key="89" number="0xF118" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0xF119" class="ORDINARY" name="" style="normal"/>
+ <entry key="130" number="0x2216" class="ORDINARY" name="" style="normal"/>
+ <entry key="146" number="0x22A9" class="ORDINARY" name="Vdash" style="normal"/>
+ <entry key="145" number="0x22A8" class="ORDINARY" name="vDash" style="normal"/>
+ <entry key="42" number="0x22A1" class="ORDINARY" name="boxdot" style="normal"/>
+ <entry key="148" number="0x22A3" class="ORDINARY" name="dashv" style="normal"/>
+ <entry key="144" number="0x22A2" class="ORDINARY" name="" style="normal"/>
+ <entry key="149" number="0x22A4" class="ORDINARY" name="top" style="normal"/>
+ <entry key="147" number="0x22AA" class="ORDINARY" name="Vvdash" style="normal"/>
+ <entry key="150" number="0x22AC" class="ORDINARY" name="nvdash" style="normal"/>
+ <entry key="152" number="0x22AE" class="ORDINARY" name="nVdash" style="normal"/>
+ <entry key="151" number="0x22AD" class="ORDINARY" name="nvDash" style="normal"/>
+ <entry key="153" number="0x22AF" class="ORDINARY" name="nVDash" style="normal"/>
+ <entry key="55" number="0x0037" class="ORDINARY" name="" style="normal"/>
+ <entry key="54" number="0x0036" class="ORDINARY" name="" style="normal"/>
+ <entry key="53" number="0x0035" class="ORDINARY" name="" style="normal"/>
+ <entry key="51" number="0x0033" class="ORDINARY" name="" style="normal"/>
+ <entry key="50" number="0x0032" class="ORDINARY" name="" style="normal"/>
+ <entry key="49" number="0x0031" class="ORDINARY" name="" style="normal"/>
+ <entry key="48" number="0x0030" class="ORDINARY" name="" style="normal"/>
+ <entry key="234" number="0x2214" class="ORDINARY" name="dotplus" style="normal"/>
+ <entry key="57" number="0x0039" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0x0038" class="ORDINARY" name="" style="normal"/>
+ <entry key="174" number="0x2247" class="ORDINARY" name="ncong" style="normal"/>
+ <entry key="171" number="0x2242" class="ORDINARY" name="eqsim" style="normal"/>
+ <entry key="170" number="0x2240" class="ORDINARY" name="wr" style="normal"/>
+ <entry key="173" number="0x2241" class="ORDINARY" name="" style="normal"/>
+ <entry key="247" number="0x0131" class="ORDINARY" name="" style="normal"/>
+ <entry key="166" number="0x224F" class="ORDINARY" name="bumpeq" style="normal"/>
+ <entry key="169" number="0x224D" class="ORDINARY" name="asymp" style="normal"/>
+ <entry key="167" number="0x224E" class="ORDINARY" name="Bumpeq" style="normal"/>
+ <entry key="172" number="0x224A" class="ORDINARY" name="approxeq" style="normal"/>
+ <entry key="183" number="0x21C1" class="ORDINARY" name="rightharpoondown" style="normal"/>
+ <entry key="180" number="0x21BC" class="ORDINARY" name="leftharpoonup" style="normal"/>
+ <entry key="210" number="0x21BB" class="ORDINARY" name="cwopencirclearrow" style="normal"/>
+ <entry key="211" number="0x21BA" class="ORDINARY" name="acwopencirclearrow" style="normal"/>
+ <entry key="186" number="0x21BF" class="RELATION" name="upharpoonleft" style="normal"/>
+ <entry key="184" number="0x21BE" class="RELATION" name="upharpoonright" style="normal"/>
+ <entry key="181" number="0x21BD" class="ORDINARY" name="leftharpoondown" style="normal"/>
+ <entry key="202" number="0x21B1" class="RELATION" name="Rsh" style="normal"/>
+ <entry key="203" number="0x21B0" class="RELATION" name="Lsh" style="normal"/>
+ <entry key="208" number="0x21B7" class="RELATION" name="curvearrowright" style="normal"/>
+ <entry key="209" number="0x21B6" class="RELATION" name="curvearrowleft" style="normal"/>
+ </unicodetable>
+ <unicodetable font="euclid%20math%20two">
+ <entry key="228" number="0x2208" class="RELATION" name="in" style="normal"/>
+ <entry key="226" number="0x228E" class="ORDINARY" name="uplus" style="normal"/>
+ <entry key="229" number="0x220B" class="RELATION" name="ni" style="normal"/>
+ <entry key="67" number="0x2102" class="ORDINARY" name="" style="normal"/>
+ <entry key="168" number="0xE92D" class="ORDINARY" name="" style="normal"/>
+ <entry key="169" number="0x22BB" class="ORDINARY" name="veebar" style="normal"/>
+ <entry key="170" number="0x22BC" class="ORDINARY" name="barwedge" style="normal"/>
+ <entry key="40" number="0x22B4" class="ORDINARY" name="trianglelefteq" style="normal"/>
+ <entry key="39" number="0x22B5" class="ORDINARY" name="trianglerighteq" style="normal"/>
+ <entry key="72" number="0x210D" class="ORDINARY" name="" style="normal"/>
+ <entry key="107" number="0xF0A4" class="ORDINARY" name="" style="normal"/>
+ <entry key="34" number="0x25BD" class="ORDINARY" name="bigtriangledown" style="normal"/>
+ <entry key="73" number="0xF088" class="ORDINARY" name="" style="normal"/>
+ <entry key="69" number="0xF084" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0xF085" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0xF086" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0xF081" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0xF083" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0xF089" class="ORDINARY" name="" style="normal"/>
+ <entry key="177" number="0x227D" class="ORDINARY" name="succcurlyeq" style="normal"/>
+ <entry key="176" number="0x227C" class="ORDINARY" name="preccurlyeq" style="normal"/>
+ <entry key="79" number="0xF08E" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0xF08A" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0xF08B" class="ORDINARY" name="" style="normal"/>
+ <entry key="77" number="0xF08C" class="ORDINARY" name="" style="normal"/>
+ <entry key="37" number="0x25B6" class="ORDINARY" name="blacktriangleright" style="normal"/>
+ <entry key="33" number="0x25B3" class="ORDINARY" name="bigtriangleup" style="normal"/>
+ <entry key="35" number="0x25B2" class="ORDINARY" name="" style="normal"/>
+ <entry key="186" number="0x2280" class="ORDINARY" name="nprec" style="normal"/>
+ <entry key="187" number="0x2281" class="ORDINARY" name="nsucc" style="normal"/>
+ <entry key="218" number="0x2288" class="RELATION" name="nsubseteq" style="normal"/>
+ <entry key="219" number="0x2289" class="RELATION" name="nsupseteq" style="normal"/>
+ <entry key="215" number="0x228B" class="RELATION" name="supsetneq" style="normal"/>
+ <entry key="214" number="0x228A" class="RELATION" name="subsetneq" style="normal"/>
+ <entry key="145" number="0xEA35" class="ORDINARY" name="" style="normal"/>
+ <entry key="144" number="0xEA34" class="ORDINARY" name="" style="normal"/>
+ <entry key="162" number="0xEA33" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0xEA32" class="ORDINARY" name="" style="normal"/>
+ <entry key="192" number="0xEA3E" class="ORDINARY" name="" style="normal"/>
+ <entry key="189" number="0xEA3D" class="ORDINARY" name="" style="normal"/>
+ <entry key="193" number="0xEA3F" class="ORDINARY" name="" style="normal"/>
+ <entry key="200" number="0xEA3A" class="ORDINARY" name="" style="normal"/>
+ <entry key="188" number="0xEA3C" class="ORDINARY" name="" style="normal"/>
+ <entry key="201" number="0xEA3B" class="ORDINARY" name="" style="normal"/>
+ <entry key="179" number="0x22DF" class="ORDINARY" name="curlyeqsucc" style="normal"/>
+ <entry key="131" number="0x22DD" class="ORDINARY" name="eqgtr" style="normal"/>
+ <entry key="178" number="0x22DE" class="ORDINARY" name="curlyeqprec" style="normal"/>
+ <entry key="166" number="0x22DB" class="ORDINARY" name="gtreqless" style="normal"/>
+ <entry key="130" number="0x22DC" class="ORDINARY" name="eqless" style="normal"/>
+ <entry key="165" number="0x22DA" class="ORDINARY" name="lesseqgtr" style="normal"/>
+ <entry key="138" number="0xE932" class="ORDINARY" name="" style="normal"/>
+ <entry key="184" number="0xE93A" class="ORDINARY" name="" style="normal"/>
+ <entry key="185" number="0xE93B" class="ORDINARY" name="" style="normal"/>
+ <entry key="202" number="0x22CF" class="ORDINARY" name="curlywedge" style="normal"/>
+ <entry key="203" number="0x22CE" class="ORDINARY" name="curlyvee" style="normal"/>
+ <entry key="128" number="0x22D6" class="ORDINARY" name="lessdot" style="normal"/>
+ <entry key="129" number="0x22D7" class="ORDINARY" name="gtrdot" style="normal"/>
+ <entry key="227" number="0x22D4" class="ORDINARY" name="pitchfork" style="normal"/>
+ <entry key="211" number="0x22D2" class="ORDINARY" name="Cap" style="normal"/>
+ <entry key="139" number="0xE933" class="ORDINARY" name="" style="normal"/>
+ <entry key="208" number="0x22D0" class="RELATION" name="Subset" style="normal"/>
+ <entry key="209" number="0x22D1" class="RELATION" name="Supset" style="normal"/>
+ <entry key="140" number="0x22D8" class="ORDINARY" name="lll" style="normal"/>
+ <entry key="136" number="0x2272" class="ORDINARY" name="lesssim" style="normal"/>
+ <entry key="132" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="133" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="134" number="0x2266" class="ORDINARY" name="leqq" style="normal"/>
+ <entry key="135" number="0x2267" class="ORDINARY" name="geqq" style="normal"/>
+ <entry key="152" number="0x2268" class="ORDINARY" name="" style="normal"/>
+ <entry key="36" number="0x25BC" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0xF093" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0xF092" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0xF097" class="ORDINARY" name="" style="normal"/>
+ <entry key="87" number="0xF096" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0xF095" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0xF094" class="ORDINARY" name="" style="normal"/>
+ <entry key="89" number="0xF098" class="ORDINARY" name="" style="normal"/>
+ <entry key="143" number="0x226F" class="ORDINARY" name="ngtr" style="normal"/>
+ <entry key="182" number="0x227E" class="ORDINARY" name="precsim" style="normal"/>
+ <entry key="244" number="0x2291" class="RELATION" name="sqsubseteq" style="normal"/>
+ <entry key="241" number="0x2290" class="RELATION" name="sqsupset" style="normal"/>
+ <entry key="243" number="0x2293" class="ORDINARY" name="sqcap" style="normal"/>
+ <entry key="245" number="0x2292" class="ORDINARY" name="sqsupseteq" style="normal"/>
+ <entry key="242" number="0x2294" class="ORDINARY" name="sqcup" style="normal"/>
+ <entry key="225" number="0xEA0B" class="ORDINARY" name="" style="normal"/>
+ <entry key="224" number="0xEA0C" class="ORDINARY" name="" style="normal"/>
+ <entry key="149" number="0xEA0E" class="ORDINARY" name="" style="normal"/>
+ <entry key="210" number="0x22D3" class="ORDINARY" name="Cup" style="normal"/>
+ <entry key="156" number="0xEA06" class="ORDINARY" name="" style="normal"/>
+ <entry key="157" number="0xEA07" class="ORDINARY" name="" style="normal"/>
+ <entry key="141" number="0x22D9" class="ORDINARY" name="ggg" style="normal"/>
+ <entry key="213" number="0xE90B" class="ORDINARY" name="" style="normal"/>
+ <entry key="212" number="0xE90C" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0x2124" class="ORDINARY" name="" style="normal"/>
+ <entry key="221" number="0xEA45" class="ORDINARY" name="" style="normal"/>
+ <entry key="163" number="0x2276" class="ORDINARY" name="lessgtr" style="normal"/>
+ <entry key="171" number="0x2306" class="ORDINARY" name="doublebarwedge" style="normal"/>
+ <entry key="183" number="0x227F" class="ORDINARY" name="succsim" style="normal"/>
+ <entry key="159" number="0x22E7" class="ORDINARY" name="gnsim" style="normal"/>
+ <entry key="158" number="0x22E6" class="ORDINARY" name="lnsim" style="normal"/>
+ <entry key="191" number="0x22E1" class="ORDINARY" name="" style="normal"/>
+ <entry key="190" number="0x22E0" class="ORDINARY" name="" style="normal"/>
+ <entry key="199" number="0x22E9" class="ORDINARY" name="succnsim" style="normal"/>
+ <entry key="198" number="0x22E8" class="ORDINARY" name="precnsim" style="normal"/>
+ <entry key="43" number="0x22ED" class="ORDINARY" name="ntrianglerighteq" style="normal"/>
+ <entry key="42" number="0x22EA" class="ORDINARY" name="ntriangleleft" style="normal"/>
+ <entry key="44" number="0x22EC" class="ORDINARY" name="ntrianglelefteq" style="normal"/>
+ <entry key="41" number="0x22EB" class="ORDINARY" name="ntriangleright" style="normal"/>
+ <entry key="164" number="0x2277" class="ORDINARY" name="gtrless" style="normal"/>
+ <entry key="137" number="0x2273" class="ORDINARY" name="gtrsim" style="normal"/>
+ <entry key="147" number="0x2271" class="ORDINARY" name="ngeq" style="normal"/>
+ <entry key="146" number="0x2270" class="ORDINARY" name="nleq" style="normal"/>
+ <entry key="153" number="0x2269" class="ORDINARY" name="" style="normal"/>
+ <entry key="65" number="0xF080" class="ORDINARY" name="" style="normal"/>
+ <entry key="160" number="0x00A0" class="ORDINARY" name="" style="normal"/>
+ <entry key="220" number="0xEA44" class="ORDINARY" name="" style="normal"/>
+ <entry key="222" number="0xEA46" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0x211A" class="ORDINARY" name="" style="normal"/>
+ <entry key="196" number="0xEA40" class="ORDINARY" name="" style="normal"/>
+ <entry key="197" number="0xEA41" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0x211D" class="ORDINARY" name="" style="normal"/>
+ <entry key="217" number="0xEA43" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0x2115" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x2119" class="ORDINARY" name="" style="normal"/>
+ <entry key="167" number="0xE922" class="ORDINARY" name="" style="normal"/>
+ <entry key="240" number="0x228F" class="RELATION" name="sqsubset" style="normal"/>
+ <entry key="142" number="0x226E" class="ORDINARY" name="nless" style="normal"/>
+ <entry key="148" number="0xEA10" class="ORDINARY" name="" style="normal"/>
+ <entry key="223" number="0xEA47" class="ORDINARY" name="" style="normal"/>
+ <entry key="216" number="0xEA42" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0x25C0" class="ORDINARY" name="blacktriangleleft" style="normal"/>
+ </unicodetable>
+ <unicodetable font="euclid%20symbol">
+ <entry key="206" number="0x2208" class="RELATION" name="in" style="normal"/>
+ <entry key="207" number="0x2209" class="RELATION" name="notin" style="normal"/>
+ <entry key="182" number="0x2202" class="ORDINARY" name="partial" style="normal"/>
+ <entry key="36" number="0x2203" class="ORDINARY" name="exists" style="normal"/>
+ <entry key="34" number="0x2200" class="ORDINARY" name="forall" style="normal"/>
+ <entry key="209" number="0x2207" class="ORDINARY" name="nabla" style="normal"/>
+ <entry key="198" number="0x2205" class="BINOP" name="oslash" style="normal"/>
+ <entry key="39" number="0x220D" class="RELATION" name="ni" style="normal"/>
+ <entry key="124" number="0x007C" class="ORDINARY" name="vert" style="normal"/>
+ <entry key="123" number="0x007B" class="ORDINARY" name="lbrace" style="normal"/>
+ <entry key="125" number="0x007D" class="ORDINARY" name="rbrace" style="normal"/>
+ <entry key="176" number="0x00B0" class="ORDINARY" name="degree" style="normal"/>
+ <entry key="177" number="0x00B1" class="BINOP" name="pm" style="normal"/>
+ <entry key="178" number="0x2033" class="ORDINARY" name="" style="normal"/>
+ <entry key="162" number="0x2032" class="ORDINARY" name="prime" style="normal"/>
+ <entry key="111" number="0x03BF" class="ORDINARY" name="o" style="normal"/>
+ <entry key="120" number="0x03BE" class="ORDINARY" name="xi" style="normal"/>
+ <entry key="110" number="0x03BD" class="ORDINARY" name="nu" style="normal"/>
+ <entry key="109" number="0x03BC" class="ORDINARY" name="mu" style="normal"/>
+ <entry key="108" number="0x03BB" class="ORDINARY" name="lambda" style="normal"/>
+ <entry key="107" number="0x03BA" class="ORDINARY" name="kappa" style="normal"/>
+ <entry key="225" number="0x2329" class="ORDINARY" name="langle" style="normal"/>
+ <entry key="245" number="0x2321" class="ORDINARY" name="" style="normal"/>
+ <entry key="243" number="0x2320" class="ORDINARY" name="" style="normal"/>
+ <entry key="241" number="0x232A" class="ORDINARY" name="rangle" style="normal"/>
+ <entry key="105" number="0x03B9" class="ORDINARY" name="iota" style="normal"/>
+ <entry key="113" number="0x03B8" class="ORDINARY" name="theta" style="normal"/>
+ <entry key="104" number="0x03B7" class="ORDINARY" name="eta" style="normal"/>
+ <entry key="122" number="0x03B6" class="ORDINARY" name="zeta" style="normal"/>
+ <entry key="101" number="0x03B5" class="ORDINARY" name="varepsilon" style="normal"/>
+ <entry key="100" number="0x03B4" class="ORDINARY" name="delta" style="normal"/>
+ <entry key="103" number="0x03B3" class="ORDINARY" name="gamma" style="normal"/>
+ <entry key="98" number="0x03B2" class="ORDINARY" name="beta" style="normal"/>
+ <entry key="97" number="0x03B1" class="ORDINARY" name="alpha" style="normal"/>
+ <entry key="184" number="0x00F7" class="BINOP" name="div" style="normal"/>
+ <entry key="79" number="0x039F" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0x039D" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0x039E" class="ORDINARY" name="Xi" style="normal"/>
+ <entry key="76" number="0x039B" class="ORDINARY" name="Lambda" style="normal"/>
+ <entry key="77" number="0x039C" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0x039A" class="ORDINARY" name="" style="normal"/>
+ <entry key="166" number="0x0192" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0x0398" class="ORDINARY" name="Theta" style="normal"/>
+ <entry key="73" number="0x0399" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0x0396" class="ORDINARY" name="" style="normal"/>
+ <entry key="72" number="0x0397" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0x0394" class="ORDINARY" name="Delta" style="normal"/>
+ <entry key="69" number="0x0395" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0x0392" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0x0393" class="ORDINARY" name="Gamma" style="normal"/>
+ <entry key="65" number="0x0391" class="ORDINARY" name="" style="normal"/>
+ <entry key="201" number="0x2283" class="RELATION" name="supset" style="normal"/>
+ <entry key="202" number="0x2287" class="RELATION" name="supseteq" style="normal"/>
+ <entry key="203" number="0x2284" class="RELATION" name="nsubset" style="normal"/>
+ <entry key="214" number="0x221A" class="ORDINARY" name="surd" style="normal"/>
+ <entry key="181" number="0x221D" class="RELATION" name="propto" style="normal"/>
+ <entry key="213" number="0x220F" class="ORDINARY" name="prod" style="normal"/>
+ <entry key="229" number="0x2211" class="ORDINARY" name="sum" style="normal"/>
+ <entry key="219" number="0x21D4" class="RELATION" name="Leftrightarrow" style="normal"/>
+ <entry key="45" number="0x2212" class="BINOP" name="minus" style="normal"/>
+ <entry key="221" number="0x21D1" class="RELATION" name="Uparrow" style="normal"/>
+ <entry key="220" number="0x21D0" class="RELATION" name="Leftarrow" style="normal"/>
+ <entry key="223" number="0x21D3" class="RELATION" name="Downarrow" style="normal"/>
+ <entry key="222" number="0x21D2" class="RELATION" name="Rightarrow" style="normal"/>
+ <entry key="174" number="0x2192" class="RELATION" name="rightarrow" style="normal"/>
+ <entry key="70" number="0x03A6" class="ORDINARY" name="Phi" style="normal"/>
+ <entry key="67" number="0x03A7" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0x03A4" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0x03A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0x03A3" class="ORDINARY" name="Sigma" style="normal"/>
+ <entry key="80" number="0x03A0" class="ORDINARY" name="Pi" style="normal"/>
+ <entry key="82" number="0x03A1" class="ORDINARY" name="" style="normal"/>
+ <entry key="52" number="0x0034" class="ORDINARY" name="" style="normal"/>
+ <entry key="89" number="0x03A8" class="ORDINARY" name="Psi" style="normal"/>
+ <entry key="87" number="0x03A9" class="ORDINARY" name="Omega" style="normal"/>
+ <entry key="192" number="0x2135" class="ORDINARY" name="aleph" style="normal"/>
+ <entry key="215" number="0x22C5" class="BINOP" name="cdot" style="normal"/>
+ <entry key="224" number="0x26C4" class="ORDINARY" name="Diamond" style="normal"/>
+ <entry key="119" number="0x03C9" class="ORDINARY" name="omega" style="normal"/>
+ <entry key="233" number="0xF8EE" class="ORDINARY" name="" style="normal"/>
+ <entry key="232" number="0xF8ED" class="ORDINARY" name="" style="normal"/>
+ <entry key="231" number="0xF8EC" class="ORDINARY" name="" style="normal"/>
+ <entry key="230" number="0xF8EB" class="ORDINARY" name="" style="normal"/>
+ <entry key="228" number="0xF8EA" class="ORDINARY" name="" style="normal"/>
+ <entry key="185" number="0x2260" class="RELATION" name="neq" style="normal"/>
+ <entry key="186" number="0x2261" class="RELATION" name="equiv" style="normal"/>
+ <entry key="163" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="179" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="46" number="0x002E" class="ORDINARY" name="" style="normal"/>
+ <entry key="47" number="0x002F" class="ORDINARY" name="" style="normal"/>
+ <entry key="91" number="0x005B" class="ORDINARY" name="" style="normal"/>
+ <entry key="93" number="0x005D" class="ORDINARY" name="" style="normal"/>
+ <entry key="95" number="0x005F" class="ORDINARY" name="" style="normal"/>
+ <entry key="227" number="0xF8E9" class="ORDINARY" name="" style="normal"/>
+ <entry key="226" number="0xF8E8" class="ORDINARY" name="" style="normal"/>
+ <entry key="190" number="0xF8E7" class="ORDINARY" name="" style="normal"/>
+ <entry key="189" number="0xF8E6" class="RELATION" name="" style="normal"/>
+ <entry key="96" number="0xF8E5" class="ORDINARY" name="" style="normal"/>
+ <entry key="204" number="0x2282" class="RELATION" name="subset" style="normal"/>
+ <entry key="205" number="0x2286" class="RELATION" name="subseteq" style="normal"/>
+ <entry key="197" number="0x2295" class="BINOP" name="oplus" style="normal"/>
+ <entry key="196" number="0x2297" class="BINOP" name="otimes" style="normal"/>
+ <entry key="175" number="0x2193" class="RELATION" name="downarrow" style="normal"/>
+ <entry key="172" number="0x2190" class="RELATION" name="leftarrow" style="normal"/>
+ <entry key="173" number="0x2191" class="RELATION" name="uparrow" style="normal"/>
+ <entry key="171" number="0x2194" class="RELATION" name="leftrightarrow" style="normal"/>
+ <entry key="217" number="0x2227" class="BINOP" name="wedge" style="normal"/>
+ <entry key="208" number="0x2220" class="ORDINARY" name="angle" style="normal"/>
+ <entry key="43" number="0x002B" class="ORDINARY" name="" style="normal"/>
+ <entry key="44" number="0x002C" class="ORDINARY" name="" style="normal"/>
+ <entry key="218" number="0x2228" class="BINOP" name="vee" style="normal"/>
+ <entry key="199" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="165" number="0x221E" class="ORDINARY" name="infty" style="normal"/>
+ <entry key="40" number="0x0028" class="ORDINARY" name="" style="normal"/>
+ <entry key="41" number="0x0029" class="ORDINARY" name="" style="normal"/>
+ <entry key="200" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="242" number="0x222B" class="ORDINARY" name="int" style="normal"/>
+ <entry key="32" number="0x0020" class="ORDINARY" name="" style="normal"/>
+ <entry key="33" number="0x0021" class="ORDINARY" name="" style="normal"/>
+ <entry key="35" number="0x0023" class="ORDINARY" name="" style="normal"/>
+ <entry key="37" number="0x0025" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0x0026" class="ORDINARY" name="" style="normal"/>
+ <entry key="210" number="0x00AE" class="ORDINARY" name="" style="normal"/>
+ <entry key="180" number="0x00D7" class="BINOP" name="times" style="normal"/>
+ <entry key="212" number="0x2122" class="ORDINARY" name="" style="normal"/>
+ <entry key="246" number="0xF8F6" class="ORDINARY" name="" style="normal"/>
+ <entry key="247" number="0xF8F7" class="ORDINARY" name="" style="normal"/>
+ <entry key="239" number="0xF8F4" class="ORDINARY" name="" style="normal"/>
+ <entry key="237" number="0xF8F2" class="ORDINARY" name="" style="normal"/>
+ <entry key="238" number="0xF8F3" class="ORDINARY" name="" style="normal"/>
+ <entry key="235" number="0xF8F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="236" number="0xF8F1" class="ORDINARY" name="" style="normal"/>
+ <entry key="248" number="0xF8F8" class="ORDINARY" name="" style="normal"/>
+ <entry key="249" number="0xF8F9" class="ORDINARY" name="" style="normal"/>
+ <entry key="253" number="0xF8FD" class="ORDINARY" name="" style="normal"/>
+ <entry key="254" number="0xF8FE" class="ORDINARY" name="" style="normal"/>
+ <entry key="251" number="0xF8FB" class="ORDINARY" name="" style="normal"/>
+ <entry key="252" number="0xF8FC" class="ORDINARY" name="" style="normal"/>
+ <entry key="250" number="0xF8FA" class="ORDINARY" name="" style="normal"/>
+ <entry key="244" number="0xF8F5" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0x03D1" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0x03D2" class="ORDINARY" name="Upsilon" style="normal"/>
+ <entry key="106" number="0x03D5" class="ORDINARY" name="varphi" style="normal"/>
+ <entry key="118" number="0x03D6" class="ORDINARY" name="varpi" style="normal"/>
+ <entry key="168" number="0x2666" class="ORDINARY" name="diamondsuit" style="normal"/>
+ <entry key="234" number="0xF8EF" class="ORDINARY" name="" style="normal"/>
+ <entry key="216" number="0x00AC" class="ORDINARY" name="neg" style="normal"/>
+ <entry key="194" number="0x211C" class="ORDINARY" name="Re" style="normal"/>
+ <entry key="193" number="0x2111" class="ORDINARY" name="Im" style="normal"/>
+ <entry key="195" number="0x2118" class="ORDINARY" name="wp" style="normal"/>
+ <entry key="211" number="0x00A9" class="ORDINARY" name="" style="normal"/>
+ <entry key="169" number="0x2665" class="ORDINARY" name="heartsuit" style="normal"/>
+ <entry key="167" number="0x2663" class="ORDINARY" name="clubsuit" style="normal"/>
+ <entry key="42" number="0x2217" class="BINOP" name="ast" style="normal"/>
+ <entry key="188" number="0x2026" class="ORDINARY" name="ldots" style="normal"/>
+ <entry key="183" number="0x2022" class="BINOP" name="bullet" style="normal"/>
+ <entry key="126" number="0x223C" class="RELATION" name="sim" style="normal"/>
+ <entry key="94" number="0x22A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="170" number="0x2660" class="ORDINARY" name="spadesuit" style="normal"/>
+ <entry key="92" number="0x2234" class="BINOP" name="therefore" style="normal"/>
+ <entry key="55" number="0x0037" class="ORDINARY" name="" style="normal"/>
+ <entry key="54" number="0x0036" class="ORDINARY" name="" style="normal"/>
+ <entry key="53" number="0x0035" class="ORDINARY" name="" style="normal"/>
+ <entry key="51" number="0x0033" class="ORDINARY" name="" style="normal"/>
+ <entry key="50" number="0x0032" class="ORDINARY" name="" style="normal"/>
+ <entry key="49" number="0x0031" class="ORDINARY" name="" style="normal"/>
+ <entry key="48" number="0x0030" class="ORDINARY" name="" style="normal"/>
+ <entry key="57" number="0x0039" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0x0038" class="ORDINARY" name="" style="normal"/>
+ <entry key="164" number="0x2244" class="ORDINARY" name="nsime" style="normal"/>
+ <entry key="64" number="0x2245" class="RELATION" name="cong" style="normal"/>
+ <entry key="187" number="0x2248" class="RELATION" name="approx" style="normal"/>
+ <entry key="112" number="0x03C0" class="ORDINARY" name="pi" style="normal"/>
+ <entry key="86" number="0x03C2" class="ORDINARY" name="" style="normal"/>
+ <entry key="115" number="0x03C3" class="ORDINARY" name="sigma" style="normal"/>
+ <entry key="116" number="0x03C4" class="ORDINARY" name="tau" style="normal"/>
+ <entry key="117" number="0x03C5" class="ORDINARY" name="upsilon" style="normal"/>
+ <entry key="102" number="0x03C6" class="ORDINARY" name="phi" style="normal"/>
+ <entry key="99" number="0x03C7" class="ORDINARY" name="chi" style="normal"/>
+ <entry key="121" number="0x03C8" class="ORDINARY" name="psi" style="normal"/>
+ <entry key="63" number="0x003F" class="ORDINARY" name="" style="normal"/>
+ <entry key="62" number="0x003E" class="ORDINARY" name="greater" style="normal"/>
+ <entry key="61" number="0x003D" class="ORDINARY" name="" style="normal"/>
+ <entry key="60" number="0x003C" class="ORDINARY" name="less" style="normal"/>
+ <entry key="59" number="0x003B" class="ORDINARY" name="" style="normal"/>
+ <entry key="58" number="0x003A" class="ORDINARY" name="colon" style="normal"/>
+ <entry key="114" number="0x03C1" class="ORDINARY" name="rho" style="normal"/>
+ <entry key="191" number="0x21B5" class="ORDINARY" name="carriagereturn" style="normal"/>
+ </unicodetable>
+ <unicodetable font="mt%20extra">
+ <entry key="123" number="0xFE38" class="ORDINARY" name="" style="normal"/>
+ <entry key="115" number="0x20D6" class="ORDINARY" name="overleftarrow" style="normal"/>
+ <entry key="114" number="0x20D7" class="ORDINARY" name="vec" style="normal"/>
+ <entry key="119" number="0x20D0" class="ORDINARY" name="leftharpoonaccent" style="normal"/>
+ <entry key="118" number="0x20D1" class="ORDINARY" name="rightharpoonaccent" style="normal"/>
+ <entry key="66" number="0x2250" class="RELATION" name="doteq" style="normal"/>
+ <entry key="163" number="0x2102" class="ORDINARY" name="" style="normal"/>
+ <entry key="243" number="0x00B9" class="ORDINARY" name="" style="normal"/>
+ <entry key="244" number="0x00B2" class="ORDINARY" name="" style="normal"/>
+ <entry key="245" number="0x00B3" class="ORDINARY" name="" style="normal"/>
+ <entry key="96" number="0x2035" class="ORDINARY" name="backprime" style="normal"/>
+ <entry key="60" number="0x22B2" class="ORDINARY" name="vartriangleleft" style="normal"/>
+ <entry key="62" number="0x22B3" class="ORDINARY" name="vartriangleright" style="normal"/>
+ <entry key="248" number="0x00BE" class="ORDINARY" name="" style="normal"/>
+ <entry key="104" number="0x210F" class="ORDINARY" name="" style="normal"/>
+ <entry key="97" number="0x21A6" class="ORDINARY" name="mapsto" style="normal"/>
+ <entry key="64" number="0x225C" class="RELATION" name="triangleq" style="normal"/>
+ <entry key="40" number="0x2323" class="ORDINARY" name="" style="normal"/>
+ <entry key="41" number="0x2322" class="ORDINARY" name="" style="normal"/>
+ <entry key="211" number="0xEE13" class="ORDINARY" name="" style="normal"/>
+ <entry key="210" number="0xEE12" class="ORDINARY" name="" style="normal"/>
+ <entry key="209" number="0xEE11" class="ORDINARY" name="" style="normal"/>
+ <entry key="214" number="0xEE16" class="ORDINARY" name="" style="normal"/>
+ <entry key="213" number="0xEE15" class="ORDINARY" name="" style="normal"/>
+ <entry key="65" number="0x2259" class="RELATION" name="wedgeq" style="normal"/>
+ <entry key="239" number="0x00F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="112" number="0x227A" class="ORDINARY" name="prec" style="normal"/>
+ <entry key="68" number="0x019B" class="ORDINARY" name="lambdabar" style="normal"/>
+ <entry key="237" number="0x00FD" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0x25B3" class="ORDINARY" name="bigtriangleup" style="normal"/>
+ <entry key="89" number="0x25B1" class="ORDINARY" name="" style="normal"/>
+ <entry key="53" number="0xEC0B" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0xEC0F" class="ORDINARY" name="" style="normal"/>
+ <entry key="69" number="0xEC0E" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0x0307" class="ORDINARY" name="" style="normal"/>
+ <entry key="35" number="0x0300" class="ORDINARY" name="grave" style="normal"/>
+ <entry key="37" number="0x0303" class="ORDINARY" name="" style="normal"/>
+ <entry key="36" number="0x0302" class="ORDINARY" name="hat" style="normal"/>
+ <entry key="120" number="0xEB19" class="ORDINARY" name="" style="normal"/>
+ <entry key="183" number="0xEE09" class="ORDINARY" name="" style="normal"/>
+ <entry key="236" number="0x0161" class="ORDINARY" name="" style="normal"/>
+ <entry key="232" number="0x0160" class="ORDINARY" name="" style="normal"/>
+ <entry key="111" number="0x2218" class="ORDINARY" name="circ" style="normal"/>
+ <entry key="109" number="0x2213" class="ORDINARY" name="mp" style="normal"/>
+ <entry key="49" number="0xEC00" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0xEC06" class="ORDINARY" name="" style="normal"/>
+ <entry key="54" number="0xEC04" class="ORDINARY" name="" style="normal"/>
+ <entry key="55" number="0xEC05" class="ORDINARY" name="" style="normal"/>
+ <entry key="116" number="0x20E1" class="ORDINARY" name="overleftrightarrow" style="normal"/>
+ <entry key="59" number="0x2243" class="RELATION" name="simeq" style="normal"/>
+ <entry key="125" number="0xFE37" class="ORDINARY" name="" style="normal"/>
+ <entry key="87" number="0x25A1" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0x25AD" class="ORDINARY" name="" style="normal"/>
+ <entry key="170" number="0xEC23" class="ORDINARY" name="" style="normal"/>
+ <entry key="195" number="0xEE10" class="ORDINARY" name="" style="normal"/>
+ <entry key="82" number="0x2221" class="ORDINARY" name="measuredangle" style="normal"/>
+ <entry key="131" number="0x21CC" class="ORDINARY" name="rightleftharpoons" style="normal"/>
+ <entry key="168" number="0x301B" class="ORDINARY" name="" style="normal"/>
+ <entry key="61" number="0x226A" class="RELATION" name="ll" style="normal"/>
+ <entry key="63" number="0x226B" class="RELATION" name="gg" style="normal"/>
+ <entry key="238" number="0x00FE" class="ORDINARY" name="" style="normal"/>
+ <entry key="136" number="0xF8E7" class="ORDINARY" name="" style="normal"/>
+ <entry key="124" number="0xEC0C" class="ORDINARY" name="" style="normal"/>
+ <entry key="249" number="0x2044" class="ORDINARY" name="" style="normal"/>
+ <entry key="126" number="0xEC0D" class="ORDINARY" name="" style="normal"/>
+ <entry key="101" number="0x2299" class="ORDINARY" name="odot" style="normal"/>
+ <entry key="93" number="0x2198" class="ORDINARY" name="searrow" style="normal"/>
+ <entry key="91" number="0x2199" class="ORDINARY" name="swarrow" style="normal"/>
+ <entry key="94" number="0x2196" class="ORDINARY" name="nwarrow" style="normal"/>
+ <entry key="90" number="0x2197" class="ORDINARY" name="nearrow" style="normal"/>
+ <entry key="98" number="0x2195" class="ORDINARY" name="updownarrow" style="normal"/>
+ <entry key="80" number="0x2225" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0x2222" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="253" number="0x02C7" class="ORDINARY" name="" style="normal"/>
+ <entry key="72" number="0xEC11" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0xEC10" class="ORDINARY" name="" style="normal"/>
+ <entry key="103" number="0xE98F" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="235" number="0x00D0" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0x2127" class="ORDINARY" name="mho" style="normal"/>
+ <entry key="162" number="0x2124" class="ORDINARY" name="" style="normal"/>
+ <entry key="231" number="0xF8FF" class="ORDINARY" name="" style="normal"/>
+ <entry key="233" number="0x00DD" class="ORDINARY" name="" style="normal"/>
+ <entry key="234" number="0x00DE" class="ORDINARY" name="" style="normal"/>
+ <entry key="247" number="0x00BC" class="ORDINARY" name="" style="normal"/>
+ <entry key="246" number="0x00BD" class="ORDINARY" name="" style="normal"/>
+ <entry key="128" number="0x21C4" class="ORDINARY" name="rightleftarrows" style="normal"/>
+ <entry key="134" number="0x21C0" class="ORDINARY" name="rightharpoonup" style="normal"/>
+ <entry key="102" number="0x227B" class="ORDINARY" name="succ" style="normal"/>
+ <entry key="77" number="0x22EE" class="ORDINARY" name="vdots" style="normal"/>
+ <entry key="76" number="0x22EF" class="ORDINARY" name="cdots" style="normal"/>
+ <entry key="113" number="0xEB1A" class="ORDINARY" name="" style="normal"/>
+ <entry key="252" number="0x02D8" class="ORDINARY" name="" style="normal"/>
+ <entry key="110" number="0xFFFD" class="ORDINARY" name="" style="normal"/>
+ <entry key="240" number="0xFB01" class="ORDINARY" name="" style="normal"/>
+ <entry key="164" number="0x211A" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0x211D" class="ORDINARY" name="" style="normal"/>
+ <entry key="108" number="0x2113" class="ORDINARY" name="" style="normal"/>
+ <entry key="165" number="0x2115" class="ORDINARY" name="" style="normal"/>
+ <entry key="250" number="0x00A6" class="ORDINARY" name="" style="normal"/>
+ <entry key="254" number="0x02DA" class="ORDINARY" name="" style="normal"/>
+ <entry key="255" number="0x02DB" class="ORDINARY" name="" style="normal"/>
+ <entry key="251" number="0x02DD" class="ORDINARY" name="" style="normal"/>
+ <entry key="99" number="0x21D5" class="ORDINARY" name="Updownarrow" style="normal"/>
+ <entry key="67" number="0x2210" class="ORDINARY" name="coprod" style="normal"/>
+ <entry key="167" number="0x301A" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0x2026" class="ORDINARY" name="ldots" style="normal"/>
+ <entry key="58" number="0x223C" class="RELATION" name="sim" style="normal"/>
+ <entry key="51" number="0xEC02" class="ORDINARY" name="" style="normal"/>
+ <entry key="52" number="0xEC03" class="ORDINARY" name="" style="normal"/>
+ <entry key="50" number="0xEC01" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0x2235" class="BINOP" name="because" style="normal"/>
+ <entry key="171" number="0xEC24" class="ORDINARY" name="" style="normal"/>
+ <entry key="172" number="0xEC25" class="ORDINARY" name="" style="normal"/>
+ <entry key="173" number="0xEC26" class="ORDINARY" name="" style="normal"/>
+ <entry key="174" number="0xEC27" class="ORDINARY" name="" style="normal"/>
+ <entry key="169" number="0xEC22" class="ORDINARY" name="" style="normal"/>
+ <entry key="176" number="0xEE04" class="ORDINARY" name="" style="normal"/>
+ <entry key="177" number="0xEE05" class="ORDINARY" name="" style="normal"/>
+ <entry key="178" number="0xEE06" class="ORDINARY" name="" style="normal"/>
+ <entry key="181" number="0xEE07" class="ORDINARY" name="" style="normal"/>
+ <entry key="105" number="0xEE00" class="ORDINARY" name="" style="normal"/>
+ <entry key="106" number="0xEE01" class="ORDINARY" name="" style="normal"/>
+ <entry key="182" number="0xEE08" class="ORDINARY" name="" style="normal"/>
+ <entry key="242" number="0x0131" class="ORDINARY" name="" style="normal"/>
+ <entry key="192" number="0xEE0D" class="ORDINARY" name="" style="normal"/>
+ <entry key="193" number="0xEE0E" class="ORDINARY" name="" style="normal"/>
+ <entry key="194" number="0xEE0F" class="ORDINARY" name="" style="normal"/>
+ <entry key="186" number="0xEE0A" class="ORDINARY" name="" style="normal"/>
+ <entry key="187" number="0xEE0B" class="ORDINARY" name="" style="normal"/>
+ <entry key="188" number="0xEE0C" class="ORDINARY" name="" style="normal"/>
+ <entry key="135" number="0x21BD" class="ORDINARY" name="leftharpoondown" style="normal"/>
+ <entry key="100" number="0x25CB" class="ORDINARY" name="bigcirc" style="normal"/>
+ <entry key="78" number="0x22F0" class="ORDINARY" name="adots" style="normal"/>
+ <entry key="79" number="0x22F1" class="ORDINARY" name="ddots" style="normal"/>
+ <entry key="132" number="0xEB03" class="ORDINARY" name="" style="normal"/>
+ <entry key="130" number="0xEB02" class="ORDINARY" name="" style="normal"/>
+ <entry key="129" number="0xEB01" class="ORDINARY" name="" style="normal"/>
+ <entry key="117" number="0xEB00" class="ORDINARY" name="" style="normal"/>
+ <entry key="241" number="0xFB02" class="ORDINARY" name="" style="normal"/>
+ <entry key="95" number="0xEB06" class="ORDINARY" name="" style="normal"/>
+ <entry key="92" number="0xEB05" class="ORDINARY" name="" style="normal"/>
+ <entry key="133" number="0xEB04" class="ORDINARY" name="" style="normal"/>
+ </unicodetable>
+ <unicodetable font="mt%20symbol">
+ <entry key="206" number="0x2208" class="RELATION" name="in" style="normal"/>
+ <entry key="207" number="0x2209" class="RELATION" name="notin" style="normal"/>
+ <entry key="182" number="0x2202" class="ORDINARY" name="partial" style="normal"/>
+ <entry key="36" number="0x2203" class="ORDINARY" name="exists" style="normal"/>
+ <entry key="34" number="0x2200" class="ORDINARY" name="forall" style="normal"/>
+ <entry key="209" number="0x2207" class="ORDINARY" name="nabla" style="normal"/>
+ <entry key="198" number="0x2205" class="BINOP" name="oslash" style="normal"/>
+ <entry key="39" number="0x220D" class="RELATION" name="ni" style="normal"/>
+ <entry key="124" number="0x007C" class="ORDINARY" name="vert" style="normal"/>
+ <entry key="123" number="0x007B" class="ORDINARY" name="lbrace" style="normal"/>
+ <entry key="125" number="0x007D" class="ORDINARY" name="rbrace" style="normal"/>
+ <entry key="176" number="0x00B0" class="ORDINARY" name="degree" style="normal"/>
+ <entry key="177" number="0x00B1" class="BINOP" name="pm" style="normal"/>
+ <entry key="178" number="0x2033" class="ORDINARY" name="" style="normal"/>
+ <entry key="162" number="0x2032" class="ORDINARY" name="prime" style="normal"/>
+ <entry key="111" number="0x03BF" class="ORDINARY" name="o" style="normal"/>
+ <entry key="120" number="0x03BE" class="ORDINARY" name="xi" style="normal"/>
+ <entry key="110" number="0x03BD" class="ORDINARY" name="nu" style="normal"/>
+ <entry key="109" number="0x03BC" class="ORDINARY" name="mu" style="normal"/>
+ <entry key="108" number="0x03BB" class="ORDINARY" name="lambda" style="normal"/>
+ <entry key="107" number="0x03BA" class="ORDINARY" name="kappa" style="normal"/>
+ <entry key="225" number="0x2329" class="ORDINARY" name="langle" style="normal"/>
+ <entry key="245" number="0x2321" class="ORDINARY" name="" style="normal"/>
+ <entry key="243" number="0x2320" class="ORDINARY" name="" style="normal"/>
+ <entry key="241" number="0x232A" class="ORDINARY" name="rangle" style="normal"/>
+ <entry key="105" number="0x03B9" class="ORDINARY" name="iota" style="normal"/>
+ <entry key="113" number="0x03B8" class="ORDINARY" name="theta" style="normal"/>
+ <entry key="104" number="0x03B7" class="ORDINARY" name="eta" style="normal"/>
+ <entry key="122" number="0x03B6" class="ORDINARY" name="zeta" style="normal"/>
+ <entry key="101" number="0x03B5" class="ORDINARY" name="varepsilon" style="normal"/>
+ <entry key="100" number="0x03B4" class="ORDINARY" name="delta" style="normal"/>
+ <entry key="103" number="0x03B3" class="ORDINARY" name="gamma" style="normal"/>
+ <entry key="98" number="0x03B2" class="ORDINARY" name="beta" style="normal"/>
+ <entry key="97" number="0x03B1" class="ORDINARY" name="alpha" style="normal"/>
+ <entry key="184" number="0x00F7" class="BINOP" name="div" style="normal"/>
+ <entry key="79" number="0x039F" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0x039D" class="ORDINARY" name="" style="normal"/>
+ <entry key="88" number="0x039E" class="ORDINARY" name="Xi" style="normal"/>
+ <entry key="76" number="0x039B" class="ORDINARY" name="Lambda" style="normal"/>
+ <entry key="77" number="0x039C" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0x039A" class="ORDINARY" name="" style="normal"/>
+ <entry key="166" number="0x0192" class="ORDINARY" name="" style="normal"/>
+ <entry key="81" number="0x0398" class="ORDINARY" name="Theta" style="normal"/>
+ <entry key="73" number="0x0399" class="ORDINARY" name="" style="normal"/>
+ <entry key="90" number="0x0396" class="ORDINARY" name="" style="normal"/>
+ <entry key="72" number="0x0397" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0x0394" class="ORDINARY" name="Delta" style="normal"/>
+ <entry key="69" number="0x0395" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0x0392" class="ORDINARY" name="" style="normal"/>
+ <entry key="71" number="0x0393" class="ORDINARY" name="Gamma" style="normal"/>
+ <entry key="65" number="0x0391" class="ORDINARY" name="" style="normal"/>
+ <entry key="201" number="0x2283" class="RELATION" name="supset" style="normal"/>
+ <entry key="202" number="0x2287" class="RELATION" name="supseteq" style="normal"/>
+ <entry key="203" number="0x2284" class="RELATION" name="nsubset" style="normal"/>
+ <entry key="214" number="0x221A" class="ORDINARY" name="surd" style="normal"/>
+ <entry key="181" number="0x221D" class="RELATION" name="propto" style="normal"/>
+ <entry key="213" number="0x220F" class="ORDINARY" name="prod" style="normal"/>
+ <entry key="229" number="0x2211" class="ORDINARY" name="sum" style="normal"/>
+ <entry key="219" number="0x21D4" class="RELATION" name="Leftrightarrow" style="normal"/>
+ <entry key="45" number="0x2212" class="BINOP" name="minus" style="normal"/>
+ <entry key="221" number="0x21D1" class="RELATION" name="Uparrow" style="normal"/>
+ <entry key="220" number="0x21D0" class="RELATION" name="Leftarrow" style="normal"/>
+ <entry key="223" number="0x21D3" class="RELATION" name="Downarrow" style="normal"/>
+ <entry key="222" number="0x21D2" class="RELATION" name="Rightarrow" style="normal"/>
+ <entry key="174" number="0x2192" class="RELATION" name="rightarrow" style="normal"/>
+ <entry key="70" number="0x03A6" class="ORDINARY" name="Phi" style="normal"/>
+ <entry key="67" number="0x03A7" class="ORDINARY" name="" style="normal"/>
+ <entry key="84" number="0x03A4" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0x03A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0x03A3" class="ORDINARY" name="Sigma" style="normal"/>
+ <entry key="80" number="0x03A0" class="ORDINARY" name="Pi" style="normal"/>
+ <entry key="82" number="0x03A1" class="ORDINARY" name="" style="normal"/>
+ <entry key="52" number="0x0034" class="ORDINARY" name="" style="normal"/>
+ <entry key="89" number="0x03A8" class="ORDINARY" name="Psi" style="normal"/>
+ <entry key="87" number="0x03A9" class="ORDINARY" name="Omega" style="normal"/>
+ <entry key="192" number="0x2135" class="ORDINARY" name="aleph" style="normal"/>
+ <entry key="215" number="0x22C5" class="BINOP" name="cdot" style="normal"/>
+ <entry key="224" number="0x26C4" class="ORDINARY" name="Diamond" style="normal"/>
+ <entry key="119" number="0x03C9" class="ORDINARY" name="omega" style="normal"/>
+ <entry key="233" number="0xF8EE" class="ORDINARY" name="" style="normal"/>
+ <entry key="232" number="0xF8ED" class="ORDINARY" name="" style="normal"/>
+ <entry key="231" number="0xF8EC" class="ORDINARY" name="" style="normal"/>
+ <entry key="230" number="0xF8EB" class="ORDINARY" name="" style="normal"/>
+ <entry key="228" number="0xF8EA" class="ORDINARY" name="" style="normal"/>
+ <entry key="185" number="0x2260" class="RELATION" name="neq" style="normal"/>
+ <entry key="186" number="0x2261" class="RELATION" name="equiv" style="normal"/>
+ <entry key="163" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="179" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="46" number="0x002E" class="ORDINARY" name="" style="normal"/>
+ <entry key="47" number="0x002F" class="ORDINARY" name="" style="normal"/>
+ <entry key="91" number="0x005B" class="ORDINARY" name="" style="normal"/>
+ <entry key="93" number="0x005D" class="ORDINARY" name="" style="normal"/>
+ <entry key="95" number="0x005F" class="ORDINARY" name="" style="normal"/>
+ <entry key="227" number="0xF8E9" class="ORDINARY" name="" style="normal"/>
+ <entry key="226" number="0xF8E8" class="ORDINARY" name="" style="normal"/>
+ <entry key="190" number="0xF8E7" class="ORDINARY" name="" style="normal"/>
+ <entry key="189" number="0xF8E6" class="RELATION" name="" style="normal"/>
+ <entry key="96" number="0xF8E5" class="ORDINARY" name="" style="normal"/>
+ <entry key="204" number="0x2282" class="RELATION" name="subset" style="normal"/>
+ <entry key="205" number="0x2286" class="RELATION" name="subseteq" style="normal"/>
+ <entry key="197" number="0x2295" class="BINOP" name="oplus" style="normal"/>
+ <entry key="196" number="0x2297" class="BINOP" name="otimes" style="normal"/>
+ <entry key="175" number="0x2193" class="RELATION" name="downarrow" style="normal"/>
+ <entry key="172" number="0x2190" class="RELATION" name="leftarrow" style="normal"/>
+ <entry key="173" number="0x2191" class="RELATION" name="uparrow" style="normal"/>
+ <entry key="171" number="0x2194" class="RELATION" name="leftrightarrow" style="normal"/>
+ <entry key="217" number="0x2227" class="BINOP" name="wedge" style="normal"/>
+ <entry key="208" number="0x2220" class="ORDINARY" name="angle" style="normal"/>
+ <entry key="43" number="0x002B" class="ORDINARY" name="" style="normal"/>
+ <entry key="44" number="0x002C" class="ORDINARY" name="" style="normal"/>
+ <entry key="218" number="0x2228" class="BINOP" name="vee" style="normal"/>
+ <entry key="199" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="165" number="0x221E" class="ORDINARY" name="infty" style="normal"/>
+ <entry key="40" number="0x0028" class="ORDINARY" name="" style="normal"/>
+ <entry key="41" number="0x0029" class="ORDINARY" name="" style="normal"/>
+ <entry key="200" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="242" number="0x222B" class="ORDINARY" name="int" style="normal"/>
+ <entry key="32" number="0x0020" class="ORDINARY" name="" style="normal"/>
+ <entry key="33" number="0x0021" class="ORDINARY" name="" style="normal"/>
+ <entry key="35" number="0x0023" class="ORDINARY" name="" style="normal"/>
+ <entry key="37" number="0x0025" class="ORDINARY" name="" style="normal"/>
+ <entry key="38" number="0x0026" class="ORDINARY" name="" style="normal"/>
+ <entry key="210" number="0x00AE" class="ORDINARY" name="" style="normal"/>
+ <entry key="180" number="0x00D7" class="BINOP" name="times" style="normal"/>
+ <entry key="212" number="0x2122" class="ORDINARY" name="" style="normal"/>
+ <entry key="246" number="0xF8F6" class="ORDINARY" name="" style="normal"/>
+ <entry key="247" number="0xF8F7" class="ORDINARY" name="" style="normal"/>
+ <entry key="239" number="0xF8F4" class="ORDINARY" name="" style="normal"/>
+ <entry key="237" number="0xF8F2" class="ORDINARY" name="" style="normal"/>
+ <entry key="238" number="0xF8F3" class="ORDINARY" name="" style="normal"/>
+ <entry key="235" number="0xF8F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="236" number="0xF8F1" class="ORDINARY" name="" style="normal"/>
+ <entry key="248" number="0xF8F8" class="ORDINARY" name="" style="normal"/>
+ <entry key="249" number="0xF8F9" class="ORDINARY" name="" style="normal"/>
+ <entry key="253" number="0xF8FD" class="ORDINARY" name="" style="normal"/>
+ <entry key="254" number="0xF8FE" class="ORDINARY" name="" style="normal"/>
+ <entry key="251" number="0xF8FB" class="ORDINARY" name="" style="normal"/>
+ <entry key="252" number="0xF8FC" class="ORDINARY" name="" style="normal"/>
+ <entry key="250" number="0xF8FA" class="ORDINARY" name="" style="normal"/>
+ <entry key="244" number="0xF8F5" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0x03D1" class="ORDINARY" name="" style="normal"/>
+ <entry key="161" number="0x03D2" class="ORDINARY" name="Upsilon" style="normal"/>
+ <entry key="106" number="0x03D5" class="ORDINARY" name="varphi" style="normal"/>
+ <entry key="118" number="0x03D6" class="ORDINARY" name="varpi" style="normal"/>
+ <entry key="168" number="0x2666" class="ORDINARY" name="diamondsuit" style="normal"/>
+ <entry key="234" number="0xF8EF" class="ORDINARY" name="" style="normal"/>
+ <entry key="216" number="0x00AC" class="ORDINARY" name="neg" style="normal"/>
+ <entry key="194" number="0x211C" class="ORDINARY" name="Re" style="normal"/>
+ <entry key="193" number="0x2111" class="ORDINARY" name="Im" style="normal"/>
+ <entry key="195" number="0x2118" class="ORDINARY" name="wp" style="normal"/>
+ <entry key="211" number="0x00A9" class="ORDINARY" name="" style="normal"/>
+ <entry key="169" number="0x2665" class="ORDINARY" name="heartsuit" style="normal"/>
+ <entry key="167" number="0x2663" class="ORDINARY" name="clubsuit" style="normal"/>
+ <entry key="42" number="0x2217" class="BINOP" name="ast" style="normal"/>
+ <entry key="188" number="0x2026" class="ORDINARY" name="ldots" style="normal"/>
+ <entry key="183" number="0x2022" class="BINOP" name="bullet" style="normal"/>
+ <entry key="126" number="0x223C" class="RELATION" name="sim" style="normal"/>
+ <entry key="94" number="0x22A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="170" number="0x2660" class="ORDINARY" name="spadesuit" style="normal"/>
+ <entry key="92" number="0x2234" class="BINOP" name="therefore" style="normal"/>
+ <entry key="55" number="0x0037" class="ORDINARY" name="" style="normal"/>
+ <entry key="54" number="0x0036" class="ORDINARY" name="" style="normal"/>
+ <entry key="53" number="0x0035" class="ORDINARY" name="" style="normal"/>
+ <entry key="51" number="0x0033" class="ORDINARY" name="" style="normal"/>
+ <entry key="50" number="0x0032" class="ORDINARY" name="" style="normal"/>
+ <entry key="49" number="0x0031" class="ORDINARY" name="" style="normal"/>
+ <entry key="48" number="0x0030" class="ORDINARY" name="" style="normal"/>
+ <entry key="57" number="0x0039" class="ORDINARY" name="" style="normal"/>
+ <entry key="56" number="0x0038" class="ORDINARY" name="" style="normal"/>
+ <entry key="164" number="0x2244" class="ORDINARY" name="nsime" style="normal"/>
+ <entry key="64" number="0x2245" class="RELATION" name="cong" style="normal"/>
+ <entry key="187" number="0x2248" class="RELATION" name="approx" style="normal"/>
+ <entry key="112" number="0x03C0" class="ORDINARY" name="pi" style="normal"/>
+ <entry key="86" number="0x03C2" class="ORDINARY" name="" style="normal"/>
+ <entry key="115" number="0x03C3" class="ORDINARY" name="sigma" style="normal"/>
+ <entry key="116" number="0x03C4" class="ORDINARY" name="tau" style="normal"/>
+ <entry key="117" number="0x03C5" class="ORDINARY" name="upsilon" style="normal"/>
+ <entry key="102" number="0x03C6" class="ORDINARY" name="phi" style="normal"/>
+ <entry key="99" number="0x03C7" class="ORDINARY" name="chi" style="normal"/>
+ <entry key="121" number="0x03C8" class="ORDINARY" name="psi" style="normal"/>
+ <entry key="63" number="0x003F" class="ORDINARY" name="" style="normal"/>
+ <entry key="62" number="0x003E" class="ORDINARY" name="greater" style="normal"/>
+ <entry key="61" number="0x003D" class="ORDINARY" name="" style="normal"/>
+ <entry key="60" number="0x003C" class="ORDINARY" name="less" style="normal"/>
+ <entry key="59" number="0x003B" class="ORDINARY" name="" style="normal"/>
+ <entry key="58" number="0x003A" class="ORDINARY" name="colon" style="normal"/>
+ <entry key="114" number="0x03C1" class="ORDINARY" name="rho" style="normal"/>
+ <entry key="191" number="0x21B5" class="ORDINARY" name="carriagereturn" style="normal"/>
+ </unicodetable>
+ <unicodetable font="symbol">
+ <entry key="34" number="0x2200" class="ORDINARY" name="forall" style="normal"/>
+ <entry key="36" number="0x2203" class="ORDINARY" name="exists" style="normal"/>
+ <entry key="39" number="0x220D" class="RELATION" name="ni" style="normal"/>
+ <entry key="40" number="0x0028" class="ORDINARY" name="" style="normal"/>
+ <entry key="41" number="0x0029" class="ORDINARY" name="" style="normal"/>
+ <entry key="64" number="0x2245" class="RELATION" name="cong" style="normal"/>
+ <entry key="65" number="0x0391" class="ORDINARY" name="" style="normal"/>
+ <entry key="66" number="0x0392" class="ORDINARY" name="" style="normal"/>
+ <entry key="67" number="0x03A7" class="ORDINARY" name="" style="normal"/>
+ <entry key="68" number="0x0394" class="ORDINARY" name="Delta" style="normal"/>
+ <entry key="69" number="0x0395" class="ORDINARY" name="" style="normal"/>
+ <entry key="70" number="0x03A6" class="ORDINARY" name="Phi" style="normal"/>
+ <entry key="71" number="0x0393" class="ORDINARY" name="Gamma" style="normal"/>
+ <entry key="72" number="0x0397" class="ORDINARY" name="" style="normal"/>
+ <entry key="73" number="0x0399" class="ORDINARY" name="" style="normal"/>
+ <entry key="74" number="0x03D1" class="ORDINARY" name="" style="normal"/>
+ <entry key="75" number="0x039A" class="ORDINARY" name="" style="normal"/>
+ <entry key="76" number="0x039B" class="ORDINARY" name="Lambda" style="normal"/>
+ <entry key="77" number="0x039C" class="ORDINARY" name="" style="normal"/>
+ <entry key="78" number="0x039D" class="ORDINARY" name="" style="normal"/>
+ <entry key="79" number="0x039F" class="ORDINARY" name="" style="normal"/>
+ <entry key="80" number="0x03A0" class="ORDINARY" name="Pi" style="normal"/>
+ <entry key="81" number="0x0398" class="ORDINARY" name="Theta" style="normal"/>
+ <entry key="82" number="0x03A1" class="ORDINARY" name="" style="normal"/>
+ <entry key="83" number="0x03A3" class="ORDINARY" name="Sigma" style="normal"/>
+ <entry key="84" number="0x03A4" class="ORDINARY" name="" style="normal"/>
+ <entry key="85" number="0x03A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="86" number="0x03C2" class="ORDINARY" name="" style="normal"/>
+ <entry key="87" number="0x03A9" class="ORDINARY" name="Omega" style="normal"/>
+ <entry key="88" number="0x039E" class="ORDINARY" name="Xi" style="normal"/>
+ <entry key="89" number="0x03A8" class="ORDINARY" name="Psi" style="normal"/>
+ <entry key="90" number="0x0396" class="ORDINARY" name="" style="normal"/>
+ <entry key="91" number="0x005B" class="ORDINARY" name="" style="normal"/>
+ <entry key="92" number="0x2234" class="BINOP" name="therefore" style="normal"/>
+ <entry key="93" number="0x005D" class="ORDINARY" name="" style="normal"/>
+ <entry key="94" number="0x22A5" class="ORDINARY" name="" style="normal"/>
+ <entry key="96" number="0xF8E5" class="ORDINARY" name="" style="normal"/>
+ <entry key="97" number="0x03B1" class="ORDINARY" name="alpha" style="normal"/>
+ <entry key="98" number="0x03B2" class="ORDINARY" name="beta" style="normal"/>
+ <entry key="99" number="0x03C7" class="ORDINARY" name="chi" style="normal"/>
+ <entry key="100" number="0x03B4" class="ORDINARY" name="delta" style="normal"/>
+ <entry key="101" number="0x03B5" class="ORDINARY" name="varepsilon" style="normal"/>
+ <entry key="102" number="0x03C6" class="ORDINARY" name="phi" style="normal"/>
+ <entry key="103" number="0x03B3" class="ORDINARY" name="gamma" style="normal"/>
+ <entry key="104" number="0x03B7" class="ORDINARY" name="eta" style="normal"/>
+ <entry key="105" number="0x03B9" class="ORDINARY" name="iota" style="normal"/>
+ <entry key="106" number="0x03D5" class="ORDINARY" name="varphi" style="normal"/>
+ <entry key="107" number="0x03BA" class="ORDINARY" name="kappa" style="normal"/>
+ <entry key="108" number="0x03BB" class="ORDINARY" name="lambda" style="normal"/>
+ <entry key="109" number="0x03BC" class="ORDINARY" name="mu" style="normal"/>
+ <entry key="110" number="0x03BD" class="ORDINARY" name="nu" style="normal"/>
+ <entry key="112" number="0x03C0" class="ORDINARY" name="pi" style="normal"/>
+ <entry key="113" number="0x03B8" class="ORDINARY" name="theta" style="normal"/>
+ <entry key="114" number="0x03C1" class="ORDINARY" name="rho" style="normal"/>
+ <entry key="115" number="0x03C3" class="ORDINARY" name="sigma" style="normal"/>
+ <entry key="116" number="0x03C4" class="ORDINARY" name="tau" style="normal"/>
+ <entry key="117" number="0x03C5" class="ORDINARY" name="upsilon" style="normal"/>
+ <entry key="118" number="0x03D6" class="ORDINARY" name="varpi" style="normal"/>
+ <entry key="119" number="0x03C9" class="ORDINARY" name="omega" style="normal"/>
+ <entry key="120" number="0x03BE" class="ORDINARY" name="xi" style="normal"/>
+ <entry key="121" number="0x03C8" class="ORDINARY" name="psi" style="normal"/>
+ <entry key="122" number="0x03B6" class="ORDINARY" name="zeta" style="normal"/>
+ <entry key="123" number="0x007B" class="ORDINARY" name="lbrace" style="normal"/>
+ <entry key="124" number="0x007C" class="ORDINARY" name="vert" style="normal"/>
+ <entry key="125" number="0x007D" class="ORDINARY" name="rbrace" style="normal"/>
+ <entry key="126" number="0x223C" class="RELATION" name="sim" style="normal"/>
+ <entry key="161" number="0x03D2" class="ORDINARY" name="Upsilon" style="normal"/>
+ <entry key="162" number="0x2032" class="ORDINARY" name="prime" style="normal"/>
+ <entry key="163" number="0x2264" class="RELATION" name="leq" style="normal"/>
+ <entry key="164" number="0x2244" class="ORDINARY" name="nsime" style="normal"/>
+ <entry key="165" number="0x221E" class="ORDINARY" name="infty" style="normal"/>
+ <entry key="166" number="0x0192" class="ORDINARY" name="" style="normal"/>
+ <entry key="167" number="0x2663" class="ORDINARY" name="clubsuit" style="normal"/>
+ <entry key="168" number="0x2666" class="ORDINARY" name="diamondsuit" style="normal"/>
+ <entry key="169" number="0x2665" class="ORDINARY" name="heartsuit" style="normal"/>
+ <entry key="170" number="0x2660" class="ORDINARY" name="spadesuit" style="normal"/>
+ <entry key="171" number="0x2194" class="RELATION" name="leftrightarrow" style="normal"/>
+ <entry key="172" number="0x2190" class="RELATION" name="leftarrow" style="normal"/>
+ <entry key="173" number="0x2191" class="RELATION" name="uparrow" style="normal"/>
+ <entry key="174" number="0x2192" class="RELATION" name="rightarrow" style="normal"/>
+ <entry key="175" number="0x2193" class="RELATION" name="downarrow" style="normal"/>
+ <entry key="176" number="0x00B0" class="ORDINARY" name="degree" style="normal"/>
+ <entry key="177" number="0x00B1" class="BINOP" name="pm" style="normal"/>
+ <entry key="178" number="0x2033" class="ORDINARY" name="" style="normal"/>
+ <entry key="179" number="0x2265" class="RELATION" name="geq" style="normal"/>
+ <entry key="180" number="0x00D7" class="BINOP" name="times" style="normal"/>
+ <entry key="181" number="0x221D" class="RELATION" name="propto" style="normal"/>
+ <entry key="182" number="0x2202" class="ORDINARY" name="partial" style="normal"/>
+ <entry key="183" number="0x2022" class="BINOP" name="bullet" style="normal"/>
+ <entry key="184" number="0x00F7" class="BINOP" name="div" style="normal"/>
+ <entry key="185" number="0x2260" class="RELATION" name="neq" style="normal"/>
+ <entry key="186" number="0x2261" class="RELATION" name="equiv" style="normal"/>
+ <entry key="187" number="0x2248" class="RELATION" name="approx" style="normal"/>
+ <entry key="188" number="0x2026" class="ORDINARY" name="ldots" style="normal"/>
+ <entry key="189" number="0xF8E6" class="RELATION" name="" style="normal"/>
+ <entry key="190" number="0xF8E7" class="ORDINARY" name="" style="normal"/>
+ <entry key="191" number="0x21B5" class="ORDINARY" name="carriagereturn" style="normal"/>
+ <entry key="192" number="0x2135" class="ORDINARY" name="aleph" style="normal"/>
+ <entry key="193" number="0x2111" class="ORDINARY" name="Im" style="normal"/>
+ <entry key="194" number="0x211C" class="ORDINARY" name="Re" style="normal"/>
+ <entry key="195" number="0x2118" class="ORDINARY" name="wp" style="normal"/>
+ <entry key="196" number="0x2297" class="BINOP" name="otimes" style="normal"/>
+ <entry key="197" number="0x2295" class="BINOP" name="oplus" style="normal"/>
+ <entry key="198" number="0x2205" class="BINOP" name="oslash" style="normal"/>
+ <entry key="199" number="0x2229" class="ORDINARY" name="cap" style="normal"/>
+ <entry key="200" number="0x222A" class="ORDINARY" name="cup" style="normal"/>
+ <entry key="201" number="0x2283" class="RELATION" name="supset" style="normal"/>
+ <entry key="202" number="0x2287" class="RELATION" name="supseteq" style="normal"/>
+ <entry key="203" number="0x2284" class="RELATION" name="nsubset" style="normal"/>
+ <entry key="204" number="0x2282" class="RELATION" name="subset" style="normal"/>
+ <entry key="205" number="0x2286" class="RELATION" name="subseteq" style="normal"/>
+ <entry key="206" number="0x2208" class="RELATION" name="in" style="normal"/>
+ <entry key="207" number="0x2209" class="RELATION" name="notin" style="normal"/>
+ <entry key="208" number="0x2220" class="ORDINARY" name="angle" style="normal"/>
+ <entry key="209" number="0x2207" class="ORDINARY" name="nabla" style="normal"/>
+ <entry key="210" number="0x00AE" class="ORDINARY" name="" style="normal"/>
+ <entry key="211" number="0x00A9" class="ORDINARY" name="" style="normal"/>
+ <entry key="212" number="0x2122" class="ORDINARY" name="" style="normal"/>
+ <entry key="213" number="0x220F" class="ORDINARY" name="prod" style="normal"/>
+ <entry key="214" number="0x221A" class="ORDINARY" name="surd" style="normal"/>
+ <entry key="215" number="0x22C5" class="BINOP" name="cdot" style="normal"/>
+ <entry key="216" number="0x00AC" class="ORDINARY" name="neg" style="normal"/>
+ <entry key="217" number="0x2227" class="BINOP" name="wedge" style="normal"/>
+ <entry key="218" number="0x2228" class="BINOP" name="vee" style="normal"/>
+ <entry key="219" number="0x21D4" class="RELATION" name="Leftrightarrow" style="normal"/>
+ <entry key="220" number="0x21D0" class="RELATION" name="Leftarrow" style="normal"/>
+ <entry key="221" number="0x21D1" class="RELATION" name="Uparrow" style="normal"/>
+ <entry key="222" number="0x21D2" class="RELATION" name="Rightarrow" style="normal"/>
+ <entry key="223" number="0x21D3" class="RELATION" name="Downarrow" style="normal"/>
+ <entry key="224" number="0x26C4" class="ORDINARY" name="Diamond" style="normal"/>
+ <entry key="225" number="0x2329" class="ORDINARY" name="langle" style="normal"/>
+ <entry key="226" number="0xF8E8" class="ORDINARY" name="" style="normal"/>
+ <entry key="227" number="0xF8E9" class="ORDINARY" name="" style="normal"/>
+ <entry key="228" number="0xF8EA" class="ORDINARY" name="" style="normal"/>
+ <entry key="229" number="0x2211" class="ORDINARY" name="sum" style="normal"/>
+ <entry key="230" number="0xF8EB" class="ORDINARY" name="" style="normal"/>
+ <entry key="231" number="0xF8EC" class="ORDINARY" name="" style="normal"/>
+ <entry key="232" number="0xF8ED" class="ORDINARY" name="" style="normal"/>
+ <entry key="233" number="0xF8EE" class="ORDINARY" name="" style="normal"/>
+ <entry key="234" number="0xF8EF" class="ORDINARY" name="" style="normal"/>
+ <entry key="235" number="0xF8F0" class="ORDINARY" name="" style="normal"/>
+ <entry key="236" number="0xF8F1" class="ORDINARY" name="" style="normal"/>
+ <entry key="237" number="0xF8F2" class="ORDINARY" name="" style="normal"/>
+ <entry key="238" number="0xF8F3" class="ORDINARY" name="" style="normal"/>
+ <entry key="239" number="0xF8F4" class="ORDINARY" name="" style="normal"/>
+ <entry key="241" number="0x232A" class="ORDINARY" name="rangle" style="normal"/>
+ <entry key="242" number="0x222B" class="ORDINARY" name="int" style="normal"/>
+ <entry key="243" number="0x2320" class="ORDINARY" name="" style="normal"/>
+ <entry key="244" number="0xF8F5" class="ORDINARY" name="" style="normal"/>
+ <entry key="245" number="0x2321" class="ORDINARY" name="" style="normal"/>
+ <entry key="246" number="0xF8F6" class="ORDINARY" name="" style="normal"/>
+ <entry key="247" number="0xF8F7" class="ORDINARY" name="" style="normal"/>
+ <entry key="248" number="0xF8F8" class="ORDINARY" name="" style="normal"/>
+ <entry key="249" number="0xF8F9" class="ORDINARY" name="" style="normal"/>
+ <entry key="250" number="0xF8FA" class="ORDINARY" name="" style="normal"/>
+ <entry key="251" number="0xF8FB" class="ORDINARY" name="" style="normal"/>
+ <entry key="252" number="0xF8FC" class="ORDINARY" name="" style="normal"/>
+ <entry key="253" number="0xF8FD" class="ORDINARY" name="" style="normal"/>
+ <entry key="254" number="0xF8FE" class="ORDINARY" name="" style="normal"/>
+ </unicodetable>
+</table>
diff --git a/lib/kformula/prototype/unicode.py b/lib/kformula/prototype/unicode.py
new file mode 100755
index 00000000..3559711d
--- /dev/null
+++ b/lib/kformula/prototype/unicode.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+
+import sys
+from qt import *
+from xml.sax import saxutils, handler, make_parser
+
+class Form1(QWidget):
+ def __init__(self,parent = None,name = None,fl = 0):
+ QWidget.__init__(self,parent,name,fl)
+
+ if name == None:
+ self.setName('Form1')
+
+ self.setCaption(self.tr('Form1'))
+ grid = QGridLayout(self)
+ grid.setSpacing(6)
+ grid.setMargin(11)
+
+ self.chars = {}
+ self.fontName = None
+
+ begin = 32
+ end = 256
+ for i in range(begin, end):
+
+ charLabel = QLabel(self,'charLabel' + chr(i))
+ charLabel.setFont(QFont("symbol", 16))
+ charLabel.setText(self.tr(chr(i)))
+ grid.addWidget(charLabel, i-begin, 0)
+
+ number = QLineEdit(self,'Number' + chr(i))
+ grid.addWidget(number, i-begin, 1)
+
+ latexName = QLineEdit(self,'latexName' + chr(i))
+ grid.addWidget(latexName, i-begin, 2)
+
+ charClass = QLineEdit(self,'charClass' + chr(i))
+ grid.addWidget(charClass, i-begin, 3)
+
+ self.chars[i] = (charLabel, number, latexName, charClass)
+
+ def fontList(self):
+ list = []
+ for i in self.chars:
+ charLabel, number, latexName, charClass = self.chars[i]
+ if str(number.text()) != "" or str(latexName.text()) != "" or str(charClass.text()) != "":
+ list.append((i, str(number.text()), str(latexName.text()), str(charClass.text())))
+ return list
+
+ def setFont(self, fontName, font):
+ fontName = fontName.replace("%20", " ")
+ self.fontName = fontName
+ for i in self.chars:
+ charLabel, number, latexName, charClass = self.chars[i]
+ charLabel.setFont(QFont(fontName, 16))
+ number.setText("")
+ latexName.setText("")
+ charClass.setText("")
+
+ for (key, number, latexName, charClass) in font:
+ i = int(key)
+ charLabel, numberWidget, latexNameWidget, charClassWidget = self.chars[i]
+ numberWidget.setText(number)
+ latexNameWidget.setText(latexName)
+ charClassWidget.setText(charClass)
+
+
+class Widget(QWidget):
+
+ def __init__(self):
+ QWidget.__init__(self)
+
+ vbox = QVBoxLayout(self)
+ vbox.setSpacing(6)
+ vbox.setMargin(0)
+
+ hbox = QHBoxLayout()
+ hbox.setSpacing(6)
+ hbox.setMargin(0)
+
+ loadButton = QPushButton("load", self)
+ saveButton = QPushButton("save", self)
+
+ QObject.connect(loadButton, SIGNAL("pressed()"), self.load)
+ QObject.connect(saveButton, SIGNAL("pressed()"), self.save)
+
+ hbox.addWidget(loadButton)
+ hbox.addWidget(saveButton)
+
+ vbox.addLayout(hbox)
+
+ splitter = QSplitter(self)
+ splitter.setOrientation(Qt.Vertical)
+
+ self.listbox = QListBox(splitter)
+
+ sv = QScrollView(splitter)
+ big_box = QVBox(sv.viewport())
+ sv.addChild(big_box, 0, 0)
+ self.child = Form1(big_box)
+
+ vbox.addWidget(splitter)
+
+ self.connect(self.listbox, SIGNAL('highlighted( const QString& )'),
+ self.fontHighlighted)
+
+ def fontHighlighted(self, fontStr):
+ if self.child.fontName:
+ self.fonts[self.child.fontName] = self.child.fontList()
+
+ font = str(fontStr)
+ self.child.setFont(font, self.fonts[font])
+
+ def load(self):
+ self.fonts = {}
+ parser = make_parser()
+ parser.setContentHandler(ContentGenerator(self.fonts))
+ parser.parse("symbol.xml")
+
+ self.listbox.clear()
+ for font in self.fonts:
+ self.listbox.insertItem(font)
+ self.listbox.sort()
+
+ def save(self):
+ if self.child.fontName:
+ self.fonts[self.child.fontName] = self.child.fontList()
+
+ f = open("symbol.xml", "w")
+ print >> f, '<?xml version="1.0" encoding="iso-8859-1"?>'
+ print >> f, '<table>'
+ for font in self.fonts:
+ print >> f, ' <unicodetable font="' + font + '">'
+ for (key, number, latexName, charClass) in self.fonts[font]:
+ if not charClass or charClass == '':
+ charClass = 'ORDINARY'
+ print >> f, ' <entry key="' + str(key) + \
+ '" number="' + str(number) + \
+ '" name="' + str(latexName) + \
+ '" class="' + str(charClass) + \
+ '"/>'
+
+ print >> f, ' </unicodetable>'
+ print >> f, '</table>'
+ f.close()
+
+
+class ContentGenerator(handler.ContentHandler):
+ def __init__(self, fonts):
+ handler.ContentHandler.__init__(self)
+ self.fonts = fonts
+ self.currentFont = None
+
+ def startElement(self, name, attrs):
+ if name == 'unicodetable':
+ for (name, value) in attrs.items():
+ if name == "font":
+ self.currentFont = value
+ self.fonts[self.currentFont] = []
+ elif name == 'entry':
+ if not self.currentFont:
+ raise "entry must belong to a font"
+ for (name, value) in attrs.items():
+ if name == "key":
+ if len(value) > 1 and value[:2] == "0x":
+ key = int(value[2:], 16)
+ else:
+ key = int(value)
+ elif name == "number": number = value
+ elif name == "name": latexName = value
+ elif name == "class": charClass = value
+
+ self.fonts[self.currentFont].append((key, number, latexName, charClass))
+ #numberWidget, latexNameWidget, charClassWidget = self.widgets[key]
+ #numberWidget.setText(number)
+ #latexNameWidget.setText(latexName)
+ #charClassWidget.setText(charClass)
+
+
+def main():
+ a = QApplication(sys.argv)
+
+ mw = Widget()
+ mw.setCaption('Unicode mapping util')
+ mw.show()
+
+ a.connect(a, SIGNAL('lastWindowClosed()'), a, SLOT('quit()'))
+ a.exec_loop()
+
+if __name__ == '__main__':
+
+ main()
diff --git a/lib/kformula/rootelement.cc b/lib/kformula/rootelement.cc
new file mode 100644
index 00000000..08a738f2
--- /dev/null
+++ b/lib/kformula/rootelement.cc
@@ -0,0 +1,680 @@
+/* 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 <qpainter.h>
+#include <qpen.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "elementvisitor.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "kformulacommand.h"
+#include "rootelement.h"
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+class RootSequenceElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ RootSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
+ virtual RootSequenceElement* clone() {
+ return new RootSequenceElement( *this );
+ }
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+};
+
+
+KCommand* RootSequenceElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ return 0;
+ }
+
+ switch ( *request ) {
+ case req_addIndex: {
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isSelection() ||
+ ( cursor->getPos() > 0 && cursor->getPos() < countChildren() ) ) {
+ break;
+ }
+ IndexRequest* ir = static_cast<IndexRequest*>( request );
+ if ( ir->index() == upperLeftPos ) {
+ RootElement* element = static_cast<RootElement*>( getParent() );
+ ElementIndexPtr index = element->getIndex();
+ if ( !index->hasIndex() ) {
+ KFCAddGenericIndex* command = new KFCAddGenericIndex( container, index );
+ return command;
+ }
+ else {
+ index->moveToIndex( cursor, afterCursor );
+ cursor->setSelection( false );
+ formula()->cursorHasMoved( cursor );
+ return 0;
+ }
+ }
+ }
+ default:
+ break;
+ }
+ return inherited::buildCommand( container, request );
+}
+
+
+RootElement::RootElement(BasicElement* parent)
+ : BasicElement(parent)
+{
+ content = new RootSequenceElement( this );
+ index = 0;
+}
+
+RootElement::~RootElement()
+{
+ delete index;
+ delete content;
+}
+
+
+RootElement::RootElement( const RootElement& other )
+ : BasicElement( other )
+{
+ content = new RootSequenceElement( *dynamic_cast<RootSequenceElement*>( other.content ) );
+ if ( other.index ) {
+ index = new SequenceElement( *( other.index ) );
+ index->setParent( this );
+ }
+ else {
+ index = 0;
+ }
+}
+
+
+bool RootElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void RootElement::entered( SequenceElement* child )
+{
+ if ( child == content ) {
+ formula()->tell( i18n( "Main list of root" ) );
+ }
+ else {
+ formula()->tell( i18n( "Index" ) );
+ }
+}
+
+
+BasicElement* RootElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin)
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+
+ e = content->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ if (hasIndex()) {
+ e = index->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ }
+
+ //int dx = point.x() - myPos.x();
+ luPixel dy = point.y() - myPos.y();
+
+ // the position after the index
+ if (hasIndex()) {
+ if (dy < index->getHeight()) {
+ index->moveLeft(cursor, this);
+ handled = true;
+ return index;
+ }
+ }
+
+ return this;
+ }
+ return 0;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void RootElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ content->calcSizes( context, tstyle,
+ context.convertIndexStyleLower(istyle), style );
+
+ luPixel indexWidth = 0;
+ luPixel indexHeight = 0;
+ if (hasIndex()) {
+ index->calcSizes( context,
+ context.convertTextStyleIndex(tstyle),
+ context.convertIndexStyleUpper(istyle),
+ style );
+ indexWidth = index->getWidth();
+ indexHeight = index->getHeight();
+ }
+
+ double factor = style.sizeFactor();
+ luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+ luPixel unit = (content->getHeight() + distY)/ 3;
+
+ if (hasIndex()) {
+ if (indexWidth > unit) {
+ index->setX(0);
+ rootOffset.setX( indexWidth - unit );
+ }
+ else {
+ index->setX( ( unit - indexWidth )/2 );
+ rootOffset.setX(0);
+ }
+ if (indexHeight > unit) {
+ index->setY(0);
+ rootOffset.setY( indexHeight - unit );
+ }
+ else {
+ index->setY( unit - indexHeight );
+ rootOffset.setY(0);
+ }
+ }
+ else {
+ rootOffset.setX(0);
+ rootOffset.setY(0);
+ }
+
+ setWidth( content->getWidth() + unit+unit/3+ rootOffset.x() + distX/2 );
+ setHeight( content->getHeight() + distY*2 + rootOffset.y() );
+
+ content->setX( rootOffset.x() + unit+unit/3 );
+ content->setY( rootOffset.y() + distY );
+ setBaseline(content->getBaseline() + content->getY());
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void RootElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ content->draw( painter, r, context, tstyle,
+ context.convertIndexStyleLower(istyle), style, myPos);
+ if (hasIndex()) {
+ index->draw(painter, r, context,
+ context.convertTextStyleIndex(tstyle),
+ context.convertIndexStyleUpper(istyle), style, myPos);
+ }
+
+ luPixel x = myPos.x() + rootOffset.x();
+ luPixel y = myPos.y() + rootOffset.y();
+ //int distX = context.getDistanceX(tstyle);
+ double factor = style.sizeFactor();
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+ luPixel unit = (content->getHeight() + distY)/ 3;
+
+ painter.setPen( QPen( style.color(),
+ context.layoutUnitToPixelX( 2*context.getLineWidth( factor ) ) ) );
+ painter.drawLine( context.layoutUnitToPixelX( x+unit/3 ),
+ context.layoutUnitToPixelY( y+unit+distY/3 ),
+ context.layoutUnitToPixelX( x+unit/2+unit/3 ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
+
+ painter.setPen( QPen( style.color(),
+ context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
+
+ painter.drawLine( context.layoutUnitToPixelX( x+unit+unit/3 ),
+ context.layoutUnitToPixelY( y+distY/3 ),
+ context.layoutUnitToPixelX( x+unit/2+unit/3 ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
+ painter.drawLine( context.layoutUnitToPixelX( x+unit+unit/3 ),
+ context.layoutUnitToPixelY( y+distY/3 ),
+ context.layoutUnitToPixelX( x+unit+unit/3+content->getWidth() ),
+ context.layoutUnitToPixelY( y+distY/3 ) );
+ painter.drawLine( context.layoutUnitToPixelX( x+unit/3 ),
+ context.layoutUnitToPixelY( y+unit+distY/2 ),
+ context.layoutUnitToPixelX( x ),
+ context.layoutUnitToPixelY( y+unit+unit/2 ) );
+}
+
+
+void RootElement::dispatchFontCommand( FontCommand* cmd )
+{
+ content->dispatchFontCommand( cmd );
+ if (hasIndex()) {
+ index->dispatchFontCommand( cmd );
+ }
+}
+
+/**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+void RootElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ content->moveLeft(cursor, this);
+ }
+ else if (from == content) {
+ if (linear && hasIndex()) {
+ index->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+void RootElement::moveRight(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ if (linear && hasIndex()) {
+ index->moveRight(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+ }
+ else if (from == index) {
+ content->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveRight(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+void RootElement::moveUp(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveUp(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ content->moveRight(cursor, this);
+ }
+ else if (from == content) {
+ if (hasIndex()) {
+ index->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveUp(cursor, this);
+ }
+ }
+ else {
+ getParent()->moveUp(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+void RootElement::moveDown(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveDown(cursor, this);
+ }
+ else {
+ if (from == getParent()) {
+ if (hasIndex()) {
+ index->moveRight(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+ }
+ else if (from == index) {
+ content->moveRight(cursor, this);
+ }
+ else {
+ getParent()->moveDown(cursor, this);
+ }
+ }
+}
+
+/**
+ * Reinserts the index if it has been removed.
+ */
+void RootElement::insert(FormulaCursor* cursor,
+ QPtrList<BasicElement>& newChildren,
+ Direction direction)
+{
+ if (cursor->getPos() == upperLeftPos) {
+ index = static_cast<SequenceElement*>(newChildren.take(0));
+ index->setParent(this);
+
+ if (direction == beforeCursor) {
+ index->moveLeft(cursor, this);
+ }
+ else {
+ index->moveRight(cursor, this);
+ }
+ cursor->setSelection(false);
+ formula()->changed();
+ }
+}
+
+/**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * We remove ourselve if we are requested to remove our content.
+ */
+void RootElement::remove(FormulaCursor* cursor,
+ QPtrList<BasicElement>& removedChildren,
+ Direction direction)
+{
+ switch (cursor->getPos()) {
+ case contentPos:
+ getParent()->selectChild(cursor, this);
+ getParent()->remove(cursor, removedChildren, direction);
+ break;
+ case upperLeftPos:
+ removedChildren.append(index);
+ formula()->elementRemoval(index);
+ index = 0;
+ cursor->setTo(this, upperLeftPos);
+ formula()->changed();
+ break;
+ }
+}
+
+
+/**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+void RootElement::normalize(FormulaCursor* cursor, Direction direction)
+{
+ if (direction == beforeCursor) {
+ content->moveLeft(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+}
+
+
+// main child
+//
+// If an element has children one has to become the main one.
+
+SequenceElement* RootElement::getMainChild()
+{
+ return content;
+}
+
+// void RootElement::setMainChild(SequenceElement* child)
+// {
+// formula()->elementRemoval(content);
+// content = child;
+// content->setParent(this);
+// formula()->changed();
+// }
+
+
+/**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+void RootElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ if (child == content) {
+ cursor->setTo(this, contentPos);
+ }
+ else if (child == index) {
+ cursor->setTo(this, upperLeftPos);
+ }
+}
+
+
+void RootElement::moveToIndex(FormulaCursor* cursor, Direction direction)
+{
+ if (hasIndex()) {
+ if (direction == beforeCursor) {
+ index->moveLeft(cursor, this);
+ }
+ else {
+ index->moveRight(cursor, this);
+ }
+ }
+}
+
+void RootElement::setToIndex(FormulaCursor* cursor)
+{
+ cursor->setTo(this, upperLeftPos);
+}
+
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void RootElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ QDomDocument doc = element.ownerDocument();
+
+ QDomElement con = doc.createElement("CONTENT");
+ con.appendChild(content->getElementDom(doc));
+ element.appendChild(con);
+
+ if(hasIndex()) {
+ QDomElement ind = doc.createElement("ROOTINDEX");
+ ind.appendChild(index->getElementDom(doc));
+ element.appendChild(ind);
+ }
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool RootElement::readAttributesFromDom(QDomElement element)
+{
+ return BasicElement::readAttributesFromDom(element);
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool RootElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ if ( !buildChild( content, node, "CONTENT" ) ) {
+ kdWarning( DEBUGID ) << "Empty content in RootElement." << endl;
+ return false;
+ }
+ node = node.nextSibling();
+
+ if ( node.nodeName().upper() == "ROOTINDEX" ) {
+ if ( !buildChild( index=new SequenceElement( this ), node, "ROOTINDEX" ) ) {
+ return false;
+ }
+ }
+ // backward compatibility
+ else if ( node.nodeName().upper() == "INDEX" ) {
+ if ( !buildChild( index=new SequenceElement( this ), node, "INDEX" ) ) {
+ return false;
+ }
+ }
+ node = node.nextSibling();
+
+ return true;
+}
+
+/**
+ * Reads our attributes from the MathML element.
+ * Also checks whether it's a msqrt or mroot.
+ * Returns false if it failed.
+ */
+bool RootElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( element.tagName().lower() == "mroot" )
+ square = false;
+ else
+ square = true;
+ return true;
+}
+
+
+/**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+int RootElement::readContentFromMathMLDom(QDomNode& node)
+{
+ if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
+ return -1;
+ }
+
+ if ( square ) {
+ // Any number of arguments are allowed
+ if ( content->readContentFromMathMLDom( node ) == -1 ) {
+ kdWarning( DEBUGID ) << "Empty content in RootElement." << endl;
+ return -1;
+ }
+ }
+ else {
+ // Exactly two arguments are required
+ int contentNumber = content->buildMathMLChild( node );
+ if ( contentNumber == -1 ) {
+ kdWarning( DEBUGID ) << "Empty content in RootElement." << endl;
+ return -1;
+ }
+ for (int i = 0; i < contentNumber; i++ ) {
+ if ( node.isNull() ) {
+ return -1;
+ }
+ node = node.nextSibling();
+ }
+
+ index = new SequenceElement( this );
+ if ( index->buildMathMLChild( node ) == -1 ) {
+ kdWarning( DEBUGID ) << "Empty index in RootElement." << endl;
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+QString RootElement::toLatex()
+{
+ QString root;
+ root="\\sqrt";
+ if(hasIndex()) {
+ root+="[";
+ root+=index->toLatex();
+ root+="]";
+ }
+ root+="{";
+ root+=content->toLatex();
+ root+="}";
+
+ return root;
+}
+
+QString RootElement::formulaString()
+{
+ if ( hasIndex() ) {
+ return "(" + content->formulaString() + ")**(1.0/(" + index->formulaString() + "))";
+ }
+ return "sqrt(" + content->formulaString() + ")";
+}
+
+void RootElement::writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const
+{
+ content->writeMathML( doc, element, oasisFormat );
+ if( hasIndex() )
+ {
+ index->writeMathML( doc, element, oasisFormat );
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/rootelement.h b/lib/kformula/rootelement.h
new file mode 100644
index 00000000..0d579fd8
--- /dev/null
+++ b/lib/kformula/rootelement.h
@@ -0,0 +1,273 @@
+/* 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.
+*/
+
+#ifndef ROOTELEMENT_H
+#define ROOTELEMENT_H
+
+#include <qpoint.h>
+
+#include "basicelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+class SequenceElement;
+
+
+/**
+ * A nice graphical root.
+ */
+class RootElement : public BasicElement {
+ RootElement& operator=( const RootElement& ) { return *this; }
+public:
+
+ //enum { contentPos, indexPos };
+
+ RootElement(BasicElement* parent = 0);
+ ~RootElement();
+
+ RootElement( const RootElement& );
+
+ virtual RootElement* clone() {
+ return new RootElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * The cursor has entered one of our child sequences.
+ * This is a good point to tell the user where he is.
+ */
+ virtual void entered( SequenceElement* child );
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Reinserts the index if it has been removed.
+ */
+ virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * We remove ourselve if we are requested to remove our content.
+ */
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+ virtual void normalize(FormulaCursor*, Direction);
+
+ // main child
+ //
+ // If an element has children one has to become the main one.
+
+ virtual SequenceElement* getMainChild();
+ SequenceElement* getRadiant() { return index; }
+ //virtual void setMainChild(SequenceElement*);
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor* cursor, BasicElement* child);
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ //virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child) = 0;
+
+ // Moves the cursor inside the index. The index has to exist.
+ void moveToIndex(FormulaCursor*, Direction);
+
+ // Sets the cursor to point to the place where the index normaly
+ // is. These functions are only used if there is no such index and
+ // we want to insert them.
+ void setToIndex(FormulaCursor*);
+
+ bool hasIndex() const { return index != 0; }
+
+ ElementIndexPtr getIndex() { return ElementIndexPtr( new RootElementIndex( this ) ); }
+
+ // Save&load
+ //virtual QDomElement getElementDom(QDomDocument *doc);
+ //virtual bool buildFromDom(QDomElement *elem);
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "ROOT"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ /**
+ * Reads our attributes from the MathML element.
+ * Also checks whether it's a msqrt or mroot.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+
+ /**
+ * Reads our content from the MathML node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual int readContentFromMathMLDom(QDomNode& node);
+
+private:
+
+ virtual QString getElementName() const { return hasIndex() ? "mroot" : "msqrt"; }
+ virtual void writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const ;
+
+ class RootElementIndex : public ElementIndex {
+ public:
+ RootElementIndex(RootElement* p) : parent(p) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToIndex(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToIndex(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasIndex(); }
+ virtual RootElement* getElement() { return parent; }
+ protected:
+ RootElement* parent;
+ };
+
+
+ /**
+ * The one below the graph.
+ */
+ SequenceElement* content;
+
+ /**
+ * An optional index.
+ */
+ SequenceElement* index;
+
+ /**
+ * The point the artwork relates to.
+ */
+ LuPixelPoint rootOffset;
+
+ /**
+ * Whether it is msqrt or mroot element. It is only used while reading
+ * from MathML. When reading element contents we must know which of them
+ * it is. After reading, hasIndex() should be used instead.
+ */
+ bool square;
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // ROOTELEMENT_H
diff --git a/lib/kformula/scripts/bycodes.py b/lib/kformula/scripts/bycodes.py
new file mode 100755
index 00000000..16d71959
--- /dev/null
+++ b/lib/kformula/scripts/bycodes.py
@@ -0,0 +1,63 @@
+#! /usr/bin/env python
+
+"""This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+"""
+import sys
+import string
+import qt
+
+def decode( fd, font, line ):
+ begin = string.find( line, '"' )
+ end = string.find( line, '"', begin + 1)
+ unicode = line[begin + 2:end] # Remove 'U' from string aswell
+ char_list = []
+ separation = string.find( unicode, '-' )
+ if separation != -1:
+ second = unicode
+ while separation != -1:
+ first = second[0:separation]
+ second = second[separation + 2:]
+ char_list.append( string.atoi( first, 16 ) )
+ separation = string.find( second, '-' )
+ if separation == -1:
+ char_list.append( string.atoi( second, 16 ) )
+ else:
+ char_list.append( string.atoi ( unicode, 16 ) )
+ fm = qt.QFontMetrics( qt.QFont( font ) )
+ in_font = True
+ for c in char_list:
+ if not fm.inFont( qt.QChar( c ) ):
+ in_font = False
+ fd.write( unicode + ' ' + str( in_font ) + '\n')
+
+def parse( file, font ):
+ fd = open( file )
+ fd2 = open( 'mathml.list', 'w' )
+ line = fd.readline()
+ while line != "":
+ if string.find( line, 'name' ) != -1:
+ decode( fd2, font, line )
+ line = fd.readline()
+
+if __name__ == '__main__':
+ a = qt.QApplication( sys.argv )
+ if len( sys.argv ) == 2:
+ sys.argv.append( 'Arev Sans' )
+ parse ( sys.argv[1], sys.argv[2] )
+ a.quit()
diff --git a/lib/kformula/scripts/bynames.py b/lib/kformula/scripts/bynames.py
new file mode 100755
index 00000000..afb9ece5
--- /dev/null
+++ b/lib/kformula/scripts/bynames.py
@@ -0,0 +1,153 @@
+#! /usr/bin/env python
+
+"""This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+"""
+import sys
+import string
+import time
+import os
+
+def write_header( f ):
+ print >> f, '''//
+// Created: ''' + time.ctime(time.time()) + '''
+// by: ''' + os.path.basename( sys.argv[0] ) + '''
+// from: ''' + os.path.basename( sys.argv[1] ) + '''
+//
+// WARNING! All changes made in this file will be lost!
+
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+'''
+
+def write_h( f ):
+ print >>f, '''
+#ifndef ENTITIES_H
+#define ENTITIES_H
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+struct entityMap {
+ static int size();
+ int operator<( const char* right ) const {
+ return qstrcmp( name, right ) < 0;
+ }
+ const char* name;
+ const uint unicode;
+};
+
+extern const entityMap entities[];
+
+KFORMULA_NAMESPACE_END
+
+#endif // ENTITIES_H
+'''
+
+def write_cc( fr, fw ):
+ print >> fw, '''
+#include "entities.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+const entityMap entities[] = {'''
+
+ parse( fr, fw )
+
+ print >> fw, '''
+};
+
+// Needed since sizeof is a macro and we cannot be used until size is known
+int entityMap::size()
+{
+ return sizeof( entities ) / sizeof( entityMap );
+}
+
+KFORMULA_NAMESPACE_END
+ '''
+
+def name_cmp( a, b ):
+
+ if a[0] < b[0]:
+ return -1
+ if a[0] > b[0]:
+ return 1
+ print 'WARNING: Same name in entity: ' + a[0] + ', ' + b[0]
+ return 0;
+
+def parse( fr, fw ):
+ line = fr.readline()
+ while line != "" and string.find( line, '<pre>' ) == -1:
+ line = fr.readline()
+ pos = string.find( line, '<pre>' ) ### Ad-hoc detection
+ if pos == -1:
+ return
+ line = line[pos + len('<pre>'):].strip() ### Ad-hoc detection
+ entries = []
+ while line != "" and string.find( line, ',' ) != -1:
+ fields = line.split(',')
+ name = fields[0].strip()
+ number = fields[1].strip()
+ ###
+ # TODO: Support multicharacter entities, should also be supported by
+ # application. The best solution would probably to map to a single
+ # character provided by the font in the private area of Unicode
+ if string.find( number, '-' ) == -1:
+ entries.append( [name, '0x' + number[1:]] )
+ line = fr.readline().strip()
+
+ entries.sort( name_cmp, None, True )
+ fd_list = open( 'entity.list', 'w' )
+ while True:
+ e = entries.pop()
+ fd_list.write( e[0] + ' ' + e[1] + '\n')
+ print >> fw, ' {"' + e[0] + '", ' + e[1] + '}',
+ if len( entries ) == 0:
+ break
+ print >> fw, ','
+ fd_list.close()
+
+if __name__ == '__main__':
+ fh = open( '../entities.h', 'w' )
+ write_header( fh )
+ write_h( fh )
+ fh.close()
+ fcc = open( '../entities.cc', 'w' )
+ write_header( fcc )
+ fr = open( sys.argv[1] )
+ write_cc( fr , fcc )
+ fcc.close()
+ fr.close()
+
diff --git a/lib/kformula/scripts/oper-dict.py b/lib/kformula/scripts/oper-dict.py
new file mode 100755
index 00000000..49191ef6
--- /dev/null
+++ b/lib/kformula/scripts/oper-dict.py
@@ -0,0 +1,256 @@
+#! /usr/bin/env python
+
+"""This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+"""
+import codecs
+import sys
+import string
+import time
+import os
+
+###
+# If operator element's attributes change in the future, just update this list
+# and the attr dictionary below
+attr_list = [
+ 'lspace',
+ 'rspace',
+ 'maxsize',
+ 'minsize',
+ 'fence',
+ 'separator',
+ 'stretchy',
+ 'symmetric',
+ 'largeop',
+ 'movablelimits',
+ 'accent'
+ ]
+
+
+def write_header( f ):
+ print >> f, '''//
+// Created: ''' + time.ctime(time.time()) + '''
+// by: ''' + os.path.basename( sys.argv[0] ) + '''
+// from: ''' + os.path.basename( sys.argv[1] ) + '''
+//
+// WARNING! All changes made in this file will be lost!
+
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+'''
+
+def write_h( f ):
+ print >>f, '''
+#ifndef OPERATORDICTIONARY_H
+#define OPERATORDICTIONARY_H
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+struct DictionaryKey
+{
+ int operator==( const DictionaryKey& right ) const {
+ if ( qstrcmp( name, right.name ) || qstrcmp( form, right.form ) ) {
+ return false;
+ }
+ return true;
+ }
+ const char* name;
+ const char* form;
+};
+
+struct OperatorDictionary {
+ static int size();
+ int operator<( const DictionaryKey& right ) const {
+ int equal = qstrcmp( key.name, right.name );
+ if ( equal != 0 ) {
+ return equal < 0;
+ }
+ return qstrcmp( key.form, right.form ) < 0;
+ }
+ const DictionaryKey key;
+ const char* lspace;
+ const char* rspace;
+ const char* maxsize;
+ const char* minsize;
+ bool fence;
+ bool separator;
+ bool stretchy;
+ bool symmetric;
+ bool largeop;
+ bool movablelimits;
+ bool accent;
+};
+
+extern const OperatorDictionary operators[];
+
+KFORMULA_NAMESPACE_END
+
+#endif // OPERATORDICTIONARY_H
+'''
+
+def write_cc( fr, fw ):
+ print >> fw, '''
+#include "operatordictionary.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+const OperatorDictionary operators[] = {'''
+
+ entities = get_entities()
+ parse( fr, fw, entities )
+
+ print >> fw, '''
+};
+
+// Needed since sizeof is a macro and we cannot be used until size is known
+int OperatorDictionary::size()
+{
+ return sizeof( operators ) / sizeof( OperatorDictionary );
+}
+
+KFORMULA_NAMESPACE_END
+ '''
+
+def get_entities():
+ # First, read entity list into a dict
+ fd = open( 'entity.list' )
+ entities = {}
+ for line in fd.readlines():
+ fields = line.split()
+ entities[fields[0]] = string.atoi( fields[1], 16 )
+ fd.close()
+ return entities
+
+def key_cmp( a, b ):
+
+ if a[0] < b[0]:
+ return -1
+ if a[0] > b[0]:
+ return 1
+
+ if a[1] < b[1]:
+ return -1
+ if a[1] > b[1]:
+ return 1
+ print 'WARNING: Same key in operator dictionary: ' + a[0] + ', ' + b[0]
+ return 0
+
+def parse( fr, fw, entities ):
+ entries = []
+ line = fr.readline()
+ while line != "":
+ if line[0] == '"':
+ ###
+ # If operator element's attributes or default values change in the future,
+ # just update this dictionary and the list at the beginning of the file
+ attr_dict = {
+ attr_list[0]: '"thickmathspace"',
+ attr_list[1]: '"thickmathspace"',
+ attr_list[2]: '"infinity"',
+ attr_list[3]: '"1"',
+ attr_list[4]: '"false"',
+ attr_list[5]: '"false"',
+ attr_list[6]: '"false"',
+ attr_list[7]: '"true"',
+ attr_list[8]: '"false"',
+ attr_list[9]: '"false"',
+ attr_list[10]: '"false"'
+ }
+ fields = line.split()
+ name = string.replace( fields[0], '&amp;', '&' )
+ fields.pop(0) # Remove name
+ entities_found = True
+ while True:
+ begin = string.find( name, '&' )
+ end = string.find( name, ';' )
+ if begin == -1 or end == -1:
+ break
+ ###
+ # TODO: Support multicharacter entities, should also be supported by
+ # application. The best solution would probably to map to a single
+ # character provided by the font in the private area of Unicode
+ entity_name = name[begin + 1:end]
+ if entities.has_key( entity_name ) :
+ name = name.replace( '&' + entity_name + ';', unichr(entities[entity_name]));
+ else:
+ entities_found = False
+ break
+ if entities_found:
+ form = string.split( fields[0], '=' )[1]
+ fields.pop(0) # Remove form
+ for f in fields:
+ attr, value = string.split( f, '=' )
+ if not attr_dict.has_key( attr ) :
+ print 'Unsupported attribute: ' + attr
+ print 'If it is valid, update attribute dictionary'
+ sys.exit(-1)
+ # Spec has a typo, fix it
+ if string.count( value, '"' ) == 3:
+ value = value[:-1]
+ attr_dict[attr] = value
+ entries.append( [name, form, attr_dict] )
+ line = fr.readline()
+ entries.sort( key_cmp, None, True )
+
+ while True:
+ e = entries.pop()
+ print >> fw, ' { {' + e[0] + ', ' + e[1] + '},'
+ d = e[2]
+ for a in attr_list:
+ # Convert, at least, bool values
+ value = d[a]
+ if value == '"true"' or value == '"false"':
+ value = string.strip( value, '"' )
+ print >> fw, '\t\t' + value,
+ if a != attr_list[len(attr_list) - 1]:
+ print >> fw, ','
+ print >> fw, '}',
+ if len( entries ) == 0:
+ break
+ print >> fw, ',\n'
+
+if __name__ == '__main__':
+ fh = open( '../operatordictionary.h', 'w' )
+ write_header( fh )
+ write_h( fh )
+ fh.close()
+ fcc = codecs.open( '../operatordictionary.cc', 'w', 'utf-8' )
+ write_header( fcc )
+ fr = open( sys.argv[1] )
+ write_cc( fr , fcc )
+ fcc.close()
+ fr.close()
+
diff --git a/lib/kformula/scrollview.h b/lib/kformula/scrollview.h
new file mode 100644
index 00000000..200ade2a
--- /dev/null
+++ b/lib/kformula/scrollview.h
@@ -0,0 +1,32 @@
+
+#ifndef SCROLLVIEW_H
+#define SCROLLVIEW_H
+
+#include <qscrollview.h>
+
+#include "kformuladefs.h"
+
+class KFormulaWidget;
+
+using namespace KFormula;
+
+
+class ScrollView : public QScrollView {
+ Q_OBJECT
+public:
+ ScrollView();
+
+ virtual void addChild(KFormulaWidget* c, int x=0, int y=0);
+
+protected:
+ virtual void focusInEvent(QFocusEvent* event);
+
+protected slots:
+
+ void cursorChanged(bool visible, bool selecting);
+
+private:
+ KFormulaWidget* child;
+};
+
+#endif // SCROLLVIEW_H
diff --git a/lib/kformula/sequenceelement.cc b/lib/kformula/sequenceelement.cc
new file mode 100644
index 00000000..b57125bd
--- /dev/null
+++ b/lib/kformula/sequenceelement.cc
@@ -0,0 +1,1934 @@
+/* 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 <stdlib.h>
+#include <math.h>
+
+#include <qpainter.h>
+#include <qpaintdevice.h>
+#include <qvaluestack.h>
+
+#include <kcommand.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+//#include <boost/spirit.hpp>
+
+#include "MatrixDialog.h"
+#include "bracketelement.h"
+#include "creationstrategy.h"
+#include "elementtype.h"
+#include "elementvisitor.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "fractionelement.h"
+#include "indexelement.h"
+#include "kformulacommand.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "matrixelement.h"
+#include "rootelement.h"
+#include "sequenceelement.h"
+#include "sequenceparser.h"
+#include "spaceelement.h"
+#include "symbolelement.h"
+#include "symboltable.h"
+#include "textelement.h"
+#include "numberelement.h"
+#include "identifierelement.h"
+#include "operatorelement.h"
+
+#include <assert.h>
+
+KFORMULA_NAMESPACE_BEGIN
+//using namespace std;
+
+ElementCreationStrategy* SequenceElement::creationStrategy = 0;
+
+void SequenceElement::setCreationStrategy( ElementCreationStrategy* strategy )
+{
+ creationStrategy = strategy;
+}
+
+void SequenceElement::setStyle( StyleElement *st )
+{
+ style = st;
+}
+
+SequenceElement::SequenceElement(BasicElement* parent)
+ : BasicElement(parent), parseTree(0), textSequence(true),singlePipe(true), style(0)
+{
+ assert( creationStrategy != 0 );
+ children.setAutoDelete(true);
+}
+
+
+SequenceElement::~SequenceElement()
+{
+ delete parseTree;
+}
+
+SequenceElement::SequenceElement( const SequenceElement& other )
+ : BasicElement( other )
+{
+ children.setAutoDelete(true);
+ uint count = other.children.count();
+ for (uint i = 0; i < count; i++) {
+ BasicElement* child = children.at(i)->clone();
+ child->setParent( this );
+ children.append( child );
+ }
+}
+
+
+bool SequenceElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+bool SequenceElement::readOnly( const FormulaCursor* ) const
+{
+ return getParent()->readOnly( this );
+}
+
+
+/**
+ * Returns the element the point is in.
+ */
+BasicElement* SequenceElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+
+ uint count = children.count();
+ for (uint i = 0; i < count; i++) {
+ BasicElement* child = children.at(i);
+ e = child->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ if (!handled) {
+ handled = true;
+ if ((point.x() - myPos.x()) < (e->getX() + e->getWidth()*2/3)) {
+ cursor->setTo(this, children.find(e));
+ }
+ else {
+ cursor->setTo(this, children.find(e)+1);
+ }
+ }
+ return e;
+ }
+ }
+
+ luPixel dx = point.x() - myPos.x();
+ //int dy = point.y() - myPos.y();
+
+ for (uint i = 0; i < count; i++) {
+ BasicElement* child = children.at(i);
+ if (dx < child->getX()) {
+ cursor->setTo( this, i );
+ handled = true;
+ return children.at( i );
+ }
+ }
+
+ cursor->setTo(this, countChildren());
+ handled = true;
+ return this;
+ }
+ return 0;
+}
+
+
+bool SequenceElement::isEmpty()
+{
+ uint count = children.count();
+ for (uint i = 0; i < count; i++) {
+ BasicElement* child = children.at(i);
+ if (!child->isInvisible()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void SequenceElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ if (!isEmpty()) {
+ luPixel width = 0;
+ luPixel toBaseline = 0;
+ luPixel fromBaseline = 0;
+
+ width += context.ptToPixelX( getSpaceBefore( context, tstyle, factor ) );
+
+ // Let's do all normal elements that have a base line.
+ QPtrListIterator<BasicElement> it( children );
+ for ( ; it.current(); ++it ) {
+ BasicElement* child = it.current();
+
+ if ( !child->isInvisible() ) {
+ child->calcSizes( context, tstyle, istyle, style );
+ child->setX( width );
+ width += child->getWidth();
+
+ luPixel childBaseline = child->getBaseline();
+ if ( childBaseline > -1 ) {
+ toBaseline = QMAX( toBaseline, childBaseline );
+ fromBaseline = QMAX( fromBaseline,
+ child->getHeight() - childBaseline );
+ }
+ else {
+ luPixel bl = child->getHeight()/2 + context.axisHeight( tstyle, factor );
+ toBaseline = QMAX( toBaseline, bl );
+ fromBaseline = QMAX( fromBaseline, child->getHeight() - bl );
+ }
+ }
+ else {
+ child->setX( width );
+ }
+ }
+
+ width += context.ptToPixelX( getSpaceAfter( context, tstyle, factor ) );
+
+ setWidth(width);
+ setHeight(toBaseline+fromBaseline);
+ setBaseline(toBaseline);
+
+ setChildrenPositions();
+ }
+ else {
+ luPixel w = context.getEmptyRectWidth( factor );
+ luPixel h = context.getEmptyRectHeight( factor );
+ setWidth( w );
+ setHeight( h );
+ setBaseline( h );
+ //setMidline( h*.5 );
+ }
+}
+
+
+void SequenceElement::setChildrenPositions()
+{
+ QPtrListIterator<BasicElement> it( children );
+ for ( ; it.current(); ++it ) {
+ BasicElement* child = it.current();
+ child->setY(getBaseline() - child->getBaseline());
+ }
+}
+
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void SequenceElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x() + getX(), parentOrigin.y() + getY() );
+ // There might be zero sized elements that still want to be drawn at least
+ // in edit mode. (EmptyElement)
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ if (!isEmpty()) {
+ QPtrListIterator<BasicElement> it( children );
+ for (int i = 0 ; it.current(); i++) {
+ BasicElement* child = it.current();
+ if (!child->isInvisible()) {
+ child->draw(painter, r, context, tstyle, istyle, style, myPos);
+
+ // Each starting element draws the whole token
+ // This only concerns TextElements.
+ /*
+ ElementType* token = child->getElementType();
+ if ( token != 0 ) {
+ it += token->end() - token->start();
+ }
+ else {
+ ++it;
+ }
+ */
+ }
+// else {
+ ++it;
+// }
+ }
+ }
+ else {
+ drawEmptyRect( painter, context, style.sizeFactor(), myPos );
+ }
+ // Debug
+ //painter.setPen(Qt::green);
+ //painter.drawRect(parentOrigin.x() + getX(), parentOrigin.y() + getY(),
+ // getWidth(), getHeight());
+// painter.drawLine( context.layoutUnitToPixelX( parentOrigin.x() + getX() ),
+// context.layoutUnitToPixelY( parentOrigin.y() + getY() + axis( context, tstyle ) ),
+// context.layoutUnitToPixelX( parentOrigin.x() + getX() + getWidth() ),
+// context.layoutUnitToPixelY( parentOrigin.y() + getY() + axis( context, tstyle ) ) );
+// painter.setPen(Qt::red);
+// painter.drawLine( context.layoutUnitToPixelX( parentOrigin.x() + getX() ),
+// context.layoutUnitToPixelY( parentOrigin.y() + getY() + getBaseline() ),
+// context.layoutUnitToPixelX( parentOrigin.x() + getX() + getWidth() ),
+// context.layoutUnitToPixelY( parentOrigin.y() + getY() + getBaseline() ) );
+}
+
+
+void SequenceElement::dispatchFontCommand( FontCommand* cmd )
+{
+ QPtrListIterator<BasicElement> it( children );
+ for ( ; it.current(); ++it ) {
+ BasicElement* child = it.current();
+ child->dispatchFontCommand( cmd );
+ }
+}
+
+
+void SequenceElement::drawEmptyRect( QPainter& painter, const ContextStyle& context,
+ double factor, const LuPixelPoint& upperLeft )
+{
+ if ( context.edit() ) {
+ painter.setBrush(Qt::NoBrush);
+ painter.setPen( QPen( context.getEmptyColor(),
+ context.layoutUnitToPixelX( context.getLineWidth( factor ) ) ) );
+ painter.drawRect( context.layoutUnitToPixelX( upperLeft.x() ),
+ context.layoutUnitToPixelY( upperLeft.y() ),
+ context.layoutUnitToPixelX( getWidth() ),
+ context.layoutUnitToPixelY( getHeight() ) );
+ }
+}
+
+void SequenceElement::calcCursorSize( const ContextStyle& context,
+ FormulaCursor* cursor, bool smallCursor )
+{
+ LuPixelPoint point = widgetPos();
+ uint pos = cursor->getPos();
+
+ luPixel posX = getChildPosition( context, pos );
+ luPixel height = getHeight();
+
+ luPixel unitX = context.ptToLayoutUnitPixX( 1 );
+ luPixel unitY = context.ptToLayoutUnitPixY( 1 );
+
+ // Here are those evil constants that describe the cursor size.
+
+ if ( cursor->isSelection() ) {
+ uint mark = cursor->getMark();
+ luPixel markX = getChildPosition( context, mark );
+ luPixel x = QMIN(posX, markX);
+ luPixel width = abs(posX - markX);
+
+ if ( smallCursor ) {
+ cursor->cursorSize.setRect( point.x()+x, point.y(), width, height );
+ }
+ else {
+ cursor->cursorSize.setRect( point.x()+x, point.y() - 2*unitY,
+ width + unitX, height + 4*unitY );
+ }
+ }
+ else {
+ if ( smallCursor ) {
+ cursor->cursorSize.setRect( point.x()+posX, point.y(),
+ unitX, height );
+ }
+ else {
+ cursor->cursorSize.setRect( point.x(), point.y() - 2*unitY,
+ getWidth() + unitX, height + 4*unitY );
+ }
+ }
+
+ cursor->cursorPoint.setX( point.x()+posX );
+ cursor->cursorPoint.setY( point.y()+getHeight()/2 );
+}
+
+
+/**
+ * If the cursor is inside a sequence it needs to be drawn.
+ */
+void SequenceElement::drawCursor( QPainter& painter, const ContextStyle& context,
+ StyleAttributes& style, FormulaCursor* cursor,
+ bool smallCursor, bool activeCursor )
+{
+ painter.setRasterOp( Qt::XorROP );
+ if ( cursor->isSelection() ) {
+ const LuPixelRect& r = cursor->cursorSize;
+ painter.fillRect( context.layoutUnitToPixelX( r.x() ),
+ context.layoutUnitToPixelY( r.y() ),
+ context.layoutUnitToPixelX( r.width() ),
+ context.layoutUnitToPixelY( r.height() ),
+ Qt::white );
+ }
+ painter.setPen( QPen( Qt::white,
+ context.layoutUnitToPixelX( context.getLineWidth( style.sizeFactor() )/2 ) ) );
+ const LuPixelPoint& point = cursor->getCursorPoint();
+ const LuPixelRect& size = cursor->getCursorSize();
+ if ( activeCursor )
+ {
+ int offset = 0;
+ if ( cursor->isSelection() && cursor->getPos() > cursor->getMark() )
+ offset = -1;
+ painter.drawLine( context.layoutUnitToPixelX( point.x() ) + offset,
+ context.layoutUnitToPixelY( size.top() ),
+ context.layoutUnitToPixelX( point.x() ) + offset,
+ context.layoutUnitToPixelY( size.bottom() )-1 );
+ painter.drawLine( context.layoutUnitToPixelX( point.x() ) + offset + 1,
+ context.layoutUnitToPixelY( size.top() ),
+ context.layoutUnitToPixelX( point.x() ) + offset + 1,
+ context.layoutUnitToPixelY( size.bottom() )-1 );
+ }
+ if ( !smallCursor && !cursor->isSelection() )
+ painter.drawLine( context.layoutUnitToPixelX( size.left() ),
+ context.layoutUnitToPixelY( size.bottom() )-1,
+ context.layoutUnitToPixelX( size.right() )-1,
+ context.layoutUnitToPixelY( size.bottom() )-1 );
+ // This might be wrong but probably isn't.
+ painter.setRasterOp( Qt::CopyROP );
+}
+
+
+luPixel SequenceElement::getChildPosition( const ContextStyle& context, uint child )
+{
+ if (child < children.count()) {
+ return children.at(child)->getX();
+ }
+ else {
+ if (children.count() > 0) {
+ return children.at(child-1)->getX() + children.at(child-1)->getWidth();
+ }
+ else {
+ return context.ptToLayoutUnitPixX( 2 );
+ }
+ }
+}
+
+
+// navigation
+//
+// The elements are responsible to handle cursor movement themselves.
+// To do this they need to know the direction the cursor moves and
+// the element it comes from.
+//
+// The cursor might be in normal or in selection mode.
+
+/**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+void SequenceElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
+{
+ // Our parent asks us for a cursor position. Found.
+ if (from == getParent()) {
+ cursor->setTo(this, children.count());
+ if ( cursor->isSelectionMode() ) {
+ cursor->setMark( children.count() );
+ }
+ from->entered( this );
+ }
+
+ // We already owned the cursor. Ask next child then.
+ else if (from == this) {
+ if (cursor->getPos() > 0) {
+ cursor->setTo(this, cursor->getPos()-1);
+
+ // invisible elements are not visible so we move on.
+ if (children.at(cursor->getPos())->isInvisible()) {
+ moveLeft(cursor, this);
+ }
+ }
+ else {
+ // Needed because FormulaElement derives this.
+ if (getParent() != 0) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ formula()->moveOutLeft( cursor );
+ }
+ }
+ }
+
+ // The cursor came from one of our children or
+ // something is wrong.
+ else {
+ int fromPos = children.find(from);
+ if ( fromPos > 0 ) {
+ children.at( fromPos - 1)->moveLeft( cursor, this );
+ }
+
+ // invisible elements are not visible so we move on.
+ if (from->isInvisible()) {
+ moveLeft(cursor, this);
+ }
+ formula()->tell( "" );
+ }
+}
+
+/**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+void SequenceElement::moveRight(FormulaCursor* cursor, BasicElement* from)
+{
+ // Our parent asks us for a cursor position. Found.
+ if (from == getParent()) {
+ cursor->setTo(this, 0);
+ from->entered( this );
+ }
+
+ // We already owned the cursor. Ask next child then.
+ else if (from == this) {
+ uint pos = cursor->getPos();
+ if (pos < children.count()) {
+ cursor->setTo(this, pos+1);
+
+ // invisible elements are not visible so we move on.
+ if (children.at(pos)->isInvisible()) {
+ moveRight(cursor, this);
+ }
+ }
+ else {
+ // Needed because FormulaElement derives this.
+ if (getParent() != 0) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ formula()->moveOutRight( cursor );
+ }
+ }
+ }
+
+ // The cursor came from one of our children or
+ // something is wrong.
+ else {
+ int fromPos = children.find(from);
+ if ( fromPos < children.count() - 1 ) {
+ children.at( fromPos + 1 )->moveDown( cursor, this );
+ }
+ else {
+ cursor->setTo(this, fromPos+1);
+ }
+ if (cursor->isSelectionMode()) {
+ cursor->setMark(fromPos);
+ }
+
+ // invisible elements are not visible so we move on.
+ if (from->isInvisible()) {
+ moveRight(cursor, this);
+ }
+ formula()->tell( "" );
+ }
+}
+
+
+void SequenceElement::moveWordLeft(FormulaCursor* cursor)
+{
+ uint pos = cursor->getPos();
+ if (pos > 0) {
+ ElementType* type = children.at(pos-1)->getElementType();
+ if (type != 0) {
+ cursor->setTo(this, type->start());
+ }
+ }
+ else {
+ moveLeft(cursor, this);
+ }
+}
+
+
+void SequenceElement::moveWordRight(FormulaCursor* cursor)
+{
+ uint pos = cursor->getPos();
+ if (pos < children.count()) {
+ ElementType* type = children.at(pos)->getElementType();
+ if (type != 0) {
+ cursor->setTo(this, type->end());
+ }
+ }
+ else {
+ moveRight(cursor, this);
+ }
+}
+
+
+/**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+void SequenceElement::moveUp(FormulaCursor* cursor, BasicElement* from)
+{
+ if (from == getParent()) {
+ moveRight(cursor, this);
+ }
+ else if ( from == this ) {
+ if ( getParent() != 0 ) {
+ uint pos = cursor->getPos();
+ if ( pos < (children.count() - 1) / 2 ) {
+ getParent()->moveLeft( cursor, this );
+ }
+ else {
+ getParent()->moveRight( cursor, this );
+ }
+ }
+ else {
+ formula()->moveOutAbove( cursor );
+ }
+ }
+ else {
+ if (getParent() != 0) {
+ getParent()->moveUp(cursor, this);
+ }
+ else {
+ formula()->moveOutAbove( cursor );
+ }
+ }
+}
+
+/**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+void SequenceElement::moveDown(FormulaCursor* cursor, BasicElement* from)
+{
+ if (from == getParent()) {
+ cursor->setTo(this, 0);
+ from->entered( this );
+ }
+ else if (from == this) {
+ uint pos = cursor->getPos();
+ if (pos < children.count()) {
+ children.at(pos)->moveDown(cursor, this);
+ }
+ }
+ else {
+ if (getParent() != 0) {
+ getParent()->moveDown(cursor, this);
+ }
+ else {
+ cursor->setTo( this, children.count() );
+ from->entered( this );
+// formula()->moveOutBelow( cursor );
+ }
+ }
+}
+
+/**
+ * Moves the cursor to the first position in this sequence.
+ * (That is before the first child.)
+ */
+void SequenceElement::moveHome(FormulaCursor* cursor)
+{
+ if (cursor->isSelectionMode()) {
+ BasicElement* element = cursor->getElement();
+ if (element != this) {
+ while (element->getParent() != this) {
+ element = element->getParent();
+ }
+ cursor->setMark(children.find(element)+1);
+ }
+ }
+ cursor->setTo(this, 0);
+}
+
+/**
+ * Moves the cursor to the last position in this sequence.
+ * (That is behind the last child.)
+ */
+void SequenceElement::moveEnd(FormulaCursor* cursor)
+{
+ if (cursor->isSelectionMode()) {
+ BasicElement* element = cursor->getElement();
+ if (element != this) {
+ while (element->getParent() != this) {
+ element = element->getParent();
+ if (element == 0) {
+ cursor->setMark(children.count());
+ break;
+ }
+ }
+ if (element != 0) {
+ cursor->setMark(children.find(element));
+ }
+ }
+ }
+ cursor->setTo(this, children.count());
+}
+
+/**
+ * Sets the cursor inside this element to its start position.
+ * For most elements that is the main child.
+ */
+void SequenceElement::goInside(FormulaCursor* cursor)
+{
+ cursor->setSelection(false);
+ cursor->setTo(this, 0);
+}
+
+/**
+ * Sets the cursor inside this element to its end position.
+ * For most elements that is the main child.
+ */
+void SequenceElement::goInsideLast(FormulaCursor* cursor)
+{
+ cursor->setSelection(false);
+ cursor->setTo(this, children.count());
+}
+
+
+// children
+
+ /**
+ * Insert a new child in the sequence
+ *
+ * @returns true if succesful, i.e. if index is in range, otherwise returns
+ * false. The valid range is 0 to count(). The child is appended if index == count().
+ *
+ * @param index position in the sequence to insert the child
+ * @param child the child to insert in the sequence
+ */
+
+bool SequenceElement::insert( uint index, BasicElement *child )
+{
+ return children.insert( index, child );
+}
+
+/**
+ * Removes the child. If this was the main child this element might
+ * request its own removal.
+ * The cursor is the one that caused the removal. It has to be moved
+ * to the place any user expects the cursor after that particular
+ * element has been removed.
+ */
+// void SequenceElement::removeChild(FormulaCursor* cursor, BasicElement* child)
+// {
+// int pos = children.find(child);
+// formula()->elementRemoval(child, pos);
+// cursor->setTo(this, pos);
+// children.remove(pos);
+// /*
+// if len(self.children) == 0:
+// if self.parent != None:
+// self.parent.removeChild(cursor, self)
+// return
+// */
+// formula()->changed();
+// }
+
+
+/**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction. The inserted elements will
+ * be selected.
+ *
+ * The list will be emptied but stays the property of the caller.
+ */
+void SequenceElement::insert(FormulaCursor* cursor,
+ QPtrList<BasicElement>& newChildren,
+ Direction direction)
+{
+ int pos = cursor->getPos();
+ uint count = newChildren.count();
+ for (uint i = 0; i < count; i++) {
+ BasicElement* child = newChildren.take(0);
+ child->setParent(this);
+ children.insert(pos+i, child);
+ }
+ if (direction == beforeCursor) {
+ cursor->setTo(this, pos+count, pos);
+ }
+ else {
+ cursor->setTo(this, pos, pos+count);
+ }
+
+ formula()->changed();
+ parse();
+}
+
+
+/**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * The ownership of the list is passed to the caller.
+ */
+void SequenceElement::remove(FormulaCursor* cursor,
+ QPtrList<BasicElement>& removedChildren,
+ Direction direction)
+{
+ if (cursor->isSelection()) {
+ int from = cursor->getSelectionStart();
+ int to = cursor->getSelectionEnd();
+ for (int i = from; i < to; i++) {
+ removeChild(removedChildren, from);
+ }
+ cursor->setTo(this, from);
+ cursor->setSelection(false);
+ }
+ else {
+ if (direction == beforeCursor) {
+ int pos = cursor->getPos() - 1;
+ if (pos >= 0) {
+ while (pos >= 0) {
+ BasicElement* child = children.at(pos);
+ formula()->elementRemoval(child);
+ children.take(pos);
+ removedChildren.prepend(child);
+ if (!child->isInvisible()) {
+ break;
+ }
+ pos--;
+ }
+ cursor->setTo(this, pos);
+ formula()->changed();
+ }
+ }
+ else {
+ uint pos = cursor->getPos();
+ if (pos < children.count()) {
+ while (pos < children.count()) {
+ BasicElement* child = children.at(pos);
+ formula()->elementRemoval(child);
+ children.take(pos);
+ removedChildren.append(child);
+ if (!child->isInvisible()) {
+ break;
+ }
+ }
+ // It is necessary to set the cursor to its old
+ // position because it got a notification and
+ // moved to the beginning of this sequence.
+ cursor->setTo(this, pos);
+ formula()->changed();
+ }
+ }
+ }
+ parse();
+}
+
+
+/**
+ * Removes the children at pos and appends it to the list.
+ */
+void SequenceElement::removeChild(QPtrList<BasicElement>& removedChildren, int pos)
+{
+ BasicElement* child = children.at(pos);
+ formula()->elementRemoval(child);
+ children.take(pos);
+ removedChildren.append(child);
+ //cerr << *removedChildren.at(0) << endl;
+ formula()->changed();
+}
+
+
+/**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+void SequenceElement::normalize(FormulaCursor* cursor, Direction)
+{
+ cursor->setSelection(false);
+}
+
+
+/**
+ * Returns the child at the cursor.
+ * Does not care about the selection.
+ */
+BasicElement* SequenceElement::getChild( FormulaCursor* cursor, Direction direction )
+{
+ if ( direction == beforeCursor ) {
+ if ( cursor->getPos() > 0 ) {
+ return children.at( cursor->getPos() - 1 );
+ }
+ }
+ else {
+ if ( cursor->getPos() < qRound( children.count() ) ) {
+ return children.at( cursor->getPos() );
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+void SequenceElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ int pos = children.find(child);
+ if (pos > -1) {
+ cursor->setTo(this, pos+1, pos);
+ }
+}
+
+void SequenceElement::childWillVanish(FormulaCursor* cursor, BasicElement* child)
+{
+ int childPos = children.find(child);
+ if (childPos > -1) {
+ int pos = cursor->getPos();
+ if (pos > childPos) {
+ pos--;
+ }
+ int mark = cursor->getMark();
+ if (mark > childPos) {
+ mark--;
+ }
+ cursor->setTo(this, pos, mark);
+ }
+}
+
+
+/**
+ * Selects all children. The cursor is put behind, the mark before them.
+ */
+void SequenceElement::selectAllChildren(FormulaCursor* cursor)
+{
+ cursor->setTo(this, children.count(), 0);
+}
+
+bool SequenceElement::onlyTextSelected( FormulaCursor* cursor )
+{
+ if ( cursor->isSelection() ) {
+ uint from = QMIN( cursor->getPos(), cursor->getMark() );
+ uint to = QMAX( cursor->getPos(), cursor->getMark() );
+ for ( uint i = from; i < to; i++ ) {
+ BasicElement* element = getChild( i );
+ if ( element->getCharacter() == QChar::null ) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+KCommand* SequenceElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ formula()->tell( i18n( "write protection" ) );
+ return 0;
+ }
+
+ switch ( *request ) {
+ case req_addText: {
+ KFCReplaceToken* command = new KFCReplaceToken( i18n("Add Text"), container );
+ TextRequest* tr = static_cast<TextRequest*>( request );
+ IdentifierElement* id = creationStrategy->createIdentifierElement();
+ command->addToken( id );
+ for ( uint i = 0; i < tr->text().length(); i++ ) {
+ TextElement* text = creationStrategy->createTextElement( tr->text()[i] );
+ command->addContent( id, text );
+ }
+ return command;
+ }
+ case req_addTextChar: {
+ KFCReplaceToken* command = new KFCReplaceToken( i18n("Add Text"), container );
+ TextCharRequest* tr = static_cast<TextCharRequest*>( request );
+ IdentifierElement* id = creationStrategy->createIdentifierElement();
+ TextElement* text = creationStrategy->createTextElement( tr->ch() );
+ command->addToken( id );
+ command->addContent( id, text );
+ return command;
+ }
+
+ case req_addOperator: {
+ KFCReplaceToken* command = new KFCReplaceToken( i18n("Add Operator"), container );
+ OperatorRequest* opr = static_cast<OperatorRequest*>( request );
+ OperatorElement* op = creationStrategy->createOperatorElement();
+ TextElement* text = creationStrategy->createTextElement( opr->ch() );
+ command->addToken( op );
+ command->addContent( op, text );
+ return command;
+ }
+
+ case req_addNumber: {
+ KFCReplaceToken* command = new KFCReplaceToken( i18n("Add Number"), container );
+ NumberRequest* nr = static_cast<NumberRequest*>( request );
+ NumberElement* num = creationStrategy->createNumberElement();
+ num->setParent( this );
+ TextElement* text = creationStrategy->createTextElement( nr->ch() );
+ text->setParent( num );
+ command->addToken( num );
+ command->addContent( num, text );
+ return command;
+ }
+
+ case req_addEmptyBox: {
+ EmptyElement* element = creationStrategy->createEmptyElement();
+ if ( element != 0 ) {
+ KFCReplace* command = new KFCReplace( i18n("Add Empty Box"), container );
+ command->addElement( element );
+ return command;
+ }
+ break;
+ }
+ case req_addNameSequence:
+ if ( onlyTextSelected( container->activeCursor() ) ) {
+ NameSequence* nameSequence = creationStrategy->createNameSequence();
+ if ( nameSequence != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing( i18n( "Add Name" ), container );
+ command->setElement( nameSequence );
+ return command;
+ }
+ }
+ break;
+ case req_addBracket: {
+ BracketRequest* br = static_cast<BracketRequest*>( request );
+ BracketElement* bracketElement =
+ creationStrategy->createBracketElement( br->left(), br->right() );
+ if ( bracketElement != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing(i18n("Add Bracket"), container);
+ command->setElement( bracketElement );
+ return command;
+ }
+ break;
+ }
+ case req_addOverline: {
+ OverlineElement* overline = creationStrategy->createOverlineElement();
+ if ( overline != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing(i18n("Add Overline"), container);
+ command->setElement( overline );
+ return command;
+ }
+ break;
+ }
+ case req_addUnderline: {
+ UnderlineElement* underline = creationStrategy->createUnderlineElement();
+ if ( underline != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing(i18n("Add Underline"), container);
+ command->setElement( underline );
+ return command;
+ }
+ break;
+ }
+ case req_addMultiline: {
+ MultilineElement* multiline = creationStrategy->createMultilineElement();
+ if ( multiline != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing(i18n("Add Multiline"), container);
+ command->setElement( multiline );
+ return command;
+ }
+ break;
+ }
+ case req_addSpace: {
+ SpaceRequest* sr = static_cast<SpaceRequest*>( request );
+ SpaceElement* element = creationStrategy->createSpaceElement( sr->space() );
+ if ( element != 0 ) {
+ KFCReplace* command = new KFCReplace( i18n("Add Space"), container );
+ command->addElement( element );
+ return command;
+ }
+ break;
+ }
+ case req_addFraction: {
+ FractionElement* fraction = creationStrategy->createFractionElement();
+ if ( fraction != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing(i18n("Add Fraction"), container);
+ command->setElement( fraction );
+ return command;
+ }
+ break;
+ }
+ case req_addRoot: {
+ RootElement* root = creationStrategy->createRootElement();
+ if ( root != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing(i18n("Add Root"), container);
+ command->setElement( root );
+ return command;
+ }
+ break;
+ }
+ case req_addSymbol: {
+ SymbolRequest* sr = static_cast<SymbolRequest*>( request );
+ SymbolElement* symbol = creationStrategy->createSymbolElement( sr->type() );
+ if ( symbol != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing( i18n( "Add Symbol" ), container );
+ command->setElement( symbol );
+ return command;
+ }
+ break;
+ }
+ case req_addOneByTwoMatrix: {
+ FractionElement* element = creationStrategy->createFractionElement();
+ if ( element != 0 ) {
+ KFCAddReplacing* command = new KFCAddReplacing( i18n("Add 1x2 Matrix"), container );
+ element->showLine(false);
+ command->setElement(element);
+ return command;
+ }
+ }
+ case req_addMatrix: {
+ MatrixRequest* mr = static_cast<MatrixRequest*>( request );
+ uint rows = mr->rows(), cols = mr->columns();
+ if ( ( rows == 0 ) || ( cols == 0 ) ) {
+ MatrixDialog* dialog = new MatrixDialog( 0 );
+ if ( dialog->exec() ) {
+ rows = dialog->h;
+ cols = dialog->w;
+ }
+ delete dialog;
+ }
+
+ if ( ( rows != 0 ) && ( cols != 0 ) ) {
+ KFCAddReplacing* command = new KFCAddReplacing( i18n( "Add Matrix" ), container );
+ command->setElement( creationStrategy->createMatrixElement( rows, cols ) );
+ return command;
+ }
+ else
+ return 0L;
+ }
+ case req_addIndex: {
+ if ( cursor->getPos() > 0 && !cursor->isSelection() ) {
+ IndexElement* element =
+ dynamic_cast<IndexElement*>( children.at( cursor->getPos()-1 ) );
+ if ( element != 0 ) {
+ element->goInside( cursor );
+ return element->buildCommand( container, request );
+ }
+ }
+ IndexElement* element = creationStrategy->createIndexElement();
+ if ( element != 0 ) {
+ if ( !cursor->isSelection() ) {
+ cursor->moveLeft( SelectMovement | WordMovement );
+ }
+ IndexRequest* ir = static_cast<IndexRequest*>( request );
+ KFCAddIndex* command = new KFCAddIndex( container, element,
+ element->getIndex( ir->index() ) );
+ return command;
+ }
+ break;
+ }
+ case req_removeEnclosing: {
+ if ( !cursor->isSelection() ) {
+ DirectedRemove* dr = static_cast<DirectedRemove*>( request );
+ KFCRemoveEnclosing* command = new KFCRemoveEnclosing( container, dr->direction() );
+ return command;
+ }
+ }
+ case req_remove: {
+ SequenceElement* sequence = cursor->normal();
+ if ( sequence &&
+ ( sequence == sequence->formula() ) &&
+ ( sequence->countChildren() == 0 ) ) {
+ sequence->formula()->removeFormula( cursor );
+ return 0;
+ }
+ else {
+ DirectedRemove* dr = static_cast<DirectedRemove*>( request );
+
+ // empty removes are not legal!
+ if ( !cursor->isSelection() ) {
+ if ( countChildren() > 0 ) {
+ if ( ( cursor->getPos() == 0 ) && ( dr->direction() == beforeCursor ) ) {
+ return 0;
+ }
+ if ( ( cursor->getPos() == countChildren() ) && ( dr->direction() == afterCursor ) ) {
+ return 0;
+ }
+ }
+ else if ( getParent() == 0 ) {
+ return 0;
+ }
+ }
+
+ KFCRemove* command = new KFCRemove( container, dr->direction() );
+ return command;
+ }
+ }
+ case req_compactExpression: {
+ cursor->moveEnd();
+ cursor->moveRight();
+ formula()->cursorHasMoved( cursor );
+ break;
+ }
+ case req_makeGreek: {
+ TextElement* element = cursor->getActiveTextElement();
+ if ((element != 0) && !element->isSymbol()) {
+ cursor->selectActiveElement();
+ const SymbolTable& table = container->document()->getSymbolTable();
+ if (table.greekLetters().find(element->getCharacter()) != -1) {
+ KFCReplace* command = new KFCReplace( i18n( "Change Char to Symbol" ), container );
+ TextElement* symbol = creationStrategy->createTextElement( table.unicodeFromSymbolFont( element->getCharacter() ), true );
+ command->addElement( symbol );
+ return command;
+ }
+ cursor->setSelection( false );
+ }
+ break;
+ }
+ case req_paste:
+ case req_copy:
+ case req_cut:
+ break;
+ case req_formatBold:
+ case req_formatItalic: {
+ if ( cursor->isSelection() ) {
+ CharStyleRequest* csr = static_cast<CharStyleRequest*>( request );
+ CharStyle cs = normalChar;
+ if ( csr->bold() ) cs = static_cast<CharStyle>( cs | boldChar );
+ if ( csr->italic() ) cs = static_cast<CharStyle>( cs | italicChar );
+ CharStyleCommand* cmd = new CharStyleCommand( cs, i18n( "Change Char Style" ), container );
+ int end = cursor->getSelectionEnd();
+ for ( int i = cursor->getSelectionStart(); i<end; ++i ) {
+ cmd->addElement( children.at( i ) );
+ }
+ return cmd;
+ }
+ break;
+ }
+ case req_formatFamily: {
+ if ( cursor->isSelection() ) {
+ CharFamilyRequest* cfr = static_cast<CharFamilyRequest*>( request );
+ CharFamily cf = cfr->charFamily();
+ CharFamilyCommand* cmd = new CharFamilyCommand( cf, i18n( "Change Char Family" ), container );
+ int end = cursor->getSelectionEnd();
+ for ( int i = cursor->getSelectionStart(); i<end; ++i ) {
+ cmd->addElement( children.at( i ) );
+ }
+ return cmd;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+KCommand* SequenceElement::input( Container* container, QKeyEvent* event )
+{
+ QChar ch = event->text().at( 0 );
+ if ( ch.isPrint() ) {
+ return input( container, ch );
+ }
+ else {
+ int action = event->key();
+ int state = event->state();
+ MoveFlag flag = movementFlag(state);
+
+ switch ( action ) {
+ case Qt::Key_BackSpace: {
+ DirectedRemove r( req_remove, beforeCursor );
+ return buildCommand( container, &r );
+ }
+ case Qt::Key_Delete: {
+ DirectedRemove r( req_remove, afterCursor );
+ return buildCommand( container, &r );
+ }
+ case Qt::Key_Left: {
+ FormulaCursor* cursor = container->activeCursor();
+ cursor->moveLeft( flag );
+ formula()->cursorHasMoved( cursor );
+ break;
+ }
+ case Qt::Key_Right: {
+ FormulaCursor* cursor = container->activeCursor();
+ cursor->moveRight( flag );
+ formula()->cursorHasMoved( cursor );
+ break;
+ }
+ case Qt::Key_Up: {
+ FormulaCursor* cursor = container->activeCursor();
+ cursor->moveUp( flag );
+ formula()->cursorHasMoved( cursor );
+ break;
+ }
+ case Qt::Key_Down: {
+ FormulaCursor* cursor = container->activeCursor();
+ cursor->moveDown( flag );
+ formula()->cursorHasMoved( cursor );
+ break;
+ }
+ case Qt::Key_Home: {
+ FormulaCursor* cursor = container->activeCursor();
+ cursor->moveHome( flag );
+ formula()->cursorHasMoved( cursor );
+ break;
+ }
+ case Qt::Key_End: {
+ FormulaCursor* cursor = container->activeCursor();
+ cursor->moveEnd( flag );
+ formula()->cursorHasMoved( cursor );
+ break;
+ }
+ default:
+ if ( state & Qt::ControlButton ) {
+ switch ( event->key() ) {
+ case Qt::Key_AsciiCircum: {
+ IndexRequest r( upperLeftPos );
+ return buildCommand( container, &r );
+ }
+ case Qt::Key_Underscore: {
+ IndexRequest r( lowerLeftPos );
+ return buildCommand( container, &r );
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+KCommand* SequenceElement::input( Container* container, QChar ch )
+{
+ int unicode = ch.unicode();
+ switch (unicode) {
+ case '(': {
+ BracketRequest r( container->document()->leftBracketChar(),
+ container->document()->rightBracketChar() );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }
+ case '[': {
+ BracketRequest r( LeftSquareBracket, RightSquareBracket );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }
+ case '{': {
+ BracketRequest r( LeftCurlyBracket, RightCurlyBracket );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }
+ case '|': {
+ if (!singlePipe) { // We have had 2 '|' in a row so we want brackets
+
+ DirectedRemove rDelete( req_remove, beforeCursor ); //Delete the previous '|' we dont need it any more
+ KCommand* command = buildCommand( container, &rDelete );
+ command->execute();
+
+ BracketRequest rBracket( LeftLineBracket , RightLineBracket);
+ singlePipe = true; //the next '|' will be a single pipe again
+ return buildCommand( container, &rBracket );
+ }
+ else { // We really do only want 1 '|'
+ TextCharRequest r(ch);
+
+ //in case another '|' character is entered right after this one, '| |' brackets are made; see above
+ singlePipe = false;
+
+ return buildCommand( container, &r );
+ }
+ }
+ case '^': {
+ IndexRequest r( upperRightPos );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }
+ case '_': {
+ IndexRequest r( lowerRightPos );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }
+ /*
+ case ' ': {
+ Request r( req_compactExpression );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }*/
+ case '}': {
+ Request r( req_addEmptyBox );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }
+ case ']':
+ case ')':
+ singlePipe = true;
+ break;
+ case '\\': {
+ Request r( req_addNameSequence );
+ singlePipe = true;
+ return buildCommand( container, &r );
+ }
+ default: {
+ singlePipe = true;
+ if ( ch.isPunct() || ch.isSymbol() ) {
+ OperatorRequest r( ch );
+ return buildCommand( container, &r );
+ }
+ if ( ch.isNumber() ) {
+ NumberRequest r( ch );
+ return buildCommand( container, &r );
+ }
+ TextCharRequest r( ch );
+ return buildCommand( container, &r );
+ }
+ }
+ return 0;
+}
+
+/**
+ * Stores the given childrens dom in the element.
+ */
+void SequenceElement::getChildrenDom( QDomDocument& doc, QDomElement elem,
+ uint from, uint to)
+{
+ for (uint i = from; i < to; i++) {
+ QDomElement tmpEleDom=children.at(i)->getElementDom(doc);
+ elem.appendChild(tmpEleDom);
+ }
+}
+
+/**
+ * Stores the given childrens MathML dom in the element.
+ */
+void SequenceElement::getChildrenMathMLDom( QDomDocument& doc, QDomNode& parent,
+ uint from, uint to)
+{
+ for ( uint i = from; i < to; i++ ) {
+ children.at( i )->writeMathML( doc, parent, false );
+ }
+}
+
+
+/**
+ * Builds elements from the given node and its siblings and
+ * puts them into the list.
+ * Returns false if an error occures.
+ */
+bool SequenceElement::buildChildrenFromDom(QPtrList<BasicElement>& list, QDomNode n)
+{
+ while (!n.isNull()) {
+ if (n.isElement()) {
+ QDomElement e = n.toElement();
+ BasicElement* child = 0;
+ QString tag = e.tagName().upper();
+
+ child = createElement(tag, e);
+ if (child != 0) {
+ child->setParent(this);
+ if (child->buildFromDom(e)) {
+ list.append(child);
+ }
+ else {
+ delete child;
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ n = n.nextSibling();
+ }
+ parse();
+ return true;
+}
+
+
+BasicElement* SequenceElement::createElement( QString type, const QDomElement& element )
+{
+ return creationStrategy->createElement( type, element );
+}
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void SequenceElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ uint count = children.count();
+ QDomDocument doc = element.ownerDocument();
+ getChildrenDom(doc, element, 0, count);
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool SequenceElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool SequenceElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ return buildChildrenFromDom(children, node);
+}
+
+
+void SequenceElement::parse()
+{
+ delete parseTree;
+
+ textSequence = true;
+ for (BasicElement* element = children.first();
+ element != 0;
+ element = children.next()) {
+
+ // Those types are gone. Make sure they won't
+ // be used.
+ element->setElementType(0);
+
+ if (element->getCharacter().isNull()) {
+ textSequence = false;
+ }
+ }
+
+ const SymbolTable& symbols = formula()->getSymbolTable();
+ SequenceParser parser(symbols);
+ parseTree = parser.parse(children);
+
+ // With the IndexElement dynamically changing its text/non-text
+ // behaviour we need to reparse your parent, too. Hacky!
+ BasicElement* p = getParent();
+ if ( p != 0 ) {
+ SequenceElement* seq = dynamic_cast<SequenceElement*>( p->getParent() );
+ if ( seq != 0 ) {
+ seq->parse();
+ }
+ }
+ // debug
+ //parseTree->output();
+}
+
+
+bool SequenceElement::isFirstOfToken( BasicElement* child )
+{
+ return ( child->getElementType() != 0 ) && isChildNumber( child->getElementType()->start(), child );
+}
+
+
+QString SequenceElement::toLatex()
+{
+ QString content;
+ uint count = children.count();
+ for ( uint i = 0; i < count; i++ ) {
+ BasicElement* child = children.at( i );
+// if ( isFirstOfToken( child ) ) {
+// content += "";
+// }
+ content += child->toLatex();
+ }
+ return content;
+}
+
+
+QString SequenceElement::formulaString()
+{
+ QString content;
+ uint count = children.count();
+ for ( uint i = 0; i < count; i++ ) {
+ BasicElement* child = children.at( i );
+ //if ( isFirstOfToken( child ) ) {
+ // content += " ";
+ //}
+ content += child->formulaString();
+ }
+ return content;
+}
+
+
+void SequenceElement::writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const
+{
+ for ( QPtrListIterator<BasicElement> it( children ); it.current(); ++it ) {
+ it.current()->writeMathML( doc, element, oasisFormat );
+ }
+}
+
+
+const BasicElement* SequenceElement::getChild( uint i ) const
+{
+ QPtrListIterator<BasicElement> it( children );
+ it += i;
+ return it.current();
+}
+
+
+int SequenceElement::childPos( const BasicElement* child ) const
+{
+ QPtrListIterator<BasicElement> it( children );
+ uint count = it.count();
+ for ( uint i=0; i<count; ++i, ++it ) {
+ if ( it.current() == child ) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+NameSequence::NameSequence( BasicElement* parent )
+ : SequenceElement( parent )
+{
+}
+
+
+bool NameSequence::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void NameSequence::calcCursorSize( const ContextStyle& context,
+ FormulaCursor* cursor, bool smallCursor )
+{
+ inherited::calcCursorSize( context, cursor, smallCursor );
+ LuPixelPoint point = widgetPos();
+ luPixel unitX = context.ptToLayoutUnitPixX( 1 );
+ luPixel unitY = context.ptToLayoutUnitPixY( 1 );
+ cursor->addCursorSize( LuPixelRect( point.x()-unitX, point.y()-unitY,
+ getWidth()+2*unitX, getHeight()+2*unitY ) );
+}
+
+void NameSequence::drawCursor( QPainter& painter, const ContextStyle& context,
+ StyleAttributes& style, FormulaCursor* cursor,
+ bool smallCursor, bool activeCursor )
+{
+ LuPixelPoint point = widgetPos();
+ painter.setPen( QPen( context.getEmptyColor(),
+ context.layoutUnitToPixelX( context.getLineWidth( style.sizeFactor() )/2 ) ) );
+ luPixel unitX = context.ptToLayoutUnitPixX( 1 );
+ luPixel unitY = context.ptToLayoutUnitPixY( 1 );
+ painter.drawRect( context.layoutUnitToPixelX( point.x()-unitX ),
+ context.layoutUnitToPixelY( point.y()-unitY ),
+ context.layoutUnitToPixelX( getWidth()+2*unitX ),
+ context.layoutUnitToPixelY( getHeight()+2*unitY ) );
+
+ inherited::drawCursor( painter, context, style, cursor, smallCursor, activeCursor );
+}
+
+void NameSequence::moveWordLeft( FormulaCursor* cursor )
+{
+ uint pos = cursor->getPos();
+ if ( pos > 0 ) {
+ cursor->setTo( this, 0 );
+ }
+ else {
+ moveLeft( cursor, this );
+ }
+}
+
+void NameSequence::moveWordRight( FormulaCursor* cursor )
+{
+ int pos = cursor->getPos();
+ if ( pos < countChildren() ) {
+ cursor->setTo( this, countChildren() );
+ }
+ else {
+ moveRight( cursor, this );
+ }
+}
+
+
+KCommand* NameSequence::compactExpressionCmd( Container* container )
+{
+ BasicElement* element = replaceElement( container->document()->getSymbolTable() );
+ if ( element != 0 ) {
+ getParent()->selectChild( container->activeCursor(), this );
+
+ KFCReplace* command = new KFCReplace( i18n( "Add Element" ), container );
+ command->addElement( element );
+ return command;
+ }
+ return 0;
+}
+
+KCommand* NameSequence::buildCommand( Container* container, Request* request )
+{
+ switch ( *request ) {
+ case req_compactExpression:
+ return compactExpressionCmd( container );
+ case req_addSpace:
+ case req_addIndex:
+ case req_addMatrix:
+ case req_addOneByTwoMatrix:
+ case req_addSymbol:
+ case req_addRoot:
+ case req_addFraction:
+ case req_addBracket:
+ case req_addNameSequence:
+ return 0;
+ default:
+ break;
+ }
+ return inherited::buildCommand( container, request );
+}
+
+
+KCommand* NameSequence::input( Container* container, QChar ch )
+{
+ int unicode = ch.unicode();
+ switch (unicode) {
+ case '(':
+ case '[':
+ case '|':
+ case '^':
+ case '_':
+ case '}':
+ case ']':
+ case ')':
+ case '\\': {
+// KCommand* compact = compactExpressionCmd( container );
+// KCommand* cmd = static_cast<SequenceElement*>( getParent() )->input( container, ch );
+// if ( compact != 0 ) {
+// KMacroCommand* macro = new KMacroCommand( cmd->name() );
+// macro->addCommand( compact );
+// macro->addCommand( cmd );
+// return macro;
+// }
+// else {
+// return cmd;
+// }
+ break;
+ }
+ case '{':
+ case ' ': {
+ Request r( req_compactExpression );
+ return buildCommand( container, &r );
+ }
+ default: {
+ TextCharRequest r( ch );
+ return buildCommand( container, &r );
+ }
+ }
+ return 0;
+}
+
+void NameSequence::setElementType( ElementType* t )
+{
+ inherited::setElementType( t );
+ parse();
+}
+
+BasicElement* NameSequence::replaceElement( const SymbolTable& table )
+{
+ QString name = buildName();
+ QChar ch = table.unicode( name );
+ if ( !ch.isNull() ) {
+ return new TextElement( ch, true );
+ }
+ else {
+ ch = table.unicode( i18n( name.latin1() ) );
+ if ( !ch.isNull() ) {
+ return new TextElement( ch, true );
+ }
+ }
+
+ if ( name == "!" ) return new SpaceElement( NEGTHIN );
+ if ( name == "," ) return new SpaceElement( THIN );
+ if ( name == ">" ) return new SpaceElement( MEDIUM );
+ if ( name == ";" ) return new SpaceElement( THICK );
+ if ( name == "quad" ) return new SpaceElement( QUAD );
+
+ if ( name == "frac" ) return new FractionElement();
+ if ( name == "atop" ) {
+ FractionElement* frac = new FractionElement();
+ frac->showLine( false );
+ return frac;
+ }
+ if ( name == "sqrt" ) return new RootElement();
+
+ return 0;
+}
+
+BasicElement* NameSequence::createElement( QString type )
+{
+ if ( type == "TEXT" ) return new TextElement();
+ return 0;
+}
+
+// void NameSequence::parse()
+// {
+// // A name sequence is known as name and so are its children.
+// // Caution: this is fake!
+// for ( int i = 0; i < countChildren(); i++ ) {
+// getChild( i )->setElementType( getElementType() );
+// }
+// }
+
+QString NameSequence::buildName()
+{
+ QString name;
+ for ( uint i = 0; i < countChildren(); i++ ) {
+ name += getChild( i )->getCharacter();
+ }
+ return name;
+}
+
+bool NameSequence::isValidSelection( FormulaCursor* cursor )
+{
+ SequenceElement* sequence = cursor->normal();
+ if ( sequence == 0 ) {
+ return false;
+ }
+ return sequence->onlyTextSelected( cursor );
+}
+
+int SequenceElement::buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n)
+{
+ while (!n.isNull()) {
+ int nodeNumber = 1;
+ if (n.isElement()) {
+ QDomElement e = n.toElement();
+ BasicElement* child = 0;
+ QString tag = e.tagName().lower();
+
+ kdDebug( DEBUGID ) << "Sequence Tag: " << tag << endl;
+ if ( tag == "semantics" ) { // Special case, just pick the first child
+ QDomNode node = e.firstChild();
+ while( ! node.isElement() ) {
+ node = node.nextSibling();
+ if ( node.isNull() ) {
+ return -1;
+ }
+ }
+ e = node.toElement();
+ tag = e.tagName().lower();
+ }
+ child = creationStrategy->createElement(tag, e);
+ if (child != 0) {
+ child->setParent(this);
+ if (style != 0) {
+ child->setStyle(style);
+ }
+ nodeNumber = child->buildFromMathMLDom( e );
+ if ( nodeNumber != -1 ) {
+ list.append(child);
+ }
+ else {
+ delete child;
+ return -1;
+ }
+ }
+ else {
+ kdWarning() << "Unsupported MathML element: " << tag << endl;
+ }
+ }
+ for (int i = 0; i < nodeNumber; i++ ) {
+ if ( n.isNull() ) {
+ return -1;
+ }
+ n = n.nextSibling();
+ }
+ }
+ // Operator elements inside a sequence have to be parsed to get proper form
+ // value. Form value is needed to access operator dictionary and has to be
+ // obtained after sequence parsing since its value depends on position
+ // inside the sequence.
+
+ // If the sequence contains more than one element, if the first or last
+ // element are operators, they have to be marked differently
+ if ( list.count() > 1 ) {
+ if ( list.getFirst()->getElementName() == "mo" ) {
+ static_cast<OperatorElement*>( list.getFirst() )->setForm( PrefixForm );
+ }
+ if ( list.getLast()->getElementName() == "mo" ) {
+ static_cast<OperatorElement*>( list.getLast() )->setForm( PostfixForm );
+ }
+ for ( uint i = 1; i < list.count() - 1; i++ ) {
+ if ( list.at( i )->getElementName() == "mo" ) {
+ static_cast<OperatorElement*>( list.at( i ) )->setForm( InfixForm );
+ }
+ }
+ }
+ else if ( list.count() == 1 ) {
+ if ( list.getFirst()->getElementName() == "mo" ) {
+ static_cast<OperatorElement*>( list.getFirst() )->setForm( InfixForm );
+ }
+ }
+ parse();
+ return 1;
+}
+
+/**
+ */
+int SequenceElement::readContentFromMathMLDom(QDomNode& node)
+{
+ if ( BasicElement::readContentFromMathMLDom(node) == -1 ) {
+ return -1;
+ }
+
+ return buildChildrenFromMathMLDom(children, node);
+}
+
+int SequenceElement::buildMathMLChild( QDomNode node )
+{
+ int nodeCounter = 1;
+ while ( ! node.isElement() ) {
+ node = node.nextSibling();
+ nodeCounter++;
+ if ( node.isNull() ) {
+ return -1;
+ }
+ }
+ QDomElement e = node.toElement();
+ BasicElement* child = 0;
+ QString tag = e.tagName().lower();
+
+ child = creationStrategy->createElement(tag, e);
+ if (child != 0) {
+ child->setParent(this);
+ if (style != 0) {
+ child->setStyle(style);
+ }
+ if (child->buildFromMathMLDom(e) != -1) {
+ children.append(child);
+ }
+ else {
+ delete child;
+ return -1;
+ }
+ }
+ else {
+ return -1;
+ }
+ parse();
+ return nodeCounter;
+}
+
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/sequenceelement.h b/lib/kformula/sequenceelement.h
new file mode 100644
index 00000000..9bc3c500
--- /dev/null
+++ b/lib/kformula/sequenceelement.h
@@ -0,0 +1,620 @@
+/* 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.
+*/
+
+#ifndef SEQUENCEELEMENT_H
+#define SEQUENCEELEMENT_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+#include "basicelement.h"
+
+class QKeyEvent;
+
+KFORMULA_NAMESPACE_BEGIN
+
+class SymbolTable;
+class ElementCreationStrategy;
+
+/**
+ * The element that contains a number of children.
+ * The children are aligned in one line.
+ */
+class SequenceElement : public BasicElement {
+ SequenceElement& operator=( const SequenceElement& ) { return *this; }
+public:
+
+ SequenceElement(BasicElement* parent = 0);
+ ~SequenceElement();
+
+ SequenceElement( const SequenceElement& );
+
+ virtual SequenceElement* clone() {
+ return new SequenceElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns whether its prohibited to change the sequence with this cursor.
+ */
+ virtual bool readOnly( const FormulaCursor* ) const;
+
+ /**
+ * @returns true if the sequence contains only text.
+ */
+ virtual bool isTextOnly() const { return textSequence; }
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point,
+ const LuPixelPoint& parentOrigin );
+
+ // drawing
+ //
+ // Drawing depends on a context which knows the required properties like
+ // fonts, spaces and such.
+ // It is essential to calculate elements size with the same context
+ // before you draw.
+
+ /**
+ * Tells the sequence to have a smaller size than its parant.
+ */
+ void setSizeReduction(const ContextStyle& context);
+
+ /**
+ * @returns true if there is no visible element in the sequence.
+ * Please note that there might be phantom elements.
+ */
+ bool isEmpty();
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ virtual void drawEmptyRect( QPainter& painter, const ContextStyle& context,
+ double factor, const LuPixelPoint& upperLeft );
+
+ virtual void calcCursorSize( const ContextStyle& context,
+ FormulaCursor* cursor, bool smallCursor );
+
+ /**
+ * If the cursor is inside a sequence it needs to be drawn.
+ */
+ virtual void drawCursor( QPainter& painter, const ContextStyle& context,
+ StyleAttributes& style, FormulaCursor* cursor,
+ bool smallCursor, bool activeCursor );
+
+ // navigation
+ //
+ // The elements are responsible to handle cursor movement themselves.
+ // To do this they need to know the direction the cursor moves and
+ // the element it comes from.
+ //
+ // The cursor might be in normal or in selection mode.
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Moves to the beginning of this word or if we are there already
+ * to the beginning of the previous.
+ */
+ virtual void moveWordLeft(FormulaCursor* cursor);
+
+ /**
+ * Moves to the end of this word or if we are there already
+ * to the end of the next.
+ */
+ virtual void moveWordRight(FormulaCursor* cursor);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Moves the cursor to the first position in this sequence.
+ * (That is before the first child.)
+ */
+ virtual void moveHome(FormulaCursor* cursor);
+
+ /**
+ * Moves the cursor to the last position in this sequence.
+ * (That is behind the last child.)
+ */
+ virtual void moveEnd(FormulaCursor* cursor);
+
+ /**
+ * Sets the cursor inside this element to its start position.
+ * For most elements that is the main child.
+ */
+ virtual void goInside(FormulaCursor* cursor);
+
+ /**
+ * Sets the cursor inside this element to its last position.
+ * For most elements that is the main child.
+ */
+ virtual void goInsideLast(FormulaCursor* cursor);
+
+
+ // children
+
+ /**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction. The inserted elements will
+ * be selected.
+ *
+ * The list will be emptied but stays the property of the caller.
+ */
+ virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ */
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+ virtual void normalize(FormulaCursor*, Direction);
+
+ /**
+ * Returns the child at the cursor.
+ * Does not care about the selection.
+ */
+ virtual BasicElement* getChild(FormulaCursor*, Direction = beforeCursor);
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor* cursor, BasicElement* child);
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child);
+
+ /**
+ * @returns the number of children we have.
+ */
+ uint countChildren() const { return children.count(); }
+
+ /**
+ * @returns whether the child has the given number.
+ */
+ bool isChildNumber( uint pos, BasicElement* child )
+ { return children.at( pos ) == child; }
+
+ /**
+ * Selects all children. The cursor is put behind, the mark before them.
+ */
+ void selectAllChildren(FormulaCursor* cursor);
+
+ bool onlyTextSelected( FormulaCursor* cursor );
+
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+
+
+ /**
+ * Parses the input. It's the container which does create
+ * new elements because it owns the undo stack. But only the
+ * sequence knows what chars are allowed.
+ */
+ virtual KCommand* input( Container* container, QChar ch );
+ virtual KCommand* input( Container* container, QKeyEvent* event );
+
+ /**
+ * Parses the sequence and generates a new syntax tree.
+ * Has to be called after each modification.
+ */
+ virtual void parse();
+
+ /**
+ * Stores the given childrens dom in the element.
+ */
+ void getChildrenDom( QDomDocument& doc, QDomElement elem, uint from, uint to);
+
+ /**
+ * Stores the given childrens MathML dom in the element.
+ */
+ void getChildrenMathMLDom( QDomDocument& doc, QDomNode& elem, uint from, uint to );
+
+ /**
+ * Builds elements from the given node and its siblings and
+ * puts them into the list.
+ * Returns false if an error occures.
+ */
+ bool buildChildrenFromDom(QPtrList<BasicElement>& list, QDomNode n);
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+ /**
+ * @returns the child at position i.
+ */
+ BasicElement* getChild(uint i) { return children.at(i); }
+ const BasicElement* getChild(uint i) const;
+
+ int childPos( BasicElement* child ) { return children.find( child ); }
+ int childPos( const BasicElement* child ) const;
+
+ class ChildIterator {
+ public:
+ ChildIterator( SequenceElement* sequence, int pos=0 )
+ : m_sequence( sequence ), m_pos( pos ) {}
+
+ typedef BasicElement value_type;
+ typedef BasicElement* pointer;
+ typedef BasicElement& reference;
+
+ // we simply expect the compared iterators to belong
+ // to the same sequence.
+ bool operator== ( const ChildIterator& it ) const
+ { return /*m_sequence==it.m_sequence &&*/ m_pos==it.m_pos; }
+ bool operator!= ( const ChildIterator& it ) const
+ { return /*m_sequence!=it.m_sequence ||*/ m_pos!=it.m_pos; }
+
+ const BasicElement& operator* () const
+ { return *m_sequence->getChild( m_pos ); }
+ BasicElement& operator* ()
+ { return *m_sequence->getChild( m_pos ); }
+
+ BasicElement* operator->() const
+ { return m_sequence->getChild( m_pos ); }
+
+ ChildIterator& operator++ ()
+ { ++m_pos; return *this; }
+ ChildIterator operator++ ( int )
+ { ChildIterator it( *this ); ++m_pos; return it; }
+ ChildIterator& operator-- ()
+ { --m_pos; return *this; }
+ ChildIterator operator-- ( int )
+ { ChildIterator it( *this ); --m_pos; return it; }
+ ChildIterator& operator+= ( int j )
+ { m_pos+=j; return *this; }
+ ChildIterator & operator-= ( int j )
+ { m_pos-=j; return *this; }
+
+ private:
+ SequenceElement* m_sequence;
+ int m_pos;
+ };
+
+ typedef ChildIterator iterator;
+
+ iterator begin() { return ChildIterator( this, 0 ); }
+ iterator end() { return ChildIterator( this, countChildren() ); }
+
+ static void setCreationStrategy( ElementCreationStrategy* strategy );
+
+ virtual void setStyle(StyleElement *style);
+ virtual int buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n);
+ virtual int readContentFromMathMLDom(QDomNode& node);
+ int buildMathMLChild( QDomNode node );
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "SEQUENCE"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ virtual QString getElementName() const { return "mrow"; }
+ virtual void writeMathMLContent( QDomDocument& doc,
+ QDomElement& element,
+ bool oasisFormat ) const;
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ /**
+ * Sets the childrens' positions after their size has been
+ * calculated.
+ *
+ * @see #calcSizes
+ */
+ virtual void setChildrenPositions();
+
+ /**
+ * Creates a new element with the given type.
+ *
+ * @param type the desired type of the element
+ */
+ virtual BasicElement* createElement(QString type, const QDomElement &element);
+
+ /**
+ * @returns the position where the child starts.
+ *
+ * @param context the context the child is in
+ * @param child the child's number
+ */
+ luPixel getChildPosition( const ContextStyle& context, uint child );
+
+ /**
+ * @returns whether the child is the first element of its token.
+ */
+ virtual bool isFirstOfToken( BasicElement* child );
+
+ /**
+ * Insert a new child in the sequence
+ *
+ * @returns true if succesful, i.e. if index is in range, otherwise returns
+ * false. The valid range is 0 to count(). The child is appended if index == count().
+ *
+ * @param index position in the sequence to insert the child
+ * @param child the child to insert in the sequence
+ */
+ bool insert( uint index, BasicElement *child );
+
+ static ElementCreationStrategy* getCreationStrategy() { return creationStrategy; }
+
+ /**
+ * Space around sequence
+ */
+ virtual luPt getSpaceBefore( const ContextStyle&, ContextStyle::TextStyle, double ) { return 0; }
+ virtual luPt getSpaceAfter( const ContextStyle&, ContextStyle::TextStyle, double ) { return 0; }
+
+ static ElementCreationStrategy* creationStrategy;
+
+private:
+
+ /**
+ * Removes the children at pos and appends it to the list.
+ */
+ void removeChild(QPtrList<BasicElement>& removedChildren, int pos);
+
+
+ /**
+ * Our children. Be sure to notify the rootElement before
+ * you remove any.
+ */
+ QPtrList<BasicElement> children;
+
+ /**
+ * the syntax tree of the sequence
+ */
+ ElementType* parseTree;
+
+ /**
+ * true if the sequence contains only text
+ */
+ bool textSequence;
+
+ bool singlePipe; //The key '|' produces one '|' not '| |', '||' produces '| |'
+
+ StyleElement *style;
+};
+
+
+/**
+ * The sequence thats a name. Actually the purpose
+ * is to be able to insert any element by keyboard.
+ */
+class NameSequence : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ NameSequence( BasicElement* parent = 0 );
+
+ virtual NameSequence* clone() {
+ return new NameSequence( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns true if the sequence contains only text.
+ */
+ //virtual bool isTextOnly() const { return true; }
+
+ /**
+ * @returns the character that represents this element. Used for
+ * parsing a sequence.
+ * This is guaranteed to be QChar::null for all non-text elements.
+ */
+ virtual QChar getCharacter() const { return '\\'; }
+
+ /**
+ * @returns the type of this element. Used for
+ * parsing a sequence.
+ */
+ virtual TokenType getTokenType() const { return NAME; }
+
+ /**
+ * We are our own main child. This causes interessting effects.
+ */
+ virtual SequenceElement* getMainChild() { return this; }
+
+ virtual void calcCursorSize( const ContextStyle& context,
+ FormulaCursor* cursor, bool smallCursor );
+
+ /**
+ * If the cursor is inside a sequence it needs to be drawn.
+ */
+ virtual void drawCursor( QPainter& painter, const ContextStyle& context,
+ StyleAttributes& style, FormulaCursor* cursor,
+ bool smallCursor, bool activeCursor );
+
+ /**
+ * Moves to the beginning of this word or if we are there already
+ * to the beginning of the previous.
+ */
+ virtual void moveWordLeft(FormulaCursor* cursor);
+
+ /**
+ * Moves to the end of this word or if we are there already
+ * to the end of the next.
+ */
+ virtual void moveWordRight(FormulaCursor* cursor);
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+
+
+ /**
+ * Parses the input. It's the container which does create
+ * new elements because it owns the undo stack. But only the
+ * sequence knows what chars are allowed.
+ */
+ virtual KCommand* input( Container* container, QChar ch );
+
+ /**
+ * Sets a new type. This is done during parsing.
+ */
+ virtual void setElementType( ElementType* t );
+
+ /**
+ * @returns the element this sequence is to be replaced with.
+ */
+ BasicElement* replaceElement( const SymbolTable& table );
+
+ /**
+ * Tests whether the selected elements can be inserted in a
+ * name sequence.
+ */
+ static bool isValidSelection( FormulaCursor* cursor );
+
+protected:
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "NAMESEQUENCE"; }
+
+ virtual QString getElementName() const { return "mi"; }
+ /**
+ * Creates a new element with the given type.
+ *
+ * @param type the desired type of the element
+ */
+ virtual BasicElement* createElement( QString type );
+
+ /**
+ * Parses the sequence and generates a new syntax tree.
+ * Has to be called after each modification.
+ */
+ //virtual void parse();
+
+ /**
+ * @returns whether the child is the first element of its token.
+ * This can never happen here. Our children reuse our own
+ * element type.
+ */
+ virtual bool isFirstOfToken( BasicElement* ) { return false; }
+
+private:
+
+ KCommand* compactExpressionCmd( Container* container );
+
+ QString buildName();
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // SEQUENCEELEMENT_H
diff --git a/lib/kformula/sequenceparser.cc b/lib/kformula/sequenceparser.cc
new file mode 100644
index 00000000..55c8dec7
--- /dev/null
+++ b/lib/kformula/sequenceparser.cc
@@ -0,0 +1,241 @@
+/* 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 "basicelement.h"
+#include "elementtype.h"
+#include "sequenceparser.h"
+#include "symboltable.h"
+#include "textelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+SequenceParser::SequenceParser( const SymbolTable& t )
+ : tokenStart( 0 ), tokenEnd( 0 ), type( SEQUENCE ),
+ binOpAllowed( false ), table( t )
+{
+}
+
+
+void SequenceParser::setElementType( uint pos, ElementType* type )
+{
+ list.at( pos )->setElementType( type );
+}
+
+
+ElementType* SequenceParser::parse( QPtrList<BasicElement>& elements )
+{
+ list = elements;
+ return new SequenceType( this );
+}
+
+
+void SequenceParser::nextToken()
+{
+ tokenStart = tokenEnd;
+ if ( tokenStart >= list.count() ) {
+ type = END;
+ return;
+ }
+ tokenEnd++;
+ BasicElement* element = list.at( tokenStart );
+ type = element->getTokenType();
+ if ( type == SEPARATOR ) {
+ if ( tokenEnd < list.count() ) {
+ QChar ch = getEndChar();
+ switch ( ch ) {
+ case ',':
+ case '>':
+ case ';':
+ type = NAME;
+ tokenEnd++;
+ break;
+ default:
+ readText();
+ }
+ }
+ }
+ else if ( type == ORDINARY ) {
+ readText();
+ }
+ else if ( type == NUMBER ) {
+ readNumber();
+ }
+ if ( !binOpAllowed && ( type == BINOP ) ) {
+ type = ORDINARY;
+ }
+ binOpAllowed = ( type == ORDINARY ) || ( type == NUMBER ) || ( type == NAME ) ||
+ ( type == ELEMENT ) || ( type == BRACKET ) || ( type == INNER );
+
+ //cerr << "SequenceParser::nextToken(): " << type << " "
+ // << tokenStart << " " << tokenEnd << endl;
+}
+
+
+void SequenceParser::readNumber()
+{
+ type = NUMBER;
+ readDigits();
+ if ( tokenEnd < list.count()-1 ) {
+ QChar ch = getEndChar();
+
+ // Look for a dot.
+ if ( ch == '.' ) {
+ tokenEnd++;
+ ch = getEndChar();
+ if ( ch.isNumber() ) {
+ readDigits();
+ }
+// else {
+// tokenEnd--;
+// return;
+// }
+ }
+
+ // there might as well be an exponent
+ if ( tokenEnd < list.count()-1 ) {
+ BasicElement* element = list.at(tokenEnd);
+ ch = getEndChar();
+ if ( ( element->getTokenType() == ORDINARY ) &&
+ ( ( ch == 'E' ) || ( ch == 'e' ) ) ) {
+ tokenEnd++;
+ ch = getEndChar();
+
+ // signs are allowed after the exponent
+ if ( ( ( ch == '+' ) || ( ch == '-' ) ) &&
+ ( tokenEnd < list.count()-1 ) ) {
+ tokenEnd++;
+ ch = getEndChar();
+ if ( ch.isNumber() ) {
+ readDigits();
+ }
+ else {
+ tokenEnd -= 2;
+ return;
+ }
+ }
+ else if ( ch.isNumber() ) {
+ readDigits();
+ }
+ else {
+ tokenEnd--;
+ }
+ }
+ }
+ }
+}
+
+
+void SequenceParser::readDigits()
+{
+ for ( ; tokenEnd < list.count(); tokenEnd++ ) {
+ QChar ch = getEndChar();
+ if ( !ch.isNumber() ) {
+ break;
+ }
+ }
+}
+
+
+void SequenceParser::readText()
+{
+ BasicElement* element = list.at( tokenStart );
+ TextElement* beginText = static_cast<TextElement*>( element );
+ if ( beginText->isSymbol() ||
+ ( beginText->getCharacter() == '/' ) ) {
+ return;
+ }
+ char format = beginText->format();
+ type = ORDINARY;
+ for ( ; tokenEnd < list.count(); tokenEnd++ ) {
+ element = list.at( tokenEnd );
+ TokenType tt = element->getTokenType();
+ if ( ( ( tt != ORDINARY ) ||
+ ( element->getCharacter() == '/' ) ) &&
+ ( tt != NUMBER ) ) {
+ return;
+ }
+ if ( static_cast<TextElement*>( element )->format() != format ) {
+ return;
+ }
+ if ( static_cast<TextElement*>( element )->isSymbol() ) {
+ return;
+ }
+ }
+}
+
+QChar SequenceParser::getEndChar()
+{
+ BasicElement* element = list.at( tokenEnd );
+ return element->getCharacter();
+}
+
+
+ElementType* SequenceParser::getPrimitive()
+{
+ //cerr << "SequenceParser::getPrimitive(): " << type << " "
+ // << tokenStart << " " << tokenEnd << endl;
+ switch ( type ) {
+ case ORDINARY: {
+// QString text = getText();
+// if ( table.contains( text ) || ( text == "\\quad" ) ) {
+// return new NameType( this, text );
+// }
+// else {
+ return new TextType( this );
+// }
+ }
+ case NAME:
+ return new NameType( this );
+ case NUMBER:
+ return new NumberType( this );
+ case ELEMENT:
+ return new ComplexElementType( this );
+ case INNER:
+ return new InnerElementType( this );
+ case BINOP:
+ return new OperatorType( this );
+ case RELATION:
+ return new RelationType( this );
+ case PUNCTUATION:
+ return new PunctuationType( this );
+ case BRACKET:
+ return new BracketType( this );
+ case SEQUENCE:
+ case SEPARATOR:
+ case END:
+ return 0;
+ }
+ return 0;
+}
+
+
+QString SequenceParser::text()
+{
+ QString text;
+ for ( uint i = tokenStart; i < tokenEnd; i++ ) {
+ BasicElement* element = list.at( i );
+ text.append( element->getCharacter() );
+ }
+ return text;
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/sequenceparser.h b/lib/kformula/sequenceparser.h
new file mode 100644
index 00000000..1051ec12
--- /dev/null
+++ b/lib/kformula/sequenceparser.h
@@ -0,0 +1,132 @@
+/* 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.
+*/
+
+#ifndef SEQUENCEPARSER_H
+#define SEQUENCEPARSER_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class BasicElement;
+class ElementType;
+class SymbolTable;
+
+
+/**
+ * The parser that gets the element list and returns a syntax tree.
+ */
+class SequenceParser {
+public:
+ SequenceParser(const SymbolTable& table);
+
+ /**
+ * @returns a parse tree.
+ */
+ ElementType* parse(QPtrList<BasicElement>& elements);
+
+ /**
+ * Reads the next token.
+ */
+ void nextToken();
+
+ uint getStart() const { return tokenStart; }
+ uint getEnd() const { return tokenEnd; }
+ TokenType getTokenType() const { return type; }
+
+ /**
+ * Tells the element about its new type.
+ *
+ * @param pos the position of the element
+ * @param type the new type
+ */
+ void setElementType(uint pos, ElementType* type);
+
+ /**
+ * @returns a new primitive token.
+ */
+ ElementType* getPrimitive();
+
+ /**
+ * @returns the current token's text
+ */
+ QString text();
+
+private:
+
+ /**
+ * Reads the next token which is a number.
+ */
+ void readNumber();
+
+ /**
+ * Reads a sequence of digits.
+ */
+ void readDigits();
+
+ /**
+ * Reads the next token which is some text.
+ */
+ void readText();
+
+ /**
+ * @returns the char at tokenEnd.
+ */
+ QChar getEndChar();
+
+ /**
+ * The elements we want to parse. The parser must not change
+ * it!
+ */
+ QPtrList<BasicElement> list;
+
+ /**
+ * The position up to which we have read. The current
+ * token starts here.
+ */
+ uint tokenStart;
+
+ /**
+ * The first position after the current token.
+ */
+ uint tokenEnd;
+
+ /**
+ * The type of the current token.
+ */
+ TokenType type;
+
+ /**
+ * Whether the next token might be a binary operator.
+ */
+ bool binOpAllowed;
+
+ /**
+ * The table that contains all known symbols.
+ */
+ const SymbolTable& table;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // SEQUENCEPARSER_H
diff --git a/lib/kformula/spaceelement.cc b/lib/kformula/spaceelement.cc
new file mode 100644
index 00000000..1ff62da7
--- /dev/null
+++ b/lib/kformula/spaceelement.cc
@@ -0,0 +1,431 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
+ Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qfontmetrics.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <kprinter.h>
+
+#include "contextstyle.h"
+#include "elementvisitor.h"
+#include "spaceelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+SpaceElement::SpaceElement( SpaceWidth space, bool tab, BasicElement* parent )
+ : BasicElement( parent ),
+ m_tab( tab ),
+ m_widthType( NoSize ),
+ m_heightType( NoSize ),
+ m_depthType( NoSize ),
+ m_lineBreak( NoBreakType )
+{
+ // Backwards compatibility with KFO format
+ switch ( space ) {
+ case NEGTHIN:
+ m_widthType = NegativeThinMathSpace;
+ break;
+ case THIN:
+ m_widthType = ThinMathSpace;
+ break;
+ case MEDIUM:
+ m_widthType = MediumMathSpace;
+ break;
+ case THICK:
+ m_widthType = ThickMathSpace;
+ break;
+ case QUAD:
+ m_widthType = VeryVeryThickMathSpace;
+ break;
+ }
+}
+
+
+SpaceElement::SpaceElement( const SpaceElement& other )
+ : BasicElement( other ),
+ m_widthType( other.m_widthType ),
+ m_width( other.m_width ),
+ m_heightType( other.m_heightType ),
+ m_height( other.m_height ),
+ m_depthType( other.m_depthType ),
+ m_depth( other.m_depth ),
+ m_lineBreak( other.m_lineBreak )
+{
+}
+
+
+bool SpaceElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void SpaceElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ QFont font = context.getDefaultFont();
+ font.setPointSize( mySize );
+
+ QFontMetrics fm( font );
+ QChar w = 'M';
+ LuPixelRect hbound = fm.boundingRect( w );
+ QChar h = 'x';
+ LuPixelRect vbound = fm.boundingRect( h );
+
+ double width = style.getSpace( m_widthType, m_width );
+ if ( m_widthType == AbsoluteSize ) {
+ width = m_width / context.layoutUnitPtToPt( context.getBaseSize() );
+ }
+ else if ( m_widthType == PixelSize ) {
+ width = context.pixelYToPt( m_width ) / context.layoutUnitPtToPt( context.getBaseSize() );
+ }
+ double height = style.getSpace( m_heightType, m_height );
+ if ( m_heightType == AbsoluteSize ) {
+ height = m_height / context.layoutUnitPtToPt( context.getBaseSize() );
+ }
+ else if ( m_heightType == PixelSize ) {
+ height = context.pixelYToPt( m_height ) / context.layoutUnitPtToPt( context.getBaseSize() );
+ }
+ double depth = style.getSpace( m_depthType, m_depth );
+ if ( m_depthType == AbsoluteSize ) {
+ depth = m_depth / context.layoutUnitPtToPt( context.getBaseSize() );
+ }
+ else if ( m_depthType == PixelSize ) {
+ depth = context.pixelYToPt( m_depth ) / context.layoutUnitPtToPt( context.getBaseSize() );
+ }
+
+ setWidth( hbound.width() * width );
+ setHeight( vbound.height() * height + vbound.height() * depth );
+ setBaseline( vbound.height() * height );
+
+ if ( m_tab ) {
+ getParent()->registerTab( this );
+ }
+}
+
+void SpaceElement::draw( QPainter& painter, const LuPixelRect& /*r*/,
+ const ContextStyle& context,
+ ContextStyle::TextStyle /*tstyle*/,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& /*style*/,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos(parentOrigin.x()+getX(), parentOrigin.y()+getY());
+ // there is such a thing as negative space!
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ if ( context.edit() ) {
+ painter.setPen( context.getEmptyColor() );
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ),
+ context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ),
+ context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ),
+ context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
+ }
+}
+
+
+void SpaceElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+ switch ( m_widthType ) {
+ case NegativeVeryVeryThinMathSpace:
+ case NegativeVeryThinMathSpace:
+ case NegativeThinMathSpace:
+ case NegativeMediumMathSpace:
+ case NegativeThickMathSpace:
+ case NegativeVeryThickMathSpace:
+ case NegativeVeryVeryThickMathSpace:
+ element.setAttribute( "WIDTH", "negthin" );
+ break;
+ case VeryVeryThinMathSpace:
+ case VeryThinMathSpace:
+ case ThinMathSpace:
+ element.setAttribute( "WIDTH", "thin" );
+ break;
+ case MediumMathSpace:
+ element.setAttribute( "WIDTH", "medium" );
+ break;
+ case ThickMathSpace:
+ element.setAttribute( "WIDTH", "thick" );
+ break;
+ case VeryThickMathSpace:
+ case VeryVeryThickMathSpace:
+ element.setAttribute( "WIDTH", "quad" );
+ break;
+ case AbsoluteSize:
+ case RelativeSize:
+ case PixelSize:
+ if ( m_width < 0 ) {
+ element.setAttribute( "WIDTH", "negthin" );
+ }
+ else {
+ element.setAttribute( "WIDTH", "thin" );
+ }
+ default:
+ break;
+ }
+ if ( m_tab ) {
+ element.setAttribute( "TAB", "true" );
+ }
+}
+
+bool SpaceElement::readAttributesFromDom( QDomElement element )
+{
+ if ( !BasicElement::readAttributesFromDom( element ) ) {
+ return false;
+ }
+ QString widthStr = element.attribute( "WIDTH" );
+ if( !widthStr.isNull() ) {
+ if ( widthStr.lower() == "quad" ) {
+ m_widthType = VeryVeryThickMathSpace;
+ }
+ else if ( widthStr.lower() == "thick" ) {
+ m_widthType = ThickMathSpace;
+ }
+ else if ( widthStr.lower() == "medium" ) {
+ m_widthType = MediumMathSpace;
+ }
+ else if ( widthStr.lower() == "negthin" ) {
+ m_widthType = NegativeThinMathSpace;
+ }
+ else {
+ m_widthType = ThinMathSpace;
+ }
+ }
+ else {
+ return false;
+ }
+ QString tabStr = element.attribute( "TAB" );
+ m_tab = !tabStr.isNull();
+ return true;
+}
+
+bool SpaceElement::readContentFromDom(QDomNode& node)
+{
+ return BasicElement::readContentFromDom( node );
+}
+
+bool SpaceElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ QString widthStr = element.attribute( "width" ).stripWhiteSpace().lower();
+ if ( ! widthStr.isNull() ) {
+ m_width = getSize( widthStr, &m_widthType );
+ if ( m_widthType == NoSize ) {
+ m_widthType = getSpace( widthStr );
+ }
+ }
+ QString heightStr = element.attribute( "height" ).stripWhiteSpace().lower();
+ if ( ! heightStr.isNull() ) {
+ m_height = getSize( heightStr, &m_heightType );
+ }
+ QString depthStr = element.attribute( "depth" ).stripWhiteSpace().lower();
+ if ( ! depthStr.isNull() ) {
+ m_depth = getSize( depthStr, &m_depthType );
+ }
+ QString linebreakStr = element.attribute( "linebreak" ).stripWhiteSpace().lower();
+ if ( ! linebreakStr.isNull() ) {
+ if ( linebreakStr == "auto" ) {
+ m_lineBreak = AutoBreak;
+ }
+ else if ( linebreakStr == "newline" ) {
+ m_lineBreak = NewLineBreak;
+ }
+ else if ( linebreakStr == "indentingnewline" ) {
+ m_lineBreak = IndentingNewLineBreak;
+ }
+ else if ( linebreakStr == "nobreak" ) {
+ m_lineBreak = NoBreak;
+ }
+ else if ( linebreakStr == "goodbreak" ) {
+ m_lineBreak = GoodBreak;
+ }
+ else if ( linebreakStr == "badbreak" ) {
+ m_lineBreak = BadBreak;
+ }
+ }
+ return true;
+}
+
+void SpaceElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ switch ( m_widthType ) {
+ case AbsoluteSize:
+ element.setAttribute( "width", QString( "%1pt" ).arg( m_width ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "width", QString( "%1%" ).arg( m_width * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "width", QString( "%1px" ).arg( m_width ) );
+ break;
+ case NegativeVeryVeryThinMathSpace:
+ element.setAttribute( "width", "negativeveryverythinmathspace" );
+ break;
+ case NegativeVeryThinMathSpace:
+ element.setAttribute( "width", "negativeverythinmathspace" );
+ break;
+ case NegativeThinMathSpace:
+ element.setAttribute( "width", "negativethinmathspace" );
+ break;
+ case NegativeMediumMathSpace:
+ element.setAttribute( "width", "negativemediummathspace" );
+ break;
+ case NegativeThickMathSpace:
+ element.setAttribute( "width", "negativethickmathspace" );
+ break;
+ case NegativeVeryThickMathSpace:
+ element.setAttribute( "width", "negativeverythickmathspace" );
+ break;
+ case NegativeVeryVeryThickMathSpace:
+ element.setAttribute( "width", "negativeveryverythickmathspace" );
+ break;
+ case VeryVeryThinMathSpace:
+ element.setAttribute( "width", "veryverythinmathspace" );
+ break;
+ case VeryThinMathSpace:
+ element.setAttribute( "width", "verythinmathspace" );
+ break;
+ case ThinMathSpace:
+ element.setAttribute( "width", "thinmathspace" );
+ break;
+ case MediumMathSpace:
+ element.setAttribute( "width", "mediummathspace" );
+ break;
+ case ThickMathSpace:
+ element.setAttribute( "width", "thickmathspace" );
+ break;
+ case VeryThickMathSpace:
+ element.setAttribute( "width", "verythickmathspace" );
+ break;
+ case VeryVeryThickMathSpace:
+ element.setAttribute( "width", "veryverythickmathspace" );
+ break;
+ default:
+ break;
+ }
+ switch ( m_heightType ) {
+ case AbsoluteSize:
+ element.setAttribute( "height", QString( "%1pt" ).arg( m_height ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "height", QString( "%1%" ).arg( m_height * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "height", QString( "%1px" ).arg( m_height ) );
+ break;
+ default:
+ break;
+ }
+ switch ( m_depthType ) {
+ case AbsoluteSize:
+ element.setAttribute( "depth", QString( "%1pt" ).arg( m_depth ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "depth", QString( "%1%" ).arg( m_depth * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "depth", QString( "%1px" ).arg( m_depth ) );
+ break;
+ default:
+ break;
+ }
+ switch ( m_lineBreak ) {
+ case AutoBreak:
+ element.setAttribute( "linebreak", "auto" );
+ break;
+ case NewLineBreak:
+ element.setAttribute( "linebreak", "newline" );
+ break;
+ case IndentingNewLineBreak:
+ element.setAttribute( "linebreak", "indentingnewline" );
+ break;
+ case NoBreak:
+ element.setAttribute( "linebreak", "nobreak" );
+ break;
+ case GoodBreak:
+ element.setAttribute( "linebreak", "goodbreak" );
+ break;
+ case BadBreak:
+ element.setAttribute( "linebreak", "badbreak" );
+ break;
+ default:
+ break;
+ }
+}
+
+QString SpaceElement::toLatex()
+{
+ switch ( m_widthType ) {
+ case NegativeVeryVeryThinMathSpace:
+ case NegativeVeryThinMathSpace:
+ case NegativeThinMathSpace:
+ case NegativeMediumMathSpace:
+ case NegativeThickMathSpace:
+ case NegativeVeryThickMathSpace:
+ case NegativeVeryVeryThickMathSpace:
+ return "\\!";
+ case VeryVeryThinMathSpace:
+ case VeryThinMathSpace:
+ case ThinMathSpace:
+ return "\\,";
+ case MediumMathSpace:
+ return "\\>";
+ case ThickMathSpace:
+ return "\\;";
+ case VeryThickMathSpace:
+ case VeryVeryThickMathSpace:
+ return "\\quad ";
+ case AbsoluteSize:
+ case RelativeSize:
+ case PixelSize:
+ if ( m_width < 0 ) {
+ return "\\!";
+ }
+ else {
+ return "\\,";
+ }
+ default:
+ break;
+ }
+ return "";
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/spaceelement.h b/lib/kformula/spaceelement.h
new file mode 100644
index 00000000..52a666d1
--- /dev/null
+++ b/lib/kformula/spaceelement.h
@@ -0,0 +1,167 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
+ Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef SPACEELEMENT_H
+#define SPACEELEMENT_H
+
+#include <qfont.h>
+#include <qstring.h>
+
+#include "basicelement.h"
+
+class SymbolTable;
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+/**
+ * A element that represents a space.
+ */
+class SpaceElement : public BasicElement {
+ enum LineBreakType {
+ NoBreakType,
+ AutoBreak,
+ NewLineBreak,
+ IndentingNewLineBreak,
+ NoBreak,
+ GoodBreak,
+ BadBreak
+ };
+ SpaceElement operator=( const SpaceElement& ) { return *this; }
+public:
+
+ SpaceElement( SpaceWidth space = THIN, bool tab=false, BasicElement* parent = 0 );
+ SpaceElement( const SpaceElement& );
+
+ virtual SpaceElement* clone() {
+ return new SpaceElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns the type of this element. Used for
+ * parsing a sequence.
+ */
+ //virtual TokenType getTokenType() const;
+
+ /**
+ * @returns the character that represents this element. Used for
+ * parsing a sequence.
+ */
+ virtual QChar getCharacter() const { return ' '; }
+
+ // drawing
+ //
+ // Drawing depends on a conspace which knows the required properties like
+ // fonts, spaces and such.
+ // It is essential to calculate elements size with the same conspace
+ // before you draw.
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ //virtual void childWillVanish(FormulaCursor*, BasicElement*) {}
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+protected:
+
+ //Save/load support
+
+ /**
+ * @returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "SPACE"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ /**
+ * Reads our attributes from the MathML element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+
+private:
+
+ virtual QString getElementName() const { return "mspace"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+
+ /**
+ * Whether this space behaves like a tab.
+ */
+ bool m_tab;
+
+ // MathML Attributes, Section 3.2.7.2
+ SizeType m_widthType;
+ double m_width;
+ SizeType m_heightType;
+ double m_height;
+ SizeType m_depthType;
+ double m_depth;
+ LineBreakType m_lineBreak;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // SPACEELEMENT_H
diff --git a/lib/kformula/stringelement.cc b/lib/kformula/stringelement.cc
new file mode 100644
index 00000000..8e7b54c4
--- /dev/null
+++ b/lib/kformula/stringelement.cc
@@ -0,0 +1,88 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "textelement.h"
+#include "stringelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+StringElement::StringElement( BasicElement* parent ) : TokenElement( parent )
+{
+}
+
+bool StringElement::readAttributesFromMathMLDom(const QDomElement& element)
+{
+ if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ if ( ! inherited::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ m_lquote = element.attribute( "lquote" );
+ if ( ! m_lquote.isNull() ) {
+ m_customLquote = true;
+ }
+ m_rquote = element.attribute( "rquote" );
+ if ( ! m_rquote.isNull() ) {
+ m_customRquote = true;
+ }
+
+ return true;
+}
+
+int StringElement::buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n)
+{
+ int count = inherited::buildChildrenFromMathMLDom( list, n );
+ if ( count == -1 )
+ return -1;
+ TextElement* child = new TextElement( '"' );
+ child->setParent( this );
+ child->setCharFamily( charFamily() );
+ child->setCharStyle( charStyle() );
+ insert( 0, child );
+ child = new TextElement( '"' );
+ child->setParent( this );
+ child->setCharFamily( charFamily() );
+ child->setCharStyle( charStyle() );
+ insert( countChildren(), child );
+ return count;
+}
+
+void StringElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ inherited::writeMathMLAttributes( element );
+ if ( m_customLquote ) {
+ element.setAttribute( "lquote", m_lquote );
+ }
+ if ( m_customRquote ) {
+ element.setAttribute( "rquote", m_rquote );
+ }
+}
+
+void StringElement::writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const
+{
+ for ( uint i = 1; i < countChildren() - 1; ++i ) {
+ const BasicElement* e = getChild( i );
+ e->writeMathML( doc, element, oasisFormat );
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/stringelement.h b/lib/kformula/stringelement.h
new file mode 100644
index 00000000..e3542204
--- /dev/null
+++ b/lib/kformula/stringelement.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef STRINGELEMENT_H
+#define STRINGELEMENT_H
+
+#include "tokenelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class StringElement : public TokenElement {
+ typedef TokenElement inherited;
+public:
+ StringElement( BasicElement* parent = 0 );
+ virtual int buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n);
+
+protected:
+ virtual bool readAttributesFromMathMLDom(const QDomElement& element);
+
+private:
+ virtual QString getElementName() const { return "ms"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+ virtual void writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const ;
+
+ QString m_lquote;
+ QString m_rquote;
+ bool m_customLquote;
+ bool m_customRquote;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // STRINGELEMENT_H
diff --git a/lib/kformula/styleelement.cc b/lib/kformula/styleelement.cc
new file mode 100644
index 00000000..8475a1da
--- /dev/null
+++ b/lib/kformula/styleelement.cc
@@ -0,0 +1,390 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 "basicelement.h"
+#include "styleelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+StyleElement::StyleElement( BasicElement* parent ) : TokenStyleElement( parent ),
+ m_scriptMinSizeType( NoSize ),
+ m_veryVeryThinMathSpaceType( NoSize ),
+ m_veryThinMathSpaceType( NoSize ),
+ m_thinMathSpaceType( NoSize ),
+ m_mediumMathSpaceType( NoSize ),
+ m_thickMathSpaceType( NoSize ),
+ m_veryThickMathSpaceType( NoSize ),
+ m_veryVeryThickMathSpaceType( NoSize ),
+ m_customScriptLevel( false ),
+ m_relativeScriptLevel( false ),
+ m_customDisplayStyle( false ),
+ m_customScriptSizeMultiplier( false ),
+ m_customBackground( false )
+{
+}
+
+bool StyleElement::readAttributesFromMathMLDom( const QDomElement& element )
+{
+ if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ QString scriptlevelStr = element.attribute( "scriptlevel" );
+ if ( ! scriptlevelStr.isNull() ) {
+ if ( scriptlevelStr[0] == '+' || scriptlevelStr[0] == '-' ) {
+ m_relativeScriptLevel = true;
+ }
+ bool ok;
+ m_scriptLevel = scriptlevelStr.toInt( &ok );
+ if ( ! ok ) {
+ kdWarning( DEBUGID ) << "Invalid scriptlevel attribute value: "
+ << scriptlevelStr << endl;
+ }
+ else {
+ m_customScriptLevel = true;
+ }
+ }
+ QString displaystyleStr = element.attribute( "displaystyle" );
+ if ( ! displaystyleStr.isNull() ) {
+ if ( displaystyleStr.lower() == "true" ) {
+ m_displayStyle = true;
+ }
+ else {
+ m_displayStyle = false;
+ }
+ m_customDisplayStyle = true;
+ }
+ QString scriptsizemultiplierStr = element.attribute( "scriptsizemultiplier" );
+ if ( ! scriptsizemultiplierStr.isNull() ) {
+ bool ok;
+ m_scriptSizeMultiplier = scriptsizemultiplierStr.toDouble( &ok );
+ if ( ! ok ) {
+ kdWarning( DEBUGID ) << "Invalid scriptsizemultiplier attribute value: "
+ << scriptsizemultiplierStr << endl;
+ }
+ else {
+ m_customScriptSizeMultiplier = true;
+ }
+ }
+ QString scriptminsizeStr = element.attribute( "scriptminsize" );
+ if ( ! scriptminsizeStr.isNull() ) {
+ readSizeAttribute( scriptminsizeStr, &m_scriptMinSizeType, &m_scriptMinSize );
+ }
+ QString backgroundStr = element.attribute( "background" );
+ if ( ! backgroundStr.isNull() ) {
+ // TODO: tranparent background
+ m_customBackground = true;
+ if ( backgroundStr[0] != '#' ) {
+ m_background = QColor( getHtmlColor( backgroundStr ) );
+ }
+ else {
+ m_background = QColor( backgroundStr );
+ }
+ }
+ QString veryverythinmathspaceStr = element.attribute( "veryverythinmathspace" );
+ if ( ! veryverythinmathspaceStr.isNull() ) {
+ readSizeAttribute( veryverythinmathspaceStr, &m_veryVeryThinMathSpaceType, &m_veryVeryThinMathSpace );
+ }
+ QString verythinmathspaceStr = element.attribute( "verythinmathspace" );
+ if ( ! verythinmathspaceStr.isNull() ) {
+ readSizeAttribute( verythinmathspaceStr, &m_veryThinMathSpaceType, &m_veryThinMathSpace );
+ }
+ QString thinmathspaceStr = element.attribute( "thinmathspace" );
+ if ( ! thinmathspaceStr.isNull() ) {
+ readSizeAttribute( thinmathspaceStr, &m_thinMathSpaceType, &m_thinMathSpace );
+ }
+ QString mediummathspaceStr = element.attribute( "mediummathspace" );
+ if ( ! mediummathspaceStr.isNull() ) {
+ readSizeAttribute( mediummathspaceStr, &m_mediumMathSpaceType, &m_mediumMathSpace );
+ }
+ QString thickmathspaceStr = element.attribute( "thickmathspace" );
+ if ( ! thickmathspaceStr.isNull() ) {
+ readSizeAttribute( thickmathspaceStr, &m_thickMathSpaceType, &m_thickMathSpace );
+ }
+ QString verythickmathspaceStr = element.attribute( "verythickmathspace" );
+ if ( ! verythickmathspaceStr.isNull() ) {
+ readSizeAttribute( verythickmathspaceStr, &m_veryThickMathSpaceType, &m_veryThickMathSpace );
+ }
+ QString veryverythickmathspaceStr = element.attribute( "veryverythickmathspace" );
+ if ( ! veryverythickmathspaceStr.isNull() ) {
+ readSizeAttribute( veryverythickmathspaceStr, &m_veryVeryThickMathSpaceType, &m_veryVeryThickMathSpace );
+ }
+ return inherited::readAttributesFromMathMLDom( element );
+}
+
+void StyleElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ if ( m_customScriptLevel ) {
+ QString prefix;
+ if ( m_relativeScriptLevel && m_scriptLevel >= 0 ) {
+ prefix = "+";
+ }
+ element.setAttribute( "scriptlevel", prefix + QString( "%1" ).arg( m_scriptLevel ) );
+ }
+ if ( m_customDisplayStyle ) {
+ element.setAttribute( "displaystyle", m_displayStyle ? "true" : "false" );
+ }
+ if ( m_customScriptSizeMultiplier ) {
+ element.setAttribute( "scriptsizemultiplier", QString( "%1" ).arg( m_scriptSizeMultiplier ) );
+ }
+ writeSizeAttribute( element, "scriptminsize", m_scriptMinSizeType, m_scriptMinSize );
+ if ( m_customBackground ) {
+ element.setAttribute( "background", m_background.name() );
+ }
+ writeSizeAttribute( element, "veryverythinmathspace", m_veryVeryThinMathSpaceType, m_veryVeryThinMathSpace );
+ writeSizeAttribute( element, "verythinmathspace", m_veryThinMathSpaceType, m_veryThinMathSpace );
+ writeSizeAttribute( element, "thinmathspace", m_thinMathSpaceType, m_thinMathSpace );
+ writeSizeAttribute( element, "mediummathspace", m_mediumMathSpaceType, m_mediumMathSpace );
+ writeSizeAttribute( element, "thickmathspace", m_thickMathSpaceType, m_thickMathSpace );
+ writeSizeAttribute( element, "verythickmathspace", m_veryThickMathSpaceType, m_veryThickMathSpace );
+ writeSizeAttribute( element, "veryverythickmathspace", m_veryVeryThickMathSpaceType, m_veryVeryThickMathSpace );
+
+ inherited::writeMathMLAttributes( element );
+}
+
+
+void StyleElement::setStyleSize( const ContextStyle& context, StyleAttributes& style )
+{
+ if ( m_customScriptLevel ) {
+ if ( m_relativeScriptLevel ) {
+ style.setScriptLevel( style.scriptLevel() + m_scriptLevel );
+ }
+ else {
+ style.setScriptLevel( m_scriptLevel );
+ }
+ }
+ else {
+ style.setScriptLevel( style.scriptLevel() );
+ }
+ if ( m_customDisplayStyle || style.customDisplayStyle() ) {
+ style.setCustomDisplayStyle( true );
+ if ( m_customDisplayStyle ) {
+ style.setDisplayStyle( m_displayStyle );
+ }
+ else {
+ style.setDisplayStyle( style.displayStyle() );
+ }
+ }
+ else {
+ style.setCustomDisplayStyle( false );
+ }
+ if ( m_customScriptSizeMultiplier ) {
+ style.setScriptSizeMultiplier( m_scriptSizeMultiplier );
+ }
+ else {
+ style.setScriptSizeMultiplier( style.scriptSizeMultiplier() );
+ }
+
+ // Get scriptminsize attribute in absolute units, so we don't depend on
+ // context to get the default value
+ double basesize = context.layoutUnitPtToPt( context.getBaseSize() );
+ double size = style.scriptMinSize();
+ switch ( m_scriptMinSizeType ) {
+ case AbsoluteSize:
+ size = m_scriptMinSize;
+ case RelativeSize:
+ size = m_scriptMinSize * basesize;
+ case PixelSize:
+ size = context.pixelXToPt( m_scriptMinSize );
+ default:
+ break;
+ }
+ style.setScriptMinSize( size );
+
+ style.setVeryVeryThinMathSpace( sizeFactor( context,
+ m_veryVeryThinMathSpaceType,
+ m_veryVeryThinMathSpace,
+ style.veryVeryThinMathSpace() ));
+ style.setVeryThinMathSpace( sizeFactor( context, m_veryThinMathSpaceType,
+ m_veryThinMathSpace,
+ style.veryThinMathSpace() ));
+ style.setThinMathSpace( sizeFactor( context, m_thinMathSpaceType,
+ m_thinMathSpace,
+ style.thinMathSpace() ));
+ style.setMediumMathSpace( sizeFactor( context, m_mediumMathSpaceType,
+ m_mediumMathSpace,
+ style.mediumMathSpace() ));
+ style.setThickMathSpace( sizeFactor( context, m_thickMathSpaceType,
+ m_thickMathSpace,
+ style.thickMathSpace() ));
+ style.setVeryThickMathSpace( sizeFactor( context, m_veryThickMathSpaceType,
+ m_veryThickMathSpace,
+ style.veryThickMathSpace() ));
+ style.setVeryVeryThickMathSpace( sizeFactor( context,
+ m_veryVeryThickMathSpaceType,
+ m_veryVeryThickMathSpace,
+ style.veryVeryThickMathSpace() ));
+ inherited::setStyleSize( context, style );
+}
+
+double StyleElement::sizeFactor( const ContextStyle& context, SizeType st,
+ double length, double defvalue )
+{
+ double basesize = context.layoutUnitPtToPt( context.getBaseSize() );
+ switch ( st ) {
+ case AbsoluteSize:
+ return length / basesize;
+ case RelativeSize:
+ return length;
+ case PixelSize:
+ return context.pixelXToPt( length ) / basesize;
+ default:
+ break;
+ }
+ return defvalue;
+}
+
+void StyleElement::setStyleVariant( StyleAttributes& style )
+{
+ if ( customMathVariant() ) {
+ style.setCustomMathVariant ( true );
+ style.setCustomFontWeight( false );
+ style.setCustomFontStyle( false );
+ style.setCustomFont( false );
+ if ( customMathVariant() ) {
+ style.setCharFamily ( charFamily() );
+ style.setCharStyle( charStyle() );
+ }
+ else {
+ style.setCharFamily( style.charFamily() );
+ style.setCharStyle( style.charStyle() );
+ }
+ }
+ else {
+ style.setCustomMathVariant( false );
+ if ( customFontFamily() ) {
+ style.setCustomFont( true );
+ style.setFont( QFont(fontFamily()) );
+ }
+
+ bool fontweight = false;
+ if ( customFontWeight() || style.customFontWeight() ) {
+ style.setCustomFontWeight( true );
+ if ( customFontWeight() ) {
+ fontweight = fontWeight();
+ }
+ else {
+ fontweight = style.fontWeight();
+ }
+ style.setFontWeight( fontweight );
+ }
+ else {
+ style.setCustomFontWeight( false );
+ }
+
+ bool fontstyle = false;
+ if ( customFontStyle() || style.customFontStyle() ) {
+ style.setCustomFontStyle( true );
+ if ( customFontStyle() ) {
+ fontstyle = fontStyle();
+ }
+ else {
+ fontstyle = style.fontStyle();
+ }
+ style.setFontStyle( fontstyle );
+ }
+ else {
+ style.setCustomFontStyle( false );
+ }
+
+ if ( fontweight && fontstyle ) {
+ style.setCharStyle( boldItalicChar );
+ }
+ else if ( fontweight && ! fontstyle ) {
+ style.setCharStyle( boldChar );
+ }
+ else if ( ! fontweight && fontstyle ) {
+ style.setCharStyle( italicChar );
+ }
+ else {
+ style.setCharStyle( normalChar );
+ }
+ }
+}
+
+void StyleElement::setStyleBackground( StyleAttributes& style )
+{
+ if ( customMathBackground() ) {
+ style.setBackground( mathBackground() );
+ }
+ else if ( m_customBackground ) {
+ style.setBackground( m_background );
+ }
+ else {
+ style.setBackground( style.background() );
+ }
+}
+
+void StyleElement::resetStyle( StyleAttributes& style )
+{
+ inherited::resetStyle( style );
+ style.resetScriptLevel();
+ style.resetScriptSizeMultiplier();
+ style.resetScriptMinSize();
+ style.resetVeryVeryThinMathSpace();
+ style.resetVeryThinMathSpace();
+ style.resetThinMathSpace();
+ style.resetMediumMathSpace();
+ style.resetThickMathSpace();
+ style.resetVeryThickMathSpace();
+ style.resetVeryVeryThickMathSpace();
+ style.resetDisplayStyle();
+}
+
+void StyleElement::readSizeAttribute( const QString& str, SizeType* st, double* s )
+{
+ if ( st == 0 || s == 0 ){
+ return;
+ }
+ if ( str == "small" ) {
+ *st = RelativeSize;
+ *s = 0.8; // ### Arbitrary size
+ }
+ else if ( str == "normal" ) {
+ *st = RelativeSize;
+ *s = 1.0;
+ }
+ else if ( str == "big" ) {
+ *st = RelativeSize;
+ *s = 1.2; // ### Arbitrary size
+ }
+ else {
+ *s = getSize( str, st );
+ }
+}
+
+void StyleElement::writeSizeAttribute( QDomElement element, const QString& str, SizeType st, double s ) const
+{
+ switch ( st ) {
+ case AbsoluteSize:
+ element.setAttribute( str, QString( "%1pt" ).arg( s ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( str, QString( "%1%" ).arg( s * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( str, QString( "%1px" ).arg( s ) );
+ break;
+ default:
+ break;
+ }
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/styleelement.h b/lib/kformula/styleelement.h
new file mode 100644
index 00000000..b497a241
--- /dev/null
+++ b/lib/kformula/styleelement.h
@@ -0,0 +1,81 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef STYLEELEMENT_H
+#define STYLEELEMENT_H
+
+#include "kformuladefs.h"
+#include "tokenstyleelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class StyleElement : public TokenStyleElement {
+ typedef TokenStyleElement inherited;
+public:
+
+ StyleElement( BasicElement* parent = 0 );
+
+protected:
+
+ virtual bool readAttributesFromMathMLDom( const QDomElement &element );
+
+ virtual void setStyleSize( const ContextStyle& context, StyleAttributes& style );
+ virtual void setStyleVariant( StyleAttributes& style );
+ virtual void setStyleBackground( StyleAttributes& style );
+ virtual void resetStyle( StyleAttributes& style );
+
+private:
+ virtual QString getElementName() const { return "mstyle"; }
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+
+ void readSizeAttribute( const QString& str, SizeType* st, double* s );
+ void writeSizeAttribute( QDomElement element, const QString& str, SizeType st, double s ) const ;
+
+ double sizeFactor( const ContextStyle& context, SizeType st, double length, double defvalue );
+
+ int m_scriptLevel;
+ SizeType m_scriptMinSizeType;
+ double m_scriptSizeMultiplier;
+ double m_scriptMinSize;
+ QColor m_background;
+ SizeType m_veryVeryThinMathSpaceType;
+ double m_veryVeryThinMathSpace;
+ SizeType m_veryThinMathSpaceType;
+ double m_veryThinMathSpace;
+ SizeType m_thinMathSpaceType;
+ double m_thinMathSpace;
+ SizeType m_mediumMathSpaceType;
+ double m_mediumMathSpace;
+ SizeType m_thickMathSpaceType;
+ double m_thickMathSpace;
+ SizeType m_veryThickMathSpaceType;
+ double m_veryThickMathSpace;
+ SizeType m_veryVeryThickMathSpaceType;
+ double m_veryVeryThickMathSpace;
+ bool m_displayStyle;
+ bool m_customScriptLevel;
+ bool m_relativeScriptLevel;
+ bool m_customDisplayStyle;
+ bool m_customScriptSizeMultiplier;
+ bool m_customBackground;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // TOKENSTYLEELEMENT_H
diff --git a/lib/kformula/symbolaction.cc b/lib/kformula/symbolaction.cc
new file mode 100644
index 00000000..7939f231
--- /dev/null
+++ b/lib/kformula/symbolaction.cc
@@ -0,0 +1,174 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Heinrich Kuettler <heinrich.kuettler@gmx.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 <qlistbox.h>
+#include <qpainter.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kglobalsettings.h>
+#include <ktoolbar.h>
+#include <kdebug.h>
+
+#include "symbolaction.h"
+
+/*
+ * The items for the SymbolCombos. *
+ */
+
+KFORMULA_NAMESPACE_BEGIN
+
+class SymbolComboItem : public QListBoxItem
+{
+public:
+ SymbolComboItem( const QString&, const QFont& , QChar, QComboBox* combo );
+ virtual ~SymbolComboItem();
+
+ virtual int width( const QListBox* ) const;
+ virtual int height( const QListBox* ) const;
+
+protected:
+ virtual void paint( QPainter *p );
+
+private:
+ QComboBox *m_combo;
+ QString m_name;
+ QFont m_font;
+ QChar m_symbol;
+
+ static int widest;
+};
+
+int SymbolComboItem::widest = 0;
+
+SymbolComboItem::SymbolComboItem( const QString &name, const QFont& font,
+ QChar symbol, QComboBox *combo )
+ : QListBoxItem( combo->listBox() ),
+ m_combo( combo ),
+ m_name( name ),
+ m_font( font ),
+ m_symbol( symbol )
+{
+ setText( name );
+ int charWidth = QFontMetrics( m_font ).width( QChar( m_symbol ) );
+ widest = QMAX( widest, charWidth );
+}
+
+SymbolComboItem::~SymbolComboItem()
+{
+}
+
+int SymbolComboItem::width( const QListBox * /*lb*/ ) const
+{
+ return widest + QFontMetrics( KGlobalSettings::generalFont() ).width( text() ) + 12;
+}
+
+int SymbolComboItem::height( const QListBox * /*lb*/ ) const
+{
+ int generalHeight = QFontMetrics( KGlobalSettings::generalFont() ).lineSpacing();
+ int fontHeight = QFontMetrics( m_font ).lineSpacing();
+ return QMAX( generalHeight, fontHeight ) + 2;
+}
+
+void SymbolComboItem::paint( QPainter *p )
+{
+ p->setFont( m_font );
+ QFontMetrics fm( p->fontMetrics() );
+ p->drawText( 3, fm.ascent() + fm.leading() / 2,
+ QString( "%1" ).arg( QChar( m_symbol ) ) );
+
+ p->setFont( KGlobalSettings::generalFont() );
+ fm = p->fontMetrics();
+ p->drawText( widest + 6, height( m_combo->listBox() ) / 2 + fm.strikeOutPos(), m_name );
+}
+
+/*
+ * The symbol action *
+ */
+SymbolAction::SymbolAction( QObject* parent, const char* name )
+ : KSelectAction( parent, name )
+{
+ setEditable( FALSE );
+}
+
+SymbolAction::SymbolAction( const QString& text, const KShortcut& cut,
+ const QObject* receiver, const char* slot,
+ QObject* parent, const char* name )
+ : KSelectAction( text, cut, receiver, slot, parent, name )
+{
+ setEditable( FALSE );
+}
+
+int SymbolAction::plug( QWidget* w, int index )
+{
+ if (kapp && !kapp->authorizeKAction(name()))
+ return -1;
+ if ( w->inherits( "KToolBar" ) )
+ {
+ KToolBar* bar = static_cast<KToolBar*>( w );
+ int id_ = KAction::getToolButtonID();
+ KComboBox *cb = new KComboBox( bar );
+ connect( cb, SIGNAL( activated( const QString & ) ),
+ SLOT( slotActivated( const QString & ) ) );
+ cb->setEnabled( isEnabled() );
+ bar->insertWidget( id_, comboWidth(), cb, index );
+ cb->setMinimumWidth( cb->sizeHint().width() );
+
+ addContainer( bar, id_ );
+
+ connect( bar, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
+
+ updateItems( containerCount() - 1 );
+
+ return containerCount() - 1;
+ }
+ else return KSelectAction::plug( w, index );
+}
+
+void SymbolAction::setSymbols( const QStringList &names,
+ const QFont& font,
+ const QMemArray<QChar>& chars )
+{
+ m_chars = chars;
+ m_font = font;
+ setItems( names );
+
+ int len = containerCount();
+ for ( int i = 0; i < len; ++i )
+ updateItems( i );
+}
+
+void SymbolAction::updateItems( int id )
+{
+ QWidget *w = container( id );
+ if ( w->inherits( "KToolBar" ) ) {
+ QWidget *r = static_cast<KToolBar*>( w )->getWidget( itemId( id ) );
+ if ( r->inherits( "QComboBox" ) ) {
+ QComboBox *cb = static_cast<QComboBox*>( r );
+ cb->clear();
+
+ for( uint i = 0; i < items().count(); ++i ) {
+ new SymbolComboItem( *items().at( i ), m_font, m_chars.at( i ), cb );
+ }
+ cb->setMinimumWidth( cb->sizeHint().width() );
+ }
+ }
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/symbolaction.h b/lib/kformula/symbolaction.h
new file mode 100644
index 00000000..704afa2e
--- /dev/null
+++ b/lib/kformula/symbolaction.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Heinrich Kuettler <heinrich.kuettler@gmx.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.
+*/
+
+#ifndef _SYMBOLACTION_H_
+#define _SYMBOLACTION_H_
+
+#include <kaction.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include <qmemarray.h>
+
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class SymbolAction : public KSelectAction
+{
+public:
+ SymbolAction( QObject* parent = 0, const char* name = 0 );
+ SymbolAction( const QString& text, const KShortcut& cut,
+ const QObject* receiver, const char* slot, QObject* parent,
+ const char* name = 0 );
+
+ int plug( QWidget*, int index = -1 );
+ void setSymbols( const QStringList&, const QFont& font, const QMemArray<QChar>& );
+ void updateItems( int );
+
+private:
+ QValueList<QFont> m_fonts;
+ QMemArray<QChar> m_chars;
+ QFont m_font;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // _SYMBOLACTION_H_
diff --git a/lib/kformula/symbolelement.cc b/lib/kformula/symbolelement.cc
new file mode 100644
index 00000000..49932bee
--- /dev/null
+++ b/lib/kformula/symbolelement.cc
@@ -0,0 +1,906 @@
+/* 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 <qpainter.h>
+
+#include <kdebug.h>
+
+#include "elementvisitor.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "kformulacommand.h"
+#include "sequenceelement.h"
+#include "symbolelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+
+class SymbolSequenceElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ SymbolSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
+
+ /**
+ * This is called by the container to get a command depending on
+ * the current cursor position (this is how the element gets chosen)
+ * and the request.
+ *
+ * @returns the command that performs the requested action with
+ * the containers active cursor.
+ */
+ virtual KCommand* buildCommand( Container*, Request* );
+};
+
+
+KCommand* SymbolSequenceElement::buildCommand( Container* container, Request* request )
+{
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isReadOnly() ) {
+ return 0;
+ }
+
+ switch ( *request ) {
+ case req_addIndex: {
+ FormulaCursor* cursor = container->activeCursor();
+ if ( cursor->isSelection() ||
+ ( cursor->getPos() > 0 && cursor->getPos() < countChildren() ) ) {
+ break;
+ }
+ IndexRequest* ir = static_cast<IndexRequest*>( request );
+ if ( ( ir->index() == upperMiddlePos ) || ( ir->index() == lowerMiddlePos ) ) {
+ SymbolElement* element = static_cast<SymbolElement*>( getParent() );
+ ElementIndexPtr index = element->getIndex( ir->index() );
+ if ( !index->hasIndex() ) {
+ KFCAddGenericIndex* command = new KFCAddGenericIndex( container, index );
+ return command;
+ }
+ else {
+ index->moveToIndex( cursor, afterCursor );
+ cursor->setSelection( false );
+ formula()->cursorHasMoved( cursor );
+ return 0;
+ }
+ }
+ }
+ default:
+ break;
+ }
+ return inherited::buildCommand( container, request );
+}
+
+
+SymbolElement::SymbolElement(SymbolType type, BasicElement* parent)
+ : BasicElement(parent), symbol( 0 ), symbolType( type )
+{
+ content = new SymbolSequenceElement( this );
+ upper = 0;
+ lower = 0;
+}
+
+SymbolElement::~SymbolElement()
+{
+ delete lower;
+ delete upper;
+ delete content;
+ delete symbol;
+}
+
+
+SymbolElement::SymbolElement( const SymbolElement& other )
+ : BasicElement( other ), symbol( 0 ), symbolType( other.symbolType )
+{
+ content = new SymbolSequenceElement( *dynamic_cast<SymbolSequenceElement*>( other.content ) );
+ content->setParent( this );
+
+ if ( other.upper ) {
+ upper = new SequenceElement( *( other.upper ) );
+ upper->setParent( this );
+ }
+ else {
+ upper = 0;
+ }
+ if ( other.lower ) {
+ lower = new SequenceElement( *( other.lower ) );
+ lower->setParent( this );
+ }
+ else {
+ lower = 0;
+ }
+}
+
+
+bool SymbolElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+BasicElement* SymbolElement::goToPos( FormulaCursor* cursor, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
+{
+ BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
+ if (e != 0) {
+ LuPixelPoint myPos(parentOrigin.x() + getX(),
+ parentOrigin.y() + getY());
+
+ e = content->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ if (hasLower()) {
+ e = lower->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ }
+ if (hasUpper()) {
+ e = upper->goToPos(cursor, handled, point, myPos);
+ if (e != 0) {
+ return e;
+ }
+ }
+
+ // the positions after the indexes.
+ luPixel dx = point.x() - myPos.x();
+ luPixel dy = point.y() - myPos.y();
+ if (dy < symbol->getY()) {
+ if (hasUpper() && (dx > upper->getX())) {
+ upper->moveLeft(cursor, this);
+ handled = true;
+ return upper;
+ }
+ }
+ else if (dy > symbol->getY()+symbol->getHeight()) {
+ if (hasLower() && (dx > lower->getX())) {
+ lower->moveLeft(cursor, this);
+ handled = true;
+ return lower;
+ }
+ }
+
+ // Have the cursor jump behind the integral.
+ if ( ( dx < symbol->getX()+symbol->getWidth() ) &&
+ ( dx > symbol->getX()+symbol->getWidth()/2 ) ) {
+ content->moveRight( cursor, this );
+ handled = true;
+ return content;
+ }
+
+ return this;
+ }
+ return 0;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void SymbolElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
+ luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
+
+ //if ( symbol == 0 ) {
+ delete symbol;
+ symbol = context.fontStyle().createArtwork( symbolType );
+ //}
+
+ symbol->calcSizes(context, tstyle, factor, mySize);
+ content->calcSizes( context, tstyle, istyle, style );
+
+ //symbol->scale(((double)parentSize)/symbol->getHeight()*2);
+
+ luPixel upperWidth = 0;
+ luPixel upperHeight = 0;
+ if (hasUpper()) {
+ upper->calcSizes( context, context.convertTextStyleIndex( tstyle ),
+ context.convertIndexStyleUpper( istyle ), style );
+ upperWidth = upper->getWidth();
+ upperHeight = upper->getHeight() + distY;
+ }
+
+ luPixel lowerWidth = 0;
+ luPixel lowerHeight = 0;
+ if (hasLower()) {
+ lower->calcSizes( context, context.convertTextStyleIndex( tstyle ),
+ context.convertIndexStyleLower( istyle ), style );
+ lowerWidth = lower->getWidth();
+ lowerHeight = lower->getHeight() + distY;
+ }
+
+ // widths
+ luPixel xOffset = QMAX(symbol->getWidth(), QMAX(upperWidth, lowerWidth));
+ if (context.getCenterSymbol()) {
+ symbol->setX((xOffset - symbol->getWidth()) / 2);
+ }
+ else {
+ symbol->setX(xOffset - symbol->getWidth());
+ }
+ // ???
+ content->setX(xOffset +
+ static_cast<luPixel>( symbol->slant()*symbol->getHeight()/2 ) +
+ distX/2);
+
+ setWidth(QMAX(content->getX() + content->getWidth(),
+ QMAX(upperWidth, lowerWidth)));
+
+ // heights
+ //int toMidline = QMAX(content->getHeight() / 2,
+ luPixel toMidline = QMAX(content->axis( context, tstyle, factor ),
+ upperHeight + symbol->getHeight()/2);
+ //int fromMidline = QMAX(content->getHeight() / 2,
+ luPixel fromMidline = QMAX(content->getHeight() - content->axis( context, tstyle, factor ),
+ lowerHeight + symbol->getHeight()/2);
+ setHeight(toMidline + fromMidline);
+ //setMidline(toMidline);
+
+ symbol->setY(toMidline - symbol->getHeight()/2);
+ //content->setY(toMidline - content->getHeight()/2);
+ content->setY(toMidline - content->axis( context, tstyle, factor ));
+
+ if (hasUpper()) {
+ luPixel slant =
+ static_cast<luPixel>( symbol->slant()*( symbol->getHeight()+distY ) );
+ if (context.getCenterSymbol()) {
+ upper->setX((xOffset - upperWidth) / 2 + slant );
+ }
+ else {
+ if (upperWidth < symbol->getWidth()) {
+ upper->setX(symbol->getX() +
+ (symbol->getWidth() - upperWidth) / 2 + slant );
+ }
+ else {
+ upper->setX(xOffset - upperWidth);
+ }
+ }
+ upper->setY(toMidline - upperHeight - symbol->getHeight()/2);
+ }
+ if (hasLower()) {
+ luPixel slant = static_cast<luPixel>( -symbol->slant()*distY );
+ if (context.getCenterSymbol()) {
+ lower->setX((xOffset - lowerWidth) / 2 + slant);
+ }
+ else {
+ if (lowerWidth < symbol->getWidth()) {
+ lower->setX(symbol->getX() +
+ (symbol->getWidth() - lowerWidth) / 2 + slant );
+ }
+ else {
+ lower->setX(xOffset - lowerWidth);
+ }
+ }
+ lower->setY(toMidline + symbol->getHeight()/2 + distY);
+ }
+ setBaseline(content->getBaseline() + content->getY());
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void SymbolElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
+ symbol->draw( painter, r, context, tstyle, style, mySize, myPos );
+ content->draw( painter, r, context, tstyle, istyle, style, myPos );
+ if ( hasUpper() ) {
+ upper->draw( painter, r, context, context.convertTextStyleIndex( tstyle ),
+ context.convertIndexStyleUpper( istyle ), style, myPos );
+ }
+ if ( hasLower() ) {
+ lower->draw( painter, r, context, context.convertTextStyleIndex( tstyle ),
+ context.convertIndexStyleLower( istyle ), style, myPos );
+ }
+
+ // Debug
+#if 0
+ painter.setBrush(Qt::NoBrush);
+ painter.setPen(Qt::red);
+// painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
+// context.layoutUnitToPixelY( myPos.y() ),
+// context.layoutUnitToPixelX( getWidth() ),
+// context.layoutUnitToPixelY( getHeight() ) );
+ painter.drawRect( context.layoutUnitToPixelX( myPos.x()+symbol->getX() ),
+ context.layoutUnitToPixelY( myPos.y()+symbol->getY() ),
+ context.layoutUnitToPixelX( symbol->getWidth() ),
+ context.layoutUnitToPixelY( symbol->getHeight() ) );
+ painter.setPen(Qt::green);
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+axis(context, tstyle) ),
+ context.layoutUnitToPixelX( myPos.x()+getWidth() ),
+ context.layoutUnitToPixelY( myPos.y()+axis(context, tstyle) ) );
+#endif
+}
+
+
+void SymbolElement::dispatchFontCommand( FontCommand* cmd )
+{
+ content->dispatchFontCommand( cmd );
+ if ( hasUpper() ) {
+ upper->dispatchFontCommand( cmd );
+ }
+ if ( hasLower() ) {
+ lower->dispatchFontCommand( cmd );
+ }
+}
+
+// navigation
+//
+// The elements are responsible to handle cursor movement themselves.
+// To do this they need to know the direction the cursor moves and
+// the element it comes from.
+//
+// The cursor might be in normal or in selection mode.
+
+/**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+void SymbolElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveLeft(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ content->moveLeft(cursor, this);
+ }
+ else if (from == content) {
+ if (linear && hasLower()) {
+ lower->moveLeft(cursor, this);
+ }
+ else if (linear && hasUpper()) {
+ upper->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+ else if (from == lower) {
+ if (linear && hasUpper()) {
+ upper->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+ else if (from == upper) {
+ getParent()->moveLeft(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+void SymbolElement::moveRight(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveRight(cursor, this);
+ }
+ else {
+ bool linear = cursor->getLinearMovement();
+ if (from == getParent()) {
+ if (linear && hasUpper()) {
+ upper->moveRight(cursor, this);
+ }
+ else if (linear && hasLower()) {
+ lower->moveRight(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+ }
+ else if (from == upper) {
+ if (linear && hasLower()) {
+ lower->moveRight(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+ }
+ else if (from == lower) {
+ content->moveRight(cursor, this);
+ }
+ else if (from == content) {
+ getParent()->moveRight(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+void SymbolElement::moveUp(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveUp(cursor, this);
+ }
+ else {
+ if (from == content) {
+ if (hasUpper()) {
+ upper->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveUp(cursor, this);
+ }
+ }
+ else if (from == upper) {
+ getParent()->moveUp(cursor, this);
+ }
+ else if ((from == getParent()) || (from == lower)) {
+ content->moveRight(cursor, this);
+ }
+ }
+}
+
+/**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+void SymbolElement::moveDown(FormulaCursor* cursor, BasicElement* from)
+{
+ if (cursor->isSelectionMode()) {
+ getParent()->moveDown(cursor, this);
+ }
+ else {
+ if (from == content) {
+ if (hasLower()) {
+ lower->moveLeft(cursor, this);
+ }
+ else {
+ getParent()->moveDown(cursor, this);
+ }
+ }
+ else if (from == lower) {
+ getParent()->moveDown(cursor, this);
+ }
+ else if ((from == getParent()) || (from == upper)) {
+ content->moveRight(cursor, this);
+ }
+ }
+}
+
+// children
+
+// main child
+//
+// If an element has children one has to become the main one.
+
+// void SymbolElement::setMainChild(SequenceElement* child)
+// {
+// formula()->elementRemoval(content);
+// content = child;
+// content->setParent(this);
+// formula()->changed();
+// }
+
+
+/**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction.
+ *
+ * You only can insert one index at a time. So the list must contain
+ * exactly on SequenceElement. And the index you want to insert
+ * must not exist already.
+ *
+ * The list will be emptied but stays the property of the caller.
+ */
+void SymbolElement::insert(FormulaCursor* cursor,
+ QPtrList<BasicElement>& newChildren,
+ Direction direction)
+{
+ SequenceElement* index = static_cast<SequenceElement*>(newChildren.take(0));
+ index->setParent(this);
+
+ switch (cursor->getPos()) {
+ case upperMiddlePos:
+ upper = index;
+ break;
+ case lowerMiddlePos:
+ lower = index;
+ break;
+ default:
+ // this is an error!
+ return;
+ }
+
+ if (direction == beforeCursor) {
+ index->moveLeft(cursor, this);
+ }
+ else {
+ index->moveRight(cursor, this);
+ }
+ cursor->setSelection(false);
+ formula()->changed();
+}
+
+/**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * The cursor has to be inside one of our indexes which is supposed
+ * to be empty. The index will be removed and the cursor will
+ * be placed to the removed index so it can be inserted again.
+ * This methode is called by SequenceElement::remove only.
+ *
+ * The ownership of the list is passed to the caller.
+ */
+void SymbolElement::remove(FormulaCursor* cursor,
+ QPtrList<BasicElement>& removedChildren,
+ Direction direction)
+{
+ int pos = cursor->getPos();
+ switch (pos) {
+ case upperMiddlePos:
+ removedChildren.append(upper);
+ formula()->elementRemoval(upper);
+ upper = 0;
+ setToUpper(cursor);
+ break;
+ case lowerMiddlePos:
+ removedChildren.append(lower);
+ formula()->elementRemoval(lower);
+ lower = 0;
+ setToLower(cursor);
+ break;
+ case contentPos: {
+ BasicElement* parent = getParent();
+ parent->selectChild(cursor, this);
+ parent->remove(cursor, removedChildren, direction);
+ break;
+ }
+ }
+ formula()->changed();
+}
+
+/**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+void SymbolElement::normalize(FormulaCursor* cursor, Direction direction)
+{
+ if (direction == beforeCursor) {
+ content->moveLeft(cursor, this);
+ }
+ else {
+ content->moveRight(cursor, this);
+ }
+}
+
+/**
+ * Returns the child at the cursor.
+ */
+BasicElement* SymbolElement::getChild(FormulaCursor* cursor, Direction)
+{
+ int pos = cursor->getPos();
+ switch (pos) {
+ case contentPos:
+ return content;
+ case upperMiddlePos:
+ return upper;
+ case lowerMiddlePos:
+ return lower;
+ }
+ return 0;
+}
+
+/**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+void SymbolElement::selectChild(FormulaCursor* cursor, BasicElement* child)
+{
+ if (child == content) {
+ setToContent(cursor);
+ }
+ else if (child == upper) {
+ setToUpper(cursor);
+ }
+ else if (child == lower) {
+ setToLower(cursor);
+ }
+}
+
+void SymbolElement::setToUpper(FormulaCursor* cursor)
+{
+ cursor->setTo(this, upperMiddlePos);
+}
+
+void SymbolElement::setToLower(FormulaCursor* cursor)
+{
+ cursor->setTo(this, lowerMiddlePos);
+}
+
+/**
+ * Sets the cursor to point to the place where the content is.
+ * There always is a content so this is not a useful place.
+ * No insertion or removal will succeed as long as the cursor is
+ * there.
+ */
+void SymbolElement::setToContent(FormulaCursor* cursor)
+{
+ cursor->setTo(this, contentPos);
+}
+
+
+void SymbolElement::moveToUpper(FormulaCursor* cursor, Direction direction)
+{
+ if (hasUpper()) {
+ if (direction == beforeCursor) {
+ upper->moveLeft(cursor, this);
+ }
+ else {
+ upper->moveRight(cursor, this);
+ }
+ }
+}
+
+void SymbolElement::moveToLower(FormulaCursor* cursor, Direction direction)
+{
+ if (hasLower()) {
+ if (direction == beforeCursor) {
+ lower->moveLeft(cursor, this);
+ }
+ else {
+ lower->moveRight(cursor, this);
+ }
+ }
+}
+
+
+ElementIndexPtr SymbolElement::getIndex( int position )
+{
+ switch ( position ) {
+ case lowerMiddlePos:
+ return getLowerIndex();
+ case upperMiddlePos:
+ return getUpperIndex();
+ }
+ return getUpperIndex();
+}
+
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void SymbolElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+
+ element.setAttribute("TYPE", symbolType);
+
+ QDomDocument doc = element.ownerDocument();
+
+ QDomElement con = doc.createElement("CONTENT");
+ con.appendChild(content->getElementDom(doc));
+ element.appendChild(con);
+
+ if(hasLower()) {
+ QDomElement ind = doc.createElement("LOWER");
+ ind.appendChild(lower->getElementDom(doc));
+ element.appendChild(ind);
+ }
+ if(hasUpper()) {
+ QDomElement ind = doc.createElement("UPPER");
+ ind.appendChild(upper->getElementDom(doc));
+ element.appendChild(ind);
+ }
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool SymbolElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+
+ QString typeStr = element.attribute("TYPE");
+ if(!typeStr.isNull()) {
+ symbolType = static_cast<SymbolType>(typeStr.toInt());
+ }
+
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool SymbolElement::readContentFromDom(QDomNode& node)
+{
+ if (!BasicElement::readContentFromDom(node)) {
+ return false;
+ }
+
+ if ( !buildChild( content, node, "CONTENT" ) ) {
+ kdWarning( DEBUGID ) << "Empty content in SymbolElement." << endl;
+ return false;
+ }
+ node = node.nextSibling();
+
+ bool lowerRead = false;
+ bool upperRead = false;
+
+ while (!node.isNull() && !(upperRead && lowerRead)) {
+
+ if (!lowerRead && (node.nodeName().upper() == "LOWER")) {
+ lowerRead = buildChild( lower=new SequenceElement( this ), node, "LOWER" );
+ if ( !lowerRead ) return false;
+ }
+
+ if (!upperRead && (node.nodeName().upper() == "UPPER")) {
+ upperRead = buildChild( upper=new SequenceElement( this ), node, "UPPER" );
+ if ( !upperRead ) return false;
+ }
+
+ node = node.nextSibling();
+ }
+ return true;
+}
+
+QString SymbolElement::toLatex()
+{
+ QString sym;
+
+ switch(symbolType) {
+
+ case 1001:
+ sym="\\int";
+ break;
+ case 1002:
+ sym="\\sum";
+ break;
+ case 1003:
+ sym="\\prod";
+ break;
+
+ default:
+ sym=" ";
+
+ }
+
+
+ if(hasLower()) {
+ sym+="_{";
+ sym+=lower->toLatex();
+ sym+="}";
+ }
+
+ if(hasUpper()) {
+ sym+="^{";
+ sym+=upper->toLatex();
+ sym+="} ";
+ }
+
+ sym += " ";
+
+ sym+=content->toLatex();
+
+
+ return sym;
+}
+
+QString SymbolElement::formulaString()
+{
+ QString sym;
+ switch ( symbolType ) {
+ case 1001:
+ sym="int(";
+ break;
+ case 1002:
+ sym="sum(";
+ break;
+ case 1003:
+ sym="prod(";
+ break;
+ default:
+ sym="(";
+ }
+ sym += content->formulaString();
+ if ( hasLower() ) {
+ sym += ", " + lower->formulaString();
+ }
+ if ( hasUpper() ) {
+ sym += ", " + upper->formulaString();
+ }
+ return sym + ")";
+}
+
+void SymbolElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
+{
+ QDomElement de = doc.createElement( oasisFormat ? "math:mrow" : "mrow" );
+ QDomElement mo = doc.createElement( oasisFormat ? "math:mo" : "mo" );
+
+ QString value;
+
+ switch( symbolType )
+ {
+ case EmptyBracket: break;
+ case LeftLineBracket: case RightLineBracket:
+ mo.appendChild( doc.createTextNode( "|" ) ); break;
+ case Integral:
+ mo.appendChild( doc.createEntityReference( "int" ) ); break;
+ case Sum:
+ mo.appendChild( doc.createEntityReference( "sum" ) ); break;
+ case Product:
+ mo.appendChild( doc.createEntityReference( "prod" ) ); break;
+ default:
+ mo.appendChild( doc.createTextNode( QChar( symbolType ) ) );
+ }
+
+ QDomElement between;
+ if ( hasUpper() && hasLower() )
+ {
+ between = doc.createElement( oasisFormat ? "math:msubsup" : "msubsup" );
+ between.appendChild( mo );
+ lower->writeMathML( doc, between, oasisFormat );
+ upper->writeMathML( doc, between, oasisFormat );
+ }
+ else if ( hasUpper() )
+ {
+ between = doc.createElement( oasisFormat ? "math:msup" : "msup" );
+ between.appendChild( mo );
+ upper->writeMathML( doc, between, oasisFormat );
+ }
+ else if ( hasLower() )
+ {
+ between = doc.createElement( oasisFormat ? "math:msub" : "msub" );
+ between.appendChild( mo );
+ lower->writeMathML( doc, between, oasisFormat );
+ }
+ else
+ between = mo;
+
+ de.appendChild( between );
+ content->writeMathML( doc, de, oasisFormat );
+
+ parent.appendChild( de );
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/symbolelement.h b/lib/kformula/symbolelement.h
new file mode 100644
index 00000000..cb908034
--- /dev/null
+++ b/lib/kformula/symbolelement.h
@@ -0,0 +1,313 @@
+/* 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.
+*/
+
+#ifndef SYMBOLELEMENT_H
+#define SYMBOLELEMENT_H
+
+#include "fontstyle.h"
+#include "basicelement.h"
+#include "kformuladefs.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+/**
+ * A symbol is simply a piece of art.
+ */
+class SymbolElement : public BasicElement {
+ SymbolElement operator=( const SymbolElement& ) { return *this; }
+public:
+
+ //enum { contentPos, upperPos, lowerPos };
+
+ SymbolElement(SymbolType type = EmptyBracket, BasicElement* parent = 0);
+ ~SymbolElement();
+
+ SymbolElement( const SymbolElement& );
+
+ virtual SymbolElement* clone() {
+ return new SymbolElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * Sets the cursor and returns the element the point is in.
+ * The handled flag shows whether the cursor has been set.
+ * This is needed because only the innermost matching element
+ * is allowed to set the cursor.
+ */
+ virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
+ const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
+
+ // drawing
+ //
+ // Drawing depends on a context which knows the required properties like
+ // fonts, spaces and such.
+ // It is essential to calculate elements size with the same context
+ // before you draw.
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ // navigation
+ //
+ // The elements are responsible to handle cursor movement themselves.
+ // To do this they need to know the direction the cursor moves and
+ // the element it comes from.
+ //
+ // The cursor might be in normal or in selection mode.
+
+ /**
+ * Enters this element while moving to the left starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the left of it.
+ */
+ virtual void moveLeft(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving to the right starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or to the right of it.
+ */
+ virtual void moveRight(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving up starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or above it.
+ */
+ virtual void moveUp(FormulaCursor* cursor, BasicElement* from);
+
+ /**
+ * Enters this element while moving down starting inside
+ * the element `from'. Searches for a cursor position inside
+ * this element or below it.
+ */
+ virtual void moveDown(FormulaCursor* cursor, BasicElement* from);
+
+ // children
+
+ /**
+ * Removes the child. If this was the main child this element might
+ * request its own removal.
+ * The cursor is the one that caused the removal. It has to be moved
+ * to the place any user expects the cursor after that particular
+ * element has been removed.
+ */
+ //virtual void removeChild(FormulaCursor* cursor, BasicElement* child);
+
+
+ // main child
+ //
+ // If an element has children one has to become the main one.
+
+ virtual SequenceElement* getMainChild() { return content; }
+ //virtual void setMainChild(SequenceElement*);
+
+
+ /**
+ * Inserts all new children at the cursor position. Places the
+ * cursor according to the direction.
+ *
+ * You only can insert one index at a time. So the list must contain
+ * exactly on SequenceElement. And the index you want to insert
+ * must not exist already.
+ *
+ * The list will be emptied but stays the property of the caller.
+ */
+ virtual void insert(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Removes all selected children and returns them. Places the
+ * cursor to where the children have been.
+ *
+ * The cursor has to be inside one of our indexes which is supposed
+ * to be empty. The index will be removed and the cursor will
+ * be placed to the removed index so it can be inserted again.
+ * This methode is called by SequenceElement::remove only.
+ *
+ * The ownership of the list is passed to the caller.
+ */
+ virtual void remove(FormulaCursor*, QPtrList<BasicElement>&, Direction);
+
+ /**
+ * Moves the cursor to a normal place where new elements
+ * might be inserted.
+ */
+ virtual void normalize(FormulaCursor*, Direction);
+
+ /**
+ * Returns the child at the cursor.
+ */
+ virtual BasicElement* getChild(FormulaCursor*, Direction = beforeCursor);
+
+ /**
+ * Sets the cursor to select the child. The mark is placed before,
+ * the position behind it.
+ */
+ virtual void selectChild(FormulaCursor* cursor, BasicElement* child);
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ //virtual void childWillVanish(FormulaCursor* cursor, BasicElement* child) = 0;
+
+ bool hasUpper() const { return upper != 0; }
+ bool hasLower() const { return lower != 0; }
+
+ // If we want to create an index we need a cursor that points there.
+
+ void setToUpper(FormulaCursor* cursor);
+ void setToLower(FormulaCursor* cursor);
+
+ // Moves the cursor inside the index. The index has to exist.
+ void moveToUpper(FormulaCursor*, Direction);
+ void moveToLower(FormulaCursor*, Direction);
+
+ // Generic access to each index.
+
+ ElementIndexPtr getUpperIndex() { return ElementIndexPtr( new UpperIndex( this ) ); }
+ ElementIndexPtr getLowerIndex() { return ElementIndexPtr( new LowerIndex( this ) ); }
+
+ /**
+ * Returns the index at the position. Defaults to upperRight.
+ */
+ ElementIndexPtr getIndex( int position );
+
+ // Save&load
+ //virtual QDomElement getElementDom(QDomDocument *doc);
+ //virtual bool buildFromDom(QDomElement *elem);
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
+
+protected:
+
+ //Save/load support
+
+ /**
+ * Returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "SYMBOL"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+private:
+
+ /**
+ * An index that belongs to us.
+ */
+ class SymbolElementIndex : public ElementIndex {
+ public:
+ SymbolElementIndex(SymbolElement* p) : parent(p) {}
+ virtual SymbolElement* getElement() { return parent; }
+ protected:
+ SymbolElement* parent;
+ };
+
+ // We have a (very simple) type for every index.
+
+ class UpperIndex : public SymbolElementIndex {
+ public:
+ UpperIndex(SymbolElement* parent) : SymbolElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToUpper(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToUpper(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasUpper(); }
+ };
+
+ class LowerIndex : public SymbolElementIndex {
+ public:
+ LowerIndex(SymbolElement* parent) : SymbolElementIndex(parent) {}
+ virtual void moveToIndex(FormulaCursor* cursor, Direction direction)
+ { parent->moveToLower(cursor, direction); }
+ virtual void setToIndex(FormulaCursor* cursor)
+ { parent->setToLower(cursor); }
+ virtual bool hasIndex() const
+ { return parent->hasLower(); }
+ };
+
+
+ void setToContent(FormulaCursor* cursor);
+
+ SequenceElement* content;
+ SequenceElement* upper;
+ SequenceElement* lower;
+
+ /**
+ * Our symbol.
+ */
+ Artwork* symbol;
+
+ SymbolType symbolType;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // SYMBOLELEMENT_H
diff --git a/lib/kformula/symbolfontmapping.cc b/lib/kformula/symbolfontmapping.cc
new file mode 100644
index 00000000..71fbfcb0
--- /dev/null
+++ b/lib/kformula/symbolfontmapping.cc
@@ -0,0 +1,171 @@
+//
+// Created: Thu May 29 14:40:54 2003
+// by: gensymbolfontmap.py
+// from: symbol.xml
+//
+// WARNING! All changes made in this file will be lost!
+
+
+
+static InternFontTable symbolMap[] = {
+ { 0x2208, 0xce, RELATION, normalChar },
+ { 0x2209, 0xcf, RELATION, normalChar },
+ { 0x2202, 0xb6, ORDINARY, normalChar },
+ { 0x2203, 0x24, ORDINARY, normalChar },
+ { 0x2200, 0x22, ORDINARY, normalChar },
+ { 0x2207, 0xd1, ORDINARY, normalChar },
+ { 0x2205, 0xc6, BINOP, normalChar },
+ { 0x220D, 0x27, RELATION, normalChar },
+ { 0x007C, 0x7c, ORDINARY, normalChar },
+ { 0x007B, 0x7b, ORDINARY, normalChar },
+ { 0x007D, 0x7d, ORDINARY, normalChar },
+ { 0x00B0, 0xb0, ORDINARY, normalChar },
+ { 0x00B1, 0xb1, BINOP, normalChar },
+ { 0x2033, 0xb2, ORDINARY, normalChar },
+ { 0x2032, 0xa2, ORDINARY, normalChar },
+ { 0x03BE, 0x78, ORDINARY, normalChar },
+ { 0x03BD, 0x6e, ORDINARY, normalChar },
+ { 0x03BC, 0x6d, ORDINARY, normalChar },
+ { 0x03BB, 0x6c, ORDINARY, normalChar },
+ { 0x03BA, 0x6b, ORDINARY, normalChar },
+ { 0x2329, 0xe1, ORDINARY, normalChar },
+ { 0x2321, 0xf5, ORDINARY, normalChar },
+ { 0x2320, 0xf3, ORDINARY, normalChar },
+ { 0x232A, 0xf1, ORDINARY, normalChar },
+ { 0x03B9, 0x69, ORDINARY, normalChar },
+ { 0x03B8, 0x71, ORDINARY, normalChar },
+ { 0x03B7, 0x68, ORDINARY, normalChar },
+ { 0x03B6, 0x7a, ORDINARY, normalChar },
+ { 0x03B5, 0x65, ORDINARY, normalChar },
+ { 0x03B4, 0x64, ORDINARY, normalChar },
+ { 0x03B3, 0x67, ORDINARY, normalChar },
+ { 0x03B2, 0x62, ORDINARY, normalChar },
+ { 0x03B1, 0x61, ORDINARY, normalChar },
+ { 0x00F7, 0xb8, BINOP, normalChar },
+ { 0x039F, 0x4f, ORDINARY, normalChar },
+ { 0x039D, 0x4e, ORDINARY, normalChar },
+ { 0x039E, 0x58, ORDINARY, normalChar },
+ { 0x039B, 0x4c, ORDINARY, normalChar },
+ { 0x039C, 0x4d, ORDINARY, normalChar },
+ { 0x039A, 0x4b, ORDINARY, normalChar },
+ { 0x0192, 0xa6, ORDINARY, normalChar },
+ { 0x0398, 0x51, ORDINARY, normalChar },
+ { 0x0399, 0x49, ORDINARY, normalChar },
+ { 0x0396, 0x5a, ORDINARY, normalChar },
+ { 0x0397, 0x48, ORDINARY, normalChar },
+ { 0x0394, 0x44, ORDINARY, normalChar },
+ { 0x0395, 0x45, ORDINARY, normalChar },
+ { 0x0392, 0x42, ORDINARY, normalChar },
+ { 0x0393, 0x47, ORDINARY, normalChar },
+ { 0x0391, 0x41, ORDINARY, normalChar },
+ { 0x2283, 0xc9, RELATION, normalChar },
+ { 0x2287, 0xca, RELATION, normalChar },
+ { 0x2284, 0xcb, RELATION, normalChar },
+ { 0x221A, 0xd6, ORDINARY, normalChar },
+ { 0x221E, 0xa5, ORDINARY, normalChar },
+ { 0x221D, 0xb5, RELATION, normalChar },
+ { 0x220F, 0xd5, ORDINARY, normalChar },
+ { 0x2211, 0xe5, ORDINARY, normalChar },
+ { 0x21D1, 0xdd, RELATION, normalChar },
+ { 0x21D0, 0xdc, RELATION, normalChar },
+ { 0x21D3, 0xdf, RELATION, normalChar },
+ { 0x03A6, 0x46, ORDINARY, normalChar },
+ { 0x03A7, 0x43, ORDINARY, normalChar },
+ { 0x03A4, 0x54, ORDINARY, normalChar },
+ { 0x03A5, 0x55, ORDINARY, normalChar },
+ { 0x03A3, 0x53, ORDINARY, normalChar },
+ { 0x03A0, 0x50, ORDINARY, normalChar },
+ { 0x03A1, 0x52, ORDINARY, normalChar },
+ { 0x03A8, 0x59, ORDINARY, normalChar },
+ { 0x03A9, 0x57, ORDINARY, normalChar },
+ { 0x2135, 0xc0, ORDINARY, normalChar },
+ { 0x22C5, 0xd7, BINOP, normalChar },
+ { 0x03C3, 0x73, ORDINARY, normalChar },
+ { 0x26C4, 0xe0, ORDINARY, normalChar },
+ { 0xF8EF, 0xea, ORDINARY, normalChar },
+ { 0xF8EE, 0xe9, ORDINARY, normalChar },
+ { 0xF8ED, 0xe8, ORDINARY, normalChar },
+ { 0xF8EC, 0xe7, ORDINARY, normalChar },
+ { 0xF8EB, 0xe6, ORDINARY, normalChar },
+ { 0xF8EA, 0xe4, ORDINARY, normalChar },
+ { 0x2260, 0xb9, RELATION, normalChar },
+ { 0x2261, 0xba, RELATION, normalChar },
+ { 0x2264, 0xa3, RELATION, normalChar },
+ { 0x2265, 0xb3, RELATION, normalChar },
+ { 0x005B, 0x5b, ORDINARY, normalChar },
+ { 0x005D, 0x5d, ORDINARY, normalChar },
+ { 0xF8E9, 0xe3, ORDINARY, normalChar },
+ { 0xF8E8, 0xe2, ORDINARY, normalChar },
+ { 0xF8E7, 0xbe, ORDINARY, normalChar },
+ { 0xF8E6, 0xbd, RELATION, normalChar },
+ { 0xF8E5, 0x60, ORDINARY, normalChar },
+ { 0x2282, 0xcc, RELATION, normalChar },
+ { 0x2286, 0xcd, RELATION, normalChar },
+ { 0x2295, 0xc5, BINOP, normalChar },
+ { 0x2297, 0xc4, BINOP, normalChar },
+ { 0x2192, 0xae, RELATION, normalChar },
+ { 0x2193, 0xaf, RELATION, normalChar },
+ { 0x2190, 0xac, RELATION, normalChar },
+ { 0x2191, 0xad, RELATION, normalChar },
+ { 0x2194, 0xab, RELATION, normalChar },
+ { 0x2227, 0xd9, BINOP, normalChar },
+ { 0x2220, 0xd0, ORDINARY, normalChar },
+ { 0x2228, 0xda, BINOP, normalChar },
+ { 0x2229, 0xc7, ORDINARY, normalChar },
+ { 0x0028, 0x28, ORDINARY, normalChar },
+ { 0x0029, 0x29, ORDINARY, normalChar },
+ { 0x222A, 0xc8, ORDINARY, normalChar },
+ { 0x222B, 0xf2, ORDINARY, normalChar },
+ { 0x00AE, 0xd2, ORDINARY, normalChar },
+ { 0x00D7, 0xb4, BINOP, normalChar },
+ { 0x2122, 0xd4, ORDINARY, normalChar },
+ { 0xF8F6, 0xf6, ORDINARY, normalChar },
+ { 0xF8F7, 0xf7, ORDINARY, normalChar },
+ { 0xF8F4, 0xef, ORDINARY, normalChar },
+ { 0xF8F2, 0xed, ORDINARY, normalChar },
+ { 0xF8F3, 0xee, ORDINARY, normalChar },
+ { 0xF8F0, 0xeb, ORDINARY, normalChar },
+ { 0xF8F1, 0xec, ORDINARY, normalChar },
+ { 0xF8F8, 0xf8, ORDINARY, normalChar },
+ { 0xF8F9, 0xf9, ORDINARY, normalChar },
+ { 0xF8FD, 0xfd, ORDINARY, normalChar },
+ { 0xF8FE, 0xfe, ORDINARY, normalChar },
+ { 0xF8FB, 0xfb, ORDINARY, normalChar },
+ { 0xF8FC, 0xfc, ORDINARY, normalChar },
+ { 0xF8FA, 0xfa, ORDINARY, normalChar },
+ { 0x03D1, 0x4a, ORDINARY, normalChar },
+ { 0x03D2, 0xa1, ORDINARY, normalChar },
+ { 0x03D5, 0x6a, ORDINARY, normalChar },
+ { 0x03D6, 0x76, ORDINARY, normalChar },
+ { 0x2666, 0xa8, ORDINARY, normalChar },
+ { 0x00AC, 0xd8, ORDINARY, normalChar },
+ { 0x211C, 0xc2, ORDINARY, normalChar },
+ { 0x2111, 0xc1, ORDINARY, normalChar },
+ { 0x2118, 0xc3, ORDINARY, normalChar },
+ { 0x00A9, 0xd3, ORDINARY, normalChar },
+ { 0x2665, 0xa9, ORDINARY, normalChar },
+ { 0x2660, 0xaa, ORDINARY, normalChar },
+ { 0x2663, 0xa7, ORDINARY, normalChar },
+ { 0x21D4, 0xdb, RELATION, normalChar },
+ { 0x2026, 0xbc, ORDINARY, normalChar },
+ { 0x21D2, 0xde, RELATION, normalChar },
+ { 0x2022, 0xb7, BINOP, normalChar },
+ { 0x223C, 0x7e, RELATION, normalChar },
+ { 0x22A5, 0x5e, ORDINARY, normalChar },
+ { 0x2234, 0x5c, BINOP, normalChar },
+ { 0x2244, 0xa4, ORDINARY, normalChar },
+ { 0x2245, 0x40, RELATION, normalChar },
+ { 0x2248, 0xbb, RELATION, normalChar },
+ { 0x03C0, 0x70, ORDINARY, normalChar },
+ { 0x03C1, 0x72, ORDINARY, normalChar },
+ { 0x03C2, 0x56, ORDINARY, normalChar },
+ { 0xF8F5, 0xf4, ORDINARY, normalChar },
+ { 0x03C4, 0x74, ORDINARY, normalChar },
+ { 0x03C5, 0x75, ORDINARY, normalChar },
+ { 0x03C6, 0x66, ORDINARY, normalChar },
+ { 0x03C7, 0x63, ORDINARY, normalChar },
+ { 0x03C8, 0x79, ORDINARY, normalChar },
+ { 0x03C9, 0x77, ORDINARY, normalChar },
+ { 0x21B5, 0xbf, ORDINARY, normalChar },
+ { 0, 0, ORDINARY, normalChar }
+};
diff --git a/lib/kformula/symboltable.cc b/lib/kformula/symboltable.cc
new file mode 100644
index 00000000..0a444519
--- /dev/null
+++ b/lib/kformula/symboltable.cc
@@ -0,0 +1,152 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
+ Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qfile.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qfontmetrics.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "symboltable.h"
+#include "contextstyle.h"
+#include "unicodetable.cc"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+#include "symbolfontmapping.cc"
+
+SymbolFontHelper::SymbolFontHelper()
+ : greek("abgdezhqiklmnxpvrstufjcywGDQLXPSUFYVW")
+{
+ for ( uint i = 0; symbolMap[ i ].unicode != 0; i++ ) {
+ compatibility[ symbolMap[ i ].pos ] = symbolMap[ i ].unicode;
+ }
+}
+
+QChar SymbolFontHelper::unicodeFromSymbolFont( QChar pos ) const
+{
+ if ( compatibility.contains( pos ) ) {
+ return compatibility[ pos.latin1() ];
+ }
+ return QChar::null;
+}
+
+
+SymbolTable::SymbolTable()
+{
+}
+
+
+void SymbolTable::init( const QFont& font )
+{
+ backupFont = font;
+ for ( int i=0; operatorTable[i].unicode != 0; ++i ) {
+ names[QChar( operatorTable[i].unicode )] = get_name( operatorTable[i] );
+ entries[get_name( operatorTable[i] )] = QChar( operatorTable[i].unicode );
+ }
+ for ( int i=0; arrowTable[i].unicode != 0; ++i ) {
+ names[QChar( arrowTable[i].unicode )] = get_name( arrowTable[i] );
+ entries[get_name( arrowTable[i] )] = QChar( arrowTable[i].unicode );
+ }
+ for ( int i=0; greekTable[i].unicode != 0; ++i ) {
+ names[QChar( greekTable[i].unicode )] = get_name( greekTable[i] );
+ entries[get_name( greekTable[i] )] = QChar( greekTable[i].unicode );
+ }
+}
+
+bool SymbolTable::contains(QString name) const
+{
+ return entries.find( name ) != entries.end();
+}
+
+QChar SymbolTable::unicode(QString name) const
+{
+ return entries[ name ];
+}
+
+
+QString SymbolTable::name( QChar symbol ) const
+{
+ return names[symbol];
+}
+
+QFont SymbolTable::font( QChar symbol, const QFont& f ) const {
+ QFontMetrics fm( f );
+ if ( fm.inFont( symbol ) ) {
+ return f;
+ }
+ return QFont("Arev Sans");
+}
+
+CharClass SymbolTable::charClass( QChar symbol ) const
+{
+ return ORDINARY;
+ // FIXME
+// return entry( symbol, style ).charClass();
+}
+
+
+QChar SymbolTable::unicodeFromSymbolFont( QChar pos ) const
+{
+ return symbolFontHelper.unicodeFromSymbolFont( pos );
+}
+
+
+QString SymbolTable::greekLetters() const
+{
+ return symbolFontHelper.greekLetters();
+}
+
+
+QStringList SymbolTable::allNames() const
+{
+ QStringList list;
+
+ for ( int i=0; operatorTable[i].unicode != 0; ++i ) {
+ list.append( get_name( operatorTable[i] ));
+ }
+ for ( int i=0; arrowTable[i].unicode != 0; ++i ) {
+ list.append( get_name( arrowTable[i] ));
+ }
+ for ( int i=0; greekTable[i].unicode != 0; ++i ) {
+ list.append( get_name( greekTable[i] ) );
+ }
+ return list;
+}
+
+
+QString SymbolTable::get_name( struct UnicodeNameTable entry ) const
+{
+ if ( !*entry.name ) {
+ return "U" + QString( "%1" ).arg( entry.unicode, 4, 16 ).upper();
+ }
+ return entry.name;
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/symboltable.h b/lib/kformula/symboltable.h
new file mode 100644
index 00000000..9218e6b4
--- /dev/null
+++ b/lib/kformula/symboltable.h
@@ -0,0 +1,148 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
+ Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef SYMBOLTABLE_H
+#define SYMBOLTABLE_H
+
+#include <qfont.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluevector.h>
+
+#include "kformuladefs.h"
+
+class KConfig;
+
+KFORMULA_NAMESPACE_BEGIN
+
+class ContextStyle;
+struct UnicodeNameTable;
+
+/**
+ * We expect to always have the symbol font.
+ */
+class SymbolFontHelper {
+public:
+
+ SymbolFontHelper();
+
+ /**
+ * @returns a string with all greek letters.
+ */
+ QString greekLetters() const { return greek; }
+
+ /**
+ * @returns the unicode value of the symbol font char.
+ */
+ QChar unicodeFromSymbolFont( QChar pos ) const;
+
+private:
+
+ /**
+ * symbol font char -> unicode mapping.
+ */
+ QMap<QChar, QChar> compatibility;
+
+ /**
+ * All greek letters that are known.
+ */
+ QString greek;
+};
+
+
+/**
+ * The symbol table.
+ *
+ * It contains all names that are know to the system.
+ */
+class KOFORMULA_EXPORT SymbolTable {
+public:
+
+ SymbolTable();
+
+ /**
+ * lazy init support. Needs to be run before anything else.
+ * @param install if true fonts may be installed if needed
+ */
+ void init( const QFont& font );
+
+ bool contains( QString name ) const;
+
+ /**
+ * @returns the char in the symbol font that belongs to
+ * the given name.
+ */
+ QChar unicode( QString name ) const;
+ QString name( QChar symbol ) const;
+
+ QFont font( QChar symbol, const QFont& f ) const;
+
+ CharClass charClass( QChar symbol ) const;
+
+ /**
+ * @returns a string with all greek letters.
+ */
+ QString greekLetters() const;
+
+ /**
+ * @returns the unicode value of the symbol font char.
+ */
+ QChar unicodeFromSymbolFont( QChar pos ) const;
+
+ /**
+ * @returns all known names as strings.
+ */
+ QStringList allNames() const;
+
+ typedef QMap<QChar, QString> NameTable;
+ typedef QMap<QString, QChar> EntryTable;
+
+private:
+
+ QString get_name( UnicodeNameTable entry ) const;
+
+ /**
+ * unicode -> name mapping.
+ */
+ NameTable names;
+
+ /**
+ * Name -> unicode mapping.
+ */
+ EntryTable entries;
+
+ /**
+ * Basic symbol font support.
+ */
+ SymbolFontHelper symbolFontHelper;
+
+ /**
+ * Backup font for mathematical operators. We ensure that every symbol in
+ * this table is present in this font. If user selected font doesn't have
+ * the needed glyph this font will be used instead.
+ */
+ QFont backupFont;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // SYMBOLTABLE_H
diff --git a/lib/kformula/textelement.cc b/lib/kformula/textelement.cc
new file mode 100644
index 00000000..7526acb6
--- /dev/null
+++ b/lib/kformula/textelement.cc
@@ -0,0 +1,567 @@
+/* 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 <qfontmetrics.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+
+#include "basicelement.h"
+#include "contextstyle.h"
+#include "elementtype.h"
+#include "elementvisitor.h"
+#include "fontstyle.h"
+#include "formulaelement.h"
+#include "kformulacommand.h"
+#include "sequenceelement.h"
+#include "symboltable.h"
+#include "textelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+TextElement::TextElement(QChar ch, bool beSymbol, BasicElement* parent)
+ : BasicElement(parent), character(ch), symbol(beSymbol)
+{
+ charStyle( anyChar );
+ charFamily( anyFamily );
+}
+
+
+TextElement::TextElement( const TextElement& other )
+ : BasicElement( other ),
+ character( other.character ),
+ symbol( other.symbol ),
+ m_format( other.m_format )
+{
+}
+
+
+bool TextElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+TokenType TextElement::getTokenType() const
+{
+ if ( isSymbol() ) {
+ return getSymbolTable().charClass( character );
+ }
+
+ switch ( character.unicode() ) {
+ case '+':
+ case '-':
+ case '*':
+ //case '/': because it counts as text -- no extra spaces
+ return BINOP;
+ case '=':
+ case '<':
+ case '>':
+ return RELATION;
+ case ',':
+ case ';':
+ case ':':
+ return PUNCTUATION;
+ case '\\':
+ return SEPARATOR;
+ case '\0':
+ return ELEMENT;
+ default:
+ if ( character.isNumber() ) {
+ return NUMBER;
+ }
+ else {
+ return ORDINARY;
+ }
+ }
+}
+
+
+bool TextElement::isInvisible() const
+{
+ if (getElementType() != 0) {
+ return getElementType()->isInvisible(*this);
+ }
+ return false;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void TextElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+
+ setCharStyle( style.charStyle() );
+ setCharFamily( style.charFamily() );
+
+ QFont font = getFont( context, style );
+ double fontsize = context.layoutUnitPtToPt( mySize );
+ double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
+ double size = fontsize * scriptsize;
+ font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
+
+ QFontMetrics fm( font );
+ if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
+ setWidth( 0 );
+ setHeight( 0 );
+ setBaseline( getHeight() );
+ }
+ else {
+ QChar ch = getRealCharacter(context);
+ if ( ch == QChar::null ) {
+ setWidth( qRound( context.getEmptyRectWidth( factor ) * 2./3. ) );
+ setHeight( qRound( context.getEmptyRectHeight( factor ) * 2./3. ) );
+ setBaseline( getHeight() );
+ }
+ else {
+ QRect bound = fm.boundingRect( ch );
+ setWidth( context.ptToLayoutUnitPt( fm.width( ch ) ) );
+ setHeight( context.ptToLayoutUnitPt( bound.height() ) );
+ setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
+
+ // There are some glyphs in TeX that have
+ // baseline==0. (\int, \sum, \prod)
+ if ( getBaseline() == 0 ) {
+ //setBaseline( getHeight()/2 + context.axisHeight( tstyle ) );
+ setBaseline( -1 );
+ }
+ }
+ }
+}
+
+/**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+void TextElement::draw( QPainter& painter, const LuPixelRect& /*r*/,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
+ return;
+ }
+
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ // Let container set the color, instead of elementType
+ //setUpPainter( context, painter );
+ painter.setPen( style.color() );
+
+ setCharStyle( style.charStyle() );
+ setCharFamily( style.charFamily() );
+
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ QFont font = getFont( context, style );
+ double fontsize = context.layoutUnitPtToPt( mySize );
+ double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
+ double size = fontsize * scriptsize;
+ font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
+ painter.setFont( font );
+
+ //kdDebug( DEBUGID ) << "TextElement::draw font=" << font.rawName() << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw size=" << mySize << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw size=" << context.layoutUnitToFontSize( mySize, false ) << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw height: " << getHeight() << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw width: " << getWidth() << endl;
+ //kdDebug( DEBUGID ) << endl;
+
+ // Each starting element draws the whole token
+ /*
+ ElementType* token = getElementType();
+ if ( ( token != 0 ) && !symbol ) {
+ QString text = token->text( static_cast<SequenceElement*>( getParent() ) );
+// kdDebug() << "draw text: " << text[0].unicode()
+// << " " << painter.font().family().latin1()
+// << endl;
+ painter.fillRect( context.layoutUnitToPixelX( parentOrigin.x() ),
+ context.layoutUnitToPixelY( parentOrigin.y() ),
+ context.layoutUnitToPixelX( getParent()->getWidth() ),
+ context.layoutUnitToPixelY( getParent()->getHeight() ),
+ style.background() );
+ painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getBaseline() ),
+ text );
+ }
+ else {
+ */
+ QChar ch = getRealCharacter(context);
+ if ( ch != QChar::null ) {
+ luPixel bl = getBaseline();
+ if ( bl == -1 ) {
+ // That's quite hacky and actually not the way it's
+ // meant to be. You shouldn't calculate a lot in
+ // draw. But I don't see how else to deal with
+ // baseline==0 glyphs without yet another flag.
+ bl = -( getHeight()/2 + context.axisHeight( tstyle, factor ) );
+ }
+ painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+bl ),
+ ch );
+ }
+ else {
+ painter.setPen( QPen( context.getErrorColor(),
+ context.layoutUnitToPixelX( context.getLineWidth( factor ) ) ) );
+ painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y() ),
+ context.layoutUnitToPixelX( getWidth() ),
+ context.layoutUnitToPixelY( getHeight() ) );
+ }
+// }
+
+ // Debug
+ //painter.setBrush(Qt::NoBrush);
+// if ( isSymbol() ) {
+// painter.setPen( Qt::red );
+// painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
+// context.layoutUnitToPixelX( myPos.y() ),
+// context.layoutUnitToPixelX( getWidth() ),
+// context.layoutUnitToPixelX( getHeight() ) );
+// painter.setPen(Qt::green);
+// painter.drawLine(myPos.x(), myPos.y()+axis( context, tstyle ),
+// myPos.x()+getWidth(), myPos.y()+axis( context, tstyle ));
+// }
+}
+
+
+void TextElement::dispatchFontCommand( FontCommand* cmd )
+{
+ cmd->addTextElement( this );
+}
+
+void TextElement::setCharStyle( CharStyle cs )
+{
+ charStyle( cs );
+ formula()->changed();
+}
+
+void TextElement::setCharFamily( CharFamily cf )
+{
+ charFamily( cf );
+ formula()->changed();
+}
+
+QChar TextElement::getRealCharacter(const ContextStyle& context)
+{
+ return character;
+/*
+ if ( !isSymbol() ) {
+ const FontStyle& fontStyle = context.fontStyle();
+ const AlphaTable* alphaTable = fontStyle.alphaTable();
+ if ( alphaTable != 0 ) {
+ AlphaTableEntry ate = alphaTable->entry( character,
+ charFamily(),
+ charStyle() );
+ if ( ate.valid() ) {
+ return ate.pos;
+ }
+ }
+ return character;
+ }
+ else {
+ return getSymbolTable().character(character, charStyle());
+ }
+*/
+}
+
+
+QFont TextElement::getFont(const ContextStyle& context, const StyleAttributes& style)
+{
+ const FontStyle& fontStyle = context.fontStyle();
+ QFont font;
+ if ( style.customFont() ) {
+ font = style.font();
+ }
+ else if (getElementType() != 0) {
+ font = getElementType()->getFont(context);
+ }
+ else {
+ font = context.getDefaultFont();
+ }
+ switch ( charStyle() ) {
+ case anyChar:
+ font.setItalic( false );
+ font.setBold( false );
+ break;
+ case normalChar:
+ font.setItalic( false );
+ font.setBold( false );
+ break;
+ case boldChar:
+ font.setItalic( false );
+ font.setBold( true );
+ break;
+ case italicChar:
+ font.setItalic( true );
+ font.setBold( false );
+ break;
+ case boldItalicChar:
+ font.setItalic( true );
+ font.setBold( true );
+ break;
+ }
+ return fontStyle.symbolTable()->font( character, font );
+}
+
+
+void TextElement::setUpPainter(const ContextStyle& context, QPainter& painter)
+{
+ if (getElementType() != 0) {
+ getElementType()->setUpPainter(context, painter);
+ }
+ else {
+ painter.setPen(Qt::red);
+ }
+}
+
+const SymbolTable& TextElement::getSymbolTable() const
+{
+ return formula()->getSymbolTable();
+}
+
+
+void TextElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool ) const
+{
+ parent.appendChild( doc.createTextNode( getCharacter() ) );
+}
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void TextElement::writeDom(QDomElement element)
+{
+ BasicElement::writeDom(element);
+ element.setAttribute("CHAR", QString(character));
+ //QString s;
+ //element.setAttribute("CHAR", s.sprintf( "#x%05X", character ) );
+ if (symbol) element.setAttribute("SYMBOL", "3");
+
+ switch ( charStyle() ) {
+ case anyChar: break;
+ case normalChar: element.setAttribute("STYLE", "normal"); break;
+ case boldChar: element.setAttribute("STYLE", "bold"); break;
+ case italicChar: element.setAttribute("STYLE", "italic"); break;
+ case boldItalicChar: element.setAttribute("STYLE", "bolditalic"); break;
+ }
+
+ switch ( charFamily() ) {
+ case normalFamily: element.setAttribute("FAMILY", "normal"); break;
+ case scriptFamily: element.setAttribute("FAMILY", "script"); break;
+ case frakturFamily: element.setAttribute("FAMILY", "fraktur"); break;
+ case doubleStruckFamily: element.setAttribute("FAMILY", "doublestruck"); break;
+ case anyFamily: break;
+ }
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool TextElement::readAttributesFromDom(QDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ QString charStr = element.attribute("CHAR");
+ if(!charStr.isNull()) {
+ character = charStr.at(0);
+ }
+ QString symbolStr = element.attribute("SYMBOL");
+ if(!symbolStr.isNull()) {
+ int symbolInt = symbolStr.toInt();
+ if ( symbolInt == 1 ) {
+ character = getSymbolTable().unicodeFromSymbolFont(character);
+ }
+ if ( symbolInt == 2 ) {
+ switch ( character.unicode() ) {
+ case 0x03D5: character = 0x03C6; break;
+ case 0x03C6: character = 0x03D5; break;
+ case 0x03Ba: character = 0x03BA; break;
+ case 0x00B4: character = 0x2032; break;
+ case 0x2215: character = 0x2244; break;
+ case 0x00B7: character = 0x2022; break;
+ case 0x1D574: character = 0x2111; break;
+ case 0x1D579: character = 0x211C; break;
+ case 0x2219: character = 0x22C5; break;
+ case 0x2662: character = 0x26C4; break;
+ case 0x220B: character = 0x220D; break;
+ case 0x224C: character = 0x2245; break;
+ case 0x03DB: character = 0x03C2; break;
+ }
+ }
+ symbol = symbolInt != 0;
+ }
+
+ QString styleStr = element.attribute("STYLE");
+ if ( styleStr == "normal" ) {
+ charStyle( normalChar );
+ }
+ else if ( styleStr == "bold" ) {
+ charStyle( boldChar );
+ }
+ else if ( styleStr == "italic" ) {
+ charStyle( italicChar );
+ }
+ else if ( styleStr == "bolditalic" ) {
+ charStyle( boldItalicChar );
+ }
+ else {
+ charStyle( anyChar );
+ }
+
+ QString familyStr = element.attribute( "FAMILY" );
+ if ( familyStr == "normal" ) {
+ charFamily( normalFamily );
+ }
+ else if ( familyStr == "script" ) {
+ charFamily( scriptFamily );
+ }
+ else if ( familyStr == "fraktur" ) {
+ charFamily( frakturFamily );
+ }
+ else if ( familyStr == "doublestruck" ) {
+ charFamily( doubleStruckFamily );
+ }
+ else {
+ charFamily( anyFamily );
+ }
+
+// kdDebug() << "charStyle=" << charStyle()
+// << " charFamily=" << charFamily()
+// << " format=" << int( format() ) << endl;
+
+ return true;
+}
+
+/**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+bool TextElement::readContentFromDom(QDomNode& node)
+{
+ return BasicElement::readContentFromDom(node);
+}
+
+QString TextElement::toLatex()
+{
+ if ( isSymbol() ) {
+ QString texName = getSymbolTable().name( character );
+ if ( !texName.isNull() )
+ return " \\" + texName + " ";
+ return " ? ";
+ }
+ else {
+ return QString(character);
+ }
+}
+
+QString TextElement::formulaString()
+{
+ if ( isSymbol() ) {
+ QString texName = getSymbolTable().name( character );
+ if ( !texName.isNull() )
+ return " " + texName + " ";
+ return " ? ";
+ }
+ else {
+ return character;
+ }
+}
+
+
+EmptyElement::EmptyElement( BasicElement* parent )
+ : BasicElement( parent )
+{
+}
+
+EmptyElement::EmptyElement( const EmptyElement& other )
+ : BasicElement( other )
+{
+}
+
+
+bool EmptyElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void EmptyElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style )
+{
+ luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
+ //kdDebug( DEBUGID ) << "TextElement::calcSizes size=" << mySize << endl;
+
+ QFont font = context.getDefaultFont();
+ font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
+
+ QFontMetrics fm( font );
+ QChar ch = 'A';
+ QRect bound = fm.boundingRect( ch );
+ setWidth( 0 );
+ setHeight( context.ptToLayoutUnitPt( bound.height() ) );
+ setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
+}
+
+void EmptyElement::draw( QPainter& painter, const LuPixelRect& /*r*/,
+ const ContextStyle& context,
+ ContextStyle::TextStyle /*tstyle*/,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& /*style*/ ,
+ const LuPixelPoint& parentOrigin )
+{
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ /*
+ if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ return;
+ */
+
+ if ( context.edit() ) {
+ painter.setPen( context.getHelpColor() );
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y() ),
+ context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
+ }
+}
+
+QString EmptyElement::toLatex()
+{
+ return "{}";
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/textelement.h b/lib/kformula/textelement.h
new file mode 100644
index 00000000..bac10acc
--- /dev/null
+++ b/lib/kformula/textelement.h
@@ -0,0 +1,287 @@
+/* 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.
+*/
+
+#ifndef TEXTELEMENT_H
+#define TEXTELEMENT_H
+
+#include <qfont.h>
+#include <qstring.h>
+
+#include "basicelement.h"
+
+class SymbolTable;
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+/**
+ * An element that represents one char.
+ */
+class TextElement : public BasicElement {
+ TextElement operator=( const TextElement& ) { return *this; }
+public:
+
+ TextElement(QChar ch = ' ', bool beSymbol = false, BasicElement* parent = 0);
+ TextElement( const TextElement& );
+
+ virtual TextElement* clone() {
+ return new TextElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns the type of this element. Used for
+ * parsing a sequence.
+ */
+ virtual TokenType getTokenType() const;
+
+ /**
+ * @returns true if we don't want to see the element.
+ */
+ virtual bool isInvisible() const;
+
+ /**
+ * @returns the character that represents this element. Used for
+ * parsing a sequence.
+ */
+ virtual QChar getCharacter() const { return character; }
+
+ // drawing
+ //
+ // Drawing depends on a context which knows the required properties like
+ // fonts, spaces and such.
+ // It is essential to calculate elements size with the same context
+ // before you draw.
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+ /**
+ * Dispatch this FontCommand to all our TextElement children.
+ */
+ virtual void dispatchFontCommand( FontCommand* cmd );
+
+ /**
+ * Set the color to use to display
+ */
+ void setColor( QColor c ) { color = c; }
+
+ CharStyle getCharStyle() const { return charStyle(); }
+ void setCharStyle( CharStyle cs );
+
+ CharFamily getCharFamily() const { return charFamily(); }
+ void setCharFamily( CharFamily cf );
+
+ char format() const { return m_format; }
+
+ /**
+ * Moves the cursor away from the given child. The cursor is
+ * guaranteed to be inside this element.
+ */
+ //virtual void childWillVanish(FormulaCursor*, BasicElement*) {}
+
+ /**
+ * @returns whether we are a symbol (greek letter).
+ */
+ bool isSymbol() const { return symbol; }
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+ virtual QString formulaString();
+
+ virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
+
+protected:
+
+ //Save/load support
+
+ /**
+ * @returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "TEXT"; }
+
+ /**
+ * Appends our attributes to the dom element.
+ */
+ virtual void writeDom(QDomElement element);
+
+ /**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+ virtual bool readAttributesFromDom(QDomElement element);
+
+ /**
+ * Reads our content from the node. Sets the node to the next node
+ * that needs to be read.
+ * Returns false if it failed.
+ */
+ virtual bool readContentFromDom(QDomNode& node);
+
+ /**
+ * @returns the char that is used to draw with the given font.
+ */
+ QChar getRealCharacter(const ContextStyle& context);
+
+ /**
+ * @returns the font to be used for the element.
+ */
+ QFont getFont(const ContextStyle& context, const StyleAttributes& style);
+
+ /**
+ * Sets up the painter to be used for drawing.
+ */
+ void setUpPainter(const ContextStyle& context, QPainter& painter);
+
+ const SymbolTable& getSymbolTable() const;
+
+private:
+
+ /**
+ * Our content.
+ */
+ QChar character;
+
+ /**
+ * Whether this character is a symbol.
+ */
+ bool symbol;
+
+ /**
+ * Color to display. Set by container.
+ */
+ QColor color;
+
+ /**
+ * The attribute of the char. "anyChar" means leave the default.
+ *
+ * This must be in sync with the definition in kformuladefs.h!
+ */
+ CharStyle charStyle() const { return static_cast<CharStyle>( m_format & 0x0f ); }
+ void charStyle( CharStyle cs )
+ { m_format = ( m_format & 0xf0 ) | static_cast<char>( cs ); }
+
+ /**
+ * Very rarely used so it's actually a shame to have it here.
+ *
+ * This must be in sync with the definition in kformuladefs.h!
+ */
+ CharFamily charFamily() const
+ { return static_cast<CharFamily>( m_format >> 4 ); }
+ void charFamily( CharFamily cf )
+ { m_format = ( m_format & 0x0f ) | ( static_cast<char>( cf ) << 4 ); }
+
+ /**
+ * To save space both CharStyle and CharFamily are packed into one
+ * char.
+ */
+ char m_format;
+};
+
+
+/**
+ * An element that represents an empty box.
+ */
+class EmptyElement : public BasicElement {
+ EmptyElement& operator=( const EmptyElement& ) { return *this; }
+public:
+
+ EmptyElement( BasicElement* parent = 0 );
+ EmptyElement( const EmptyElement& );
+
+ virtual EmptyElement* clone() {
+ return new EmptyElement( *this );
+ }
+
+ virtual bool accept( ElementVisitor* visitor );
+
+ /**
+ * @returns the character that represents this element. Used for
+ * parsing a sequence.
+ * Here we use a dummy so an EmptyElement pretends to be a letter.
+ */
+ virtual QChar getCharacter() const { return 'A'; }
+
+ /**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+ virtual void calcSizes( const ContextStyle& cstyle,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ /**
+ * Draws the whole element including its children.
+ * The `parentOrigin' is the point this element's parent starts.
+ * We can use our parentPosition to get our own origin then.
+ */
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+
+ /**
+ * @returns the latex representation of the element and
+ * of the element's children
+ */
+ virtual QString toLatex();
+
+protected:
+
+ //Save/load support
+
+ /**
+ * @returns the tag name of this element type.
+ */
+ virtual QString getTagName() const { return "EMPTY"; }
+
+};
+
+
+KFORMULA_NAMESPACE_END
+
+#endif // TEXTELEMENT_H
diff --git a/lib/kformula/tokenelement.cc b/lib/kformula/tokenelement.cc
new file mode 100644
index 00000000..6c849e9c
--- /dev/null
+++ b/lib/kformula/tokenelement.cc
@@ -0,0 +1,124 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <algorithm>
+
+#include <qpainter.h>
+
+#include <klocale.h>
+
+#include "entities.h"
+#include "elementtype.h"
+#include "sequenceelement.h"
+#include "textelement.h"
+#include "glyphelement.h"
+#include "tokenelement.h"
+#include "identifierelement.h"
+#include "kformulacommand.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "formulaelement.h"
+#include "creationstrategy.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+TokenElement::TokenElement( BasicElement* parent ) : TokenStyleElement( parent ),
+ m_textOnly( true )
+{
+}
+
+int TokenElement::buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n)
+{
+ while ( ! n.isNull() ) {
+ if ( n.isText() ) {
+ QString textelements = n.toText().data();
+ textelements = textelements.stripWhiteSpace();
+
+ for (uint i = 0; i < textelements.length(); i++) {
+ TextElement* child = new TextElement(textelements[i]);
+ child->setParent(this);
+ child->setCharFamily( charFamily() );
+ child->setCharStyle( charStyle() );
+ list.append(child);
+ }
+ }
+ else if ( n.isEntityReference() ) {
+ QString entity = n.toEntityReference().nodeName();
+ const entityMap* begin = entities;
+ const entityMap* end = entities + entityMap::size();
+ const entityMap* pos = std::lower_bound( begin, end, entity.ascii() );
+ if ( pos == end || QString( pos->name ) != entity ) {
+ kdWarning() << "Invalid entity refererence: " << entity << endl;
+ }
+ else {
+ TextElement* child = new TextElement( QChar( pos->unicode ) );
+ child->setParent(this);
+ child->setCharFamily( charFamily() );
+ child->setCharStyle( charStyle() );
+ list.append(child);
+ }
+ }
+ else if ( n.isElement() ) {
+ m_textOnly = false;
+ // Only mglyph element is allowed
+ QDomElement e = n.toElement();
+ if ( e.tagName().lower() != "mglyph" ) {
+ kdWarning( DEBUGID ) << "Invalid element inside Token Element\n";
+ return -1;
+ }
+ GlyphElement* child = new GlyphElement();
+ child->setParent(this);
+ child->setCharFamily( charFamily() );
+ child->setCharStyle( charStyle() );
+ if ( child->buildFromMathMLDom( e ) == -1 ) {
+ return -1;
+ }
+ list.append( child );
+ }
+ else {
+ kdWarning() << "Invalid content in TokenElement\n";
+ }
+ n = n.nextSibling();
+ }
+// parse();
+ kdWarning() << "Num of children " << list.count() << endl;
+ return 1;
+}
+
+luPt TokenElement::getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( !context.isScript( tstyle ) ) {
+ return context.getMediumSpace( tstyle, factor );
+ }
+ return 0;
+}
+
+luPt TokenElement::getSpaceAfter( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor )
+{
+ if ( !context.isScript( tstyle ) ) {
+ return context.getThinSpace( tstyle, factor );
+ }
+ return 0;
+}
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/tokenelement.h b/lib/kformula/tokenelement.h
new file mode 100644
index 00000000..8a64bb99
--- /dev/null
+++ b/lib/kformula/tokenelement.h
@@ -0,0 +1,61 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef TOKENELEMENT_H
+#define TOKENELEMENT_H
+
+#include "formulacursor.h"
+#include "tokenstyleelement.h"
+#include "sequenceelement.h"
+#include "contextstyle.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+class TokenElement : public TokenStyleElement {
+ typedef TokenStyleElement inherited;
+public:
+ TokenElement( BasicElement* parent = 0 );
+
+ virtual int buildChildrenFromMathMLDom(QPtrList<BasicElement>& list, QDomNode n);
+
+ virtual QString getElementName() const { return "mtext"; }
+protected:
+ QString getCharFromEntity( const QString& entity );
+
+ /**
+ * @returns true if the sequence contains only text.
+ */
+ virtual bool isTextOnly() const { return m_textOnly; }
+
+ /**
+ * Space around sequence
+ */
+ virtual luPt getSpaceBefore( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+ virtual luPt getSpaceAfter( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ double factor );
+private:
+ bool m_textOnly;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // TOKENELEMENT_H
diff --git a/lib/kformula/tokenstyleelement.cc b/lib/kformula/tokenstyleelement.cc
new file mode 100644
index 00000000..d205f70d
--- /dev/null
+++ b/lib/kformula/tokenstyleelement.cc
@@ -0,0 +1,624 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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 <qpainter.h>
+
+#include "basicelement.h"
+#include "tokenstyleelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+TokenStyleElement::TokenStyleElement( BasicElement* parent ) : SequenceElement( parent ),
+ m_mathSizeType ( NoSize ),
+ m_charStyle( anyChar ),
+ m_charFamily( anyFamily ),
+ m_mathColor( "#000000" ),
+ m_mathBackground( "#FFFFFF" ),
+ m_fontSizeType( NoSize ),
+ m_customMathVariant( false ),
+ m_customMathColor( false ),
+ m_customMathBackground( false ),
+ m_customFontWeight( false ),
+ m_customFontStyle( false ),
+ m_customFontFamily( false ),
+ m_customColor( false )
+{
+}
+
+void TokenStyleElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style )
+{
+ setStyleSize( context, style );
+ setStyleVariant( style );
+ setStyleColor( style );
+ setStyleBackground( style );
+ inherited::calcSizes( context, tstyle, istyle, style );
+ resetStyle( style );
+}
+
+void TokenStyleElement::draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ setStyleSize( context, style );
+ setStyleVariant( style );
+ setStyleColor( style );
+ setStyleBackground( style );
+ if ( style.background() != Qt::color0 ) {
+ painter.fillRect( context.layoutUnitToPixelX( parentOrigin.x() + getX() ),
+ context.layoutUnitToPixelY( parentOrigin.y() + getY() ),
+ context.layoutUnitToPixelX( getWidth() ),
+ context.layoutUnitToPixelY( getHeight() ),
+ style.background() );
+ }
+ inherited::draw( painter, r, context, tstyle, istyle, style, parentOrigin );
+ resetStyle( style );
+}
+
+bool TokenStyleElement::readAttributesFromMathMLDom( const QDomElement& element )
+{
+ if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
+ return false;
+ }
+
+ // MathML Section 3.2.2
+ QString variantStr = element.attribute( "mathvariant" );
+ if ( !variantStr.isNull() ) {
+ if ( variantStr == "normal" ) {
+ setCharStyle( normalChar );
+ setCharFamily( normalFamily );
+ }
+ else if ( variantStr == "bold" ) {
+ setCharStyle( boldChar );
+ setCharFamily( normalFamily );
+ }
+ else if ( variantStr == "italic" ) {
+ setCharStyle( italicChar );
+ setCharFamily( normalFamily );
+ }
+ else if ( variantStr == "bold-italic" ) {
+ setCharStyle( boldItalicChar );
+ setCharFamily( normalFamily );
+ }
+ else if ( variantStr == "double-struck" ) {
+ setCharStyle( normalChar );
+ setCharFamily( doubleStruckFamily );
+ }
+ else if ( variantStr == "bold-fraktur" ) {
+ setCharStyle( boldChar );
+ setCharFamily( frakturFamily );
+ }
+ else if ( variantStr == "script" ) {
+ setCharStyle( normalChar );
+ setCharFamily( scriptFamily );
+ }
+ else if ( variantStr == "bold-script" ) {
+ setCharStyle( boldChar );
+ setCharFamily( scriptFamily );
+ }
+ else if ( variantStr == "fraktur" ) {
+ setCharStyle( boldChar );
+ setCharFamily( frakturFamily );
+ }
+ else if ( variantStr == "sans-serif" ) {
+ setCharStyle( normalChar );
+ setCharFamily( sansSerifFamily );
+ }
+ else if ( variantStr == "bold-sans-serif" ) {
+ setCharStyle( boldChar );
+ setCharFamily( sansSerifFamily );
+ }
+ else if ( variantStr == "sans-serif-italic" ) {
+ setCharStyle( italicChar );
+ setCharFamily( sansSerifFamily );
+ }
+ else if ( variantStr == "sans-serif-bold-italic" ) {
+ setCharStyle( boldItalicChar );
+ setCharFamily( sansSerifFamily );
+ }
+ else if ( variantStr == "monospace" ) {
+ setCharStyle( normalChar );
+ setCharFamily( monospaceFamily );
+ }
+ }
+
+ QString sizeStr = element.attribute( "mathsize" );
+ if ( !sizeStr.isNull() ) {
+ if ( sizeStr == "small" ) {
+ setRelativeSize( 0.8 ); // ### Arbitrary size
+ }
+ else if ( sizeStr == "normal" ) {
+ setRelativeSize( 1.0 );
+ }
+ else if ( sizeStr == "big" ) {
+ setRelativeSize( 1.2 ); // ### Arbitrary size
+ }
+ else {
+ double s = getSize( sizeStr, &m_mathSizeType );
+ switch ( m_mathSizeType ) {
+ case AbsoluteSize:
+ setAbsoluteSize( s );
+ break;
+ case RelativeSize:
+ setRelativeSize( s );
+ break;
+ case PixelSize:
+ setPixelSize( s );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ QString colorStr = element.attribute( "mathcolor" );
+ if ( !colorStr.isNull() ) {
+ if ( colorStr[0] != '#' ) {
+ setMathColor( QColor( getHtmlColor( colorStr ) ) );
+ }
+ else {
+ setMathColor( QColor( colorStr ) );
+ }
+ }
+ QString backgroundStr = element.attribute( "mathbackground" );
+ if ( !backgroundStr.isNull() ) {
+ if ( backgroundStr[0] != '#' ) {
+ setMathBackground( QColor( getHtmlColor( backgroundStr ) ) );
+ }
+ else {
+ setMathBackground( QColor( backgroundStr ) );
+ }
+ }
+
+ // Deprecated attributes. See Section 3.2.2.1
+
+ sizeStr = element.attribute( "fontsize" );
+ if ( ! sizeStr.isNull() ) {
+ if ( sizeStr == "small" ) {
+ setRelativeSize( 0.8, true ); // ### Arbitrary size
+ }
+ else if ( sizeStr == "normal" ) {
+ setRelativeSize( 1.0, true );
+ }
+ else if ( sizeStr == "big" ) {
+ setRelativeSize( 1.2, true ); // ### Arbitrary size
+ }
+ else {
+ double s = getSize( sizeStr, &m_fontSizeType );
+ switch ( m_fontSizeType ) {
+ case AbsoluteSize:
+ setAbsoluteSize( s, true );
+ break;
+ case RelativeSize:
+ setRelativeSize( s, true );
+ break;
+ case PixelSize:
+ setPixelSize( s, true );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ QString styleStr = element.attribute( "fontstyle" );
+ if ( ! styleStr.isNull() ) {
+ if ( styleStr.lower() == "italic" ) {
+ setFontStyle( true );
+ }
+ else {
+ setFontStyle( false );
+ }
+ }
+
+ QString weightStr = element.attribute( "fontweight" );
+ if ( ! weightStr.isNull() ) {
+ if ( weightStr.lower() == "bold" ) {
+ setFontWeight( true );
+ }
+ else {
+ setFontWeight( false );
+ }
+ }
+
+ QString familyStr = element.attribute( "fontfamily" );
+ if ( ! familyStr.isNull() ) {
+ setFontFamily( familyStr );
+ }
+
+ colorStr = element.attribute( "color" );
+ if ( ! colorStr.isNull() ) {
+ if ( colorStr[0] != '#' ) {
+ setColor( QColor( getHtmlColor( colorStr ) ) );
+ }
+ else {
+ setColor( QColor( colorStr ) );
+ }
+ }
+
+ return true;
+}
+
+void TokenStyleElement::writeMathMLAttributes( QDomElement& element ) const
+{
+ // mathvariant attribute
+ if ( customMathVariant() ) {
+ if ( charFamily() == normalFamily ) {
+ if ( charStyle() == normalChar ) {
+ element.setAttribute( "mathvariant", "normal" );
+ }
+ else if ( charStyle() == boldChar ) {
+ element.setAttribute( "mathvariant", "bold" );
+ }
+ else if ( charStyle() == italicChar ) {
+ element.setAttribute( "mathvariant", "italic" );
+ }
+ else if ( charStyle() == boldItalicChar ) {
+ element.setAttribute( "mathvariant", "bold-italic" );
+ }
+ else { // anyChar or unknown, it's always an error
+ kdWarning( DEBUGID ) << "Mathvariant: unknown style for normal family\n";
+ }
+ }
+ else if ( charFamily() == doubleStruckFamily ) {
+ if ( charStyle() == normalChar ) {
+ element.setAttribute( "mathvariant", "double-struck" );
+ }
+ else { // Shouldn't happen, it's a bug
+ kdWarning( DEBUGID ) << "Mathvariant: unknown style for double-struck family\n";
+ }
+ }
+ else if ( charFamily() == frakturFamily ) {
+ if ( charStyle() == normalChar ) {
+ element.setAttribute( "mathvariant", "fraktur" );
+ }
+ else if ( charStyle() == boldChar ) {
+ element.setAttribute( "mathvariant", "bold-fraktur" );
+ }
+ else {
+ kdWarning( DEBUGID ) << "Mathvariant: unknown style for fraktur family\n";
+ }
+ }
+ else if ( charFamily() == scriptFamily ) {
+ if ( charStyle() == normalChar ) {
+ element.setAttribute( "mathvariant", "script" );
+ }
+ else if ( charStyle() == boldChar ) {
+ element.setAttribute( "mathvariant", "bold-script" );
+ }
+ else { // Shouldn't happen, it's a bug
+ kdWarning( DEBUGID ) << "Mathvariant: unknown style for script family\n";
+ }
+ }
+ else if ( charFamily() == sansSerifFamily ) {
+ if ( charStyle() == normalChar ) {
+ element.setAttribute( "mathvariant", "sans-serif" );
+ }
+ else if ( charStyle() == boldChar ) {
+ element.setAttribute( "mathvariant", "bold-sans-serif" );
+ }
+ else if ( charStyle() == italicChar ) {
+ element.setAttribute( "mathvariant", "sans-serif-italic" );
+ }
+ else if ( charStyle() == boldItalicChar ) {
+ element.setAttribute( "mathvariant", "sans-serif-bold-italic" );
+ }
+ else {
+ kdWarning( DEBUGID ) << "Mathvariant: unknown style for sans serif family\n";
+ }
+ }
+ else if ( charFamily() == monospaceFamily ) {
+ if ( charStyle() == normalChar ) {
+ element.setAttribute( "mathvariant", "monospace" );
+ }
+ else {
+ kdWarning( DEBUGID ) << "Mathvariant: unknown style for monospace family\n";
+ }
+ }
+ else {
+ kdWarning( DEBUGID ) << "Mathvariant: unknown family\n";
+ }
+ }
+
+ // mathsize attribute
+ switch ( m_mathSizeType ) {
+ case AbsoluteSize:
+ element.setAttribute( "mathsize", QString( "%1pt" ).arg( m_mathSize ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "mathsize", QString( "%1%" ).arg( m_mathSize * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "mathsize", QString( "%1px" ).arg( m_mathSize ) );
+ break;
+ default:
+ break;
+ }
+
+ // mathcolor attribute
+ if ( customMathColor() ) {
+ element.setAttribute( "mathcolor", mathColor().name() );
+ }
+
+ // mathbackground attribute
+ if ( customMathBackground() ) {
+ element.setAttribute( "mathbackground", mathBackground().name() );
+ }
+
+ // Deprecated MathML 1.01 Attributes
+ // fontsize attribute
+ switch ( m_fontSizeType ) {
+ case AbsoluteSize:
+ element.setAttribute( "fontsize", QString( "%1pt" ).arg( m_fontSize ) );
+ break;
+ case RelativeSize:
+ element.setAttribute( "fontsize", QString( "%1%" ).arg( m_fontSize * 100.0 ) );
+ break;
+ case PixelSize:
+ element.setAttribute( "fontsize", QString( "%3px" ).arg( m_fontSize ) );
+ break;
+ default:
+ break;
+ }
+
+ // fontweight attribute
+ if ( customFontWeight() ) {
+ element.setAttribute( "fontweight", fontWeight() ? "bold" : "normal" );
+ }
+
+ // fontstyle attribute
+ if ( customFontStyle() ) {
+ element.setAttribute( "fontstyle", fontStyle() ? "italic" : "normal" );
+ }
+
+ // fontfamily attribute
+ if ( customFontFamily() ) {
+ element.setAttribute( "fontfamily", fontFamily() );
+ }
+
+ // color attribute
+ if ( customColor() ) {
+ element.setAttribute( "color", color().name() );
+ }
+}
+
+void TokenStyleElement::setAbsoluteSize( double s, bool fontsize )
+{
+ kdDebug( DEBUGID) << "Setting absolute size: " << s << endl;
+ if ( fontsize ) {
+ m_fontSizeType = AbsoluteSize;
+ m_fontSize = s;
+ }
+ else {
+ m_mathSizeType = AbsoluteSize;
+ m_mathSize = s;
+ }
+}
+
+void TokenStyleElement::setRelativeSize( double f, bool fontsize )
+{
+ kdDebug( DEBUGID) << "Setting relative size: " << f << endl;
+ if ( fontsize ) {
+ m_fontSizeType = RelativeSize;
+ m_fontSize = f;
+ }
+ else {
+ m_mathSizeType = RelativeSize;
+ m_mathSize = f;
+ }
+}
+
+void TokenStyleElement::setPixelSize( double px, bool fontsize )
+{
+ kdDebug( DEBUGID) << "Setting pixel size: " << px << endl;
+ if ( fontsize ) {
+ m_fontSizeType = PixelSize;
+ m_fontSize = px;
+ }
+ else {
+ m_mathSizeType = PixelSize;
+ m_mathSize = px;
+ }
+}
+
+void TokenStyleElement::setStyleSize( const ContextStyle& context, StyleAttributes& style )
+{
+ style.setSizeFactor( sizeFactor( context, style.sizeFactor() ) );
+}
+
+void TokenStyleElement::setStyleVariant( StyleAttributes& style )
+{
+ if ( customMathVariant() || style.customMathVariant() ) {
+ style.setCustomMathVariant ( true );
+ style.setCustomFontWeight( false );
+ style.setCustomFontStyle( false );
+ style.setCustomFont( false );
+ if ( customMathVariant() ) {
+ style.setCharFamily ( charFamily() );
+ style.setCharStyle( charStyle() );
+ }
+ else {
+ style.setCharFamily( style.charFamily() );
+ style.setCharStyle( style.charStyle() );
+ }
+ }
+ else {
+ style.setCustomMathVariant( false );
+ if ( customFontFamily() ) {
+ style.setCustomFont( true );
+ style.setFont( QFont(fontFamily()) );
+ }
+
+ bool fontweight = false;
+ if ( customFontWeight() || style.customFontWeight() ) {
+ style.setCustomFontWeight( true );
+ if ( customFontWeight() ) {
+ fontweight = fontWeight();
+ }
+ else {
+ fontweight = style.fontWeight();
+ }
+ style.setFontWeight( fontweight );
+ }
+ else {
+ style.setCustomFontWeight( false );
+ }
+
+ bool fontstyle = false;
+ if ( style.customFontStyle() ) {
+ style.setCustomFontStyle( true );
+ fontstyle = style.fontStyle();
+ style.setFontStyle( fontstyle );
+ }
+ else {
+ style.setCustomFontStyle( false );
+ }
+ if ( customFontStyle() ) {
+ fontstyle = fontStyle();
+ }
+
+ if ( fontweight && fontstyle ) {
+ style.setCharStyle( boldItalicChar );
+ }
+ else if ( fontweight && ! fontstyle ) {
+ style.setCharStyle( boldChar );
+ }
+ else if ( ! fontweight && fontstyle ) {
+ style.setCharStyle( italicChar );
+ }
+ else {
+ style.setCharStyle( normalChar );
+ }
+ }
+}
+
+void TokenStyleElement::setStyleColor( StyleAttributes& style )
+{
+ if ( customMathColor() ) {
+ style.setColor( mathColor() );
+ }
+ else if ( customColor() ) {
+ style.setColor( color() );
+ }
+ else {
+ style.setColor( style.color() );
+ }
+}
+
+void TokenStyleElement::setStyleBackground( StyleAttributes& style )
+{
+ if ( customMathBackground() ) {
+ style.setBackground( mathBackground() );
+ }
+ else {
+ style.setBackground( style.background() );
+ }
+}
+
+void TokenStyleElement::resetStyle( StyleAttributes& style )
+{
+ style.resetSize();
+ style.resetCharStyle();
+ style.resetCharFamily();
+ style.resetColor();
+ style.resetBackground();
+ style.resetFontFamily();
+ style.resetFontWeight();
+ style.resetFontStyle();
+}
+
+double TokenStyleElement::sizeFactor( const ContextStyle& context, double factor )
+{
+ double basesize = context.layoutUnitPtToPt( context.getBaseSize() );
+ switch ( m_mathSizeType ) {
+ case AbsoluteSize:
+ return m_mathSize / basesize;
+ case RelativeSize:
+ return m_mathSize;
+ case PixelSize:
+ // 3.2.2 says v-unit instead of h-unit, that's why we use Y and not X
+ return context.pixelYToPt( m_mathSize ) / basesize;
+ case NoSize:
+ switch ( m_fontSizeType ) {
+ case AbsoluteSize:
+ return m_fontSize / basesize;
+ case RelativeSize:
+ return m_fontSize;
+ case PixelSize:
+ return context.pixelYToPt( m_fontSize ) / basesize;
+ default:
+ return factor;
+ }
+ default:
+ break;
+ }
+ kdWarning( DEBUGID ) << k_funcinfo << " Unknown SizeType\n";
+ return factor;
+}
+
+/**
+ * Return RGB string from HTML Colors. See HTML Spec, section 6.5
+ */
+QString TokenStyleElement::getHtmlColor( const QString& colorStr ){
+
+ QString colorname = colorStr.lower();
+
+ if ( colorname == "black" )
+ return "#000000";
+ if ( colorname == "silver" )
+ return "#C0C0C0";
+ if ( colorname == "gray" )
+ return "#808080";
+ if ( colorname == "white" )
+ return "#FFFFFF";
+ if ( colorname == "maroon" )
+ return "#800000";
+ if ( colorname == "red" )
+ return "#FF0000";
+ if ( colorname == "purple" )
+ return "#800080";
+ if ( colorname == "fuchsia" )
+ return "#FF00FF";
+ if ( colorname == "green" )
+ return "#008000";
+ if ( colorname == "lime" )
+ return "#00FF00";
+ if ( colorname == "olive" )
+ return "#808000";
+ if ( colorname == "yellow" )
+ return "#FFFF00";
+ if ( colorname == "navy" )
+ return "#000080";
+ if ( colorname == "blue")
+ return "#0000FF";
+ if ( colorname == "teal" )
+ return "#008080";
+ if ( colorname == "aqua" )
+ return "#00FFFF";
+ kdWarning( DEBUGID ) << "Invalid HTML color: " << colorname << endl;
+ return "#FFFFFF"; // ### Arbitrary selection of default color
+}
+
+
+KFORMULA_NAMESPACE_END
diff --git a/lib/kformula/tokenstyleelement.h b/lib/kformula/tokenstyleelement.h
new file mode 100644
index 00000000..9f17b19c
--- /dev/null
+++ b/lib/kformula/tokenstyleelement.h
@@ -0,0 +1,168 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+#ifndef TOKENSTYLEELEMENT_H
+#define TOKENSTYLEELEMENT_H
+
+#include "kformuladefs.h"
+#include "sequenceelement.h"
+
+KFORMULA_NAMESPACE_BEGIN
+
+/**
+ * This class handles mathematical style attributes common to token elements,
+ * as explained in MathML Spec, Section 3.2.2.
+ *
+ * It is in charge of reading and saving elements' attributes and setting
+ * rendering information according to these attributes.
+ */
+class TokenStyleElement : public SequenceElement {
+ typedef SequenceElement inherited;
+public:
+
+ TokenStyleElement( BasicElement* parent = 0 );
+
+ virtual void calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style );
+
+ virtual void draw( QPainter& painter, const LuPixelRect& r,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle istyle,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin );
+
+protected:
+ virtual bool readAttributesFromMathMLDom( const QDomElement &element );
+ virtual void writeMathMLAttributes( QDomElement& element ) const ;
+
+ void setAbsoluteSize( double s, bool fontsize = false );
+ void setRelativeSize( double s, bool fontsize = false );
+ void setPixelSize( double s, bool fontsize = false );
+
+ void setCharStyle( CharStyle cs ) {
+ m_charStyle = cs;
+ m_customMathVariant = true;
+ }
+ CharStyle charStyle() const { return m_charStyle; }
+
+ void setCharFamily( CharFamily cf ) {
+ m_charFamily = cf;
+ m_customMathVariant = true;
+ }
+ CharFamily charFamily() const { return m_charFamily; }
+
+ void setMathColor( const QColor& c ) {
+ m_mathColor = c;
+ m_customMathColor = true;
+ }
+ QColor mathColor() const { return m_mathColor; }
+
+ void setMathBackground( const QColor& bg ) {
+ m_mathBackground = bg;
+ m_customMathBackground = true;
+ }
+ QColor mathBackground() const { return m_mathBackground; }
+
+ void setFontWeight( bool w ) {
+ m_fontWeight = w;
+ m_customFontWeight = true;
+ }
+ bool fontWeight() const { return m_fontWeight; }
+
+ void setFontStyle( bool s ) {
+ m_fontStyle = s;
+ m_customFontStyle = true;
+ }
+ bool fontStyle() const { return m_fontStyle; }
+
+ void setFontFamily( const QString& s ) {
+ m_fontFamily = s;
+ m_customFontFamily = true;
+ }
+ QString fontFamily() const { return m_fontFamily; }
+
+ void setColor( const QColor& c ) {
+ m_color = c;
+ m_customColor = true;
+ }
+ QColor color() const { return m_color; }
+
+ bool customMathVariant() const { return m_customMathVariant; }
+ bool customMathColor() const { return m_customMathColor; }
+ bool customMathBackground() const { return m_customMathBackground; }
+ bool customFontWeight() const { return m_customFontWeight; }
+ bool customFontStyle() const { return m_customFontStyle; }
+ bool customFontFamily() const { return m_customFontFamily; }
+ bool customColor() const { return m_customColor; }
+
+ virtual void setStyleSize( const ContextStyle& context, StyleAttributes& style );
+ /**
+ * Set the mathvariant related info in style stacks, including info for
+ * deprecated attributes. It may be redefined by token elements whose
+ * behaviour differs from default one (e.g. identifiers)
+ */
+ virtual void setStyleVariant( StyleAttributes& style );
+
+ void setStyleColor( StyleAttributes& style );
+ virtual void setStyleBackground( StyleAttributes& style );
+
+ virtual void resetStyle( StyleAttributes& style );
+ /**
+ * Return RGB string from HTML Colors. See HTML Spec, section 6.5
+ */
+ QString getHtmlColor( const QString& colorStr );
+
+private:
+
+ double sizeFactor( const ContextStyle& context, double factor );
+
+ // MathML 2.0 attributes
+ SizeType m_mathSizeType;
+ double m_mathSize;
+ CharStyle m_charStyle;
+ CharFamily m_charFamily;
+ QColor m_mathColor;
+ QColor m_mathBackground;
+
+ // Deprecated MathML 1.01 attributes
+ SizeType m_fontSizeType;
+ double m_fontSize;
+ QString m_fontFamily;
+ QColor m_color;
+ bool m_fontWeight;
+ bool m_fontStyle;
+
+ // MathML 2.0 attributes set ?
+ bool m_customMathVariant;
+ bool m_customMathColor;
+ bool m_customMathBackground;
+
+ // Deprecated MathML 1.01 attributes set ?
+ bool m_customFontWeight;
+ bool m_customFontStyle;
+ bool m_customFontFamily;
+ bool m_customColor;
+};
+
+KFORMULA_NAMESPACE_END
+
+#endif // TOKENSTYLEELEMENT_H
diff --git a/lib/kformula/unicodetable.cc b/lib/kformula/unicodetable.cc
new file mode 100644
index 00000000..23dc8636
--- /dev/null
+++ b/lib/kformula/unicodetable.cc
@@ -0,0 +1,546 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
+
+ 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.
+*/
+
+KFORMULA_NAMESPACE_BEGIN
+
+struct UnicodeNameTable { short unicode; const char* name; };
+
+static UnicodeNameTable greekTable[] = {
+ { 0x03B1, "alpha" },
+ { 0x03B2, "beta" },
+ { 0x03B3, "gamma" },
+ { 0x03B4, "delta" },
+ { 0x03B5, "epsilon" },
+ { 0x03F5, "varepsilon" },
+ { 0x03B6, "zeta" },
+ { 0x03B7, "eta" },
+ { 0x03B8, "theta" },
+ { 0x03D1, "vartheta" },
+ { 0x03B9, "iota" },
+ { 0x03BA, "kappa" },
+ { 0x03F0, "varkappa" },
+ { 0x03BB, "lambda" },
+ { 0x03BC, "mu" },
+ { 0x03BD, "nu" },
+ { 0x03BE, "xi" },
+ { 0x03C0, "pi" },
+ { 0x03D6, "varpi" },
+ { 0x03C1, "rho" },
+ { 0x03F1, "varrho" },
+ { 0x03C3, "sigma" },
+ { 0x03C2, "varsigma" },
+ { 0x03C4, "tau" },
+ { 0x03C5, "upsilon" },
+ { 0x03D5, "phi" },
+ { 0x03C6, "varphi" },
+ { 0x03C7, "chi" },
+ { 0x03C8, "psi" },
+ { 0x03C9, "omega" },
+ { 0x0393, "Gamma" },
+ { 0x0394, "Delta" },
+ { 0x0398, "Theta" },
+ { 0x039B, "Lambda" },
+ { 0x039E, "Xi" },
+ { 0x03A0, "Pi" },
+ { 0x03A3, "Sigma" },
+ { 0x03D2, "Upsilon" },
+ { 0x03A6, "Phi" },
+ { 0x03A8, "Psi" },
+ { 0x03A9, "Omega" },
+ { 0, 0 }
+};
+
+static UnicodeNameTable arrowTable[] = {
+ { 0x2190, "leftarrow" },
+ { 0x2191, "uparrow" },
+ { 0x2192, "rightarrow" },
+ { 0x2193, "downarrow" },
+ { 0x2194, "leftrightarrow" },
+ { 0x2195, "updownarrow" },
+ { 0x2196, "nwarrow" },
+ { 0x2197, "nearrow" },
+ { 0x2198, "searrow" },
+ { 0x2199, "swarrow" },
+ { 0x219A, "nleftarrow" },
+ { 0x219B, "nrightarrow" },
+ { 0x219C, "" },
+ { 0x219D, "rightsquigarrow" },
+ { 0x219E, "twoheadleftarrow" },
+ { 0x219F, "" },
+ { 0x21A0, "twoheadrightarrow" },
+ { 0x21A1, "" },
+ { 0x21A2, "leftarrowtail" },
+ { 0x21A3, "rightarrowtail" },
+ { 0x21A4, "" },
+ { 0x21A5, "" },
+ { 0x21A6, "mapsto" },
+ { 0x21A7, "" },
+ { 0x21A8, "" },
+ { 0x21A9, "hookleftarrow" },
+ { 0x21AA, "hookrightarrow" },
+ { 0x21AB, "looparrowleft" },
+ { 0x21AC, "looparrowright" },
+ { 0x21AD, "leftrightsquigarrow" },
+ { 0x21AE, "nleftrightarrow" },
+ { 0x21AF, "" },
+ { 0x21B0, "Lsh" },
+ { 0x21B1, "Rsh" },
+ { 0x21B2, "" },
+ { 0x21B3, "" },
+ { 0x21B4, "" },
+ { 0x21B5, "carriagereturn" },
+ { 0x21B6, "curvearrowleft" },
+ { 0x21B7, "curvearrowright" },
+ { 0x21B8, "" },
+ { 0x21B9, "" },
+ { 0x21BA, "acwopencirclearrow" },
+ { 0x21BB, "cwopencirclearrow" },
+ { 0x21BC, "leftharpoonup" },
+ { 0x21BD, "leftharpoondown" },
+ { 0x21BE, "upharpoonright" },
+ { 0x21BF, "upharpoonleft" },
+ { 0x21C0, "rightharpoonup" },
+ { 0x21C1, "rightharpoondown" },
+ { 0x21C2, "downharpoonright" },
+ { 0x21C3, "downharpoonleft" },
+ { 0x21C4, "rightleftarrows" },
+ { 0x21C5, "" },
+ { 0x21C6, "leftrightarrows" },
+ { 0x21C7, "leftleftarrows" },
+ { 0x21C8, "upuparrows" },
+ { 0x21C9, "rightrightarrows" },
+ { 0x21CA, "downdownarrows" },
+ { 0x21CB, "leftrightharpoons" },
+ { 0x21CC, "rightleftharpoons" },
+ { 0x21CD, "nLeftarrow" },
+ { 0x21CE, "nLeftrightarrow" },
+ { 0x21CF, "nRightarrow" },
+ { 0x21D0, "Leftarrow" },
+ { 0x21D1, "Uparrow" },
+ { 0x21D2, "Rightarrow" },
+ { 0x21D3, "Downarrow" },
+ { 0x21D4, "Leftrightarrow" },
+ { 0x21D5, "Updownarrow" },
+ { 0x21D6, "" },
+ { 0x21D7, "" },
+ { 0x21D8, "" },
+ { 0x21D9, "" },
+ { 0x21DA, "Lleftarrow" },
+ { 0x21DB, "Rrightarrow" },
+ { 0x21DC, "" },
+ { 0x21DD, "rightzigzagarrow" },
+ { 0x21DE, "" },
+ { 0x21DF, "" },
+ { 0x21E0, "" },
+ { 0x21E1, "" },
+ { 0x21E2, "" },
+ { 0x21E3, "" },
+ { 0x21E4, "" },
+ { 0x21E5, "" },
+ { 0x21E6, "" },
+ { 0x21E7, "" },
+ { 0x21E8, "" },
+ { 0x21E9, "" },
+ { 0x21EA, "" },
+ { 0x21EB, "" },
+ { 0x21EC, "" },
+ { 0x21ED, "" },
+ { 0x21EE, "" },
+ { 0x21EF, "" },
+ { 0x21F0, "" },
+ { 0x21F1, "" },
+ { 0x21F2, "" },
+ { 0x21F3, "" },
+ { 0x21F4, "" },
+ { 0x21F5, "" },
+ { 0x21F6, "" },
+ { 0x21F7, "" },
+ { 0x21F8, "" },
+ { 0x21F9, "" },
+ { 0x21FA, "" },
+ { 0x21FB, "" },
+ { 0x21FC, "" },
+ { 0x21FD, "" },
+ { 0x21FE, "" },
+ { 0x21FF, "" },
+ { 0, 0 }
+};
+
+/*
+ { 0x003A, "colon" },
+ { 0x003A, "colon" },
+ { 0x003C, "less" },
+ { 0x003C, "less" },
+ { 0x003E, "greater" },
+ { 0x003E, "greater" },
+ { 0x005C, "backslash" },
+ { 0x005E, "textasciicircum" },
+ { 0x007B, "lbrace" },
+ { 0x007C, "vert" },
+ { 0x007D, "rbrace" },
+ { 0x007E, "textasciitilde" },
+ { 0x00A1, "textexclamdown" },
+ { 0x00A7, "S" },
+ { 0x00AC, "neg" },
+ { 0x00B0, "degree" },
+ { 0x00B1, "pm" },
+ { 0x00B6, "P" },
+ { 0x00BF, "textquestiondown" },
+ { 0x00D7, "times" },
+ { 0x00D8, "O" },
+ { 0x00F7, "div" },
+ { 0x00F8, "o" },
+ { 0x019B, "lambdabar" },
+ { 0x0300, "grave" },
+ { 0x0301, "acute" },
+ { 0x0302, "hat" },
+ { 0x0304, "bar" },
+ { 0x030A, "ocirc" },
+ { 0x0338, "not" },
+ { 0x2013, "endash" },
+ { 0x2014, "emdash" },
+ { 0x2022, "bullet" },
+ { 0x2026, "ldots" },
+ { 0x2032, "prime" },
+ { 0x2035, "backprime" },
+ { 0x20D0, "leftharpoonaccent" },
+ { 0x20D1, "rightharpoonaccent" },
+ { 0x20D6, "overleftarrow" },
+ { 0x20D7, "vec" },
+ { 0x20E1, "overleftrightarrow" },
+ { 0x2111, "Im" },
+ { 0x2118, "wp" },
+ { 0x211C, "Re" },
+ { 0x2127, "mho" },
+ { 0x2309, "rceil" },
+ { 0x2329, "langle" },
+ { 0x232A, "rangle" },
+ { 0x24C8, "circledS" },
+ { 0x25B3, "bigtriangleup" },
+ { 0x25B4, "blacktriangle" },
+ { 0x25B5, "vartriangle" },
+ { 0x25B6, "blacktriangleright" },
+ { 0x25BD, "bigtriangledown" },
+ { 0x25BE, "blacktriangledown" },
+ { 0x25C0, "blacktriangleleft" },
+ { 0x25CB, "bigcirc" },
+ { 0x2605, "bigstar" },
+ { 0x2660, "spadesuit" },
+ { 0x2661, "heartsuit" },
+ { 0x2662, "diamondsuit" },
+ { 0x2663, "clubsuit" },
+ { 0x2666, "diamondsuit" },
+ { 0x266D, "flat" },
+ { 0x266E, "natural" },
+ { 0x266F, "sharp" },
+ { 0x2713, "checkmark" },
+ { 0x2720, "maltese" },
+ { 0xE201, "longleftarrow" },
+ { 0xE205, "longrightarrow" },
+ { 0xE29F, "gnapprox" },
+ { 0xE2A0, "gneq" },
+ { 0xE2A3, "lneq" },
+ { 0xE2A6, "ngeqslant" },
+ { 0xE2A7, "nleqslant" },
+ { 0xE2A8, "nleqq" },
+ { 0xE2B0, "nsupseteqq" },
+ { 0xE2B2, "precnapprox" },
+ { 0xE2B4, "succnapprox" },
+ { 0xE2B6, "subsetneqq" },
+ { 0xE2B7, "supsetneqq" },
+ { 0xE2B8, "varsubsetneqq" },
+ { 0xE2B9, "varsubsetneq" },
+ { 0xE2BA, "varsupsetneq" },
+ { 0xE2BB, "varsupsetneqq" },
+ { 0xE2F4, "gtrapprox" },
+ { 0xE2F5, "gtreqqless" },
+ { 0xE2F6, "geqslant" },
+ { 0xE2F8, "lessapprox" },
+ { 0xE2F9, "lesseqqgtr" },
+ { 0xE2FA, "leqslant" },
+ { 0xE2FD, "precapprox" },
+ { 0xE2FE, "preceq" },
+ { 0xE2FF, "succapprox" },
+ { 0xE300, "succeq" },
+ { 0xE304, "subseteqq" },
+ { 0xE305, "supseteqq" },
+ { 0xE5CF, "eqslantless" },
+ { 0xE5DC, "npreceq" },
+ { 0xE5F1, "nsucceq" },
+ { 0xE663, "Upsilon" },
+*/
+
+static UnicodeNameTable operatorTable[] = {
+ { 0x2200, "forall" },
+ { 0x2201, "complement" },
+ { 0x2202, "partial" },
+ { 0x2203, "exists" },
+ { 0x2204, "nexists" },
+ { 0x2205, "oslash" },
+ { 0x2206, "triangle" },
+ { 0x2207, "nabla" },
+ { 0x2208, "in" },
+ { 0x2209, "notin" },
+ { 0x220A, "in" },
+ { 0x220B, "ni" },
+ { 0x220C, "" },
+ { 0x220D, "ni" },
+ { 0x220E, "blacksquare" },
+ { 0x220F, "prod" },
+ { 0x2210, "coprod" },
+ { 0x2211, "sum" },
+ { 0x2212, "minus" },
+ { 0x2213, "mp" },
+ { 0x2214, "dotplus" },
+ { 0x2215, "slash" },
+ { 0x2216, "setminus" },
+ { 0x2217, "ast" },
+ { 0x2218, "circ" },
+ { 0x2219, "bullet" },
+ { 0x221A, "surd" },
+ { 0x221B, "" },
+ { 0x221C, "" },
+ { 0x221D, "propto" },
+ { 0x221E, "infty" },
+ { 0x221F, "" },
+ { 0x2220, "angle" },
+ { 0x2221, "measuredangle" },
+ { 0x2222, "" },
+ { 0x2223, "mid" },
+ { 0x2224, "nmid" },
+ { 0x2225, "parallel" },
+ { 0x2226, "nparallel" },
+ { 0x2227, "wedge" },
+ { 0x2228, "vee" },
+ { 0x2229, "cap" },
+ { 0x222A, "cup" },
+ { 0x222B, "int" },
+ { 0x222C, "" },
+ { 0x222D, "" },
+ { 0x222E, "oint" },
+ { 0x222F, "" },
+ { 0x2230, "" },
+ { 0x2231, "" },
+ { 0x2232, "" },
+ { 0x2233, "" },
+ { 0x2234, "therefore" },
+ { 0x2235, "because" },
+ { 0x2236, "" },
+ { 0x2237, "" },
+ { 0x2238, "" },
+ { 0x2239, "" },
+ { 0x223A, "" },
+ { 0x223B, "" },
+ { 0x223C, "sim" },
+ { 0x223D, "backsim" },
+ { 0x223E, "" },
+ { 0x223F, "" },
+ { 0x2240, "wr" },
+ { 0x2241, "" },
+ { 0x2242, "eqsim" },
+ { 0x2243, "simeq" },
+ { 0x2244, "nsime" },
+ { 0x2245, "cong" },
+ { 0x2246, "" },
+ { 0x2247, "ncong" },
+ { 0x2248, "approx" },
+ { 0x2249, "" },
+ { 0x224A, "approxeq" },
+ { 0x224B, "" },
+ { 0x224C, "" },
+ { 0x224D, "asymp" },
+ { 0x224E, "Bumpeq" },
+ { 0x224F, "bumpeq" },
+ { 0x2250, "doteq" },
+ { 0x2251, "Doteq" },
+ { 0x2252, "fallingdotseq" },
+ { 0x2253, "risingdotseq" },
+ { 0x2254, "" },
+ { 0x2255, "" },
+ { 0x2256, "eqcirc" },
+ { 0x2257, "circeq" },
+ { 0x2258, "" },
+ { 0x2259, "wedgeq" },
+ { 0x225A, "" },
+ { 0x225B, "" },
+ { 0x225C, "triangleq" },
+ { 0x225D, "" },
+ { 0x225E, "" },
+ { 0x225F, "" },
+ { 0x2260, "neq" },
+ { 0x2261, "equiv" },
+ { 0x2262, "" },
+ { 0x2263, "" },
+ { 0x2264, "leq" },
+ { 0x2265, "geq" },
+ { 0x2266, "leqq" },
+ { 0x2267, "geqq" },
+ { 0x2268, "" },
+ { 0x2269, "" },
+ { 0x226A, "ll" },
+ { 0x226B, "gg" },
+ { 0x226C, "between" },
+ { 0x226D, "" },
+ { 0x226E, "nless" },
+ { 0x226F, "ngtr" },
+ { 0x2270, "nleq" },
+ { 0x2271, "ngeq" },
+ { 0x2272, "lesssim" },
+ { 0x2273, "gtrsim" },
+ { 0x2274, "" },
+ { 0x2275, "" },
+ { 0x2276, "lessgtr" },
+ { 0x2277, "gtrless" },
+ { 0x2278, "" },
+ { 0x2279, "" },
+ { 0x227A, "prec" },
+ { 0x227B, "succ" },
+ { 0x227C, "preccurlyeq" },
+ { 0x227D, "succcurlyeq" },
+ { 0x227E, "precsim" },
+ { 0x227F, "succsim" },
+ { 0x2280, "nprec" },
+ { 0x2281, "nsucc" },
+ { 0x2282, "subset" },
+ { 0x2283, "supset" },
+ { 0x2284, "nsubset" },
+ { 0x2286, "subseteq" },
+ { 0x2287, "supseteq" },
+ { 0x2288, "nsubseteq" },
+ { 0x2289, "nsupseteq" },
+ { 0x228A, "subsetneq" },
+ { 0x228B, "supsetneq" },
+ { 0x228C, "" },
+ { 0x228D, "" },
+ { 0x228E, "uplus" },
+ { 0x228F, "sqsubset" },
+ { 0x2290, "sqsupset" },
+ { 0x2291, "sqsubseteq" },
+ { 0x2292, "sqsupseteq" },
+ { 0x2293, "sqcap" },
+ { 0x2294, "sqcup" },
+ { 0x2295, "oplus" },
+ { 0x2296, "ominus" },
+ { 0x2297, "otimes" },
+ { 0x2298, "oslash" },
+ { 0x2299, "odot" },
+ { 0x229A, "circledcirc" },
+ { 0x229B, "circledast" },
+ { 0x229C, "" },
+ { 0x229D, "circleddash" },
+ { 0x229E, "boxplus" },
+ { 0x229F, "boxminus" },
+ { 0x22A0, "boxtimes" },
+ { 0x22A1, "boxdot" },
+ { 0x22A2, "" },
+ { 0x22A3, "dashv" },
+ { 0x22A4, "top" },
+ { 0x22A5, "" },
+ { 0x22A6, "" },
+ { 0x22A7, "" },
+ { 0x22A8, "vDash" },
+ { 0x22A9, "Vdash" },
+ { 0x22AA, "Vvdash" },
+ { 0x22AB, "" },
+ { 0x22AC, "nvdash" },
+ { 0x22AD, "nvDash" },
+ { 0x22AE, "nVdash" },
+ { 0x22AF, "nVDash" },
+ { 0x22B1, "" },
+ { 0x22B2, "vartriangleleft" },
+ { 0x22B3, "vartriangleright" },
+ { 0x22B4, "trianglelefteq" },
+ { 0x22B5, "trianglerighteq" },
+ { 0x22B6, "" },
+ { 0x22B7, "" },
+ { 0x22B8, "multimap" },
+ { 0x22B9, "" },
+ { 0x22BA, "intercal" },
+ { 0x22BB, "veebar" },
+ { 0x22BC, "barwedge" },
+ { 0x22BD, "" },
+ { 0x22BE, "" },
+ { 0x22BF, "" },
+ { 0x22C1, "" },
+ { 0x22C2, "" },
+ { 0x22C3, "" },
+ { 0x22C4, "diamond" },
+ { 0x22C5, "cdot" },
+ { 0x22C6, "star" },
+ { 0x22C7, "divideontimes" },
+ { 0x22C8, "" },
+ { 0x22C9, "ltimes" },
+ { 0x22CA, "rtimes" },
+ { 0x22CB, "leftthreetimes" },
+ { 0x22CC, "rightthreetimes" },
+ { 0x22CD, "backsimeq" },
+ { 0x22CE, "curlyvee" },
+ { 0x22CF, "curlywedge" },
+ { 0x22D0, "Subset" },
+ { 0x22D1, "Supset" },
+ { 0x22D2, "Cap" },
+ { 0x22D3, "Cup" },
+ { 0x22D4, "pitchfork" },
+ { 0x22D5, "" },
+ { 0x22D6, "lessdot" },
+ { 0x22D7, "gtrdot" },
+ { 0x22D8, "lll" },
+ { 0x22D9, "ggg" },
+ { 0x22DA, "lesseqgtr" },
+ { 0x22DB, "gtreqless" },
+ { 0x22DC, "eqless" },
+ { 0x22DD, "eqgtr" },
+ { 0x22DE, "curlyeqprec" },
+ { 0x22DF, "curlyeqsucc" },
+ { 0x22E0, "" },
+ { 0x22E1, "" },
+ { 0x22E2, "" },
+ { 0x22E3, "" },
+ { 0x22E4, "" },
+ { 0x22E5, "" },
+ { 0x22E6, "lnsim" },
+ { 0x22E7, "gnsim" },
+ { 0x22E8, "precnsim" },
+ { 0x22E9, "succnsim" },
+ { 0x22EA, "ntriangleleft" },
+ { 0x22EB, "ntriangleright" },
+ { 0x22EC, "ntrianglelefteq" },
+ { 0x22ED, "ntrianglerighteq" },
+ { 0x22EE, "vdots" },
+ { 0x22EF, "cdots" },
+ { 0x22F0, "adots" },
+ { 0x22F1, "ddots" },
+ { 0x22F2, "" },
+ { 0x22F3, "" },
+ { 0x22F4, "" },
+ { 0x22F5, "" },
+ { 0x22F6, "" },
+ { 0x22F7, "" },
+ { 0x22F8, "" },
+ { 0x22F9, "" },
+ { 0x22FA, "" },
+ { 0x22FB, "" },
+ { 0x22FC, "" },
+ { 0x22FD, "" },
+ { 0x22FE, "" },
+ { 0x22FF, "" },
+ { 0, 0 }
+};
+
+KFORMULA_NAMESPACE_END