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