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 <qglobal.h>
00021 #if QT_VERSION >= 0x030200
00022 #define INDIC
00023 #endif
00024 
00025 #include "kotextformat.h"
00026 #include "korichtext.h" // for KoTextParag etc.
00027 #include "kozoomhandler.h"
00028 #include <kglobal.h>
00029 #include <kdebug.h>
00030 #include <klocale.h>
00031 #include <assert.h>
00032 #include "kostyle.h"
00033 
00034 void KoTextFormat::KoTextFormatPrivate::clearCache()
00035 {
00036     delete m_screenFontMetrics; m_screenFontMetrics = 0L;
00037     delete m_screenFont; m_screenFont = 0L;
00038     delete m_refFontMetrics; m_refFontMetrics = 0L;
00039     delete m_refFont; m_refFont = 0L;
00040     m_refAscent = -1;
00041     m_refDescent = -1;
00042     m_refHeight = -1;
00043     memset( m_screenWidths, 0, 256 * sizeof( ushort ) );
00044 }
00045 
00046 KoTextFormat::KoTextFormat()
00047 {
00048     //linkColor = TRUE;
00049     ref = 0;
00050     missp = FALSE;
00051     va = AlignNormal;
00052     collection = 0;
00054     fn.setStyleStrategy( QFont::ForceOutline );
00055     d = new KoTextFormatPrivate;
00056     m_textUnderlineColor=QColor();
00057     m_underlineType = U_NONE;
00058     m_strikeOutType = S_NONE;
00059     m_underlineStyle = U_SOLID;
00060     m_strikeOutStyle = S_SOLID;
00061     m_language = KGlobal::locale()->language();
00062     d->m_bHyphenation = false;
00063     d->m_underLineWidth = 1.0;
00064     d->m_shadowDistanceX = 0;
00065     d->m_shadowDistanceY = 0;
00066     d->m_relativeTextSize = 0.66;
00067     d->m_offsetFromBaseLine= 0;
00068     d->m_bWordByWord = false;
00069     m_attributeFont = ATT_NONE;
00071 //#ifdef DEBUG_COLLECTION
00072 //    kdDebug(32500) << "KoTextFormat simple ctor, no addRef, no generateKey ! " << this << endl;
00073 //#endif
00074 }
00075 
00076 KoTextFormat::KoTextFormat( const QFont &f, const QColor &c, const QString &_language, bool hyphenation, double ulw, KoTextFormatCollection *parent )
00077     : fn( f ), col( c ) /*fm( QFontMetrics( f ) ),*/ //linkColor( TRUE )
00078 {
00079 #ifdef DEBUG_COLLECTION
00080     kdDebug(32500) << "KoTextFormat with font & color & parent (" << parent << "), addRef. " << this << endl;
00081 #endif
00082     int pointSize;
00083     if ( f.pointSize() == -1 ) // font was set with a pixelsize, we need a pointsize!
00084         pointSize = (int)( ( (double)fn.pixelSize() * 72.0 ) / (double)QPaintDevice::x11AppDpiY() );
00085     else
00086         pointSize = f.pointSize();
00087     fn.setPointSize( pointSize );
00088     // WYSIWYG works much much better with scalable fonts -> force it to be scalable
00089     fn.setStyleStrategy( QFont::ForceOutline );
00090     ref = 0;
00091     collection = parent;
00092     //leftBearing = fm.minLeftBearing();
00093     //rightBearing = fm.minRightBearing();
00094     //hei = fm.height();
00095     //asc = fm.ascent();
00096     //dsc = fm.descent();
00097     missp = FALSE;
00098     va = AlignNormal;
00100     d = new KoTextFormatPrivate;
00101     m_textUnderlineColor = QColor();
00102     m_underlineType = U_NONE;
00103     m_strikeOutType = S_NONE;
00104     m_underlineStyle = U_SOLID;
00105     m_strikeOutStyle = S_SOLID;
00106     m_language = _language;
00107     d->m_shadowDistanceX = 0;
00108     d->m_shadowDistanceY = 0;
00109     d->m_relativeTextSize= 0.66;
00110     d->m_offsetFromBaseLine = 0;
00111     d->m_bWordByWord = false;
00112     d->m_charStyle = 0L;
00113     d->m_bHyphenation = hyphenation;
00114     d->m_underLineWidth = ulw;
00115     m_attributeFont = ATT_NONE;
00117     generateKey();
00118     addRef();
00119 }
00120 
00121 KoTextFormat::KoTextFormat( const QFont &_font,
00122                             VerticalAlignment _valign,
00123                             const QColor & _color,
00124                             const QColor & _backGroundColor,
00125                             const QColor & _underlineColor,
00126                             KoTextFormat::UnderlineType _underlineType,
00127                             KoTextFormat::UnderlineStyle _underlineStyle,
00128                             KoTextFormat::StrikeOutType _strikeOutType,
00129                             KoTextFormat::StrikeOutStyle _strikeOutStyle,
00130                             KoTextFormat::AttributeStyle _fontAttribute,
00131                             const QString &_language,
00132                             double _relativeTextSize,
00133                             int _offsetFromBaseLine,
00134                             bool _wordByWord,
00135                             bool _hyphenation,
00136                             double _shadowDistanceX,
00137                             double _shadowDistanceY,
00138                             const QColor& _shadowColor )
00139 {
00140     ref = 0;
00141     collection = 0;
00142     fn = _font;
00143     col = _color;
00144     missp = false;
00145     va = _valign;
00146     d = new KoTextFormatPrivate;
00147     m_textBackColor = _backGroundColor;
00148     m_textUnderlineColor = _underlineColor;
00149     m_underlineType = _underlineType;
00150     m_strikeOutType = _strikeOutType;
00151     m_underlineStyle = _underlineStyle;
00152     m_strikeOutStyle = _strikeOutStyle;
00153     m_language = _language;
00154     d->m_bHyphenation = _hyphenation;
00155     d->m_underLineWidth = 1.0;
00156     d->m_shadowDistanceX = _shadowDistanceX;
00157     d->m_shadowDistanceY = _shadowDistanceY;
00158     d->m_shadowColor = _shadowColor;
00159     d->m_relativeTextSize = _relativeTextSize;
00160     d->m_offsetFromBaseLine = _offsetFromBaseLine;
00161     d->m_bWordByWord = _wordByWord;
00162     m_attributeFont = _fontAttribute;
00163     d->m_charStyle = 0L;
00165     generateKey();
00166     addRef();
00167 }
00168 
00169 KoTextFormat::KoTextFormat( const KoTextFormat &f )
00170 {
00171     d = 0L;
00172     operator=( f );
00173 }
00174 
00175 KoTextFormat::~KoTextFormat()
00176 {
00178     // Removing a format that is in the collection is forbidden, in fact.
00179     // It should have been removed from the collection before being deleted.
00180 #ifndef NDEBUG
00181     if ( parent() && parent()->defaultFormat() ) // not when destroying the collection
00182         assert( ! ( parent()->dict().find( key() ) == this ) );
00183         // (has to be the same pointer, not only the same key)
00184 #endif
00185     delete d;
00187 }
00188 
00189 KoTextFormat& KoTextFormat::operator=( const KoTextFormat &f )
00190 {
00191 #ifdef DEBUG_COLLECTION
00192     kdDebug(32500) << "KoTextFormat::operator= " << this << " (copying " << &f << "). Will addRef" << endl;
00193 #endif
00194     ref = 0;
00195     collection = 0; // f might be in the collection, but we are not
00196     fn = f.fn;
00197     col = f.col;
00198     //fm = f.fm;
00199     //leftBearing = f.leftBearing;
00200     //rightBearing = f.rightBearing;
00201     //hei = f.hei;
00202     //asc = f.asc;
00203     //dsc = f.dsc;
00204     missp = f.missp;
00205     va = f.va;
00206     k = f.k;
00207     //linkColor = f.linkColor;
00209     delete d;
00210     d = new KoTextFormatPrivate;
00211     m_textBackColor=f.m_textBackColor;
00212     m_textUnderlineColor=f.m_textUnderlineColor;
00213     m_underlineType = f.m_underlineType;
00214     m_strikeOutType = f.m_strikeOutType;
00215     m_underlineStyle = f.m_underlineStyle;
00216     m_strikeOutStyle = f.m_strikeOutStyle;
00217     m_language = f.m_language;
00218     d->m_bHyphenation=f.d->m_bHyphenation;
00219     d->m_underLineWidth=f.d->m_underLineWidth;
00220     d->m_shadowDistanceX = f.d->m_shadowDistanceX;
00221     d->m_shadowDistanceY = f.d->m_shadowDistanceY;
00222     d->m_shadowColor = f.d->m_shadowColor;
00223     d->m_relativeTextSize = f.d->m_relativeTextSize;
00224     d->m_offsetFromBaseLine = f.d->m_offsetFromBaseLine;
00225     d->m_bWordByWord = f.d->m_bWordByWord;
00226     m_attributeFont = f.m_attributeFont;
00227     d->m_charStyle = 0L;
00229     addRef();
00230     return *this;
00231 }
00232 
00233 void KoTextFormat::update()
00234 {
00235     //kdDebug(32500) << this << " KoTextFormat::update " << fn.family() << " " << pointSize() << endl;
00236     fn.setStyleStrategy( QFont::ForceOutline );
00237     //fm = QFontMetrics( fn );
00238     //leftBearing = fm.minLeftBearing();
00239     //rightBearing = fm.minRightBearing();
00240     //hei = fm.height();
00241     //asc = fm.ascent();
00242     //dsc = fm.descent();
00243     generateKey();
00244     //updateStyleFlags();
00246     assert( d );
00247     d->clearCache(); // i.e. recalc at the next screenFont[Metrics]() call
00249 }
00250 
00251 void KoTextFormat::copyFormat( const KoTextFormat & nf, int flags )
00252 {
00253     if ( flags & KoTextFormat::Bold )
00254     fn.setBold( nf.fn.bold() );
00255     if ( flags & KoTextFormat::Italic )
00256     fn.setItalic( nf.fn.italic() );
00257     if ( flags & KoTextFormat::Underline )
00258     fn.setUnderline( nf.fn.underline() );
00259     if ( flags & KoTextFormat::Family )
00260     fn.setFamily( nf.fn.family() );
00261     if ( flags & KoTextFormat::Size )
00262     fn.setPointSize( nf.fn.pointSize() );
00263     if ( flags & KoTextFormat::Color )
00264     col = nf.col;
00265     if ( flags & KoTextFormat::Misspelled )
00266     missp = nf.missp;
00267     if ( flags & KoTextFormat::VAlign )
00268     {
00269     va = nf.va;
00270         setRelativeTextSize( nf.relativeTextSize());
00271     }
00273     if ( flags & KoTextFormat::StrikeOut )
00274     {
00275         setStrikeOutStyle( nf.strikeOutStyle() );
00276         setStrikeOutType (nf.strikeOutType());
00277     }
00278     if( flags & KoTextFormat::TextBackgroundColor)
00279         setTextBackgroundColor(nf.textBackgroundColor());
00280     if( flags & KoTextFormat::ExtendUnderLine)
00281     {
00282         setTextUnderlineColor(nf.textUnderlineColor());
00283         setUnderlineType (nf.underlineType());
00284         setUnderlineStyle (nf.underlineStyle());
00285     }
00286     if( flags & KoTextFormat::Language)
00287         setLanguage(nf.language());
00288     if( flags & KoTextFormat::ShadowText)
00289         setShadow(nf.shadowDistanceX(), nf.shadowDistanceY(), nf.shadowColor());
00290     if( flags & KoTextFormat::OffsetFromBaseLine)
00291         setOffsetFromBaseLine(nf.offsetFromBaseLine());
00292     if( flags & KoTextFormat::WordByWord)
00293         setWordByWord(nf.wordByWord());
00294     if( flags & KoTextFormat::Attribute)
00295         setAttributeFont(nf.attributeFont());
00296     if( flags & KoTextFormat::Hyphenation )
00297         setHyphenation( nf.hyphenation());
00298     if( flags & KoTextFormat::UnderLineWidth )
00299         setUnderLineWidth( nf.underLineWidth());
00301     update();
00302     //kdDebug(32500) << "KoTextFormat " << (void*)this << " copyFormat nf=" << (void*)&nf << " " << nf.key() << " flags=" << flags
00303     //        << " ==> result " << this << " " << key() << endl;
00304 }
00305 
00306 void KoTextFormat::setBold( bool b )
00307 {
00308     if ( b == fn.bold() )
00309     return;
00310     fn.setBold( b );
00311     update();
00312 }
00313 
00314 void KoTextFormat::setMisspelled( bool b )
00315 {
00316     if ( b == (bool)missp )
00317     return;
00318     missp = b;
00319     update();
00320 }
00321 
00322 void KoTextFormat::setVAlign( VerticalAlignment a )
00323 {
00324     if ( a == va )
00325     return;
00326     va = a;
00327     update();
00328 }
00329 
00330 void KoTextFormat::setItalic( bool b )
00331 {
00332     if ( b == fn.italic() )
00333     return;
00334     fn.setItalic( b );
00335     update();
00336 }
00337 
00338 void KoTextFormat::setUnderline( bool b )
00339 {
00340     if ( b == fn.underline() )
00341     return;
00342     fn.setUnderline( b );
00343     update();
00344 }
00345 
00346 void KoTextFormat::setFamily( const QString &f )
00347 {
00348     if ( f == fn.family() )
00349     return;
00350     fn.setFamily( f );
00351     update();
00352 }
00353 
00354 void KoTextFormat::setPointSize( int s )
00355 {
00356     if ( s == fn.pointSize() )
00357     return;
00358     fn.setPointSize( s );
00359     update();
00360 }
00361 
00362 void KoTextFormat::setFont( const QFont &f )
00363 {
00364     if ( f == fn && !k.isEmpty() )
00365     return;
00366     fn = f;
00367     update();
00368 }
00369 
00370 void KoTextFormat::setColor( const QColor &c )
00371 {
00372     if ( c == col )
00373     return;
00374     col = c;
00375     update();
00376 }
00377 
00378 #if 0
00379 int KoTextFormat::minLeftBearing() const
00380 {
00381     if ( !painter || !painter->isActive() )
00382     return leftBearing;
00383     painter->setFont( fn );
00384     return painter->fontMetrics().minLeftBearing();
00385 }
00386 
00387 int KoTextFormat::minRightBearing() const
00388 {
00389     if ( !painter || !painter->isActive() )
00390     return rightBearing;
00391     painter->setFont( fn );
00392     return painter->fontMetrics().minRightBearing();
00393 }
00394 #endif
00395 
00396 // ## Maybe we need a binary form for speed when NDEBUG, and to keep the
00397 // ## readable form when !NDEBUG, like QFont does?
00398 void KoTextFormat::generateKey()
00399 {
00400     k = fn.key();
00401     k += '/';
00402     if ( col.isValid() ) // just to shorten the key in the common case
00403         k += QString::number( (uint)col.rgb() );
00404     k += '/';
00405     k += QString::number( (int)isMisspelled() ); // 1 digit, no need for '/'
00406     k += QString::number( (int)vAlign() );
00408     k += '/';
00409     if (m_textBackColor.isValid())
00410         k += QString::number( (uint)m_textBackColor.rgb() );
00411     k += '/';
00412     if ( m_textUnderlineColor.isValid())
00413         k += QString::number( (uint)m_textUnderlineColor.rgb() );
00414     k += '/';
00415     k += QString::number( (int)m_underlineType ); // a digit each, no need for '/'
00416     k += QString::number( (int)m_strikeOutType );
00417     k += QString::number( (int)m_underlineStyle );
00418     k += QString::number( (int)m_strikeOutStyle );
00419     k += '/';
00420     k += m_language;
00421     k += '/';
00422     if ( d->m_shadowDistanceX != 0 || d->m_shadowDistanceY != 0 )
00423     {
00424         k += QString::number( d->m_shadowDistanceX );
00425         k += '/';
00426         k += QString::number( d->m_shadowDistanceY );
00427         k += '/';
00428         k += QString::number( (uint)d->m_shadowColor.rgb() );
00429     }
00430     k += '/';
00431     k += QString::number( d->m_relativeTextSize);
00432     k += '/';
00433     k += QString::number( d->m_offsetFromBaseLine);
00434     k += '/';
00435     k += QString::number( (int)d->m_bWordByWord); // boolean -> 1 digit -> no '/'
00436     k += QString::number( (int)m_attributeFont);
00437     k += '/';
00438     k += QString::number( (int)d->m_bHyphenation); // boolean -> 1 digit -> no '/'
00439     k += QString::number( (double)d->m_underLineWidth);
00441     // Keep in sync with method below
00442 }
00443 
00444 // This is used to create "simple formats", with font and color etc., but without
00445 // advanced features. Doesn't matter, don't extend the args.
00446 QString KoTextFormat::getKey( const QFont &fn, const QColor &col, bool misspelled, VerticalAlignment a )
00447 {
00448     QString k = fn.key();
00449     k += '/';
00450     if ( col.isValid() ) // just to shorten the key in the common case
00451         k += QString::number( (uint)col.rgb() );
00452     k += '/';
00453     k += QString::number( (int)misspelled );
00454     k += QString::number( (int)a );
00456     k += '/';
00457         // no background color
00458     k += '/';
00459         // no underline color
00460     k += '/';
00461     k += QString::number( (int)U_NONE );
00462     k += QString::number( (int)S_NONE ); // no double-underline in a "simple format"
00463     k += QString::number( (int)U_SOLID );
00464     k += QString::number( (int)S_SOLID ); // no double-underline in a "simple format"
00465     k += '/';
00466     //k += QString::null; // spellcheck language
00467     k += '/';
00468       //no shadow
00469     k += '/';
00470     k += "0.66"; //relative text size
00471     k += '/';
00472     k += "0"; // no offset from base line
00473     k += '/';
00474     k += "0"; //no wordbyword attribute
00475     k += "0"; //no font attribute
00476     k += '/';
00477     k += "0"; //no hyphen
00478     k += "0"; //no ulw
00479 
00481     return k;
00482 }
00483 
00484 void KoTextFormat::addRef()
00485 {
00486     ref++;
00487 #ifdef DEBUG_COLLECTION
00488     if ( collection )
00489         kdDebug(32500) << "  add ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
00490 #endif
00491 }
00492 
00493 void KoTextFormat::removeRef()
00494 {
00495     ref--;
00496     if ( !collection )
00497         return;
00498 #ifdef DEBUG_COLLECTION
00499     kdDebug(32500) << "  remove ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
00500 #endif
00501     if ( ref == 0 )
00502         collection->remove( this );
00503 }
00504 
00505 void KoTextFormat::setStrikeOutType (StrikeOutType _type)
00506 {
00507     if ( m_strikeOutType == _type )
00508         return;
00509     m_strikeOutType = _type;
00510     update();
00511 }
00512 
00513 void KoTextFormat::setUnderlineType (UnderlineType _type)
00514 {
00515     if ( m_underlineType == _type )
00516         return;
00517     m_underlineType = _type;
00518     update();
00519 }
00520 
00521 void KoTextFormat::setUnderlineStyle (UnderlineStyle _type)
00522 {
00523     if ( m_underlineStyle == _type )
00524         return;
00525     m_underlineStyle = _type;
00526     update();
00527 }
00528 
00529 void KoTextFormat::setStrikeOutStyle( StrikeOutStyle _type )
00530 {
00531     if ( m_strikeOutStyle == _type )
00532         return;
00533     m_strikeOutStyle = _type;
00534     update();
00535 }
00536 
00537 void KoTextFormat::setTextBackgroundColor(const QColor &_col)
00538 {
00539     if(m_textBackColor==_col)
00540         return;
00541     m_textBackColor=_col;
00542     update();
00543 }
00544 void KoTextFormat::setTextUnderlineColor(const QColor &_col)
00545 {
00546     if ( m_textUnderlineColor == _col )
00547         return;
00548     m_textUnderlineColor=_col;
00549     update();
00550 }
00551 
00552 void KoTextFormat::setShadow( double shadowDistanceX, double shadowDistanceY, const QColor& shadowColor )
00553 {
00554     if ( d->m_shadowDistanceX == shadowDistanceX &&
00555          d->m_shadowDistanceY == shadowDistanceY &&
00556          d->m_shadowColor == shadowColor )
00557         return;
00558     d->m_shadowDistanceX = shadowDistanceX;
00559     d->m_shadowDistanceY = shadowDistanceY;
00560     d->m_shadowColor = shadowColor;
00561     update();
00562 }
00563 
00564 void KoTextFormat::setRelativeTextSize( double _size )
00565 {
00566     if ( d->m_relativeTextSize == _size)
00567         return;
00568     d->m_relativeTextSize = _size;
00569     update();
00570 }
00571 
00572 void KoTextFormat::setOffsetFromBaseLine( int _offset )
00573 {
00574     if ( d->m_offsetFromBaseLine == _offset)
00575         return;
00576     d->m_offsetFromBaseLine = _offset;
00577     update();
00578 }
00579 
00580 void KoTextFormat::setWordByWord( bool _b )
00581 {
00582     if ( d->m_bWordByWord == _b)
00583         return;
00584     d->m_bWordByWord = _b;
00585     update();
00586 }
00587 
00588 
00589 void KoTextFormat::setAttributeFont(KoTextFormat::AttributeStyle _att )
00590 {
00591     if ( m_attributeFont == _att)
00592         return;
00593     m_attributeFont = _att;
00594     update();
00595 
00596 }
00597 
00598 int KoTextFormat::compare( const KoTextFormat & format ) const
00599 {
00600     int flags = 0;
00601     if ( fn.weight() != format.fn.weight() )
00602         flags |= KoTextFormat::Bold;
00603     if ( fn.italic() != format.fn.italic() )
00604         flags |= KoTextFormat::Italic;
00605     if ( textUnderlineColor()!=format.textUnderlineColor() ||
00606          underlineType()!= format.underlineType() ||
00607          underlineStyle() != format.underlineStyle())
00608         flags |= KoTextFormat::ExtendUnderLine;
00609     if ( fn.family() != format.fn.family() )
00610         flags |= KoTextFormat::Family;
00611     if ( pointSize() != format.pointSize() )
00612         flags |= KoTextFormat::Size;
00613     if ( color() != format.color() )
00614         flags |= KoTextFormat::Color;
00615     if ( vAlign() != format.vAlign() ||
00616         relativeTextSize() != format.relativeTextSize())
00617         flags |= KoTextFormat::VAlign;
00618     if ( strikeOutType() != format.strikeOutType()
00619         || underlineStyle() != format.underlineStyle())
00620         flags |= KoTextFormat::StrikeOut;
00621     if ( textBackgroundColor() != format.textBackgroundColor() )
00622         flags |= KoTextFormat::TextBackgroundColor;
00623     if ( language() != format.language() )
00624         flags |= KoTextFormat::Language;
00625     if ( d->m_shadowDistanceX != format.shadowDistanceX()
00626          || d->m_shadowDistanceY != format.shadowDistanceY()
00627          || d->m_shadowColor != format.shadowColor() )
00628         flags |= KoTextFormat::ShadowText;
00629     if ( offsetFromBaseLine() != format.offsetFromBaseLine() )
00630         flags |= KoTextFormat::OffsetFromBaseLine;
00631     if ( wordByWord() != format.wordByWord() )
00632         flags |= KoTextFormat::WordByWord;
00633     if ( attributeFont() != format.attributeFont() )
00634         flags |= KoTextFormat::Attribute;
00635     if( hyphenation() != format.hyphenation() )
00636         flags |= KoTextFormat::Hyphenation;
00637     if( underLineWidth() != format.underLineWidth() )
00638         flags |= KoTextFormat::UnderLineWidth;
00639     return flags;
00640 }
00641 
00642 QColor KoTextFormat::defaultTextColor( QPainter * painter )
00643 {
00644     if ( painter->device()->devType() == QInternal::Printer )
00645         return Qt::black;
00646     return QApplication::palette().color( QPalette::Active, QColorGroup::Text );
00647 }
00648 
00649 float KoTextFormat::screenPointSize( const KoZoomHandler* zh ) const
00650 {
00651     // ## simplify (needs a change in KoZoomHandler)
00652     int pointSizeLU = KoTextZoomHandler::ptToLayoutUnitPt( pointSize() );
00653     if ( vAlign() != KoTextFormat::AlignNormal )
00654         pointSizeLU = (int)( pointSizeLU *relativeTextSize() );
00655     return zh->layoutUnitToFontSize( pointSizeLU, false /* forPrint */ );
00656 }
00657 
00658 float KoTextFormat::refPointSize() const
00659 {
00660     if ( vAlign() != KoTextFormat::AlignNormal )
00661         return (float)pointSize() * relativeTextSize();
00662     else
00663         return pointSize();
00664 }
00665 
00666 QFont KoTextFormat::refFont() const
00667 {
00668     float pointSize = refPointSize();
00669     if ( !d->m_refFont || pointSize != d->m_refFont->pointSizeFloat() )
00670     {
00671         delete d->m_refFont;
00672         d->m_refFont = new QFont( font() );
00673         d->m_refFont->setPointSizeFloat( pointSize );
00674         delete d->m_refFontMetrics;
00675         d->m_refFontMetrics = 0;
00676         //kdDebug(32500) << "KoTextFormat::refFont created new font with size " << pointSize << endl;
00677     }
00678     return *d->m_refFont;
00679 }
00680 
00681 QFont KoTextFormat::screenFont( const KoZoomHandler* zh ) const
00682 {
00683     float pointSize = screenPointSize( zh );
00684     //kdDebug(32500) << "KoTextFormat::screenFont pointSize=" << pointSize << endl;
00685     // Compare if this is the size for which we cached the font metrics.
00686     // We have to do this very dynamically, because 2 views could be painting the same
00687     // stuff, with different zoom levels. So no absolute caching possible.
00688     /*if ( d->m_screenFont )
00689       kdDebug(32500) << " d->m_screenFont->pointSizeFloat()=" << d->m_screenFont->pointSizeFloat() << endl;*/
00690     if ( !d->m_screenFont || kAbs( pointSize - d->m_screenFont->pointSizeFloat() ) > 1E-4 )
00691     {
00692         delete d->m_screenFont;
00693         d->m_screenFont = new QFont( font() );
00694         d->m_screenFont->setPointSizeFloat( pointSize );
00695         delete d->m_screenFontMetrics;
00696         d->m_screenFontMetrics = 0;
00697         //kdDebug(32500) << "KoTextFormat::screenFont created new font with size " << pointSize << endl;
00698     }
00699     return *d->m_screenFont;
00700 }
00701 
00702 const QFontMetrics& KoTextFormat::screenFontMetrics( const KoZoomHandler* zh ) const
00703 {
00704     QFont f = screenFont(zh); // don't move inside the if!
00705 
00706     if ( !d->m_screenFontMetrics ) // not calculated, or invalidated by screenFont above
00707     {
00708         //kdDebug(32500) << this << " KoTextFormat::screenFontMetrics pointSize=" << pointSize << " d->m_screenFont->pointSizeFloat()=" << d->m_screenFont->pointSizeFloat() << endl;
00709         d->m_screenFontMetrics = new QFontMetrics( f );
00710         //kdDebug(32500) << "KoTextFormat::screenFontMetrics created new metrics with size " << pointSize << "   height:" << d->m_screenFontMetrics->height() << endl;
00711     }
00712     return *d->m_screenFontMetrics;
00713 }
00714 
00715 const QFontMetrics& KoTextFormat::refFontMetrics() const
00716 {
00717     QFont f = refFont();
00718 
00719     if ( !d->m_refFontMetrics )
00720     {
00721         //kdDebug(32500) << this << " KoTextFormat::refFontMetrics pointSize=" << pointSize << " d->m_refFont->pointSizeFloat()=" << d->m_refFont->pointSizeFloat() << endl;
00722         d->m_refFontMetrics = new QFontMetrics( f );
00723         //kdDebug(32500) << "KoTextFormat::refFontMetrics created new metrics with size " << pointSize << "   height:" << d->m_refFontMetrics->height() << endl;
00724     }
00725     return *d->m_refFontMetrics;
00726 }
00727 
00728 QFont KoTextFormat::smallCapsFont( const KoZoomHandler* zh, bool applyZoom ) const
00729 {
00730     QFont font = applyZoom ? screenFont( zh ) : refFont();
00731     QFontMetrics fm = refFontMetrics(); // only used for proportions, so applyZoom doesn't matter
00732     double pointSize = font.pointSize() * ((double)fm.boundingRect("x").height()/(double)fm.boundingRect("X").height());
00733     font.setPointSizeFloat( pointSize );
00734     return font;
00735 }
00736 
00737 int KoTextFormat::charWidth( const KoZoomHandler* zh, bool applyZoom, const KoTextStringChar* c,
00738                              const KoTextParag* parag, int i ) const
00739 {
00740     ushort unicode = c->c.unicode();
00741 #ifndef INDIC
00742     if ( unicode == 0xad ) // soft hyphen
00743     return 0;
00744 #else
00745     if ( !c->charStop || unicode == 0xad || unicode == 0x2028 )
00746      return 0;
00747 #endif
00748     Q_ASSERT( !c->isCustom() ); // actually it's a bit stupid to call this for custom items
00749     if( c->isCustom() ) {
00750      if( c->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
00751              // customitem width is in LU pixels. Convert to 100%-zoom-pixels (pt2pt==pix2pix)
00752              int w = qRound( KoTextZoomHandler::layoutUnitPtToPt( c->customItem()->width ) );
00753              return applyZoom ? ( w * zh->zoom() / 100 ) : w;
00754          }
00755          else
00756              return 0;
00757     }
00758     int pixelww;
00759     int r = c->c.row();
00760 #ifndef INDIC
00761     if( r < 0x06 || r > 0x1f )
00762 #else
00763     if( /*r < 0x06 || r > 0x1f*/ r < 0x06 || (r > 0x1f && !(r > 0xd7 && r < 0xe0)) )
00764 #endif
00765     {
00766         // Small caps -> we can't use the cached font metrics from KoTextFormat
00767         if ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.upper() != c->c )
00768         {
00769             pixelww = QFontMetrics( smallCapsFont( zh, applyZoom ) ).width( displayedChar( c->c ) );
00770         }
00771         else
00772         // Use the cached font metrics from KoTextFormat
00773         if ( applyZoom )
00774         {
00775         if ( r ) {
00776                 pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
00777         } else {
00778                 // Use the m_screenWidths[] array when possible, even faster
00779                 Q_ASSERT( unicode < 256 );
00780         pixelww = d->m_screenWidths[ unicode ];
00781                 // Not in cache yet -> calculate
00782                 if ( pixelww == 0 ) {
00783                     pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
00784                     Q_ASSERT( pixelww < 65535 );
00785                     d->m_screenWidths[ unicode ] = pixelww;
00786                 }
00787         }
00788         }
00789         else {
00790             pixelww = this->refFontMetrics().width( displayedChar( c->c ) );
00791     }
00792     }
00793     else {
00794         // Complex text. We need some hacks to get the right metric here
00795         bool smallCaps = ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.upper() != c->c );
00796         const QFontMetrics& fontMetrics = smallCaps ? smallCapsFont( zh, applyZoom ) : applyZoom ? screenFontMetrics( zh ) : refFontMetrics();
00797         QString str;
00798         int pos = 0;
00799 #ifndef INDIC
00800         if( i > 4 )
00801             pos = i - 4;
00802 #else
00803         if( i > 8 )
00804             pos = i - 8;
00805 #endif
00806         int off = i - pos;
00807 #ifndef INDIC
00808         int end = QMIN( parag->length(), i + 4 );
00809 #else
00810         int end = QMIN( parag->length(), i + 8 );
00811 #endif
00812         while ( pos < end ) {
00813             str += displayedChar( parag->at(pos)->c );
00814             pos++;
00815         }
00816         pixelww = fontMetrics.charWidth( str, off );
00817     }
00818 
00819 #if 0
00820     // Add room for the shadow - hmm, this is wrong. A word with a shadow
00821     // doesn't need to space its chars so that the shadow never runs into
00822     // the next char. The usual effect is that it DOES run into other chars.
00823     if ( d->m_shadowDistanceX != 0 )
00824     {
00825         // pt to pixel conversion
00826         int shadowpix = (int)(POINT_TO_INCH( static_cast<double>( QPaintDevice::x11AppDpiX() ) ) * QABS( d->m_shadowDistanceX ) );
00827         //kdDebug(32500) << "d->m_shadowDistanceX=" << d->m_shadowDistanceX << " -> shadowpix=" << shadowpix
00828         //      << ( applyZoom ? " and applying zoom " : " (100% zoom) " )
00829         //      << " -> adding " << ( applyZoom ? (  shadowpix * zh->zoom() / 100 ) : shadowpix ) << endl;
00830         pixelww += applyZoom ? ( shadowpix * zh->zoom() / 100 ) : shadowpix;
00831     }
00832 #endif
00833 
00834 #if 0
00835         kdDebug(32500) << "KoTextFormat::charWidth: char=" << QString(c->c) << " format=" << key()
00836                        << ", applyZoom=" << applyZoom << " pixel-width=" << pixelww << endl;
00837 #endif
00838     return pixelww;
00839 }
00840 
00841 int KoTextFormat::height() const
00842 {
00843     if ( d->m_refHeight < 0 )
00844     {
00845         // Calculate height using 100%-zoom font
00846         int h = refFontMetrics().height()+QABS(offsetFromBaseLine());
00847         if ( vAlign() == KoTextFormat::AlignSuperScript )
00848             h += refFontMetrics().height()/2;
00849         else if ( vAlign() == KoTextFormat::AlignSubScript )
00850             h += refFontMetrics().height()/6;
00851 
00852         // Add room for the shadow
00853         if ( d->m_shadowDistanceY != 0 ) {
00854             // pt -> pixel (at 100% zoom)
00855             h += (int)(POINT_TO_INCH( static_cast<double>( QPaintDevice::x11AppDpiY() ) ) * QABS( d->m_shadowDistanceY ) );
00856         }
00857 
00858         //kdDebug(32500) << "KoTextFormat::height 100%-zoom font says h=" << h << " in LU:" << KoTextZoomHandler::ptToLayoutUnitPt(h) << endl;
00859         // Then scale to LU
00860         d->m_refHeight = qRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
00861     }
00862     return d->m_refHeight;
00863 }
00864 
00865 int KoTextFormat::offsetX() const // in LU pixels
00866 {
00867     int off = 0;
00868 #if 0
00869     // Shadow on left -> character is moved to the right
00870     // Wrong if next char has no shadow (they'll run into each other)
00871     // Somehow we should only do this if x == 0 (in the formatter)
00872     if ( d->m_shadowDistanceX < 0 )
00873     {
00874         double lupt = KoTextZoomHandler::ptToLayoutUnitPt( QABS( d->m_shadowDistanceX ) );
00875         off += (int)(POINT_TO_INCH( static_cast<double>( QPaintDevice::x11AppDpiX() ) ) * lupt );
00876     }
00877 #endif
00878     return off;
00879 }
00880 
00881 int KoTextFormat::offsetY() const // in LU pixels
00882 {
00883     int off = 0;
00884 #if 0
00885     // Shadow on top -> character is moved down
00886     if ( d->m_shadowDistanceY < 0 )
00887     {
00888         double lupt = KoTextZoomHandler::ptToLayoutUnitPt( QABS( d->m_shadowDistanceY ) );
00889         off += (int)(POINT_TO_INCH( static_cast<double>( QPaintDevice::x11AppDpiY() ) ) * lupt );
00890     }
00891 #endif
00892     return off;
00893 }
00894 
00895 QString KoTextFormat::displayedString( const QString& str )const
00896 {
00897     switch ( m_attributeFont ) {
00898     case ATT_NONE:
00899         return str;
00900     case ATT_UPPER:
00901     case ATT_SMALL_CAPS:
00902         return str.upper();
00903     case ATT_LOWER:
00904         return str.lower();
00905     default:
00906         kdDebug(32500)<<" Error in AttributeStyle \n";
00907         return str;
00908     }
00909 }
00910 
00911 QChar KoTextFormat::displayedChar( QChar c )const
00912 {
00913     if ( c.unicode() == 0xa0 ) // nbsp
00914         return ' ';
00915     switch ( m_attributeFont ) {
00916     case ATT_NONE:
00917         return c;
00918     case ATT_SMALL_CAPS:
00919     case ATT_UPPER:
00920         return c.upper();
00921     case ATT_LOWER:
00922         return c.lower();
00923     default:
00924         kdDebug(32500)<<" Error in AttributeStyle \n";
00925         return c;
00926     }
00927 }
00928 
00929 int KoTextFormat::ascent() const
00930 {
00931     if ( d->m_refAscent < 0 )
00932     {
00933         // Calculate ascent using 100%-zoom font
00934         int h = refFontMetrics().ascent();
00935         if ( offsetFromBaseLine()>0 )
00936             h += offsetFromBaseLine();
00937         if ( vAlign() == KoTextFormat::AlignSuperScript )
00938             h += refFontMetrics().height()/2;
00939         // Then scale to LU
00940         d->m_refAscent = qRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
00941         //d->m_refAscent += offsetY();
00942     }
00943     return d->m_refAscent;
00944 }
00945 
00946 int KoTextFormat::descent() const
00947 {
00948     if ( d->m_refDescent < 0 )
00949     {
00950         // Calculate descent using 100%-zoom font
00951         int h = refFontMetrics().descent();
00952         if ( offsetFromBaseLine()<0 )
00953             h -= offsetFromBaseLine();
00954         // Then scale to LU
00955         d->m_refDescent = qRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
00956         //d->m_refDescent += offsetY();
00957     }
00958     return d->m_refDescent;
00959 }
00960 
00961 int KoTextFormat::charWidthLU( const KoTextStringChar* c, const KoTextParag* parag, int i ) const
00962 {
00963     // Hmm, we add precision to the least precise one!
00964     // TODO: We should instead implement it here in LU, and let charWidth call it...
00965    return KoTextZoomHandler::ptToLayoutUnitPt( charWidth( 0L, false, c, parag, i ) );
00966 }
00967 
00968 int KoTextFormat::width( const QChar& ch ) const
00969 {
00970     // Warning this doesn't take into account the shadow
00971     return KoTextZoomHandler::ptToLayoutUnitPt( refFontMetrics().width( ch ) );
00972 }
00973 
00974 void KoTextFormat::applyCharStyle( KoCharStyle *_style )
00975 {
00976     d->m_charStyle = _style;
00977 }
00978 
00979 KoCharStyle *KoTextFormat::style() const
00980 {
00981     return d->m_charStyle;
00982 }
00983 
00984 QString KoTextFormat::shadowAsCss(  double shadowDistanceX, double shadowDistanceY, const QColor& shadowColor )
00985 {
00986     // http://www.w3.org/TR/REC-CSS2/text.html#text-shadow-props
00987     // none | [<color> || <length (h)> <length (v)> <length (blur radius, not used here)>] ...
00988     // => none or color length length
00989     if ( shadowDistanceX != 0 || shadowDistanceY != 0 )
00990     {
00991         QString css = shadowColor.name() + " ";
00992         css += QString::number(shadowDistanceX) + "pt ";
00993         css += QString::number(shadowDistanceY) + "pt";
00994         return css;
00995     }
00996     return "none";
00997 }
00998 
00999 QString KoTextFormat::shadowAsCss() const
01000 {
01001     return shadowAsCss( d->m_shadowDistanceX, d->m_shadowDistanceY, d->m_shadowColor );
01002 }
01003 
01004 void KoTextFormat::parseShadowFromCss( const QString& _css )
01005 {
01006     QString css = _css.simplifyWhiteSpace();
01007     if ( css.isEmpty() || css == "none" )
01008     {
01009         d->m_shadowDistanceX = 0;
01010         d->m_shadowDistanceY = 0;
01011         d->m_shadowColor = QColor();
01012     } else
01013     {
01014         QStringList tokens = QStringList::split(' ', css);
01015         if ( tokens.isEmpty() ) {
01016             kdWarning(32500) << "Parse error in text-shadow: " << css << endl;
01017             return;
01018         }
01019         // Check which token looks like a colour
01020         QColor col( tokens.first() );
01021         if ( col.isValid() )
01022             tokens.pop_front();
01023         else if ( tokens.count() > 1 )
01024         {
01025             col.setNamedColor( tokens.last() );
01026             if ( col.isValid() )
01027                 tokens.pop_back();
01028         }
01029         d->m_shadowColor = col; // whether valid or not
01030         // Parse x distance
01031         if ( !tokens.isEmpty() ) {
01032             d->m_shadowDistanceX = KoUnit::parseValue( tokens.first() );
01033             tokens.pop_front();
01034         }
01035         // Parse y distance
01036         if ( !tokens.isEmpty() ) {
01037             d->m_shadowDistanceY = KoUnit::parseValue( tokens.first() );
01038             tokens.pop_front();
01039         }
01040         // We ignore whatever else is in the string (e.g. blur radius, other shadows)
01041     }
01042     update();
01043 }
01044 
01045 QColor KoTextFormat::shadowColor() const
01046 {
01047     if ( d->m_shadowColor.isValid() )
01048         return d->m_shadowColor;
01049     else // CSS says "[If] no color has been specified, the shadow will have the same color as the [text] itself"
01050         return col;
01051 }
01052 
01053 int KoTextFormat::shadowX( KoZoomHandler *zh ) const
01054 {
01055     return zh->zoomItX( d->m_shadowDistanceX );
01056 }
01057 
01058 int KoTextFormat::shadowY( KoZoomHandler *zh ) const
01059 {
01060     return zh->zoomItY( d->m_shadowDistanceY );
01061 }
01062 
01063 //static
01064 QString KoTextFormat::underlineStyleToString( KoTextFormat::UnderlineStyle _lineType )
01065 {
01066     QString strLineType;
01067     switch ( _lineType )
01068     {
01069     case KoTextFormat::U_SOLID:
01070         strLineType ="solid";
01071         break;
01072     case KoTextFormat::U_DASH:
01073         strLineType ="dash";
01074         break;
01075     case KoTextFormat::U_DOT:
01076         strLineType ="dot";
01077         break;
01078     case KoTextFormat::U_DASH_DOT:
01079         strLineType="dashdot";
01080         break;
01081     case KoTextFormat::U_DASH_DOT_DOT:
01082         strLineType="dashdotdot";
01083         break;
01084     }
01085     return strLineType;
01086 }
01087 
01088 QString KoTextFormat::strikeOutStyleToString( KoTextFormat::StrikeOutStyle _lineType )
01089 {
01090     QString strLineType;
01091     switch ( _lineType )
01092     {
01093     case KoTextFormat::S_SOLID:
01094         strLineType ="solid";
01095         break;
01096     case KoTextFormat::S_DASH:
01097         strLineType ="dash";
01098         break;
01099     case KoTextFormat::S_DOT:
01100         strLineType ="dot";
01101         break;
01102     case KoTextFormat::S_DASH_DOT:
01103         strLineType="dashdot";
01104         break;
01105     case KoTextFormat::S_DASH_DOT_DOT:
01106         strLineType="dashdotdot";
01107         break;
01108     }
01109     return strLineType;
01110 }
01111 
01112 KoTextFormat::UnderlineStyle KoTextFormat::stringToUnderlineStyle( const QString & _str )
01113 {
01114     if ( _str =="solid")
01115         return KoTextFormat::U_SOLID;
01116     else if ( _str =="dash" )
01117         return KoTextFormat::U_DASH;
01118     else if ( _str =="dot" )
01119         return KoTextFormat::U_DOT;
01120     else if ( _str =="dashdot")
01121         return KoTextFormat::U_DASH_DOT;
01122     else if ( _str=="dashdotdot")
01123         return KoTextFormat::U_DASH_DOT_DOT;
01124     else
01125         return KoTextFormat::U_SOLID;
01126 }
01127 
01128 KoTextFormat::StrikeOutStyle KoTextFormat::stringToStrikeOutStyle( const QString & _str )
01129 {
01130     if ( _str =="solid")
01131         return KoTextFormat::S_SOLID;
01132     else if ( _str =="dash" )
01133         return KoTextFormat::S_DASH;
01134     else if ( _str =="dot" )
01135         return KoTextFormat::S_DOT;
01136     else if ( _str =="dashdot")
01137         return KoTextFormat::S_DASH_DOT;
01138     else if ( _str=="dashdotdot")
01139         return KoTextFormat::S_DASH_DOT_DOT;
01140     else
01141         return KoTextFormat::S_SOLID;
01142 }
01143 
01144 QString KoTextFormat::attributeFontToString( KoTextFormat::AttributeStyle _attr )
01145 {
01146     if (_attr == KoTextFormat::ATT_NONE )
01147         return QString("none");
01148     else if ( _attr == KoTextFormat::ATT_UPPER )
01149         return QString("uppercase");
01150     else if ( _attr == KoTextFormat::ATT_LOWER )
01151         return QString("lowercase");
01152     else if ( _attr == KoTextFormat::ATT_SMALL_CAPS )
01153         return QString("smallcaps");
01154     else
01155         return QString("none");
01156 }
01157 
01158 KoTextFormat::AttributeStyle KoTextFormat::stringToAttributeFont( const QString & _str )
01159 {
01160     if ( _str == "none" )
01161         return KoTextFormat::ATT_NONE;
01162     else if ( _str == "uppercase")
01163         return KoTextFormat::ATT_UPPER;
01164     else if ( _str == "lowercase")
01165         return KoTextFormat::ATT_LOWER;
01166     else if ( _str == "smallcaps" )
01167         return KoTextFormat::ATT_SMALL_CAPS;
01168     else
01169         return KoTextFormat::ATT_NONE;
01170 }
01171 
01172 
01173 void KoTextFormat::setHyphenation( bool b )
01174 {
01175     if ( d->m_bHyphenation == b )
01176         return;
01177     d->m_bHyphenation = b;
01178     update();
01179 
01180 }
01181 
01182 void KoTextFormat::setUnderLineWidth( double ulw )
01183 {
01184     if ( d->m_underLineWidth == ulw )
01185         return;
01186     d->m_underLineWidth = ulw;
01187     update();
01188 
01189 }
01190 
01191 void KoTextFormat::setLanguage( const QString & _lang)
01192 {
01193     if ( m_language == _lang )
01194         return;
01195     m_language = _lang;
01196     update();
01197 }
01198 
01199 QStringList KoTextFormat::underlineTypeList()
01200 {
01201     QStringList lst;
01202     lst <<i18n("Without");
01203     lst <<i18n("Single");
01204     lst <<i18n("Simple Bold");
01205     lst <<i18n("Double");
01206     lst <<i18n("Wave");
01207     return lst;
01208 }
01209 
01210 QStringList KoTextFormat::strikeOutTypeList()
01211 {
01212     QStringList lst;
01213     lst <<i18n("Without");
01214     lst <<i18n("Single");
01215     lst <<i18n("Simple Bold");
01216     lst <<i18n("Double");
01217     return lst;
01218 }
01219 
01220 QStringList KoTextFormat::fontAttributeList()
01221 {
01222     QStringList lst;
01223     lst <<i18n("Normal");
01224     lst <<i18n("Uppercase");
01225     lst <<i18n("Lowercase");
01226     lst <<i18n("Small Caps");
01227     return lst;
01228 }
01229 
01230 QStringList KoTextFormat::underlineStyleList()
01231 {
01232     QStringList lst;
01233     lst <<i18n("Solid Line");
01234     lst <<i18n("Dash Line");
01235     lst <<i18n("Dot Line");
01236     lst <<i18n("Dash Dot Line");
01237     lst <<i18n("Dash Dot Dot Line");
01238     return lst;
01239 }
01240 
01241 QStringList KoTextFormat::strikeOutStyleList()
01242 {
01243     QStringList lst;
01244     lst <<i18n("Solid Line");
01245     lst <<i18n("Dash Line");
01246     lst <<i18n("Dot Line");
01247     lst <<i18n("Dash Dot Line");
01248     lst <<i18n("Dash Dot Dot Line");
01249     return lst;
01250 }
01251 
01252 
01253 #ifndef NDEBUG
01254 void KoTextFormat::printDebug()
01255 {
01256     QString col = color().isValid() ? color().name() : QString("(default)");
01257     kdDebug(32500) << "format '" << key() << "' (" << (void*)this << "):"
01258                    << " refcount: " << ref
01259                    << " realfont: " << QFontInfo( font() ).family()
01260                    << " color: " << col << " shadow=" << shadowAsCss() << endl;
01261 }
01262 #endif
01263 
01265 
01266 KoTextFormatCollection::KoTextFormatCollection()
01267     : cKey( 307 )//, sheet( 0 )
01268 {
01269 #ifdef DEBUG_COLLECTION
01270     kdDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
01271 #endif
01272     defFormat = new KoTextFormat( QApplication::font(), QColor(), KGlobal::locale()->language(), false, 1.0 ); 
01273     lastFormat = cres = 0;
01274     cflags = -1;
01275     cKey.setAutoDelete( TRUE );
01276     cachedFormat = 0;
01277 }
01278 
01279 KoTextFormatCollection::KoTextFormatCollection( const QFont& defaultFont, const QColor& defaultColor, const QString & defaultLanguage, bool hyphen, double ulw )
01280     : cKey( 307 )//, sheet( 0 )
01281 {
01282 #ifdef DEBUG_COLLECTION
01283     kdDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
01284 #endif
01285     defFormat = new KoTextFormat( defaultFont, defaultColor, defaultLanguage, hyphen, ulw );
01286     lastFormat = cres = 0;
01287     cflags = -1;
01288     cKey.setAutoDelete( TRUE );
01289     cachedFormat = 0;
01290 }
01291 
01292 KoTextFormatCollection::~KoTextFormatCollection()
01293 {
01294 #ifdef DEBUG_COLLECTION
01295     kdDebug(32500) << "KoTextFormatCollection::~KoTextFormatCollection " << this << endl;
01296 #endif
01297     delete defFormat;
01298     defFormat = 0;
01299 }
01300 
01301 KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *f )
01302 {
01303     if ( f->parent() == this || f == defFormat ) {
01304 #ifdef DEBUG_COLLECTION
01305         kdDebug(32500) << " format(f) need '" << f->key() << "', best case!" << endl;
01306 #endif
01307     lastFormat = const_cast<KoTextFormat*>(f);
01308     lastFormat->addRef();
01309     return lastFormat;
01310     }
01311 
01312     if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
01313 #ifdef DEBUG_COLLECTION
01314         kdDebug(32500) << " format(f) need '" << f->key() << "', good case!" << endl;
01315 #endif
01316     lastFormat->addRef();
01317     return lastFormat;
01318     }
01319 
01320 #if 0 // #### disabled, because if this format is not in the
01321  // formatcollection, it doesn't get the painter through
01322  // KoTextFormatCollection::setPainter() which breaks printing on
01323  // windows
01324     if ( f->isAnchor() ) {
01325     lastFormat = createFormat( *f );
01326     lastFormat->collection = 0;
01327     return lastFormat;
01328     }
01329 #endif
01330 
01331     KoTextFormat *fm = cKey.find( f->key() );
01332     if ( fm ) {
01333 #ifdef DEBUG_COLLECTION
01334         kdDebug(32500) << " format(f) need '" << f->key() << "', normal case!" << endl;
01335 #endif
01336     lastFormat = fm;
01337     lastFormat->addRef();
01338     return lastFormat;
01339     }
01340 
01341     if ( f->key() == defFormat->key() )
01342     return defFormat;
01343 
01344 #ifdef DEBUG_COLLECTION
01345     kdDebug(32500) << " format(f) need '" << f->key() << "', worst case!" << endl;
01346 #endif
01347     lastFormat = createFormat( *f );
01348     lastFormat->collection = this;
01349     cKey.insert( lastFormat->key(), lastFormat );
01350     Q_ASSERT( f->key() == lastFormat->key() );
01351     return lastFormat;
01352 }
01353 
01354 KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *of, const KoTextFormat *nf, int flags )
01355 {
01356     if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
01357 #ifdef DEBUG_COLLECTION
01358     kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << "', best case!" << endl;
01359 #endif
01360     cres->addRef();
01361     return cres;
01362     }
01363 
01364 #ifdef DEBUG_COLLECTION
01365     kdDebug(32500) << " format(of,nf," << flags << ") calling createFormat(of=" << of << " " << of->key() << ")" << endl;
01366 #endif
01367     cres = createFormat( *of );
01368     kof = of->key();
01369     knf = nf->key();
01370     cflags = flags;
01371 
01372 #ifdef DEBUG_COLLECTION
01373     kdDebug(32500) << " format(of,nf," << flags << ") calling copyFormat(nf=" << nf << " " << nf->key() << ")" << endl;
01374 #endif
01375     cres->copyFormat( *nf, flags );
01376 
01377     KoTextFormat *fm = cKey.find( cres->key() );
01378     if ( !fm ) {
01379 #ifdef DEBUG_COLLECTION
01380     kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", worst case!" << endl;
01381 #endif
01382     cres->collection = this;
01383     cKey.insert( cres->key(), cres );
01384     } else {
01385 #ifdef DEBUG_COLLECTION
01386     kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", good case!" << endl;
01387 #endif
01388     delete cres;
01389     cres = fm;
01390     cres->addRef();
01391     }
01392 
01393     return cres;
01394 }
01395 
01396 KoTextFormat *KoTextFormatCollection::format( const QFont &f, const QColor &c, const QString & language, bool hyphen, double ulw )
01397 {
01398     if ( cachedFormat && cfont == f && ccol == c ) {
01399 #ifdef DEBUG_COLLECTION
01400     kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - best case" << endl;
01401 #endif
01402     cachedFormat->addRef();
01403     return cachedFormat;
01404     }
01405 
01406     QString key = KoTextFormat::getKey( f, c, FALSE, KoTextFormat::AlignNormal );
01407     cachedFormat = cKey.find( key );
01408     cfont = f;
01409     ccol = c;
01410 
01411     if ( cachedFormat ) {
01412 #ifdef DEBUG_COLLECTION
01413     kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - good case" << endl;
01414 #endif
01415     cachedFormat->addRef();
01416     return cachedFormat;
01417     }
01418 
01419     if ( key == defFormat->key() )
01420     return defFormat;
01421 
01422     cachedFormat = createFormat( f, c,language, hyphen, ulw );
01423     cachedFormat->collection = this;
01424     cKey.insert( cachedFormat->key(), cachedFormat );
01425     if ( cachedFormat->key() != key )
01426     kdWarning() << "ASSERT: keys for format not identical: '" << cachedFormat->key() << " '" << key << "'" << endl;
01427 #ifdef DEBUG_COLLECTION
01428     kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - worst case" << endl;
01429 #endif
01430     return cachedFormat;
01431 }
01432 
01433 void KoTextFormatCollection::remove( KoTextFormat *f )
01434 {
01435     if ( lastFormat == f )
01436     lastFormat = 0;
01437     if ( cres == f )
01438     cres = 0;
01439     if ( cachedFormat == f )
01440     cachedFormat = 0;
01441     cKey.remove( f->key() );
01442 }
01443 
01444 #if 0
01445 void KoTextFormatCollection::setPainter( QPainter *p )
01446 {
01447     QDictIterator<KoTextFormat> it( cKey );
01448     KoTextFormat *f;
01449     while ( ( f = it.current() ) ) {
01450     ++it;
01451     f->setPainter( p );
01452     }
01453 }
01454 #endif
01455 
01456 #ifndef NDEBUG
01457 void KoTextFormatCollection::debug()
01458 {
01459     kdDebug(32500) << "------------ KoTextFormatCollection: debug --------------- BEGIN" << endl;
01460     kdDebug(32500) << "Default Format: '" << defFormat->key() << "' (" << (void*)defFormat << "): realfont: " << QFontInfo( defFormat->font() ).family() << endl;
01461     QDictIterator<KoTextFormat> it( cKey );
01462     for ( ; it.current(); ++it ) {
01463          Q_ASSERT(it.currentKey() == it.current()->key());
01464          if(it.currentKey() != it.current()->key())
01465              kdDebug(32500) << "**** MISMATCH key=" << it.currentKey() << " (see line below for format)" << endl;
01466      it.current()->printDebug();
01467     }
01468     kdDebug(32500) << "------------ KoTextFormatCollection: debug --------------- END" << endl;
01469 }
01470 
01471 #endif
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Mar 11 11:47:44 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003