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