00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qpainter.h>
00022
00023 #include <kdebug.h>
00024 #include <klocale.h>
00025
00026 #include "elementvisitor.h"
00027 #include "formulaelement.h"
00028 #include "formulacursor.h"
00029 #include "fractionelement.h"
00030 #include "sequenceelement.h"
00031
00032 KFORMULA_NAMESPACE_BEGIN
00033 using namespace std;
00034
00035 FractionElement::FractionElement(BasicElement* parent) : BasicElement(parent),
00036 m_lineThicknessType( NoSize ),
00037 m_numAlign( NoHorizontalAlign ),
00038 m_denomAlign( NoHorizontalAlign ),
00039 m_customBevelled( false )
00040 {
00041 numerator = new SequenceElement(this);
00042 denominator = new SequenceElement(this);
00043 }
00044
00045 FractionElement::~FractionElement()
00046 {
00047 delete denominator;
00048 delete numerator;
00049 }
00050
00051 FractionElement::FractionElement( const FractionElement& other )
00052 : BasicElement( other ),
00053 m_lineThicknessType( other.m_lineThicknessType ),
00054 m_lineThickness( other.m_lineThickness ),
00055 m_numAlign( other.m_numAlign ),
00056 m_denomAlign( other.m_denomAlign ),
00057 m_customBevelled( other.m_customBevelled ),
00058 m_bevelled( other.m_bevelled )
00059 {
00060 numerator = new SequenceElement( *( other.numerator ) );
00061 denominator = new SequenceElement( *( other.denominator ) );
00062 numerator->setParent( this );
00063 denominator->setParent( this );
00064 }
00065
00066
00067 bool FractionElement::accept( ElementVisitor* visitor )
00068 {
00069 return visitor->visit( this );
00070 }
00071
00072 void FractionElement::entered( SequenceElement* child )
00073 {
00074 if ( child == numerator ) {
00075 formula()->tell( i18n( "Numerator" ) );
00076 }
00077 else {
00078 formula()->tell( i18n( "Denominator" ) );
00079 }
00080 }
00081
00082
00083 BasicElement* FractionElement::goToPos( FormulaCursor* cursor, bool& handled,
00084 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00085 {
00086 BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00087 if (e != 0) {
00088 LuPixelPoint myPos(parentOrigin.x() + getX(),
00089 parentOrigin.y() + getY());
00090 e = numerator->goToPos(cursor, handled, point, myPos);
00091 if (e != 0) {
00092 return e;
00093 }
00094 e = denominator->goToPos(cursor, handled, point, myPos);
00095 if (e != 0) {
00096 return e;
00097 }
00098
00099 luPixel dx = point.x() - myPos.x();
00100 luPixel dy = point.y() - myPos.y();
00101
00102
00103 if ((dx > numerator->getX()) &&
00104 (dy < numerator->getHeight())) {
00105 numerator->moveLeft(cursor, this);
00106 handled = true;
00107 return numerator;
00108 }
00109 else if ((dx > denominator->getX()) &&
00110 (dy > denominator->getY())) {
00111 denominator->moveLeft(cursor, this);
00112 handled = true;
00113 return denominator;
00114 }
00115
00116 return this;
00117 }
00118 return 0;
00119 }
00120
00121
00126 void FractionElement::calcSizes( const ContextStyle& context,
00127 ContextStyle::TextStyle tstyle,
00128 ContextStyle::IndexStyle istyle,
00129 StyleAttributes& style )
00130 {
00131 ContextStyle::TextStyle i_tstyle = context.convertTextStyleFraction( tstyle );
00132 ContextStyle::IndexStyle u_istyle = context.convertIndexStyleUpper( istyle );
00133 ContextStyle::IndexStyle l_istyle = context.convertIndexStyleLower( istyle );
00134 double factor = style.sizeFactor();
00135
00136 numerator->calcSizes( context, i_tstyle, u_istyle, style );
00137 denominator->calcSizes( context, i_tstyle, l_istyle, style );
00138
00139 luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
00140
00141 double linethickness = lineThickness( context, factor );
00142
00143 setWidth( QMAX( numerator->getWidth(), denominator->getWidth() ) );
00144 setHeight( numerator->getHeight() + denominator->getHeight() +
00145 2*distY + linethickness );
00146 setBaseline( qRound( numerator->getHeight() + distY + .5*linethickness
00147 + context.axisHeight( tstyle, factor ) ) );
00148
00149 numerator->setX( ( getWidth() - numerator->getWidth() ) / 2 );
00150 denominator->setX( ( getWidth() - denominator->getWidth() ) / 2 );
00151
00152 numerator->setY( 0 );
00153 denominator->setY( getHeight() - denominator->getHeight() );
00154 }
00155
00156
00162 void FractionElement::draw( QPainter& painter, const LuPixelRect& r,
00163 const ContextStyle& context,
00164 ContextStyle::TextStyle tstyle,
00165 ContextStyle::IndexStyle istyle,
00166 StyleAttributes& style,
00167 const LuPixelPoint& parentOrigin )
00168 {
00169 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00170
00171
00172
00173 numerator->draw( painter, r, context,
00174 context.convertTextStyleFraction( tstyle ),
00175 context.convertIndexStyleUpper( istyle ), style, myPos);
00176 if (denominator) {
00177 denominator->draw( painter, r, context,
00178 context.convertTextStyleFraction( tstyle ),
00179 context.convertIndexStyleLower( istyle ), style,
00180 myPos);
00181 }
00182
00183 if ( withLine() ) {
00184
00185 double factor = style.sizeFactor();
00186 double linethickness = lineThickness( context, factor );
00187 painter.setPen( QPen( style.color(),
00188 context.layoutUnitToPixelY( linethickness ) ) );
00189 painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
00190 context.layoutUnitToPixelY( myPos.y() + axis( context, tstyle, factor ) ),
00191 context.layoutUnitToPixelX( myPos.x() + getWidth() ),
00192 context.layoutUnitToPixelY( myPos.y() + axis( context, tstyle, factor ) ) );
00193 }
00194 }
00195
00196
00197 void FractionElement::dispatchFontCommand( FontCommand* cmd )
00198 {
00199 numerator->dispatchFontCommand( cmd );
00200 denominator->dispatchFontCommand( cmd );
00201 }
00202
00208 void FractionElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
00209 {
00210 if (cursor->isSelectionMode()) {
00211 getParent()->moveLeft(cursor, this);
00212 }
00213 else {
00214 bool linear = cursor->getLinearMovement();
00215 if (from == getParent()) {
00216 if (linear) {
00217 denominator->moveLeft(cursor, this);
00218 }
00219 else {
00220 numerator->moveLeft(cursor, this);
00221 }
00222 }
00223 else if (from == denominator) {
00224 numerator->moveLeft(cursor, this);
00225 }
00226 else {
00227 getParent()->moveLeft(cursor, this);
00228 }
00229 }
00230 }
00231
00232
00238 void FractionElement::moveRight(FormulaCursor* cursor, BasicElement* from)
00239 {
00240 if (cursor->isSelectionMode()) {
00241 getParent()->moveRight(cursor, this);
00242 }
00243 else {
00244 bool linear = cursor->getLinearMovement();
00245 if (from == getParent()) {
00246 numerator->moveRight(cursor, this);
00247 }
00248 else if (from == numerator) {
00249 if (linear) {
00250 denominator->moveRight(cursor, this);
00251 }
00252 else {
00253 getParent()->moveRight(cursor, this);
00254 }
00255 }
00256 else {
00257 getParent()->moveRight(cursor, this);
00258 }
00259 }
00260 }
00261
00262
00268 void FractionElement::moveUp(FormulaCursor* cursor, BasicElement* from)
00269 {
00270 if (cursor->isSelectionMode()) {
00271 getParent()->moveUp(cursor, this);
00272 }
00273 else {
00274 if (from == getParent()) {
00275 denominator->moveRight(cursor, this);
00276 }
00277 else if (from == denominator) {
00278 numerator->moveRight(cursor, this);
00279 }
00280 else {
00281 getParent()->moveUp(cursor, this);
00282 }
00283 }
00284 }
00285
00286
00292 void FractionElement::moveDown(FormulaCursor* cursor, BasicElement* from)
00293 {
00294 if (cursor->isSelectionMode()) {
00295 getParent()->moveDown(cursor, this);
00296 }
00297 else {
00298 if (from == getParent()) {
00299 numerator->moveRight(cursor, this);
00300 }
00301 else if (from == numerator) {
00302 denominator->moveRight(cursor, this);
00303 }
00304 else {
00305 getParent()->moveDown(cursor, this);
00306 }
00307 }
00308 }
00309
00310
00314 void FractionElement::insert(FormulaCursor* cursor,
00315 QPtrList<BasicElement>& newChildren,
00316 Direction direction)
00317 {
00318 if (cursor->getPos() == denominatorPos) {
00319 denominator = static_cast<SequenceElement*>(newChildren.take(0));
00320 denominator->setParent(this);
00321
00322 if (direction == beforeCursor) {
00323 denominator->moveLeft(cursor, this);
00324 }
00325 else {
00326 denominator->moveRight(cursor, this);
00327 }
00328 cursor->setSelection(false);
00329 formula()->changed();
00330 }
00331 }
00332
00333
00343 void FractionElement::remove(FormulaCursor* cursor,
00344 QPtrList<BasicElement>& removedChildren,
00345 Direction direction)
00346 {
00347 switch (cursor->getPos()) {
00348 case numeratorPos:
00349 getParent()->selectChild(cursor, this);
00350 getParent()->remove(cursor, removedChildren, direction);
00351 break;
00352 case denominatorPos:
00353 removedChildren.append(denominator);
00354 formula()->elementRemoval(denominator);
00355 denominator = 0;
00356 cursor->setTo(this, denominatorPos);
00357 formula()->changed();
00358 break;
00359 }
00360 }
00361
00362
00368 bool FractionElement::isSenseless()
00369 {
00370 return denominator == 0;
00371 }
00372
00373
00374
00375
00376
00377
00378 SequenceElement* FractionElement::getMainChild()
00379 {
00380 return numerator;
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00396 void FractionElement::selectChild(FormulaCursor* cursor, BasicElement* child)
00397 {
00398 if (child == numerator) {
00399 cursor->setTo(this, numeratorPos);
00400 }
00401 else if (child == denominator) {
00402 cursor->setTo(this, denominatorPos);
00403 }
00404 }
00405
00406
00410 void FractionElement::writeDom(QDomElement element)
00411 {
00412 BasicElement::writeDom(element);
00413
00414 QDomDocument doc = element.ownerDocument();
00415 if (!withLine()) element.setAttribute("NOLINE", 1);
00416
00417 QDomElement num = doc.createElement("NUMERATOR");
00418 num.appendChild(numerator->getElementDom(doc));
00419 element.appendChild(num);
00420
00421 QDomElement den = doc.createElement("DENOMINATOR");
00422 den.appendChild(denominator->getElementDom(doc));
00423 element.appendChild(den);
00424 }
00425
00430 bool FractionElement::readAttributesFromDom(QDomElement element)
00431 {
00432 if (!BasicElement::readAttributesFromDom(element)) {
00433 return false;
00434 }
00435 QString lineStr = element.attribute("NOLINE");
00436 if(!lineStr.isNull()) {
00437 m_lineThicknessType = RelativeSize;
00438 m_lineThickness = lineStr.toInt();
00439 }
00440 return true;
00441 }
00442
00447 bool FractionElement::readAttributesFromMathMLDom(const QDomElement& element)
00448 {
00449 if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
00450 return false;
00451 }
00452 QString linethicknessStr = element.attribute( "linethickness" ).lower();
00453 if ( ! linethicknessStr.isNull() ) {
00454 if ( linethicknessStr == "thin" ) {
00455 m_lineThicknessType = RelativeSize;
00456 m_lineThickness = 0.5;
00457 }
00458 else if ( linethicknessStr == "medium" ) {
00459 m_lineThicknessType = RelativeSize;
00460 m_lineThickness = 1.0;
00461 }
00462 else if ( linethicknessStr == "thick" ) {
00463 m_lineThicknessType = RelativeSize;
00464 m_lineThickness = 2.0;
00465 }
00466 else {
00467 m_lineThickness = getSize( linethicknessStr, &m_lineThicknessType );
00468 }
00469 }
00470 QString numalignStr = element.attribute( "numalign" ).lower();
00471 if ( ! numalignStr.isNull() ) {
00472 if ( numalignStr == "left" ) {
00473 m_numAlign = LeftHorizontalAlign;
00474 }
00475 else if ( numalignStr == "center" ) {
00476 m_numAlign = CenterHorizontalAlign;
00477 }
00478 else if ( numalignStr == "right" ) {
00479 m_numAlign = RightHorizontalAlign;
00480 }
00481 }
00482 QString denomalignStr = element.attribute( "denomalign" ).lower();
00483 if ( ! denomalignStr.isNull() ) {
00484 if ( denomalignStr == "left" ) {
00485 m_denomAlign = LeftHorizontalAlign;
00486 }
00487 else if ( denomalignStr == "center" ) {
00488 m_denomAlign = CenterHorizontalAlign;
00489 }
00490 else if ( denomalignStr == "right" ) {
00491 m_denomAlign = RightHorizontalAlign;
00492 }
00493 }
00494 QString bevelledStr = element.attribute( "bevelled" ).lower();
00495 if ( ! bevelledStr.isNull() ) {
00496 m_customBevelled = true;
00497 if ( bevelledStr == "true" ) {
00498 m_bevelled = true;
00499 }
00500 else {
00501 m_bevelled = false;
00502 }
00503 }
00504
00505 return true;
00506 }
00507
00513 bool FractionElement::readContentFromDom(QDomNode& node)
00514 {
00515 if (!BasicElement::readContentFromDom(node)) {
00516 return false;
00517 }
00518
00519 if ( !buildChild( numerator, node, "NUMERATOR" ) ) {
00520 kdWarning( DEBUGID ) << "Empty numerator in FractionElement." << endl;
00521 return false;
00522 }
00523 node = node.nextSibling();
00524
00525 if ( !buildChild( denominator, node, "DENOMINATOR" ) ) {
00526 kdWarning( DEBUGID ) << "Empty denominator in FractionElement." << endl;
00527 return false;
00528 }
00529 node = node.nextSibling();
00530
00531 return true;
00532 }
00533
00539 int FractionElement::readContentFromMathMLDom(QDomNode& node)
00540 {
00541 if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
00542 return -1;
00543 }
00544
00545 int numeratorNumber = numerator->buildMathMLChild( node );
00546 if ( numeratorNumber == -1 ) {
00547 kdWarning( DEBUGID ) << "Empty numerator in FractionElement." << endl;
00548 return -1;
00549 }
00550 for (int i = 0; i < numeratorNumber; i++ ) {
00551 if ( node.isNull() ) {
00552 return -1;
00553 }
00554 node = node.nextSibling();
00555 }
00556
00557 if ( denominator->buildMathMLChild( node ) == -1 ) {
00558 kdWarning( DEBUGID ) << "Empty denominator in FractionElement." << endl;
00559 return -1;
00560 }
00561
00562 return 1;
00563 }
00564
00565 QString FractionElement::toLatex()
00566 {
00567 if ( withLine() ) {
00568 return "\\frac{" + numerator->toLatex() +"}{" + denominator->toLatex() + "}";
00569 }
00570 else {
00571 return "{" + numerator->toLatex() + "\\atop " + denominator->toLatex() + "}";
00572 }
00573 }
00574
00575 QString FractionElement::formulaString()
00576 {
00577 return "(" + numerator->formulaString() + ")/(" + denominator->formulaString() + ")";
00578 }
00579
00580 void FractionElement::writeMathMLAttributes( QDomElement& element ) const
00581 {
00582 switch ( m_lineThicknessType ) {
00583 case AbsoluteSize:
00584 element.setAttribute( "linethickness", QString( "%1pt" ).arg( m_lineThickness ) );
00585 break;
00586 case RelativeSize:
00587 element.setAttribute( "linethickness", QString( "%1%" ).arg( m_lineThickness * 100.0 ) );
00588 break;
00589 case PixelSize:
00590 element.setAttribute( "linethickness", QString( "%1px" ).arg( m_lineThickness ) );
00591 break;
00592 default:
00593 break;
00594 }
00595
00596 switch ( m_numAlign ) {
00597 case LeftHorizontalAlign:
00598 element.setAttribute( "numalign", "left" );
00599 break;
00600 case CenterHorizontalAlign:
00601 element.setAttribute( "numalign", "center" );
00602 break;
00603 case RightHorizontalAlign:
00604 element.setAttribute( "numalign", "right" );
00605 break;
00606 default:
00607 break;
00608 }
00609
00610 switch ( m_denomAlign ) {
00611 case LeftHorizontalAlign:
00612 element.setAttribute( "denomalign", "left" );
00613 break;
00614 case CenterHorizontalAlign:
00615 element.setAttribute( "denomalign", "center" );
00616 break;
00617 case RightHorizontalAlign:
00618 element.setAttribute( "denomalign", "right" );
00619 break;
00620 default:
00621 break;
00622 }
00623
00624 if ( m_customBevelled ) {
00625 element.setAttribute( "bevelled", m_bevelled ? "true" : "false" );
00626 }
00627 }
00628
00629 void FractionElement::writeMathMLContent( QDomDocument& doc,
00630 QDomElement& element,
00631 bool oasisFormat ) const
00632 {
00633 numerator->writeMathML( doc, element, oasisFormat );
00634 denominator->writeMathML( doc, element, oasisFormat );
00635 }
00636
00637 double FractionElement::lineThickness( const ContextStyle& context, double factor )
00638 {
00639 double linethickness = context.getLineWidth( factor );
00640 switch ( m_lineThicknessType ) {
00641 case AbsoluteSize:
00642 linethickness = context.ptToLayoutUnitPixX( m_lineThickness );
00643 break;
00644 case RelativeSize:
00645 linethickness *= m_lineThickness;
00646 break;
00647 case PixelSize:
00648 linethickness = m_lineThickness;
00649 break;
00650 default:
00651 break;
00652 }
00653 return linethickness;
00654 }
00655
00656
00657 KFORMULA_NAMESPACE_END