00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <QPainter>
00021 #include <QPen>
00022 #include <QApplication>
00023
00024 #include <kdebug.h>
00025 #include <klocale.h>
00026 #include <kstandarddirs.h>
00027 #include <kio/netaccess.h>
00028 #include <kio/job.h>
00029 #include <kmessagebox.h>
00030
00031 #include "kformuladefs.h"
00032 #include "cmstyle.h"
00033
00034
00035 KFORMULA_NAMESPACE_BEGIN
00036
00037 #include "cmmapping.cc"
00038
00039 bool CMStyle::m_installed = false;
00040
00041 bool CMStyle::init( ContextStyle* context, bool install )
00042 {
00043 if (!m_installed && install)
00044 installFonts();
00045 SymbolTable* st = symbolTable();
00046 st->init( context );
00047
00048 SymbolTable::NameTable tempNames;
00049 fillNameTable( tempNames );
00050
00051 st->initFont( cmbx10Map, "cmbx10", tempNames );
00052 st->initFont( cmex10Map, "cmex10", tempNames );
00053 st->initFont( cmmi10Map, "cmmi10", tempNames );
00054 st->initFont( cmr10Map, "cmr10", tempNames );
00055 st->initFont( cmsy10Map, "cmsy10", tempNames );
00056 st->initFont( msam10Map, "msam10", tempNames );
00057 st->initFont( msbm10Map, "msbm10", tempNames );
00058
00059 return true;
00060 }
00061
00062
00063 const AlphaTable* CMStyle::alphaTable() const
00064 {
00065 return &m_alphaTable;
00066 }
00067
00068
00069 Artwork* CMStyle::createArtwork( SymbolType type ) const
00070 {
00071 return new CMArtwork( type );
00072 }
00073
00074 QStringList CMStyle::missingFonts( bool install )
00075 {
00076 if (!m_installed && install)
00077 installFonts();
00078
00079 QStringList missing = missingFontsInternal();
00080 return missing;
00081 }
00082
00083 QStringList CMStyle::missingFontsInternal()
00084 {
00085 QStringList missing;
00086
00087 testFont( missing, "cmbx10" );
00088 testFont( missing, "cmex10" );
00089 testFont( missing, "cmmi10" );
00090 testFont( missing, "cmr10" );
00091 testFont( missing, "cmsy10" );
00092 testFont( missing, "msam10" );
00093 testFont( missing, "msbm10" );
00094
00095 return missing;
00096 }
00097
00098 void CMStyle::installFonts()
00099 {
00100 if (m_installed)
00101 return;
00102 const QStringList missing = missingFontsInternal();
00103 if (!missing.isEmpty())
00104 {
00105 KUrl::List urlList;
00106 for (QStringList::const_iterator it = missing.begin(); it != missing.end(); ++it)
00107 {
00108 if (!KIO::NetAccess::exists("fonts:/Personal/" + *it + ".ttf", true, NULL))
00109 urlList.append(KUrl::fromPath(KStandardDirs::locate("data", "kformula/fonts/" + *it + ".ttf")));
00110 }
00111 KIO::copy(urlList, KUrl("fonts:/Personal/"), false);
00112 KMessageBox::information(qApp->activeWindow(),
00113 i18n("Some fonts have been installed to assure that symbols in formulas are properly visualized. You must restart the application in order so that changes take effect"));
00114 }
00115 m_installed = true;
00116 }
00117
00118 CMAlphaTable::CMAlphaTable()
00119 {
00120 }
00121
00122
00123 AlphaTableEntry CMAlphaTable::entry( short pos,
00124 CharFamily family,
00125 CharStyle ) const
00126 {
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 AlphaTableEntry entry;
00145 switch( family ) {
00146
00147 case scriptFamily:
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 if ( ( pos >= 'A' ) && ( pos <= 'Z' ) ) {
00158 entry.pos = pos;
00159 entry.font = QFont( "cmsy10" );
00160 }
00161 break;
00162 case frakturFamily:
00163 break;
00164 case doubleStruckFamily:
00165 if ( ( pos >= 'A' ) && ( pos <= 'Z' ) ) {
00166 entry.pos = pos;
00167 entry.font = QFont( "msbm10" );
00168 }
00169 break;
00170 default:
00171 break;
00172 }
00173 return entry;
00174 }
00175
00176
00177 static const char cmex_LeftSquareBracket = 163;
00178 static const char cmex_RightSquareBracket = 164;
00179 static const char cmex_LeftCurlyBracket = 169;
00180 static const char cmex_RightCurlyBracket = 170;
00181 static const char cmex_LeftCornerBracket = 173;
00182 static const char cmex_RightCornerBracket = 174;
00183 static const char cmex_LeftRoundBracket = 161;
00184 static const char cmex_RightRoundBracket = 162;
00185 static const char cmex_SlashBracket = 177;
00186 static const char cmex_BackSlashBracket = 178;
00187
00188
00189
00190
00191 static const char cmex_Int = 90;
00192 static const char cmex_Sum = 88;
00193 static const char cmex_Prod = 89;
00194
00195
00196
00197 static short cmex_nextchar( short ch )
00198 {
00199 switch ( ch ) {
00200 case 161: return 179;
00201 case 162: return 180;
00202 case 163: return 104;
00203 case 164: return 105;
00204 case 169: return 110;
00205 case 170: return 111;
00206 case 165: return 106;
00207 case 166: return 107;
00208 case 167: return 108;
00209 case 168: return 109;
00210 case 173: return 68;
00211 case 174: return 69;
00212 case 177: return 46;
00213 case 178: return 47;
00214
00215 case 179: return 181;
00216 case 180: return 182;
00217 case 104: return 183;
00218 case 105: return 184;
00219 case 110: return 189;
00220 case 111: return 190;
00221 case 106: return 185;
00222 case 107: return 186;
00223 case 108: return 187;
00224 case 109: return 188;
00225 case 68: return 191;
00226 case 69: return 192;
00227 case 46: return 193;
00228 case 47: return 194;
00229
00230 case 181: return 195;
00231 case 182: return 33;
00232 case 183: return 34;
00233 case 184: return 35;
00234 case 189: return 40;
00235 case 190: return 41;
00236 case 185: return 36;
00237 case 186: return 37;
00238 case 187: return 38;
00239 case 188: return 39;
00240 case 191: return 42;
00241 case 192: return 43;
00242 case 193: return 44;
00243 case 194: return 45;
00244 }
00245 return 0;
00246 }
00247
00248 CMArtwork::CMArtwork( SymbolType t )
00249 : Artwork( t ), cmChar( -1 )
00250 {
00251 }
00252
00253
00254 void CMArtwork::calcSizes( const ContextStyle& style,
00255 ContextStyle::TextStyle tstyle,
00256 luPt parentSize )
00257 {
00258 setBaseline( -1 );
00259 cmChar = -1;
00260 luPt mySize = style.getAdjustedSize( tstyle );
00261 switch (getType()) {
00262 case LeftSquareBracket:
00263 if ( calcCMDelimiterSize( style, cmex_LeftSquareBracket,
00264 mySize, parentSize ) ) {
00265 return;
00266 }
00267 calcRoundBracket( style, leftSquareBracket, parentSize, mySize );
00268 break;
00269 case RightSquareBracket:
00270 if ( calcCMDelimiterSize( style, cmex_RightSquareBracket,
00271 mySize, parentSize ) ) {
00272 return;
00273 }
00274 calcRoundBracket( style, rightSquareBracket, parentSize, mySize );
00275 break;
00276 case LeftLineBracket:
00277 calcRoundBracket( style, leftLineBracket, parentSize, mySize );
00278 setWidth( getWidth()/2 );
00279 break;
00280 case RightLineBracket:
00281 calcRoundBracket( style, rightLineBracket, parentSize, mySize );
00282 setWidth( getWidth()/2 );
00283 break;
00284 case SlashBracket:
00285 if ( calcCMDelimiterSize( style, cmex_SlashBracket,
00286 mySize, parentSize ) ) {
00287 return;
00288 }
00289 calcLargest( style, cmex_SlashBracket, mySize );
00290 break;
00291 case BackSlashBracket:
00292 if ( calcCMDelimiterSize( style, cmex_BackSlashBracket,
00293 mySize, parentSize ) ) {
00294 return;
00295 }
00296 calcLargest( style, cmex_BackSlashBracket, mySize );
00297 break;
00298 case LeftCornerBracket:
00299 if ( calcCMDelimiterSize( style, cmex_LeftCornerBracket,
00300 mySize, parentSize ) ) {
00301 return;
00302 }
00303 calcLargest( style, cmex_LeftCornerBracket, mySize );
00304 break;
00305 case RightCornerBracket:
00306 if ( calcCMDelimiterSize( style, cmex_RightCornerBracket,
00307 mySize, parentSize ) ) {
00308 return;
00309 }
00310 calcLargest( style, cmex_RightCornerBracket, mySize );
00311 break;
00312 case LeftRoundBracket:
00313 if ( calcCMDelimiterSize( style, cmex_LeftRoundBracket,
00314 mySize, parentSize ) ) {
00315 return;
00316 }
00317 calcRoundBracket( style, leftRoundBracket, parentSize, mySize );
00318 break;
00319 case RightRoundBracket:
00320 if ( calcCMDelimiterSize( style, cmex_RightRoundBracket,
00321 mySize, parentSize ) ) {
00322 return;
00323 }
00324 calcRoundBracket( style, rightRoundBracket, parentSize, mySize );
00325 break;
00326 case EmptyBracket:
00327 setHeight(parentSize);
00328
00329 setWidth(0);
00330 break;
00331 case LeftCurlyBracket:
00332 if ( calcCMDelimiterSize( style, cmex_LeftCurlyBracket,
00333 mySize, parentSize ) ) {
00334 return;
00335 }
00336 calcCurlyBracket( style, leftCurlyBracket, parentSize, mySize );
00337 break;
00338 case RightCurlyBracket:
00339 if ( calcCMDelimiterSize( style, cmex_RightCurlyBracket,
00340 mySize, parentSize ) ) {
00341 return;
00342 }
00343 calcCurlyBracket( style, rightCurlyBracket, parentSize, mySize );
00344 break;
00345 case Integral:
00346 calcCharSize( style, QFont( "cmex10" ), mySize, cmex_Int );
00347 break;
00348 case Sum:
00349 calcCharSize( style, QFont( "cmex10" ), mySize, cmex_Sum );
00350 break;
00351 case Product:
00352 calcCharSize( style, QFont( "cmex10" ), mySize, cmex_Prod );
00353 break;
00354 }
00355 }
00356
00357
00358 void CMArtwork::calcSizes( const ContextStyle& style,
00359 ContextStyle::TextStyle tstyle )
00360 {
00361 luPt mySize = style.getAdjustedSize( tstyle );
00362 switch (getType()) {
00363 case LeftLineBracket:
00364 case RightLineBracket:
00365 calcCharSize(style, mySize, 0x2223);
00366 break;
00367 default:
00368 Artwork::calcSizes( style, tstyle );
00369 break;
00370 }
00371 }
00372
00373
00374 void CMArtwork::draw( QPainter& painter, const LuPixelRect& r,
00375 const ContextStyle& style,
00376 ContextStyle::TextStyle tstyle,
00377 const LuPixelPoint& parentOrigin )
00378 {
00379 luPt mySize = style.getAdjustedSize( tstyle );
00380 luPixel myX = parentOrigin.x() + getX();
00381 luPixel myY = parentOrigin.y() + getY();
00382
00383
00384
00385
00386
00387 painter.setPen(style.getDefaultColor());
00388
00389 switch (getType()) {
00390 case LeftLineBracket:
00391 case RightLineBracket:
00392 drawCharacter(painter, style, myX, myY, mySize, 0x2223);
00393 break;
00394 default:
00395 Artwork::draw( painter, r, style, tstyle, parentOrigin );
00396 break;
00397 }
00398 }
00399
00400
00401 void CMArtwork::draw(QPainter& painter, const LuPixelRect& ,
00402 const ContextStyle& style, ContextStyle::TextStyle tstyle,
00403 luPt , const LuPixelPoint& origin)
00404 {
00405 luPt mySize = style.getAdjustedSize( tstyle );
00406 luPixel myX = origin.x() + getX();
00407 luPixel myY = origin.y() + getY();
00408
00409
00410
00411
00412
00413 painter.setPen(style.getDefaultColor());
00414
00415 switch (getType()) {
00416 case LeftSquareBracket:
00417 if ( cmChar != -1 ) {
00418 drawCMDelimiter( painter, style, myX, myY, mySize );
00419 }
00420 else {
00421 drawBigRoundBracket( painter, style, leftSquareBracket, myX, myY, mySize );
00422 }
00423 break;
00424 case RightSquareBracket:
00425 if ( cmChar != -1 ) {
00426 drawCMDelimiter( painter, style, myX, myY, mySize );
00427 }
00428 else {
00429 drawBigRoundBracket( painter, style, rightSquareBracket, myX, myY, mySize );
00430 }
00431 break;
00432 case LeftCurlyBracket:
00433 if ( cmChar != -1 ) {
00434 drawCMDelimiter( painter, style, myX, myY, mySize );
00435 }
00436 else {
00437 drawBigCurlyBracket( painter, style, leftCurlyBracket, myX, myY, mySize );
00438 }
00439 break;
00440 case RightCurlyBracket:
00441 if ( cmChar != -1 ) {
00442 drawCMDelimiter( painter, style, myX, myY, mySize );
00443 }
00444 else {
00445 drawBigCurlyBracket( painter, style, rightCurlyBracket, myX, myY, mySize );
00446 }
00447 break;
00448 case LeftLineBracket: {
00449 luPixel halfWidth = getWidth()/2;
00450 drawBigRoundBracket( painter, style, leftLineBracket,
00451 myX-halfWidth, myY, mySize );
00452 }
00453 break;
00454 case RightLineBracket: {
00455 luPixel halfWidth = getWidth()/2;
00456 drawBigRoundBracket( painter, style, rightLineBracket,
00457 myX-halfWidth, myY, mySize );
00458 }
00459 break;
00460 case SlashBracket:
00461 if ( cmChar != -1 ) {
00462 drawCMDelimiter( painter, style, myX, myY, mySize );
00463 }
00464 break;
00465 case BackSlashBracket:
00466 if ( cmChar != -1 ) {
00467 drawCMDelimiter( painter, style, myX, myY, mySize );
00468 }
00469 break;
00470 case LeftCornerBracket:
00471 if ( cmChar != -1 ) {
00472 drawCMDelimiter( painter, style, myX, myY, mySize );
00473 }
00474 else drawCharacter(painter, style, myX, myY, mySize, leftAngleBracketChar);
00475 break;
00476 case RightCornerBracket:
00477 if ( cmChar != -1 ) {
00478 drawCMDelimiter( painter, style, myX, myY, mySize );
00479 }
00480 else drawCharacter(painter, style, myX, myY, mySize, rightAngleBracketChar);
00481 break;
00482 case LeftRoundBracket:
00483 if ( cmChar != -1 ) {
00484 drawCMDelimiter( painter, style, myX, myY, mySize );
00485 }
00486 else {
00487 drawBigRoundBracket( painter, style, leftRoundBracket, myX, myY, mySize );
00488 }
00489 break;
00490 case RightRoundBracket:
00491 if ( cmChar != -1 ) {
00492 drawCMDelimiter( painter, style, myX, myY, mySize );
00493 }
00494 else {
00495 drawBigRoundBracket( painter, style, rightRoundBracket, myX, myY, mySize );
00496 }
00497 break;
00498 case EmptyBracket:
00499 break;
00500 case Integral:
00501 drawCharacter(painter, style, QFont( "cmex10" ), myX, myY, mySize, cmex_Int);
00502 break;
00503 case Sum:
00504 drawCharacter(painter, style, QFont( "cmex10" ), myX, myY, mySize, cmex_Sum);
00505 break;
00506 case Product:
00507 drawCharacter(painter, style, QFont( "cmex10" ), myX, myY, mySize, cmex_Prod);
00508 break;
00509 }
00510
00511
00512
00513
00514
00515
00516
00517
00518 }
00519
00520
00521 bool CMArtwork::isNormalChar() const
00522 {
00523 return Artwork::isNormalChar() && ( cmChar == -1 );
00524 }
00525
00526 double CMArtwork::slant() const
00527 {
00528 if ( getType() == Integral ) {
00529 return 0.25;
00530 }
00531 return 0;
00532 }
00533
00534 bool CMArtwork::calcCMDelimiterSize( const ContextStyle& context,
00535 uchar c,
00536 luPt fontSize,
00537 luPt parentSize )
00538 {
00539 QFont f( "cmex10" );
00540 f.setPointSizeF( context.layoutUnitPtToPt( fontSize ) );
00541 QFontMetrics fm( f );
00542
00543 for ( char i=1; c != 0; ++i ) {
00544 LuPixelRect bound = fm.boundingRect( c );
00545
00546 luPt height = context.ptToLayoutUnitPt( bound.height() );
00547 if ( height >= parentSize ) {
00548 luPt width = context.ptToLayoutUnitPt( fm.width( c ) );
00549 luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
00550
00551 cmChar = c;
00552
00553 setHeight( height );
00554 setWidth( width );
00555 setBaseline( baseline );
00556
00557 return true;
00558 }
00559 c = cmex_nextchar( c );
00560 }
00561
00562
00563 return false;
00564 }
00565
00566
00567 void CMArtwork::calcLargest( const ContextStyle& context,
00568 uchar c, luPt fontSize )
00569 {
00570 QFont f( "cmex10" );
00571 f.setPointSizeF( context.layoutUnitPtToPt( fontSize ) );
00572 QFontMetrics fm( f );
00573
00574 cmChar = c;
00575 for ( ;; ) {
00576 c = cmex_nextchar( c );
00577 if ( c == 0 ) {
00578 break;
00579 }
00580 cmChar = c;
00581 }
00582
00583 LuPixelRect bound = fm.boundingRect( cmChar );
00584
00585 luPt height = context.ptToLayoutUnitPt( bound.height() );
00586 luPt width = context.ptToLayoutUnitPt( fm.width( cmChar ) );
00587 luPt baseline = context.ptToLayoutUnitPt( -bound.top() );
00588
00589 setHeight( height );
00590 setWidth( width );
00591 setBaseline( baseline );
00592 }
00593
00594
00595 void CMArtwork::drawCMDelimiter( QPainter& painter, const ContextStyle& style,
00596 luPixel x, luPixel y,
00597 luPt height )
00598 {
00599 QFont f( "cmex10" );
00600 f.setPointSizeF( style.layoutUnitToFontSize( height, false ) );
00601
00602 painter.setFont( f );
00603 painter.drawText( style.layoutUnitToPixelX( x ),
00604 style.layoutUnitToPixelY( y + getBaseline() ),
00605 QString( QChar( cmChar ) ) );
00606
00607
00608 #if 0
00609 QFontMetrics fm( f );
00610 LuPixelRect bound = fm.boundingRect( cmChar );
00611 painter.setBrush(Qt::NoBrush);
00612 painter.setPen(Qt::green);
00613 painter.drawRect( style.layoutUnitToPixelX( x ),
00614 style.layoutUnitToPixelY( y ),
00615 fm.width( cmChar ),
00616 bound.height() );
00617 #endif
00618 }
00619
00620
00621 KFORMULA_NAMESPACE_END