lib Library API Documentation

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., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, 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 {
00096     content = new IndexSequenceElement( this );
00097 
00098     upperLeft   = 0;
00099     upperMiddle = 0;
00100     upperRight  = 0;
00101     lowerLeft   = 0;
00102     lowerMiddle = 0;
00103     lowerRight  = 0;
00104 }
00105 
00106 IndexElement::~IndexElement()
00107 {
00108     delete content;
00109     delete upperLeft;
00110     delete upperMiddle;
00111     delete upperRight;
00112     delete lowerLeft;
00113     delete lowerMiddle;
00114     delete lowerRight;
00115 }
00116 
00117 
00118 IndexElement::IndexElement( const IndexElement& other )
00119     : BasicElement( other )
00120 {
00121     content = new IndexSequenceElement( *dynamic_cast<IndexSequenceElement*>( other.content ) );
00122 
00123     if ( other.upperLeft ) {
00124         upperLeft = new SequenceElement( *( other.upperLeft ) );
00125         upperLeft->setParent( this );
00126     }
00127     else {
00128         upperLeft = 0;
00129     }
00130     if ( other.upperMiddle ) {
00131         upperMiddle = new SequenceElement( *( other.upperMiddle ) );
00132         upperMiddle->setParent( this );
00133     }
00134     else {
00135         upperMiddle = 0;
00136     }
00137     if ( other.upperRight ) {
00138         upperRight = new SequenceElement( *( other.upperRight ) );
00139         upperRight->setParent( this );
00140     }
00141     else {
00142         upperRight = 0;
00143     }
00144 
00145     if ( other.lowerLeft ) {
00146         lowerLeft = new SequenceElement( *( other.lowerLeft ) );
00147         lowerLeft->setParent( this );
00148     }
00149     else {
00150         lowerLeft = 0;
00151     }
00152     if ( other.lowerMiddle ) {
00153         lowerMiddle = new SequenceElement( *( other.lowerMiddle ) );
00154         lowerMiddle->setParent( this );
00155     }
00156     else {
00157         lowerMiddle = 0;
00158     }
00159     if ( other.lowerRight ) {
00160         lowerRight = new SequenceElement( *( other.lowerRight ) );
00161         lowerRight->setParent( this );
00162     }
00163     else {
00164         lowerRight = 0;
00165     }
00166 }
00167 
00168 
00169 bool IndexElement::accept( ElementVisitor* visitor )
00170 {
00171     return visitor->visit( this );
00172 }
00173 
00174 
00175 QChar IndexElement::getCharacter() const
00176 {
00177     if ( !content->isTextOnly() ) {
00178         return QChar::null;
00179     }
00180 
00181     if ( hasUpperRight() && !upperRight->isTextOnly() ) {
00182         return QChar::null;
00183     }
00184     if ( hasUpperMiddle() && !upperMiddle->isTextOnly() ) {
00185         return QChar::null;
00186     }
00187     if ( hasUpperLeft() && !upperLeft->isTextOnly() ) {
00188         return QChar::null;
00189     }
00190     if ( hasLowerRight() && !lowerRight->isTextOnly() ) {
00191         return QChar::null;
00192     }
00193     if ( hasLowerMiddle() && !lowerMiddle->isTextOnly() ) {
00194         return QChar::null;
00195     }
00196     if ( hasLowerLeft() && !lowerLeft->isTextOnly() ) {
00197         return QChar::null;
00198     }
00199 
00200     return ' ';
00201 }
00202 
00203 void IndexElement::entered( SequenceElement* child )
00204 {
00205     if ( child == content ) {
00206         formula()->tell( i18n( "Indexed list" ) );
00207     }
00208     else {
00209         formula()->tell( i18n( "Index" ) );
00210     }
00211 }
00212 
00213 
00217 BasicElement* IndexElement::goToPos( FormulaCursor* cursor, bool& handled,
00218                                      const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00219 {
00220     BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00221     if (e != 0) {
00222         LuPixelPoint myPos(parentOrigin.x()+getX(), parentOrigin.y()+getY());
00223         e = content->goToPos(cursor, handled, point, myPos);
00224         if (e != 0) return e;
00225 
00226         if (hasUpperRight()) {
00227             e = upperRight->goToPos(cursor, handled, point, myPos);
00228             if (e != 0) return e;
00229         }
00230         if (hasUpperMiddle()) {
00231             e = upperMiddle->goToPos(cursor, handled, point, myPos);
00232             if (e != 0) return e;
00233         }
00234         if (hasUpperLeft()) {
00235             e = upperLeft->goToPos(cursor, handled, point, myPos);
00236             if (e != 0) return e;
00237         }
00238         if (hasLowerRight()) {
00239             e = lowerRight->goToPos(cursor, handled, point, myPos);
00240             if (e != 0) return e;
00241         }
00242         if (hasLowerMiddle()) {
00243             e = lowerMiddle->goToPos(cursor, handled, point, myPos);
00244             if (e != 0) return e;
00245         }
00246         if (hasLowerLeft()) {
00247             e = lowerLeft->goToPos(cursor, handled, point, myPos);
00248             if (e != 0) return e;
00249         }
00250 
00251         luPixel dx = point.x() - myPos.x();
00252         luPixel dy = point.y() - myPos.y();
00253 
00254         // the positions after the left indexes
00255         if (dx < content->getX()+content->getWidth()) {
00256             if (dy < content->getY()) {
00257                 if (hasUpperMiddle() && (dx > upperMiddle->getX())) {
00258                     upperMiddle->moveLeft(cursor, this);
00259                     handled = true;
00260                     return upperMiddle;
00261                 }
00262                 if (hasUpperLeft() && (dx > upperLeft->getX())) {
00263                     upperLeft->moveLeft(cursor, this);
00264                     handled = true;
00265                     return upperLeft;
00266                 }
00267             }
00268             else if (dy > content->getY()+content->getHeight()) {
00269                 if (hasLowerMiddle() && (dx > lowerMiddle->getX())) {
00270                     lowerMiddle->moveLeft(cursor, this);
00271                     handled = true;
00272                     return lowerMiddle;
00273                 }
00274                 if (hasLowerLeft() && (dx > lowerLeft->getX())) {
00275                     lowerLeft->moveLeft(cursor, this);
00276                     handled = true;
00277                     return lowerLeft;
00278                 }
00279             }
00280         }
00281         // the positions after the left indexes
00282         else {
00283             if (dy < content->getY()) {
00284                 if (hasUpperRight()) {
00285                     upperRight->moveLeft(cursor, this);
00286                     handled = true;
00287                     return upperRight;
00288                 }
00289             }
00290             else if (dy > content->getY()+content->getHeight()) {
00291                 if (hasLowerRight()) {
00292                     lowerRight->moveLeft(cursor, this);
00293                     handled = true;
00294                     return lowerRight;
00295                 }
00296             }
00297             else {
00298                 content->moveLeft(cursor, this);
00299                 handled = true;
00300                 return content;
00301             }
00302         }
00303 
00304         return this;
00305     }
00306     return 0;
00307 }
00308 
00309 
00310 // drawing
00311 //
00312 // Drawing depends on a context which knows the required properties like
00313 // fonts, spaces and such.
00314 // It is essential to calculate elements size with the same context
00315 // before you draw.
00316 
00317 
00318 void IndexElement::setMiddleX(int xOffset, int middleWidth)
00319 {
00320     content->setX(xOffset + (middleWidth - content->getWidth()) / 2);
00321     if (hasUpperMiddle()) {
00322         upperMiddle->setX(xOffset + (middleWidth - upperMiddle->getWidth()) / 2);
00323     }
00324     if (hasLowerMiddle()) {
00325         lowerMiddle->setX(xOffset + (middleWidth - lowerMiddle->getWidth()) / 2);
00326     }
00327 }
00328 
00329 
00334 void IndexElement::calcSizes(const ContextStyle& style, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle)
00335 {
00336     luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00337 
00338     ContextStyle::TextStyle i_tstyle = style.convertTextStyleIndex(tstyle);
00339     ContextStyle::IndexStyle u_istyle = style.convertIndexStyleUpper( istyle );
00340     ContextStyle::IndexStyle l_istyle = style.convertIndexStyleLower( istyle );
00341 
00342     // get the indexes size
00343     luPixel ulWidth = 0, ulHeight = 0, ulMidline = 0;
00344     if (hasUpperLeft()) {
00345         upperLeft->calcSizes( style, i_tstyle, u_istyle );
00346         ulWidth = upperLeft->getWidth();
00347         ulHeight = upperLeft->getHeight();
00348         ulMidline = upperLeft->axis( style, i_tstyle );
00349     }
00350 
00351     luPixel umWidth = 0, umHeight = 0, umMidline = 0;
00352     if (hasUpperMiddle()) {
00353     upperMiddle->calcSizes( style, i_tstyle, u_istyle );
00354         umWidth = upperMiddle->getWidth();
00355         umHeight = upperMiddle->getHeight() + distY;
00356         umMidline = upperMiddle->axis( style, i_tstyle );
00357     }
00358 
00359     luPixel urWidth = 0, urHeight = 0, urMidline = 0;
00360     if (hasUpperRight()) {
00361         upperRight->calcSizes( style, i_tstyle, u_istyle );
00362         urWidth = upperRight->getWidth();
00363         urHeight = upperRight->getHeight();
00364         urMidline = upperRight->axis( style, i_tstyle );
00365     }
00366 
00367     luPixel llWidth = 0, llHeight = 0, llMidline = 0;
00368     if (hasLowerLeft()) {
00369         lowerLeft->calcSizes( style, i_tstyle, l_istyle );
00370         llWidth = lowerLeft->getWidth();
00371         llHeight = lowerLeft->getHeight();
00372         llMidline = lowerLeft->axis( style, i_tstyle );
00373     }
00374 
00375     luPixel lmWidth = 0, lmHeight = 0, lmMidline = 0;
00376     if (hasLowerMiddle()) {
00377         lowerMiddle->calcSizes( style, i_tstyle, l_istyle );
00378         lmWidth = lowerMiddle->getWidth();
00379         lmHeight = lowerMiddle->getHeight() + distY;
00380         lmMidline = lowerMiddle->axis( style, i_tstyle );
00381     }
00382 
00383     luPixel lrWidth = 0, lrHeight = 0, lrMidline = 0;
00384     if (hasLowerRight()) {
00385         lowerRight->calcSizes( style, i_tstyle, l_istyle );
00386         lrWidth = lowerRight->getWidth();
00387         lrHeight = lowerRight->getHeight();
00388         lrMidline = lowerRight->axis( style, i_tstyle );
00389     }
00390 
00391     // get the contents size
00392     content->calcSizes(style, tstyle, istyle);
00393     luPixel width = QMAX(content->getWidth(), QMAX(umWidth, lmWidth));
00394     luPixel toMidline = content->axis( style, tstyle );
00395     luPixel fromMidline = content->getHeight() - toMidline;
00396 
00397     // calculate the x offsets
00398     if (ulWidth > llWidth) {
00399         upperLeft->setX(0);
00400         if (hasLowerLeft()) {
00401             lowerLeft->setX(ulWidth - llWidth);
00402         }
00403         setMiddleX(ulWidth, width);
00404         width += ulWidth;
00405     }
00406     else {
00407         if (hasUpperLeft()) {
00408             upperLeft->setX(llWidth - ulWidth);
00409         }
00410         if (hasLowerLeft()) {
00411             lowerLeft->setX(0);
00412         }
00413         setMiddleX(llWidth, width);
00414         width += llWidth;
00415     }
00416 
00417     if (hasUpperRight()) {
00418         upperRight->setX(width);
00419     }
00420     if (hasLowerRight()) {
00421         lowerRight->setX(width);
00422     }
00423     width += QMAX(urWidth, lrWidth);
00424 
00425     // calculate the y offsets
00426     luPixel ulOffset = 0;
00427     luPixel urOffset = 0;
00428     luPixel llOffset = 0;
00429     luPixel lrOffset = 0;
00430     if (content->isTextOnly()) {
00431         luPt mySize = style.getAdjustedSize( tstyle );
00432         QFont font = style.getDefaultFont();
00433         font.setPointSizeFloat( style.layoutUnitPtToPt( mySize ) );
00434 
00435         QFontMetrics fm(font);
00436         LuPixelRect bound = fm.boundingRect('x');
00437 
00438         luPixel exBaseline = style.ptToLayoutUnitPt( -bound.top() );
00439 
00440         // the upper half
00441         ulOffset = ulHeight + exBaseline - content->getBaseline();
00442         urOffset = urHeight + exBaseline - content->getBaseline();
00443 
00444         // the lower half
00445         llOffset = lrOffset = content->getBaseline();
00446     }
00447     else {
00448 
00449         // the upper half
00450         ulOffset = QMAX(ulMidline, ulHeight-toMidline);
00451         urOffset = QMAX(urMidline, urHeight-toMidline);
00452 
00453         // the lower half
00454         llOffset = QMAX(content->getHeight()-llMidline, toMidline);
00455         lrOffset = QMAX(content->getHeight()-lrMidline, toMidline);
00456     }
00457     luPixel height = QMAX(umHeight, QMAX(ulOffset, urOffset));
00458 
00459     // the upper half
00460     content->setY(height);
00461     toMidline += height;
00462     if (hasUpperLeft()) {
00463         upperLeft->setY(height-ulOffset);
00464     }
00465     if (hasUpperMiddle()) {
00466         upperMiddle->setY(height-umHeight);
00467     }
00468     if (hasUpperRight()) {
00469         upperRight->setY(height-urOffset);
00470     }
00471 
00472     // the lower half
00473     if (hasLowerLeft()) {
00474         lowerLeft->setY(height+llOffset);
00475     }
00476     if (hasLowerMiddle()) {
00477         lowerMiddle->setY(height+content->getHeight()+distY);
00478     }
00479     if (hasLowerRight()) {
00480         lowerRight->setY(height+lrOffset);
00481     }
00482 
00483     fromMidline += QMAX(QMAX(llHeight+llOffset, lrHeight+lrOffset) - content->getHeight(), lmHeight);
00484 
00485     // set the result
00486     setWidth(width);
00487     setHeight(toMidline+fromMidline);
00488     if (content->isTextOnly()) {
00489         setBaseline(content->getY() + content->getBaseline());
00490         //setMidline(content->getY() + content->getMidline());
00491     }
00492     else {
00493         //setMidline(toMidline);
00494         setBaseline(content->getBaseline() + content->getY());
00495     }
00496 }
00497 
00503 void IndexElement::draw( QPainter& painter, const LuPixelRect& r,
00504                          const ContextStyle& style,
00505                          ContextStyle::TextStyle tstyle,
00506                          ContextStyle::IndexStyle istyle,
00507                          const LuPixelPoint& parentOrigin )
00508 {
00509     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00510     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00511     //    return;
00512 
00513     ContextStyle::TextStyle i_tstyle = style.convertTextStyleIndex(tstyle);
00514     ContextStyle::IndexStyle u_istyle = style.convertIndexStyleUpper( istyle );
00515     ContextStyle::IndexStyle l_istyle = style.convertIndexStyleLower( istyle );
00516 
00517     content->draw(painter, r, style, tstyle, istyle, myPos);
00518     if (hasUpperLeft()) {
00519         upperLeft->draw(painter, r, style, i_tstyle, u_istyle, myPos);
00520     }
00521     if (hasUpperMiddle()) {
00522         upperMiddle->draw(painter, r, style, i_tstyle, u_istyle, myPos);
00523     }
00524     if (hasUpperRight()) {
00525         upperRight->draw(painter, r, style, i_tstyle, u_istyle, myPos);
00526     }
00527     if (hasLowerLeft()) {
00528         lowerLeft->draw(painter, r, style, i_tstyle, l_istyle, myPos);
00529     }
00530     if (hasLowerMiddle()) {
00531         lowerMiddle->draw(painter, r, style, i_tstyle, l_istyle, myPos);
00532     }
00533     if (hasLowerRight()) {
00534         lowerRight->draw(painter, r, style, i_tstyle, l_istyle, myPos);
00535     }
00536 
00537     // Debug
00538     //painter.setBrush(Qt::NoBrush);
00539     //painter.setPen(Qt::red);
00540     //painter.drawRect(myPos.x(), myPos.y(), getWidth(), getHeight());
00541     //painter.drawLine(myPos.x(), myPos.y()+getMidline(),
00542     //                 myPos.x()+getWidth(), myPos.y()+getMidline());
00543 }
00544 
00545 
00546 void IndexElement::dispatchFontCommand( FontCommand* cmd )
00547 {
00548     content->dispatchFontCommand( cmd );
00549     if (hasUpperLeft()) {
00550         upperLeft->dispatchFontCommand( cmd );
00551     }
00552     if (hasUpperMiddle()) {
00553         upperMiddle->dispatchFontCommand( cmd );
00554     }
00555     if (hasUpperRight()) {
00556         upperRight->dispatchFontCommand( cmd );
00557     }
00558     if (hasLowerLeft()) {
00559         lowerLeft->dispatchFontCommand( cmd );
00560     }
00561     if (hasLowerMiddle()) {
00562         lowerMiddle->dispatchFontCommand( cmd );
00563     }
00564     if (hasLowerRight()) {
00565         lowerRight->dispatchFontCommand( cmd );
00566     }
00567 }
00568 
00569 
00570 // navigation
00571 //
00572 // The elements are responsible to handle cursor movement themselves.
00573 // To do this they need to know the direction the cursor moves and
00574 // the element it comes from.
00575 //
00576 // The cursor might be in normal or in selection mode.
00577 
00578 int IndexElement::getFromPos(BasicElement* from)
00579 {
00580     if (from == lowerRight) {
00581         return lowerRightPos;
00582     }
00583     else if (from == upperRight) {
00584         return upperRightPos;
00585     }
00586     else if (from == lowerMiddle) {
00587         return lowerMiddlePos;
00588     }
00589     else if (from == content) {
00590         return contentPos;
00591     }
00592     else if (from == upperMiddle) {
00593         return upperMiddlePos;
00594     }
00595     else if (from == lowerLeft) {
00596         return lowerLeftPos;
00597     }
00598     else if (from == upperLeft) {
00599         return upperLeftPos;
00600     }
00601     return parentPos;
00602 }
00603 
00609 void IndexElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
00610 {
00611     if (cursor->isSelectionMode()) {
00612         getParent()->moveLeft(cursor, this);
00613     }
00614     else {
00615         bool linear = cursor->getLinearMovement();
00616         int fromPos = getFromPos(from);
00617         if (!linear) {
00618             if ((fromPos == lowerRightPos) && hasLowerMiddle()) {
00619                 lowerMiddle->moveLeft(cursor, this);
00620                 return;
00621             }
00622             else if ((fromPos == upperRightPos) && hasUpperMiddle()) {
00623                 upperMiddle->moveLeft(cursor, this);
00624                 return;
00625             }
00626             else if ((fromPos == lowerMiddlePos) && hasLowerLeft()) {
00627                 lowerLeft->moveLeft(cursor, this);
00628                 return;
00629             }
00630             else if ((fromPos == upperMiddlePos) && hasUpperLeft()) {
00631                 upperLeft->moveLeft(cursor, this);
00632                 return;
00633             }
00634         }
00635         switch (fromPos) {
00636             case parentPos:
00637                 if (hasLowerRight() && linear) {
00638                     lowerRight->moveLeft(cursor, this);
00639                     break;
00640                 }
00641             case lowerRightPos:
00642                 if (hasUpperRight() && linear) {
00643                     upperRight->moveLeft(cursor, this);
00644                     break;
00645                 }
00646             case upperRightPos:
00647                 if (hasLowerMiddle() && linear) {
00648                     lowerMiddle->moveLeft(cursor, this);
00649                     break;
00650                 }
00651             case lowerMiddlePos:
00652                 content->moveLeft(cursor, this);
00653                 break;
00654             case contentPos:
00655                 if (hasUpperMiddle() && linear) {
00656                     upperMiddle->moveLeft(cursor, this);
00657                     break;
00658                 }
00659             case upperMiddlePos:
00660                 if (hasLowerLeft() && linear) {
00661                     lowerLeft->moveLeft(cursor, this);
00662                     break;
00663                 }
00664             case lowerLeftPos:
00665                 if (hasUpperLeft() && linear) {
00666                     upperLeft->moveLeft(cursor, this);
00667                     break;
00668                 }
00669             case upperLeftPos:
00670                 getParent()->moveLeft(cursor, this);
00671         }
00672     }
00673 }
00674 
00680 void IndexElement::moveRight(FormulaCursor* cursor, BasicElement* from)
00681 {
00682     if (cursor->isSelectionMode()) {
00683         getParent()->moveRight(cursor, this);
00684     }
00685     else {
00686         bool linear = cursor->getLinearMovement();
00687         int fromPos = getFromPos(from);
00688         if (!linear) {
00689             if ((fromPos == lowerLeftPos) && hasLowerMiddle()) {
00690                 lowerMiddle->moveRight(cursor, this);
00691                 return;
00692             }
00693             else if ((fromPos == upperLeftPos) && hasUpperMiddle()) {
00694                 upperMiddle->moveRight(cursor, this);
00695                 return;
00696             }
00697             else if ((fromPos == lowerMiddlePos) && hasLowerRight()) {
00698                 lowerRight->moveRight(cursor, this);
00699                 return;
00700             }
00701             else if ((fromPos == upperMiddlePos) && hasUpperRight()) {
00702                 upperRight->moveRight(cursor, this);
00703                 return;
00704             }
00705         }
00706         switch (fromPos) {
00707             case parentPos:
00708                 if (hasUpperLeft() && linear) {
00709                     upperLeft->moveRight(cursor, this);
00710                     break;
00711                 }
00712             case upperLeftPos:
00713                 if (hasLowerLeft() && linear) {
00714                     lowerLeft->moveRight(cursor, this);
00715                     break;
00716                 }
00717             case lowerLeftPos:
00718                 if (hasUpperMiddle() && linear) {
00719                     upperMiddle->moveRight(cursor, this);
00720                     break;
00721                 }
00722             case upperMiddlePos:
00723                 content->moveRight(cursor, this);
00724                 break;
00725             case contentPos:
00726                 if (hasLowerMiddle() && linear) {
00727                     lowerMiddle->moveRight(cursor, this);
00728                     break;
00729                 }
00730             case lowerMiddlePos:
00731                 if (hasUpperRight() && linear) {
00732                     upperRight->moveRight(cursor, this);
00733                     break;
00734                 }
00735             case upperRightPos:
00736                 if (hasLowerRight() && linear) {
00737                     lowerRight->moveRight(cursor, this);
00738                     break;
00739                 }
00740             case lowerRightPos:
00741                 getParent()->moveRight(cursor, this);
00742         }
00743     }
00744 }
00745 
00751 void IndexElement::moveUp(FormulaCursor* cursor, BasicElement* from)
00752 {
00753     if (cursor->isSelectionMode()) {
00754         getParent()->moveUp(cursor, this);
00755     }
00756     else {
00757         if (from == content) {
00758             if ((cursor->getPos() == 0) && (cursor->getElement() == from)) {
00759                 if (hasUpperLeft()) {
00760                     upperLeft->moveLeft(cursor, this);
00761                     return;
00762                 }
00763                 else if (hasUpperMiddle()) {
00764                     upperMiddle->moveRight(cursor, this);
00765                     return;
00766                 }
00767             }
00768             if (hasUpperRight()) {
00769                 upperRight->moveRight(cursor, this);
00770             }
00771             else if (hasUpperMiddle()) {
00772                 upperMiddle->moveLeft(cursor, this);
00773             }
00774             else if (hasUpperLeft()) {
00775                 upperLeft->moveLeft(cursor, this);
00776             }
00777             else {
00778                 getParent()->moveUp(cursor, this);
00779             }
00780         }
00781         else if ((from == upperLeft) || (from == upperMiddle) || (from == upperRight)) {
00782             getParent()->moveUp(cursor, this);
00783         }
00784         else if ((from == getParent()) || (from == lowerLeft) || (from == lowerMiddle)) {
00785             content->moveRight(cursor, this);
00786         }
00787         else if (from == lowerRight) {
00788             content->moveLeft(cursor, this);
00789         }
00790     }
00791 }
00792 
00798 void IndexElement::moveDown(FormulaCursor* cursor, BasicElement* from)
00799 {
00800     if (cursor->isSelectionMode()) {
00801         getParent()->moveDown(cursor, this);
00802     }
00803     else {
00804         if (from == content) {
00805             if ((cursor->getPos() == 0) && (cursor->getElement() == from)) {
00806                 if (hasLowerLeft()) {
00807                     lowerLeft->moveLeft(cursor, this);
00808                     return;
00809                 }
00810                 else if (hasLowerMiddle()) {
00811                     lowerMiddle->moveRight(cursor, this);
00812                     return;
00813                 }
00814             }
00815             if (hasLowerRight()) {
00816                 lowerRight->moveRight(cursor, this);
00817             }
00818             else if (hasLowerMiddle()) {
00819                 lowerMiddle->moveLeft(cursor, this);
00820             }
00821             else if (hasLowerLeft()) {
00822                 lowerLeft->moveLeft(cursor, this);
00823             }
00824             else {
00825                 getParent()->moveDown(cursor, this);
00826             }
00827         }
00828         else if ((from == lowerLeft) || (from == lowerMiddle) || (from == lowerRight)) {
00829             getParent()->moveDown(cursor, this);
00830         }
00831         else if ((from == getParent()) || (from == upperLeft) || (from == upperMiddle)) {
00832             content->moveRight(cursor, this);
00833         }
00834         if (from == upperRight) {
00835             content->moveLeft(cursor, this);
00836         }
00837     }
00838 }
00839 
00840 
00841 // children
00842 
00843 
00844 // main child
00845 //
00846 // If an element has children one has to become the main one.
00847 
00848 // void IndexElement::setMainChild(SequenceElement* child)
00849 // {
00850 //     formula()->elementRemoval(content);
00851 //     content = child;
00852 //     content->setParent(this);
00853 //     formula()->changed();
00854 // }
00855 
00856 
00867 void IndexElement::insert(FormulaCursor* cursor,
00868                           QPtrList<BasicElement>& newChildren,
00869                           Direction direction)
00870 {
00871     SequenceElement* index = static_cast<SequenceElement*>(newChildren.take(0));
00872     index->setParent(this);
00873 
00874     switch (cursor->getPos()) {
00875     case upperLeftPos:
00876         upperLeft = index;
00877         break;
00878     case lowerLeftPos:
00879         lowerLeft = index;
00880         break;
00881     case upperMiddlePos:
00882         upperMiddle = index;
00883         break;
00884     case lowerMiddlePos:
00885         lowerMiddle = index;
00886         break;
00887     case upperRightPos:
00888         upperRight = index;
00889         break;
00890     case lowerRightPos:
00891         lowerRight = index;
00892         break;
00893     default:
00894         // this is an error!
00895         return;
00896     }
00897 
00898     if (direction == beforeCursor) {
00899         index->moveLeft(cursor, this);
00900     }
00901     else {
00902         index->moveRight(cursor, this);
00903     }
00904     cursor->setSelection(false);
00905     formula()->changed();
00906 }
00907 
00908 
00920 void IndexElement::remove(FormulaCursor* cursor,
00921                           QPtrList<BasicElement>& removedChildren,
00922                           Direction direction)
00923 {
00924     int pos = cursor->getPos();
00925     switch (pos) {
00926     case upperLeftPos:
00927         removedChildren.append(upperLeft);
00928         formula()->elementRemoval(upperLeft);
00929         upperLeft = 0;
00930         setToUpperLeft(cursor);
00931         break;
00932     case lowerLeftPos:
00933         removedChildren.append(lowerLeft);
00934         formula()->elementRemoval(lowerLeft);
00935         lowerLeft = 0;
00936         setToLowerLeft(cursor);
00937         break;
00938     case contentPos: {
00939         BasicElement* parent = getParent();
00940         parent->selectChild(cursor, this);
00941         parent->remove(cursor, removedChildren, direction);
00942         break;
00943     }
00944     case upperMiddlePos:
00945         removedChildren.append(upperMiddle);
00946         formula()->elementRemoval(upperMiddle);
00947         upperMiddle = 0;
00948         setToUpperMiddle(cursor);
00949         break;
00950     case lowerMiddlePos:
00951         removedChildren.append(lowerMiddle);
00952         formula()->elementRemoval(lowerMiddle);
00953         lowerMiddle = 0;
00954         setToLowerMiddle(cursor);
00955         break;
00956     case upperRightPos:
00957         removedChildren.append(upperRight);
00958         formula()->elementRemoval(upperRight);
00959         upperRight = 0;
00960         setToUpperRight(cursor);
00961         break;
00962     case lowerRightPos:
00963         removedChildren.append(lowerRight);
00964         formula()->elementRemoval(lowerRight);
00965         lowerRight = 0;
00966         setToLowerRight(cursor);
00967         break;
00968     }
00969     formula()->changed();
00970 }
00971 
00976 void IndexElement::normalize(FormulaCursor* cursor, Direction direction)
00977 {
00978     if (direction == beforeCursor) {
00979         content->moveLeft(cursor, this);
00980     }
00981     else {
00982         content->moveRight(cursor, this);
00983     }
00984 }
00985 
00991 bool IndexElement::isSenseless()
00992 {
00993     return !hasUpperLeft() && !hasUpperRight() && !hasUpperMiddle() &&
00994         !hasLowerLeft() && !hasLowerRight() && !hasLowerMiddle();
00995 }
00996 
00997 
01001 BasicElement* IndexElement::getChild(FormulaCursor* cursor, Direction)
01002 {
01003     int pos = cursor->getPos();
01004     /*
01005       It makes no sense to care for the direction.
01006     if (direction == beforeCursor) {
01007         pos -= 1;
01008     }
01009     */
01010     switch (pos) {
01011     case contentPos:
01012         return content;
01013     case upperLeftPos:
01014         return upperLeft;
01015     case lowerLeftPos:
01016         return lowerLeft;
01017     case upperMiddlePos:
01018         return upperMiddle;
01019     case lowerMiddlePos:
01020         return lowerMiddle;
01021     case upperRightPos:
01022         return upperRight;
01023     case lowerRightPos:
01024         return lowerRight;
01025     }
01026     return 0;
01027 }
01028 
01029 
01034 void IndexElement::selectChild(FormulaCursor* cursor, BasicElement* child)
01035 {
01036     if (child == content) {
01037         setToContent(cursor);
01038     }
01039     else if (child == upperLeft) {
01040         setToUpperLeft(cursor);
01041     }
01042     else if (child == lowerLeft) {
01043         setToLowerLeft(cursor);
01044     }
01045     else if (child == upperMiddle) {
01046         setToUpperMiddle(cursor);
01047     }
01048     else if (child == lowerMiddle) {
01049         setToLowerMiddle(cursor);
01050     }
01051     else if (child == upperRight) {
01052         setToUpperRight(cursor);
01053     }
01054     else if (child == lowerRight) {
01055         setToLowerRight(cursor);
01056     }
01057 }
01058 
01059 
01066 void IndexElement::setToContent(FormulaCursor* cursor)
01067 {
01068     cursor->setTo(this, contentPos);
01069 }
01070 
01071 // point the cursor to a gap where an index is to be inserted.
01072 // this makes no sense if there is such an index already.
01073 
01074 void IndexElement::setToUpperLeft(FormulaCursor* cursor)
01075 {
01076     cursor->setTo(this, upperLeftPos);
01077 }
01078 
01079 void IndexElement::setToUpperMiddle(FormulaCursor* cursor)
01080 {
01081     cursor->setTo(this, upperMiddlePos);
01082 }
01083 
01084 void IndexElement::setToUpperRight(FormulaCursor* cursor)
01085 {
01086     cursor->setTo(this, upperRightPos);
01087 }
01088 
01089 void IndexElement::setToLowerLeft(FormulaCursor* cursor)
01090 {
01091     cursor->setTo(this, lowerLeftPos);
01092 }
01093 
01094 void IndexElement::setToLowerMiddle(FormulaCursor* cursor)
01095 {
01096     cursor->setTo(this, lowerMiddlePos);
01097 }
01098 
01099 void IndexElement::setToLowerRight(FormulaCursor* cursor)
01100 {
01101     cursor->setTo(this, lowerRightPos);
01102 }
01103 
01104 
01105 // move inside an index that exists already.
01106 
01107 void IndexElement::moveToUpperLeft(FormulaCursor* cursor, Direction direction)
01108 {
01109     if (hasUpperLeft()) {
01110         if (direction == beforeCursor) {
01111             upperLeft->moveLeft(cursor, this);
01112         }
01113         else {
01114             upperLeft->moveRight(cursor, this);
01115         }
01116     }
01117 }
01118 
01119 void IndexElement::moveToUpperMiddle(FormulaCursor* cursor, Direction direction)
01120 {
01121     if (hasUpperMiddle()) {
01122         if (direction == beforeCursor) {
01123             upperMiddle->moveLeft(cursor, this);
01124         }
01125         else {
01126             upperMiddle->moveRight(cursor, this);
01127         }
01128     }
01129 }
01130 
01131 void IndexElement::moveToUpperRight(FormulaCursor* cursor, Direction direction)
01132 {
01133     if (hasUpperRight()) {
01134         if (direction == beforeCursor) {
01135             upperRight->moveLeft(cursor, this);
01136         }
01137         else {
01138             upperRight->moveRight(cursor, this);
01139         }
01140     }
01141 }
01142 
01143 void IndexElement::moveToLowerLeft(FormulaCursor* cursor, Direction direction)
01144 {
01145     if (hasLowerLeft()) {
01146         if (direction == beforeCursor) {
01147             lowerLeft->moveLeft(cursor, this);
01148         }
01149         else {
01150             lowerLeft->moveRight(cursor, this);
01151         }
01152     }
01153 }
01154 
01155 void IndexElement::moveToLowerMiddle(FormulaCursor* cursor, Direction direction)
01156 {
01157     if (hasLowerMiddle()) {
01158         if (direction == beforeCursor) {
01159             lowerMiddle->moveLeft(cursor, this);
01160         }
01161         else {
01162             lowerMiddle->moveRight(cursor, this);
01163         }
01164     }
01165 }
01166 
01167 void IndexElement::moveToLowerRight(FormulaCursor* cursor, Direction direction)
01168 {
01169     if (hasLowerRight()) {
01170         if (direction == beforeCursor) {
01171             lowerRight->moveLeft(cursor, this);
01172         }
01173         else {
01174             lowerRight->moveRight(cursor, this);
01175         }
01176     }
01177 }
01178 
01179 
01183 void IndexElement::writeDom(QDomElement element)
01184 {
01185     BasicElement::writeDom(element);
01186 
01187     QDomDocument doc = element.ownerDocument();
01188 
01189     QDomElement cont = doc.createElement("CONTENT");
01190     cont.appendChild(content->getElementDom(doc));
01191     element.appendChild(cont);
01192 
01193     if (hasUpperLeft()) {
01194         QDomElement ind = doc.createElement("UPPERLEFT");
01195         ind.appendChild(upperLeft->getElementDom(doc));
01196         element.appendChild(ind);
01197     }
01198     if (hasUpperMiddle()) {
01199         QDomElement ind = doc.createElement("UPPERMIDDLE");
01200         ind.appendChild(upperMiddle->getElementDom(doc));
01201         element.appendChild(ind);
01202     }
01203     if (hasUpperRight()) {
01204         QDomElement ind = doc.createElement("UPPERRIGHT");
01205         ind.appendChild(upperRight->getElementDom(doc));
01206         element.appendChild(ind);
01207     }
01208     if (hasLowerLeft()) {
01209         QDomElement ind = doc.createElement("LOWERLEFT");
01210         ind.appendChild(lowerLeft->getElementDom(doc));
01211         element.appendChild(ind);
01212     }
01213     if (hasLowerMiddle()) {
01214         QDomElement ind = doc.createElement("LOWERMIDDLE");
01215         ind.appendChild(lowerMiddle->getElementDom(doc));
01216         element.appendChild(ind);
01217     }
01218     if (hasLowerRight()) {
01219         QDomElement ind = doc.createElement("LOWERRIGHT");
01220         ind.appendChild(lowerRight->getElementDom(doc));
01221         element.appendChild(ind);
01222     }
01223 }
01224 
01229 bool IndexElement::readAttributesFromDom(QDomElement element)
01230 {
01231     if (!BasicElement::readAttributesFromDom(element)) {
01232         return false;
01233     }
01234     return true;
01235 }
01236 
01242 bool IndexElement::readContentFromDom(QDomNode& node)
01243 {
01244     if (!BasicElement::readContentFromDom(node)) {
01245         return false;
01246     }
01247 
01248     if ( !buildChild( content, node, "CONTENT" ) ) {
01249         kdWarning( DEBUGID ) << "Empty content in IndexElement." << endl;
01250         return false;
01251     }
01252     node = node.nextSibling();
01253 
01254     bool upperLeftRead = false;
01255     bool upperMiddleRead = false;
01256     bool upperRightRead = false;
01257     bool lowerLeftRead = false;
01258     bool lowerMiddleRead = false;
01259     bool lowerRightRead = false;
01260 
01261     while (!node.isNull() &&
01262            !(upperLeftRead && upperMiddleRead && upperRightRead &&
01263              lowerLeftRead && lowerMiddleRead && lowerRightRead)) {
01264 
01265         if (!upperLeftRead && (node.nodeName().upper() == "UPPERLEFT")) {
01266             upperLeftRead = buildChild( upperLeft=new SequenceElement( this ), node, "UPPERLEFT" );
01267             if ( !upperLeftRead ) return false;
01268         }
01269 
01270         if (!upperMiddleRead && (node.nodeName().upper() == "UPPERMIDDLE")) {
01271             upperMiddleRead = buildChild( upperMiddle=new SequenceElement( this ), node, "UPPERMIDDLE" );
01272             if ( !upperMiddleRead ) return false;
01273         }
01274 
01275         if (!upperRightRead && (node.nodeName().upper() == "UPPERRIGHT")) {
01276             upperRightRead = buildChild( upperRight=new SequenceElement( this ), node, "UPPERRIGHT" );
01277             if ( !upperRightRead ) return false;
01278         }
01279 
01280         if (!lowerLeftRead && (node.nodeName().upper() == "LOWERLEFT")) {
01281             lowerLeftRead = buildChild( lowerLeft=new SequenceElement( this ), node, "LOWERLEFT" );
01282             if ( !lowerLeftRead ) return false;
01283         }
01284 
01285         if (!lowerMiddleRead && (node.nodeName().upper() == "LOWERMIDDLE")) {
01286             lowerMiddleRead = buildChild( lowerMiddle=new SequenceElement( this ), node, "LOWERMIDDLE" );
01287             if ( !lowerMiddleRead ) return false;
01288         }
01289 
01290         if (!lowerRightRead && (node.nodeName().upper() == "LOWERRIGHT")) {
01291             lowerRightRead = buildChild( lowerRight=new SequenceElement( this ), node, "LOWERRIGHT" );
01292             if ( !lowerRightRead ) return false;
01293         }
01294 
01295         node = node.nextSibling();
01296     }
01297     return upperLeftRead || upperMiddleRead || upperRightRead ||
01298         lowerLeftRead || lowerMiddleRead || lowerRightRead;
01299 }
01300 
01301 ElementIndexPtr IndexElement::getIndex( int position )
01302 {
01303     switch (position) {
01304     case upperRightPos:
01305         return getUpperRight();
01306     case lowerRightPos:
01307         return getLowerRight();
01308     case lowerMiddlePos:
01309         return getLowerMiddle();
01310     case upperMiddlePos:
01311         return getUpperMiddle();
01312     case lowerLeftPos:
01313         return getLowerLeft();
01314     case upperLeftPos:
01315         return getUpperLeft();
01316     }
01317     return getUpperRight();
01318 }
01319 
01320 
01321 
01322 QString IndexElement::toLatex()
01323 {
01324     QString index;
01325 
01326     if ( hasUpperMiddle() ) {
01327         index += "\\overset{" + upperMiddle->toLatex() + "}{";
01328     }
01329 
01330     if ( hasLowerMiddle() ) {
01331         index += "\\underset{" + lowerMiddle->toLatex() + "}{";
01332     }
01333 
01334     if ( hasUpperLeft() || hasUpperRight() ) { //Not sure that this is possible in Latex!
01335         /*index += "{}";
01336         if ( hasUpperLeft() )
01337             index += "^" + upperLeft->toLatex();
01338         if ( hasLowerLeft() )
01339             index += "_" + lowerLeft->toLatex();
01340         */
01341     }
01342 
01343     index += content->toLatex();
01344 
01345     if ( hasUpperRight() || hasLowerRight() ) {
01346         if ( hasUpperRight() )
01347             index += "^{" + upperRight->toLatex() + "}";
01348         if ( hasLowerRight() )
01349             index += "_{" + lowerRight->toLatex() + "}";
01350         index += " ";
01351     }
01352 
01353     if ( hasLowerMiddle() ) {
01354         index += "}";
01355     }
01356 
01357     if ( hasUpperMiddle() ) {
01358         index += "}";
01359     }
01360 
01361     return index;
01362 }
01363 
01364 QString IndexElement::formulaString()
01365 {
01366     QString index = "(" + content->formulaString() + ")";
01367     if ( hasLowerRight() ) {
01368         index += "_(" + lowerRight->formulaString() + ")";
01369     }
01370     if ( hasUpperRight() ) {
01371         index += "**(" + upperRight->formulaString() + ")";
01372     }
01373     return index;
01374 }
01375 
01376 void IndexElement::writeMathML( QDomDocument& doc, QDomNode parent, bool oasisFormat )
01377 {
01378     QDomElement de;
01379     QDomElement uo;
01380     bool uoscripts = true;
01381 
01382     if ( hasUpperMiddle() && hasLowerMiddle() )
01383     {
01384         uo = doc.createElement( "munderover" );
01385         content->writeMathML( doc, uo, oasisFormat ); // base
01386         lowerMiddle->writeMathML( doc, uo, oasisFormat );
01387         upperMiddle->writeMathML( doc, uo,oasisFormat );
01388     }
01389     else if ( hasUpperMiddle() )
01390     {
01391         uo = doc.createElement( "mover" );
01392         content->writeMathML( doc, uo,oasisFormat ); // base
01393         upperMiddle->writeMathML( doc, uo,oasisFormat );
01394     }
01395     else if ( hasLowerMiddle() )
01396     {
01397         uo = doc.createElement( "munder" );
01398         content->writeMathML( doc, uo, oasisFormat ); // base
01399         lowerMiddle->writeMathML( doc, uo,oasisFormat );
01400     }
01401     else // no over- or underscripts
01402         uoscripts = false;
01403 
01404 
01405     if ( hasLowerLeft() || hasUpperLeft() )
01406     {
01407         de = doc.createElement( "mmultiscripts" );
01408         if ( !uoscripts ) // base
01409             content->writeMathML( doc, de, oasisFormat );
01410         else
01411             de.appendChild( uo );
01412 
01413         if ( hasLowerRight() )
01414             lowerRight->writeMathML( doc, de, oasisFormat );
01415         else
01416             de.appendChild( doc.createElement( "none" ) );
01417 
01418         if ( hasUpperRight() )
01419             upperRight->writeMathML( doc, de, oasisFormat );
01420         else
01421             de.appendChild( doc.createElement( "none" ) );
01422 
01423         de.appendChild( doc.createElement( "mprescripts" ) );
01424 
01425         if ( hasLowerLeft() )
01426             lowerLeft->writeMathML( doc, de, oasisFormat );
01427         else
01428             de.appendChild( doc.createElement( "none" ) );
01429 
01430         if ( hasUpperLeft() )
01431             upperLeft->writeMathML( doc, de, oasisFormat );
01432         else
01433             de.appendChild( doc.createElement( "none" ) );
01434     }
01435     else if ( hasLowerRight() || hasUpperRight() )
01436     {
01437         if ( !hasUpperRight() )
01438         {
01439             de = doc.createElement( "msub" );
01440             if ( !uoscripts ) // base
01441                 content->writeMathML( doc, de, oasisFormat );
01442             else
01443                 de.appendChild( uo );
01444             lowerRight->writeMathML( doc, de, oasisFormat );
01445         }
01446         else if ( !hasLowerRight() )
01447         {
01448             de = doc.createElement( "msup" );
01449             if ( !uoscripts ) // base
01450                 content->writeMathML( doc, de, oasisFormat );
01451             else
01452                 de.appendChild( uo );
01453             upperRight->writeMathML( doc, de, oasisFormat );
01454         }
01455         else // both
01456         {
01457             de = doc.createElement( "msubsup" );
01458             if ( !uoscripts ) // base
01459                 content->writeMathML( doc, de, oasisFormat );
01460             else
01461                 de.appendChild( uo );
01462             lowerRight->writeMathML( doc, de, oasisFormat );
01463             upperRight->writeMathML( doc, de,oasisFormat );
01464         }
01465     }
01466     else // no mmultiscripts, msubsup, msub or msup
01467         de = uo;
01468 
01469 
01470     parent.appendChild( de );
01471 
01472 }
01473 
01474 KFORMULA_NAMESPACE_END
KDE Logo
This file is part of the documentation for lib Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:39:56 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003