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, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle )
00112 {
00113 luPt mySize = context.getAdjustedSize( tstyle );
00114
00115
00116 QFont font = getFont( context );
00117 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
00118
00119 QFontMetrics fm( font );
00120 QChar ch = getRealCharacter(context);
00121 if ( ch != QChar::null ) {
00122 QRect bound = fm.boundingRect( ch );
00123 setWidth( context.ptToLayoutUnitPt( fm.width( ch ) ) );
00124 setHeight( context.ptToLayoutUnitPt( bound.height() ) );
00125 setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
00126
00127
00128
00129 if ( getBaseline() == 0 ) {
00130
00131 setBaseline( -1 );
00132 }
00133 }
00134 else {
00135 setWidth( qRound( context.getEmptyRectWidth() * 2./3. ) );
00136 setHeight( qRound( context.getEmptyRectHeight() * 2./3. ) );
00137 setBaseline( getHeight() );
00138 }
00139
00140
00141
00142 }
00143
00149 void TextElement::draw( QPainter& painter, const LuPixelRect& ,
00150 const ContextStyle& context,
00151 ContextStyle::TextStyle tstyle,
00152 ContextStyle::IndexStyle ,
00153 const LuPixelPoint& parentOrigin )
00154 {
00155 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00156
00157
00158
00159 setUpPainter( context, painter );
00160
00161 luPt mySize = context.getAdjustedSize( tstyle );
00162 QFont font = getFont( context );
00163 font.setPointSizeFloat( context.layoutUnitToFontSize( mySize, false ) );
00164 painter.setFont( font );
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 ElementType* token = getElementType();
00175 if ( ( token != 0 ) && !symbol ) {
00176 QString text = token->text( static_cast<SequenceElement*>( getParent() ) );
00177
00178
00179
00180 painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
00181 context.layoutUnitToPixelY( myPos.y()+getBaseline() ),
00182 text );
00183 }
00184 else {
00185
00186 QChar ch = getRealCharacter(context);
00187 if ( ch != QChar::null ) {
00188 luPixel bl = getBaseline();
00189 if ( bl == -1 ) {
00190
00191
00192
00193
00194 bl = -( getHeight()/2 + context.axisHeight( tstyle ) );
00195 }
00196 painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
00197 context.layoutUnitToPixelY( myPos.y()+bl ),
00198 ch );
00199 }
00200 else {
00201 painter.setPen( QPen( context.getErrorColor(),
00202 context.layoutUnitToPixelX( context.getLineWidth() ) ) );
00203 painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
00204 context.layoutUnitToPixelY( myPos.y() ),
00205 context.layoutUnitToPixelX( getWidth() ),
00206 context.layoutUnitToPixelY( getHeight() ) );
00207 }
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 }
00223
00224
00225 void TextElement::dispatchFontCommand( FontCommand* cmd )
00226 {
00227 cmd->addTextElement( this );
00228 }
00229
00230 void TextElement::setCharStyle( CharStyle cs )
00231 {
00232 charStyle( cs );
00233 formula()->changed();
00234 }
00235
00236 void TextElement::setCharFamily( CharFamily cf )
00237 {
00238 charFamily( cf );
00239 formula()->changed();
00240 }
00241
00242 QChar TextElement::getRealCharacter(const ContextStyle& context)
00243 {
00244 if ( !isSymbol() ) {
00245 const FontStyle& fontStyle = context.fontStyle();
00246 const AlphaTable* alphaTable = fontStyle.alphaTable();
00247 if ( alphaTable != 0 ) {
00248 AlphaTableEntry ate = alphaTable->entry( character,
00249 charFamily(),
00250 charStyle() );
00251 if ( ate.valid() ) {
00252 return ate.pos;
00253 }
00254 }
00255 return character;
00256 }
00257 else {
00258 return getSymbolTable().character(character, charStyle());
00259 }
00260 }
00261
00262
00263 QFont TextElement::getFont(const ContextStyle& context)
00264 {
00265 if ( !isSymbol() ) {
00266 const FontStyle& fontStyle = context.fontStyle();
00267 const AlphaTable* alphaTable = fontStyle.alphaTable();
00268 if ( alphaTable != 0 ) {
00269 AlphaTableEntry ate = alphaTable->entry( character,
00270 charFamily(),
00271 charStyle() );
00272 if ( ate.valid() ) {
00273 return ate.font;
00274 }
00275 }
00276 QFont font;
00277 if (getElementType() != 0) {
00278 font = getElementType()->getFont(context);
00279 }
00280 else {
00281 font = context.getDefaultFont();
00282 }
00283 switch ( charStyle() ) {
00284 case anyChar:
00285 break;
00286 case normalChar:
00287 font.setItalic( false );
00288 font.setBold( false );
00289 break;
00290 case boldChar:
00291 font.setItalic( false );
00292 font.setBold( true );
00293 break;
00294 case italicChar:
00295 font.setItalic( true );
00296 font.setBold( false );
00297 break;
00298 case boldItalicChar:
00299 font.setItalic( true );
00300 font.setBold( true );
00301 break;
00302 }
00303 return font;
00304 }
00305 return context.symbolTable().font( character, charStyle() );
00306 }
00307
00308
00309 void TextElement::setUpPainter(const ContextStyle& context, QPainter& painter)
00310 {
00311 if (getElementType() != 0) {
00312 getElementType()->setUpPainter(context, painter);
00313 }
00314 else {
00315 painter.setPen(Qt::red);
00316 }
00317 }
00318
00319 const SymbolTable& TextElement::getSymbolTable() const
00320 {
00321 return formula()->getSymbolTable();
00322 }
00323
00324
00328 void TextElement::writeDom(QDomElement element)
00329 {
00330 BasicElement::writeDom(element);
00331 element.setAttribute("CHAR", QString(character));
00332
00333
00334 if (symbol) element.setAttribute("SYMBOL", "3");
00335
00336 switch ( charStyle() ) {
00337 case anyChar: break;
00338 case normalChar: element.setAttribute("STYLE", "normal"); break;
00339 case boldChar: element.setAttribute("STYLE", "bold"); break;
00340 case italicChar: element.setAttribute("STYLE", "italic"); break;
00341 case boldItalicChar: element.setAttribute("STYLE", "bolditalic"); break;
00342 }
00343
00344 switch ( charFamily() ) {
00345 case normalFamily: element.setAttribute("FAMILY", "normal"); break;
00346 case scriptFamily: element.setAttribute("FAMILY", "script"); break;
00347 case frakturFamily: element.setAttribute("FAMILY", "fraktur"); break;
00348 case doubleStruckFamily: element.setAttribute("FAMILY", "doublestruck"); break;
00349 case anyFamily: break;
00350 }
00351 }
00352
00357 bool TextElement::readAttributesFromDom(QDomElement element)
00358 {
00359 if (!BasicElement::readAttributesFromDom(element)) {
00360 return false;
00361 }
00362 QString charStr = element.attribute("CHAR");
00363 if(!charStr.isNull()) {
00364 character = charStr.at(0);
00365 }
00366 QString symbolStr = element.attribute("SYMBOL");
00367 if(!symbolStr.isNull()) {
00368 int symbolInt = symbolStr.toInt();
00369 if ( symbolInt == 1 ) {
00370 character = getSymbolTable().unicodeFromSymbolFont(character);
00371 }
00372 if ( symbolInt == 2 ) {
00373 switch ( character.unicode() ) {
00374 case 0x03D5: character = 0x03C6; break;
00375 case 0x03C6: character = 0x03D5; break;
00376 case 0x03Ba: character = 0x03BA; break;
00377 case 0x00B4: character = 0x2032; break;
00378 case 0x2215: character = 0x2244; break;
00379 case 0x00B7: character = 0x2022; break;
00380 case 0x1D574: character = 0x2111; break;
00381 case 0x1D579: character = 0x211C; break;
00382 case 0x2219: character = 0x22C5; break;
00383 case 0x2662: character = 0x26C4; break;
00384 case 0x220B: character = 0x220D; break;
00385 case 0x224C: character = 0x2245; break;
00386 case 0x03DB: character = 0x03C2; break;
00387 }
00388 }
00389 symbol = symbolInt != 0;
00390 }
00391
00392 QString styleStr = element.attribute("STYLE");
00393 if ( styleStr == "normal" ) {
00394 charStyle( normalChar );
00395 }
00396 else if ( styleStr == "bold" ) {
00397 charStyle( boldChar );
00398 }
00399 else if ( styleStr == "italic" ) {
00400 charStyle( italicChar );
00401 }
00402 else if ( styleStr == "bolditalic" ) {
00403 charStyle( boldItalicChar );
00404 }
00405 else {
00406 charStyle( anyChar );
00407 }
00408
00409 QString familyStr = element.attribute( "FAMILY" );
00410 if ( familyStr == "normal" ) {
00411 charFamily( normalFamily );
00412 }
00413 else if ( familyStr == "script" ) {
00414 charFamily( scriptFamily );
00415 }
00416 else if ( familyStr == "fraktur" ) {
00417 charFamily( frakturFamily );
00418 }
00419 else if ( familyStr == "doublestruck" ) {
00420 charFamily( doubleStruckFamily );
00421 }
00422 else {
00423 charFamily( anyFamily );
00424 }
00425
00426
00427
00428
00429
00430 return true;
00431 }
00432
00438 bool TextElement::readContentFromDom(QDomNode& node)
00439 {
00440 return BasicElement::readContentFromDom(node);
00441 }
00442
00443 QString TextElement::toLatex()
00444 {
00445 if ( isSymbol() ) {
00446 QString texName = getSymbolTable().name( character );
00447 if ( !texName.isNull() )
00448 return "\\" + texName;
00449 return " ? ";
00450 }
00451 else {
00452 return character;
00453 }
00454 }
00455
00456 QString TextElement::formulaString()
00457 {
00458 if ( isSymbol() ) {
00459 QString texName = getSymbolTable().name( character );
00460 if ( !texName.isNull() )
00461 return " " + texName + " ";
00462 return " ? ";
00463 }
00464 else {
00465 return character;
00466 }
00467 }
00468
00469
00470 EmptyElement::EmptyElement( BasicElement* parent )
00471 : BasicElement( parent )
00472 {
00473 }
00474
00475 EmptyElement::EmptyElement( const EmptyElement& other )
00476 : BasicElement( other )
00477 {
00478 }
00479
00480
00481 bool EmptyElement::accept( ElementVisitor* visitor )
00482 {
00483 return visitor->visit( this );
00484 }
00485
00486
00487 void EmptyElement::calcSizes( const ContextStyle& context,
00488 ContextStyle::TextStyle tstyle,
00489 ContextStyle::IndexStyle )
00490 {
00491 luPt mySize = context.getAdjustedSize( tstyle );
00492
00493
00494 QFont font = context.getDefaultFont();
00495 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
00496
00497 QFontMetrics fm( font );
00498 QChar ch = 'A';
00499 QRect bound = fm.boundingRect( ch );
00500 setWidth( 0 );
00501 setHeight( context.ptToLayoutUnitPt( bound.height() ) );
00502 setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
00503 }
00504
00505 void EmptyElement::draw( QPainter& painter, const LuPixelRect& ,
00506 const ContextStyle& context,
00507 ContextStyle::TextStyle ,
00508 ContextStyle::IndexStyle ,
00509 const LuPixelPoint& parentOrigin )
00510 {
00511 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00512
00513
00514
00515
00516
00517 if ( context.edit() ) {
00518 painter.setPen( context.getHelpColor() );
00519 painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
00520 context.layoutUnitToPixelY( myPos.y() ),
00521 context.layoutUnitToPixelX( myPos.x() ),
00522 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
00523 }
00524 }
00525
00526 QString EmptyElement::toLatex()
00527 {
00528 return "{}";
00529 }
00530
00531 KFORMULA_NAMESPACE_END