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