F:/KPlato/koffice/libs/kformula/cmstyle.cc

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
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 /*style*/ ) const
00126 {
00127     /*
00128     static short uppercase_greek[] = {
00129         0x0393, // Gamma
00130         0x0394, // Delta
00131         0x0398, // Theta
00132         0x039B, // Lambda
00133         0x039E, // Xi
00134         0x03A0, // Pi
00135         0x03A3, // Sigma
00136         0x03A6, // Phi
00137         0x03A8, // Psi
00138         0x03A9, // Omega
00139         0x03D2, // Upsilon
00140         0
00141     };
00142     */
00143 
00144     AlphaTableEntry entry;
00145     switch( family ) {
00146         //case normal:
00147     case scriptFamily:
00148         /*
00149         for ( int i=0; uppercase_greek[i] != 0; ++i ) {
00150             if ( pos == uppercase_greek[i] ) {
00151                 entry.pos = pos;
00152                 entry.font = QFont( "cmsl10" );
00153                 return;
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 //static const char cmex_LeftLineBracket = 0x4b;
00188 //static const char cmex_RightLineBracket = 0x4b;
00189 
00190 // use the big symbols here
00191 static const char cmex_Int = 90;
00192 static const char cmex_Sum = 88;
00193 static const char cmex_Prod = 89;
00194 
00195 
00196 // cmex is a special font with symbols in four sizes.
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         //setWidth(style.getEmptyRectWidth());
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     if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
00384         return;
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& /*r*/,
00402                      const ContextStyle& style, ContextStyle::TextStyle tstyle,
00403                      luPt /*parentSize*/, const LuPixelPoint& origin)
00404 {
00405     luPt mySize = style.getAdjustedSize( tstyle );
00406     luPixel myX = origin.x() + getX();
00407     luPixel myY = origin.y() + getY();
00408     /*
00409     if ( !LuPixelRect( myX, myY, getWidth(), getHeight() ).intersects( r ) )
00410         return;
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     // debug
00512 //     painter.setBrush(Qt::NoBrush);
00513 //     painter.setPen(Qt::green);
00514 //     painter.drawRect( style.layoutUnitToPixelX( myX ),
00515 //                       style.layoutUnitToPixelY( myY ),
00516 //                       style.layoutUnitToPixelX( getWidth() ),
00517 //                       style.layoutUnitToPixelY( getHeight() ) );
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     // Build it up from pieces.
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     // Debug
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

Généré le Wed Nov 22 23:41:00 2006 pour KPlato par  doxygen 1.5.1-p1