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.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 24 18:22:21 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003