lib Library API Documentation

kotextformat.cc

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