lib Library API Documentation

bracketelement.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 <qptrlist.h>
00022 #include <qpainter.h>
00023 #include <qpen.h>
00024 #include <qpointarray.h>
00025 
00026 #include <kdebug.h>
00027 #include <klocale.h>
00028 
00029 #include "bracketelement.h"
00030 #include "elementvisitor.h"
00031 #include "fontstyle.h"
00032 #include "formulacursor.h"
00033 #include "formulaelement.h"
00034 #include "sequenceelement.h"
00035 
00036 KFORMULA_NAMESPACE_BEGIN
00037 
00038 SingleContentElement::SingleContentElement(BasicElement* parent )
00039     : BasicElement( parent )
00040 {
00041     content = new SequenceElement( this );
00042 }
00043 
00044 
00045 SingleContentElement::SingleContentElement( const SingleContentElement& other )
00046     : BasicElement( other )
00047 {
00048     content = new SequenceElement( other.content );
00049     content->setParent( this );
00050 }
00051 
00052 
00053 SingleContentElement::~SingleContentElement()
00054 {
00055     delete content;
00056 }
00057 
00058 
00059 QChar SingleContentElement::getCharacter() const
00060 {
00061     // This is meant to make the SingleContentElement text only.
00062     // This "fixes" the parenthesis problem (parenthesis too large).
00063     // I'm not sure if we really want this. There should be better ways.
00064     if ( content->isTextOnly() ) {
00065         return '\\';
00066     }
00067     return content->getCharacter();
00068 }
00069 
00070 BasicElement* SingleContentElement::goToPos( FormulaCursor* cursor, bool& handled,
00071                                              const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00072 {
00073     BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00074     if (e != 0) {
00075         LuPixelPoint myPos(parentOrigin.x() + getX(),
00076                            parentOrigin.y() + getY());
00077 
00078         e = content->goToPos(cursor, handled, point, myPos);
00079         if (e != 0) {
00080             return e;
00081         }
00082         return this;
00083     }
00084     return 0;
00085 }
00086 
00087 void SingleContentElement::dispatchFontCommand( FontCommand* cmd )
00088 {
00089     content->dispatchFontCommand( cmd );
00090 }
00091 
00092 void SingleContentElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
00093 {
00094     if (cursor->isSelectionMode()) {
00095         getParent()->moveLeft(cursor, this);
00096     }
00097     else {
00098         //bool linear = cursor->getLinearMovement();
00099         if (from == getParent()) {
00100             content->moveLeft(cursor, this);
00101         }
00102         else {
00103             getParent()->moveLeft(cursor, this);
00104         }
00105     }
00106 }
00107 
00108 void SingleContentElement::moveRight(FormulaCursor* cursor, BasicElement* from)
00109 {
00110     if (cursor->isSelectionMode()) {
00111         getParent()->moveRight(cursor, this);
00112     }
00113     else {
00114         //bool linear = cursor->getLinearMovement();
00115         if (from == getParent()) {
00116             content->moveRight(cursor, this);
00117         }
00118         else {
00119             getParent()->moveRight(cursor, this);
00120         }
00121     }
00122 }
00123 
00124 void SingleContentElement::moveUp(FormulaCursor* cursor, BasicElement* /*from*/)
00125 {
00126     getParent()->moveUp(cursor, this);
00127 }
00128 
00129 void SingleContentElement::moveDown(FormulaCursor* cursor, BasicElement* /*from*/)
00130 {
00131     getParent()->moveDown(cursor, this);
00132 }
00133 
00134 void SingleContentElement::remove( FormulaCursor* cursor,
00135                                    QPtrList<BasicElement>& removedChildren,
00136                                    Direction direction )
00137 {
00138     switch (cursor->getPos()) {
00139     case contentPos:
00140         BasicElement* parent = getParent();
00141         parent->selectChild(cursor, this);
00142         parent->remove(cursor, removedChildren, direction);
00143     }
00144 }
00145 
00146 void SingleContentElement::normalize( FormulaCursor* cursor, Direction direction )
00147 {
00148     if (direction == beforeCursor) {
00149         content->moveLeft(cursor, this);
00150     }
00151     else {
00152         content->moveRight(cursor, this);
00153     }
00154 }
00155 
00156 SequenceElement* SingleContentElement::getMainChild()
00157 {
00158     return content;
00159 }
00160 
00161 void SingleContentElement::selectChild(FormulaCursor* cursor, BasicElement* child)
00162 {
00163     if (child == content) {
00164         cursor->setTo(this, contentPos);
00165     }
00166 }
00167 
00168 void SingleContentElement::writeDom(QDomElement element)
00169 {
00170     BasicElement::writeDom(element);
00171 
00172     QDomDocument doc = element.ownerDocument();
00173 
00174     QDomElement con = doc.createElement("CONTENT");
00175     con.appendChild(content->getElementDom(doc));
00176     element.appendChild(con);
00177 }
00178 
00179 bool SingleContentElement::readContentFromDom(QDomNode& node)
00180 {
00181     if (!BasicElement::readContentFromDom(node)) {
00182         return false;
00183     }
00184 
00185     if ( !buildChild( content, node, "CONTENT" ) ) {
00186         kdWarning( DEBUGID ) << "Empty content in " << getTagName() << endl;
00187         return false;
00188     }
00189     node = node.nextSibling();
00190 
00191     return true;
00192 }
00193 
00194 void SingleContentElement::writeMathML( QDomDocument doc, QDomNode parent )
00195 {
00196     content->writeMathML( doc, parent );
00197 }
00198 
00199 
00200 
00201 BracketElement::BracketElement(SymbolType l, SymbolType r, BasicElement* parent)
00202     : SingleContentElement(parent),
00203       left( 0 ), right( 0 ),
00204       leftType( l ), rightType( r )
00205 {
00206 }
00207 
00208 
00209 BracketElement::~BracketElement()
00210 {
00211     delete left;
00212     delete right;
00213 }
00214 
00215 
00216 BracketElement::BracketElement( const BracketElement& other )
00217     : SingleContentElement( other ),
00218       left( 0 ), right( 0 ),
00219       leftType( other.leftType ), rightType( other.rightType )
00220 {
00221 }
00222 
00223 
00224 bool BracketElement::accept( ElementVisitor* visitor )
00225 {
00226     return visitor->visit( this );
00227 }
00228 
00229 
00230 void BracketElement::entered( SequenceElement* /*child*/ )
00231 {
00232     formula()->tell( i18n( "Delimited list" ) );
00233 }
00234 
00235 
00236 BasicElement* BracketElement::goToPos( FormulaCursor* cursor, bool& handled,
00237                                        const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00238 {
00239     BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00240     if (e != 0) {
00241         LuPixelPoint myPos(parentOrigin.x() + getX(),
00242                            parentOrigin.y() + getY());
00243         e = getContent()->goToPos(cursor, handled, point, myPos);
00244         if (e != 0) {
00245             return e;
00246         }
00247 
00248         // We are in one of those gaps.
00249         luPixel dx = point.x() - myPos.x();
00250         luPixel dy = point.y() - myPos.y();
00251 
00252         if ((dx > getContent()->getX()+getContent()->getWidth()) ||
00253             (dy > getContent()->getY()+getContent()->getHeight())) {
00254             getContent()->moveEnd(cursor);
00255             handled = true;
00256             return getContent();
00257         }
00258         return this;
00259     }
00260     return 0;
00261 }
00262 
00263 
00268 void BracketElement::calcSizes(const ContextStyle& style, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle)
00269 {
00270     SequenceElement* content = getContent();
00271     content->calcSizes(style, tstyle, istyle);
00272 
00273     //if ( left == 0 ) {
00274     delete left;
00275     delete right;
00276     left = style.fontStyle().createArtwork( leftType );
00277     right = style.fontStyle().createArtwork( rightType );
00278     //}
00279 
00280     if (content->isTextOnly()) {
00281         left->calcSizes(style, tstyle);
00282         right->calcSizes(style, tstyle);
00283 
00284         setBaseline(QMAX(content->getBaseline(),
00285                          QMAX(left->getBaseline(), right->getBaseline())));
00286 
00287         content->setY(getBaseline() - content->getBaseline());
00288         left   ->setY(getBaseline() - left   ->getBaseline());
00289         right  ->setY(getBaseline() - right  ->getBaseline());
00290 
00291         //setMidline(content->getY() + content->getMidline());
00292         setHeight(QMAX(content->getY() + content->getHeight(),
00293                        QMAX(left ->getY() + left ->getHeight(),
00294                             right->getY() + right->getHeight())));
00295     }
00296     else {
00297         //kdDebug( DEBUGID ) << "BracketElement::calcSizes " << content->axis( style, tstyle ) << " " << content->getHeight() << endl;
00298         luPixel contentHeight = 2 * QMAX( content->axis( style, tstyle ),
00299                                           content->getHeight() - content->axis( style, tstyle ) );
00300         left->calcSizes( style, tstyle, contentHeight );
00301         right->calcSizes( style, tstyle, contentHeight );
00302 
00303         // height
00304         setHeight(QMAX(contentHeight,
00305                        QMAX(left->getHeight(), right->getHeight())));
00306         //setMidline(getHeight() / 2);
00307 
00308         content->setY(getHeight() / 2 - content->axis( style, tstyle ));
00309         setBaseline(content->getBaseline() + content->getY());
00310 
00311         if ( left->isNormalChar() ) {
00312             left->setY(getBaseline() - left->getBaseline());
00313         }
00314         else {
00315             left->setY((getHeight() - left->getHeight())/2);
00316         }
00317         if ( right->isNormalChar() ) {
00318             right->setY(getBaseline() - right->getBaseline());
00319         }
00320         else {
00321             right->setY((getHeight() - right->getHeight())/2);
00322         }
00323 
00324 //         kdDebug() << "BracketElement::calcSizes" << endl
00325 //                   << "getHeight(): " << getHeight() << endl
00326 //                   << "left->getHeight():  " << left->getHeight() << endl
00327 //                   << "right->getHeight(): " << right->getHeight() << endl
00328 //                   << "left->getY():  " << left->getY() << endl
00329 //                   << "right->getY(): " << right->getY() << endl
00330 //                   << endl;
00331     }
00332 
00333     // width
00334     setWidth(left->getWidth() + content->getWidth() + right->getWidth());
00335     content->setX(left->getWidth());
00336     right  ->setX(left->getWidth()+content->getWidth());
00337 }
00338 
00339 
00345 void BracketElement::draw( QPainter& painter, const LuPixelRect& r,
00346                            const ContextStyle& style,
00347                            ContextStyle::TextStyle tstyle,
00348                            ContextStyle::IndexStyle istyle,
00349                            const LuPixelPoint& parentOrigin )
00350 {
00351     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00352     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00353     //    return;
00354 
00355     SequenceElement* content = getContent();
00356     content->draw(painter, r, style, tstyle, istyle, myPos);
00357 
00358     if (content->isTextOnly()) {
00359         left->draw(painter, r, style, tstyle, myPos);
00360         right->draw(painter, r, style, tstyle, myPos);
00361     }
00362     else {
00363         luPixel contentHeight = 2 * QMAX(content->axis( style, tstyle ),
00364                                          content->getHeight() - content->axis( style, tstyle ));
00365         left->draw(painter, r, style, tstyle, contentHeight, myPos);
00366         right->draw(painter, r, style, tstyle, contentHeight, myPos);
00367     }
00368 
00369     // Debug
00370 #if 0
00371     painter.setBrush( Qt::NoBrush );
00372     painter.setPen( Qt::red );
00373     painter.drawRect( style.layoutUnitToPixelX( myPos.x()+left->getX() ),
00374                       style.layoutUnitToPixelY( myPos.y()+left->getY() ),
00375                       style.layoutUnitToPixelX( left->getWidth() ),
00376                       style.layoutUnitToPixelY( left->getHeight() ) );
00377     painter.drawRect( style.layoutUnitToPixelX( myPos.x()+right->getX() ),
00378                       style.layoutUnitToPixelY( myPos.y()+right->getY() ),
00379                       style.layoutUnitToPixelX( right->getWidth() ),
00380                       style.layoutUnitToPixelY( right->getHeight() ) );
00381 #endif
00382 }
00383 
00384 
00388 void BracketElement::writeDom(QDomElement element)
00389 {
00390     SingleContentElement::writeDom(element);
00391     element.setAttribute("LEFT", leftType);
00392     element.setAttribute("RIGHT", rightType);
00393 }
00394 
00399 bool BracketElement::readAttributesFromDom(QDomElement element)
00400 {
00401     if (!BasicElement::readAttributesFromDom(element)) {
00402         return false;
00403     }
00404     QString leftStr = element.attribute("LEFT");
00405     if(!leftStr.isNull()) {
00406         leftType = static_cast<SymbolType>(leftStr.toInt());
00407     }
00408     QString rightStr = element.attribute("RIGHT");
00409     if(!rightStr.isNull()) {
00410         rightType = static_cast<SymbolType>(rightStr.toInt());
00411     }
00412     return true;
00413 }
00414 
00415 QString BracketElement::toLatex()
00416 {
00417     QString ls,rs,cs;
00418     cs=getContent()->toLatex();
00419     ls="\\left"+latexString(leftType);
00420     rs="\\right"+latexString(rightType);
00421 
00422     return ls+cs+rs;
00423 }
00424 
00425 QString BracketElement::latexString(char type)
00426 {
00427     switch (type) {
00428     case ']':
00429         return "]";
00430     case '[':
00431         return "[";
00432     case '{':
00433         return "\\{";
00434     case '}':
00435         return "\\}";
00436     case '(':
00437         return "(";
00438     case ')':
00439         return ")";
00440     case '|':
00441         return "|";
00442         case '<':
00443             return "\\langle";
00444         case '>':
00445             return "\\rangle";
00446         case '/':
00447             return "/";
00448         case '\\':
00449             return "\\backslash";
00450     }
00451     return ".";
00452 }
00453 
00454 QString BracketElement::formulaString()
00455 {
00456     return "(" + getContent()->formulaString() + ")";
00457 }
00458 
00459 void BracketElement::writeMathML( QDomDocument doc, QDomNode parent )
00460 {
00461     QDomElement de = doc.createElement( "mfenced" );
00462     if ( left->getType() != LeftRoundBracket ||
00463          right->getType() != RightRoundBracket )
00464     {
00465         de.setAttribute( "open",  QString( QChar( leftType ) ) );
00466         de.setAttribute( "close", QString( QChar( rightType ) ) );
00467     }
00468     SingleContentElement::writeMathML( doc, de );
00469     parent.appendChild( de );
00470 }
00471 
00472 
00473 OverlineElement::OverlineElement( BasicElement* parent )
00474     : SingleContentElement( parent )
00475 {
00476 }
00477 
00478 OverlineElement::~OverlineElement()
00479 {
00480 }
00481 
00482 OverlineElement::OverlineElement( const OverlineElement& other )
00483     : SingleContentElement( other )
00484 {
00485 }
00486 
00487 
00488 bool OverlineElement::accept( ElementVisitor* visitor )
00489 {
00490     return visitor->visit( this );
00491 }
00492 
00493 
00494 void OverlineElement::entered( SequenceElement* /*child*/ )
00495 {
00496     formula()->tell( i18n( "Overline" ) );
00497 }
00498 
00499 
00500 void OverlineElement::calcSizes(const ContextStyle& style, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle)
00501 {
00502     SequenceElement* content = getContent();
00503     content->calcSizes(style, tstyle,
00504                style.convertIndexStyleLower(istyle));
00505 
00506     //luPixel distX = style.ptToPixelX( style.getThinSpace( tstyle ) );
00507     luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00508     //luPixel unit = (content->getHeight() + distY)/ 3;
00509 
00510     setWidth( content->getWidth() );
00511     setHeight( content->getHeight() + distY );
00512 
00513     content->setX( 0 );
00514     content->setY( distY );
00515     setBaseline(content->getBaseline() + content->getY());
00516 }
00517 
00518 void OverlineElement::draw( QPainter& painter, const LuPixelRect& r,
00519                             const ContextStyle& style,
00520                             ContextStyle::TextStyle tstyle,
00521                             ContextStyle::IndexStyle istyle,
00522                             const LuPixelPoint& parentOrigin )
00523 {
00524     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00525     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00526     //    return;
00527 
00528     SequenceElement* content = getContent();
00529     content->draw( painter, r, style, tstyle,
00530                    style.convertIndexStyleLower( istyle ), myPos );
00531 
00532     luPixel x = myPos.x();
00533     luPixel y = myPos.y();
00534     //int distX = style.getDistanceX(tstyle);
00535     luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00536     //luPixel unit = (content->getHeight() + distY)/ 3;
00537 
00538     painter.setPen( QPen( style.getDefaultColor(),
00539                           style.layoutUnitToPixelY( style.getLineWidth() ) ) );
00540 
00541     painter.drawLine( style.layoutUnitToPixelX( x ),
00542                       style.layoutUnitToPixelY( y+distY/3 ),
00543                       style.layoutUnitToPixelX( x+content->getWidth() ),
00544                       style.layoutUnitToPixelY( y+distY/3 ) );
00545 }
00546 
00547 
00548 QString OverlineElement::toLatex()
00549 {
00550     return "\\overline{" + getContent()->toLatex() + "}";
00551 }
00552 
00553 QString OverlineElement::formulaString()
00554 {
00555     return getContent()->formulaString();
00556 }
00557 
00558 void OverlineElement::writeMathML( QDomDocument doc, QDomNode parent )
00559 {
00560     QDomElement de = doc.createElement( "mover" );
00561     SingleContentElement::writeMathML( doc, de );
00562     QDomElement op = doc.createElement( "mo" );
00563     // is this the right entity? Mozilla renders it correctly.
00564     op.appendChild( doc.createEntityReference( "OverBar" ) );
00565     de.appendChild( op );
00566     parent.appendChild( de );
00567 }
00568 
00569 
00570 UnderlineElement::UnderlineElement( BasicElement* parent )
00571     : SingleContentElement( parent )
00572 {
00573 }
00574 
00575 UnderlineElement::~UnderlineElement()
00576 {
00577 }
00578 
00579 
00580 UnderlineElement::UnderlineElement( const UnderlineElement& other )
00581     : SingleContentElement( other )
00582 {
00583 }
00584 
00585 
00586 bool UnderlineElement::accept( ElementVisitor* visitor )
00587 {
00588     return visitor->visit( this );
00589 }
00590 
00591 
00592 void UnderlineElement::entered( SequenceElement* /*child*/ )
00593 {
00594     formula()->tell( i18n( "Underline" ) );
00595 }
00596 
00597 
00598 void UnderlineElement::calcSizes(const ContextStyle& style,
00599                                  ContextStyle::TextStyle tstyle,
00600                                  ContextStyle::IndexStyle istyle)
00601 {
00602     SequenceElement* content = getContent();
00603     content->calcSizes(style, tstyle,
00604                style.convertIndexStyleLower(istyle));
00605 
00606     //luPixel distX = style.ptToPixelX( style.getThinSpace( tstyle ) );
00607     luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00608     //luPixel unit = (content->getHeight() + distY)/ 3;
00609 
00610     setWidth( content->getWidth() );
00611     setHeight( content->getHeight() + distY );
00612 
00613     content->setX( 0 );
00614     content->setY( 0 );
00615     setBaseline(content->getBaseline() + content->getY());
00616 }
00617 
00618 void UnderlineElement::draw( QPainter& painter, const LuPixelRect& r,
00619                              const ContextStyle& style,
00620                              ContextStyle::TextStyle tstyle,
00621                              ContextStyle::IndexStyle istyle,
00622                              const LuPixelPoint& parentOrigin )
00623 {
00624     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00625     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00626     //    return;
00627 
00628     SequenceElement* content = getContent();
00629     content->draw( painter, r, style, tstyle,
00630                    style.convertIndexStyleLower( istyle ), myPos );
00631 
00632     luPixel x = myPos.x();
00633     luPixel y = myPos.y();
00634     //int distX = style.getDistanceX(tstyle);
00635     //luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00636     //luPixel unit = (content->getHeight() + distY)/ 3;
00637 
00638     painter.setPen( QPen( style.getDefaultColor(),
00639                           style.layoutUnitToPixelY( style.getLineWidth() ) ) );
00640 
00641     painter.drawLine( style.layoutUnitToPixelX( x ),
00642                       style.layoutUnitToPixelY( y+getHeight()-style.getLineWidth() ),
00643                       style.layoutUnitToPixelX( x+content->getWidth() ),
00644                       style.layoutUnitToPixelY( y+getHeight()-style.getLineWidth() ) );
00645 }
00646 
00647 
00648 QString UnderlineElement::toLatex()
00649 {
00650     return "\\underline{" + getContent()->toLatex() + "}";
00651 }
00652 
00653 QString UnderlineElement::formulaString()
00654 {
00655     return getContent()->formulaString();
00656 }
00657 
00658 void UnderlineElement::writeMathML( QDomDocument doc, QDomNode parent )
00659 {
00660     QDomElement de = doc.createElement( "munder" );
00661     SingleContentElement::writeMathML( doc, de );
00662     QDomElement op = doc.createElement( "mo" );
00663     // is this the right entity? Mozilla renders it correctly.
00664     op.appendChild( doc.createEntityReference( "UnderBar" ) );
00665     de.appendChild( op );
00666     parent.appendChild( de );
00667 }
00668 
00669 KFORMULA_NAMESPACE_END
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Mar 20 14:25:23 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003