summaryrefslogtreecommitdiffstats
path: root/lib/kformula/indexelement.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kformula/indexelement.cc')
-rw-r--r--lib/kformula/indexelement.cc1763
1 files changed, 1763 insertions, 0 deletions
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