lib

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., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, 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 int SingleContentElement::readContentFromMathMLDom( QDomNode& node )
00195 {
00196     if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
00197         return -1;
00198     }
00199 
00200     if ( content->buildMathMLChild( node ) == -1 ) {
00201         kdWarning( DEBUGID) << "Empty content in SingleContentElement\n";
00202         return -1;
00203     }
00204 
00205     return 1;
00206 }
00207 
00208 void SingleContentElement::writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const
00209 {
00210     content->writeMathML( doc, element, oasisFormat );
00211 }
00212 
00213 
00214 
00215 BracketElement::BracketElement(SymbolType l, SymbolType r, BasicElement* parent)
00216     : SingleContentElement(parent),
00217       left( 0 ), right( 0 ),
00218       leftType( l ), rightType( r ),
00219       m_operator( false ), m_customLeft( false ), m_customRight( false )
00220 {
00221 }
00222 
00223 
00224 BracketElement::~BracketElement()
00225 {
00226     delete left;
00227     delete right;
00228 }
00229 
00230 
00231 BracketElement::BracketElement( const BracketElement& other )
00232     : SingleContentElement( other ),
00233       left( 0 ), right( 0 ),
00234       leftType( other.leftType ), rightType( other.rightType ),
00235       m_operator( other.m_operator ),
00236       m_customLeft( other.m_customLeft ), m_customRight( other.m_customRight )
00237 {
00238 }
00239 
00240 
00241 bool BracketElement::accept( ElementVisitor* visitor )
00242 {
00243     return visitor->visit( this );
00244 }
00245 
00246 
00247 void BracketElement::entered( SequenceElement* /*child*/ )
00248 {
00249     formula()->tell( i18n( "Delimited list" ) );
00250 }
00251 
00252 
00253 BasicElement* BracketElement::goToPos( FormulaCursor* cursor, bool& handled,
00254                                        const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00255 {
00256     BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00257     if (e != 0) {
00258         LuPixelPoint myPos(parentOrigin.x() + getX(),
00259                            parentOrigin.y() + getY());
00260         e = getContent()->goToPos(cursor, handled, point, myPos);
00261         if (e != 0) {
00262             return e;
00263         }
00264 
00265         // We are in one of those gaps.
00266         luPixel dx = point.x() - myPos.x();
00267         luPixel dy = point.y() - myPos.y();
00268 
00269         if ((dx > getContent()->getX()+getContent()->getWidth()) ||
00270             (dy > getContent()->getY()+getContent()->getHeight())) {
00271             getContent()->moveEnd(cursor);
00272             handled = true;
00273             return getContent();
00274         }
00275         return this;
00276     }
00277     return 0;
00278 }
00279 
00280 
00285 void BracketElement::calcSizes( const ContextStyle& context,
00286                                 ContextStyle::TextStyle tstyle,
00287                                 ContextStyle::IndexStyle istyle,
00288                                 StyleAttributes& style )
00289 {
00290     SequenceElement* content = getContent();
00291     content->calcSizes( context, tstyle, istyle, style );
00292 
00293     //if ( left == 0 ) {
00294     delete left;
00295     delete right;
00296     left = context.fontStyle().createArtwork( leftType );
00297     right = context.fontStyle().createArtwork( rightType );
00298     //}
00299 
00300     double factor = style.sizeFactor();
00301     if (content->isTextOnly()) {
00302         left->calcSizes(context, tstyle, factor);
00303         right->calcSizes(context, tstyle, factor);
00304 
00305         setBaseline(QMAX(content->getBaseline(),
00306                          QMAX(left->getBaseline(), right->getBaseline())));
00307 
00308         content->setY(getBaseline() - content->getBaseline());
00309         left   ->setY(getBaseline() - left   ->getBaseline());
00310         right  ->setY(getBaseline() - right  ->getBaseline());
00311 
00312         //setMidline(content->getY() + content->getMidline());
00313         setHeight(QMAX(content->getY() + content->getHeight(),
00314                        QMAX(left ->getY() + left ->getHeight(),
00315                             right->getY() + right->getHeight())));
00316     }
00317     else {
00318         //kdDebug( DEBUGID ) << "BracketElement::calcSizes " << content->axis( context, tstyle ) << " " << content->getHeight() << endl;
00319         luPixel contentHeight = 2 * QMAX( content->axis( context, tstyle, factor ),
00320                                           content->getHeight() - content->axis( context, tstyle, factor ) );
00321         left->calcSizes( context, tstyle, factor, contentHeight );
00322         right->calcSizes( context, tstyle, factor, contentHeight );
00323 
00324         // height
00325         setHeight(QMAX(contentHeight,
00326                        QMAX(left->getHeight(), right->getHeight())));
00327         //setMidline(getHeight() / 2);
00328 
00329         content->setY(getHeight() / 2 - content->axis( context, tstyle, factor ));
00330         setBaseline(content->getBaseline() + content->getY());
00331 
00332         if ( left->isNormalChar() ) {
00333             left->setY(getBaseline() - left->getBaseline());
00334         }
00335         else {
00336             left->setY((getHeight() - left->getHeight())/2);
00337         }
00338         if ( right->isNormalChar() ) {
00339             right->setY(getBaseline() - right->getBaseline());
00340         }
00341         else {
00342             right->setY((getHeight() - right->getHeight())/2);
00343         }
00344 
00345 //         kdDebug() << "BracketElement::calcSizes" << endl
00346 //                   << "getHeight(): " << getHeight() << endl
00347 //                   << "left->getHeight():  " << left->getHeight() << endl
00348 //                   << "right->getHeight(): " << right->getHeight() << endl
00349 //                   << "left->getY():  " << left->getY() << endl
00350 //                   << "right->getY(): " << right->getY() << endl
00351 //                   << endl;
00352     }
00353 
00354     // width
00355     setWidth(left->getWidth() + content->getWidth() + right->getWidth());
00356     content->setX(left->getWidth());
00357     right  ->setX(left->getWidth()+content->getWidth());
00358 }
00359 
00360 
00366 void BracketElement::draw( QPainter& painter, const LuPixelRect& r,
00367                            const ContextStyle& context,
00368                            ContextStyle::TextStyle tstyle,
00369                            ContextStyle::IndexStyle istyle,
00370                            StyleAttributes& style,
00371                            const LuPixelPoint& parentOrigin )
00372 {
00373     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00374     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00375     //    return;
00376 
00377     SequenceElement* content = getContent();
00378     content->draw(painter, r, context, tstyle, istyle, style, myPos);
00379 
00380     if (content->isTextOnly()) {
00381         left->draw(painter, r, context, tstyle, style, myPos);
00382         right->draw(painter, r, context, tstyle, style, myPos);
00383     }
00384     else {
00385         double factor = style.sizeFactor();
00386         luPixel contentHeight = 2 * QMAX(content->axis( context, tstyle, factor ),
00387                                          content->getHeight() - content->axis( context, tstyle, factor ));
00388         left->draw(painter, r, context, tstyle, style, contentHeight, myPos);
00389         right->draw(painter, r, context, tstyle, style, contentHeight, myPos);
00390     }
00391 
00392     // Debug
00393 #if 0
00394     painter.setBrush( Qt::NoBrush );
00395     painter.setPen( Qt::red );
00396     painter.drawRect( context.layoutUnitToPixelX( myPos.x()+left->getX() ),
00397                       context.layoutUnitToPixelY( myPos.y()+left->getY() ),
00398                       context.layoutUnitToPixelX( left->getWidth() ),
00399                       context.layoutUnitToPixelY( left->getHeight() ) );
00400     painter.drawRect( context.layoutUnitToPixelX( myPos.x()+right->getX() ),
00401                       context.layoutUnitToPixelY( myPos.y()+right->getY() ),
00402                       context.layoutUnitToPixelX( right->getWidth() ),
00403                       context.layoutUnitToPixelY( right->getHeight() ) );
00404 #endif
00405 }
00406 
00407 
00411 void BracketElement::writeDom(QDomElement element)
00412 {
00413     SingleContentElement::writeDom(element);
00414     element.setAttribute("LEFT", leftType);
00415     element.setAttribute("RIGHT", rightType);
00416 }
00417 
00422 bool BracketElement::readAttributesFromDom(QDomElement element)
00423 {
00424     if (!BasicElement::readAttributesFromDom(element)) {
00425         return false;
00426     }
00427     QString leftStr = element.attribute("LEFT");
00428     if(!leftStr.isNull()) {
00429         leftType = static_cast<SymbolType>(leftStr.toInt());
00430     }
00431     QString rightStr = element.attribute("RIGHT");
00432     if(!rightStr.isNull()) {
00433         rightType = static_cast<SymbolType>(rightStr.toInt());
00434     }
00435     return true;
00436 }
00437 
00442 bool BracketElement::readAttributesFromMathMLDom(const QDomElement& element)
00443 {
00444     if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
00445         return false;
00446     }
00447 
00448     if ( element.tagName().lower() == "mo" ) {
00449         m_operator = true;
00450         // TODO: parse attributes in section 3.2.5.2
00451     }
00452     else { // mfenced, see attributes in section 3.3.8.2
00453         leftType = LeftRoundBracket;
00454         rightType = RightRoundBracket;
00455         QString openStr = element.attribute( "open" ).stripWhiteSpace();
00456         if ( !openStr.isNull() ) {
00457             m_customLeft = true;
00458             if ( openStr == "[" )
00459                 leftType = LeftSquareBracket;
00460             else if ( openStr == "]" )
00461                 leftType = RightSquareBracket;
00462             else if ( openStr == "{" )
00463                 leftType = LeftCurlyBracket;
00464             else if ( openStr == "}" )
00465                 leftType = RightCurlyBracket;
00466             else if ( openStr == "<" )
00467                 leftType = LeftCornerBracket;
00468             else if ( openStr == ">" )
00469                 leftType = RightCornerBracket;
00470             else if ( openStr == "(" )
00471                 leftType = LeftRoundBracket;
00472             else if ( openStr == ")" )
00473                 leftType = RightRoundBracket;
00474             else if ( openStr == "/" )
00475                 leftType = SlashBracket;
00476             else if ( openStr == "\\" )
00477                 leftType = BackSlashBracket;
00478             else // TODO: Check for entity references
00479                 leftType = LeftRoundBracket;
00480         }
00481         QString closeStr = element.attribute( "close" ).stripWhiteSpace();
00482         if ( !closeStr.isNull() ) {
00483             m_customRight = true;
00484             if ( closeStr == "[" )
00485                 rightType = LeftSquareBracket;
00486             else if ( closeStr == "]" )
00487                 rightType = RightSquareBracket;
00488             else if ( closeStr == "{" )
00489                 rightType = LeftCurlyBracket;
00490             else if ( closeStr == "}" )
00491                 rightType = RightCurlyBracket;
00492             else if ( closeStr == "<" )
00493                 rightType = LeftCornerBracket;
00494             else if ( closeStr == ">" )
00495                 rightType = RightCornerBracket;
00496             else if ( closeStr == "(" )
00497                 rightType = LeftRoundBracket;
00498             else if ( closeStr == ")" )
00499                 rightType = RightRoundBracket;
00500             else if ( closeStr == "/" )
00501                 rightType = SlashBracket;
00502             else if ( closeStr == "\\" )
00503                 rightType = BackSlashBracket;
00504             else // TODO: Check for entity references
00505                 rightType = LeftRoundBracket;
00506         }
00507         m_separators = element.attribute( "separators" ).simplifyWhiteSpace();
00508     }
00509     return true;
00510 }
00511 
00517 int BracketElement::readContentFromMathMLDom(QDomNode& node)
00518 {
00519     bool empty = false;
00520     if ( m_operator ) {
00521         node = node.parentNode();
00522         QDomNode open = node;
00523         QDomNode parent = node.parentNode();
00524         if ( ! operatorType( node, true ) )
00525             return -1;
00526         int nodeNum = searchOperator( node );
00527         if ( nodeNum == -1 ) // Closing bracket not found
00528             return -1;
00529         if ( nodeNum == 0 ) { // Empty content
00530             empty = true;
00531         }
00532         if ( nodeNum > 1 ) { // More than two elements inside, infer a mrow
00533             kdWarning() << "NodeNum: " << nodeNum << endl;
00534             QDomDocument doc = node.ownerDocument();
00535             QDomElement de = doc.createElement( "mrow" );
00536             int i = 0;
00537             do {
00538                 QDomNode n = node.nextSibling();
00539                 de.appendChild( node.toElement() );
00540                 node = n;
00541             } while ( ++i < nodeNum );
00542             parent.insertAfter( de, open );
00543             node = de;
00544             kdWarning() << doc.toString() << endl;
00545         }
00546     }
00547     else {
00548         // if it's a mfence tag, we need to convert to equivalent expanded form.
00549         // See section 3.3.8
00550         while ( ! node.isNull() && ! node.isElement() )
00551             node = node.nextSibling();
00552         QDomNode next = node.nextSibling();
00553         while ( ! next.isNull() && ! next.isElement() )
00554             next = next.nextSibling();
00555         if ( ! next.isNull()) {
00556             QDomDocument doc = node.ownerDocument();
00557             QDomNode parent = node.parentNode();
00558             QString ns = parent.prefix();
00559             QDomElement de = doc.createElementNS( ns, "mrow" );
00560             uint pos = 0;
00561             while ( ! node.isNull() ) {
00562                 QDomNode no = node.nextSibling();
00563                 while ( ! no.isNull() && ! no.isElement() )
00564                     no = no.nextSibling();
00565                 de.appendChild( node.toElement() );
00566                 if ( ! no.isNull() && ( m_separators.isNull() || ! m_separators.isEmpty() ) ) {
00567                     QDomElement sep = doc.createElementNS( ns, "mo" );
00568                     de.appendChild( sep );
00569                     if ( m_separators.isNull() ) {
00570                         sep.appendChild( doc.createTextNode( "," ) );
00571                     }
00572                     else {
00573                         if ( m_separators.at( pos ).isSpace() ) {
00574                             pos++;
00575                         }
00576                         sep.appendChild( doc.createTextNode( QString ( m_separators.at( pos ) ) ) );
00577                     }
00578                     if ( pos < m_separators.length() - 1 ) {
00579                         pos++;
00580                     }
00581                 }
00582                 node = no;
00583             }
00584             parent.appendChild( de );
00585             node = parent.firstChild();
00586             while ( ! node.isElement() )
00587                 node = node.nextSibling();
00588         }
00589     }
00590     if ( ! empty ) {
00591         inherited::readContentFromMathMLDom( node );
00592     }
00593     if ( m_operator ) {
00594         if ( ! operatorType( node, false ) ) {
00595             return -1;
00596         }
00597         if ( empty )
00598             return 2;
00599         return 3;
00600     }
00601     return 1;
00602 }
00603 
00604 QString BracketElement::toLatex()
00605 {
00606     QString ls,rs,cs;
00607     cs=getContent()->toLatex();
00608     ls="\\left"+latexString(leftType) + " ";
00609     rs=" \\right"+latexString(rightType);
00610 
00611     return ls+cs+rs;
00612 }
00613 
00614 QString BracketElement::latexString(char type)
00615 {
00616     switch (type) {
00617     case ']':
00618         return "]";
00619     case '[':
00620         return "[";
00621     case '{':
00622         return "\\{";
00623     case '}':
00624         return "\\}";
00625     case '(':
00626         return "(";
00627     case ')':
00628         return ")";
00629     case '|':
00630         return "|";
00631         case '<':
00632             return "\\langle";
00633         case '>':
00634             return "\\rangle";
00635         case '/':
00636             return "/";
00637         case '\\':
00638             return "\\backslash";
00639     }
00640     return ".";
00641 }
00642 
00643 QString BracketElement::formulaString()
00644 {
00645     return "(" + getContent()->formulaString() + ")";
00646 }
00647 
00648 bool BracketElement::operatorType( QDomNode& node, bool open )
00649 {
00650     SymbolType* type = open ? &leftType : &rightType;
00651     if ( node.isElement() ) {
00652         QDomElement e = node.toElement();
00653         QString s =  e.text();
00654         if ( s.isNull() )
00655             return false;
00656         *type = static_cast<SymbolType>( QString::number( s.at( 0 ).latin1() ).toInt() );
00657         node = node.nextSibling();
00658     }
00659     else if ( node.isEntityReference() ) {
00660         QString name = node.nodeName();
00661         // TODO: To fully support these, SymbolType has to be extended,
00662         //       and better Unicode support is a must
00663         // CloseCurlyDoubleQuote 0x201D
00664         // CloseCurlyQoute       0x2019
00665         // LeftCeiling           0x2308
00666         // LeftDoubleBracket     0x301A
00667         // LeftFloor             0x230A
00668         // OpenCurlyDoubleQuote  0x201C
00669         // OpenCurlyQuote        0x2018
00670         // RightCeiling          0x2309
00671         // RightDoubleBracket    0x301B
00672         // RightFloor            0x230B
00673         if ( name == "LeftAngleBracket" ) {
00674             *type = LeftCornerBracket;
00675         }
00676         else if ( name == "RightAngleBracket" ) {
00677             *type = RightCornerBracket; 
00678         }
00679         else {
00680             if ( open ) {
00681                 *type = LeftRoundBracket;
00682             }
00683             else
00684                 *type = RightRoundBracket;
00685         }
00686         node = node.nextSibling();
00687     }
00688     else {
00689         return false;
00690     }
00691     return true;
00692 }
00693 
00694 int BracketElement::searchOperator( const QDomNode& node )
00695 {
00696     QDomNode n = node;
00697     for ( int i = 0; ! n.isNull(); n = n.nextSibling(), i++ ) {
00698         if ( n.isElement() ) {
00699             QDomElement e = n.toElement();
00700             if ( e.tagName().lower() == "mo" ) {
00701                 // Try to guess looking at attributes
00702                 QString form = e.attribute( "form" );
00703                 QString f;
00704                 if ( ! form.isNull() ) {
00705                     f = form.stripWhiteSpace().lower();
00706                 }
00707                 QString fence = e.attribute( "fence" );
00708                 if ( ! fence.isNull() ) {
00709                     if ( fence.stripWhiteSpace().lower() == "false" ) {
00710                         continue;
00711                     }
00712                     if ( ! f.isNull() ) {
00713                         if ( f == "postfix" ) {
00714                             return i;
00715                         }
00716                         else {
00717                             continue;
00718                         }
00719                     }
00720                 }
00721                 
00722                 // Guess looking at contents
00723                 QDomNode child = e.firstChild();
00724                 QString name;
00725                 if ( child.isText() )
00726                     name = child.toText().data().stripWhiteSpace();
00727                 else if ( child.isEntityReference() )
00728                     name = child.nodeName();
00729                 else 
00730                     continue;
00731                 if ( name == ")"
00732                      || name == "]"
00733                      || name == "}"
00734                      || name == "CloseCurlyDoubleQuote"
00735                      || name == "CloseCurlyQuote"
00736                      || name == "RightAngleBracket"
00737                      || name == "RightCeiling"
00738                      || name == "RightDoubleBracket"
00739                      || name == "RightFloor" ) {
00740                     if ( f.isNull() || f == "postfix" )
00741                         return i;
00742                 }
00743                 if ( name == "("
00744                      || name == "["
00745                      || name == "{"
00746                      || name == "LeftAngleBracket"
00747                      || name == "LeftCeiling"
00748                      || name == "LeftDoubleBracket"
00749                      || name == "LeftFloor"
00750                      || name == "OpenCurlyQuote" ) {
00751                     if ( ! f.isNull() && f == "postfix" )
00752                         return i;
00753                 }
00754             }
00755         }
00756     }
00757     return -1;
00758 }
00759 
00760 
00761 void BracketElement::writeMathMLAttributes( QDomElement& element ) const
00762 {
00763     if ( left->getType() != LeftRoundBracket ||
00764          right->getType() != RightRoundBracket )
00765     {
00766         element.setAttribute( "open",  QString( QChar( leftType ) ) );
00767         element.setAttribute( "close", QString( QChar( rightType ) ) );
00768     }
00769     if ( ! m_separators.isNull() ) {
00770         element.setAttribute( "separators", m_separators );
00771     }
00772 }
00773 
00774 OverlineElement::OverlineElement( BasicElement* parent )
00775     : SingleContentElement( parent )
00776 {
00777 }
00778 
00779 OverlineElement::~OverlineElement()
00780 {
00781 }
00782 
00783 OverlineElement::OverlineElement( const OverlineElement& other )
00784     : SingleContentElement( other )
00785 {
00786 }
00787 
00788 
00789 bool OverlineElement::accept( ElementVisitor* visitor )
00790 {
00791     return visitor->visit( this );
00792 }
00793 
00794 
00795 void OverlineElement::entered( SequenceElement* /*child*/ )
00796 {
00797     formula()->tell( i18n( "Overline" ) );
00798 }
00799 
00800 
00801 void OverlineElement::calcSizes( const ContextStyle& context,
00802                                  ContextStyle::TextStyle tstyle,
00803                                  ContextStyle::IndexStyle istyle,
00804                                  StyleAttributes& style )
00805 {
00806     SequenceElement* content = getContent();
00807     content->calcSizes(context, tstyle,
00808                        context.convertIndexStyleLower(istyle), style );
00809 
00810     //luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, style.sizeFactor() ) );
00811     luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, style.sizeFactor() ) );
00812     //luPixel unit = (content->getHeight() + distY)/ 3;
00813 
00814     setWidth( content->getWidth() );
00815     setHeight( content->getHeight() + distY );
00816 
00817     content->setX( 0 );
00818     content->setY( distY );
00819     setBaseline(content->getBaseline() + content->getY());
00820 }
00821 
00822 void OverlineElement::draw( QPainter& painter, const LuPixelRect& r,
00823                             const ContextStyle& context,
00824                             ContextStyle::TextStyle tstyle,
00825                             ContextStyle::IndexStyle istyle,
00826                             StyleAttributes& style,
00827                             const LuPixelPoint& parentOrigin )
00828 {
00829     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00830     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00831     //    return;
00832 
00833     SequenceElement* content = getContent();
00834     content->draw( painter, r, context, tstyle,
00835                    context.convertIndexStyleLower( istyle ), style, myPos );
00836 
00837     luPixel x = myPos.x();
00838     luPixel y = myPos.y();
00839     //int distX = context.getDistanceX(tstyle);
00840     double factor = style.sizeFactor();
00841     luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
00842     //luPixel unit = (content->getHeight() + distY)/ 3;
00843 
00844     painter.setPen( QPen( context.getDefaultColor(),
00845                           context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
00846 
00847     painter.drawLine( context.layoutUnitToPixelX( x ),
00848                       context.layoutUnitToPixelY( y+distY/3 ),
00849                       context.layoutUnitToPixelX( x+content->getWidth() ),
00850                       context.layoutUnitToPixelY( y+distY/3 ) );
00851 }
00852 
00853 
00854 QString OverlineElement::toLatex()
00855 {
00856     return "\\overline{" + getContent()->toLatex() + "}";
00857 }
00858 
00859 QString OverlineElement::formulaString()
00860 {
00861     return getContent()->formulaString();
00862 }
00863 
00864 void OverlineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
00865 {
00866     QDomElement de = doc.createElement( oasisFormat ? "math:mover" : "mover" );
00867     SingleContentElement::writeMathML( doc, de, oasisFormat );
00868     QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
00869     // is this the right entity? Mozilla renders it correctly.
00870     op.appendChild( doc.createEntityReference( "OverBar" ) );
00871     de.appendChild( op );
00872     parent.appendChild( de );
00873 }
00874 
00875 
00876 UnderlineElement::UnderlineElement( BasicElement* parent )
00877     : SingleContentElement( parent )
00878 {
00879 }
00880 
00881 UnderlineElement::~UnderlineElement()
00882 {
00883 }
00884 
00885 
00886 UnderlineElement::UnderlineElement( const UnderlineElement& other )
00887     : SingleContentElement( other )
00888 {
00889 }
00890 
00891 
00892 bool UnderlineElement::accept( ElementVisitor* visitor )
00893 {
00894     return visitor->visit( this );
00895 }
00896 
00897 
00898 void UnderlineElement::entered( SequenceElement* /*child*/ )
00899 {
00900     formula()->tell( i18n( "Underline" ) );
00901 }
00902 
00903 
00904 void UnderlineElement::calcSizes( const ContextStyle& context,
00905                                   ContextStyle::TextStyle tstyle,
00906                                   ContextStyle::IndexStyle istyle,
00907                                   StyleAttributes& style )
00908 {
00909     SequenceElement* content = getContent();
00910     double factor = style.sizeFactor();
00911     content->calcSizes(context, tstyle,
00912                        context.convertIndexStyleLower(istyle), style );
00913 
00914     //luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle ) );
00915     luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
00916     //luPixel unit = (content->getHeight() + distY)/ 3;
00917 
00918     setWidth( content->getWidth() );
00919     setHeight( content->getHeight() + distY );
00920 
00921     content->setX( 0 );
00922     content->setY( 0 );
00923     setBaseline(content->getBaseline() + content->getY());
00924 }
00925 
00926 void UnderlineElement::draw( QPainter& painter, const LuPixelRect& r,
00927                              const ContextStyle& context,
00928                              ContextStyle::TextStyle tstyle,
00929                              ContextStyle::IndexStyle istyle,
00930                              StyleAttributes& style,
00931                              const LuPixelPoint& parentOrigin )
00932 {
00933     LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00934     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00935     //    return;
00936 
00937     SequenceElement* content = getContent();
00938     content->draw( painter, r, context, tstyle,
00939                    context.convertIndexStyleLower( istyle ), style, myPos );
00940 
00941     luPixel x = myPos.x();
00942     luPixel y = myPos.y();
00943     //int distX = context.getDistanceX(tstyle);
00944     //luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle ) );
00945     //luPixel unit = (content->getHeight() + distY)/ 3;
00946 
00947     double factor = style.sizeFactor();
00948     painter.setPen( QPen( context.getDefaultColor(),
00949                           context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
00950 
00951     painter.drawLine( context.layoutUnitToPixelX( x ),
00952                       context.layoutUnitToPixelY( y+getHeight()-context.getLineWidth( factor ) ),
00953                       context.layoutUnitToPixelX( x+content->getWidth() ),
00954                       context.layoutUnitToPixelY( y+getHeight()-context.getLineWidth( factor ) ) );
00955 }
00956 
00957 
00958 QString UnderlineElement::toLatex()
00959 {
00960     return "\\underline{" + getContent()->toLatex() + "}";
00961 }
00962 
00963 QString UnderlineElement::formulaString()
00964 {
00965     return getContent()->formulaString();
00966 }
00967 
00968 void UnderlineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
00969 {
00970     QDomElement de = doc.createElement( oasisFormat ? "math:munder" : "munder" );
00971     SingleContentElement::writeMathML( doc, de, oasisFormat );
00972     QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
00973     // is this the right entity? Mozilla renders it correctly.
00974     op.appendChild( doc.createEntityReference( "UnderBar" ) );
00975     de.appendChild( op );
00976     parent.appendChild( de );
00977 }
00978 
00979 KFORMULA_NAMESPACE_END
KDE Home | KDE Accessibility Home | Description of Access Keys