lib

indexelement.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
00003                   Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <qpainter.h>
00022 
00023 #include <kdebug.h>
00024 #include <klocale.h>
00025 
00026 #include "elementvisitor.h"
00027 #include "indexelement.h"
00028 #include "formulacursor.h"
00029 #include "formulaelement.h"
00030 #include "kformulacommand.h"
00031 #include "sequenceelement.h"
00032 
00033 
00034 KFORMULA_NAMESPACE_BEGIN
00035 
00036 
00037 class IndexSequenceElement : public SequenceElement {
00038     typedef SequenceElement inherited;
00039 public:
00040 
00041     IndexSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
00042     virtual IndexSequenceElement* clone() {
00043         return new IndexSequenceElement( *this );
00044     }
00045 
00054     virtual KCommand* buildCommand( Container*, Request* );
00055 };
00056 
00057 
00058 KCommand* IndexSequenceElement::buildCommand( Container* container, Request* request )
00059 {
00060     FormulaCursor* cursor = container->activeCursor();
00061     if ( cursor->isReadOnly() ) {
00062         return 0;
00063     }
00064 
00065     switch ( *request ) {
00066     case req_addIndex: {
00067         FormulaCursor* cursor = container->activeCursor();
00068         if ( cursor->isSelection() ||
00069              ( cursor->getPos() > 0 && cursor->getPos() < countChildren() ) ) {
00070             break;
00071         }
00072         IndexElement* element = static_cast<IndexElement*>( getParent() );
00073         IndexRequest* ir = static_cast<IndexRequest*>( request );
00074         ElementIndexPtr index = element->getIndex( ir->index() );
00075         if ( !index->hasIndex() ) {
00076             KFCAddGenericIndex* command = new KFCAddGenericIndex( container, index );
00077             return command;
00078         }
00079         else {
00080             index->moveToIndex( cursor, afterCursor );
00081             cursor->setSelection( false );
00082             formula()->cursorHasMoved( cursor );
00083             return 0;
00084         }
00085     }
00086     default:
00087         break;
00088     }
00089     return inherited::buildCommand( container, request );
00090 }
00091 
00092 
00093 IndexElement::IndexElement(BasicElement* parent)
00094     : BasicElement(parent),
00095       m_subScriptShiftType( NoSize ),
00096       m_superScriptShiftType( NoSize ),
00097       m_customAccentUnder( false ),
00098       m_customAccent ( false )
00099 {
00100     content = new IndexSequenceElement( this );
00101 
00102     upperLeft   = 0;
00103     upperMiddle = 0;
00104     upperRight  = 0;
00105     lowerLeft   = 0;
00106     lowerMiddle = 0;
00107     lowerRight  = 0;
00108 }
00109 
00110 IndexElement::~IndexElement()
00111 {
00112     delete content;
00113     delete upperLeft;
00114     delete upperMiddle;
00115     delete upperRight;
00116     delete lowerLeft;
00117     delete lowerMiddle;
00118     delete lowerRight;
00119 }
00120 
00121 
00122 IndexElement::IndexElement( const IndexElement& other )
00123     : BasicElement( other ),
00124       m_subScriptShiftType( other.m_subScriptShiftType ),
00125       m_subScriptShift( other.m_subScriptShift ),
00126       m_superScriptShiftType( other.m_superScriptShiftType ),
00127       m_superScriptShift( other.m_superScriptShift ),
00128       m_customAccentUnder( other.m_customAccentUnder ),
00129       m_accentUnder( other.m_accentUnder ),
00130       m_customAccent ( other.m_customAccent ),
00131       m_accent( other.m_accent )      
00132 {
00133     content = new IndexSequenceElement( *dynamic_cast<IndexSequenceElement*>( other.content ) );
00134 
00135     if ( other.upperLeft ) {
00136         upperLeft = new SequenceElement( *( other.upperLeft ) );
00137         upperLeft->setParent( this );
00138     }
00139     else {
00140         upperLeft = 0;
00141     }
00142     if ( other.upperMiddle ) {
00143         upperMiddle = new SequenceElement( *( other.upperMiddle ) );
00144         upperMiddle->setParent( this );
00145     }
00146     else {
00147         upperMiddle = 0;
00148     }
00149     if ( other.upperRight ) {
00150         upperRight = new SequenceElement( *( other.upperRight ) );
00151         upperRight->setParent( this );
00152     }
00153     else {
00154         upperRight = 0;
00155     }
00156 
00157     if ( other.lowerLeft ) {
00158         lowerLeft = new SequenceElement( *( other.lowerLeft ) );
00159         lowerLeft->setParent( this );
00160     }
00161     else {
00162         lowerLeft = 0;
00163     }
00164     if ( other.lowerMiddle ) {
00165         lowerMiddle = new SequenceElement( *( other.lowerMiddle ) );
00166         lowerMiddle->setParent( this );
00167     }
00168     else {
00169         lowerMiddle = 0;
00170     }
00171     if ( other.lowerRight ) {
00172         lowerRight = new SequenceElement( *( other.lowerRight ) );
00173         lowerRight->setParent( this );
00174     }
00175     else {
00176         lowerRight = 0;
00177     }
00178 }
00179 
00180 
00181 bool IndexElement::accept( ElementVisitor* visitor )
00182 {
00183     return visitor->visit( this );
00184 }
00185 
00186 
00187 QChar IndexElement::getCharacter() const
00188 {
00189     if ( !content->isTextOnly() ) {
00190         return QChar::null;
00191     }
00192 
00193     if ( hasUpperRight() && !upperRight->isTextOnly() ) {
00194         return QChar::null;
00195     }
00196     if ( hasUpperMiddle() && !upperMiddle->isTextOnly() ) {
00197         return QChar::null;
00198     }
00199     if ( hasUpperLeft() && !upperLeft->isTextOnly() ) {
00200         return QChar::null;
00201     }
00202     if ( hasLowerRight() && !lowerRight->isTextOnly() ) {
00203         return QChar::null;
00204     }
00205     if ( hasLowerMiddle() && !lowerMiddle->isTextOnly() ) {
00206         return QChar::null;
00207     }
00208     if ( hasLowerLeft() && !lowerLeft->isTextOnly() ) {
00209         return QChar::null;
00210     }
00211 
00212     return ' ';
00213 }
00214 
00215 void IndexElement::entered( SequenceElement* child )
00216 {
00217     if ( child == content ) {
00218         formula()->tell( i18n( "Indexed list" ) );
00219     }
00220     else {
00221         formula()->tell( i18n( "Index" ) );
00222     }
00223 }
00224 
00225 
00229 BasicElement* IndexElement::goToPos( FormulaCursor* cursor, bool& handled,
00230                                      const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00231 {
00232     BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00233     if (e != 0) {
00234         LuPixelPoint myPos(parentOrigin.x()+getX(), parentOrigin.y()+getY());
00235         e = content->goToPos(cursor, handled, point, myPos);
00236         if (e != 0) return e;
00237 
00238         if (hasUpperRight()) {
00239             e = upperRight->goToPos(cursor, handled, point, myPos);
00240             if (e != 0) return e;
00241         }
00242         if (hasUpperMiddle()) {
00243             e = upperMiddle->goToPos(cursor, handled, point, myPos);
00244             if (e != 0) return e;
00245         }
00246         if (hasUpperLeft()) {
00247             e = upperLeft->goToPos(cursor, handled, point, myPos);
00248             if (e != 0) return e;
00249         }
00250         if (hasLowerRight()) {
00251             e = lowerRight->goToPos(cursor, handled, point, myPos);
00252             if (e != 0) return e;
00253         }
00254         if (hasLowerMiddle()) {
00255             e = lowerMiddle->goToPos(cursor, handled, point, myPos);
00256             if (e != 0) return e;
00257         }
00258         if (hasLowerLeft()) {
00259             e = lowerLeft->goToPos(cursor, handled, point, myPos);
00260             if (e != 0) return e;
00261         }
00262 
00263         luPixel dx = point.x() - myPos.x();
00264         luPixel dy = point.y() - myPos.y();
00265 
00266         // the positions after the left indexes
00267         if (dx < content->getX()+content->getWidth()) {
00268             if (dy < content->getY()) {
00269                 if (hasUpperMiddle() && (dx > upperMiddle->getX())) {
00270                     upperMiddle->moveLeft(cursor, this);
00271                     handled = true;
00272                     return upperMiddle;
00273                 }
00274                 if (hasUpperLeft() && (dx > upperLeft->getX())) {
00275                     upperLeft->moveLeft(cursor, this);
00276                     handled = true;
00277                     return upperLeft;
00278                 }
00279             }
00280             else if (dy > content->getY()+content->getHeight()) {
00281                 if (hasLowerMiddle() && (dx > lowerMiddle->getX())) {
00282                     lowerMiddle->moveLeft(cursor, this);
00283                     handled = true;
00284                     return lowerMiddle;
00285                 }
00286                 if (hasLowerLeft() && (dx > lowerLeft->getX())) {
00287                     lowerLeft->moveLeft(cursor, this);
00288                     handled = true;
00289                     return lowerLeft;
00290                 }
00291             }
00292         }
00293         // the positions after the left indexes
00294         else {
00295             if (dy < content->getY()) {
00296                 if (hasUpperRight()) {
00297                     upperRight->moveLeft(cursor, this);
00298                     handled = true;
00299                     return upperRight;
00300                 }
00301             }
00302             else if (dy > content->getY()+content->getHeight()) {
00303                 if (hasLowerRight()) {
00304                     lowerRight->moveLeft(cursor, this);
00305                     handled = true;
00306                     return lowerRight;
00307                 }
00308             }
00309             else {
00310                 content->moveLeft(cursor, this);
00311                 handled = true;
00312                 return content;
00313             }
00314         }
00315 
00316         return this;
00317     }
00318     return 0;
00319 }
00320 
00321 
00322 // drawing
00323 //
00324 // Drawing depends on a context which knows the required properties like
00325 // fonts, spaces and such.
00326 // It is essential to calculate elements size with the same context
00327 // before you draw.
00328 
00329 
00330 void IndexElement::setMiddleX(int xOffset, int middleWidth)
00331 {
00332     content->setX(xOffset + (middleWidth - content->getWidth()) / 2);
00333     if (hasUpperMiddle()) {
00334         upperMiddle->setX(xOffset + (middleWidth - upperMiddle->getWidth()) / 2);
00335     }
00336     if (hasLowerMiddle()) {
00337         lowerMiddle->setX(xOffset + (middleWidth - lowerMiddle->getWidth()) / 2);
00338     }
00339 }
00340 
00341 
00346 void IndexElement::calcSizes(const ContextStyle& context, 
00347                              ContextStyle::TextStyle tstyle,
00348                              ContextStyle::IndexStyle istyle,
00349                              StyleAttributes& style )
00350 {
00351     double factor = style.sizeFactor();
00352     luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
00353 
00354     ContextStyle::TextStyle i_tstyle = context.convertTextStyleIndex(tstyle);
00355     ContextStyle::IndexStyle u_istyle = context.convertIndexStyleUpper( istyle );
00356     ContextStyle::IndexStyle l_istyle = context.convertIndexStyleLower( istyle );
00357 
00358     // get the indexes size
00359     luPixel ulWidth = 0, ulHeight = 0, ulMidline = 0;
00360     if (hasUpperLeft()) {
00361       upperLeft->calcSizes( context, i_tstyle, u_istyle, style );
00362         ulWidth = upperLeft->getWidth();
00363         ulHeight = upperLeft->getHeight();
00364         ulMidline = upperLeft->axis( context, i_tstyle, factor );
00365     }
00366 
00367     luPixel umWidth = 0, umHeight = 0, umMidline = 0;
00368     if (hasUpperMiddle()) {
00369         upperMiddle->calcSizes( context, i_tstyle, u_istyle, style );
00370         umWidth = upperMiddle->getWidth();
00371         umHeight = upperMiddle->getHeight() + distY;
00372         umMidline = upperMiddle->axis( context, i_tstyle, factor );
00373     }
00374 
00375     luPixel urWidth = 0, urHeight = 0, urMidline = 0;
00376     if (hasUpperRight()) {
00377         upperRight->calcSizes( context, i_tstyle, u_istyle, style );
00378         urWidth = upperRight->getWidth();
00379         urHeight = upperRight->getHeight();
00380         urMidline = upperRight->axis( context, i_tstyle, factor );
00381     }
00382 
00383     luPixel llWidth = 0, llHeight = 0, llMidline = 0;
00384     if (hasLowerLeft()) {
00385         lowerLeft->calcSizes( context, i_tstyle, l_istyle, style );
00386         llWidth = lowerLeft->getWidth();
00387         llHeight = lowerLeft->getHeight();
00388         llMidline = lowerLeft->axis( context, i_tstyle, factor );
00389     }
00390 
00391     luPixel lmWidth = 0, lmHeight = 0, lmMidline = 0;
00392     if (hasLowerMiddle()) {
00393         lowerMiddle->calcSizes( context, i_tstyle, l_istyle, style );
00394         lmWidth = lowerMiddle->getWidth();
00395         lmHeight = lowerMiddle->getHeight() + distY;
00396         lmMidline = lowerMiddle->axis( context, i_tstyle, factor );
00397     }
00398 
00399     luPixel lrWidth = 0, lrHeight = 0, lrMidline = 0;
00400     if (hasLowerRight()) {
00401         lowerRight->calcSizes( context, i_tstyle, l_istyle, style );
00402         lrWidth = lowerRight->getWidth();
00403         lrHeight = lowerRight->getHeight();
00404         lrMidline = lowerRight->axis( context, i_tstyle, factor );
00405     }
00406 
00407     // get the contents size
00408     content->calcSizes( context, tstyle, istyle, style );
00409     luPixel width = QMAX(content->getWidth(), QMAX(umWidth, lmWidth));
00410     luPixel toMidline = content->axis( context, tstyle, factor );
00411     luPixel fromMidline = content->getHeight() - toMidline;
00412 
00413     // calculate the x offsets
00414     if (ulWidth > llWidth) {
00415         upperLeft->setX(0);
00416         if (hasLowerLeft()) {
00417             lowerLeft->setX(ulWidth - llWidth);
00418         }
00419         setMiddleX(ulWidth, width);
00420         width += ulWidth;
00421     }
00422     else {
00423         if (hasUpperLeft()) {
00424             upperLeft->setX(llWidth - ulWidth);
00425         }
00426         if (hasLowerLeft()) {
00427             lowerLeft->setX(0);
00428         }
00429         setMiddleX(llWidth, width);
00430         width += llWidth;
00431     }
00432 
00433     if (hasUpperRight()) {
00434         upperRight->setX(width);
00435     }
00436     if (hasLowerRight()) {
00437         lowerRight->setX(width);
00438     }
00439     width += QMAX(urWidth, lrWidth);
00440 
00441     // calculate the y offsets
00442     luPixel ulOffset = 0;
00443     luPixel urOffset = 0;
00444     luPixel llOffset = 0;
00445     luPixel lrOffset = 0;
00446     if (content->isTextOnly()) {
00447         luPt mySize = context.getAdjustedSize( tstyle, factor );
00448         QFont font = context.getDefaultFont();
00449         font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
00450 
00451         QFontMetrics fm(font);
00452         LuPixelRect bound = fm.boundingRect('x');
00453 
00454         luPixel exBaseline = context.ptToLayoutUnitPt( -bound.top() );
00455 
00456         // the upper half
00457         ulOffset = ulHeight + exBaseline - content->getBaseline();
00458         urOffset = urHeight + exBaseline - content->getBaseline();
00459 
00460         // the lower half
00461         llOffset = lrOffset = content->getBaseline();
00462     }
00463     else {
00464 
00465         // the upper half
00466         ulOffset = QMAX(ulMidline, ulHeight-toMidline);
00467         urOffset = QMAX(urMidline, urHeight-toMidline);
00468 
00469         // the lower half
00470         llOffset = QMAX(content->getHeight()-llMidline, toMidline);
00471         lrOffset = QMAX(content->getHeight()-lrMidline, toMidline);
00472     }
00473 
00474     // Add more offset if defined in attributes
00475     switch ( m_superScriptShiftType ) {
00476     case AbsoluteSize:
00477         urOffset += context.ptToLayoutUnitPt( m_superScriptShift );
00478         break;
00479     case RelativeSize:
00480         urOffset += urOffset * m_superScriptShift;
00481         break;
00482     case PixelSize:
00483         urOffset += context.pixelToLayoutUnitY( m_superScriptShift );
00484         break;
00485     default:
00486         break;
00487     }
00488 
00489     switch ( m_subScriptShiftType ) {
00490     case AbsoluteSize:
00491         lrOffset += context.ptToLayoutUnitPt( m_subScriptShift );
00492         break;
00493     case RelativeSize:
00494         lrOffset += lrOffset * m_subScriptShift;
00495         break;
00496     case PixelSize:
00497         lrOffset += context.pixelToLayoutUnitY( m_subScriptShift );
00498         break;
00499     default:
00500         break;
00501     }
00502 
00503     luPixel height = QMAX(umHeight, QMAX(ulOffset, urOffset));
00504 
00505     // the upper half
00506     content->setY(height);
00507     toMidline += height;
00508     if (hasUpperLeft()) {
00509         upperLeft->setY(height-ulOffset);
00510     }
00511     if (hasUpperMiddle()) {
00512         upperMiddle->setY(height-umHeight);
00513     }
00514     if (hasUpperRight()) {
00515         upperRight->setY( height - urOffset );
00516     }
00517 
00518     // the lower half
00519     if (hasLowerLeft()) {
00520         lowerLeft->setY(height+llOffset);
00521     }
00522     if (hasLowerMiddle()) {
00523         lowerMiddle->setY(height+content->getHeight()+distY);
00524     }
00525     if (hasLowerRight()) {
00526         lowerRight->setY( height + lrOffset );
00527     }
00528 
00529     fromMidline += QMAX(QMAX(llHeight+llOffset, lrHeight+lrOffset) - content->getHeight(), lmHeight);
00530 
00531     // set the result
00532     setWidth(width);
00533     setHeight(toMidline+fromMidline);
00534     if (content->isTextOnly()) {
00535         setBaseline(content->getY() + content->getBaseline());
00536         //setMidline(content->getY() + content->getMidline());
00537     }
00538     else {
00539         //setMidline(toMidline);
00540         setBaseline(content->getBaseline() + content->getY());
00541     }
00542 }
00543 
00549 void IndexElement::draw( QPainter& painter, const LuPixelRect& r,
00550                          const ContextStyle& context,
00551                          ContextStyle::TextStyle tstyle,
00552                          ContextStyle::IndexStyle istyle,
00553                          StyleAttributes& style,
00554                          const LuPixelPoint& parentOrigin )
00555 {
00556     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00557     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00558     //    return;
00559 
00560     ContextStyle::TextStyle i_tstyle = context.convertTextStyleIndex(tstyle);
00561     ContextStyle::IndexStyle u_istyle = context.convertIndexStyleUpper( istyle );
00562     ContextStyle::IndexStyle l_istyle = context.convertIndexStyleLower( istyle );
00563 
00564     content->draw(painter, r, context, tstyle, istyle, style, myPos);
00565     if (hasUpperLeft()) {
00566         upperLeft->draw(painter, r, context, i_tstyle, u_istyle, style, myPos);
00567     }
00568     if (hasUpperMiddle()) {
00569         upperMiddle->draw(painter, r, context, i_tstyle, u_istyle, style, myPos);
00570     }
00571     if (hasUpperRight()) {
00572         upperRight->draw(painter, r, context, i_tstyle, u_istyle, style, myPos);
00573     }
00574     if (hasLowerLeft()) {
00575         lowerLeft->draw(painter, r, context, i_tstyle, l_istyle, style, myPos);
00576     }
00577     if (hasLowerMiddle()) {
00578         lowerMiddle->draw(painter, r, context, i_tstyle, l_istyle, style, myPos);
00579     }
00580     if (hasLowerRight()) {
00581         lowerRight->draw(painter, r, context, i_tstyle, l_istyle, style, myPos);
00582     }
00583 
00584     // Debug
00585     //painter.setBrush(Qt::NoBrush);
00586     //painter.setPen(Qt::red);
00587     //painter.drawRect(myPos.x(), myPos.y(), getWidth(), getHeight());
00588     //painter.drawLine(myPos.x(), myPos.y()+getMidline(),
00589     //                 myPos.x()+getWidth(), myPos.y()+getMidline());
00590 }
00591 
00592 
00593 void IndexElement::dispatchFontCommand( FontCommand* cmd )
00594 {
00595     content->dispatchFontCommand( cmd );
00596     if (hasUpperLeft()) {
00597         upperLeft->dispatchFontCommand( cmd );
00598     }
00599     if (hasUpperMiddle()) {
00600         upperMiddle->dispatchFontCommand( cmd );
00601     }
00602     if (hasUpperRight()) {
00603         upperRight->dispatchFontCommand( cmd );
00604     }
00605     if (hasLowerLeft()) {
00606         lowerLeft->dispatchFontCommand( cmd );
00607     }
00608     if (hasLowerMiddle()) {
00609         lowerMiddle->dispatchFontCommand( cmd );
00610     }
00611     if (hasLowerRight()) {
00612         lowerRight->dispatchFontCommand( cmd );
00613     }
00614 }
00615 
00616 
00617 // navigation
00618 //
00619 // The elements are responsible to handle cursor movement themselves.
00620 // To do this they need to know the direction the cursor moves and
00621 // the element it comes from.
00622 //
00623 // The cursor might be in normal or in selection mode.
00624 
00625 int IndexElement::getFromPos(BasicElement* from)
00626 {
00627     if (from == lowerRight) {
00628         return lowerRightPos;
00629     }
00630     else if (from == upperRight) {
00631         return upperRightPos;
00632     }
00633     else if (from == lowerMiddle) {
00634         return lowerMiddlePos;
00635     }
00636     else if (from == content) {
00637         return contentPos;
00638     }
00639     else if (from == upperMiddle) {
00640         return upperMiddlePos;
00641     }
00642     else if (from == lowerLeft) {
00643         return lowerLeftPos;
00644     }
00645     else if (from == upperLeft) {
00646         return upperLeftPos;
00647     }
00648     return parentPos;
00649 }
00650 
00656 void IndexElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
00657 {
00658     if (cursor->isSelectionMode()) {
00659         getParent()->moveLeft(cursor, this);
00660     }
00661     else {
00662         bool linear = cursor->getLinearMovement();
00663         int fromPos = getFromPos(from);
00664         if (!linear) {
00665             if ((fromPos == lowerRightPos) && hasLowerMiddle()) {
00666                 lowerMiddle->moveLeft(cursor, this);
00667                 return;
00668             }
00669             else if ((fromPos == upperRightPos) && hasUpperMiddle()) {
00670                 upperMiddle->moveLeft(cursor, this);
00671                 return;
00672             }
00673             else if ((fromPos == lowerMiddlePos) && hasLowerLeft()) {
00674                 lowerLeft->moveLeft(cursor, this);
00675                 return;
00676             }
00677             else if ((fromPos == upperMiddlePos) && hasUpperLeft()) {
00678                 upperLeft->moveLeft(cursor, this);
00679                 return;
00680             }
00681         }
00682         switch (fromPos) {
00683             case parentPos:
00684                 if (hasLowerRight() && linear) {
00685                     lowerRight->moveLeft(cursor, this);
00686                     break;
00687                 }
00688             case lowerRightPos:
00689                 if (hasUpperRight() && linear) {
00690                     upperRight->moveLeft(cursor, this);
00691                     break;
00692                 }
00693             case upperRightPos:
00694                 if (hasLowerMiddle() && linear) {
00695                     lowerMiddle->moveLeft(cursor, this);
00696                     break;
00697                 }
00698             case lowerMiddlePos:
00699                 content->moveLeft(cursor, this);
00700                 break;
00701             case contentPos:
00702                 if (hasUpperMiddle() && linear) {
00703                     upperMiddle->moveLeft(cursor, this);
00704                     break;
00705                 }
00706             case upperMiddlePos:
00707                 if (hasLowerLeft() && linear) {
00708                     lowerLeft->moveLeft(cursor, this);
00709                     break;
00710                 }
00711             case lowerLeftPos:
00712                 if (hasUpperLeft() && linear) {
00713                     upperLeft->moveLeft(cursor, this);
00714                     break;
00715                 }
00716             case upperLeftPos:
00717                 getParent()->moveLeft(cursor, this);
00718         }
00719     }
00720 }
00721 
00727 void IndexElement::moveRight(FormulaCursor* cursor, BasicElement* from)
00728 {
00729     if (cursor->isSelectionMode()) {
00730         getParent()->moveRight(cursor, this);
00731     }
00732     else {
00733         bool linear = cursor->getLinearMovement();
00734         int fromPos = getFromPos(from);
00735         if (!linear) {
00736             if ((fromPos == lowerLeftPos) && hasLowerMiddle()) {
00737                 lowerMiddle->moveRight(cursor, this);
00738                 return;
00739             }
00740             else if ((fromPos == upperLeftPos) && hasUpperMiddle()) {
00741                 upperMiddle->moveRight(cursor, this);
00742                 return;
00743             }
00744             else if ((fromPos == lowerMiddlePos) && hasLowerRight()) {
00745                 lowerRight->moveRight(cursor, this);
00746                 return;
00747             }
00748             else if ((fromPos == upperMiddlePos) && hasUpperRight()) {
00749                 upperRight->moveRight(cursor, this);
00750                 return;
00751             }
00752         }
00753         switch (fromPos) {
00754             case parentPos:
00755                 if (hasUpperLeft() && linear) {
00756                     upperLeft->moveRight(cursor, this);
00757                     break;
00758                 }
00759             case upperLeftPos:
00760                 if (hasLowerLeft() && linear) {
00761                     lowerLeft->moveRight(cursor, this);
00762                     break;
00763                 }
00764             case lowerLeftPos:
00765                 if (hasUpperMiddle() && linear) {
00766                     upperMiddle->moveRight(cursor, this);
00767                     break;
00768                 }
00769             case upperMiddlePos:
00770                 content->moveRight(cursor, this);
00771                 break;
00772             case contentPos:
00773                 if (hasLowerMiddle() && linear) {
00774                     lowerMiddle->moveRight(cursor, this);
00775                     break;
00776                 }
00777             case lowerMiddlePos:
00778                 if (hasUpperRight() && linear) {
00779                     upperRight->moveRight(cursor, this);
00780                     break;
00781                 }
00782             case upperRightPos:
00783                 if (hasLowerRight() && linear) {
00784                     lowerRight->moveRight(cursor, this);
00785                     break;
00786                 }
00787             case lowerRightPos:
00788                 getParent()->moveRight(cursor, this);
00789         }
00790     }
00791 }
00792 
00798 void IndexElement::moveUp(FormulaCursor* cursor, BasicElement* from)
00799 {
00800     if (cursor->isSelectionMode()) {
00801         getParent()->moveUp(cursor, this);
00802     }
00803     else {
00804         if (from == content) {
00805             if ((cursor->getPos() == 0) && (cursor->getElement() == from)) {
00806                 if (hasUpperLeft()) {
00807                     upperLeft->moveLeft(cursor, this);
00808                     return;
00809                 }
00810                 else if (hasUpperMiddle()) {
00811                     upperMiddle->moveRight(cursor, this);
00812                     return;
00813                 }
00814             }
00815             if (hasUpperRight()) {
00816                 upperRight->moveRight(cursor, this);
00817             }
00818             else if (hasUpperMiddle()) {
00819                 upperMiddle->moveLeft(cursor, this);
00820             }
00821             else if (hasUpperLeft()) {
00822                 upperLeft->moveLeft(cursor, this);
00823             }
00824             else {
00825                 getParent()->moveUp(cursor, this);
00826             }
00827         }
00828         else if ((from == upperLeft) || (from == upperMiddle) || (from == upperRight)) {
00829             getParent()->moveUp(cursor, this);
00830         }
00831         else if ((from == getParent()) || (from == lowerLeft) || (from == lowerMiddle)) {
00832             content->moveRight(cursor, this);
00833         }
00834         else if (from == lowerRight) {
00835             content->moveLeft(cursor, this);
00836         }
00837     }
00838 }
00839 
00845 void IndexElement::moveDown(FormulaCursor* cursor, BasicElement* from)
00846 {
00847     if (cursor->isSelectionMode()) {
00848         getParent()->moveDown(cursor, this);
00849     }
00850     else {
00851         if (from == content) {
00852             if ((cursor->getPos() == 0) && (cursor->getElement() == from)) {
00853                 if (hasLowerLeft()) {
00854                     lowerLeft->moveLeft(cursor, this);
00855                     return;
00856                 }
00857                 else if (hasLowerMiddle()) {
00858                     lowerMiddle->moveRight(cursor, this);
00859                     return;
00860                 }
00861             }
00862             if (hasLowerRight()) {
00863                 lowerRight->moveRight(cursor, this);
00864             }
00865             else if (hasLowerMiddle()) {
00866                 lowerMiddle->moveLeft(cursor, this);
00867             }
00868             else if (hasLowerLeft()) {
00869                 lowerLeft->moveLeft(cursor, this);
00870             }
00871             else {
00872                 getParent()->moveDown(cursor, this);
00873             }
00874         }
00875         else if ((from == lowerLeft) || (from == lowerMiddle) || (from == lowerRight)) {
00876             getParent()->moveDown(cursor, this);
00877         }
00878         else if ((from == getParent()) || (from == upperLeft) || (from == upperMiddle)) {
00879             content->moveRight(cursor, this);
00880         }
00881         if (from == upperRight) {
00882             content->moveLeft(cursor, this);
00883         }
00884     }
00885 }
00886 
00887 
00888 // children
00889 
00890 
00891 // main child
00892 //
00893 // If an element has children one has to become the main one.
00894 
00895 // void IndexElement::setMainChild(SequenceElement* child)
00896 // {
00897 //     formula()->elementRemoval(content);
00898 //     content = child;
00899 //     content->setParent(this);
00900 //     formula()->changed();
00901 // }
00902 
00903 
00914 void IndexElement::insert(FormulaCursor* cursor,
00915                           QPtrList<BasicElement>& newChildren,
00916                           Direction direction)
00917 {
00918     SequenceElement* index = static_cast<SequenceElement*>(newChildren.take(0));
00919     index->setParent(this);
00920 
00921     switch (cursor->getPos()) {
00922     case upperLeftPos:
00923         upperLeft = index;
00924         break;
00925     case lowerLeftPos:
00926         lowerLeft = index;
00927         break;
00928     case upperMiddlePos:
00929         upperMiddle = index;
00930         break;
00931     case lowerMiddlePos:
00932         lowerMiddle = index;
00933         break;
00934     case upperRightPos:
00935         upperRight = index;
00936         break;
00937     case lowerRightPos:
00938         lowerRight = index;
00939         break;
00940     default:
00941         // this is an error!
00942         return;
00943     }
00944 
00945     if (direction == beforeCursor) {
00946         index->moveLeft(cursor, this);
00947     }
00948     else {
00949         index->moveRight(cursor, this);
00950     }
00951     cursor->setSelection(false);
00952     formula()->changed();
00953 }
00954 
00955 
00967 void IndexElement::remove(FormulaCursor* cursor,
00968                           QPtrList<BasicElement>& removedChildren,
00969                           Direction direction)
00970 {
00971     int pos = cursor->getPos();
00972     switch (pos) {
00973     case upperLeftPos:
00974         removedChildren.append(upperLeft);
00975         formula()->elementRemoval(upperLeft);
00976         upperLeft = 0;
00977         setToUpperLeft(cursor);
00978         break;
00979     case lowerLeftPos:
00980         removedChildren.append(lowerLeft);
00981         formula()->elementRemoval(lowerLeft);
00982         lowerLeft = 0;
00983         setToLowerLeft(cursor);
00984         break;
00985     case contentPos: {
00986         BasicElement* parent = getParent();
00987         parent->selectChild(cursor, this);
00988         parent->remove(cursor, removedChildren, direction);
00989         break;
00990     }
00991     case upperMiddlePos:
00992         removedChildren.append(upperMiddle);
00993         formula()->elementRemoval(upperMiddle);
00994         upperMiddle = 0;
00995         setToUpperMiddle(cursor);
00996         break;
00997     case lowerMiddlePos:
00998         removedChildren.append(lowerMiddle);
00999         formula()->elementRemoval(lowerMiddle);
01000         lowerMiddle = 0;
01001         setToLowerMiddle(cursor);
01002         break;
01003     case upperRightPos:
01004         removedChildren.append(upperRight);
01005         formula()->elementRemoval(upperRight);
01006         upperRight = 0;
01007         setToUpperRight(cursor);
01008         break;
01009     case lowerRightPos:
01010         removedChildren.append(lowerRight);
01011         formula()->elementRemoval(lowerRight);
01012         lowerRight = 0;
01013         setToLowerRight(cursor);
01014         break;
01015     }
01016     formula()->changed();
01017 }
01018 
01023 void IndexElement::normalize(FormulaCursor* cursor, Direction direction)
01024 {
01025     if (direction == beforeCursor) {
01026         content->moveLeft(cursor, this);
01027     }
01028     else {
01029         content->moveRight(cursor, this);
01030     }
01031 }
01032 
01038 bool IndexElement::isSenseless()
01039 {
01040     return !hasUpperLeft() && !hasUpperRight() && !hasUpperMiddle() &&
01041         !hasLowerLeft() && !hasLowerRight() && !hasLowerMiddle();
01042 }
01043 
01044 
01048 BasicElement* IndexElement::getChild(FormulaCursor* cursor, Direction)
01049 {
01050     int pos = cursor->getPos();
01051     /*
01052       It makes no sense to care for the direction.
01053     if (direction == beforeCursor) {
01054         pos -= 1;
01055     }
01056     */
01057     switch (pos) {
01058     case contentPos:
01059         return content;
01060     case upperLeftPos:
01061         return upperLeft;
01062     case lowerLeftPos:
01063         return lowerLeft;
01064     case upperMiddlePos:
01065         return upperMiddle;
01066     case lowerMiddlePos:
01067         return lowerMiddle;
01068     case upperRightPos:
01069         return upperRight;
01070     case lowerRightPos:
01071         return lowerRight;
01072     }
01073     return 0;
01074 }
01075 
01076 
01081 void IndexElement::selectChild(FormulaCursor* cursor, BasicElement* child)
01082 {
01083     if (child == content) {
01084         setToContent(cursor);
01085     }
01086     else if (child == upperLeft) {
01087         setToUpperLeft(cursor);
01088     }
01089     else if (child == lowerLeft) {
01090         setToLowerLeft(cursor);
01091     }
01092     else if (child == upperMiddle) {
01093         setToUpperMiddle(cursor);
01094     }
01095     else if (child == lowerMiddle) {
01096         setToLowerMiddle(cursor);
01097     }
01098     else if (child == upperRight) {
01099         setToUpperRight(cursor);
01100     }
01101     else if (child == lowerRight) {
01102         setToLowerRight(cursor);
01103     }
01104 }
01105 
01106 
01113 void IndexElement::setToContent(FormulaCursor* cursor)
01114 {
01115     cursor->setTo(this, contentPos);
01116 }
01117 
01118 // point the cursor to a gap where an index is to be inserted.
01119 // this makes no sense if there is such an index already.
01120 
01121 void IndexElement::setToUpperLeft(FormulaCursor* cursor)
01122 {
01123     cursor->setTo(this, upperLeftPos);
01124 }
01125 
01126 void IndexElement::setToUpperMiddle(FormulaCursor* cursor)
01127 {
01128     cursor->setTo(this, upperMiddlePos);
01129 }
01130 
01131 void IndexElement::setToUpperRight(FormulaCursor* cursor)
01132 {
01133     cursor->setTo(this, upperRightPos);
01134 }
01135 
01136 void IndexElement::setToLowerLeft(FormulaCursor* cursor)
01137 {
01138     cursor->setTo(this, lowerLeftPos);
01139 }
01140 
01141 void IndexElement::setToLowerMiddle(FormulaCursor* cursor)
01142 {
01143     cursor->setTo(this, lowerMiddlePos);
01144 }
01145 
01146 void IndexElement::setToLowerRight(FormulaCursor* cursor)
01147 {
01148     cursor->setTo(this, lowerRightPos);
01149 }
01150 
01151 
01152 // move inside an index that exists already.
01153 
01154 void IndexElement::moveToUpperLeft(FormulaCursor* cursor, Direction direction)
01155 {
01156     if (hasUpperLeft()) {
01157         if (direction == beforeCursor) {
01158             upperLeft->moveLeft(cursor, this);
01159         }
01160         else {
01161             upperLeft->moveRight(cursor, this);
01162         }
01163     }
01164 }
01165 
01166 void IndexElement::moveToUpperMiddle(FormulaCursor* cursor, Direction direction)
01167 {
01168     if (hasUpperMiddle()) {
01169         if (direction == beforeCursor) {
01170             upperMiddle->moveLeft(cursor, this);
01171         }
01172         else {
01173             upperMiddle->moveRight(cursor, this);
01174         }
01175     }
01176 }
01177 
01178 void IndexElement::moveToUpperRight(FormulaCursor* cursor, Direction direction)
01179 {
01180     if (hasUpperRight()) {
01181         if (direction == beforeCursor) {
01182             upperRight->moveLeft(cursor, this);
01183         }
01184         else {
01185             upperRight->moveRight(cursor, this);
01186         }
01187     }
01188 }
01189 
01190 void IndexElement::moveToLowerLeft(FormulaCursor* cursor, Direction direction)
01191 {
01192     if (hasLowerLeft()) {
01193         if (direction == beforeCursor) {
01194             lowerLeft->moveLeft(cursor, this);
01195         }
01196         else {
01197             lowerLeft->moveRight(cursor, this);
01198         }
01199     }
01200 }
01201 
01202 void IndexElement::moveToLowerMiddle(FormulaCursor* cursor, Direction direction)
01203 {
01204     if (hasLowerMiddle()) {
01205         if (direction == beforeCursor) {
01206             lowerMiddle->moveLeft(cursor, this);
01207         }
01208         else {
01209             lowerMiddle->moveRight(cursor, this);
01210         }
01211     }
01212 }
01213 
01214 void IndexElement::moveToLowerRight(FormulaCursor* cursor, Direction direction)
01215 {
01216     if (hasLowerRight()) {
01217         if (direction == beforeCursor) {
01218             lowerRight->moveLeft(cursor, this);
01219         }
01220         else {
01221             lowerRight->moveRight(cursor, this);
01222         }
01223     }
01224 }
01225 
01226 
01230 void IndexElement::writeDom(QDomElement element)
01231 {
01232     BasicElement::writeDom(element);
01233 
01234     QDomDocument doc = element.ownerDocument();
01235 
01236     QDomElement cont = doc.createElement("CONTENT");
01237     cont.appendChild(content->getElementDom(doc));
01238     element.appendChild(cont);
01239 
01240     if (hasUpperLeft()) {
01241         QDomElement ind = doc.createElement("UPPERLEFT");
01242         ind.appendChild(upperLeft->getElementDom(doc));
01243         element.appendChild(ind);
01244     }
01245     if (hasUpperMiddle()) {
01246         QDomElement ind = doc.createElement("UPPERMIDDLE");
01247         ind.appendChild(upperMiddle->getElementDom(doc));
01248         element.appendChild(ind);
01249     }
01250     if (hasUpperRight()) {
01251         QDomElement ind = doc.createElement("UPPERRIGHT");
01252         ind.appendChild(upperRight->getElementDom(doc));
01253         element.appendChild(ind);
01254     }
01255     if (hasLowerLeft()) {
01256         QDomElement ind = doc.createElement("LOWERLEFT");
01257         ind.appendChild(lowerLeft->getElementDom(doc));
01258         element.appendChild(ind);
01259     }
01260     if (hasLowerMiddle()) {
01261         QDomElement ind = doc.createElement("LOWERMIDDLE");
01262         ind.appendChild(lowerMiddle->getElementDom(doc));
01263         element.appendChild(ind);
01264     }
01265     if (hasLowerRight()) {
01266         QDomElement ind = doc.createElement("LOWERRIGHT");
01267         ind.appendChild(lowerRight->getElementDom(doc));
01268         element.appendChild(ind);
01269     }
01270 }
01271 
01276 bool IndexElement::readAttributesFromDom(QDomElement element)
01277 {
01278     if (!BasicElement::readAttributesFromDom(element)) {
01279         return false;
01280     }
01281     return true;
01282 }
01283 
01289 bool IndexElement::readContentFromDom(QDomNode& node)
01290 {
01291     if (!BasicElement::readContentFromDom(node)) {
01292         return false;
01293     }
01294 
01295     if ( !buildChild( content, node, "CONTENT" ) ) {
01296         kdWarning( DEBUGID ) << "Empty content in IndexElement." << endl;
01297         return false;
01298     }
01299     node = node.nextSibling();
01300 
01301     bool upperLeftRead = false;
01302     bool upperMiddleRead = false;
01303     bool upperRightRead = false;
01304     bool lowerLeftRead = false;
01305     bool lowerMiddleRead = false;
01306     bool lowerRightRead = false;
01307 
01308     while (!node.isNull() &&
01309            !(upperLeftRead && upperMiddleRead && upperRightRead &&
01310              lowerLeftRead && lowerMiddleRead && lowerRightRead)) {
01311 
01312         if (!upperLeftRead && (node.nodeName().upper() == "UPPERLEFT")) {
01313             upperLeftRead = buildChild( upperLeft=new SequenceElement( this ), node, "UPPERLEFT" );
01314             if ( !upperLeftRead ) return false;
01315         }
01316 
01317         if (!upperMiddleRead && (node.nodeName().upper() == "UPPERMIDDLE")) {
01318             upperMiddleRead = buildChild( upperMiddle=new SequenceElement( this ), node, "UPPERMIDDLE" );
01319             if ( !upperMiddleRead ) return false;
01320         }
01321 
01322         if (!upperRightRead && (node.nodeName().upper() == "UPPERRIGHT")) {
01323             upperRightRead = buildChild( upperRight=new SequenceElement( this ), node, "UPPERRIGHT" );
01324             if ( !upperRightRead ) return false;
01325         }
01326 
01327         if (!lowerLeftRead && (node.nodeName().upper() == "LOWERLEFT")) {
01328             lowerLeftRead = buildChild( lowerLeft=new SequenceElement( this ), node, "LOWERLEFT" );
01329             if ( !lowerLeftRead ) return false;
01330         }
01331 
01332         if (!lowerMiddleRead && (node.nodeName().upper() == "LOWERMIDDLE")) {
01333             lowerMiddleRead = buildChild( lowerMiddle=new SequenceElement( this ), node, "LOWERMIDDLE" );
01334             if ( !lowerMiddleRead ) return false;
01335         }
01336 
01337         if (!lowerRightRead && (node.nodeName().upper() == "LOWERRIGHT")) {
01338             lowerRightRead = buildChild( lowerRight=new SequenceElement( this ), node, "LOWERRIGHT" );
01339             if ( !lowerRightRead ) return false;
01340         }
01341 
01342         node = node.nextSibling();
01343     }
01344     return upperLeftRead || upperMiddleRead || upperRightRead ||
01345         lowerLeftRead || lowerMiddleRead || lowerRightRead;
01346 }
01347 
01348 bool IndexElement::readAttributesFromMathMLDom( const QDomElement& element )
01349 {
01350     if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
01351         return false;
01352     }
01353 
01354     QString tag = element.tagName().stripWhiteSpace().lower();
01355     if ( tag == "msub" || tag == "msubsup" ) {
01356         QString subscriptshiftStr = element.attribute( "subscriptshift" ).stripWhiteSpace().lower();
01357         if ( ! subscriptshiftStr.isNull() ) {
01358             m_subScriptShift = getSize( subscriptshiftStr, &m_subScriptShiftType );
01359         }
01360     }
01361     if ( tag == "msup" || tag == "msubsup" ) {
01362         QString superscriptshiftStr = element.attribute( "superscriptshift" ).stripWhiteSpace().lower();
01363         if ( ! superscriptshiftStr.isNull() ) {
01364             m_superScriptShift = getSize( superscriptshiftStr, &m_superScriptShiftType );
01365         }
01366     }
01367 
01368     if ( tag == "munder" || tag == "munderover" ) {
01369         QString accentunderStr = element.attribute( "accentunder" ).stripWhiteSpace().lower();
01370         if ( ! accentunderStr.isNull() ) {
01371             if ( accentunderStr == "true" ) {
01372                 m_customAccentUnder = true;
01373                 m_accentUnder = true;
01374             }
01375             else if ( accentunderStr == "false" ) {
01376                 m_customAccentUnder = true;
01377                 m_accentUnder = false;
01378             }
01379             else {
01380                 kdWarning( DEBUGID ) << "Invalid value for attribute `accentunder': " 
01381                                      << accentunderStr << endl;
01382             }
01383         }
01384     }
01385     if ( tag == "mover" || tag == "munderover" ) {
01386         QString accentStr = element.attribute( "accent" ).stripWhiteSpace().lower();
01387         if ( ! accentStr.isNull() ) {
01388             if ( accentStr == "true" ) {
01389                 m_customAccent = true;
01390                 m_accent = true;
01391             }
01392             else if ( accentStr == "false" ) {
01393                 m_customAccent = true;
01394                 m_accent = false;
01395             }
01396             else {
01397                 kdWarning( DEBUGID ) << "Invalid value for attribute `accent': " 
01398                                      << accentStr << endl;
01399             }
01400         }
01401     }
01402     return true;
01403 }
01404 
01411 int IndexElement::readContentFromMathMLDom( QDomNode& node )
01412 {
01413     if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
01414         return -1;
01415     }
01416 
01417     int contentNumber = content->buildMathMLChild( node );
01418     if ( contentNumber == -1 ) {
01419         kdWarning( DEBUGID ) << "Empty base in Script" << endl;
01420         return -1;
01421     }
01422     for (int i = 0; i < contentNumber; i++ ) {
01423         if ( node.isNull() ) {
01424             return -1;
01425         }
01426         node = node.nextSibling();
01427     }
01428 
01429     QString indexType = node.parentNode().toElement().tagName().lower();
01430     if ( indexType == "msub" ) {
01431         lowerRight = new SequenceElement( this );
01432         int lowerRightNumber = lowerRight->buildMathMLChild( node );
01433         if ( lowerRightNumber == -1 ) {
01434             kdWarning( DEBUGID ) << "Empty subscript in Script" << endl;
01435             return -1;
01436         }
01437         for (int i = 0; i < lowerRightNumber; i++ ) {
01438             if ( node.isNull() ) {
01439                 return -1;
01440             }
01441             node = node.nextSibling();
01442         }
01443 
01444         return 1;
01445     }
01446 
01447     if ( indexType == "msup" ) {
01448         upperRight = new SequenceElement( this );
01449         int upperRightNumber = upperRight->buildMathMLChild( node );
01450         if ( upperRightNumber == -1 ) {
01451             kdWarning( DEBUGID ) << "Empty superscript in Script" << endl;
01452             return -1;
01453         }
01454         for (int i = 0; i < upperRightNumber; i++ ) {
01455             if ( node.isNull() ) {
01456                 return -1;
01457             }
01458             node = node.nextSibling();
01459         }
01460 
01461         return 1;
01462     }
01463 
01464     if ( indexType == "msubsup" ) {
01465         lowerRight = new SequenceElement( this );
01466         int lowerRightNumber = lowerRight->buildMathMLChild( node );
01467         if ( lowerRightNumber == -1 ) {
01468             kdWarning( DEBUGID ) << "Empty subscript in Script" << endl;
01469             return -1;
01470         }
01471         for (int i = 0; i < lowerRightNumber; i++ ) {
01472             if ( node.isNull() ) {
01473                 return -1;
01474             }
01475             node = node.nextSibling();
01476         }
01477 
01478         upperRight = new SequenceElement( this );
01479         int upperRightNumber = upperRight->buildMathMLChild( node );
01480         if ( upperRightNumber == -1 ) {
01481             kdWarning( DEBUGID ) << "Empty superscript in Script" << endl;
01482             return -1;
01483         }
01484         for (int i = 0; i < upperRightNumber; i++ ) {
01485             if ( node.isNull() ) {
01486                 return -1;
01487             }
01488             node = node.nextSibling();
01489         }
01490 
01491         return 1;
01492     }
01493     if ( indexType == "munder" ) {
01494         lowerMiddle = new SequenceElement( this );
01495         int lowerMiddleNumber = lowerMiddle->buildMathMLChild( node );
01496         if ( lowerMiddleNumber == -1 ) {
01497             kdWarning( DEBUGID ) << "Empty underscript in Script" << endl;
01498             return -1;
01499         }
01500         for (int i = 0; i < lowerMiddleNumber; i++ ) {
01501             if ( node.isNull() ) {
01502                 return -1;
01503             }
01504             node = node.nextSibling();
01505         }
01506 
01507         return 1;
01508     }
01509 
01510     if ( indexType == "mover" ) {
01511         upperMiddle = new SequenceElement( this );
01512         int upperMiddleNumber = upperMiddle->buildMathMLChild( node );
01513         if ( upperMiddleNumber == -1 ) {
01514             kdWarning( DEBUGID ) << "Empty overscript in Script" << endl;
01515             return -1;
01516         }
01517         for (int i = 0; i < upperMiddleNumber; i++ ) {
01518             if ( node.isNull() ) {
01519                 return -1;
01520             }
01521             node = node.nextSibling();
01522         }
01523 
01524         return 1;
01525     }
01526 
01527     if ( indexType == "munderover" ) {
01528         lowerMiddle = new SequenceElement( this );
01529         int lowerMiddleNumber = lowerMiddle->buildMathMLChild( node );
01530         if ( lowerMiddleNumber == -1 ) {
01531             kdWarning( DEBUGID ) << "Empty underscript in Script" << endl;
01532             return -1;
01533         }
01534         for (int i = 0; i < lowerMiddleNumber; i++ ) {
01535             if ( node.isNull() ) {
01536                 return -1;
01537             }
01538             node = node.nextSibling();
01539         }
01540 
01541 
01542         upperMiddle = new SequenceElement( this );
01543         int upperMiddleNumber = upperMiddle->buildMathMLChild( node );
01544         if ( upperMiddleNumber == -1 ) {
01545             kdWarning( DEBUGID ) << "Empty overscript in Script" << endl;
01546             return -1;
01547         }
01548         for (int i = 0; i < upperMiddleNumber; i++ ) {
01549             if ( node.isNull() ) {
01550                 return -1;
01551             }
01552             node = node.nextSibling();
01553         }
01554 
01555         return 1;
01556     }
01557     // TODO: mmultiscripts, section 3.4.7
01558     return 1;
01559 }
01560 
01561 
01562 ElementIndexPtr IndexElement::getIndex( int position )
01563 {
01564     switch (position) {
01565     case upperRightPos:
01566         return getUpperRight();
01567     case lowerRightPos:
01568         return getLowerRight();
01569     case lowerMiddlePos:
01570         return getLowerMiddle();
01571     case upperMiddlePos:
01572         return getUpperMiddle();
01573     case lowerLeftPos:
01574         return getLowerLeft();
01575     case upperLeftPos:
01576         return getUpperLeft();
01577     }
01578     return getUpperRight();
01579 }
01580 
01581 
01582 
01583 QString IndexElement::toLatex()
01584 {
01585     QString index;
01586 
01587     if ( hasUpperMiddle() ) {
01588         index += "\\overset{" + upperMiddle->toLatex() + "}{";
01589     }
01590 
01591     if ( hasLowerMiddle() ) {
01592         index += "\\underset{" + lowerMiddle->toLatex() + "}{";
01593     }
01594 
01595     if ( hasUpperLeft() || hasUpperRight() ) { //Not sure that this is possible in Latex!
01596         /*index += "{}";
01597         if ( hasUpperLeft() )
01598             index += "^" + upperLeft->toLatex();
01599         if ( hasLowerLeft() )
01600             index += "_" + lowerLeft->toLatex();
01601         */
01602     }
01603 
01604     index += content->toLatex();
01605 
01606     if ( hasUpperRight() || hasLowerRight() ) {
01607         if ( hasUpperRight() )
01608             index += "^{" + upperRight->toLatex() + "}";
01609         if ( hasLowerRight() )
01610             index += "_{" + lowerRight->toLatex() + "}";
01611         index += " ";
01612     }
01613 
01614     if ( hasLowerMiddle() ) {
01615         index += "}";
01616     }
01617 
01618     if ( hasUpperMiddle() ) {
01619         index += "}";
01620     }
01621 
01622     return index;
01623 }
01624 
01625 QString IndexElement::formulaString()
01626 {
01627     QString index = "(" + content->formulaString() + ")";
01628     if ( hasLowerRight() ) {
01629         index += "_(" + lowerRight->formulaString() + ")";
01630     }
01631     if ( hasUpperRight() ) {
01632         index += "**(" + upperRight->formulaString() + ")";
01633     }
01634     return index;
01635 }
01636 
01637 QString IndexElement::getElementName() const
01638 {
01639     if ( hasUpperMiddle() && hasLowerMiddle() )
01640         return "munderover";
01641     if ( hasUpperMiddle() )
01642         return "mover";
01643     if ( hasLowerMiddle() )
01644         return "munder";
01645     if ( hasLowerLeft() || hasUpperLeft() )
01646         return "mmultiscripts";
01647     if ( hasLowerRight() || hasUpperRight() ) {
01648         if ( ! hasUpperRight() )
01649             return "msub";
01650         if ( ! hasLowerRight() )
01651             return "msup";
01652     }
01653     return "msubsup";
01654 }
01655 
01656 void IndexElement::writeMathMLAttributes( QDomElement& element ) const
01657 {
01658     QString tag = getElementName();
01659     if ( tag == "msub" || tag == "msubsup" ) {
01660         switch ( m_subScriptShiftType ) {
01661         case AbsoluteSize:
01662             element.setAttribute( "subscriptshift", QString( "%1pt" ).arg( m_subScriptShift ) );
01663             break;
01664         case RelativeSize:
01665             element.setAttribute( "subscriptshift", QString( "%1%" ).arg( m_subScriptShift * 100.0 ) );
01666             break;
01667         case PixelSize:
01668             element.setAttribute( "subscriptshift", QString( "%1px" ).arg( m_subScriptShift ) );
01669             break;
01670         default:
01671             break;
01672         }
01673     }
01674     if ( tag == "msup" || tag == "msubsup" ) {
01675         switch ( m_superScriptShiftType ) {
01676         case AbsoluteSize:
01677             element.setAttribute( "superscriptshift", QString( "%1pt" ).arg( m_superScriptShift ) );
01678             break;
01679         case RelativeSize:
01680             element.setAttribute( "superscriptshift", QString( "%1%" ).arg( m_superScriptShift * 100.0 ) );
01681             break;
01682         case PixelSize:
01683             element.setAttribute( "superscriptshift", QString( "%1px" ).arg( m_superScriptShift ) );
01684             break;
01685         default:
01686             break;
01687         }
01688     }
01689     if ( tag == "munder" || tag == "munderover" ) {
01690         if ( m_customAccentUnder ) {
01691             element.setAttribute( "accentunder", m_accentUnder ? "true" : "false" );
01692         }
01693     }
01694     if ( tag == "mover" || tag == "munderover" ) {
01695         if ( m_customAccent ) {
01696             element.setAttribute( "accent", m_accent ? "true" : "false" );
01697         }
01698     }
01699 }
01700 
01701 
01702 void IndexElement::writeMathMLContent( QDomDocument& doc, 
01703                                        QDomElement& element,
01704                                        bool oasisFormat ) const
01705 {
01706     QDomElement de;
01707 
01708     content->writeMathML( doc, element, oasisFormat ); // base
01709     if ( hasUpperMiddle() && hasLowerMiddle() )
01710     {
01711         lowerMiddle->writeMathML( doc, element, oasisFormat );
01712         upperMiddle->writeMathML( doc, element,oasisFormat );
01713     }
01714     else if ( hasUpperMiddle() )
01715     {
01716         upperMiddle->writeMathML( doc, element,oasisFormat );
01717     }
01718     else if ( hasLowerMiddle() )
01719     {
01720         lowerMiddle->writeMathML( doc, element,oasisFormat );
01721     }
01722 
01723     if ( hasLowerLeft() || hasUpperLeft() )
01724     {
01725         if ( hasLowerRight() )
01726             lowerRight->writeMathML( doc, element, oasisFormat );
01727         else
01728             element.appendChild( doc.createElement( "none" ) );
01729 
01730         if ( hasUpperRight() )
01731             upperRight->writeMathML( doc, element, oasisFormat );
01732         else
01733             element.appendChild( doc.createElement( "none" ) );
01734         
01735         element.appendChild( doc.createElement( "mprescripts" ) );
01736 
01737         if ( hasLowerLeft() )
01738             lowerLeft->writeMathML( doc, element, oasisFormat );
01739         else
01740             element.appendChild( doc.createElement( "none" ) );
01741 
01742         if ( hasUpperLeft() )
01743             upperLeft->writeMathML( doc, element, oasisFormat );
01744         else
01745             element.appendChild( doc.createElement( "none" ) );
01746     }
01747     else if ( hasLowerRight() || hasUpperRight() )
01748     {
01749         if ( !hasUpperRight() ) {
01750             lowerRight->writeMathML( doc, element, oasisFormat );
01751         }
01752         else if ( !hasLowerRight() ) {
01753             upperRight->writeMathML( doc, element, oasisFormat );
01754         }
01755         else // both
01756         {
01757             lowerRight->writeMathML( doc, element, oasisFormat );
01758             upperRight->writeMathML( doc, element,oasisFormat );
01759         }
01760     }
01761 }
01762 
01763 KFORMULA_NAMESPACE_END
KDE Home | KDE Accessibility Home | Description of Access Keys