F:/KPlato/koffice/libs/kotext/KoTextFormat.cpp

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2001-2006 David Faure <faure@kde.org>
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 "KoTextFormat.h"
00021 #include "KoTextParag.h"
00022 #include "KoTextZoomHandler.h"
00023 #include "KoStyleCollection.h"
00024 #include "KoOasisContext.h"
00025 #include <KoGenStyles.h>
00026 #include <KoXmlNS.h>
00027 #include <KoGlobal.h>
00028 #include <KoUnit.h>
00029 
00030 #include <kglobal.h>
00031 #include <kdebug.h>
00032 #include <klocale.h>
00033 
00034 #include <QApplication>
00035 #include <QRegExp>
00036 #include <assert.h>
00037 
00038 void KoTextFormat::KoTextFormatPrivate::clearCache()
00039 {
00040     delete m_screenFontMetrics; m_screenFontMetrics = 0L;
00041     delete m_screenFont; m_screenFont = 0L;
00042     delete m_refFontMetrics; m_refFontMetrics = 0L;
00043     delete m_refFont; m_refFont = 0L;
00044     m_refAscent = -1;
00045     m_refDescent = -1;
00046     m_refHeight = -1;
00047     memset( m_screenWidths, 0, 256 * sizeof( ushort ) );
00048 }
00049 
00050 void KoTextFormat::zoomChanged()
00051 {
00052     delete d->m_screenFontMetrics; d->m_screenFontMetrics = 0;
00053     delete d->m_screenFont; d->m_screenFont = 0;
00054     memset( d->m_screenWidths, 0, 256 * sizeof( ushort ) );
00055 }
00056 
00057 KoTextFormat::KoTextFormat()
00058 {
00059     //linkColor = true;
00060     ref = 0;
00061     missp = false;
00062     va = AlignNormal;
00063     collection = 0;
00065     fn.setStyleStrategy( QFont::ForceOutline );
00066     d = new KoTextFormatPrivate;
00067     m_textUnderlineColor=QColor();
00068     m_underlineType = U_NONE;
00069     m_strikeOutType = S_NONE;
00070     m_underlineStyle = U_SOLID;
00071     m_strikeOutStyle = S_SOLID;
00072     m_language = KGlobal::locale()->language();
00073     d->m_bHyphenation = false;
00074     d->m_underLineWidth = 1.0;
00075     d->m_shadowDistanceX = 0;
00076     d->m_shadowDistanceY = 0;
00077     d->m_relativeTextSize = 0.66;
00078     d->m_offsetFromBaseLine= 0;
00079     d->m_bWordByWord = false;
00080     m_attributeFont = ATT_NONE;
00082 //#ifdef DEBUG_COLLECTION
00083 //    kDebug(32500) << "KoTextFormat simple ctor, no addRef, no generateKey ! " << this << endl;
00084 //#endif
00085 }
00086 
00087 KoTextFormat::KoTextFormat( const QFont &f, const QColor &c, const QString &_language, bool hyphenation, KoTextFormatCollection *parent )
00088     : fn( f ), col( c ) /*fm( QFontMetrics( f ) ),*/ //linkColor( true )
00089 {
00090 #ifdef DEBUG_COLLECTION
00091     kDebug(32500) << "KoTextFormat with font & color & parent (" << parent << "), addRef. " << this << endl;
00092 #endif
00093     int pointSize;
00094     if ( f.pointSize() == -1 ) // font was set with a pixelsize, we need a pointsize!
00095         pointSize = (int)( ( (double)fn.pixelSize() * 72.0 ) / (double)KoGlobal::dpiY() );
00096     else
00097         pointSize = f.pointSize();
00098     fn.setPointSize( pointSize );
00099     // WYSIWYG works much much better with scalable fonts -> force it to be scalable
00100     fn.setStyleStrategy( QFont::ForceOutline );
00101     ref = 0;
00102     collection = parent;
00103     //leftBearing = fm.minLeftBearing();
00104     //rightBearing = fm.minRightBearing();
00105     //hei = fm.height();
00106     //asc = fm.ascent();
00107     //dsc = fm.descent();
00108     missp = false;
00109     va = AlignNormal;
00111     d = new KoTextFormatPrivate;
00112     m_textUnderlineColor = QColor();
00113     m_underlineType = U_NONE;
00114     m_strikeOutType = S_NONE;
00115     m_underlineStyle = U_SOLID;
00116     m_strikeOutStyle = S_SOLID;
00117     m_language = _language;
00118     d->m_shadowDistanceX = 0;
00119     d->m_shadowDistanceY = 0;
00120     d->m_relativeTextSize= 0.66;
00121     d->m_offsetFromBaseLine = 0;
00122     d->m_bWordByWord = false;
00123     d->m_charStyle = 0L;
00124     d->m_bHyphenation = hyphenation;
00125     d->m_underLineWidth = 1.0;
00126     m_attributeFont = ATT_NONE;
00128     generateKey();
00129     addRef();
00130 }
00131 
00132 KoTextFormat::KoTextFormat( const QFont &_font,
00133                             VerticalAlignment _valign,
00134                             const QColor & _color,
00135                             const QColor & _backGroundColor,
00136                             const QColor & _underlineColor,
00137                             KoTextFormat::UnderlineType _underlineType,
00138                             KoTextFormat::UnderlineStyle _underlineStyle,
00139                             KoTextFormat::StrikeOutType _strikeOutType,
00140                             KoTextFormat::StrikeOutStyle _strikeOutStyle,
00141                             KoTextFormat::AttributeStyle _fontAttribute,
00142                             const QString &_language,
00143                             double _relativeTextSize,
00144                             int _offsetFromBaseLine,
00145                             bool _wordByWord,
00146                             bool _hyphenation,
00147                             double _shadowDistanceX,
00148                             double _shadowDistanceY,
00149                             const QColor& _shadowColor )
00150 {
00151     ref = 0;
00152     collection = 0;
00153     fn = _font;
00154     fn.setStyleStrategy( QFont::ForceOutline );
00155     col = _color;
00156     missp = false;
00157     va = _valign;
00158     d = new KoTextFormatPrivate;
00159     m_textBackColor = _backGroundColor;
00160     m_textUnderlineColor = _underlineColor;
00161     m_underlineType = _underlineType;
00162     m_strikeOutType = _strikeOutType;
00163     m_underlineStyle = _underlineStyle;
00164     m_strikeOutStyle = _strikeOutStyle;
00165     m_language = _language;
00166     d->m_bHyphenation = _hyphenation;
00167     d->m_underLineWidth = 1.0;
00168     d->m_shadowDistanceX = _shadowDistanceX;
00169     d->m_shadowDistanceY = _shadowDistanceY;
00170     d->m_shadowColor = _shadowColor;
00171     d->m_relativeTextSize = _relativeTextSize;
00172     d->m_offsetFromBaseLine = _offsetFromBaseLine;
00173     d->m_bWordByWord = _wordByWord;
00174     m_attributeFont = _fontAttribute;
00175     d->m_charStyle = 0L;
00177     generateKey();
00178     addRef();
00179 }
00180 
00181 KoTextFormat::KoTextFormat( const KoTextFormat &f )
00182 {
00183     d = 0L;
00184     operator=( f );
00185 }
00186 
00187 KoTextFormat::~KoTextFormat()
00188 {
00190     // Removing a format that is in the collection is forbidden, in fact.
00191     // It should have been removed from the collection before being deleted.
00192 #ifndef NDEBUG
00193     if ( parent() && parent()->defaultFormat() ) // not when destroying the collection
00194         assert( ! ( parent()->dict().find( key() ) == this ) );
00195         // (has to be the same pointer, not only the same key)
00196 #endif
00197     delete d;
00199 }
00200 
00201 KoTextFormat& KoTextFormat::operator=( const KoTextFormat &f )
00202 {
00203 #ifdef DEBUG_COLLECTION
00204     kDebug(32500) << "KoTextFormat::operator= " << this << " (copying " << &f << "). Will addRef" << endl;
00205 #endif
00206     ref = 0;
00207     collection = 0; // f might be in the collection, but we are not
00208     fn = f.fn;
00209     col = f.col;
00210     //fm = f.fm;
00211     //leftBearing = f.leftBearing;
00212     //rightBearing = f.rightBearing;
00213     //hei = f.hei;
00214     //asc = f.asc;
00215     //dsc = f.dsc;
00216     missp = f.missp;
00217     va = f.va;
00218     m_key = f.m_key;
00219     //linkColor = f.linkColor;
00221     delete d;
00222     d = new KoTextFormatPrivate;
00223     m_textBackColor=f.m_textBackColor;
00224     m_textUnderlineColor=f.m_textUnderlineColor;
00225     m_underlineType = f.m_underlineType;
00226     m_strikeOutType = f.m_strikeOutType;
00227     m_underlineStyle = f.m_underlineStyle;
00228     m_strikeOutStyle = f.m_strikeOutStyle;
00229     m_language = f.m_language;
00230     d->m_bHyphenation=f.d->m_bHyphenation;
00231     d->m_underLineWidth=f.d->m_underLineWidth;
00232     d->m_shadowDistanceX = f.d->m_shadowDistanceX;
00233     d->m_shadowDistanceY = f.d->m_shadowDistanceY;
00234     d->m_shadowColor = f.d->m_shadowColor;
00235     d->m_relativeTextSize = f.d->m_relativeTextSize;
00236     d->m_offsetFromBaseLine = f.d->m_offsetFromBaseLine;
00237     d->m_bWordByWord = f.d->m_bWordByWord;
00238     m_attributeFont = f.m_attributeFont;
00239     d->m_charStyle = 0L;
00241     addRef();
00242     return *this;
00243 }
00244 
00245 // Helper for load
00246 static void importTextPosition( const QString& text_position, double fontSize, KoTextFormat::VerticalAlignment& value, double& relativetextsize, int& offset, KoOasisContext& context )
00247 {
00248     //OO: <vertical position (% or sub or super)> [<size as %>]
00249     //Examples: "super" or "super 58%" or "82% 58%" (where 82% is the vertical position)
00250     QStringList lst = QStringList::split( ' ', text_position );
00251     if ( !lst.isEmpty() )
00252     {
00253         QString textPos = lst.front().trimmed();
00254         QString textSize;
00255         lst.pop_front();
00256         if ( !lst.isEmpty() )
00257             textSize = lst.front().trimmed();
00258         // Workaround bug in KOffice-1.4: it saved '0% 66%' for normal text
00259         if ( context.generator().startsWith( "KOffice/1.4" )
00260              && text_position.startsWith( "0%" ) ) {
00261             //kDebug(32500) << "Detected koffice-1.4 bug in text-position, assuming Normal text" << endl;
00262             value = KoTextFormat::AlignNormal;
00263             return;
00264         }
00265 
00266         if ( textPos.endsWith("%") && textPos != "0% 100%" && textPos != "0%" )
00267         {
00268             textPos.truncate( textPos.length() - 1 );
00269             double val = textPos.toDouble();
00270             offset = qRound( fontSize * val / 100.0 );
00271             value = KoTextFormat::AlignCustom;
00272         }
00273         else if ( textPos == "super" )
00274             value = KoTextFormat::AlignSuperScript;
00275         else if ( textPos == "sub" )
00276             value = KoTextFormat::AlignSubScript;
00277         else
00278             value = KoTextFormat::AlignNormal;
00279         if ( !textSize.isEmpty() && textSize.endsWith("%") )
00280         {
00281             textSize.truncate( textSize.length() - 1 );
00282             relativetextsize = textSize.toDouble() / 100; // e.g. 0.58
00283         }
00284     }
00285     else
00286         value = KoTextFormat::AlignNormal;
00287 }
00288 
00289 // OASIS 14.2.29
00290 static void importOasisUnderline( const QString& type, const QString& style,
00291                                   KoTextFormat::UnderlineType& underline,
00292                                   KoTextFormat::UnderlineStyle& styleline )
00293 {
00294   if ( type == "single" )
00295       underline = KoTextFormat::U_SIMPLE;
00296   else if ( type == "double" )
00297       underline = KoTextFormat::U_DOUBLE;
00298   else if ( type == "none" )
00299       underline = KoTextFormat::U_NONE;
00300   else if ( style.isEmpty() || style == "none" )
00301       underline = KoTextFormat::U_NONE;
00302   else
00303       underline = KoTextFormat::U_SIMPLE; // OO exports empty type, and style=solid, for normal underline
00304 
00305   styleline = KoTextFormat::U_SOLID; // assume "solid" if unknown
00306   if ( style == "dotted" )
00307       styleline = KoTextFormat::U_DOT;
00308   else if ( style == "dash"
00309             || style == "long-dash" ) // not in kotext
00310       styleline = KoTextFormat::U_DASH;
00311   else if ( style == "dot-dash" )
00312       styleline = KoTextFormat::U_DASH_DOT;
00313   else if ( style == "dot-dot-dash" )
00314       styleline = KoTextFormat::U_DASH_DOT_DOT;
00315   else if ( style == "wave" )
00316       underline = KoTextFormat::U_WAVE;
00317 
00318   // TODO bold. But this is another attribute in OASIS (text-underline-width), which makes sense.
00319   // We should separate them in kotext...
00320 }
00321 
00322 QString exportOasisUnderline( KoTextFormat::UnderlineStyle styleline )
00323 {
00324     switch( styleline ) {
00325     case KoTextFormat::U_DOT:
00326         return "dotted";
00327     case KoTextFormat::U_DASH:
00328         return "dash";
00329     case KoTextFormat::U_DASH_DOT:
00330         return "dot-dash";
00331     case KoTextFormat::U_DASH_DOT_DOT:
00332         return "dot-dot-dash";
00333     default:
00334         return "solid";
00335     }
00336 }
00337 
00338 // Helper for load. Legacy OO format.
00339 static void importUnderline( const QString& in,
00340                              KoTextFormat::UnderlineType& underline,
00341                              KoTextFormat::UnderlineStyle& styleline )
00342 {
00343     underline = KoTextFormat::U_SIMPLE;
00344     styleline = KoTextFormat::U_SOLID;
00345     if ( in == "none" )
00346         underline = KoTextFormat::U_NONE;
00347     else if ( in == "single" )
00348         styleline = KoTextFormat::U_SOLID;
00349     else if ( in == "double" ) {
00350         underline = KoTextFormat::U_DOUBLE;
00351     }
00352     else if ( in == "dotted" || in == "bold-dotted" ) // bold-dotted not in libkotext
00353         styleline = KoTextFormat::U_DOT;
00354     else if ( in == "dash"
00355               // those are not in libkotext:
00356               || in == "long-dash"
00357               || in == "bold-dash"
00358               || in == "bold-long-dash" )
00359         styleline = KoTextFormat::U_DASH;
00360     else if ( in == "dot-dash"
00361               || in == "bold-dot-dash") // not in libkotext
00362         styleline = KoTextFormat::U_DASH_DOT; // tricky ;)
00363     else if ( in == "dot-dot-dash"
00364               || in == "bold-dot-dot-dash") // not in libkotext
00365         styleline = KoTextFormat::U_DASH_DOT_DOT; // this is getting fun...
00366     else if ( in == "wave"
00367               || in == "bold-wave" // not in libkotext
00368               || in == "double-wave" // not in libkotext
00369               || in == "small-wave" ) { // not in libkotext
00370         underline = KoTextFormat::U_WAVE;
00371     } else if( in == "bold" ) {
00372         underline = KoTextFormat::U_SIMPLE_BOLD;
00373     } else
00374         kWarning() << k_funcinfo << " unsupported text-underline value: " << in << endl;
00375 }
00376 
00377 void KoTextFormat::load( KoOasisContext& context )
00378 {
00379     KoStyleStack& styleStack = context.styleStack();
00380     styleStack.setTypeProperties( "text" ); // load all style attributes from "style:text-properties"
00381 
00382     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "color" ) ) { // 3.10.3
00383         col.setNamedColor( styleStack.attributeNS( KoXmlNS::fo, "color" ) ); // #rrggbb format
00384     }
00385     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-family" )  // 3.10.9
00386          || styleStack.hasAttributeNS( KoXmlNS::style, "font-name") ) { // 3.10.8
00387         // Hmm, the remove "'" could break it's in the middle of the fontname...
00388         QString fontName = styleStack.attributeNS( KoXmlNS::fo, "font-family" ).remove( "'" );
00389         if (fontName.isEmpty()) {
00390             // ##### TODO. This is wrong. style:font-name refers to a font-decl entry.
00391             // We have to look it up there, and retrieve _all_ font attributes from it, not just the name.
00392             fontName = styleStack.attributeNS( KoXmlNS::style, "font-name" ).remove( "'" );
00393         }
00394         // 'Thorndale' is not known outside OpenOffice so we substitute it
00395         // with 'Times New Roman' that looks nearly the same.
00396         if ( fontName == "Thorndale" )
00397             fontName = "Times New Roman";
00398 
00399         fontName.remove(QRegExp("\\sCE$")); // Arial CE -> Arial
00400         fn.setFamily( fontName );
00401     }
00402     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-size" ) ) { // 3.10.14
00403         double pointSize = styleStack.fontSize();
00404         fn.setPointSizeF( pointSize );
00405     }
00406     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-weight" ) ) { // 3.10.24
00407         QString fontWeight = styleStack.attributeNS( KoXmlNS::fo, "font-weight" );
00408         int boldness;
00409         if ( fontWeight == "normal" )
00410             boldness = 50;
00411         else if ( fontWeight == "bold" )
00412             boldness = 75;
00413         else
00414             // XSL/CSS has 100,200,300...900. Not the same scale as Qt!
00415             // See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
00416             boldness = fontWeight.toInt() / 10;
00417         fn.setWeight( boldness );
00418     }
00419     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-style" ) ) // 3.10.19
00420         if ( styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "italic" ||
00421              styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "oblique" ) { // no difference in kotext
00422             fn.setItalic( true );
00423         }
00424 
00425     d->m_bWordByWord = styleStack.attributeNS( KoXmlNS::style, "text-underline-mode" ) == "skip-white-space";
00426     // TODO style:text-line-through-mode
00427 
00428 #if 0 // OO compat code, to move to OO import filter
00429     d->m_bWordByWord = (styleStack.hasAttributeNS( KoXmlNS::fo, "score-spaces")) // 3.10.25
00430                       && (styleStack.attributeNS( KoXmlNS::fo, "score-spaces") == "false");
00431     if( styleStack.hasAttributeNS( KoXmlNS::style, "text-crossing-out" )) { // 3.10.6
00432         QString strikeOutType = styleStack.attributeNS( KoXmlNS::style, "text-crossing-out" );
00433         if( strikeOutType =="double-line")
00434             m_strikeOutType = S_DOUBLE;
00435         else if( strikeOutType =="single-line")
00436             m_strikeOutType = S_SIMPLE;
00437         else if( strikeOutType =="thick-line")
00438             m_strikeOutType = S_SIMPLE_BOLD;
00439         // not supported by KWord: "slash" and "X"
00440         // not supported by OO: stylelines (solid, dash, dot, dashdot, dashdotdot)
00441     }
00442 #endif
00443     if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-underline-type" )
00444         || styleStack.hasAttributeNS( KoXmlNS::style, "text-underline-style" ) ) { // OASIS 14.4.28
00445         importOasisUnderline( styleStack.attributeNS( KoXmlNS::style, "text-underline-type" ),
00446                               styleStack.attributeNS( KoXmlNS::style, "text-underline-style" ),
00447                               m_underlineType, m_underlineStyle );
00448     }
00449     else if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-underline" ) ) { // OO compat (3.10.22), to be moved out
00450         importUnderline( styleStack.attributeNS( KoXmlNS::style, "text-underline" ),
00451                          m_underlineType, m_underlineStyle );
00452     }
00453     QString underLineColor = styleStack.attributeNS( KoXmlNS::style, "text-underline-color" ); // OO 3.10.23, OASIS 14.4.31
00454     if ( !underLineColor.isEmpty() && underLineColor != "font-color" )
00455         m_textUnderlineColor.setNamedColor( underLineColor );
00456 
00457     if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-line-through-type" ) ) { // OASIS 14.4.7
00458         // Reuse code for loading underlines, and convert to strikeout enum (if not wave)
00459         UnderlineType uType; UnderlineStyle uStyle;
00460         importOasisUnderline( styleStack.attributeNS( KoXmlNS::style, "text-line-through-type" ),
00461                               styleStack.attributeNS( KoXmlNS::style, "text-line-through-style" ),
00462                               uType, uStyle );
00463         m_strikeOutType = S_NONE;
00464         if ( uType != U_WAVE )
00465             m_strikeOutType = (StrikeOutType)uType;
00466         m_strikeOutStyle = (StrikeOutStyle)uStyle;
00467     }
00468 
00469     // Text position
00470     va = AlignNormal;
00471     d->m_relativeTextSize = 0.58;
00472     d->m_offsetFromBaseLine = 0;
00473     if( styleStack.hasAttributeNS( KoXmlNS::style, "text-position")) { // OO 3.10.7
00474         importTextPosition( styleStack.attributeNS( KoXmlNS::style, "text-position"), fn.pointSizeF(),
00475                             va, d->m_relativeTextSize, d->m_offsetFromBaseLine, context );
00476     }
00477     // Small caps, lowercase, uppercase
00478     m_attributeFont = ATT_NONE;
00479     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-variant" ) // 3.10.1
00480          || styleStack.hasAttributeNS( KoXmlNS::fo, "text-transform" ) ) { // 3.10.2
00481         bool smallCaps = styleStack.attributeNS( KoXmlNS::fo, "font-variant" ) == "small-caps";
00482         if ( smallCaps ) {
00483             m_attributeFont = ATT_SMALL_CAPS;
00484         } else {
00485             QString textTransform = styleStack.attributeNS( KoXmlNS::fo, "text-transform" );
00486             if ( textTransform == "uppercase" )
00487                 m_attributeFont = ATT_UPPER;
00488             else if ( textTransform == "lowercase" )
00489                 m_attributeFont = ATT_LOWER;
00490             // TODO in KWord: "capitalize".
00491         }
00492     }
00493     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "language") ) { // 3.10.17
00494         m_language = styleStack.attributeNS( KoXmlNS::fo, "language");
00495         const QString country = styleStack.attributeNS( KoXmlNS::fo, "country" );
00496         if ( !country.isEmpty() ) {
00497             m_language += '_';
00498             m_language += country;
00499         }
00500     }
00501     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color") ) {
00502         QString tmp = styleStack.attributeNS( KoXmlNS::fo, "background-color");
00503         if (tmp != "transparent")
00504             m_textBackColor.setNamedColor( tmp );
00505     }
00506     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "text-shadow") ) { // 3.10.21
00507         parseShadowFromCss( styleStack.attributeNS( KoXmlNS::fo, "text-shadow") );
00508     }
00509 
00510     d->m_bHyphenation = true;
00511     if ( styleStack.hasAttributeNS( KoXmlNS::fo, "hyphenate" ) ) // it's a character property in OASIS (but not in OO-1.1)
00512         d->m_bHyphenation = styleStack.attributeNS( KoXmlNS::fo, "hyphenate" ) == "true";
00513 
00514     /*
00515       Missing properties:
00516       style:use-window-font-color, 3.10.4 - this is what KWord uses by default (fg color from the color style)
00517          OO also switches to another color when necessary to avoid dark-on-dark and light-on-light cases.
00518          (that is TODO in KWord)
00519       style:text-outline, 3.10.5 - not implemented in kotext
00520       style:font-family-generic, 3.10.10 - roman, swiss, modern -> map to a font?
00521       style:font-style-name, 3.10.11 - can be ignored, says DV, the other ways to specify a font are more precise
00522       style:font-pitch, 3.10.12 - fixed or variable -> map to a font?
00523       style:font-charset, 3.10.14 - not necessary with Qt
00524       style:font-size-rel, 3.10.15 - TODO in StyleStack::fontSize()
00525       fo:letter-spacing, 3.10.16 - not implemented in kotext
00526       style:text-relief, 3.10.20 - not implemented in kotext
00527       style:letter-kerning, 3.10.20 - not implemented in kotext
00528       style:text-blinking, 3.10.27 - not implemented in kotext IIRC
00529       style:text-combine, 3.10.29/30 - not implemented, see http://www.w3.org/TR/WD-i18n-format/
00530       style:text-emphasis, 3.10.31 - not implemented in kotext
00531       style:text-scale, 3.10.33 - not implemented in kotext
00532       style:text-rotation-angle, 3.10.34 - not implemented in kotext (kpr rotates whole objects)
00533       style:text-rotation-scale, 3.10.35 - not implemented in kotext (kpr rotates whole objects)
00534       style:punctuation-wrap, 3.10.36 - not implemented in kotext
00535     */
00536 
00537     d->m_underLineWidth = 1.0;
00538 
00539     generateKey();
00540     addRef();
00541 }
00542 
00543 void KoTextFormat::save( KoGenStyle& gs, KoSavingContext& context, KoTextFormat * refFormat ) const
00544 {
00545     KoGenStyle::PropertyType tt = KoGenStyle::TextType;
00546     if ( !refFormat || this->color() != refFormat->color() )
00547     {
00548         gs.addProperty( "fo:color", col.isValid() ? col.name() : "#000000", tt );
00549     }
00550     if ( !refFormat || this->font().family() != refFormat->font().family() )
00551     {
00552         gs.addProperty( "style:font-name", fn.family(), tt );
00553         context.addFontFace( fn.family() );
00554     }
00555     if ( !refFormat || this->pointSize() != refFormat->pointSize() )
00556     {
00557         gs.addPropertyPt( "fo:font-size", fn.pointSize(), tt );
00558     }
00559     int w = fn.weight();
00560     if ( !refFormat || w != refFormat->font().weight() )
00561     {
00562         gs.addProperty( "fo:font-weight", w == 50 ? "normal" : w == 75 ? "bold" : QString::number( qRound( w / 10 ) * 100 ), tt );
00563     }
00564     if ( !refFormat || this->font().italic() != refFormat->font().italic() )
00565     {
00566         gs.addProperty( "fo:font-style", fn.italic() ? "italic" : "normal", tt );
00567     }
00568     if ( !refFormat || this->wordByWord() != refFormat->wordByWord() )
00569     {
00570         gs.addProperty( "style:text-underline-mode", d->m_bWordByWord ? "skip-white-space" : "continuous", tt );
00571     }
00572     if ( !refFormat || this->underlineType() != refFormat->underlineType()
00573                     || this->underlineStyle() !=refFormat->underlineStyle() )
00574     {
00575         gs.addProperty( "style:text-underline-type", m_underlineType == U_NONE ? "none" :
00576                         m_underlineType == U_DOUBLE ? "double" : "single", tt );
00577         QString styleline;
00578         if ( m_underlineType == U_WAVE )
00579             styleline = "wave";
00580         else
00581             styleline = exportOasisUnderline( m_underlineStyle );
00582         gs.addProperty( "style:text-underline-style", m_underlineType == U_NONE ? "none" : styleline, tt );
00583     }
00584     if ( !refFormat || this->textUnderlineColor() !=refFormat->textUnderlineColor() )
00585     {
00586         gs.addProperty( "style:text-underline-color", m_textUnderlineColor.isValid() ? m_textUnderlineColor.name() : "font-color", tt );
00587     }
00588 
00589     if ( !refFormat
00590         || this->strikeOutType() != refFormat->strikeOutType()
00591         || this->strikeOutStyle()!= refFormat->strikeOutStyle() )
00592     {
00593         if ( m_strikeOutType != S_NONE )
00594         {
00595             // TODO U_SIMPLE_BOLD
00596             // TODO style:text-line-through-mode
00597             gs.addProperty( "style:text-line-through-type", m_strikeOutType == S_DOUBLE ? "double" : "single", tt );
00598             const QString styleline = exportOasisUnderline( (UnderlineStyle) m_strikeOutStyle );
00599             gs.addProperty( "style:text-line-through-style", styleline, tt );
00600             //gs.addProperty( "style:text-line-through-color", ...) TODO in kotext
00601         }
00602         else
00603         {
00604             gs.addProperty( "style:text-line-through-type", "none", tt );
00605             gs.addProperty( "style:text-line-through-style", "none", tt );
00606         }
00607     }
00608     if ( !refFormat || (this->vAlign() != refFormat->vAlign())
00609         || (this->relativeTextSize() != refFormat->relativeTextSize()) )
00610     {
00611         QString textPos;
00612         if ( d->m_offsetFromBaseLine != 0 )
00613             textPos = QString::number( 100 * d->m_offsetFromBaseLine / fn.pointSizeF() ) + '%';
00614         else if ( va == AlignSuperScript ) textPos = "super";
00615         else if ( va == AlignSubScript ) textPos = "sub";
00616         else textPos = "0%"; // AlignNormal
00617         if ( va != AlignNormal )
00618         {
00619             textPos += ' ';
00620             textPos += QString::number( d->m_relativeTextSize * 100 );
00621             textPos += '%';
00622         }
00623         gs.addProperty( "style:text-position", textPos, tt );
00624     }
00625 
00626     if( !refFormat || this->attributeFont() != refFormat->attributeFont())
00627     {
00628         if ( m_attributeFont == ATT_SMALL_CAPS ) {
00629             gs.addProperty( "fo:font-variant", "small-caps", tt );
00630             gs.addProperty( "fo:text-transform", "none", tt );
00631         }
00632         else if ( m_attributeFont == ATT_UPPER ) {
00633             gs.addProperty( "fo:font-variant", "normal", tt );
00634             gs.addProperty( "fo:text-transform", "uppercase", tt );
00635         }
00636         else if ( m_attributeFont == ATT_LOWER ) {
00637             gs.addProperty( "fo:font-variant", "normal", tt );
00638             gs.addProperty( "fo:text-transform", "lowercase", tt );
00639         }
00640         else {
00641             gs.addProperty( "fo:font-variant", "normal", tt );
00642             gs.addProperty( "fo:text-transform", "none", tt );
00643         }
00644     }
00645 
00646     if( !refFormat || this->language() != refFormat->language())
00647     {
00648         QString lang = m_language;
00649         QString country;
00650         const int pos = lang.find( '_' );
00651         if ( pos != -1 ) {
00652             country = lang.mid( pos + 1 );
00653             lang = lang.left( pos );
00654         }
00655 
00656         gs.addProperty( "fo:language", lang, tt );
00657         gs.addProperty( "fo:country", country, tt );
00658     }
00659     if( !refFormat || this->textBackgroundColor() != refFormat->textBackgroundColor() )
00660     {
00661         gs.addProperty( "fo:background-color",
00662                         m_textBackColor.isValid() ? m_textBackColor.name() : "transparent", tt );
00663     }
00664     if( !refFormat ||
00665         ( this->shadowDistanceX() != refFormat->shadowDistanceX()
00666           || ( this->shadowDistanceY() != refFormat->shadowDistanceY() )
00667           || ( this->shadowColor() != refFormat->shadowColor() ) ) )
00668     {
00669         gs.addProperty( "fo:text-shadow", shadowAsCss(), tt );
00670     }
00671     if ( !refFormat || this->hyphenation() != refFormat->hyphenation() )
00672     {
00673         gs.addProperty( "fo:hyphenate", d->m_bHyphenation, tt );
00674     }
00675 }
00676 
00677 void KoTextFormat::update()
00678 {
00679     //kDebug(32500) << this << " KoTextFormat::update " << fn.family() << " " << pointSize() << endl;
00680     m_key = QString::null; // invalidate key, recalc at the next key() call
00681     assert( d );
00682     d->clearCache(); // i.e. recalc at the next screenFont[Metrics]() call
00683 }
00684 
00685 void KoTextFormat::copyFormat( const KoTextFormat & nf, int flags )
00686 {
00687     if ( flags & KoTextFormat::Bold )
00688         fn.setBold( nf.fn.bold() );
00689     if ( flags & KoTextFormat::Italic )
00690         fn.setItalic( nf.fn.italic() );
00691     if ( flags & KoTextFormat::Underline )
00692         fn.setUnderline( nf.fn.underline() );
00693     if ( flags & KoTextFormat::Family )
00694         fn.setFamily( nf.fn.family() );
00695     if ( flags & KoTextFormat::Size )
00696         fn.setPointSize( nf.fn.pointSize() );
00697     if ( flags & KoTextFormat::Color )
00698         col = nf.col;
00699     if ( flags & KoTextFormat::Misspelled )
00700         missp = nf.missp;
00701     if ( flags & KoTextFormat::VAlign )
00702     {
00703         va = nf.va;
00704         setRelativeTextSize( nf.relativeTextSize());
00705     }
00707     if ( flags & KoTextFormat::StrikeOut )
00708     {
00709         setStrikeOutStyle( nf.strikeOutStyle() );
00710         setStrikeOutType (nf.strikeOutType());
00711     }
00712     if( flags & KoTextFormat::TextBackgroundColor)
00713         setTextBackgroundColor(nf.textBackgroundColor());
00714     if( flags & KoTextFormat::ExtendUnderLine)
00715     {
00716         setTextUnderlineColor(nf.textUnderlineColor());
00717         setUnderlineType (nf.underlineType());
00718         setUnderlineStyle (nf.underlineStyle());
00719     }
00720     if( flags & KoTextFormat::Language)
00721         setLanguage(nf.language());
00722     if( flags & KoTextFormat::ShadowText)
00723         setShadow(nf.shadowDistanceX(), nf.shadowDistanceY(), nf.shadowColor());
00724     if( flags & KoTextFormat::OffsetFromBaseLine)
00725         setOffsetFromBaseLine(nf.offsetFromBaseLine());
00726     if( flags & KoTextFormat::WordByWord)
00727         setWordByWord(nf.wordByWord());
00728     if( flags & KoTextFormat::Attribute)
00729         setAttributeFont(nf.attributeFont());
00730     if( flags & KoTextFormat::Hyphenation )
00731         setHyphenation( nf.hyphenation());
00732     if( flags & KoTextFormat::UnderLineWidth )
00733         setUnderLineWidth( nf.underLineWidth());
00735     update();
00736     //kDebug(32500) << "KoTextFormat " << (void*)this << " copyFormat nf=" << (void*)&nf << " " << nf.key() << " flags=" << flags
00737     //        << " ==> result " << this << " " << key() << endl;
00738 }
00739 
00740 void KoTextFormat::setBold( bool b )
00741 {
00742     if ( b == fn.bold() )
00743         return;
00744     fn.setBold( b );
00745     update();
00746 }
00747 
00748 void KoTextFormat::setMisspelled( bool b )
00749 {
00750     if ( b == (bool)missp )
00751         return;
00752     missp = b;
00753     update();
00754 }
00755 
00756 void KoTextFormat::setVAlign( VerticalAlignment a )
00757 {
00758     if ( a == va )
00759         return;
00760     va = a;
00761     update();
00762 }
00763 
00764 void KoTextFormat::setItalic( bool b )
00765 {
00766     if ( b == fn.italic() )
00767         return;
00768     fn.setItalic( b );
00769     update();
00770 }
00771 
00772 void KoTextFormat::setUnderline( bool b )
00773 {
00774     if ( b == fn.underline() )
00775         return;
00776     fn.setUnderline( b );
00777     update();
00778 }
00779 
00780 void KoTextFormat::setFamily( const QString &f )
00781 {
00782     if ( f == fn.family() )
00783         return;
00784     fn.setFamily( f );
00785     update();
00786 }
00787 
00788 void KoTextFormat::setPointSize( int s )
00789 {
00790     if ( s == fn.pointSize() )
00791         return;
00792     fn.setPointSize( s );
00793     update();
00794 }
00795 
00796 void KoTextFormat::setFont( const QFont &f )
00797 {
00798     if ( f == fn )
00799         return;
00800     fn = f;
00801     fn.setStyleStrategy( QFont::ForceOutline );
00802     update();
00803 }
00804 
00805 void KoTextFormat::setColor( const QColor &c )
00806 {
00807     if ( c == col )
00808         return;
00809     col = c;
00810     update();
00811 }
00812 
00813 #if 0
00814 int KoTextFormat::minLeftBearing() const
00815 {
00816     if ( !painter || !painter->isActive() )
00817         return leftBearing;
00818     painter->setFont( fn );
00819     return painter->fontMetrics().minLeftBearing();
00820 }
00821 
00822 int KoTextFormat::minRightBearing() const
00823 {
00824     if ( !painter || !painter->isActive() )
00825         return rightBearing;
00826     painter->setFont( fn );
00827     return painter->fontMetrics().minRightBearing();
00828 }
00829 #endif
00830 
00831 // ## Maybe we need a binary form for speed when NDEBUG, and to keep the
00832 // ## readable form when !NDEBUG, like QFont does?
00833 void KoTextFormat::generateKey()
00834 {
00835     QString k = fn.key();
00836     k += '/';
00837     if ( col.isValid() ) // just to shorten the key in the common case
00838         k += QString::number( (uint)col.rgb() );
00839     k += '/';
00840     k += QString::number( (int)isMisspelled() ); // 1 digit, no need for '/'
00841     k += QString::number( (int)vAlign() );
00843     k += '/';
00844     if (m_textBackColor.isValid())
00845         k += QString::number( (uint)m_textBackColor.rgb() );
00846     k += '/';
00847     if ( m_textUnderlineColor.isValid())
00848         k += QString::number( (uint)m_textUnderlineColor.rgb() );
00849     k += '/';
00850     k += QString::number( (int)m_underlineType ); // a digit each, no need for '/'
00851     k += QString::number( (int)m_strikeOutType );
00852     k += QString::number( (int)m_underlineStyle );
00853     k += QString::number( (int)m_strikeOutStyle );
00854     k += '/';
00855     k += m_language;
00856     k += '/';
00857     if ( d->m_shadowDistanceX != 0 || d->m_shadowDistanceY != 0 )
00858     {
00859         k += QString::number( d->m_shadowDistanceX );
00860         k += '/';
00861         k += QString::number( d->m_shadowDistanceY );
00862         k += '/';
00863         k += QString::number( (uint)d->m_shadowColor.rgb() );
00864     }
00865     k += '/';
00866     k += QString::number( d->m_relativeTextSize);
00867     k += '/';
00868     k += QString::number( d->m_offsetFromBaseLine);
00869     k += '/';
00870     k += QString::number( (int)d->m_bWordByWord); // boolean -> 1 digit -> no '/'
00871     k += QString::number( (int)m_attributeFont);
00872     k += '/';
00873     k += QString::number( (int)d->m_bHyphenation); // boolean -> 1 digit -> no '/'
00874     k += QString::number( (double)d->m_underLineWidth);
00876     // Keep in sync with method below
00877     m_key = k;
00878 }
00879 
00880 // This is used to create "simple formats", with font and color etc., but without
00881 // advanced features. Doesn't matter, don't extend the args.
00882 QString KoTextFormat::getKey( const QFont &fn, const QColor &col, bool misspelled, VerticalAlignment a )
00883 {
00884     QString k = fn.key();
00885     k += '/';
00886     if ( col.isValid() ) // just to shorten the key in the common case
00887         k += QString::number( (uint)col.rgb() );
00888     k += '/';
00889     k += QString::number( (int)misspelled );
00890     k += QString::number( (int)a );
00892     k += '/';
00893         // no background color
00894     k += '/';
00895         // no underline color
00896     k += '/';
00897     k += QString::number( (int)U_NONE );
00898     k += QString::number( (int)S_NONE ); // no double-underline in a "simple format"
00899     k += QString::number( (int)U_SOLID );
00900     k += QString::number( (int)S_SOLID ); // no double-underline in a "simple format"
00901     k += '/';
00902     //k += QString::null; // spellcheck language
00903     k += '/';
00904       //no shadow
00905     k += '/';
00906     k += "0.66"; //relative text size
00907     k += '/';
00908     k += '0'; // no offset from base line
00909     k += '/';
00910     k += '0'; //no wordbyword attribute
00911     k += '0'; //no font attribute
00912     k += '/';
00913     k += '0'; //no hyphen
00914     k += '0'; //no ulw
00915 
00917     return k;
00918 }
00919 
00920 
00921 QString KoTextFormat::key() const
00922 {
00923     if ( m_key.isEmpty() )
00924         const_cast<KoTextFormat*>( this )->generateKey();
00925     return m_key;
00926 }
00927 
00928 void KoTextFormat::addRef()
00929 {
00930     ref++;
00931 #ifdef DEBUG_COLLECTION
00932     if ( collection )
00933         kDebug(32500) << "  add ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
00934 #endif
00935 }
00936 
00937 void KoTextFormat::removeRef()
00938 {
00939     ref--;
00940     if ( !collection )
00941         return;
00942 #ifdef DEBUG_COLLECTION
00943     kDebug(32500) << "  remove ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
00944 #endif
00945     if ( ref == 0 )
00946         collection->remove( this );
00947 }
00948 
00949 void KoTextFormat::setStrikeOutType (StrikeOutType _type)
00950 {
00951     if ( m_strikeOutType == _type )
00952         return;
00953     m_strikeOutType = _type;
00954     update();
00955 }
00956 
00957 void KoTextFormat::setUnderlineType (UnderlineType _type)
00958 {
00959     if ( m_underlineType == _type )
00960         return;
00961     m_underlineType = _type;
00962     update();
00963 }
00964 
00965 void KoTextFormat::setUnderlineStyle (UnderlineStyle _type)
00966 {
00967     if ( m_underlineStyle == _type )
00968         return;
00969     m_underlineStyle = _type;
00970     update();
00971 }
00972 
00973 void KoTextFormat::setStrikeOutStyle( StrikeOutStyle _type )
00974 {
00975     if ( m_strikeOutStyle == _type )
00976         return;
00977     m_strikeOutStyle = _type;
00978     update();
00979 }
00980 
00981 void KoTextFormat::setTextBackgroundColor(const QColor &_col)
00982 {
00983     if(m_textBackColor==_col)
00984         return;
00985     m_textBackColor=_col;
00986     update();
00987 }
00988 void KoTextFormat::setTextUnderlineColor(const QColor &_col)
00989 {
00990     if ( m_textUnderlineColor == _col )
00991         return;
00992     m_textUnderlineColor=_col;
00993     update();
00994 }
00995 
00996 void KoTextFormat::setShadow( double shadowDistanceX, double shadowDistanceY, const QColor& shadowColor )
00997 {
00998     if ( d->m_shadowDistanceX == shadowDistanceX &&
00999          d->m_shadowDistanceY == shadowDistanceY &&
01000          d->m_shadowColor == shadowColor )
01001         return;
01002     d->m_shadowDistanceX = shadowDistanceX;
01003     d->m_shadowDistanceY = shadowDistanceY;
01004     d->m_shadowColor = shadowColor;
01005     update();
01006 }
01007 
01008 void KoTextFormat::setRelativeTextSize( double _size )
01009 {
01010     if ( d->m_relativeTextSize == _size)
01011         return;
01012     d->m_relativeTextSize = _size;
01013     update();
01014 }
01015 
01016 void KoTextFormat::setOffsetFromBaseLine( int _offset )
01017 {
01018     if ( d->m_offsetFromBaseLine == _offset)
01019         return;
01020     d->m_offsetFromBaseLine = _offset;
01021     update();
01022 }
01023 
01024 void KoTextFormat::setWordByWord( bool _b )
01025 {
01026     if ( d->m_bWordByWord == _b)
01027         return;
01028     d->m_bWordByWord = _b;
01029     update();
01030 }
01031 
01032 
01033 void KoTextFormat::setAttributeFont(KoTextFormat::AttributeStyle _att )
01034 {
01035     if ( m_attributeFont == _att)
01036         return;
01037     m_attributeFont = _att;
01038     update();
01039 
01040 }
01041 
01042 int KoTextFormat::compare( const KoTextFormat & format ) const
01043 {
01044     int flags = 0;
01045     if ( fn.weight() != format.fn.weight() )
01046         flags |= KoTextFormat::Bold;
01047     if ( fn.italic() != format.fn.italic() )
01048         flags |= KoTextFormat::Italic;
01049     if ( textUnderlineColor()!=format.textUnderlineColor() ||
01050          underlineType()!= format.underlineType() ||
01051          underlineStyle() != format.underlineStyle())
01052         flags |= KoTextFormat::ExtendUnderLine;
01053     if ( fn.family() != format.fn.family() )
01054         flags |= KoTextFormat::Family;
01055     if ( pointSize() != format.pointSize() )
01056         flags |= KoTextFormat::Size;
01057     if ( color() != format.color() )
01058         flags |= KoTextFormat::Color;
01059     if ( vAlign() != format.vAlign() ||
01060         relativeTextSize() != format.relativeTextSize())
01061         flags |= KoTextFormat::VAlign;
01062     if ( strikeOutType() != format.strikeOutType()
01063         || underlineStyle() != format.underlineStyle())
01064         flags |= KoTextFormat::StrikeOut;
01065     if ( textBackgroundColor() != format.textBackgroundColor() )
01066         flags |= KoTextFormat::TextBackgroundColor;
01067     if ( language() != format.language() )
01068         flags |= KoTextFormat::Language;
01069     if ( d->m_shadowDistanceX != format.shadowDistanceX()
01070          || d->m_shadowDistanceY != format.shadowDistanceY()
01071          || d->m_shadowColor != format.shadowColor() )
01072         flags |= KoTextFormat::ShadowText;
01073     if ( offsetFromBaseLine() != format.offsetFromBaseLine() )
01074         flags |= KoTextFormat::OffsetFromBaseLine;
01075     if ( wordByWord() != format.wordByWord() )
01076         flags |= KoTextFormat::WordByWord;
01077     if ( attributeFont() != format.attributeFont() )
01078         flags |= KoTextFormat::Attribute;
01079     if( hyphenation() != format.hyphenation() )
01080         flags |= KoTextFormat::Hyphenation;
01081     if( underLineWidth() != format.underLineWidth() )
01082         flags |= KoTextFormat::UnderLineWidth;
01083     return flags;
01084 }
01085 
01086 QColor KoTextFormat::defaultTextColor( QPainter * painter )
01087 {
01088     if ( painter->device()->devType() == QInternal::Printer )
01089         return Qt::black;
01090     return QApplication::palette().color( QPalette::Active, QColorGroup::Text );
01091 }
01092 
01093 float KoTextFormat::screenPointSize( const KoTextZoomHandler* zh ) const
01094 {
01095     // ## simplify (needs a change in KoTextZoomHandler)
01096     int pointSizeLU = KoTextZoomHandler::ptToLayoutUnitPt( pointSize() );
01097     if ( vAlign() != KoTextFormat::AlignNormal )
01098         pointSizeLU = (int)( pointSizeLU *relativeTextSize() );
01099     return zh->layoutUnitToFontSize( pointSizeLU, false /* forPrint */ );
01100 }
01101 
01102 float KoTextFormat::refPointSize() const
01103 {
01104     if ( vAlign() != KoTextFormat::AlignNormal )
01105         return (float)pointSize() * relativeTextSize();
01106     else
01107         return pointSize();
01108 }
01109 
01110 QFont KoTextFormat::refFont() const
01111 {
01112     float pointSize = refPointSize();
01113     if ( !d->m_refFont || pointSize != d->m_refFont->pointSizeF() )
01114     {
01115         delete d->m_refFont;
01116         d->m_refFont = new QFont( font() );
01117         d->m_refFont->setPointSizeF( pointSize );
01118         delete d->m_refFontMetrics;
01119         d->m_refFontMetrics = 0;
01120         //kDebug(32500) << "KoTextFormat::refFont created new font with size " << pointSize << endl;
01121     }
01122     return *d->m_refFont;
01123 }
01124 
01125 QFont KoTextFormat::screenFont( const KoTextZoomHandler* zh ) const
01126 {
01127     float pointSize = screenPointSize( zh );
01128     //kDebug(32500) << "KoTextFormat::screenFont pointSize=" << pointSize << endl;
01129     // Compare if this is the size for which we cached the font metrics.
01130     // We have to do this very dynamically, because 2 views could be painting the same
01131     // stuff, with different zoom levels. So no absolute caching possible.
01132     /*if ( d->m_screenFont )
01133       kDebug(32500) << " d->m_screenFont->pointSizeF()=" << d->m_screenFont->pointSizeFloat() << endl;*/
01134     if ( !d->m_screenFont || qAbs( pointSize - d->m_screenFont->pointSizeF() ) > 1E-4 )
01135     {
01136         delete d->m_screenFont;
01137         d->m_screenFont = new QFont( font() );
01138         d->m_screenFont->setPointSizeF( pointSize );
01139         delete d->m_screenFontMetrics;
01140         d->m_screenFontMetrics = 0;
01141         //kDebug(32500) << "KoTextFormat::screenFont created new font with size " << pointSize << endl;
01142     }
01143     return *d->m_screenFont;
01144 }
01145 
01146 const QFontMetrics& KoTextFormat::screenFontMetrics( const KoTextZoomHandler* zh ) const
01147 {
01148     QFont f = screenFont(zh); // don't move inside the if!
01149 
01150     if ( !d->m_screenFontMetrics ) // not calculated, or invalidated by screenFont above
01151     {
01152         //kDebug(32500) << this << " KoTextFormat::screenFontMetrics pointSize=" << pointSize << " d->m_screenFont->pointSizeF()=" << d->m_screenFont->pointSizeFloat() << endl;
01153         d->m_screenFontMetrics = new QFontMetrics( f );
01154         //kDebug(32500) << "KoTextFormat::screenFontMetrics created new metrics with size " << pointSize << "   height:" << d->m_screenFontMetrics->height() << endl;
01155     }
01156     return *d->m_screenFontMetrics;
01157 }
01158 
01159 const QFontMetrics& KoTextFormat::refFontMetrics() const
01160 {
01161     QFont f = refFont();
01162 
01163     if ( !d->m_refFontMetrics )
01164     {
01165         //kDebug(32500) << this << " KoTextFormat::refFontMetrics pointSize=" << pointSize << " d->m_refFont->pointSizeF()=" << d->m_refFont->pointSizeFloat() << endl;
01166         d->m_refFontMetrics = new QFontMetrics( f );
01167         //kDebug(32500) << "KoTextFormat::refFontMetrics created new metrics with size " << pointSize << "   height:" << d->m_refFontMetrics->height() << endl;
01168     }
01169     return *d->m_refFontMetrics;
01170 }
01171 
01172 QFont KoTextFormat::smallCapsFont( const KoTextZoomHandler* zh, bool applyZoom ) const
01173 {
01174     QFont font = applyZoom ? screenFont( zh ) : refFont();
01175     QFontMetrics fm = refFontMetrics(); // only used for proportions, so applyZoom doesn't matter
01176     double pointSize = font.pointSize() * ((double)fm.boundingRect("x").height()/(double)fm.boundingRect("X").height());
01177     font.setPointSizeF( pointSize );
01178     return font;
01179 }
01180 
01181 int KoTextFormat::charWidth( const KoTextZoomHandler* zh, bool applyZoom, const KoTextStringChar* c,
01182                              const KoTextParag* parag, int i ) const
01183 {
01184     ushort unicode = c->c.unicode();
01185     if ( !c->charStop || unicode == 0xad || unicode == 0x2028 )
01186          return 0;
01187     Q_ASSERT( !c->isCustom() ); // actually it's a bit stupid to call this for custom items
01188     if( c->isCustom() ) {
01189          if( c->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
01190              // customitem width is in LU pixels. Convert to 100%-zoom-pixels (pt2pt==pix2pix)
01191              double w = KoTextZoomHandler::layoutUnitPtToPt( c->customItem()->width );
01192              return qRound( applyZoom ? ( w * zh->zoomFactorX() ) : w );
01193          }
01194          else
01195              return 0;
01196     }
01197     int pixelww;
01198     int r = c->c.row();
01199     if( /*r < 0x06 || r > 0x1f*/ r < 0x06 || (r > 0x1f && !(r > 0xd7 && r < 0xe0)) )
01200     {
01201         // Small caps -> we can't use the cached font metrics from KoTextFormat
01202         if ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.toUpper() != c->c )
01203         {
01204             pixelww = QFontMetrics( smallCapsFont( zh, applyZoom ) ).width( displayedChar( c->c ) );
01205         }
01206         else
01207         // Use the cached font metrics from KoTextFormat
01208         if ( applyZoom )
01209         {
01210             if ( r ) {
01211                 pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
01212             } else {
01213                 // Use the m_screenWidths[] array when possible, even faster
01214                 Q_ASSERT( unicode < 256 );
01215                 pixelww = d->m_screenWidths[ unicode ];
01216                 // Not in cache yet -> calculate
01217                 if ( pixelww == 0 ) {
01218                     pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
01219                     Q_ASSERT( pixelww < 65535 );
01220                     d->m_screenWidths[ unicode ] = pixelww;
01221                 }
01222             }
01223         }
01224         else {
01225             pixelww = this->refFontMetrics().width( displayedChar( c->c ) );
01226         }
01227     }
01228     else {
01229         // Complex text. We need some hacks to get the right metric here
01230         bool smallCaps = ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.toUpper() != c->c );
01231         const QFontMetrics& fontMetrics = smallCaps ? smallCapsFont( zh, applyZoom ) : applyZoom ? screenFontMetrics( zh ) : refFontMetrics();
01232         QString str;
01233         int pos = 0;
01234         if( i > 8 )
01235             pos = i - 8;
01236         int off = i - pos;
01237         int end = qMin( parag->length(), i + 8 );
01238         while ( pos < end ) {
01239             str += displayedChar( parag->at(pos)->c );
01240             pos++;
01241         }
01242         pixelww = fontMetrics.charWidth( str, off );
01243     }
01244 
01245 #if 0
01246         kDebug(32500) << "KoTextFormat::charWidth: char=" << QString(c->c) << " format=" << key()
01247                        << ", applyZoom=" << applyZoom << " pixel-width=" << pixelww << endl;
01248 #endif
01249     return pixelww;
01250 }
01251 
01252 int KoTextFormat::height() const
01253 {
01254     if ( d->m_refHeight < 0 )
01255     {
01256         // Calculate height using 100%-zoom font
01257         int h = refFontMetrics().height()+QABS(offsetFromBaseLine());
01258         if ( vAlign() == KoTextFormat::AlignSuperScript )
01259             h += refFontMetrics().height()/2;
01260         else if ( vAlign() == KoTextFormat::AlignSubScript )
01261             h += refFontMetrics().height()/6;
01262 
01263         // Add room for the shadow
01264         if ( d->m_shadowDistanceY != 0 ) {
01265             // pt -> pixel (at 100% zoom)
01266             h += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiY() ) ) * QABS( d->m_shadowDistanceY ) );
01267         }
01268 
01269         //kDebug(32500) << "KoTextFormat::height 100%-zoom font says h=" << h << " in LU:" << KoTextZoomHandler::ptToLayoutUnitPt(h) << endl;
01270         // Then scale to LU
01271         d->m_refHeight = qRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
01272     }
01273     return d->m_refHeight;
01274 }
01275 
01276 int KoTextFormat::offsetX() const // in LU pixels
01277 {
01278     int off = 0;
01279 #if 0
01280     // Shadow on left -> character is moved to the right
01281     // Wrong if next char has no shadow (they'll run into each other)
01282     // Somehow we should only do this if x == 0 (in the formatter)
01283     if ( d->m_shadowDistanceX < 0 )
01284     {
01285         double lupt = KoTextZoomHandler::ptToLayoutUnitPt( QABS( d->m_shadowDistanceX ) );
01286         off += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiX() ) ) * lupt );
01287     }
01288 #endif
01289     return off;
01290 }
01291 
01292 int KoTextFormat::offsetY() const // in LU pixels
01293 {
01294     int off = 0;
01295 #if 0
01296     // Shadow on top -> character is moved down
01297     if ( d->m_shadowDistanceY < 0 )
01298     {
01299         double lupt = KoTextZoomHandler::ptToLayoutUnitPt( QABS( d->m_shadowDistanceY ) );
01300         off += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiY() ) ) * lupt );
01301     }
01302 #endif
01303     return off;
01304 }
01305 
01306 QString KoTextFormat::displayedString( const QString& str )const
01307 {
01308     switch ( m_attributeFont ) {
01309     case ATT_NONE:
01310         return str;
01311     case ATT_UPPER:
01312     case ATT_SMALL_CAPS:
01313         return str.toUpper();
01314     case ATT_LOWER:
01315         return str.toLower();
01316     default:
01317         kDebug(32500)<<" Error in AttributeStyle \n";
01318         return str;
01319     }
01320 }
01321 
01322 QChar KoTextFormat::displayedChar( QChar c )const
01323 {
01324     if ( c.unicode() == 0xa0 ) // nbsp
01325         return ' ';
01326     switch ( m_attributeFont ) {
01327     case ATT_NONE:
01328         return c;
01329     case ATT_SMALL_CAPS:
01330     case ATT_UPPER:
01331         return c.toUpper();
01332     case ATT_LOWER:
01333         return c.toLower();
01334     default:
01335         kDebug(32500)<<" Error in AttributeStyle \n";
01336         return c;
01337     }
01338 }
01339 
01340 int KoTextFormat::ascent() const
01341 {
01342     if ( d->m_refAscent < 0 )
01343     {
01344         // Calculate ascent using 100%-zoom font
01345         int h = refFontMetrics().ascent();
01346         if ( offsetFromBaseLine()>0 )
01347             h += offsetFromBaseLine();
01348         if ( vAlign() == KoTextFormat::AlignSuperScript )
01349             h += refFontMetrics().height()/2;
01350         // Then scale to LU
01351         d->m_refAscent = qRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
01352         //d->m_refAscent += offsetY();
01353     }
01354     return d->m_refAscent;
01355 }
01356 
01357 int KoTextFormat::descent() const
01358 {
01359     if ( d->m_refDescent < 0 )
01360     {
01361         // Calculate descent using 100%-zoom font
01362         int h = refFontMetrics().descent();
01363         if ( offsetFromBaseLine()<0 )
01364             h -= offsetFromBaseLine();
01365         // Then scale to LU
01366         d->m_refDescent = qRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
01367         //d->m_refDescent += offsetY();
01368     }
01369     return d->m_refDescent;
01370 }
01371 
01372 int KoTextFormat::charWidthLU( const KoTextStringChar* c, const KoTextParag* parag, int i ) const
01373 {
01374     // Hmm, we add precision to the least precise one!
01375     // TODO: We should instead implement it here in LU, and let charWidth call it...
01376    return KoTextZoomHandler::ptToLayoutUnitPt( charWidth( 0L, false, c, parag, i ) );
01377 }
01378 
01379 int KoTextFormat::width( const QChar& ch ) const
01380 {
01381     // Warning this doesn't take into account the shadow
01382     return KoTextZoomHandler::ptToLayoutUnitPt( refFontMetrics().width( ch ) );
01383 }
01384 
01385 void KoTextFormat::applyCharStyle( KoCharStyle *_style )
01386 {
01387     d->m_charStyle = _style;
01388 }
01389 
01390 KoCharStyle *KoTextFormat::style() const
01391 {
01392     return d->m_charStyle;
01393 }
01394 
01395 QString KoTextFormat::shadowAsCss(  double shadowDistanceX, double shadowDistanceY, const QColor& shadowColor )
01396 {
01397     // http://www.w3.org/TR/REC-CSS2/text.html#text-shadow-props
01398     // none | [<color> || <length (h)> <length (v)> <length (blur radius, not used here)>] ...
01399     // => none or color length length
01400     if ( shadowDistanceX != 0 || shadowDistanceY != 0 )
01401     {
01402         QString css = shadowColor.name() + ' ';
01403         css += QString::number(shadowDistanceX) + "pt ";
01404         css += QString::number(shadowDistanceY) + "pt";
01405         return css;
01406     }
01407     return "none";
01408 }
01409 
01410 QString KoTextFormat::shadowAsCss() const
01411 {
01412     return shadowAsCss( d->m_shadowDistanceX, d->m_shadowDistanceY, d->m_shadowColor );
01413 }
01414 
01415 void KoTextFormat::parseShadowFromCss( const QString& _css )
01416 {
01417     QString css = _css.simplified();
01418     if ( css.isEmpty() || css == "none" )
01419     {
01420         d->m_shadowDistanceX = 0;
01421         d->m_shadowDistanceY = 0;
01422         d->m_shadowColor = QColor();
01423     } else
01424     {
01425         QStringList tokens = QStringList::split(' ', css);
01426         if ( tokens.isEmpty() ) {
01427             kWarning(32500) << "Parse error in text-shadow: " << css << endl;
01428             return;
01429         }
01430         // Check which token looks like a color
01431         QColor col( tokens.first() );
01432         if ( col.isValid() )
01433             tokens.pop_front();
01434         else if ( tokens.count() > 1 )
01435         {
01436             col.setNamedColor( tokens.last() );
01437             if ( col.isValid() )
01438                 tokens.pop_back();
01439         }
01440         d->m_shadowColor = col; // whether valid or not
01441         // Parse x distance
01442         if ( !tokens.isEmpty() ) {
01443             d->m_shadowDistanceX = KoUnit::parseValue( tokens.first() );
01444             tokens.pop_front();
01445         }
01446         // Parse y distance
01447         if ( !tokens.isEmpty() ) {
01448             d->m_shadowDistanceY = KoUnit::parseValue( tokens.first() );
01449             tokens.pop_front();
01450         }
01451         // We ignore whatever else is in the string (e.g. blur radius, other shadows)
01452 
01453     }
01454     update();
01455 }
01456 
01457 QColor KoTextFormat::shadowColor() const
01458 {
01459     if ( d->m_shadowColor.isValid() )
01460         return d->m_shadowColor;
01461     else // CSS says "[If] no color has been specified, the shadow will have the same color as the [text] itself"
01462         return col;
01463 }
01464 
01465 int KoTextFormat::shadowX( KoTextZoomHandler *zh ) const
01466 {
01467     return zh->zoomItXOld( d->m_shadowDistanceX );
01468 }
01469 
01470 int KoTextFormat::shadowY( KoTextZoomHandler *zh ) const
01471 {
01472     return zh->zoomItYOld( d->m_shadowDistanceY );
01473 }
01474 
01475 //static
01476 QString KoTextFormat::underlineStyleToString( KoTextFormat::UnderlineStyle _lineType )
01477 {
01478     QString strLineType;
01479     switch ( _lineType )
01480     {
01481     case KoTextFormat::U_SOLID:
01482         strLineType ="solid";
01483         break;
01484     case KoTextFormat::U_DASH:
01485         strLineType ="dash";
01486         break;
01487     case KoTextFormat::U_DOT:
01488         strLineType ="dot";
01489         break;
01490     case KoTextFormat::U_DASH_DOT:
01491         strLineType="dashdot";
01492         break;
01493     case KoTextFormat::U_DASH_DOT_DOT:
01494         strLineType="dashdotdot";
01495         break;
01496     }
01497     return strLineType;
01498 }
01499 
01500 QString KoTextFormat::strikeOutStyleToString( KoTextFormat::StrikeOutStyle _lineType )
01501 {
01502     QString strLineType;
01503     switch ( _lineType )
01504     {
01505     case KoTextFormat::S_SOLID:
01506         strLineType ="solid";
01507         break;
01508     case KoTextFormat::S_DASH:
01509         strLineType ="dash";
01510         break;
01511     case KoTextFormat::S_DOT:
01512         strLineType ="dot";
01513         break;
01514     case KoTextFormat::S_DASH_DOT:
01515         strLineType="dashdot";
01516         break;
01517     case KoTextFormat::S_DASH_DOT_DOT:
01518         strLineType="dashdotdot";
01519         break;
01520     }
01521     return strLineType;
01522 }
01523 
01524 KoTextFormat::UnderlineStyle KoTextFormat::stringToUnderlineStyle( const QString & _str )
01525 {
01526     if ( _str =="solid")
01527         return KoTextFormat::U_SOLID;
01528     else if ( _str =="dash" )
01529         return KoTextFormat::U_DASH;
01530     else if ( _str =="dot" )
01531         return KoTextFormat::U_DOT;
01532     else if ( _str =="dashdot")
01533         return KoTextFormat::U_DASH_DOT;
01534     else if ( _str=="dashdotdot")
01535         return KoTextFormat::U_DASH_DOT_DOT;
01536     else
01537         return KoTextFormat::U_SOLID;
01538 }
01539 
01540 KoTextFormat::StrikeOutStyle KoTextFormat::stringToStrikeOutStyle( const QString & _str )
01541 {
01542     if ( _str =="solid")
01543         return KoTextFormat::S_SOLID;
01544     else if ( _str =="dash" )
01545         return KoTextFormat::S_DASH;
01546     else if ( _str =="dot" )
01547         return KoTextFormat::S_DOT;
01548     else if ( _str =="dashdot")
01549         return KoTextFormat::S_DASH_DOT;
01550     else if ( _str=="dashdotdot")
01551         return KoTextFormat::S_DASH_DOT_DOT;
01552     else
01553         return KoTextFormat::S_SOLID;
01554 }
01555 
01556 QString KoTextFormat::attributeFontToString( KoTextFormat::AttributeStyle _attr )
01557 {
01558     if (_attr == KoTextFormat::ATT_NONE )
01559         return QString("none");
01560     else if ( _attr == KoTextFormat::ATT_UPPER )
01561         return QString("uppercase");
01562     else if ( _attr == KoTextFormat::ATT_LOWER )
01563         return QString("lowercase");
01564     else if ( _attr == KoTextFormat::ATT_SMALL_CAPS )
01565         return QString("smallcaps");
01566     else
01567         return QString("none");
01568 }
01569 
01570 KoTextFormat::AttributeStyle KoTextFormat::stringToAttributeFont( const QString & _str )
01571 {
01572     if ( _str == "none" )
01573         return KoTextFormat::ATT_NONE;
01574     else if ( _str == "uppercase")
01575         return KoTextFormat::ATT_UPPER;
01576     else if ( _str == "lowercase")
01577         return KoTextFormat::ATT_LOWER;
01578     else if ( _str == "smallcaps" )
01579         return KoTextFormat::ATT_SMALL_CAPS;
01580     else
01581         return KoTextFormat::ATT_NONE;
01582 }
01583 
01584 
01585 void KoTextFormat::setHyphenation( bool b )
01586 {
01587     if ( d->m_bHyphenation == b )
01588         return;
01589     d->m_bHyphenation = b;
01590     update();
01591 
01592 }
01593 
01594 void KoTextFormat::setUnderLineWidth( double ulw )
01595 {
01596     if ( d->m_underLineWidth == ulw )
01597         return;
01598     d->m_underLineWidth = ulw;
01599     update();
01600 
01601 }
01602 
01603 void KoTextFormat::setLanguage( const QString & _lang)
01604 {
01605     if ( m_language == _lang )
01606         return;
01607     m_language = _lang;
01608     update();
01609 }
01610 
01611 QStringList KoTextFormat::underlineTypeList()
01612 {
01613     QStringList lst;
01614     lst <<i18nc("Underline Style", "None");
01615     lst <<i18n("Single");
01616     lst <<i18n("Double");
01617     lst <<i18n("Simple Bold");
01618     lst <<i18n("Wave");
01619     return lst;
01620 }
01621 
01622 QStringList KoTextFormat::strikeOutTypeList()
01623 {
01624     QStringList lst;
01625     lst <<i18nc("Strikeout Style", "None");
01626     lst <<i18n("Single");
01627     lst <<i18n("Double");
01628     lst <<i18n("Simple Bold");
01629     return lst;
01630 }
01631 
01632 QStringList KoTextFormat::fontAttributeList()
01633 {
01634     QStringList lst;
01635     lst <<i18n("Normal");
01636     lst <<i18n("Uppercase");
01637     lst <<i18n("Lowercase");
01638     lst <<i18n("Small Caps");
01639     return lst;
01640 }
01641 
01642 QStringList KoTextFormat::underlineStyleList()
01643 {
01644     QStringList lst;
01645     lst <<"_________";   // SOLID
01646     lst <<"___ ___ __";  // DASH
01647     lst <<"_ _ _ _ _ _"; // DOT
01648     lst <<"___ _ ___ _"; // DASH_DOT
01649     lst <<"___ _ _ ___"; // DASH_DOT_DOT
01650     return lst;
01651 }
01652 
01653 QStringList KoTextFormat::strikeOutStyleList()
01654 {
01655     QStringList lst;
01656     lst <<"_________";   // SOLID
01657     lst <<"___ ___ __";  // DASH
01658     lst <<"_ _ _ _ _ _"; // DOT
01659     lst <<"___ _ ___ _"; // DASH_DOT
01660     lst <<"___ _ _ ___"; // DASH_DOT_DOT
01661     return lst;
01662 }
01663 
01664 #ifndef NDEBUG
01665 void KoTextFormat::printDebug()
01666 {
01667     QString col = color().isValid() ? color().name() : QString("(default)");
01668     kDebug(32500) << "format '" << key() << "' (" << (void*)this << "):"
01669                    << " refcount: " << ref
01670                    << " realfont: " << QFontInfo( font() ).family()
01671                    << " color: " << col << " shadow=" << shadowAsCss() << endl;
01672 }
01673 #endif
01674 
01676 
01677 KoTextFormatCollection::KoTextFormatCollection()
01678     : cKey( 307 )//, sheet( 0 )
01679 {
01680 #ifdef DEBUG_COLLECTION
01681     kDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
01682 #endif
01683     defFormat = new KoTextFormat( QApplication::font(), QColor(), KGlobal::locale()->language(), false );
01684     lastFormat = cres = 0;
01685     cflags = -1;
01686     cKey.setAutoDelete( true );
01687     cachedFormat = 0;
01688 }
01689 
01690 KoTextFormatCollection::KoTextFormatCollection( const QFont& defaultFont, const QColor& defaultColor, const QString & defaultLanguage, bool defaultHyphenation )
01691     : cKey( 307 )
01692 {
01693 #ifdef DEBUG_COLLECTION
01694     kDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
01695 #endif
01696     defFormat = new KoTextFormat( defaultFont, defaultColor, defaultLanguage, defaultHyphenation );
01697     lastFormat = cres = 0;
01698     cflags = -1;
01699     cKey.setAutoDelete( true );
01700     cachedFormat = 0;
01701 }
01702 
01703 KoTextFormatCollection::~KoTextFormatCollection()
01704 {
01705 #ifdef DEBUG_COLLECTION
01706     kDebug(32500) << "KoTextFormatCollection::~KoTextFormatCollection " << this << endl;
01707 #endif
01708     delete defFormat;
01709     defFormat = 0;
01710 }
01711 
01712 KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *f )
01713 {
01714     if ( f->parent() == this || f == defFormat ) {
01715 #ifdef DEBUG_COLLECTION
01716         kDebug(32500) << " format(f) need '" << f->key() << "', best case!" << endl;
01717 #endif
01718         lastFormat = const_cast<KoTextFormat*>(f);
01719         lastFormat->addRef();
01720         return lastFormat;
01721     }
01722 
01723     if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
01724 #ifdef DEBUG_COLLECTION
01725         kDebug(32500) << " format(f) need '" << f->key() << "', good case!" << endl;
01726 #endif
01727         lastFormat->addRef();
01728         return lastFormat;
01729     }
01730 
01731 #if 0 // #### disabled, because if this format is not in the
01732  // formatcollection, it doesn't get the painter through
01733  // KoTextFormatCollection::setPainter() which breaks printing on
01734  // windows
01735     if ( f->isAnchor() ) {
01736         lastFormat = createFormat( *f );
01737         lastFormat->collection = 0;
01738         return lastFormat;
01739     }
01740 #endif
01741 
01742     KoTextFormat *fm = cKey.find( f->key() );
01743     if ( fm ) {
01744 #ifdef DEBUG_COLLECTION
01745         kDebug(32500) << " format(f) need '" << f->key() << "', normal case!" << endl;
01746 #endif
01747         lastFormat = fm;
01748         lastFormat->addRef();
01749         return lastFormat;
01750     }
01751 
01752     if ( f->key() == defFormat->key() )
01753         return defFormat;
01754 
01755 #ifdef DEBUG_COLLECTION
01756     kDebug(32500) << " format(f) need '" << f->key() << "', worst case!" << endl;
01757 #endif
01758     lastFormat = createFormat( *f );
01759     lastFormat->collection = this;
01760     cKey.insert( lastFormat->key(), lastFormat );
01761     Q_ASSERT( f->key() == lastFormat->key() );
01762     return lastFormat;
01763 }
01764 
01765 KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *of, const KoTextFormat *nf, int flags )
01766 {
01767     if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
01768 #ifdef DEBUG_COLLECTION
01769         kDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << "', best case!" << endl;
01770 #endif
01771         cres->addRef();
01772         return cres;
01773     }
01774 
01775 #ifdef DEBUG_COLLECTION
01776     kDebug(32500) << " format(of,nf," << flags << ") calling createFormat(of=" << of << " " << of->key() << ")" << endl;
01777 #endif
01778     cres = createFormat( *of );
01779     kof = of->key();
01780     knf = nf->key();
01781     cflags = flags;
01782 
01783 #ifdef DEBUG_COLLECTION
01784     kDebug(32500) << " format(of,nf," << flags << ") calling copyFormat(nf=" << nf << " " << nf->key() << ")" << endl;
01785 #endif
01786     cres->copyFormat( *nf, flags );
01787 
01788     KoTextFormat *fm = cKey.find( cres->key() );
01789     if ( !fm ) {
01790 #ifdef DEBUG_COLLECTION
01791         kDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", worst case!" << endl;
01792 #endif
01793         cres->collection = this;
01794         cKey.insert( cres->key(), cres );
01795     } else {
01796 #ifdef DEBUG_COLLECTION
01797         kDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", good case!" << endl;
01798 #endif
01799         delete cres;
01800         cres = fm;
01801         cres->addRef();
01802     }
01803 
01804     return cres;
01805 }
01806 
01807 #if 0
01808 KoTextFormat *KoTextFormatCollection::format( const QFont &f, const QColor &c, const QString & language, bool hyphen )
01809 {
01810     if ( cachedFormat && cfont == f && ccol == c ) {
01811 #ifdef DEBUG_COLLECTION
01812         kDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - best case" << endl;
01813 #endif
01814         cachedFormat->addRef();
01815         return cachedFormat;
01816     }
01817 
01818     QString key = KoTextFormat::getKey( f, c, false, KoTextFormat::AlignNormal );
01819     cachedFormat = cKey.find( key );
01820     cfont = f;
01821     ccol = c;
01822 
01823     if ( cachedFormat ) {
01824 #ifdef DEBUG_COLLECTION
01825         kDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - good case" << endl;
01826 #endif
01827         cachedFormat->addRef();
01828         return cachedFormat;
01829     }
01830 
01831     if ( key == defFormat->key() )
01832         return defFormat;
01833 
01834     cachedFormat = createFormat( f, c, language, hyphen );
01835     cachedFormat->collection = this;
01836     cKey.insert( cachedFormat->key(), cachedFormat );
01837     if ( cachedFormat->key() != key )
01838         kWarning() << "ASSERT: keys for format not identical: '" << cachedFormat->key() << " '" << key << "'" << endl;
01839 #ifdef DEBUG_COLLECTION
01840     kDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - worst case" << endl;
01841 #endif
01842     return cachedFormat;
01843 }
01844 #endif
01845 
01846 void KoTextFormatCollection::remove( KoTextFormat *f )
01847 {
01848     if ( lastFormat == f )
01849         lastFormat = 0;
01850     if ( cres == f )
01851         cres = 0;
01852     if ( cachedFormat == f )
01853         cachedFormat = 0;
01854     cKey.remove( f->key() );
01855 }
01856 
01857 void KoTextFormatCollection::zoomChanged()
01858 {
01859     Q3DictIterator<KoTextFormat> it( cKey );
01860     for ( ; it.current(); ++it ) {
01861         it.current()->zoomChanged();
01862     }
01863 }
01864 
01865 #if 0
01866 void KoTextFormatCollection::setPainter( QPainter *p )
01867 {
01868     Q3DictIterator<KoTextFormat> it( cKey );
01869     KoTextFormat *f;
01870     while ( ( f = it.current() ) ) {
01871         ++it;
01872         f->setPainter( p );
01873     }
01874 }
01875 #endif
01876 
01877 #ifndef NDEBUG
01878 void KoTextFormatCollection::debug()
01879 {
01880     kDebug(32500) << "------------ KoTextFormatCollection: debug --------------- BEGIN" << endl;
01881     kDebug(32500) << "Default Format: '" << defFormat->key() << "' (" << (void*)defFormat << "): realfont: " << QFontInfo( defFormat->font() ).family() << endl;
01882     Q3DictIterator<KoTextFormat> it( cKey );
01883     for ( ; it.current(); ++it ) {
01884          Q_ASSERT(it.currentKey() == it.current()->key());
01885          if(it.currentKey() != it.current()->key())
01886              kDebug(32500) << "**** MISMATCH key=" << it.currentKey() << " (see line below for format)" << endl;
01887          it.current()->printDebug();
01888     }
01889     kDebug(32500) << "------------ KoTextFormatCollection: debug --------------- END" << endl;
01890 }
01891 #endif

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