00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qfontmetrics.h>
00022 #include <qpainter.h>
00023
00024 #include <kdebug.h>
00025
00026 #include "basicelement.h"
00027 #include "contextstyle.h"
00028 #include "elementtype.h"
00029 #include "elementvisitor.h"
00030 #include "fontstyle.h"
00031 #include "formulaelement.h"
00032 #include "kformulacommand.h"
00033 #include "sequenceelement.h"
00034 #include "symboltable.h"
00035 #include "textelement.h"
00036
00037
00038 KFORMULA_NAMESPACE_BEGIN
00039
00040 TextElement::TextElement(QChar ch, bool beSymbol, BasicElement* parent)
00041 : BasicElement(parent), character(ch), symbol(beSymbol)
00042 {
00043 charStyle( anyChar );
00044 charFamily( anyFamily );
00045 }
00046
00047
00048 TextElement::TextElement( const TextElement& other )
00049 : BasicElement( other ),
00050 character( other.character ),
00051 symbol( other.symbol ),
00052 m_format( other.m_format )
00053 {
00054 }
00055
00056
00057 bool TextElement::accept( ElementVisitor* visitor )
00058 {
00059 return visitor->visit( this );
00060 }
00061
00062
00063 TokenType TextElement::getTokenType() const
00064 {
00065 if ( isSymbol() ) {
00066 return getSymbolTable().charClass( character );
00067 }
00068
00069 switch ( character.unicode() ) {
00070 case '+':
00071 case '-':
00072 case '*':
00073
00074 return BINOP;
00075 case '=':
00076 case '<':
00077 case '>':
00078 return RELATION;
00079 case ',':
00080 case ';':
00081 case ':':
00082 return PUNCTUATION;
00083 case '\\':
00084 return SEPARATOR;
00085 case '\0':
00086 return ELEMENT;
00087 default:
00088 if ( character.isNumber() ) {
00089 return NUMBER;
00090 }
00091 else {
00092 return ORDINARY;
00093 }
00094 }
00095 }
00096
00097
00098 bool TextElement::isInvisible() const
00099 {
00100 if (getElementType() != 0) {
00101 return getElementType()->isInvisible(*this);
00102 }
00103 return false;
00104 }
00105
00106
00111 void TextElement::calcSizes( const ContextStyle& context,
00112 ContextStyle::TextStyle tstyle,
00113 ContextStyle::IndexStyle ,
00114 StyleAttributes& style )
00115 {
00116 double factor = style.sizeFactor();
00117 luPt mySize = context.getAdjustedSize( tstyle, factor );
00118
00119 setCharStyle( style.charStyle() );
00120 setCharFamily( style.charFamily() );
00121
00122 QFont font = getFont( context, style );
00123 double fontsize = context.layoutUnitPtToPt( mySize );
00124 double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
00125 double size = fontsize * scriptsize;
00126 font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
00127
00128 QFontMetrics fm( font );
00129 if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
00130 setWidth( 0 );
00131 setHeight( 0 );
00132 setBaseline( getHeight() );
00133 }
00134 else {
00135 QChar ch = getRealCharacter(context);
00136 if ( ch == QChar::null ) {
00137 setWidth( qRound( context.getEmptyRectWidth( factor ) * 2./3. ) );
00138 setHeight( qRound( context.getEmptyRectHeight( factor ) * 2./3. ) );
00139 setBaseline( getHeight() );
00140 }
00141 else {
00142 QRect bound = fm.boundingRect( ch );
00143 setWidth( context.ptToLayoutUnitPt( fm.width( ch ) ) );
00144 setHeight( context.ptToLayoutUnitPt( bound.height() ) );
00145 setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
00146
00147
00148
00149 if ( getBaseline() == 0 ) {
00150
00151 setBaseline( -1 );
00152 }
00153 }
00154 }
00155 }
00156
00162 void TextElement::draw( QPainter& painter, const LuPixelRect& ,
00163 const ContextStyle& context,
00164 ContextStyle::TextStyle tstyle,
00165 ContextStyle::IndexStyle ,
00166 StyleAttributes& style,
00167 const LuPixelPoint& parentOrigin )
00168 {
00169 if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
00170 return;
00171 }
00172
00173 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00174
00175
00176
00177
00178
00179 painter.setPen( style.color() );
00180
00181 setCharStyle( style.charStyle() );
00182 setCharFamily( style.charFamily() );
00183
00184 double factor = style.sizeFactor();
00185 luPt mySize = context.getAdjustedSize( tstyle, factor );
00186 QFont font = getFont( context, style );
00187 double fontsize = context.layoutUnitPtToPt( mySize );
00188 double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
00189 double size = fontsize * scriptsize;
00190 font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
00191 painter.setFont( font );
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 QChar ch = getRealCharacter(context);
00220 if ( ch != QChar::null ) {
00221 luPixel bl = getBaseline();
00222 if ( bl == -1 ) {
00223
00224
00225
00226
00227 bl = -( getHeight()/2 + context.axisHeight( tstyle, factor ) );
00228 }
00229 painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
00230 context.layoutUnitToPixelY( myPos.y()+bl ),
00231 ch );
00232 }
00233 else {
00234 painter.setPen( QPen( context.getErrorColor(),
00235 context.layoutUnitToPixelX( context.getLineWidth( factor ) ) ) );
00236 painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
00237 context.layoutUnitToPixelY( myPos.y() ),
00238 context.layoutUnitToPixelX( getWidth() ),
00239 context.layoutUnitToPixelY( getHeight() ) );
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 }
00256
00257
00258 void TextElement::dispatchFontCommand( FontCommand* cmd )
00259 {
00260 cmd->addTextElement( this );
00261 }
00262
00263 void TextElement::setCharStyle( CharStyle cs )
00264 {
00265 charStyle( cs );
00266 formula()->changed();
00267 }
00268
00269 void TextElement::setCharFamily( CharFamily cf )
00270 {
00271 charFamily( cf );
00272 formula()->changed();
00273 }
00274
00275 QChar TextElement::getRealCharacter(const ContextStyle& context)
00276 {
00277 return character;
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 }
00297
00298
00299 QFont TextElement::getFont(const ContextStyle& context, const StyleAttributes& style)
00300 {
00301 const FontStyle& fontStyle = context.fontStyle();
00302 QFont font;
00303 if ( style.customFont() ) {
00304 font = style.font();
00305 }
00306 else if (getElementType() != 0) {
00307 font = getElementType()->getFont(context);
00308 }
00309 else {
00310 font = context.getDefaultFont();
00311 }
00312 switch ( charStyle() ) {
00313 case anyChar:
00314 font.setItalic( false );
00315 font.setBold( false );
00316 break;
00317 case normalChar:
00318 font.setItalic( false );
00319 font.setBold( false );
00320 break;
00321 case boldChar:
00322 font.setItalic( false );
00323 font.setBold( true );
00324 break;
00325 case italicChar:
00326 font.setItalic( true );
00327 font.setBold( false );
00328 break;
00329 case boldItalicChar:
00330 font.setItalic( true );
00331 font.setBold( true );
00332 break;
00333 }
00334 return fontStyle.symbolTable()->font( character, font );
00335 }
00336
00337
00338 void TextElement::setUpPainter(const ContextStyle& context, QPainter& painter)
00339 {
00340 if (getElementType() != 0) {
00341 getElementType()->setUpPainter(context, painter);
00342 }
00343 else {
00344 painter.setPen(Qt::red);
00345 }
00346 }
00347
00348 const SymbolTable& TextElement::getSymbolTable() const
00349 {
00350 return formula()->getSymbolTable();
00351 }
00352
00353
00354 void TextElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool ) const
00355 {
00356 parent.appendChild( doc.createTextNode( getCharacter() ) );
00357 }
00358
00362 void TextElement::writeDom(QDomElement element)
00363 {
00364 BasicElement::writeDom(element);
00365 element.setAttribute("CHAR", QString(character));
00366
00367
00368 if (symbol) element.setAttribute("SYMBOL", "3");
00369
00370 switch ( charStyle() ) {
00371 case anyChar: break;
00372 case normalChar: element.setAttribute("STYLE", "normal"); break;
00373 case boldChar: element.setAttribute("STYLE", "bold"); break;
00374 case italicChar: element.setAttribute("STYLE", "italic"); break;
00375 case boldItalicChar: element.setAttribute("STYLE", "bolditalic"); break;
00376 }
00377
00378 switch ( charFamily() ) {
00379 case normalFamily: element.setAttribute("FAMILY", "normal"); break;
00380 case scriptFamily: element.setAttribute("FAMILY", "script"); break;
00381 case frakturFamily: element.setAttribute("FAMILY", "fraktur"); break;
00382 case doubleStruckFamily: element.setAttribute("FAMILY", "doublestruck"); break;
00383 case anyFamily: break;
00384 }
00385 }
00386
00391 bool TextElement::readAttributesFromDom(QDomElement element)
00392 {
00393 if (!BasicElement::readAttributesFromDom(element)) {
00394 return false;
00395 }
00396 QString charStr = element.attribute("CHAR");
00397 if(!charStr.isNull()) {
00398 character = charStr.at(0);
00399 }
00400 QString symbolStr = element.attribute("SYMBOL");
00401 if(!symbolStr.isNull()) {
00402 int symbolInt = symbolStr.toInt();
00403 if ( symbolInt == 1 ) {
00404 character = getSymbolTable().unicodeFromSymbolFont(character);
00405 }
00406 if ( symbolInt == 2 ) {
00407 switch ( character.unicode() ) {
00408 case 0x03D5: character = 0x03C6; break;
00409 case 0x03C6: character = 0x03D5; break;
00410 case 0x03Ba: character = 0x03BA; break;
00411 case 0x00B4: character = 0x2032; break;
00412 case 0x2215: character = 0x2244; break;
00413 case 0x00B7: character = 0x2022; break;
00414 case 0x1D574: character = 0x2111; break;
00415 case 0x1D579: character = 0x211C; break;
00416 case 0x2219: character = 0x22C5; break;
00417 case 0x2662: character = 0x26C4; break;
00418 case 0x220B: character = 0x220D; break;
00419 case 0x224C: character = 0x2245; break;
00420 case 0x03DB: character = 0x03C2; break;
00421 }
00422 }
00423 symbol = symbolInt != 0;
00424 }
00425
00426 QString styleStr = element.attribute("STYLE");
00427 if ( styleStr == "normal" ) {
00428 charStyle( normalChar );
00429 }
00430 else if ( styleStr == "bold" ) {
00431 charStyle( boldChar );
00432 }
00433 else if ( styleStr == "italic" ) {
00434 charStyle( italicChar );
00435 }
00436 else if ( styleStr == "bolditalic" ) {
00437 charStyle( boldItalicChar );
00438 }
00439 else {
00440 charStyle( anyChar );
00441 }
00442
00443 QString familyStr = element.attribute( "FAMILY" );
00444 if ( familyStr == "normal" ) {
00445 charFamily( normalFamily );
00446 }
00447 else if ( familyStr == "script" ) {
00448 charFamily( scriptFamily );
00449 }
00450 else if ( familyStr == "fraktur" ) {
00451 charFamily( frakturFamily );
00452 }
00453 else if ( familyStr == "doublestruck" ) {
00454 charFamily( doubleStruckFamily );
00455 }
00456 else {
00457 charFamily( anyFamily );
00458 }
00459
00460
00461
00462
00463
00464 return true;
00465 }
00466
00472 bool TextElement::readContentFromDom(QDomNode& node)
00473 {
00474 return BasicElement::readContentFromDom(node);
00475 }
00476
00477 QString TextElement::toLatex()
00478 {
00479 if ( isSymbol() ) {
00480 QString texName = getSymbolTable().name( character );
00481 if ( !texName.isNull() )
00482 return " \\" + texName + " ";
00483 return " ? ";
00484 }
00485 else {
00486 return QString(character);
00487 }
00488 }
00489
00490 QString TextElement::formulaString()
00491 {
00492 if ( isSymbol() ) {
00493 QString texName = getSymbolTable().name( character );
00494 if ( !texName.isNull() )
00495 return " " + texName + " ";
00496 return " ? ";
00497 }
00498 else {
00499 return character;
00500 }
00501 }
00502
00503
00504 EmptyElement::EmptyElement( BasicElement* parent )
00505 : BasicElement( parent )
00506 {
00507 }
00508
00509 EmptyElement::EmptyElement( const EmptyElement& other )
00510 : BasicElement( other )
00511 {
00512 }
00513
00514
00515 bool EmptyElement::accept( ElementVisitor* visitor )
00516 {
00517 return visitor->visit( this );
00518 }
00519
00520
00521 void EmptyElement::calcSizes( const ContextStyle& context,
00522 ContextStyle::TextStyle tstyle,
00523 ContextStyle::IndexStyle ,
00524 StyleAttributes& style )
00525 {
00526 luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
00527
00528
00529 QFont font = context.getDefaultFont();
00530 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
00531
00532 QFontMetrics fm( font );
00533 QChar ch = 'A';
00534 QRect bound = fm.boundingRect( ch );
00535 setWidth( 0 );
00536 setHeight( context.ptToLayoutUnitPt( bound.height() ) );
00537 setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
00538 }
00539
00540 void EmptyElement::draw( QPainter& painter, const LuPixelRect& ,
00541 const ContextStyle& context,
00542 ContextStyle::TextStyle ,
00543 ContextStyle::IndexStyle ,
00544 StyleAttributes& ,
00545 const LuPixelPoint& parentOrigin )
00546 {
00547 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00548
00549
00550
00551
00552
00553 if ( context.edit() ) {
00554 painter.setPen( context.getHelpColor() );
00555 painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
00556 context.layoutUnitToPixelY( myPos.y() ),
00557 context.layoutUnitToPixelX( myPos.x() ),
00558 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
00559 }
00560 }
00561
00562 QString EmptyElement::toLatex()
00563 {
00564 return "{}";
00565 }
00566
00567 KFORMULA_NAMESPACE_END