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