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 Wed Nov 17 06:54:18 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003