/* This file is part of the KDE project Copyright (C) 2001 Andrea Rizzi Ulrich Kuettler 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 #include #include #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* tqparent = 0 ) : SequenceElement( tqparent ) {} 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( getParent() ); IndexRequest* ir = static_cast( 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* tqparent) : BasicElement(tqparent), 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( 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 ); } TQChar IndexElement::getCharacter() const { if ( !content->isTextOnly() ) { return TQChar::null; } if ( hasUpperRight() && !upperRight->isTextOnly() ) { return TQChar::null; } if ( hasUpperMiddle() && !upperMiddle->isTextOnly() ) { return TQChar::null; } if ( hasUpperLeft() && !upperLeft->isTextOnly() ) { return TQChar::null; } if ( hasLowerRight() && !lowerRight->isTextOnly() ) { return TQChar::null; } if ( hasLowerMiddle() && !lowerMiddle->isTextOnly() ) { return TQChar::null; } if ( hasLowerLeft() && !lowerLeft->isTextOnly() ) { return TQChar::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& tqparentOrigin ) { BasicElement* e = BasicElement::goToPos(cursor, handled, point, tqparentOrigin); if (e != 0) { LuPixelPoint myPos(tqparentOrigin.x()+getX(), tqparentOrigin.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 tqchildren's tqparentPosition. */ 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 = TQMAX(content->getWidth(), TQMAX(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 += TQMAX(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 ); TQFont font = context.getDefaultFont(); font.setPointSizeFloat( context.tqlayoutUnitPtToPt( mySize ) ); TQFontMetrics 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 = TQMAX(ulMidline, ulHeight-toMidline); urOffset = TQMAX(urMidline, urHeight-toMidline); // the lower half llOffset = TQMAX(content->getHeight()-llMidline, toMidline); lrOffset = TQMAX(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 = TQMAX(umHeight, TQMAX(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 += TQMAX(TQMAX(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 tqchildren. * The `tqparentOrigin' is the point this element's tqparent starts. * We can use our tqparentPosition to get our own origin then. */ void IndexElement::draw( TQPainter& painter, const LuPixelRect& r, const ContextStyle& context, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes& style, const LuPixelPoint& tqparentOrigin ) { LuPixelPoint myPos( tqparentOrigin.x()+getX(), tqparentOrigin.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(TQt::NoBrush); //painter.setPen(TQt::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 tqparentPos; } /** * 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 tqparentPos: 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 tqparentPos: 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); } } } // tqchildren // main child // // If an element has tqchildren 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 tqchildren 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, TQPtrList& newChildren, Direction direction) { SequenceElement* index = static_cast(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 tqchildren and returns them. Places the * cursor to where the tqchildren 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, TQPtrList& 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* tqparent = getParent(); tqparent->selectChild(cursor, this); tqparent->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 * tqchildren (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(TQDomElement element) { BasicElement::writeDom(element); TQDomDocument doc = element.ownerDocument(); TQDomElement cont = doc.createElement("CONTENT"); cont.appendChild(content->getElementDom(doc)); element.appendChild(cont); if (hasUpperLeft()) { TQDomElement ind = doc.createElement("UPPERLEFT"); ind.appendChild(upperLeft->getElementDom(doc)); element.appendChild(ind); } if (hasUpperMiddle()) { TQDomElement ind = doc.createElement("UPPERMIDDLE"); ind.appendChild(upperMiddle->getElementDom(doc)); element.appendChild(ind); } if (hasUpperRight()) { TQDomElement ind = doc.createElement("UPPERRIGHT"); ind.appendChild(upperRight->getElementDom(doc)); element.appendChild(ind); } if (hasLowerLeft()) { TQDomElement ind = doc.createElement("LOWERLEFT"); ind.appendChild(lowerLeft->getElementDom(doc)); element.appendChild(ind); } if (hasLowerMiddle()) { TQDomElement ind = doc.createElement("LOWERMIDDLE"); ind.appendChild(lowerMiddle->getElementDom(doc)); element.appendChild(ind); } if (hasLowerRight()) { TQDomElement 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(TQDomElement 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(TQDomNode& 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 TQDomElement& element ) { if ( !BasicElement::readAttributesFromMathMLDom( element ) ) { return false; } TQString tag = element.tagName().stripWhiteSpace().lower(); if ( tag == "msub" || tag == "msubsup" ) { TQString subscriptshiftStr = element.attribute( "subscriptshift" ).stripWhiteSpace().lower(); if ( ! subscriptshiftStr.isNull() ) { m_subScriptShift = getSize( subscriptshiftStr, &m_subScriptShiftType ); } } if ( tag == "msup" || tag == "msubsup" ) { TQString superscriptshiftStr = element.attribute( "superscriptshift" ).stripWhiteSpace().lower(); if ( ! superscriptshiftStr.isNull() ) { m_superScriptShift = getSize( superscriptshiftStr, &m_superScriptShiftType ); } } if ( tag == "munder" || tag == "munderover" ) { TQString 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" ) { TQString 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( TQDomNode& 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(); } TQString indexType = node.tqparentNode().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(); } TQString IndexElement::toLatex() { TQString 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; } TQString IndexElement::formulaString() { TQString index = "(" + content->formulaString() + ")"; if ( hasLowerRight() ) { index += "_(" + lowerRight->formulaString() + ")"; } if ( hasUpperRight() ) { index += "**(" + upperRight->formulaString() + ")"; } return index; } TQString 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( TQDomElement& element ) const { TQString tag = getElementName(); if ( tag == "msub" || tag == "msubsup" ) { switch ( m_subScriptShiftType ) { case AbsoluteSize: element.setAttribute( "subscriptshift", TQString( "%1pt" ).tqarg( m_subScriptShift ) ); break; case RelativeSize: element.setAttribute( "subscriptshift", TQString( "%1%" ).tqarg( m_subScriptShift * 100.0 ) ); break; case PixelSize: element.setAttribute( "subscriptshift", TQString( "%1px" ).tqarg( m_subScriptShift ) ); break; default: break; } } if ( tag == "msup" || tag == "msubsup" ) { switch ( m_superScriptShiftType ) { case AbsoluteSize: element.setAttribute( "superscriptshift", TQString( "%1pt" ).tqarg( m_superScriptShift ) ); break; case RelativeSize: element.setAttribute( "superscriptshift", TQString( "%1%" ).tqarg( m_superScriptShift * 100.0 ) ); break; case PixelSize: element.setAttribute( "superscriptshift", TQString( "%1px" ).tqarg( 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( TQDomDocument& doc, TQDomElement& element, bool oasisFormat ) const { TQDomElement 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