diff options
Diffstat (limited to 'lib/kformula')
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 Binary files differnew file mode 100644 index 00000000..80ae5e82 --- /dev/null +++ b/lib/kformula/fonts/Arev.ttf diff --git a/lib/kformula/fonts/ArevBI.ttf b/lib/kformula/fonts/ArevBI.ttf Binary files differnew file mode 100644 index 00000000..bbec526a --- /dev/null +++ b/lib/kformula/fonts/ArevBI.ttf diff --git a/lib/kformula/fonts/ArevBd.ttf b/lib/kformula/fonts/ArevBd.ttf Binary files differnew file mode 100644 index 00000000..481154ff --- /dev/null +++ b/lib/kformula/fonts/ArevBd.ttf diff --git a/lib/kformula/fonts/ArevIt.ttf b/lib/kformula/fonts/ArevIt.ttf Binary files differnew file mode 100644 index 00000000..7501028f --- /dev/null +++ b/lib/kformula/fonts/ArevIt.ttf 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 Binary files differnew file mode 100644 index 00000000..e4b468dc --- /dev/null +++ b/lib/kformula/fonts/cmex10.ttf 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 "[0m" +//#define TERM_ERROR "[40;31;m" + +/** + * 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 Binary files differnew file mode 100644 index 00000000..13415c4a --- /dev/null +++ b/lib/kformula/oldformula 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 Binary files differnew file mode 100644 index 00000000..67bd6c47 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-abs.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-brackets.png b/lib/kformula/pics/crystalsvg/cr16-action-brackets.png Binary files differnew file mode 100644 index 00000000..bb9cd45b --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-brackets.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-frac.png b/lib/kformula/pics/crystalsvg/cr16-action-frac.png Binary files differnew file mode 100644 index 00000000..c6f6ba88 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-frac.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-gsub.png b/lib/kformula/pics/crystalsvg/cr16-action-gsub.png Binary files differnew file mode 100644 index 00000000..76b3ac78 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-gsub.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-gsup.png b/lib/kformula/pics/crystalsvg/cr16-action-gsup.png Binary files differnew file mode 100644 index 00000000..0508bc09 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-gsup.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-int.png b/lib/kformula/pics/crystalsvg/cr16-action-int.png Binary files differnew file mode 100644 index 00000000..466688eb --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-int.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-lsub.png b/lib/kformula/pics/crystalsvg/cr16-action-lsub.png Binary files differnew file mode 100644 index 00000000..559e2c26 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-lsub.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-lsup.png b/lib/kformula/pics/crystalsvg/cr16-action-lsup.png Binary files differnew file mode 100644 index 00000000..b7b6a493 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-lsup.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-matrix.png b/lib/kformula/pics/crystalsvg/cr16-action-matrix.png Binary files differnew file mode 100644 index 00000000..73052f50 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-matrix.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-multiline.png b/lib/kformula/pics/crystalsvg/cr16-action-multiline.png Binary files differnew file mode 100644 index 00000000..2f7d152e --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-multiline.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-onetwomatrix.png b/lib/kformula/pics/crystalsvg/cr16-action-onetwomatrix.png Binary files differnew file mode 100644 index 00000000..23480f19 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-onetwomatrix.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-over.png b/lib/kformula/pics/crystalsvg/cr16-action-over.png Binary files differnew file mode 100644 index 00000000..df10be73 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-over.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-paren.png b/lib/kformula/pics/crystalsvg/cr16-action-paren.png Binary files differnew file mode 100644 index 00000000..e0513a07 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-paren.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-prod.png b/lib/kformula/pics/crystalsvg/cr16-action-prod.png Binary files differnew file mode 100644 index 00000000..6bdafd79 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-prod.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-rsub.png b/lib/kformula/pics/crystalsvg/cr16-action-rsub.png Binary files differnew file mode 100644 index 00000000..f616d8b2 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-rsub.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-rsup.png b/lib/kformula/pics/crystalsvg/cr16-action-rsup.png Binary files differnew file mode 100644 index 00000000..1d2f8aad --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-rsup.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-sqrt.png b/lib/kformula/pics/crystalsvg/cr16-action-sqrt.png Binary files differnew file mode 100644 index 00000000..c28906ed --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-sqrt.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-sum.png b/lib/kformula/pics/crystalsvg/cr16-action-sum.png Binary files differnew file mode 100644 index 00000000..599135d4 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-sum.png diff --git a/lib/kformula/pics/crystalsvg/cr16-action-under.png b/lib/kformula/pics/crystalsvg/cr16-action-under.png Binary files differnew file mode 100644 index 00000000..c9f425b5 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr16-action-under.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-abs.png b/lib/kformula/pics/crystalsvg/cr22-action-abs.png Binary files differnew file mode 100644 index 00000000..030e8fba --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-abs.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-brackets.png b/lib/kformula/pics/crystalsvg/cr22-action-brackets.png Binary files differnew file mode 100644 index 00000000..bb67db9e --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-brackets.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-frac.png b/lib/kformula/pics/crystalsvg/cr22-action-frac.png Binary files differnew file mode 100644 index 00000000..2cbce42b --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-frac.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-gsub.png b/lib/kformula/pics/crystalsvg/cr22-action-gsub.png Binary files differnew file mode 100644 index 00000000..e1cbcb14 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-gsub.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-gsup.png b/lib/kformula/pics/crystalsvg/cr22-action-gsup.png Binary files differnew file mode 100644 index 00000000..69f9a6f1 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-gsup.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-inscol.png b/lib/kformula/pics/crystalsvg/cr22-action-inscol.png Binary files differnew file mode 100644 index 00000000..d00db768 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-inscol.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-insrow.png b/lib/kformula/pics/crystalsvg/cr22-action-insrow.png Binary files differnew file mode 100644 index 00000000..90603888 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-insrow.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-int.png b/lib/kformula/pics/crystalsvg/cr22-action-int.png Binary files differnew file mode 100644 index 00000000..691742f1 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-int.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-lsub.png b/lib/kformula/pics/crystalsvg/cr22-action-lsub.png Binary files differnew file mode 100644 index 00000000..151d3235 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-lsub.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-lsup.png b/lib/kformula/pics/crystalsvg/cr22-action-lsup.png Binary files differnew file mode 100644 index 00000000..f42d3b33 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-lsup.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-matrix.png b/lib/kformula/pics/crystalsvg/cr22-action-matrix.png Binary files differnew file mode 100644 index 00000000..a5320a90 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-matrix.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-multiline.png b/lib/kformula/pics/crystalsvg/cr22-action-multiline.png Binary files differnew file mode 100644 index 00000000..44585275 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-multiline.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-onetwomatrix.png b/lib/kformula/pics/crystalsvg/cr22-action-onetwomatrix.png Binary files differnew file mode 100644 index 00000000..e2320742 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-onetwomatrix.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-over.png b/lib/kformula/pics/crystalsvg/cr22-action-over.png Binary files differnew file mode 100644 index 00000000..012fd3f8 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-over.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-paren.png b/lib/kformula/pics/crystalsvg/cr22-action-paren.png Binary files differnew file mode 100644 index 00000000..98a3b98c --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-paren.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-prod.png b/lib/kformula/pics/crystalsvg/cr22-action-prod.png Binary files differnew file mode 100644 index 00000000..1e6e691e --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-prod.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-remcol.png b/lib/kformula/pics/crystalsvg/cr22-action-remcol.png Binary files differnew file mode 100644 index 00000000..343af86e --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-remcol.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-remrow.png b/lib/kformula/pics/crystalsvg/cr22-action-remrow.png Binary files differnew file mode 100644 index 00000000..6af59af7 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-remrow.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-rsub.png b/lib/kformula/pics/crystalsvg/cr22-action-rsub.png Binary files differnew file mode 100644 index 00000000..9dc6741b --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-rsub.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-rsup.png b/lib/kformula/pics/crystalsvg/cr22-action-rsup.png Binary files differnew file mode 100644 index 00000000..77dd5c36 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-rsup.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-sqrt.png b/lib/kformula/pics/crystalsvg/cr22-action-sqrt.png Binary files differnew file mode 100644 index 00000000..a63d5d2a --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-sqrt.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-sum.png b/lib/kformula/pics/crystalsvg/cr22-action-sum.png Binary files differnew file mode 100644 index 00000000..9ffd657d --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-sum.png diff --git a/lib/kformula/pics/crystalsvg/cr22-action-under.png b/lib/kformula/pics/crystalsvg/cr22-action-under.png Binary files differnew file mode 100644 index 00000000..a16d6e0a --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr22-action-under.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-abs.png b/lib/kformula/pics/crystalsvg/cr32-action-abs.png Binary files differnew file mode 100644 index 00000000..c11a8b0d --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-abs.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-brackets.png b/lib/kformula/pics/crystalsvg/cr32-action-brackets.png Binary files differnew file mode 100644 index 00000000..a0cec66e --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-brackets.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-frac.png b/lib/kformula/pics/crystalsvg/cr32-action-frac.png Binary files differnew file mode 100644 index 00000000..a962f701 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-frac.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-gsub.png b/lib/kformula/pics/crystalsvg/cr32-action-gsub.png Binary files differnew file mode 100644 index 00000000..42e05816 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-gsub.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-gsup.png b/lib/kformula/pics/crystalsvg/cr32-action-gsup.png Binary files differnew file mode 100644 index 00000000..86db0f8c --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-gsup.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-int.png b/lib/kformula/pics/crystalsvg/cr32-action-int.png Binary files differnew file mode 100644 index 00000000..df684d64 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-int.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-lsub.png b/lib/kformula/pics/crystalsvg/cr32-action-lsub.png Binary files differnew file mode 100644 index 00000000..dccd32b5 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-lsub.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-lsup.png b/lib/kformula/pics/crystalsvg/cr32-action-lsup.png Binary files differnew file mode 100644 index 00000000..440ef334 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-lsup.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-matrix.png b/lib/kformula/pics/crystalsvg/cr32-action-matrix.png Binary files differnew file mode 100644 index 00000000..45a57805 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-matrix.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-multiline.png b/lib/kformula/pics/crystalsvg/cr32-action-multiline.png Binary files differnew file mode 100644 index 00000000..3ca06a77 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-multiline.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-onetwomatrix.png b/lib/kformula/pics/crystalsvg/cr32-action-onetwomatrix.png Binary files differnew file mode 100644 index 00000000..ebe7d639 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-onetwomatrix.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-over.png b/lib/kformula/pics/crystalsvg/cr32-action-over.png Binary files differnew file mode 100644 index 00000000..3eadf6d3 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-over.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-paren.png b/lib/kformula/pics/crystalsvg/cr32-action-paren.png Binary files differnew file mode 100644 index 00000000..42ad7eac --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-paren.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-prod.png b/lib/kformula/pics/crystalsvg/cr32-action-prod.png Binary files differnew file mode 100644 index 00000000..a0a0ed0e --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-prod.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-rsub.png b/lib/kformula/pics/crystalsvg/cr32-action-rsub.png Binary files differnew file mode 100644 index 00000000..298d4aa8 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-rsub.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-rsup.png b/lib/kformula/pics/crystalsvg/cr32-action-rsup.png Binary files differnew file mode 100644 index 00000000..c2282e0a --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-rsup.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-sqrt.png b/lib/kformula/pics/crystalsvg/cr32-action-sqrt.png Binary files differnew file mode 100644 index 00000000..028f4a92 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-sqrt.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-sum.png b/lib/kformula/pics/crystalsvg/cr32-action-sum.png Binary files differnew file mode 100644 index 00000000..6d7dc2b1 --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-sum.png diff --git a/lib/kformula/pics/crystalsvg/cr32-action-under.png b/lib/kformula/pics/crystalsvg/cr32-action-under.png Binary files differnew file mode 100644 index 00000000..a7d6500a --- /dev/null +++ b/lib/kformula/pics/crystalsvg/cr32-action-under.png 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], '&', '&' ) + 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 |