lib

rootelement.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 #include <qpen.h>
00023 
00024 #include <kdebug.h>
00025 #include <klocale.h>
00026 
00027 #include "elementvisitor.h"
00028 #include "formulacursor.h"
00029 #include "formulaelement.h"
00030 #include "kformulacommand.h"
00031 #include "rootelement.h"
00032 #include "sequenceelement.h"
00033 
00034 KFORMULA_NAMESPACE_BEGIN
00035 
00036 
00037 class RootSequenceElement : public SequenceElement {
00038     typedef SequenceElement inherited;
00039 public:
00040 
00041     RootSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
00042     virtual RootSequenceElement* clone() {
00043         return new RootSequenceElement( *this );
00044     }
00045 
00054     virtual KCommand* buildCommand( Container*, Request* );
00055 };
00056 
00057 
00058 KCommand* RootSequenceElement::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         IndexRequest* ir = static_cast<IndexRequest*>( request );
00073         if ( ir->index() == upperLeftPos ) {
00074             RootElement* element = static_cast<RootElement*>( getParent() );
00075             ElementIndexPtr index = element->getIndex();
00076             if ( !index->hasIndex() ) {
00077                 KFCAddGenericIndex* command = new KFCAddGenericIndex( container, index );
00078                 return command;
00079             }
00080             else {
00081                 index->moveToIndex( cursor, afterCursor );
00082                 cursor->setSelection( false );
00083                 formula()->cursorHasMoved( cursor );
00084                 return 0;
00085             }
00086         }
00087     }
00088     default:
00089         break;
00090     }
00091     return inherited::buildCommand( container, request );
00092 }
00093 
00094 
00095 RootElement::RootElement(BasicElement* parent)
00096     : BasicElement(parent)
00097 {
00098     content = new RootSequenceElement( this );
00099     index = 0;
00100 }
00101 
00102 RootElement::~RootElement()
00103 {
00104     delete index;
00105     delete content;
00106 }
00107 
00108 
00109 RootElement::RootElement( const RootElement& other )
00110     : BasicElement( other )
00111 {
00112     content = new RootSequenceElement( *dynamic_cast<RootSequenceElement*>( other.content ) );
00113     if ( other.index ) {
00114         index = new SequenceElement( *( other.index ) );
00115         index->setParent( this );
00116     }
00117     else {
00118         index = 0;
00119     }
00120 }
00121 
00122 
00123 bool RootElement::accept( ElementVisitor* visitor )
00124 {
00125     return visitor->visit( this );
00126 }
00127 
00128 
00129 void RootElement::entered( SequenceElement* child )
00130 {
00131     if ( child == content ) {
00132         formula()->tell( i18n( "Main list of root" ) );
00133     }
00134     else {
00135         formula()->tell( i18n( "Index" ) );
00136     }
00137 }
00138 
00139 
00140 BasicElement* RootElement::goToPos( FormulaCursor* cursor, bool& handled,
00141                                     const LuPixelPoint& point, const LuPixelPoint& parentOrigin)
00142 {
00143     BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00144     if (e != 0) {
00145         LuPixelPoint myPos(parentOrigin.x() + getX(),
00146                            parentOrigin.y() + getY());
00147 
00148         e = content->goToPos(cursor, handled, point, myPos);
00149         if (e != 0) {
00150             return e;
00151         }
00152         if (hasIndex()) {
00153             e = index->goToPos(cursor, handled, point, myPos);
00154             if (e != 0) {
00155                 return e;
00156             }
00157         }
00158 
00159         //int dx = point.x() - myPos.x();
00160         luPixel dy = point.y() - myPos.y();
00161 
00162         // the position after the index
00163         if (hasIndex()) {
00164             if (dy < index->getHeight()) {
00165                 index->moveLeft(cursor, this);
00166                 handled = true;
00167                 return index;
00168             }
00169         }
00170 
00171         return this;
00172     }
00173     return 0;
00174 }
00175 
00176 
00181 void RootElement::calcSizes( const ContextStyle& context,
00182                              ContextStyle::TextStyle tstyle,
00183                              ContextStyle::IndexStyle istyle,
00184                              StyleAttributes& style )
00185 {
00186     content->calcSizes( context, tstyle,
00187                         context.convertIndexStyleLower(istyle), style );
00188 
00189     luPixel indexWidth = 0;
00190     luPixel indexHeight = 0;
00191     if (hasIndex()) {
00192         index->calcSizes( context,
00193                           context.convertTextStyleIndex(tstyle),
00194                           context.convertIndexStyleUpper(istyle),
00195                           style );
00196         indexWidth = index->getWidth();
00197         indexHeight = index->getHeight();
00198     }
00199 
00200     double factor = style.sizeFactor();
00201     luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
00202     luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
00203     luPixel unit = (content->getHeight() + distY)/ 3;
00204 
00205     if (hasIndex()) {
00206         if (indexWidth > unit) {
00207             index->setX(0);
00208             rootOffset.setX( indexWidth - unit );
00209         }
00210         else {
00211             index->setX( ( unit - indexWidth )/2 );
00212             rootOffset.setX(0);
00213         }
00214         if (indexHeight > unit) {
00215             index->setY(0);
00216             rootOffset.setY( indexHeight - unit );
00217         }
00218         else {
00219             index->setY( unit - indexHeight );
00220             rootOffset.setY(0);
00221         }
00222     }
00223     else {
00224         rootOffset.setX(0);
00225         rootOffset.setY(0);
00226     }
00227 
00228     setWidth( content->getWidth() + unit+unit/3+ rootOffset.x() + distX/2 );
00229     setHeight( content->getHeight() + distY*2 + rootOffset.y() );
00230 
00231     content->setX( rootOffset.x() + unit+unit/3 );
00232     content->setY( rootOffset.y() + distY );
00233     setBaseline(content->getBaseline() + content->getY());
00234 }
00235 
00241 void RootElement::draw( QPainter& painter, const LuPixelRect& r,
00242                         const ContextStyle& context,
00243                         ContextStyle::TextStyle tstyle,
00244                         ContextStyle::IndexStyle istyle,
00245                         StyleAttributes& style,
00246                         const LuPixelPoint& parentOrigin )
00247 {
00248     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00249     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00250     //    return;
00251 
00252     content->draw( painter, r, context, tstyle,
00253                    context.convertIndexStyleLower(istyle), style, myPos);
00254     if (hasIndex()) {
00255         index->draw(painter, r, context,
00256                     context.convertTextStyleIndex(tstyle),
00257                     context.convertIndexStyleUpper(istyle), style, myPos);
00258     }
00259 
00260     luPixel x = myPos.x() + rootOffset.x();
00261     luPixel y = myPos.y() + rootOffset.y();
00262     //int distX = context.getDistanceX(tstyle);
00263     double factor = style.sizeFactor();
00264     luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
00265     luPixel unit = (content->getHeight() + distY)/ 3;
00266 
00267     painter.setPen( QPen( style.color(),
00268                           context.layoutUnitToPixelX( 2*context.getLineWidth( factor ) ) ) );
00269     painter.drawLine( context.layoutUnitToPixelX( x+unit/3 ),
00270                       context.layoutUnitToPixelY( y+unit+distY/3 ),
00271                       context.layoutUnitToPixelX( x+unit/2+unit/3 ),
00272                       context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
00273 
00274     painter.setPen( QPen( style.color(),
00275                           context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
00276 
00277     painter.drawLine( context.layoutUnitToPixelX( x+unit+unit/3 ),
00278                       context.layoutUnitToPixelY( y+distY/3 ),
00279                       context.layoutUnitToPixelX( x+unit/2+unit/3 ),
00280                       context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
00281     painter.drawLine( context.layoutUnitToPixelX( x+unit+unit/3 ),
00282                       context.layoutUnitToPixelY( y+distY/3 ),
00283                       context.layoutUnitToPixelX( x+unit+unit/3+content->getWidth() ),
00284                       context.layoutUnitToPixelY( y+distY/3 ) );
00285     painter.drawLine( context.layoutUnitToPixelX( x+unit/3 ),
00286                       context.layoutUnitToPixelY( y+unit+distY/2 ),
00287                       context.layoutUnitToPixelX( x ),
00288                       context.layoutUnitToPixelY( y+unit+unit/2 ) );
00289 }
00290 
00291 
00292 void RootElement::dispatchFontCommand( FontCommand* cmd )
00293 {
00294     content->dispatchFontCommand( cmd );
00295     if (hasIndex()) {
00296         index->dispatchFontCommand( cmd );
00297     }
00298 }
00299 
00305 void RootElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
00306 {
00307     if (cursor->isSelectionMode()) {
00308         getParent()->moveLeft(cursor, this);
00309     }
00310     else {
00311         bool linear = cursor->getLinearMovement();
00312         if (from == getParent()) {
00313             content->moveLeft(cursor, this);
00314         }
00315         else if (from == content) {
00316             if (linear && hasIndex()) {
00317                 index->moveLeft(cursor, this);
00318             }
00319             else {
00320                 getParent()->moveLeft(cursor, this);
00321             }
00322         }
00323         else {
00324             getParent()->moveLeft(cursor, this);
00325         }
00326     }
00327 }
00328 
00334 void RootElement::moveRight(FormulaCursor* cursor, BasicElement* from)
00335 {
00336     if (cursor->isSelectionMode()) {
00337         getParent()->moveRight(cursor, this);
00338     }
00339     else {
00340         bool linear = cursor->getLinearMovement();
00341         if (from == getParent()) {
00342             if (linear && hasIndex()) {
00343                 index->moveRight(cursor, this);
00344             }
00345             else {
00346                 content->moveRight(cursor, this);
00347             }
00348         }
00349         else if (from == index) {
00350             content->moveRight(cursor, this);
00351         }
00352         else {
00353             getParent()->moveRight(cursor, this);
00354         }
00355     }
00356 }
00357 
00363 void RootElement::moveUp(FormulaCursor* cursor, BasicElement* from)
00364 {
00365     if (cursor->isSelectionMode()) {
00366         getParent()->moveUp(cursor, this);
00367     }
00368     else {
00369         if (from == getParent()) {
00370             content->moveRight(cursor, this);
00371         }
00372         else if (from == content) {
00373             if (hasIndex()) {
00374                 index->moveRight(cursor, this);
00375             }
00376             else {
00377                 getParent()->moveUp(cursor, this);
00378             }
00379         }
00380         else {
00381             getParent()->moveUp(cursor, this);
00382         }
00383     }
00384 }
00385 
00391 void RootElement::moveDown(FormulaCursor* cursor, BasicElement* from)
00392 {
00393     if (cursor->isSelectionMode()) {
00394         getParent()->moveDown(cursor, this);
00395     }
00396     else {
00397         if (from == getParent()) {
00398             if (hasIndex()) {
00399                 index->moveRight(cursor, this);
00400             }
00401             else {
00402                 content->moveRight(cursor, this);
00403             }
00404         }
00405         else if (from == index) {
00406             content->moveRight(cursor, this);
00407         }
00408         else {
00409             getParent()->moveDown(cursor, this);
00410         }
00411     }
00412 }
00413 
00417 void RootElement::insert(FormulaCursor* cursor,
00418                          QPtrList<BasicElement>& newChildren,
00419                          Direction direction)
00420 {
00421     if (cursor->getPos() == upperLeftPos) {
00422         index = static_cast<SequenceElement*>(newChildren.take(0));
00423         index->setParent(this);
00424 
00425         if (direction == beforeCursor) {
00426             index->moveLeft(cursor, this);
00427         }
00428         else {
00429             index->moveRight(cursor, this);
00430         }
00431         cursor->setSelection(false);
00432         formula()->changed();
00433     }
00434 }
00435 
00442 void RootElement::remove(FormulaCursor* cursor,
00443                          QPtrList<BasicElement>& removedChildren,
00444                          Direction direction)
00445 {
00446     switch (cursor->getPos()) {
00447     case contentPos:
00448         getParent()->selectChild(cursor, this);
00449         getParent()->remove(cursor, removedChildren, direction);
00450         break;
00451     case upperLeftPos:
00452         removedChildren.append(index);
00453         formula()->elementRemoval(index);
00454         index = 0;
00455         cursor->setTo(this, upperLeftPos);
00456         formula()->changed();
00457         break;
00458     }
00459 }
00460 
00461 
00466 void RootElement::normalize(FormulaCursor* cursor, Direction direction)
00467 {
00468     if (direction == beforeCursor) {
00469         content->moveLeft(cursor, this);
00470     }
00471     else {
00472         content->moveRight(cursor, this);
00473     }
00474 }
00475 
00476 
00477 // main child
00478 //
00479 // If an element has children one has to become the main one.
00480 
00481 SequenceElement* RootElement::getMainChild()
00482 {
00483     return content;
00484 }
00485 
00486 // void RootElement::setMainChild(SequenceElement* child)
00487 // {
00488 //     formula()->elementRemoval(content);
00489 //     content = child;
00490 //     content->setParent(this);
00491 //     formula()->changed();
00492 // }
00493 
00494 
00499 void RootElement::selectChild(FormulaCursor* cursor, BasicElement* child)
00500 {
00501     if (child == content) {
00502         cursor->setTo(this, contentPos);
00503     }
00504     else if (child == index) {
00505         cursor->setTo(this, upperLeftPos);
00506     }
00507 }
00508 
00509 
00510 void RootElement::moveToIndex(FormulaCursor* cursor, Direction direction)
00511 {
00512     if (hasIndex()) {
00513         if (direction == beforeCursor) {
00514             index->moveLeft(cursor, this);
00515         }
00516         else {
00517             index->moveRight(cursor, this);
00518         }
00519     }
00520 }
00521 
00522 void RootElement::setToIndex(FormulaCursor* cursor)
00523 {
00524     cursor->setTo(this, upperLeftPos);
00525 }
00526 
00527 
00531 void RootElement::writeDom(QDomElement element)
00532 {
00533     BasicElement::writeDom(element);
00534 
00535     QDomDocument doc = element.ownerDocument();
00536 
00537     QDomElement con = doc.createElement("CONTENT");
00538     con.appendChild(content->getElementDom(doc));
00539     element.appendChild(con);
00540 
00541     if(hasIndex()) {
00542         QDomElement ind = doc.createElement("ROOTINDEX");
00543         ind.appendChild(index->getElementDom(doc));
00544         element.appendChild(ind);
00545     }
00546 }
00547 
00552 bool RootElement::readAttributesFromDom(QDomElement element)
00553 {
00554     return BasicElement::readAttributesFromDom(element);
00555 }
00556 
00562 bool RootElement::readContentFromDom(QDomNode& node)
00563 {
00564     if (!BasicElement::readContentFromDom(node)) {
00565         return false;
00566     }
00567 
00568     if ( !buildChild( content, node, "CONTENT" ) ) {
00569         kdWarning( DEBUGID ) << "Empty content in RootElement." << endl;
00570         return false;
00571     }
00572     node = node.nextSibling();
00573 
00574     if ( node.nodeName().upper() == "ROOTINDEX" ) {
00575         if ( !buildChild( index=new SequenceElement( this ), node, "ROOTINDEX" ) ) {
00576             return false;
00577         }
00578     }
00579     // backward compatibility
00580     else if ( node.nodeName().upper() == "INDEX" ) {
00581         if ( !buildChild( index=new SequenceElement( this ), node, "INDEX" ) ) {
00582             return false;
00583         }
00584     }
00585     node = node.nextSibling();
00586 
00587     return true;
00588 }
00589 
00595 bool RootElement::readAttributesFromMathMLDom(const QDomElement& element)
00596 {
00597     if ( element.tagName().lower() == "mroot" )
00598         square = false;
00599     else
00600         square = true;
00601     return true;
00602 }
00603 
00604 
00610 int RootElement::readContentFromMathMLDom(QDomNode& node)
00611 {
00612     if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
00613         return -1;
00614     }
00615 
00616     if ( square ) {
00617         // Any number of arguments are allowed
00618         if ( content->readContentFromMathMLDom( node ) == -1 ) {
00619             kdWarning( DEBUGID ) << "Empty content in RootElement." << endl;
00620             return -1;
00621         }
00622     }
00623     else {
00624         // Exactly two arguments are required
00625         int contentNumber = content->buildMathMLChild( node );
00626         if ( contentNumber == -1 ) {
00627             kdWarning( DEBUGID ) << "Empty content in RootElement." << endl;
00628             return -1;
00629         }
00630         for (int i = 0; i < contentNumber; i++ ) {
00631             if ( node.isNull() ) {
00632                 return -1;
00633             }
00634             node = node.nextSibling();
00635         }
00636 
00637         index = new SequenceElement( this );
00638         if ( index->buildMathMLChild( node ) == -1 ) {
00639             kdWarning( DEBUGID ) << "Empty index in RootElement." << endl;
00640             return -1;
00641         }
00642     }
00643 
00644     return 1;
00645 }
00646 
00647 QString RootElement::toLatex()
00648 {
00649     QString root;
00650     root="\\sqrt";
00651     if(hasIndex()) {
00652         root+="[";
00653     root+=index->toLatex();
00654     root+="]";
00655     }
00656     root+="{";
00657     root+=content->toLatex();
00658     root+="}";
00659 
00660     return root;
00661 }
00662 
00663 QString RootElement::formulaString()
00664 {
00665     if ( hasIndex() ) {
00666         return "(" + content->formulaString() + ")**(1.0/(" + index->formulaString() + "))";
00667     }
00668     return "sqrt(" + content->formulaString() + ")";
00669 }
00670 
00671 void RootElement::writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const
00672 {
00673     content->writeMathML( doc, element, oasisFormat );
00674     if( hasIndex() )
00675     {
00676         index->writeMathML( doc, element, oasisFormat );
00677     }
00678 }
00679 
00680 KFORMULA_NAMESPACE_END
KDE Home | KDE Accessibility Home | Description of Access Keys