lib

KoTextFormat.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001-2006 David Faure <faure@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "KoTextFormat.h"
21#include "KoTextParag.h"
22#include "KoTextZoomHandler.h"
23#include "KoStyleCollection.h"
24#include "KoOasisContext.h"
25#include <KoGenStyles.h>
26#include <KoXmlNS.h>
27
28#include <tdeglobal.h>
29#include <kdebug.h>
30#include <tdelocale.h>
31
32#include <tqapplication.h>
33#include <tqregexp.h>
34#include <assert.h>
35
36void KoTextFormat::KoTextFormatPrivate::clearCache()
37{
38 delete m_screenFontMetrics; m_screenFontMetrics = 0L;
39 delete m_screenFont; m_screenFont = 0L;
40 delete m_refFontMetrics; m_refFontMetrics = 0L;
41 delete m_refFont; m_refFont = 0L;
42 m_refAscent = -1;
43 m_refDescent = -1;
44 m_refHeight = -1;
45 memset( m_screenWidths, 0, 256 * sizeof( ushort ) );
46}
47
49{
50 delete d->m_screenFontMetrics; d->m_screenFontMetrics = 0;
51 delete d->m_screenFont; d->m_screenFont = 0;
52 memset( d->m_screenWidths, 0, 256 * sizeof( ushort ) );
53}
54
55KoTextFormat::KoTextFormat()
56{
57 //linkColor = true;
58 ref = 0;
59 missp = false;
60 va = AlignNormal;
61 collection = 0;
63 fn.setStyleStrategy( TQFont::ForceOutline );
64 d = new KoTextFormatPrivate;
65 m_textUnderlineColor=TQColor();
66 m_underlineType = U_NONE;
67 m_strikeOutType = S_NONE;
68 m_underlineStyle = U_SOLID;
69 m_strikeOutStyle = S_SOLID;
70 m_language = TDEGlobal::locale()->language();
71 d->m_bHyphenation = false;
72 d->m_underLineWidth = 1.0;
73 d->m_shadowDistanceX = 0;
74 d->m_shadowDistanceY = 0;
75 d->m_relativeTextSize = 0.66;
76 d->m_offsetFromBaseLine= 0;
77 d->m_bWordByWord = false;
78 m_attributeFont = ATT_NONE;
80//#ifdef DEBUG_COLLECTION
81// kdDebug(32500) << "KoTextFormat simple ctor, no addRef, no generateKey ! " << this << endl;
82//#endif
83}
84
85KoTextFormat::KoTextFormat( const TQFont &f, const TQColor &c, const TQString &_language, bool hyphenation, KoTextFormatCollection *parent )
86 : fn( f ), col( c ) /*fm( TQFontMetrics( f ) ),*/ //linkColor( true )
87{
88#ifdef DEBUG_COLLECTION
89 kdDebug(32500) << "KoTextFormat with font & color & parent (" << parent << "), addRef. " << this << endl;
90#endif
91 int pointSize;
92 if ( f.pointSize() == -1 ) // font was set with a pixelsize, we need a pointsize!
93 pointSize = (int)( ( (double)fn.pixelSize() * 72.0 ) / (double)KoGlobal::dpiY() );
94 else
95 pointSize = f.pointSize();
96 fn.setPointSize( pointSize );
97 // WYSIWYG works much much better with scalable fonts -> force it to be scalable
98 fn.setStyleStrategy( TQFont::ForceOutline );
99 ref = 0;
100 collection = parent;
101 //leftBearing = fm.minLeftBearing();
102 //rightBearing = fm.minRightBearing();
103 //hei = fm.height();
104 //asc = fm.ascent();
105 //dsc = fm.descent();
106 missp = false;
107 va = AlignNormal;
109 d = new KoTextFormatPrivate;
110 m_textUnderlineColor = TQColor();
111 m_underlineType = U_NONE;
112 m_strikeOutType = S_NONE;
113 m_underlineStyle = U_SOLID;
114 m_strikeOutStyle = S_SOLID;
115 m_language = _language;
116 d->m_shadowDistanceX = 0;
117 d->m_shadowDistanceY = 0;
118 d->m_relativeTextSize= 0.66;
119 d->m_offsetFromBaseLine = 0;
120 d->m_bWordByWord = false;
121 d->m_charStyle = 0L;
122 d->m_bHyphenation = hyphenation;
123 d->m_underLineWidth = 1.0;
124 m_attributeFont = ATT_NONE;
126 generateKey();
127 addRef();
128}
129
130KoTextFormat::KoTextFormat( const TQFont &_font,
131 VerticalAlignment _valign,
132 const TQColor & _color,
133 const TQColor & _backGroundColor,
134 const TQColor & _underlineColor,
135 KoTextFormat::UnderlineType _underlineType,
136 KoTextFormat::UnderlineStyle _underlineStyle,
137 KoTextFormat::StrikeOutType _strikeOutType,
138 KoTextFormat::StrikeOutStyle _strikeOutStyle,
139 KoTextFormat::AttributeStyle _fontAttribute,
140 const TQString &_language,
141 double _relativeTextSize,
142 int _offsetFromBaseLine,
143 bool _wordByWord,
144 bool _hyphenation,
145 double _shadowDistanceX,
146 double _shadowDistanceY,
147 const TQColor& _shadowColor )
148{
149 ref = 0;
150 collection = 0;
151 fn = _font;
152 fn.setStyleStrategy( TQFont::ForceOutline );
153 col = _color;
154 missp = false;
155 va = _valign;
156 d = new KoTextFormatPrivate;
157 m_textBackColor = _backGroundColor;
158 m_textUnderlineColor = _underlineColor;
159 m_underlineType = _underlineType;
160 m_strikeOutType = _strikeOutType;
161 m_underlineStyle = _underlineStyle;
162 m_strikeOutStyle = _strikeOutStyle;
163 m_language = _language;
164 d->m_bHyphenation = _hyphenation;
165 d->m_underLineWidth = 1.0;
166 d->m_shadowDistanceX = _shadowDistanceX;
167 d->m_shadowDistanceY = _shadowDistanceY;
168 d->m_shadowColor = _shadowColor;
169 d->m_relativeTextSize = _relativeTextSize;
170 d->m_offsetFromBaseLine = _offsetFromBaseLine;
171 d->m_bWordByWord = _wordByWord;
172 m_attributeFont = _fontAttribute;
173 d->m_charStyle = 0L;
175 generateKey();
176 addRef();
177}
178
179KoTextFormat::KoTextFormat( const KoTextFormat &f )
180{
181 d = 0L;
182 operator=( f );
183}
184
185KoTextFormat::~KoTextFormat()
186{
188 // Removing a format that is in the collection is forbidden, in fact.
189 // It should have been removed from the collection before being deleted.
190#ifndef NDEBUG
191 if ( parent() && parent()->defaultFormat() ) // not when destroying the collection
192 assert( ! ( parent()->dict().find( key() ) == this ) );
193 // (has to be the same pointer, not only the same key)
194#endif
195 delete d;
197}
198
199KoTextFormat& KoTextFormat::operator=( const KoTextFormat &f )
200{
201#ifdef DEBUG_COLLECTION
202 kdDebug(32500) << "KoTextFormat::operator= " << this << " (copying " << &f << "). Will addRef" << endl;
203#endif
204 ref = 0;
205 collection = 0; // f might be in the collection, but we are not
206 fn = f.fn;
207 col = f.col;
208 //fm = f.fm;
209 //leftBearing = f.leftBearing;
210 //rightBearing = f.rightBearing;
211 //hei = f.hei;
212 //asc = f.asc;
213 //dsc = f.dsc;
214 missp = f.missp;
215 va = f.va;
216 m_key = f.m_key;
217 //linkColor = f.linkColor;
219 delete d;
220 d = new KoTextFormatPrivate;
221 m_textBackColor=f.m_textBackColor;
222 m_textUnderlineColor=f.m_textUnderlineColor;
223 m_underlineType = f.m_underlineType;
224 m_strikeOutType = f.m_strikeOutType;
225 m_underlineStyle = f.m_underlineStyle;
226 m_strikeOutStyle = f.m_strikeOutStyle;
227 m_language = f.m_language;
228 d->m_bHyphenation=f.d->m_bHyphenation;
229 d->m_underLineWidth=f.d->m_underLineWidth;
230 d->m_shadowDistanceX = f.d->m_shadowDistanceX;
231 d->m_shadowDistanceY = f.d->m_shadowDistanceY;
232 d->m_shadowColor = f.d->m_shadowColor;
233 d->m_relativeTextSize = f.d->m_relativeTextSize;
234 d->m_offsetFromBaseLine = f.d->m_offsetFromBaseLine;
235 d->m_bWordByWord = f.d->m_bWordByWord;
236 m_attributeFont = f.m_attributeFont;
237 d->m_charStyle = 0L;
239 addRef();
240 return *this;
241}
242
243// Helper for load
244static void importTextPosition( const TQString& text_position, double fontSize, KoTextFormat::VerticalAlignment& value, double& relativetextsize, int& offset, KoOasisContext& context )
245{
246 //OO: <vertical position (% or sub or super)> [<size as %>]
247 //Examples: "super" or "super 58%" or "82% 58%" (where 82% is the vertical position)
248 TQStringList lst = TQStringList::split( ' ', text_position );
249 if ( !lst.isEmpty() )
250 {
251 TQString textPos = lst.front().stripWhiteSpace();
252 TQString textSize;
253 lst.pop_front();
254 if ( !lst.isEmpty() )
255 textSize = lst.front().stripWhiteSpace();
256 // Workaround bug in KOffice-1.4: it saved '0% 66%' for normal text
257 if ( context.generator().startsWith( "KOffice/1.4" )
258 && text_position.startsWith( "0%" ) ) {
259 //kdDebug(32500) << "Detected koffice-1.4 bug in text-position, assuming Normal text" << endl;
260 value = KoTextFormat::AlignNormal;
261 return;
262 }
263
264 if ( textPos.endsWith("%") && textPos != "0% 100%" && textPos != "0%" )
265 {
266 textPos.truncate( textPos.length() - 1 );
267 double val = textPos.toDouble();
268 offset = tqRound( fontSize * val / 100.0 );
269 value = KoTextFormat::AlignCustom;
270 }
271 else if ( textPos == "super" )
272 value = KoTextFormat::AlignSuperScript;
273 else if ( textPos == "sub" )
274 value = KoTextFormat::AlignSubScript;
275 else
276 value = KoTextFormat::AlignNormal;
277 if ( !textSize.isEmpty() && textSize.endsWith("%") )
278 {
279 textSize.truncate( textSize.length() - 1 );
280 relativetextsize = textSize.toDouble() / 100; // e.g. 0.58
281 }
282 }
283 else
284 value = KoTextFormat::AlignNormal;
285}
286
287// OASIS 14.2.29
288static void importOasisUnderline( const TQString& type, const TQString& style,
289 KoTextFormat::UnderlineType& underline,
290 KoTextFormat::UnderlineStyle& styleline )
291{
292 if ( type == "single" )
293 underline = KoTextFormat::U_SIMPLE;
294 else if ( type == "double" )
295 underline = KoTextFormat::U_DOUBLE;
296 else if ( type == "none" )
297 underline = KoTextFormat::U_NONE;
298 else if ( style.isEmpty() || style == "none" )
299 underline = KoTextFormat::U_NONE;
300 else
301 underline = KoTextFormat::U_SIMPLE; // OO exports empty type, and style=solid, for normal underline
302
303 styleline = KoTextFormat::U_SOLID; // assume "solid" if unknown
304 if ( style == "dotted" )
305 styleline = KoTextFormat::U_DOT;
306 else if ( style == "dash"
307 || style == "long-dash" ) // not in kotext
308 styleline = KoTextFormat::U_DASH;
309 else if ( style == "dot-dash" )
310 styleline = KoTextFormat::U_DASH_DOT;
311 else if ( style == "dot-dot-dash" )
312 styleline = KoTextFormat::U_DASH_DOT_DOT;
313 else if ( style == "wave" )
314 underline = KoTextFormat::U_WAVE;
315
316 // TODO bold. But this is another attribute in OASIS (text-underline-width), which makes sense.
317 // We should separate them in kotext...
318}
319
320TQString exportOasisUnderline( KoTextFormat::UnderlineStyle styleline )
321{
322 switch( styleline ) {
323 case KoTextFormat::U_DOT:
324 return "dotted";
325 case KoTextFormat::U_DASH:
326 return "dash";
327 case KoTextFormat::U_DASH_DOT:
328 return "dot-dash";
329 case KoTextFormat::U_DASH_DOT_DOT:
330 return "dot-dot-dash";
331 default:
332 return "solid";
333 }
334}
335
336// Helper for load. Legacy OO format.
337static void importUnderline( const TQString& in,
338 KoTextFormat::UnderlineType& underline,
339 KoTextFormat::UnderlineStyle& styleline )
340{
341 underline = KoTextFormat::U_SIMPLE;
342 styleline = KoTextFormat::U_SOLID;
343 if ( in == "none" )
344 underline = KoTextFormat::U_NONE;
345 else if ( in == "single" )
346 styleline = KoTextFormat::U_SOLID;
347 else if ( in == "double" ) {
348 underline = KoTextFormat::U_DOUBLE;
349 }
350 else if ( in == "dotted" || in == "bold-dotted" ) // bold-dotted not in libkotext
351 styleline = KoTextFormat::U_DOT;
352 else if ( in == "dash"
353 // those are not in libkotext:
354 || in == "long-dash"
355 || in == "bold-dash"
356 || in == "bold-long-dash" )
357 styleline = KoTextFormat::U_DASH;
358 else if ( in == "dot-dash"
359 || in == "bold-dot-dash") // not in libkotext
360 styleline = KoTextFormat::U_DASH_DOT; // tricky ;)
361 else if ( in == "dot-dot-dash"
362 || in == "bold-dot-dot-dash") // not in libkotext
363 styleline = KoTextFormat::U_DASH_DOT_DOT; // this is getting fun...
364 else if ( in == "wave"
365 || in == "bold-wave" // not in libkotext
366 || in == "double-wave" // not in libkotext
367 || in == "small-wave" ) { // not in libkotext
368 underline = KoTextFormat::U_WAVE;
369 } else if( in == "bold" ) {
370 underline = KoTextFormat::U_SIMPLE_BOLD;
371 } else
372 kdWarning() << k_funcinfo << " unsupported text-underline value: " << in << endl;
373}
374
376{
377 KoStyleStack& styleStack = context.styleStack();
378 styleStack.setTypeProperties( "text" ); // load all style attributes from "style:text-properties"
379
380 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "color" ) ) { // 3.10.3
381 col.setNamedColor( styleStack.attributeNS( KoXmlNS::fo, "color" ) ); // #rrggbb format
382 }
383 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-family" ) // 3.10.9
384 || styleStack.hasAttributeNS( KoXmlNS::style, "font-name") ) { // 3.10.8
385 // Hmm, the remove "'" could break it's in the middle of the fontname...
386 TQString fontName = styleStack.attributeNS( KoXmlNS::fo, "font-family" ).remove( "'" );
387 if (fontName.isEmpty()) {
388 // ##### TODO. This is wrong. style:font-name refers to a font-decl entry.
389 // We have to look it up there, and retrieve _all_ font attributes from it, not just the name.
390 fontName = styleStack.attributeNS( KoXmlNS::style, "font-name" ).remove( "'" );
391 }
392 // 'Thorndale' is not known outside OpenOffice so we substitute it
393 // with 'Times New Roman' that looks nearly the same.
394 if ( fontName == "Thorndale" )
395 fontName = "Times New Roman";
396
397 fontName.remove(TQRegExp("\\sCE$")); // Arial CE -> Arial
398 fn.setFamily( fontName );
399 }
400 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-size" ) ) { // 3.10.14
401 double pointSize = styleStack.fontSize();
402 fn.setPointSizeFloat( pointSize );
403 }
404 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-weight" ) ) { // 3.10.24
405 TQString fontWeight = styleStack.attributeNS( KoXmlNS::fo, "font-weight" );
406 int boldness;
407 if ( fontWeight == "normal" )
408 boldness = 50;
409 else if ( fontWeight == "bold" )
410 boldness = 75;
411 else
412 // XSL/CSS has 100,200,300...900. Not the same scale as TQt!
413 // See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
414 boldness = fontWeight.toInt() / 10;
415 fn.setWeight( boldness );
416 }
417 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-style" ) ) // 3.10.19
418 if ( styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "italic" ||
419 styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "oblique" ) { // no difference in kotext
420 fn.setItalic( true );
421 }
422
423 d->m_bWordByWord = styleStack.attributeNS( KoXmlNS::style, "text-underline-mode" ) == "skip-white-space";
424 // TODO style:text-line-through-mode
425
426#if 0 // OO compat code, to move to OO import filter
427 d->m_bWordByWord = (styleStack.hasAttributeNS( KoXmlNS::fo, "score-spaces")) // 3.10.25
428 && (styleStack.attributeNS( KoXmlNS::fo, "score-spaces") == "false");
429 if( styleStack.hasAttributeNS( KoXmlNS::style, "text-crossing-out" )) { // 3.10.6
430 TQString strikeOutType = styleStack.attributeNS( KoXmlNS::style, "text-crossing-out" );
431 if( strikeOutType =="double-line")
432 m_strikeOutType = S_DOUBLE;
433 else if( strikeOutType =="single-line")
434 m_strikeOutType = S_SIMPLE;
435 else if( strikeOutType =="thick-line")
436 m_strikeOutType = S_SIMPLE_BOLD;
437 // not supported by KWord: "slash" and "X"
438 // not supported by OO: stylelines (solid, dash, dot, dashdot, dashdotdot)
439 }
440#endif
441 if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-underline-type" )
442 || styleStack.hasAttributeNS( KoXmlNS::style, "text-underline-style" ) ) { // OASIS 14.4.28
443 importOasisUnderline( styleStack.attributeNS( KoXmlNS::style, "text-underline-type" ),
444 styleStack.attributeNS( KoXmlNS::style, "text-underline-style" ),
445 m_underlineType, m_underlineStyle );
446 }
447 else if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-underline" ) ) { // OO compat (3.10.22), to be moved out
448 importUnderline( styleStack.attributeNS( KoXmlNS::style, "text-underline" ),
449 m_underlineType, m_underlineStyle );
450 }
451 TQString underLineColor = styleStack.attributeNS( KoXmlNS::style, "text-underline-color" ); // OO 3.10.23, OASIS 14.4.31
452 if ( !underLineColor.isEmpty() && underLineColor != "font-color" )
453 m_textUnderlineColor.setNamedColor( underLineColor );
454
455 if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-line-through-type" ) ) { // OASIS 14.4.7
456 // Reuse code for loading underlines, and convert to strikeout enum (if not wave)
457 UnderlineType uType; UnderlineStyle uStyle;
458 importOasisUnderline( styleStack.attributeNS( KoXmlNS::style, "text-line-through-type" ),
459 styleStack.attributeNS( KoXmlNS::style, "text-line-through-style" ),
460 uType, uStyle );
461 m_strikeOutType = S_NONE;
462 if ( uType != U_WAVE )
463 m_strikeOutType = (StrikeOutType)uType;
464 m_strikeOutStyle = (StrikeOutStyle)uStyle;
465 }
466
467 // Text position
468 va = AlignNormal;
469 d->m_relativeTextSize = 0.58;
470 d->m_offsetFromBaseLine = 0;
471 if( styleStack.hasAttributeNS( KoXmlNS::style, "text-position")) { // OO 3.10.7
472 importTextPosition( styleStack.attributeNS( KoXmlNS::style, "text-position"), fn.pointSizeFloat(),
473 va, d->m_relativeTextSize, d->m_offsetFromBaseLine, context );
474 }
475 // Small caps, lowercase, uppercase
476 m_attributeFont = ATT_NONE;
477 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-variant" ) // 3.10.1
478 || styleStack.hasAttributeNS( KoXmlNS::fo, "text-transform" ) ) { // 3.10.2
479 bool smallCaps = styleStack.attributeNS( KoXmlNS::fo, "font-variant" ) == "small-caps";
480 if ( smallCaps ) {
481 m_attributeFont = ATT_SMALL_CAPS;
482 } else {
483 TQString textTransform = styleStack.attributeNS( KoXmlNS::fo, "text-transform" );
484 if ( textTransform == "uppercase" )
485 m_attributeFont = ATT_UPPER;
486 else if ( textTransform == "lowercase" )
487 m_attributeFont = ATT_LOWER;
488 // TODO in KWord: "capitalize".
489 }
490 }
491 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "language") ) { // 3.10.17
492 m_language = styleStack.attributeNS( KoXmlNS::fo, "language");
493 const TQString country = styleStack.attributeNS( KoXmlNS::fo, "country" );
494 if ( !country.isEmpty() ) {
495 m_language += '_';
496 m_language += country;
497 }
498 }
499 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color") ) {
500 TQString tmp = styleStack.attributeNS( KoXmlNS::fo, "background-color");
501 if (tmp != "transparent")
502 m_textBackColor.setNamedColor( tmp );
503 }
504 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "text-shadow") ) { // 3.10.21
505 parseShadowFromCss( styleStack.attributeNS( KoXmlNS::fo, "text-shadow") );
506 }
507
508 d->m_bHyphenation = true;
509 if ( styleStack.hasAttributeNS( KoXmlNS::fo, "hyphenate" ) ) // it's a character property in OASIS (but not in OO-1.1)
510 d->m_bHyphenation = styleStack.attributeNS( KoXmlNS::fo, "hyphenate" ) == "true";
511
512 /*
513 Missing properties:
514 style:use-window-font-color, 3.10.4 - this is what KWord uses by default (fg color from the color style)
515 OO also switches to another color when necessary to avoid dark-on-dark and light-on-light cases.
516 (that is TODO in KWord)
517 style:text-outline, 3.10.5 - not implemented in kotext
518 style:font-family-generic, 3.10.10 - roman, swiss, modern -> map to a font?
519 style:font-style-name, 3.10.11 - can be ignored, says DV, the other ways to specify a font are more precise
520 style:font-pitch, 3.10.12 - fixed or variable -> map to a font?
521 style:font-charset, 3.10.14 - not necessary with TQt
522 style:font-size-rel, 3.10.15 - TODO in StyleStack::fontSize()
523 fo:letter-spacing, 3.10.16 - not implemented in kotext
524 style:text-relief, 3.10.20 - not implemented in kotext
525 style:letter-kerning, 3.10.20 - not implemented in kotext
526 style:text-blinking, 3.10.27 - not implemented in kotext IIRC
527 style:text-combine, 3.10.29/30 - not implemented, see http://www.w3.org/TR/WD-i18n-format/
528 style:text-emphasis, 3.10.31 - not implemented in kotext
529 style:text-scale, 3.10.33 - not implemented in kotext
530 style:text-rotation-angle, 3.10.34 - not implemented in kotext (kpr rotates whole objects)
531 style:text-rotation-scale, 3.10.35 - not implemented in kotext (kpr rotates whole objects)
532 style:punctuation-wrap, 3.10.36 - not implemented in kotext
533 */
534
535 d->m_underLineWidth = 1.0;
536
537 generateKey();
538 addRef();
539}
540
541void KoTextFormat::save( KoGenStyle& gs, KoSavingContext& context, KoTextFormat * refFormat ) const
542{
544 if ( !refFormat || this->color() != refFormat->color() )
545 {
546 gs.addProperty( "fo:color", col.isValid() ? col.name() : "#000000", tt );
547 }
548 if ( !refFormat || this->font().family() != refFormat->font().family() )
549 {
550 gs.addProperty( "style:font-name", fn.family(), tt );
551 context.addFontFace( fn.family() );
552 }
553 if ( !refFormat || this->pointSize() != refFormat->pointSize() )
554 {
555 gs.addPropertyPt( "fo:font-size", fn.pointSize(), tt );
556 }
557 int w = fn.weight();
558 if ( !refFormat || w != refFormat->font().weight() )
559 {
560 gs.addProperty( "fo:font-weight", w == 50 ? "normal" : w == 75 ? "bold" : TQString::number( tqRound( w / 10 ) * 100 ), tt );
561 }
562 if ( !refFormat || this->font().italic() != refFormat->font().italic() )
563 {
564 gs.addProperty( "fo:font-style", fn.italic() ? "italic" : "normal", tt );
565 }
566 if ( !refFormat || this->wordByWord() != refFormat->wordByWord() )
567 {
568 gs.addProperty( "style:text-underline-mode", d->m_bWordByWord ? "skip-white-space" : "continuous", tt );
569 }
570 if ( !refFormat || this->underlineType() != refFormat->underlineType()
571 || this->underlineStyle() !=refFormat->underlineStyle() )
572 {
573 gs.addProperty( "style:text-underline-type", m_underlineType == U_NONE ? "none" :
574 m_underlineType == U_DOUBLE ? "double" : "single", tt );
575 TQString styleline;
576 if ( m_underlineType == U_WAVE )
577 styleline = "wave";
578 else
579 styleline = exportOasisUnderline( m_underlineStyle );
580 gs.addProperty( "style:text-underline-style", m_underlineType == U_NONE ? "none" : styleline, tt );
581 }
582 if ( !refFormat || this->textUnderlineColor() !=refFormat->textUnderlineColor() )
583 {
584 gs.addProperty( "style:text-underline-color", m_textUnderlineColor.isValid() ? m_textUnderlineColor.name() : "font-color", tt );
585 }
586
587 if ( !refFormat
588 || this->strikeOutType() != refFormat->strikeOutType()
589 || this->strikeOutStyle()!= refFormat->strikeOutStyle() )
590 {
591 if ( m_strikeOutType != S_NONE )
592 {
593 // TODO U_SIMPLE_BOLD
594 // TODO style:text-line-through-mode
595 gs.addProperty( "style:text-line-through-type", m_strikeOutType == S_DOUBLE ? "double" : "single", tt );
596 const TQString styleline = exportOasisUnderline( (UnderlineStyle) m_strikeOutStyle );
597 gs.addProperty( "style:text-line-through-style", styleline, tt );
598 //gs.addProperty( "style:text-line-through-color", ...) TODO in kotext
599 }
600 else
601 {
602 gs.addProperty( "style:text-line-through-type", "none", tt );
603 gs.addProperty( "style:text-line-through-style", "none", tt );
604 }
605 }
606 if ( !refFormat || (this->vAlign() != refFormat->vAlign())
607 || (this->relativeTextSize() != refFormat->relativeTextSize()) )
608 {
609 TQString textPos;
610 if ( d->m_offsetFromBaseLine != 0 )
611 textPos = TQString::number( 100 * d->m_offsetFromBaseLine / fn.pointSizeFloat() ) + '%';
612 else if ( va == AlignSuperScript ) textPos = "super";
613 else if ( va == AlignSubScript ) textPos = "sub";
614 else textPos = "0%"; // AlignNormal
615 if ( va != AlignNormal )
616 {
617 textPos += ' ';
618 textPos += TQString::number( d->m_relativeTextSize * 100 );
619 textPos += '%';
620 }
621 gs.addProperty( "style:text-position", textPos, tt );
622 }
623
624 if( !refFormat || this->attributeFont() != refFormat->attributeFont())
625 {
626 if ( m_attributeFont == ATT_SMALL_CAPS ) {
627 gs.addProperty( "fo:font-variant", "small-caps", tt );
628 gs.addProperty( "fo:text-transform", "none", tt );
629 }
630 else if ( m_attributeFont == ATT_UPPER ) {
631 gs.addProperty( "fo:font-variant", "normal", tt );
632 gs.addProperty( "fo:text-transform", "uppercase", tt );
633 }
634 else if ( m_attributeFont == ATT_LOWER ) {
635 gs.addProperty( "fo:font-variant", "normal", tt );
636 gs.addProperty( "fo:text-transform", "lowercase", tt );
637 }
638 else {
639 gs.addProperty( "fo:font-variant", "normal", tt );
640 gs.addProperty( "fo:text-transform", "none", tt );
641 }
642 }
643
644 if( !refFormat || this->language() != refFormat->language())
645 {
646 TQString lang = m_language;
647 TQString country;
648 const int pos = lang.find( '_' );
649 if ( pos != -1 ) {
650 country = lang.mid( pos + 1 );
651 lang = lang.left( pos );
652 }
653
654 gs.addProperty( "fo:language", lang, tt );
655 gs.addProperty( "fo:country", country, tt );
656 }
657 if( !refFormat || this->textBackgroundColor() != refFormat->textBackgroundColor() )
658 {
659 gs.addProperty( "fo:background-color",
660 m_textBackColor.isValid() ? m_textBackColor.name() : "transparent", tt );
661 }
662 if( !refFormat ||
663 ( this->shadowDistanceX() != refFormat->shadowDistanceX()
664 || ( this->shadowDistanceY() != refFormat->shadowDistanceY() )
665 || ( this->shadowColor() != refFormat->shadowColor() ) ) )
666 {
667 gs.addProperty( "fo:text-shadow", shadowAsCss(), tt );
668 }
669 if ( !refFormat || this->hyphenation() != refFormat->hyphenation() )
670 {
671 gs.addProperty( "fo:hyphenate", d->m_bHyphenation, tt );
672 }
673}
674
675void KoTextFormat::update()
676{
677 //kdDebug(32500) << this << " KoTextFormat::update " << fn.family() << " " << pointSize() << endl;
678 m_key = TQString(); // invalidate key, recalc at the next key() call
679 assert( d );
680 d->clearCache(); // i.e. recalc at the next screenFont[Metrics]() call
681}
682
683void KoTextFormat::copyFormat( const KoTextFormat & nf, int flags )
684{
685 if ( flags & KoTextFormat::Bold )
686 fn.setBold( nf.fn.bold() );
687 if ( flags & KoTextFormat::Italic )
688 fn.setItalic( nf.fn.italic() );
689 if ( flags & KoTextFormat::Underline )
690 fn.setUnderline( nf.fn.underline() );
691 if ( flags & KoTextFormat::Family )
692 fn.setFamily( nf.fn.family() );
693 if ( flags & KoTextFormat::Size )
694 fn.setPointSize( nf.fn.pointSize() );
695 if ( flags & KoTextFormat::Color )
696 col = nf.col;
697 if ( flags & KoTextFormat::Misspelled )
698 missp = nf.missp;
699 if ( flags & KoTextFormat::VAlign )
700 {
701 va = nf.va;
702 setRelativeTextSize( nf.relativeTextSize());
703 }
705 if ( flags & KoTextFormat::StrikeOut )
706 {
707 setStrikeOutStyle( nf.strikeOutStyle() );
708 setStrikeOutType (nf.strikeOutType());
709 }
710 if( flags & KoTextFormat::TextBackgroundColor)
711 setTextBackgroundColor(nf.textBackgroundColor());
712 if( flags & KoTextFormat::ExtendUnderLine)
713 {
714 setTextUnderlineColor(nf.textUnderlineColor());
715 setUnderlineType (nf.underlineType());
716 setUnderlineStyle (nf.underlineStyle());
717 }
718 if( flags & KoTextFormat::Language)
719 setLanguage(nf.language());
720 if( flags & KoTextFormat::ShadowText)
721 setShadow(nf.shadowDistanceX(), nf.shadowDistanceY(), nf.shadowColor());
722 if( flags & KoTextFormat::OffsetFromBaseLine)
723 setOffsetFromBaseLine(nf.offsetFromBaseLine());
724 if( flags & KoTextFormat::WordByWord)
725 setWordByWord(nf.wordByWord());
726 if( flags & KoTextFormat::Attribute)
727 setAttributeFont(nf.attributeFont());
728 if( flags & KoTextFormat::Hyphenation )
729 setHyphenation( nf.hyphenation());
730 if( flags & KoTextFormat::UnderLineWidth )
731 setUnderLineWidth( nf.underLineWidth());
733 update();
734 //kdDebug(32500) << "KoTextFormat " << (void*)this << " copyFormat nf=" << (void*)&nf << " " << nf.key() << " flags=" << flags
735 // << " ==> result " << this << " " << key() << endl;
736}
737
738void KoTextFormat::setBold( bool b )
739{
740 if ( b == fn.bold() )
741 return;
742 fn.setBold( b );
743 update();
744}
745
746void KoTextFormat::setMisspelled( bool b )
747{
748 if ( b == (bool)missp )
749 return;
750 missp = b;
751 update();
752}
753
754void KoTextFormat::setVAlign( VerticalAlignment a )
755{
756 if ( a == va )
757 return;
758 va = a;
759 update();
760}
761
762void KoTextFormat::setItalic( bool b )
763{
764 if ( b == fn.italic() )
765 return;
766 fn.setItalic( b );
767 update();
768}
769
770void KoTextFormat::setUnderline( bool b )
771{
772 if ( b == fn.underline() )
773 return;
774 fn.setUnderline( b );
775 update();
776}
777
778void KoTextFormat::setFamily( const TQString &f )
779{
780 if ( f == fn.family() )
781 return;
782 fn.setFamily( f );
783 update();
784}
785
786void KoTextFormat::setPointSize( int s )
787{
788 if ( s == fn.pointSize() )
789 return;
790 fn.setPointSize( s );
791 update();
792}
793
794void KoTextFormat::setFont( const TQFont &f )
795{
796 if ( f == fn )
797 return;
798 fn = f;
799 fn.setStyleStrategy( TQFont::ForceOutline );
800 update();
801}
802
803void KoTextFormat::setColor( const TQColor &c )
804{
805 if ( c == col )
806 return;
807 col = c;
808 update();
809}
810
811#if 0
812int KoTextFormat::minLeftBearing() const
813{
814 if ( !painter || !painter->isActive() )
815 return leftBearing;
816 painter->setFont( fn );
817 return painter->fontMetrics().minLeftBearing();
818}
819
820int KoTextFormat::minRightBearing() const
821{
822 if ( !painter || !painter->isActive() )
823 return rightBearing;
824 painter->setFont( fn );
825 return painter->fontMetrics().minRightBearing();
826}
827#endif
828
829// ## Maybe we need a binary form for speed when NDEBUG, and to keep the
830// ## readable form when !NDEBUG, like TQFont does?
831void KoTextFormat::generateKey()
832{
833 TQString k = fn.key();
834 k += '/';
835 if ( col.isValid() ) // just to shorten the key in the common case
836 k += TQString::number( (uint)col.rgb() );
837 k += '/';
838 k += TQString::number( (int)isMisspelled() ); // 1 digit, no need for '/'
839 k += TQString::number( (int)vAlign() );
841 k += '/';
842 if (m_textBackColor.isValid())
843 k += TQString::number( (uint)m_textBackColor.rgb() );
844 k += '/';
845 if ( m_textUnderlineColor.isValid())
846 k += TQString::number( (uint)m_textUnderlineColor.rgb() );
847 k += '/';
848 k += TQString::number( (int)m_underlineType ); // a digit each, no need for '/'
849 k += TQString::number( (int)m_strikeOutType );
850 k += TQString::number( (int)m_underlineStyle );
851 k += TQString::number( (int)m_strikeOutStyle );
852 k += '/';
853 k += m_language;
854 k += '/';
855 if ( d->m_shadowDistanceX != 0 || d->m_shadowDistanceY != 0 )
856 {
857 k += TQString::number( d->m_shadowDistanceX );
858 k += '/';
859 k += TQString::number( d->m_shadowDistanceY );
860 k += '/';
861 k += TQString::number( (uint)d->m_shadowColor.rgb() );
862 }
863 k += '/';
864 k += TQString::number( d->m_relativeTextSize);
865 k += '/';
866 k += TQString::number( d->m_offsetFromBaseLine);
867 k += '/';
868 k += TQString::number( (int)d->m_bWordByWord); // boolean -> 1 digit -> no '/'
869 k += TQString::number( (int)m_attributeFont);
870 k += '/';
871 k += TQString::number( (int)d->m_bHyphenation); // boolean -> 1 digit -> no '/'
872 k += TQString::number( (double)d->m_underLineWidth);
874 // Keep in sync with method below
875 m_key = k;
876}
877
878// This is used to create "simple formats", with font and color etc., but without
879// advanced features. Doesn't matter, don't extend the args.
880TQString KoTextFormat::getKey( const TQFont &fn, const TQColor &col, bool misspelled, VerticalAlignment a )
881{
882 TQString k = fn.key();
883 k += '/';
884 if ( col.isValid() ) // just to shorten the key in the common case
885 k += TQString::number( (uint)col.rgb() );
886 k += '/';
887 k += TQString::number( (int)misspelled );
888 k += TQString::number( (int)a );
890 k += '/';
891 // no background color
892 k += '/';
893 // no underline color
894 k += '/';
895 k += TQString::number( (int)U_NONE );
896 k += TQString::number( (int)S_NONE ); // no double-underline in a "simple format"
897 k += TQString::number( (int)U_SOLID );
898 k += TQString::number( (int)S_SOLID ); // no double-underline in a "simple format"
899 k += '/';
900 //k += TQString(); // spellcheck language
901 k += '/';
902 //no shadow
903 k += '/';
904 k += "0.66"; //relative text size
905 k += '/';
906 k += "0"; // no offset from base line
907 k += '/';
908 k += "0"; //no wordbyword attribute
909 k += "0"; //no font attribute
910 k += '/';
911 k += "0"; //no hyphen
912 k += "0"; //no ulw
913
915 return k;
916}
917
918
919TQString KoTextFormat::key() const
920{
921 if ( m_key.isEmpty() )
922 const_cast<KoTextFormat*>( this )->generateKey();
923 return m_key;
924}
925
926void KoTextFormat::addRef()
927{
928 ref++;
929#ifdef DEBUG_COLLECTION
930 if ( collection )
931 kdDebug(32500) << " add ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
932#endif
933}
934
935void KoTextFormat::removeRef()
936{
937 ref--;
938 if ( !collection )
939 return;
940#ifdef DEBUG_COLLECTION
941 kdDebug(32500) << " remove ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
942#endif
943 if ( ref == 0 )
944 collection->remove( this );
945}
946
947void KoTextFormat::setStrikeOutType (StrikeOutType _type)
948{
949 if ( m_strikeOutType == _type )
950 return;
951 m_strikeOutType = _type;
952 update();
953}
954
955void KoTextFormat::setUnderlineType (UnderlineType _type)
956{
957 if ( m_underlineType == _type )
958 return;
959 m_underlineType = _type;
960 update();
961}
962
963void KoTextFormat::setUnderlineStyle (UnderlineStyle _type)
964{
965 if ( m_underlineStyle == _type )
966 return;
967 m_underlineStyle = _type;
968 update();
969}
970
971void KoTextFormat::setStrikeOutStyle( StrikeOutStyle _type )
972{
973 if ( m_strikeOutStyle == _type )
974 return;
975 m_strikeOutStyle = _type;
976 update();
977}
978
979void KoTextFormat::setTextBackgroundColor(const TQColor &_col)
980{
981 if(m_textBackColor==_col)
982 return;
983 m_textBackColor=_col;
984 update();
985}
986void KoTextFormat::setTextUnderlineColor(const TQColor &_col)
987{
988 if ( m_textUnderlineColor == _col )
989 return;
990 m_textUnderlineColor=_col;
991 update();
992}
993
994void KoTextFormat::setShadow( double shadowDistanceX, double shadowDistanceY, const TQColor& shadowColor )
995{
996 if ( d->m_shadowDistanceX == shadowDistanceX &&
997 d->m_shadowDistanceY == shadowDistanceY &&
998 d->m_shadowColor == shadowColor )
999 return;
1000 d->m_shadowDistanceX = shadowDistanceX;
1001 d->m_shadowDistanceY = shadowDistanceY;
1002 d->m_shadowColor = shadowColor;
1003 update();
1004}
1005
1006void KoTextFormat::setRelativeTextSize( double _size )
1007{
1008 if ( d->m_relativeTextSize == _size)
1009 return;
1010 d->m_relativeTextSize = _size;
1011 update();
1012}
1013
1014void KoTextFormat::setOffsetFromBaseLine( int _offset )
1015{
1016 if ( d->m_offsetFromBaseLine == _offset)
1017 return;
1018 d->m_offsetFromBaseLine = _offset;
1019 update();
1020}
1021
1022void KoTextFormat::setWordByWord( bool _b )
1023{
1024 if ( d->m_bWordByWord == _b)
1025 return;
1026 d->m_bWordByWord = _b;
1027 update();
1028}
1029
1030
1031void KoTextFormat::setAttributeFont(KoTextFormat::AttributeStyle _att )
1032{
1033 if ( m_attributeFont == _att)
1034 return;
1035 m_attributeFont = _att;
1036 update();
1037
1038}
1039
1040int KoTextFormat::compare( const KoTextFormat & format ) const
1041{
1042 int flags = 0;
1043 if ( fn.weight() != format.fn.weight() )
1044 flags |= KoTextFormat::Bold;
1045 if ( fn.italic() != format.fn.italic() )
1046 flags |= KoTextFormat::Italic;
1047 if ( textUnderlineColor()!=format.textUnderlineColor() ||
1048 underlineType()!= format.underlineType() ||
1049 underlineStyle() != format.underlineStyle())
1050 flags |= KoTextFormat::ExtendUnderLine;
1051 if ( fn.family() != format.fn.family() )
1052 flags |= KoTextFormat::Family;
1053 if ( pointSize() != format.pointSize() )
1054 flags |= KoTextFormat::Size;
1055 if ( color() != format.color() )
1056 flags |= KoTextFormat::Color;
1057 if ( vAlign() != format.vAlign() ||
1058 relativeTextSize() != format.relativeTextSize())
1059 flags |= KoTextFormat::VAlign;
1060 if ( strikeOutType() != format.strikeOutType()
1061 || underlineStyle() != format.underlineStyle())
1062 flags |= KoTextFormat::StrikeOut;
1063 if ( textBackgroundColor() != format.textBackgroundColor() )
1064 flags |= KoTextFormat::TextBackgroundColor;
1065 if ( language() != format.language() )
1066 flags |= KoTextFormat::Language;
1067 if ( d->m_shadowDistanceX != format.shadowDistanceX()
1068 || d->m_shadowDistanceY != format.shadowDistanceY()
1069 || d->m_shadowColor != format.shadowColor() )
1070 flags |= KoTextFormat::ShadowText;
1071 if ( offsetFromBaseLine() != format.offsetFromBaseLine() )
1072 flags |= KoTextFormat::OffsetFromBaseLine;
1073 if ( wordByWord() != format.wordByWord() )
1074 flags |= KoTextFormat::WordByWord;
1075 if ( attributeFont() != format.attributeFont() )
1076 flags |= KoTextFormat::Attribute;
1077 if( hyphenation() != format.hyphenation() )
1078 flags |= KoTextFormat::Hyphenation;
1079 if( underLineWidth() != format.underLineWidth() )
1080 flags |= KoTextFormat::UnderLineWidth;
1081 return flags;
1082}
1083
1084TQColor KoTextFormat::defaultTextColor( TQPainter * painter )
1085{
1086 if ( painter->device()->devType() == TQInternal::Printer )
1087 return TQt::black;
1088 return TQApplication::palette().color( TQPalette::Active, TQColorGroup::Text );
1089}
1090
1092{
1093 // ## simplify (needs a change in KoTextZoomHandler)
1094 int pointSizeLU = KoTextZoomHandler::ptToLayoutUnitPt( pointSize() );
1095 if ( vAlign() != KoTextFormat::AlignNormal )
1096 pointSizeLU = (int)( pointSizeLU *relativeTextSize() );
1097 return zh->layoutUnitToFontSize( pointSizeLU, false /* forPrint */ );
1098}
1099
1101{
1102 if ( vAlign() != KoTextFormat::AlignNormal )
1103 return (float)pointSize() * relativeTextSize();
1104 else
1105 return pointSize();
1106}
1107
1109{
1110 float pointSize = refPointSize();
1111 if ( !d->m_refFont || pointSize != d->m_refFont->pointSizeFloat() )
1112 {
1113 delete d->m_refFont;
1114 d->m_refFont = new TQFont( font() );
1115 d->m_refFont->setPointSizeFloat( pointSize );
1116 delete d->m_refFontMetrics;
1117 d->m_refFontMetrics = 0;
1118 //kdDebug(32500) << "KoTextFormat::refFont created new font with size " << pointSize << endl;
1119 }
1120 return *d->m_refFont;
1121}
1122
1124{
1125 float pointSize = screenPointSize( zh );
1126 //kdDebug(32500) << "KoTextFormat::screenFont pointSize=" << pointSize << endl;
1127 // Compare if this is the size for which we cached the font metrics.
1128 // We have to do this very dynamically, because 2 views could be painting the same
1129 // stuff, with different zoom levels. So no absolute caching possible.
1130 /*if ( d->m_screenFont )
1131 kdDebug(32500) << " d->m_screenFont->pointSizeFloat()=" << d->m_screenFont->pointSizeFloat() << endl;*/
1132 if ( !d->m_screenFont || kAbs( pointSize - d->m_screenFont->pointSizeFloat() ) > 1E-4 )
1133 {
1134 delete d->m_screenFont;
1135 d->m_screenFont = new TQFont( font() );
1136 d->m_screenFont->setPointSizeFloat( pointSize );
1137 delete d->m_screenFontMetrics;
1138 d->m_screenFontMetrics = 0;
1139 //kdDebug(32500) << "KoTextFormat::screenFont created new font with size " << pointSize << endl;
1140 }
1141 return *d->m_screenFont;
1142}
1143
1144const TQFontMetrics& KoTextFormat::screenFontMetrics( const KoTextZoomHandler* zh ) const
1145{
1146 TQFont f = screenFont(zh); // don't move inside the if!
1147
1148 if ( !d->m_screenFontMetrics ) // not calculated, or invalidated by screenFont above
1149 {
1150 //kdDebug(32500) << this << " KoTextFormat::screenFontMetrics pointSize=" << pointSize << " d->m_screenFont->pointSizeFloat()=" << d->m_screenFont->pointSizeFloat() << endl;
1151 d->m_screenFontMetrics = new TQFontMetrics( f );
1152 //kdDebug(32500) << "KoTextFormat::screenFontMetrics created new metrics with size " << pointSize << " height:" << d->m_screenFontMetrics->height() << endl;
1153 }
1154 return *d->m_screenFontMetrics;
1155}
1156
1157const TQFontMetrics& KoTextFormat::refFontMetrics() const
1158{
1159 TQFont f = refFont();
1160
1161 if ( !d->m_refFontMetrics )
1162 {
1163 //kdDebug(32500) << this << " KoTextFormat::refFontMetrics pointSize=" << pointSize << " d->m_refFont->pointSizeFloat()=" << d->m_refFont->pointSizeFloat() << endl;
1164 d->m_refFontMetrics = new TQFontMetrics( f );
1165 //kdDebug(32500) << "KoTextFormat::refFontMetrics created new metrics with size " << pointSize << " height:" << d->m_refFontMetrics->height() << endl;
1166 }
1167 return *d->m_refFontMetrics;
1168}
1169
1170TQFont KoTextFormat::smallCapsFont( const KoTextZoomHandler* zh, bool applyZoom ) const
1171{
1172 TQFont font = applyZoom ? screenFont( zh ) : refFont();
1173 TQFontMetrics fm = refFontMetrics(); // only used for proportions, so applyZoom doesn't matter
1174 double pointSize = font.pointSize() * ((double)fm.boundingRect("x").height()/(double)fm.boundingRect("X").height());
1175 font.setPointSizeFloat( pointSize );
1176 return font;
1177}
1178
1179int KoTextFormat::charWidth( const KoTextZoomHandler* zh, bool applyZoom, const KoTextStringChar* c,
1180 const KoTextParag* parag, int i ) const
1181{
1182 ushort unicode = c->c.unicode();
1183 if ( !c->charStop || unicode == 0xad || unicode == 0x2028 )
1184 return 0;
1185 Q_ASSERT( !c->isCustom() ); // actually it's a bit stupid to call this for custom items
1186 if( c->isCustom() ) {
1187 if( c->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
1188 // customitem width is in LU pixels. Convert to 100%-zoom-pixels (pt2pt==pix2pix)
1189 double w = KoTextZoomHandler::layoutUnitPtToPt( c->customItem()->width );
1190 return tqRound( applyZoom ? ( w * zh->zoomFactorX() ) : w );
1191 }
1192 else
1193 return 0;
1194 }
1195 int pixelww;
1196 int r = c->c.row();
1197 if( /*r < 0x06 || r > 0x1f*/ r < 0x06 || (r > 0x1f && !(r > 0xd7 && r < 0xe0)) )
1198 {
1199 // Small caps -> we can't use the cached font metrics from KoTextFormat
1200 if ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.upper() != c->c )
1201 {
1202 pixelww = TQFontMetrics( smallCapsFont( zh, applyZoom ) ).width( displayedChar( c->c ) );
1203 }
1204 else
1205 // Use the cached font metrics from KoTextFormat
1206 if ( applyZoom )
1207 {
1208 if ( r ) {
1209 pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
1210 } else {
1211 // Use the m_screenWidths[] array when possible, even faster
1212 Q_ASSERT( unicode < 256 );
1213 pixelww = d->m_screenWidths[ unicode ];
1214 // Not in cache yet -> calculate
1215 if ( pixelww == 0 ) {
1216 pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
1217 Q_ASSERT( pixelww < 65535 );
1218 d->m_screenWidths[ unicode ] = pixelww;
1219 }
1220 }
1221 }
1222 else {
1223 pixelww = this->refFontMetrics().width( displayedChar( c->c ) );
1224 }
1225 }
1226 else {
1227 // Complex text. We need some hacks to get the right metric here
1228 bool smallCaps = ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.upper() != c->c );
1229 const TQFontMetrics& fontMetrics = smallCaps ? smallCapsFont( zh, applyZoom ) : applyZoom ? screenFontMetrics( zh ) : refFontMetrics();
1230 TQString str;
1231 int pos = 0;
1232 if( i > 8 )
1233 pos = i - 8;
1234 int off = i - pos;
1235 int end = TQMIN( parag->length(), i + 8 );
1236 while ( pos < end ) {
1237 str += displayedChar( parag->at(pos)->c );
1238 pos++;
1239 }
1240 pixelww = fontMetrics.charWidth( str, off );
1241 }
1242
1243#if 0
1244 kdDebug(32500) << "KoTextFormat::charWidth: char=" << TQString(c->c) << " format=" << key()
1245 << ", applyZoom=" << applyZoom << " pixel-width=" << pixelww << endl;
1246#endif
1247 return pixelww;
1248}
1249
1250int KoTextFormat::height() const
1251{
1252 if ( d->m_refHeight < 0 )
1253 {
1254 // Calculate height using 100%-zoom font
1255 int h = refFontMetrics().height()+TQABS(offsetFromBaseLine());
1256 if ( vAlign() == KoTextFormat::AlignSuperScript )
1257 h += refFontMetrics().height()/2;
1258 else if ( vAlign() == KoTextFormat::AlignSubScript )
1259 h += refFontMetrics().height()/6;
1260
1261 // Add room for the shadow
1262 if ( d->m_shadowDistanceY != 0 ) {
1263 // pt -> pixel (at 100% zoom)
1264 h += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiY() ) ) * TQABS( d->m_shadowDistanceY ) );
1265 }
1266
1267 //kdDebug(32500) << "KoTextFormat::height 100%-zoom font says h=" << h << " in LU:" << KoTextZoomHandler::ptToLayoutUnitPt(h) << endl;
1268 // Then scale to LU
1269 d->m_refHeight = tqRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
1270 }
1271 return d->m_refHeight;
1272}
1273
1274int KoTextFormat::offsetX() const // in LU pixels
1275{
1276 int off = 0;
1277#if 0
1278 // Shadow on left -> character is moved to the right
1279 // Wrong if next char has no shadow (they'll run into each other)
1280 // Somehow we should only do this if x == 0 (in the formatter)
1281 if ( d->m_shadowDistanceX < 0 )
1282 {
1283 double lupt = KoTextZoomHandler::ptToLayoutUnitPt( TQABS( d->m_shadowDistanceX ) );
1284 off += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiX() ) ) * lupt );
1285 }
1286#endif
1287 return off;
1288}
1289
1290int KoTextFormat::offsetY() const // in LU pixels
1291{
1292 int off = 0;
1293#if 0
1294 // Shadow on top -> character is moved down
1295 if ( d->m_shadowDistanceY < 0 )
1296 {
1297 double lupt = KoTextZoomHandler::ptToLayoutUnitPt( TQABS( d->m_shadowDistanceY ) );
1298 off += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiY() ) ) * lupt );
1299 }
1300#endif
1301 return off;
1302}
1303
1304TQString KoTextFormat::displayedString( const TQString& str )const
1305{
1306 switch ( m_attributeFont ) {
1307 case ATT_NONE:
1308 return str;
1309 case ATT_UPPER:
1310 case ATT_SMALL_CAPS:
1311 return str.upper();
1312 case ATT_LOWER:
1313 return str.lower();
1314 default:
1315 kdDebug(32500)<<" Error in AttributeStyle \n";
1316 return str;
1317 }
1318}
1319
1320TQChar KoTextFormat::displayedChar( TQChar c )const
1321{
1322 if ( c.unicode() == 0xa0 ) // nbsp
1323 return ' ';
1324 switch ( m_attributeFont ) {
1325 case ATT_NONE:
1326 return c;
1327 case ATT_SMALL_CAPS:
1328 case ATT_UPPER:
1329 return c.upper();
1330 case ATT_LOWER:
1331 return c.lower();
1332 default:
1333 kdDebug(32500)<<" Error in AttributeStyle \n";
1334 return c;
1335 }
1336}
1337
1338int KoTextFormat::ascent() const
1339{
1340 if ( d->m_refAscent < 0 )
1341 {
1342 // Calculate ascent using 100%-zoom font
1343 int h = refFontMetrics().ascent();
1344 if ( offsetFromBaseLine()>0 )
1345 h += offsetFromBaseLine();
1346 if ( vAlign() == KoTextFormat::AlignSuperScript )
1347 h += refFontMetrics().height()/2;
1348 // Then scale to LU
1349 d->m_refAscent = tqRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
1350 //d->m_refAscent += offsetY();
1351 }
1352 return d->m_refAscent;
1353}
1354
1355int KoTextFormat::descent() const
1356{
1357 if ( d->m_refDescent < 0 )
1358 {
1359 // Calculate descent using 100%-zoom font
1360 int h = refFontMetrics().descent();
1361 if ( offsetFromBaseLine()<0 )
1362 h -= offsetFromBaseLine();
1363 // Then scale to LU
1364 d->m_refDescent = tqRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
1365 //d->m_refDescent += offsetY();
1366 }
1367 return d->m_refDescent;
1368}
1369
1370int KoTextFormat::charWidthLU( const KoTextStringChar* c, const KoTextParag* parag, int i ) const
1371{
1372 // Hmm, we add precision to the least precise one!
1373 // TODO: We should instead implement it here in LU, and let charWidth call it...
1374 return KoTextZoomHandler::ptToLayoutUnitPt( charWidth( 0L, false, c, parag, i ) );
1375}
1376
1377int KoTextFormat::width( const TQChar& ch ) const
1378{
1379 // Warning this doesn't take into account the shadow
1381}
1382
1383void KoTextFormat::applyCharStyle( KoCharStyle *_style )
1384{
1385 d->m_charStyle = _style;
1386}
1387
1388KoCharStyle *KoTextFormat::style() const
1389{
1390 return d->m_charStyle;
1391}
1392
1393TQString KoTextFormat::shadowAsCss( double shadowDistanceX, double shadowDistanceY, const TQColor& shadowColor )
1394{
1395 // http://www.w3.org/TR/REC-CSS2/text.html#text-shadow-props
1396 // none | [<color> || <length (h)> <length (v)> <length (blur radius, not used here)>] ...
1397 // => none or color length length
1398 if ( shadowDistanceX != 0 || shadowDistanceY != 0 )
1399 {
1400 TQString css = shadowColor.name() + " ";
1401 css += TQString::number(shadowDistanceX) + "pt ";
1402 css += TQString::number(shadowDistanceY) + "pt";
1403 return css;
1404 }
1405 return "none";
1406}
1407
1409{
1410 return shadowAsCss( d->m_shadowDistanceX, d->m_shadowDistanceY, d->m_shadowColor );
1411}
1412
1413void KoTextFormat::parseShadowFromCss( const TQString& _css )
1414{
1415 TQString css = _css.simplifyWhiteSpace();
1416 if ( css.isEmpty() || css == "none" )
1417 {
1418 d->m_shadowDistanceX = 0;
1419 d->m_shadowDistanceY = 0;
1420 d->m_shadowColor = TQColor();
1421 } else
1422 {
1423 TQStringList tokens = TQStringList::split(' ', css);
1424 if ( tokens.isEmpty() ) {
1425 kdWarning(32500) << "Parse error in text-shadow: " << css << endl;
1426 return;
1427 }
1428 // Check which token looks like a color
1429 TQColor col( tokens.first() );
1430 if ( col.isValid() )
1431 tokens.pop_front();
1432 else if ( tokens.count() > 1 )
1433 {
1434 col.setNamedColor( tokens.last() );
1435 if ( col.isValid() )
1436 tokens.pop_back();
1437 }
1438 d->m_shadowColor = col; // whether valid or not
1439 // Parse x distance
1440 if ( !tokens.isEmpty() ) {
1441 d->m_shadowDistanceX = KoUnit::parseValue( tokens.first() );
1442 tokens.pop_front();
1443 }
1444 // Parse y distance
1445 if ( !tokens.isEmpty() ) {
1446 d->m_shadowDistanceY = KoUnit::parseValue( tokens.first() );
1447 tokens.pop_front();
1448 }
1449 // We ignore whatever else is in the string (e.g. blur radius, other shadows)
1450
1451 }
1452 update();
1453}
1454
1455TQColor KoTextFormat::shadowColor() const
1456{
1457 if ( d->m_shadowColor.isValid() )
1458 return d->m_shadowColor;
1459 else // CSS says "[If] no color has been specified, the shadow will have the same color as the [text] itself"
1460 return col;
1461}
1462
1464{
1465 return zh->zoomItX( d->m_shadowDistanceX );
1466}
1467
1469{
1470 return zh->zoomItY( d->m_shadowDistanceY );
1471}
1472
1473//static
1474TQString KoTextFormat::underlineStyleToString( KoTextFormat::UnderlineStyle _lineType )
1475{
1476 TQString strLineType;
1477 switch ( _lineType )
1478 {
1479 case KoTextFormat::U_SOLID:
1480 strLineType ="solid";
1481 break;
1482 case KoTextFormat::U_DASH:
1483 strLineType ="dash";
1484 break;
1485 case KoTextFormat::U_DOT:
1486 strLineType ="dot";
1487 break;
1488 case KoTextFormat::U_DASH_DOT:
1489 strLineType="dashdot";
1490 break;
1491 case KoTextFormat::U_DASH_DOT_DOT:
1492 strLineType="dashdotdot";
1493 break;
1494 }
1495 return strLineType;
1496}
1497
1498TQString KoTextFormat::strikeOutStyleToString( KoTextFormat::StrikeOutStyle _lineType )
1499{
1500 TQString strLineType;
1501 switch ( _lineType )
1502 {
1503 case KoTextFormat::S_SOLID:
1504 strLineType ="solid";
1505 break;
1506 case KoTextFormat::S_DASH:
1507 strLineType ="dash";
1508 break;
1509 case KoTextFormat::S_DOT:
1510 strLineType ="dot";
1511 break;
1512 case KoTextFormat::S_DASH_DOT:
1513 strLineType="dashdot";
1514 break;
1515 case KoTextFormat::S_DASH_DOT_DOT:
1516 strLineType="dashdotdot";
1517 break;
1518 }
1519 return strLineType;
1520}
1521
1522KoTextFormat::UnderlineStyle KoTextFormat::stringToUnderlineStyle( const TQString & _str )
1523{
1524 if ( _str =="solid")
1525 return KoTextFormat::U_SOLID;
1526 else if ( _str =="dash" )
1527 return KoTextFormat::U_DASH;
1528 else if ( _str =="dot" )
1529 return KoTextFormat::U_DOT;
1530 else if ( _str =="dashdot")
1531 return KoTextFormat::U_DASH_DOT;
1532 else if ( _str=="dashdotdot")
1533 return KoTextFormat::U_DASH_DOT_DOT;
1534 else
1535 return KoTextFormat::U_SOLID;
1536}
1537
1538KoTextFormat::StrikeOutStyle KoTextFormat::stringToStrikeOutStyle( const TQString & _str )
1539{
1540 if ( _str =="solid")
1541 return KoTextFormat::S_SOLID;
1542 else if ( _str =="dash" )
1543 return KoTextFormat::S_DASH;
1544 else if ( _str =="dot" )
1545 return KoTextFormat::S_DOT;
1546 else if ( _str =="dashdot")
1547 return KoTextFormat::S_DASH_DOT;
1548 else if ( _str=="dashdotdot")
1549 return KoTextFormat::S_DASH_DOT_DOT;
1550 else
1551 return KoTextFormat::S_SOLID;
1552}
1553
1554TQString KoTextFormat::attributeFontToString( KoTextFormat::AttributeStyle _attr )
1555{
1556 if (_attr == KoTextFormat::ATT_NONE )
1557 return TQString("none");
1558 else if ( _attr == KoTextFormat::ATT_UPPER )
1559 return TQString("uppercase");
1560 else if ( _attr == KoTextFormat::ATT_LOWER )
1561 return TQString("lowercase");
1562 else if ( _attr == KoTextFormat::ATT_SMALL_CAPS )
1563 return TQString("smallcaps");
1564 else
1565 return TQString("none");
1566}
1567
1568KoTextFormat::AttributeStyle KoTextFormat::stringToAttributeFont( const TQString & _str )
1569{
1570 if ( _str == "none" )
1571 return KoTextFormat::ATT_NONE;
1572 else if ( _str == "uppercase")
1573 return KoTextFormat::ATT_UPPER;
1574 else if ( _str == "lowercase")
1575 return KoTextFormat::ATT_LOWER;
1576 else if ( _str == "smallcaps" )
1577 return KoTextFormat::ATT_SMALL_CAPS;
1578 else
1579 return KoTextFormat::ATT_NONE;
1580}
1581
1582
1583void KoTextFormat::setHyphenation( bool b )
1584{
1585 if ( d->m_bHyphenation == b )
1586 return;
1587 d->m_bHyphenation = b;
1588 update();
1589
1590}
1591
1592void KoTextFormat::setUnderLineWidth( double ulw )
1593{
1594 if ( d->m_underLineWidth == ulw )
1595 return;
1596 d->m_underLineWidth = ulw;
1597 update();
1598
1599}
1600
1601void KoTextFormat::setLanguage( const TQString & _lang)
1602{
1603 if ( m_language == _lang )
1604 return;
1605 m_language = _lang;
1606 update();
1607}
1608
1609TQStringList KoTextFormat::underlineTypeList()
1610{
1611 TQStringList lst;
1612 lst <<i18n("Underline Style", "None");
1613 lst <<i18n("Single");
1614 lst <<i18n("Double");
1615 lst <<i18n("Simple Bold");
1616 lst <<i18n("Wave");
1617 return lst;
1618}
1619
1620TQStringList KoTextFormat::strikeOutTypeList()
1621{
1622 TQStringList lst;
1623 lst <<i18n("Strikeout Style", "None");
1624 lst <<i18n("Single");
1625 lst <<i18n("Double");
1626 lst <<i18n("Simple Bold");
1627 return lst;
1628}
1629
1630TQStringList KoTextFormat::fontAttributeList()
1631{
1632 TQStringList lst;
1633 lst <<i18n("Normal");
1634 lst <<i18n("Uppercase");
1635 lst <<i18n("Lowercase");
1636 lst <<i18n("Small Caps");
1637 return lst;
1638}
1639
1640TQStringList KoTextFormat::underlineStyleList()
1641{
1642 TQStringList lst;
1643 lst <<"_________"; // SOLID
1644 lst <<"___ ___ __"; // DASH
1645 lst <<"_ _ _ _ _ _"; // DOT
1646 lst <<"___ _ ___ _"; // DASH_DOT
1647 lst <<"___ _ _ ___"; // DASH_DOT_DOT
1648 return lst;
1649}
1650
1651TQStringList KoTextFormat::strikeOutStyleList()
1652{
1653 TQStringList lst;
1654 lst <<"_________"; // SOLID
1655 lst <<"___ ___ __"; // DASH
1656 lst <<"_ _ _ _ _ _"; // DOT
1657 lst <<"___ _ ___ _"; // DASH_DOT
1658 lst <<"___ _ _ ___"; // DASH_DOT_DOT
1659 return lst;
1660}
1661
1662#ifndef NDEBUG
1663void KoTextFormat::printDebug()
1664{
1665 TQString col = color().isValid() ? color().name() : TQString("(default)");
1666 kdDebug(32500) << "format '" << key() << "' (" << (void*)this << "):"
1667 << " refcount: " << ref
1668 << " realfont: " << TQFontInfo( font() ).family()
1669 << " color: " << col << " shadow=" << shadowAsCss() << endl;
1670}
1671#endif
1672
1674
1675KoTextFormatCollection::KoTextFormatCollection()
1676 : cKey( 307 )//, sheet( 0 )
1677{
1678#ifdef DEBUG_COLLECTION
1679 kdDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
1680#endif
1681 defFormat = new KoTextFormat( TQApplication::font(), TQColor(), TDEGlobal::locale()->language(), false );
1682 lastFormat = cres = 0;
1683 cflags = -1;
1684 cKey.setAutoDelete( true );
1685 cachedFormat = 0;
1686}
1687
1688KoTextFormatCollection::KoTextFormatCollection( const TQFont& defaultFont, const TQColor& defaultColor, const TQString & defaultLanguage, bool defaultHyphenation )
1689 : cKey( 307 )
1690{
1691#ifdef DEBUG_COLLECTION
1692 kdDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
1693#endif
1694 defFormat = new KoTextFormat( defaultFont, defaultColor, defaultLanguage, defaultHyphenation );
1695 lastFormat = cres = 0;
1696 cflags = -1;
1697 cKey.setAutoDelete( true );
1698 cachedFormat = 0;
1699}
1700
1701KoTextFormatCollection::~KoTextFormatCollection()
1702{
1703#ifdef DEBUG_COLLECTION
1704 kdDebug(32500) << "KoTextFormatCollection::~KoTextFormatCollection " << this << endl;
1705#endif
1706 delete defFormat;
1707 defFormat = 0;
1708}
1709
1710KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *f )
1711{
1712 if ( f->parent() == this || f == defFormat ) {
1713#ifdef DEBUG_COLLECTION
1714 kdDebug(32500) << " format(f) need '" << f->key() << "', best case!" << endl;
1715#endif
1716 lastFormat = const_cast<KoTextFormat*>(f);
1717 lastFormat->addRef();
1718 return lastFormat;
1719 }
1720
1721 if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
1722#ifdef DEBUG_COLLECTION
1723 kdDebug(32500) << " format(f) need '" << f->key() << "', good case!" << endl;
1724#endif
1725 lastFormat->addRef();
1726 return lastFormat;
1727 }
1728
1729#if 0 // #### disabled, because if this format is not in the
1730 // formatcollection, it doesn't get the painter through
1731 // KoTextFormatCollection::setPainter() which breaks printing on
1732 // windows
1733 if ( f->isAnchor() ) {
1734 lastFormat = createFormat( *f );
1735 lastFormat->collection = 0;
1736 return lastFormat;
1737 }
1738#endif
1739
1740 KoTextFormat *fm = cKey.find( f->key() );
1741 if ( fm ) {
1742#ifdef DEBUG_COLLECTION
1743 kdDebug(32500) << " format(f) need '" << f->key() << "', normal case!" << endl;
1744#endif
1745 lastFormat = fm;
1746 lastFormat->addRef();
1747 return lastFormat;
1748 }
1749
1750 if ( f->key() == defFormat->key() )
1751 return defFormat;
1752
1753#ifdef DEBUG_COLLECTION
1754 kdDebug(32500) << " format(f) need '" << f->key() << "', worst case!" << endl;
1755#endif
1756 lastFormat = createFormat( *f );
1757 lastFormat->collection = this;
1758 cKey.insert( lastFormat->key(), lastFormat );
1759 Q_ASSERT( f->key() == lastFormat->key() );
1760 return lastFormat;
1761}
1762
1763KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *of, const KoTextFormat *nf, int flags )
1764{
1765 if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
1766#ifdef DEBUG_COLLECTION
1767 kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << "', best case!" << endl;
1768#endif
1769 cres->addRef();
1770 return cres;
1771 }
1772
1773#ifdef DEBUG_COLLECTION
1774 kdDebug(32500) << " format(of,nf," << flags << ") calling createFormat(of=" << of << " " << of->key() << ")" << endl;
1775#endif
1776 cres = createFormat( *of );
1777 kof = of->key();
1778 knf = nf->key();
1779 cflags = flags;
1780
1781#ifdef DEBUG_COLLECTION
1782 kdDebug(32500) << " format(of,nf," << flags << ") calling copyFormat(nf=" << nf << " " << nf->key() << ")" << endl;
1783#endif
1784 cres->copyFormat( *nf, flags );
1785
1786 KoTextFormat *fm = cKey.find( cres->key() );
1787 if ( !fm ) {
1788#ifdef DEBUG_COLLECTION
1789 kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", worst case!" << endl;
1790#endif
1791 cres->collection = this;
1792 cKey.insert( cres->key(), cres );
1793 } else {
1794#ifdef DEBUG_COLLECTION
1795 kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", good case!" << endl;
1796#endif
1797 delete cres;
1798 cres = fm;
1799 cres->addRef();
1800 }
1801
1802 return cres;
1803}
1804
1805#if 0
1806KoTextFormat *KoTextFormatCollection::format( const TQFont &f, const TQColor &c, const TQString & language, bool hyphen )
1807{
1808 if ( cachedFormat && cfont == f && ccol == c ) {
1809#ifdef DEBUG_COLLECTION
1810 kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - best case" << endl;
1811#endif
1812 cachedFormat->addRef();
1813 return cachedFormat;
1814 }
1815
1816 TQString key = KoTextFormat::getKey( f, c, false, KoTextFormat::AlignNormal );
1817 cachedFormat = cKey.find( key );
1818 cfont = f;
1819 ccol = c;
1820
1821 if ( cachedFormat ) {
1822#ifdef DEBUG_COLLECTION
1823 kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - good case" << endl;
1824#endif
1825 cachedFormat->addRef();
1826 return cachedFormat;
1827 }
1828
1829 if ( key == defFormat->key() )
1830 return defFormat;
1831
1832 cachedFormat = createFormat( f, c, language, hyphen );
1833 cachedFormat->collection = this;
1834 cKey.insert( cachedFormat->key(), cachedFormat );
1835 if ( cachedFormat->key() != key )
1836 kdWarning() << "ASSERT: keys for format not identical: '" << cachedFormat->key() << " '" << key << "'" << endl;
1837#ifdef DEBUG_COLLECTION
1838 kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - worst case" << endl;
1839#endif
1840 return cachedFormat;
1841}
1842#endif
1843
1844void KoTextFormatCollection::remove( KoTextFormat *f )
1845{
1846 if ( lastFormat == f )
1847 lastFormat = 0;
1848 if ( cres == f )
1849 cres = 0;
1850 if ( cachedFormat == f )
1851 cachedFormat = 0;
1852 cKey.remove( f->key() );
1853}
1854
1855void KoTextFormatCollection::zoomChanged()
1856{
1857 TQDictIterator<KoTextFormat> it( cKey );
1858 for ( ; it.current(); ++it ) {
1859 it.current()->zoomChanged();
1860 }
1861}
1862
1863#if 0
1864void KoTextFormatCollection::setPainter( TQPainter *p )
1865{
1866 TQDictIterator<KoTextFormat> it( cKey );
1867 KoTextFormat *f;
1868 while ( ( f = it.current() ) ) {
1869 ++it;
1870 f->setPainter( p );
1871 }
1872}
1873#endif
1874
1875#ifndef NDEBUG
1876void KoTextFormatCollection::debug()
1877{
1878 kdDebug(32500) << "------------ KoTextFormatCollection: debug --------------- BEGIN" << endl;
1879 kdDebug(32500) << "Default Format: '" << defFormat->key() << "' (" << (void*)defFormat << "): realfont: " << TQFontInfo( defFormat->font() ).family() << endl;
1880 TQDictIterator<KoTextFormat> it( cKey );
1881 for ( ; it.current(); ++it ) {
1882 Q_ASSERT(it.currentKey() == it.current()->key());
1883 if(it.currentKey() != it.current()->key())
1884 kdDebug(32500) << "**** MISMATCH key=" << it.currentKey() << " (see line below for format)" << endl;
1885 it.current()->printDebug();
1886 }
1887 kdDebug(32500) << "------------ KoTextFormatCollection: debug --------------- END" << endl;
1888}
1889#endif
A KoCharStyle is a set of formatting attributes (font, color, etc.) to be applied to a run of text.
A generic style, i.e.
PropertyType
The types of properties.
@ TextType
TextType is always text-properties.
void addProperty(const TQString &propName, const TQString &propValue, PropertyType type=DefaultType)
Add a property to the style.
void addPropertyPt(const TQString &propName, double propValue, PropertyType type=DefaultType)
Add a property which represents a distance, measured in pt The number is written out with the highest...
Used during loading of Oasis format (and discarded at the end of the loading).
Used during saving to Oasis format (and discarded at the end of the saving).
This class implements a stack for the different styles of an object.
bool hasAttributeNS(const char *nsURI, const char *localName, const char *detail=0) const
Check if any of the styles on the stack has an attribute called 'name'-'detail' where detail is e....
void setTypeProperties(const char *typeProperties)
Set the type of properties that will be looked for.
double fontSize() const
Special case for the current font size, due to special handling of fo:font-size="115%".
TQString attributeNS(const char *nsURI, const char *localName, const char *detail=0) const
Search for the attribute called 'name', starting on top of the stack, and return it.
Each character (KoTextStringChar) points to a KoTextFormat that defines the formatting of that charac...
void save(KoGenStyle &gs, KoSavingContext &context, KoTextFormat *refFormat=0) const
Save a text format to OASIS XML Only saves what differs from @refFormat, if set.
const TQFontMetrics & screenFontMetrics(const KoTextZoomHandler *zh) const
Returns the font metrics for the font used at the zoom & resolution given by 'zh'.
void parseShadowFromCss(const TQString &css)
Load shadow attributes from a css string, used when loading.
int shadowY(KoTextZoomHandler *zh) const
Return the amount of pixels for the vertical shadow distance at a given zoom level.
TQFont refFont() const
int charWidth(const KoTextZoomHandler *zh, bool applyZoom, const KoTextStringChar *c, const KoTextParag *parag, int i) const
Return the width of one char in one paragraph.
void load(KoOasisContext &context)
Load a text format from OASIS XML.
const TQFontMetrics & refFontMetrics() const
int width(const TQChar &c) const
Return the width of one char (from a string, not necessarily from a paragraph) in LU pixels.
float screenPointSize(const KoTextZoomHandler *zh) const
TQString shadowAsCss() const
Return css string for the shadow, used when saving.
int shadowX(KoTextZoomHandler *zh) const
Return the amount of pixels for the horizontal shadow distance at a given zoom level.
void zoomChanged()
Called when the zoom or resolution changes.
TQFont screenFont(const KoTextZoomHandler *zh) const
Returns the font to be used at the zoom & resolution given by 'zh'.
static TQColor defaultTextColor(TQPainter *painter)
Call this when a text color is set to 'invalid', meaning 'whatever the default for the color scheme i...
int charWidthLU(const KoTextStringChar *c, const KoTextParag *parag, int i) const
Return the width of one char in LU pixels.
int compare(const KoTextFormat &format) const
Return a set of flags showing the differences between this and 'format'.
float refPointSize() const
This class extends KoZoomHandler to add support for WYSIWYG text layouting.
double layoutUnitToFontSize(int luSize, bool) const
Given the font size for the font in layout units, in pt (use pointSize()) this returns the font size ...
static double ptToLayoutUnitPt(double pt)
Not zoom dependent.
static double parseValue(TQString value, double defaultVal=0.0)
parse common KOffice and OO values, like "10cm", "5mm" to pt
Definition KoUnit.cpp:148
double zoomFactorX() const
Zoom factor for X.
TDEAction * find(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)