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