00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00062
00063
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
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
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* )
00125 {
00126 getParent()->moveUp(cursor, this);
00127 }
00128
00129 void SingleContentElement::moveDown(FormulaCursor* cursor, BasicElement* )
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, bool oasisFormat )
00195 {
00196 content->writeMathML( doc, parent, oasisFormat );
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* )
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
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
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
00292 setHeight(QMAX(content->getY() + content->getHeight(),
00293 QMAX(left ->getY() + left ->getHeight(),
00294 right->getY() + right->getHeight())));
00295 }
00296 else {
00297
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
00304 setHeight(QMAX(contentHeight,
00305 QMAX(left->getHeight(), right->getHeight())));
00306
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
00325
00326
00327
00328
00329
00330
00331 }
00332
00333
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
00353
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
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, bool oasisFormat )
00460 {
00461 QDomElement de = doc.createElement( oasisFormat ? "math:mfenced" : "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, oasisFormat );
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* )
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
00507 luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00508
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
00526
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
00535 luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00536
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, bool oasisFormat )
00559 {
00560 QDomElement de = doc.createElement( oasisFormat ? "math:mover" : "mover" );
00561 SingleContentElement::writeMathML( doc, de, oasisFormat );
00562 QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
00563
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* )
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
00607 luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00608
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
00626
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
00635
00636
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, bool oasisFormat )
00659 {
00660 QDomElement de = doc.createElement( oasisFormat ? "math:munder" : "munder" );
00661 SingleContentElement::writeMathML( doc, de, oasisFormat );
00662 QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
00663
00664 op.appendChild( doc.createEntityReference( "UnderBar" ) );
00665 de.appendChild( op );
00666 parent.appendChild( de );
00667 }
00668
00669 KFORMULA_NAMESPACE_END