You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1890 lines
63 KiB
1890 lines
63 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2001-2006 David Faure <faure@kde.org>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "KoTextFormat.h"
|
|
#include "KoTextParag.h"
|
|
#include "KoTextZoomHandler.h"
|
|
#include "KoStyleCollection.h"
|
|
#include "KoOasisContext.h"
|
|
#include <KoGenStyles.h>
|
|
#include <KoXmlNS.h>
|
|
|
|
#include <kglobal.h>
|
|
#include <kdebug.h>
|
|
#include <klocale.h>
|
|
|
|
#include <tqapplication.h>
|
|
#include <tqregexp.h>
|
|
#include <assert.h>
|
|
|
|
void KoTextFormat::KoTextFormatPrivate::clearCache()
|
|
{
|
|
delete m_screenFontMetrics; m_screenFontMetrics = 0L;
|
|
delete m_screenFont; m_screenFont = 0L;
|
|
delete m_refFontMetrics; m_refFontMetrics = 0L;
|
|
delete m_refFont; m_refFont = 0L;
|
|
m_refAscent = -1;
|
|
m_refDescent = -1;
|
|
m_refHeight = -1;
|
|
memset( m_screenWidths, 0, 256 * sizeof( ushort ) );
|
|
}
|
|
|
|
void KoTextFormat::zoomChanged()
|
|
{
|
|
delete d->m_screenFontMetrics; d->m_screenFontMetrics = 0;
|
|
delete d->m_screenFont; d->m_screenFont = 0;
|
|
memset( d->m_screenWidths, 0, 256 * sizeof( ushort ) );
|
|
}
|
|
|
|
KoTextFormat::KoTextFormat()
|
|
{
|
|
//linkColor = TRUE;
|
|
ref = 0;
|
|
missp = FALSE;
|
|
va = AlignNormal;
|
|
collection = 0;
|
|
//// kotext: WYSIWYG works much much better with scalable fonts -> force it to be scalable
|
|
fn.setStyleStrategy( TQFont::ForceOutline );
|
|
d = new KoTextFormatPrivate;
|
|
m_textUnderlineColor=TQColor();
|
|
m_underlineType = U_NONE;
|
|
m_strikeOutType = S_NONE;
|
|
m_underlineStyle = U_SOLID;
|
|
m_strikeOutStyle = S_SOLID;
|
|
m_language = KGlobal::locale()->language();
|
|
d->m_bHyphenation = false;
|
|
d->m_underLineWidth = 1.0;
|
|
d->m_shadowDistanceX = 0;
|
|
d->m_shadowDistanceY = 0;
|
|
d->m_relativeTextSize = 0.66;
|
|
d->m_offsetFromBaseLine= 0;
|
|
d->m_bWordByWord = false;
|
|
m_attributeFont = ATT_NONE;
|
|
////
|
|
//#ifdef DEBUG_COLLECTION
|
|
// kdDebug(32500) << "KoTextFormat simple ctor, no addRef, no generateKey ! " << this << endl;
|
|
//#endif
|
|
}
|
|
|
|
KoTextFormat::KoTextFormat( const TQFont &f, const TQColor &c, const TQString &_language, bool hyphenation, KoTextFormatCollection *parent )
|
|
: fn( f ), col( c ) /*fm( TQFontMetrics( f ) ),*/ //linkColor( TRUE )
|
|
{
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << "KoTextFormat with font & color & parent (" << parent << "), addRef. " << this << endl;
|
|
#endif
|
|
int pointSize;
|
|
if ( f.pointSize() == -1 ) // font was set with a pixelsize, we need a pointsize!
|
|
pointSize = (int)( ( (double)fn.pixelSize() * 72.0 ) / (double)KoGlobal::dpiY() );
|
|
else
|
|
pointSize = f.pointSize();
|
|
fn.setPointSize( pointSize );
|
|
// WYSIWYG works much much better with scalable fonts -> force it to be scalable
|
|
fn.setStyleStrategy( TQFont::ForceOutline );
|
|
ref = 0;
|
|
collection = parent;
|
|
//leftBearing = fm.minLeftBearing();
|
|
//rightBearing = fm.minRightBearing();
|
|
//hei = fm.height();
|
|
//asc = fm.ascent();
|
|
//dsc = fm.descent();
|
|
missp = FALSE;
|
|
va = AlignNormal;
|
|
//// kotext
|
|
d = new KoTextFormatPrivate;
|
|
m_textUnderlineColor = TQColor();
|
|
m_underlineType = U_NONE;
|
|
m_strikeOutType = S_NONE;
|
|
m_underlineStyle = U_SOLID;
|
|
m_strikeOutStyle = S_SOLID;
|
|
m_language = _language;
|
|
d->m_shadowDistanceX = 0;
|
|
d->m_shadowDistanceY = 0;
|
|
d->m_relativeTextSize= 0.66;
|
|
d->m_offsetFromBaseLine = 0;
|
|
d->m_bWordByWord = false;
|
|
d->m_charStyle = 0L;
|
|
d->m_bHyphenation = hyphenation;
|
|
d->m_underLineWidth = 1.0;
|
|
m_attributeFont = ATT_NONE;
|
|
////
|
|
generateKey();
|
|
addRef();
|
|
}
|
|
|
|
KoTextFormat::KoTextFormat( const TQFont &_font,
|
|
VerticalAlignment _valign,
|
|
const TQColor & _color,
|
|
const TQColor & _backGroundColor,
|
|
const TQColor & _underlineColor,
|
|
KoTextFormat::UnderlineType _underlineType,
|
|
KoTextFormat::UnderlineStyle _underlineStyle,
|
|
KoTextFormat::StrikeOutType _strikeOutType,
|
|
KoTextFormat::StrikeOutStyle _strikeOutStyle,
|
|
KoTextFormat::AttributeStyle _fontAttribute,
|
|
const TQString &_language,
|
|
double _relativeTextSize,
|
|
int _offsetFromBaseLine,
|
|
bool _wordByWord,
|
|
bool _hyphenation,
|
|
double _shadowDistanceX,
|
|
double _shadowDistanceY,
|
|
const TQColor& _shadowColor )
|
|
{
|
|
ref = 0;
|
|
collection = 0;
|
|
fn = _font;
|
|
fn.setStyleStrategy( TQFont::ForceOutline );
|
|
col = _color;
|
|
missp = false;
|
|
va = _valign;
|
|
d = new KoTextFormatPrivate;
|
|
m_textBackColor = _backGroundColor;
|
|
m_textUnderlineColor = _underlineColor;
|
|
m_underlineType = _underlineType;
|
|
m_strikeOutType = _strikeOutType;
|
|
m_underlineStyle = _underlineStyle;
|
|
m_strikeOutStyle = _strikeOutStyle;
|
|
m_language = _language;
|
|
d->m_bHyphenation = _hyphenation;
|
|
d->m_underLineWidth = 1.0;
|
|
d->m_shadowDistanceX = _shadowDistanceX;
|
|
d->m_shadowDistanceY = _shadowDistanceY;
|
|
d->m_shadowColor = _shadowColor;
|
|
d->m_relativeTextSize = _relativeTextSize;
|
|
d->m_offsetFromBaseLine = _offsetFromBaseLine;
|
|
d->m_bWordByWord = _wordByWord;
|
|
m_attributeFont = _fontAttribute;
|
|
d->m_charStyle = 0L;
|
|
////
|
|
generateKey();
|
|
addRef();
|
|
}
|
|
|
|
KoTextFormat::KoTextFormat( const KoTextFormat &f )
|
|
{
|
|
d = 0L;
|
|
operator=( f );
|
|
}
|
|
|
|
KoTextFormat::~KoTextFormat()
|
|
{
|
|
//// kotext addition
|
|
// Removing a format that is in the collection is forbidden, in fact.
|
|
// It should have been removed from the collection before being deleted.
|
|
#ifndef NDEBUG
|
|
if ( parent() && parent()->defaultFormat() ) // not when destroying the collection
|
|
assert( ! ( parent()->dict().find( key() ) == this ) );
|
|
// (has to be the same pointer, not only the same key)
|
|
#endif
|
|
delete d;
|
|
////
|
|
}
|
|
|
|
KoTextFormat& KoTextFormat::operator=( const KoTextFormat &f )
|
|
{
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << "KoTextFormat::operator= " << this << " (copying " << &f << "). Will addRef" << endl;
|
|
#endif
|
|
ref = 0;
|
|
collection = 0; // f might be in the collection, but we are not
|
|
fn = f.fn;
|
|
col = f.col;
|
|
//fm = f.fm;
|
|
//leftBearing = f.leftBearing;
|
|
//rightBearing = f.rightBearing;
|
|
//hei = f.hei;
|
|
//asc = f.asc;
|
|
//dsc = f.dsc;
|
|
missp = f.missp;
|
|
va = f.va;
|
|
m_key = f.m_key;
|
|
//linkColor = f.linkColor;
|
|
//// kotext addition
|
|
delete d;
|
|
d = new KoTextFormatPrivate;
|
|
m_textBackColor=f.m_textBackColor;
|
|
m_textUnderlineColor=f.m_textUnderlineColor;
|
|
m_underlineType = f.m_underlineType;
|
|
m_strikeOutType = f.m_strikeOutType;
|
|
m_underlineStyle = f.m_underlineStyle;
|
|
m_strikeOutStyle = f.m_strikeOutStyle;
|
|
m_language = f.m_language;
|
|
d->m_bHyphenation=f.d->m_bHyphenation;
|
|
d->m_underLineWidth=f.d->m_underLineWidth;
|
|
d->m_shadowDistanceX = f.d->m_shadowDistanceX;
|
|
d->m_shadowDistanceY = f.d->m_shadowDistanceY;
|
|
d->m_shadowColor = f.d->m_shadowColor;
|
|
d->m_relativeTextSize = f.d->m_relativeTextSize;
|
|
d->m_offsetFromBaseLine = f.d->m_offsetFromBaseLine;
|
|
d->m_bWordByWord = f.d->m_bWordByWord;
|
|
m_attributeFont = f.m_attributeFont;
|
|
d->m_charStyle = 0L;
|
|
////
|
|
addRef();
|
|
return *this;
|
|
}
|
|
|
|
// Helper for load
|
|
static void importTextPosition( const TQString& text_position, double fontSize, KoTextFormat::VerticalAlignment& value, double& relativetextsize, int& offset, KoOasisContext& context )
|
|
{
|
|
//OO: <vertical position (% or sub or super)> [<size as %>]
|
|
//Examples: "super" or "super 58%" or "82% 58%" (where 82% is the vertical position)
|
|
TQStringList lst = TQStringList::split( ' ', text_position );
|
|
if ( !lst.isEmpty() )
|
|
{
|
|
TQString textPos = lst.front().stripWhiteSpace();
|
|
TQString textSize;
|
|
lst.pop_front();
|
|
if ( !lst.isEmpty() )
|
|
textSize = lst.front().stripWhiteSpace();
|
|
// Workaround bug in KOffice-1.4: it saved '0% 66%' for normal text
|
|
if ( context.generator().startsWith( "KOffice/1.4" )
|
|
&& text_position.startsWith( "0%" ) ) {
|
|
//kdDebug(32500) << "Detected koffice-1.4 bug in text-position, assuming Normal text" << endl;
|
|
value = KoTextFormat::AlignNormal;
|
|
return;
|
|
}
|
|
|
|
if ( textPos.endsWith("%") && textPos != "0% 100%" && textPos != "0%" )
|
|
{
|
|
textPos.truncate( textPos.length() - 1 );
|
|
double val = textPos.toDouble();
|
|
offset = tqRound( fontSize * val / 100.0 );
|
|
value = KoTextFormat::AlignCustom;
|
|
}
|
|
else if ( textPos == "super" )
|
|
value = KoTextFormat::AlignSuperScript;
|
|
else if ( textPos == "sub" )
|
|
value = KoTextFormat::AlignSubScript;
|
|
else
|
|
value = KoTextFormat::AlignNormal;
|
|
if ( !textSize.isEmpty() && textSize.endsWith("%") )
|
|
{
|
|
textSize.truncate( textSize.length() - 1 );
|
|
relativetextsize = textSize.toDouble() / 100; // e.g. 0.58
|
|
}
|
|
}
|
|
else
|
|
value = KoTextFormat::AlignNormal;
|
|
}
|
|
|
|
// OASIS 14.2.29
|
|
static void importOasisUnderline( const TQString& type, const TQString& style,
|
|
KoTextFormat::UnderlineType& underline,
|
|
KoTextFormat::UnderlineStyle& styleline )
|
|
{
|
|
if ( type == "single" )
|
|
underline = KoTextFormat::U_SIMPLE;
|
|
else if ( type == "double" )
|
|
underline = KoTextFormat::U_DOUBLE;
|
|
else if ( type == "none" )
|
|
underline = KoTextFormat::U_NONE;
|
|
else if ( style.isEmpty() || style == "none" )
|
|
underline = KoTextFormat::U_NONE;
|
|
else
|
|
underline = KoTextFormat::U_SIMPLE; // OO exports empty type, and style=solid, for normal underline
|
|
|
|
styleline = KoTextFormat::U_SOLID; // assume "solid" if unknown
|
|
if ( style == "dotted" )
|
|
styleline = KoTextFormat::U_DOT;
|
|
else if ( style == "dash"
|
|
|| style == "long-dash" ) // not in kotext
|
|
styleline = KoTextFormat::U_DASH;
|
|
else if ( style == "dot-dash" )
|
|
styleline = KoTextFormat::U_DASH_DOT;
|
|
else if ( style == "dot-dot-dash" )
|
|
styleline = KoTextFormat::U_DASH_DOT_DOT;
|
|
else if ( style == "wave" )
|
|
underline = KoTextFormat::U_WAVE;
|
|
|
|
// TODO bold. But this is another attribute in OASIS (text-underline-width), which makes sense.
|
|
// We should separate them in kotext...
|
|
}
|
|
|
|
TQString exportOasisUnderline( KoTextFormat::UnderlineStyle styleline )
|
|
{
|
|
switch( styleline ) {
|
|
case KoTextFormat::U_DOT:
|
|
return "dotted";
|
|
case KoTextFormat::U_DASH:
|
|
return "dash";
|
|
case KoTextFormat::U_DASH_DOT:
|
|
return "dot-dash";
|
|
case KoTextFormat::U_DASH_DOT_DOT:
|
|
return "dot-dot-dash";
|
|
default:
|
|
return "solid";
|
|
}
|
|
}
|
|
|
|
// Helper for load. Legacy OO format.
|
|
static void importUnderline( const TQString& in,
|
|
KoTextFormat::UnderlineType& underline,
|
|
KoTextFormat::UnderlineStyle& styleline )
|
|
{
|
|
underline = KoTextFormat::U_SIMPLE;
|
|
styleline = KoTextFormat::U_SOLID;
|
|
if ( in == "none" )
|
|
underline = KoTextFormat::U_NONE;
|
|
else if ( in == "single" )
|
|
styleline = KoTextFormat::U_SOLID;
|
|
else if ( in == "double" ) {
|
|
underline = KoTextFormat::U_DOUBLE;
|
|
}
|
|
else if ( in == "dotted" || in == "bold-dotted" ) // bold-dotted not in libkotext
|
|
styleline = KoTextFormat::U_DOT;
|
|
else if ( in == "dash"
|
|
// those are not in libkotext:
|
|
|| in == "long-dash"
|
|
|| in == "bold-dash"
|
|
|| in == "bold-long-dash" )
|
|
styleline = KoTextFormat::U_DASH;
|
|
else if ( in == "dot-dash"
|
|
|| in == "bold-dot-dash") // not in libkotext
|
|
styleline = KoTextFormat::U_DASH_DOT; // tricky ;)
|
|
else if ( in == "dot-dot-dash"
|
|
|| in == "bold-dot-dot-dash") // not in libkotext
|
|
styleline = KoTextFormat::U_DASH_DOT_DOT; // this is getting fun...
|
|
else if ( in == "wave"
|
|
|| in == "bold-wave" // not in libkotext
|
|
|| in == "double-wave" // not in libkotext
|
|
|| in == "small-wave" ) { // not in libkotext
|
|
underline = KoTextFormat::U_WAVE;
|
|
} else if( in == "bold" ) {
|
|
underline = KoTextFormat::U_SIMPLE_BOLD;
|
|
} else
|
|
kdWarning() << k_funcinfo << " unsupported text-underline value: " << in << endl;
|
|
}
|
|
|
|
void KoTextFormat::load( KoOasisContext& context )
|
|
{
|
|
KoStyleStack& styleStack = context.styleStack();
|
|
styleStack.setTypeProperties( "text" ); // load all style attributes from "style:text-properties"
|
|
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "color" ) ) { // 3.10.3
|
|
col.setNamedColor( styleStack.attributeNS( KoXmlNS::fo, "color" ) ); // #rrggbb format
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-family" ) // 3.10.9
|
|
|| styleStack.hasAttributeNS( KoXmlNS::style, "font-name") ) { // 3.10.8
|
|
// Hmm, the remove "'" could break it's in the middle of the fontname...
|
|
TQString fontName = styleStack.attributeNS( KoXmlNS::fo, "font-family" ).remove( "'" );
|
|
if (fontName.isEmpty()) {
|
|
// ##### TODO. This is wrong. style:font-name refers to a font-decl entry.
|
|
// We have to look it up there, and retrieve _all_ font attributes from it, not just the name.
|
|
fontName = styleStack.attributeNS( KoXmlNS::style, "font-name" ).remove( "'" );
|
|
}
|
|
// 'Thorndale' is not known outside OpenOffice so we substitute it
|
|
// with 'Times New Roman' that looks nearly the same.
|
|
if ( fontName == "Thorndale" )
|
|
fontName = "Times New Roman";
|
|
|
|
fontName.remove(TQRegExp("\\sCE$")); // Arial CE -> Arial
|
|
fn.setFamily( fontName );
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-size" ) ) { // 3.10.14
|
|
double pointSize = styleStack.fontSize();
|
|
fn.setPointSizeFloat( pointSize );
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-weight" ) ) { // 3.10.24
|
|
TQString fontWeight = styleStack.attributeNS( KoXmlNS::fo, "font-weight" );
|
|
int boldness;
|
|
if ( fontWeight == "normal" )
|
|
boldness = 50;
|
|
else if ( fontWeight == "bold" )
|
|
boldness = 75;
|
|
else
|
|
// XSL/CSS has 100,200,300...900. Not the same scale as TQt!
|
|
// See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
|
|
boldness = fontWeight.toInt() / 10;
|
|
fn.setWeight( boldness );
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-style" ) ) // 3.10.19
|
|
if ( styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "italic" ||
|
|
styleStack.attributeNS( KoXmlNS::fo, "font-style" ) == "oblique" ) { // no difference in kotext
|
|
fn.setItalic( true );
|
|
}
|
|
|
|
d->m_bWordByWord = styleStack.attributeNS( KoXmlNS::style, "text-underline-mode" ) == "skip-white-space";
|
|
// TODO style:text-line-through-mode
|
|
|
|
#if 0 // OO compat code, to move to OO import filter
|
|
d->m_bWordByWord = (styleStack.hasAttributeNS( KoXmlNS::fo, "score-spaces")) // 3.10.25
|
|
&& (styleStack.attributeNS( KoXmlNS::fo, "score-spaces") == "false");
|
|
if( styleStack.hasAttributeNS( KoXmlNS::style, "text-crossing-out" )) { // 3.10.6
|
|
TQString strikeOutType = styleStack.attributeNS( KoXmlNS::style, "text-crossing-out" );
|
|
if( strikeOutType =="double-line")
|
|
m_strikeOutType = S_DOUBLE;
|
|
else if( strikeOutType =="single-line")
|
|
m_strikeOutType = S_SIMPLE;
|
|
else if( strikeOutType =="thick-line")
|
|
m_strikeOutType = S_SIMPLE_BOLD;
|
|
// not supported by KWord: "slash" and "X"
|
|
// not supported by OO: stylelines (solid, dash, dot, dashdot, dashdotdot)
|
|
}
|
|
#endif
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-underline-type" )
|
|
|| styleStack.hasAttributeNS( KoXmlNS::style, "text-underline-style" ) ) { // OASIS 14.4.28
|
|
importOasisUnderline( styleStack.attributeNS( KoXmlNS::style, "text-underline-type" ),
|
|
styleStack.attributeNS( KoXmlNS::style, "text-underline-style" ),
|
|
m_underlineType, m_underlineStyle );
|
|
}
|
|
else if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-underline" ) ) { // OO compat (3.10.22), to be moved out
|
|
importUnderline( styleStack.attributeNS( KoXmlNS::style, "text-underline" ),
|
|
m_underlineType, m_underlineStyle );
|
|
}
|
|
TQString underLineColor = styleStack.attributeNS( KoXmlNS::style, "text-underline-color" ); // OO 3.10.23, OASIS 14.4.31
|
|
if ( !underLineColor.isEmpty() && underLineColor != "font-color" )
|
|
m_textUnderlineColor.setNamedColor( underLineColor );
|
|
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::style, "text-line-through-type" ) ) { // OASIS 14.4.7
|
|
// Reuse code for loading underlines, and convert to strikeout enum (if not wave)
|
|
UnderlineType uType; UnderlineStyle uStyle;
|
|
importOasisUnderline( styleStack.attributeNS( KoXmlNS::style, "text-line-through-type" ),
|
|
styleStack.attributeNS( KoXmlNS::style, "text-line-through-style" ),
|
|
uType, uStyle );
|
|
m_strikeOutType = S_NONE;
|
|
if ( uType != U_WAVE )
|
|
m_strikeOutType = (StrikeOutType)uType;
|
|
m_strikeOutStyle = (StrikeOutStyle)uStyle;
|
|
}
|
|
|
|
// Text position
|
|
va = AlignNormal;
|
|
d->m_relativeTextSize = 0.58;
|
|
d->m_offsetFromBaseLine = 0;
|
|
if( styleStack.hasAttributeNS( KoXmlNS::style, "text-position")) { // OO 3.10.7
|
|
importTextPosition( styleStack.attributeNS( KoXmlNS::style, "text-position"), fn.pointSizeFloat(),
|
|
va, d->m_relativeTextSize, d->m_offsetFromBaseLine, context );
|
|
}
|
|
// Small caps, lowercase, uppercase
|
|
m_attributeFont = ATT_NONE;
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "font-variant" ) // 3.10.1
|
|
|| styleStack.hasAttributeNS( KoXmlNS::fo, "text-transform" ) ) { // 3.10.2
|
|
bool smallCaps = styleStack.attributeNS( KoXmlNS::fo, "font-variant" ) == "small-caps";
|
|
if ( smallCaps ) {
|
|
m_attributeFont = ATT_SMALL_CAPS;
|
|
} else {
|
|
TQString textTransform = styleStack.attributeNS( KoXmlNS::fo, "text-transform" );
|
|
if ( textTransform == "uppercase" )
|
|
m_attributeFont = ATT_UPPER;
|
|
else if ( textTransform == "lowercase" )
|
|
m_attributeFont = ATT_LOWER;
|
|
// TODO in KWord: "capitalize".
|
|
}
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "language") ) { // 3.10.17
|
|
m_language = styleStack.attributeNS( KoXmlNS::fo, "language");
|
|
const TQString country = styleStack.attributeNS( KoXmlNS::fo, "country" );
|
|
if ( !country.isEmpty() ) {
|
|
m_language += '_';
|
|
m_language += country;
|
|
}
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color") ) {
|
|
TQString tmp = styleStack.attributeNS( KoXmlNS::fo, "background-color");
|
|
if (tmp != "transparent")
|
|
m_textBackColor.setNamedColor( tmp );
|
|
}
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "text-shadow") ) { // 3.10.21
|
|
parseShadowFromCss( styleStack.attributeNS( KoXmlNS::fo, "text-shadow") );
|
|
}
|
|
|
|
d->m_bHyphenation = true;
|
|
if ( styleStack.hasAttributeNS( KoXmlNS::fo, "hyphenate" ) ) // it's a character property in OASIS (but not in OO-1.1)
|
|
d->m_bHyphenation = styleStack.attributeNS( KoXmlNS::fo, "hyphenate" ) == "true";
|
|
|
|
/*
|
|
Missing properties:
|
|
style:use-window-font-color, 3.10.4 - this is what KWord uses by default (fg color from the color style)
|
|
OO also switches to another color when necessary to avoid dark-on-dark and light-on-light cases.
|
|
(that is TODO in KWord)
|
|
style:text-outline, 3.10.5 - not implemented in kotext
|
|
style:font-family-generic, 3.10.10 - roman, swiss, modern -> map to a font?
|
|
style:font-style-name, 3.10.11 - can be ignored, says DV, the other ways to specify a font are more precise
|
|
style:font-pitch, 3.10.12 - fixed or variable -> map to a font?
|
|
style:font-charset, 3.10.14 - not necessary with TQt
|
|
style:font-size-rel, 3.10.15 - TODO in StyleStack::fontSize()
|
|
fo:letter-spacing, 3.10.16 - not implemented in kotext
|
|
style:text-relief, 3.10.20 - not implemented in kotext
|
|
style:letter-kerning, 3.10.20 - not implemented in kotext
|
|
style:text-blinking, 3.10.27 - not implemented in kotext IIRC
|
|
style:text-combine, 3.10.29/30 - not implemented, see http://www.w3.org/TR/WD-i18n-format/
|
|
style:text-emphasis, 3.10.31 - not implemented in kotext
|
|
style:text-scale, 3.10.33 - not implemented in kotext
|
|
style:text-rotation-angle, 3.10.34 - not implemented in kotext (kpr rotates whole objects)
|
|
style:text-rotation-scale, 3.10.35 - not implemented in kotext (kpr rotates whole objects)
|
|
style:punctuation-wrap, 3.10.36 - not implemented in kotext
|
|
*/
|
|
|
|
d->m_underLineWidth = 1.0;
|
|
|
|
generateKey();
|
|
addRef();
|
|
}
|
|
|
|
void KoTextFormat::save( KoGenStyle& gs, KoSavingContext& context, KoTextFormat * refFormat ) const
|
|
{
|
|
KoGenStyle::PropertyType tt = KoGenStyle::TextType;
|
|
if ( !refFormat || this->color() != refFormat->color() )
|
|
{
|
|
gs.addProperty( "fo:color", col.isValid() ? col.name() : "#000000", tt );
|
|
}
|
|
if ( !refFormat || this->font().family() != refFormat->font().family() )
|
|
{
|
|
gs.addProperty( "style:font-name", fn.family(), tt );
|
|
context.addFontFace( fn.family() );
|
|
}
|
|
if ( !refFormat || this->pointSize() != refFormat->pointSize() )
|
|
{
|
|
gs.addPropertyPt( "fo:font-size", fn.pointSize(), tt );
|
|
}
|
|
int w = fn.weight();
|
|
if ( !refFormat || w != refFormat->font().weight() )
|
|
{
|
|
gs.addProperty( "fo:font-weight", w == 50 ? "normal" : w == 75 ? "bold" : TQString::number( tqRound( w / 10 ) * 100 ), tt );
|
|
}
|
|
if ( !refFormat || this->font().italic() != refFormat->font().italic() )
|
|
{
|
|
gs.addProperty( "fo:font-style", fn.italic() ? "italic" : "normal", tt );
|
|
}
|
|
if ( !refFormat || this->wordByWord() != refFormat->wordByWord() )
|
|
{
|
|
gs.addProperty( "style:text-underline-mode", d->m_bWordByWord ? "skip-white-space" : "continuous", tt );
|
|
}
|
|
if ( !refFormat || this->underlineType() != refFormat->underlineType()
|
|
|| this->underlineStyle() !=refFormat->underlineStyle() )
|
|
{
|
|
gs.addProperty( "style:text-underline-type", m_underlineType == U_NONE ? "none" :
|
|
m_underlineType == U_DOUBLE ? "double" : "single", tt );
|
|
TQString styleline;
|
|
if ( m_underlineType == U_WAVE )
|
|
styleline = "wave";
|
|
else
|
|
styleline = exportOasisUnderline( m_underlineStyle );
|
|
gs.addProperty( "style:text-underline-style", m_underlineType == U_NONE ? "none" : styleline, tt );
|
|
}
|
|
if ( !refFormat || this->textUnderlineColor() !=refFormat->textUnderlineColor() )
|
|
{
|
|
gs.addProperty( "style:text-underline-color", m_textUnderlineColor.isValid() ? m_textUnderlineColor.name() : "font-color", tt );
|
|
}
|
|
|
|
if ( !refFormat
|
|
|| this->strikeOutType() != refFormat->strikeOutType()
|
|
|| this->strikeOutStyle()!= refFormat->strikeOutStyle() )
|
|
{
|
|
if ( m_strikeOutType != S_NONE )
|
|
{
|
|
// TODO U_SIMPLE_BOLD
|
|
// TODO style:text-line-through-mode
|
|
gs.addProperty( "style:text-line-through-type", m_strikeOutType == S_DOUBLE ? "double" : "single", tt );
|
|
const TQString styleline = exportOasisUnderline( (UnderlineStyle) m_strikeOutStyle );
|
|
gs.addProperty( "style:text-line-through-style", styleline, tt );
|
|
//gs.addProperty( "style:text-line-through-color", ...) TODO in kotext
|
|
}
|
|
else
|
|
{
|
|
gs.addProperty( "style:text-line-through-type", "none", tt );
|
|
gs.addProperty( "style:text-line-through-style", "none", tt );
|
|
}
|
|
}
|
|
if ( !refFormat || (this->vAlign() != refFormat->vAlign())
|
|
|| (this->relativeTextSize() != refFormat->relativeTextSize()) )
|
|
{
|
|
TQString textPos;
|
|
if ( d->m_offsetFromBaseLine != 0 )
|
|
textPos = TQString::number( 100 * d->m_offsetFromBaseLine / fn.pointSizeFloat() ) + '%';
|
|
else if ( va == AlignSuperScript ) textPos = "super";
|
|
else if ( va == AlignSubScript ) textPos = "sub";
|
|
else textPos = "0%"; // AlignNormal
|
|
if ( va != AlignNormal )
|
|
{
|
|
textPos += ' ';
|
|
textPos += TQString::number( d->m_relativeTextSize * 100 );
|
|
textPos += '%';
|
|
}
|
|
gs.addProperty( "style:text-position", textPos, tt );
|
|
}
|
|
|
|
if( !refFormat || this->attributeFont() != refFormat->attributeFont())
|
|
{
|
|
if ( m_attributeFont == ATT_SMALL_CAPS ) {
|
|
gs.addProperty( "fo:font-variant", "small-caps", tt );
|
|
gs.addProperty( "fo:text-transform", "none", tt );
|
|
}
|
|
else if ( m_attributeFont == ATT_UPPER ) {
|
|
gs.addProperty( "fo:font-variant", "normal", tt );
|
|
gs.addProperty( "fo:text-transform", "uppercase", tt );
|
|
}
|
|
else if ( m_attributeFont == ATT_LOWER ) {
|
|
gs.addProperty( "fo:font-variant", "normal", tt );
|
|
gs.addProperty( "fo:text-transform", "lowercase", tt );
|
|
}
|
|
else {
|
|
gs.addProperty( "fo:font-variant", "normal", tt );
|
|
gs.addProperty( "fo:text-transform", "none", tt );
|
|
}
|
|
}
|
|
|
|
if( !refFormat || this->language() != refFormat->language())
|
|
{
|
|
TQString lang = m_language;
|
|
TQString country;
|
|
const int pos = lang.find( '_' );
|
|
if ( pos != -1 ) {
|
|
country = lang.mid( pos + 1 );
|
|
lang = lang.left( pos );
|
|
}
|
|
|
|
gs.addProperty( "fo:language", lang, tt );
|
|
gs.addProperty( "fo:country", country, tt );
|
|
}
|
|
if( !refFormat || this->textBackgroundColor() != refFormat->textBackgroundColor() )
|
|
{
|
|
gs.addProperty( "fo:background-color",
|
|
m_textBackColor.isValid() ? m_textBackColor.name() : "transparent", tt );
|
|
}
|
|
if( !refFormat ||
|
|
( this->shadowDistanceX() != refFormat->shadowDistanceX()
|
|
|| ( this->shadowDistanceY() != refFormat->shadowDistanceY() )
|
|
|| ( this->shadowColor() != refFormat->shadowColor() ) ) )
|
|
{
|
|
gs.addProperty( "fo:text-shadow", shadowAsCss(), tt );
|
|
}
|
|
if ( !refFormat || this->hyphenation() != refFormat->hyphenation() )
|
|
{
|
|
gs.addProperty( "fo:hyphenate", d->m_bHyphenation, tt );
|
|
}
|
|
}
|
|
|
|
void KoTextFormat::update()
|
|
{
|
|
//kdDebug(32500) << this << " KoTextFormat::update " << fn.family() << " " << pointSize() << endl;
|
|
m_key = TQString(); // tqinvalidate key, recalc at the next key() call
|
|
assert( d );
|
|
d->clearCache(); // i.e. recalc at the next screenFont[Metrics]() call
|
|
}
|
|
|
|
void KoTextFormat::copyFormat( const KoTextFormat & nf, int flags )
|
|
{
|
|
if ( flags & KoTextFormat::Bold )
|
|
fn.setBold( nf.fn.bold() );
|
|
if ( flags & KoTextFormat::Italic )
|
|
fn.setItalic( nf.fn.italic() );
|
|
if ( flags & KoTextFormat::Underline )
|
|
fn.setUnderline( nf.fn.underline() );
|
|
if ( flags & KoTextFormat::Family )
|
|
fn.setFamily( nf.fn.family() );
|
|
if ( flags & KoTextFormat::Size )
|
|
fn.setPointSize( nf.fn.pointSize() );
|
|
if ( flags & KoTextFormat::Color )
|
|
col = nf.col;
|
|
if ( flags & KoTextFormat::Misspelled )
|
|
missp = nf.missp;
|
|
if ( flags & KoTextFormat::VAlign )
|
|
{
|
|
va = nf.va;
|
|
setRelativeTextSize( nf.relativeTextSize());
|
|
}
|
|
////// kotext addition
|
|
if ( flags & KoTextFormat::StrikeOut )
|
|
{
|
|
setStrikeOutStyle( nf.strikeOutStyle() );
|
|
setStrikeOutType (nf.strikeOutType());
|
|
}
|
|
if( flags & KoTextFormat::TextBackgroundColor)
|
|
setTextBackgroundColor(nf.textBackgroundColor());
|
|
if( flags & KoTextFormat::ExtendUnderLine)
|
|
{
|
|
setTextUnderlineColor(nf.textUnderlineColor());
|
|
setUnderlineType (nf.underlineType());
|
|
setUnderlineStyle (nf.underlineStyle());
|
|
}
|
|
if( flags & KoTextFormat::Language)
|
|
setLanguage(nf.language());
|
|
if( flags & KoTextFormat::ShadowText)
|
|
setShadow(nf.shadowDistanceX(), nf.shadowDistanceY(), nf.shadowColor());
|
|
if( flags & KoTextFormat::OffsetFromBaseLine)
|
|
setOffsetFromBaseLine(nf.offsetFromBaseLine());
|
|
if( flags & KoTextFormat::WordByWord)
|
|
setWordByWord(nf.wordByWord());
|
|
if( flags & KoTextFormat::Attribute)
|
|
setAttributeFont(nf.attributeFont());
|
|
if( flags & KoTextFormat::Hyphenation )
|
|
setHyphenation( nf.hyphenation());
|
|
if( flags & KoTextFormat::UnderLineWidth )
|
|
setUnderLineWidth( nf.underLineWidth());
|
|
//////
|
|
update();
|
|
//kdDebug(32500) << "KoTextFormat " << (void*)this << " copyFormat nf=" << (void*)&nf << " " << nf.key() << " flags=" << flags
|
|
// << " ==> result " << this << " " << key() << endl;
|
|
}
|
|
|
|
void KoTextFormat::setBold( bool b )
|
|
{
|
|
if ( b == fn.bold() )
|
|
return;
|
|
fn.setBold( b );
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setMisspelled( bool b )
|
|
{
|
|
if ( b == (bool)missp )
|
|
return;
|
|
missp = b;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setVAlign( VerticalAlignment a )
|
|
{
|
|
if ( a == va )
|
|
return;
|
|
va = a;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setItalic( bool b )
|
|
{
|
|
if ( b == fn.italic() )
|
|
return;
|
|
fn.setItalic( b );
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setUnderline( bool b )
|
|
{
|
|
if ( b == fn.underline() )
|
|
return;
|
|
fn.setUnderline( b );
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setFamily( const TQString &f )
|
|
{
|
|
if ( f == fn.family() )
|
|
return;
|
|
fn.setFamily( f );
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setPointSize( int s )
|
|
{
|
|
if ( s == fn.pointSize() )
|
|
return;
|
|
fn.setPointSize( s );
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setFont( const TQFont &f )
|
|
{
|
|
if ( f == fn )
|
|
return;
|
|
fn = f;
|
|
fn.setStyleStrategy( TQFont::ForceOutline );
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setColor( const TQColor &c )
|
|
{
|
|
if ( c == col )
|
|
return;
|
|
col = c;
|
|
update();
|
|
}
|
|
|
|
#if 0
|
|
int KoTextFormat::minLeftBearing() const
|
|
{
|
|
if ( !painter || !painter->isActive() )
|
|
return leftBearing;
|
|
painter->setFont( fn );
|
|
return painter->fontMetrics().minLeftBearing();
|
|
}
|
|
|
|
int KoTextFormat::minRightBearing() const
|
|
{
|
|
if ( !painter || !painter->isActive() )
|
|
return rightBearing;
|
|
painter->setFont( fn );
|
|
return painter->fontMetrics().minRightBearing();
|
|
}
|
|
#endif
|
|
|
|
// ## Maybe we need a binary form for speed when NDEBUG, and to keep the
|
|
// ## readable form when !NDEBUG, like TQFont does?
|
|
void KoTextFormat::generateKey()
|
|
{
|
|
TQString k = fn.key();
|
|
k += '/';
|
|
if ( col.isValid() ) // just to shorten the key in the common case
|
|
k += TQString::number( (uint)col.rgb() );
|
|
k += '/';
|
|
k += TQString::number( (int)isMisspelled() ); // 1 digit, no need for '/'
|
|
k += TQString::number( (int)vAlign() );
|
|
//// kotext addition
|
|
k += '/';
|
|
if (m_textBackColor.isValid())
|
|
k += TQString::number( (uint)m_textBackColor.rgb() );
|
|
k += '/';
|
|
if ( m_textUnderlineColor.isValid())
|
|
k += TQString::number( (uint)m_textUnderlineColor.rgb() );
|
|
k += '/';
|
|
k += TQString::number( (int)m_underlineType ); // a digit each, no need for '/'
|
|
k += TQString::number( (int)m_strikeOutType );
|
|
k += TQString::number( (int)m_underlineStyle );
|
|
k += TQString::number( (int)m_strikeOutStyle );
|
|
k += '/';
|
|
k += m_language;
|
|
k += '/';
|
|
if ( d->m_shadowDistanceX != 0 || d->m_shadowDistanceY != 0 )
|
|
{
|
|
k += TQString::number( d->m_shadowDistanceX );
|
|
k += '/';
|
|
k += TQString::number( d->m_shadowDistanceY );
|
|
k += '/';
|
|
k += TQString::number( (uint)d->m_shadowColor.rgb() );
|
|
}
|
|
k += '/';
|
|
k += TQString::number( d->m_relativeTextSize);
|
|
k += '/';
|
|
k += TQString::number( d->m_offsetFromBaseLine);
|
|
k += '/';
|
|
k += TQString::number( (int)d->m_bWordByWord); // boolean -> 1 digit -> no '/'
|
|
k += TQString::number( (int)m_attributeFont);
|
|
k += '/';
|
|
k += TQString::number( (int)d->m_bHyphenation); // boolean -> 1 digit -> no '/'
|
|
k += TQString::number( (double)d->m_underLineWidth);
|
|
////
|
|
// Keep in sync with method below
|
|
m_key = k;
|
|
}
|
|
|
|
// This is used to create "simple formats", with font and color etc., but without
|
|
// advanced features. Doesn't matter, don't extend the args.
|
|
TQString KoTextFormat::getKey( const TQFont &fn, const TQColor &col, bool misspelled, VerticalAlignment a )
|
|
{
|
|
TQString k = fn.key();
|
|
k += '/';
|
|
if ( col.isValid() ) // just to shorten the key in the common case
|
|
k += TQString::number( (uint)col.rgb() );
|
|
k += '/';
|
|
k += TQString::number( (int)misspelled );
|
|
k += TQString::number( (int)a );
|
|
//// kotext addition
|
|
k += '/';
|
|
// no background color
|
|
k += '/';
|
|
// no underline color
|
|
k += '/';
|
|
k += TQString::number( (int)U_NONE );
|
|
k += TQString::number( (int)S_NONE ); // no double-underline in a "simple format"
|
|
k += TQString::number( (int)U_SOLID );
|
|
k += TQString::number( (int)S_SOLID ); // no double-underline in a "simple format"
|
|
k += '/';
|
|
//k += TQString(); // spellcheck language
|
|
k += '/';
|
|
//no shadow
|
|
k += '/';
|
|
k += "0.66"; //relative text size
|
|
k += '/';
|
|
k += "0"; // no offset from base line
|
|
k += '/';
|
|
k += "0"; //no wordbyword attribute
|
|
k += "0"; //no font attribute
|
|
k += '/';
|
|
k += "0"; //no hyphen
|
|
k += "0"; //no ulw
|
|
|
|
////
|
|
return k;
|
|
}
|
|
|
|
|
|
TQString KoTextFormat::key() const
|
|
{
|
|
if ( m_key.isEmpty() )
|
|
const_cast<KoTextFormat*>( this )->generateKey();
|
|
return m_key;
|
|
}
|
|
|
|
void KoTextFormat::addRef()
|
|
{
|
|
ref++;
|
|
#ifdef DEBUG_COLLECTION
|
|
if ( collection )
|
|
kdDebug(32500) << " add ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
|
|
#endif
|
|
}
|
|
|
|
void KoTextFormat::removeRef()
|
|
{
|
|
ref--;
|
|
if ( !collection )
|
|
return;
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " remove ref of '" << k << "' to " << ref << " (" << this << ") (coll " << collection << ")" << endl;
|
|
#endif
|
|
if ( ref == 0 )
|
|
collection->remove( this );
|
|
}
|
|
|
|
void KoTextFormat::setStrikeOutType (StrikeOutType _type)
|
|
{
|
|
if ( m_strikeOutType == _type )
|
|
return;
|
|
m_strikeOutType = _type;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setUnderlineType (UnderlineType _type)
|
|
{
|
|
if ( m_underlineType == _type )
|
|
return;
|
|
m_underlineType = _type;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setUnderlineStyle (UnderlineStyle _type)
|
|
{
|
|
if ( m_underlineStyle == _type )
|
|
return;
|
|
m_underlineStyle = _type;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setStrikeOutStyle( StrikeOutStyle _type )
|
|
{
|
|
if ( m_strikeOutStyle == _type )
|
|
return;
|
|
m_strikeOutStyle = _type;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setTextBackgroundColor(const TQColor &_col)
|
|
{
|
|
if(m_textBackColor==_col)
|
|
return;
|
|
m_textBackColor=_col;
|
|
update();
|
|
}
|
|
void KoTextFormat::setTextUnderlineColor(const TQColor &_col)
|
|
{
|
|
if ( m_textUnderlineColor == _col )
|
|
return;
|
|
m_textUnderlineColor=_col;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setShadow( double shadowDistanceX, double shadowDistanceY, const TQColor& shadowColor )
|
|
{
|
|
if ( d->m_shadowDistanceX == shadowDistanceX &&
|
|
d->m_shadowDistanceY == shadowDistanceY &&
|
|
d->m_shadowColor == shadowColor )
|
|
return;
|
|
d->m_shadowDistanceX = shadowDistanceX;
|
|
d->m_shadowDistanceY = shadowDistanceY;
|
|
d->m_shadowColor = shadowColor;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setRelativeTextSize( double _size )
|
|
{
|
|
if ( d->m_relativeTextSize == _size)
|
|
return;
|
|
d->m_relativeTextSize = _size;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setOffsetFromBaseLine( int _offset )
|
|
{
|
|
if ( d->m_offsetFromBaseLine == _offset)
|
|
return;
|
|
d->m_offsetFromBaseLine = _offset;
|
|
update();
|
|
}
|
|
|
|
void KoTextFormat::setWordByWord( bool _b )
|
|
{
|
|
if ( d->m_bWordByWord == _b)
|
|
return;
|
|
d->m_bWordByWord = _b;
|
|
update();
|
|
}
|
|
|
|
|
|
void KoTextFormat::setAttributeFont(KoTextFormat::AttributeStyle _att )
|
|
{
|
|
if ( m_attributeFont == _att)
|
|
return;
|
|
m_attributeFont = _att;
|
|
update();
|
|
|
|
}
|
|
|
|
int KoTextFormat::compare( const KoTextFormat & format ) const
|
|
{
|
|
int flags = 0;
|
|
if ( fn.weight() != format.fn.weight() )
|
|
flags |= KoTextFormat::Bold;
|
|
if ( fn.italic() != format.fn.italic() )
|
|
flags |= KoTextFormat::Italic;
|
|
if ( textUnderlineColor()!=format.textUnderlineColor() ||
|
|
underlineType()!= format.underlineType() ||
|
|
underlineStyle() != format.underlineStyle())
|
|
flags |= KoTextFormat::ExtendUnderLine;
|
|
if ( fn.family() != format.fn.family() )
|
|
flags |= KoTextFormat::Family;
|
|
if ( pointSize() != format.pointSize() )
|
|
flags |= KoTextFormat::Size;
|
|
if ( color() != format.color() )
|
|
flags |= KoTextFormat::Color;
|
|
if ( vAlign() != format.vAlign() ||
|
|
relativeTextSize() != format.relativeTextSize())
|
|
flags |= KoTextFormat::VAlign;
|
|
if ( strikeOutType() != format.strikeOutType()
|
|
|| underlineStyle() != format.underlineStyle())
|
|
flags |= KoTextFormat::StrikeOut;
|
|
if ( textBackgroundColor() != format.textBackgroundColor() )
|
|
flags |= KoTextFormat::TextBackgroundColor;
|
|
if ( language() != format.language() )
|
|
flags |= KoTextFormat::Language;
|
|
if ( d->m_shadowDistanceX != format.shadowDistanceX()
|
|
|| d->m_shadowDistanceY != format.shadowDistanceY()
|
|
|| d->m_shadowColor != format.shadowColor() )
|
|
flags |= KoTextFormat::ShadowText;
|
|
if ( offsetFromBaseLine() != format.offsetFromBaseLine() )
|
|
flags |= KoTextFormat::OffsetFromBaseLine;
|
|
if ( wordByWord() != format.wordByWord() )
|
|
flags |= KoTextFormat::WordByWord;
|
|
if ( attributeFont() != format.attributeFont() )
|
|
flags |= KoTextFormat::Attribute;
|
|
if( hyphenation() != format.hyphenation() )
|
|
flags |= KoTextFormat::Hyphenation;
|
|
if( underLineWidth() != format.underLineWidth() )
|
|
flags |= KoTextFormat::UnderLineWidth;
|
|
return flags;
|
|
}
|
|
|
|
TQColor KoTextFormat::defaultTextColor( TQPainter * painter )
|
|
{
|
|
if ( painter->device()->devType() == TQInternal::Printer )
|
|
return TQt::black;
|
|
return TQApplication::palette().color( TQPalette::Active, TQColorGroup::Text );
|
|
}
|
|
|
|
float KoTextFormat::screenPointSize( const KoTextZoomHandler* zh ) const
|
|
{
|
|
// ## simplify (needs a change in KoTextZoomHandler)
|
|
int pointSizeLU = KoTextZoomHandler::ptToLayoutUnitPt( pointSize() );
|
|
if ( vAlign() != KoTextFormat::AlignNormal )
|
|
pointSizeLU = (int)( pointSizeLU *relativeTextSize() );
|
|
return zh->layoutUnitToFontSize( pointSizeLU, false /* forPrint */ );
|
|
}
|
|
|
|
float KoTextFormat::refPointSize() const
|
|
{
|
|
if ( vAlign() != KoTextFormat::AlignNormal )
|
|
return (float)pointSize() * relativeTextSize();
|
|
else
|
|
return pointSize();
|
|
}
|
|
|
|
TQFont KoTextFormat::refFont() const
|
|
{
|
|
float pointSize = refPointSize();
|
|
if ( !d->m_refFont || pointSize != d->m_refFont->pointSizeFloat() )
|
|
{
|
|
delete d->m_refFont;
|
|
d->m_refFont = new TQFont( font() );
|
|
d->m_refFont->setPointSizeFloat( pointSize );
|
|
delete d->m_refFontMetrics;
|
|
d->m_refFontMetrics = 0;
|
|
//kdDebug(32500) << "KoTextFormat::refFont created new font with size " << pointSize << endl;
|
|
}
|
|
return *d->m_refFont;
|
|
}
|
|
|
|
TQFont KoTextFormat::screenFont( const KoTextZoomHandler* zh ) const
|
|
{
|
|
float pointSize = screenPointSize( zh );
|
|
//kdDebug(32500) << "KoTextFormat::screenFont pointSize=" << pointSize << endl;
|
|
// Compare if this is the size for which we cached the font metrics.
|
|
// We have to do this very dynamically, because 2 views could be painting the same
|
|
// stuff, with different zoom levels. So no absolute caching possible.
|
|
/*if ( d->m_screenFont )
|
|
kdDebug(32500) << " d->m_screenFont->pointSizeFloat()=" << d->m_screenFont->pointSizeFloat() << endl;*/
|
|
if ( !d->m_screenFont || kAbs( pointSize - d->m_screenFont->pointSizeFloat() ) > 1E-4 )
|
|
{
|
|
delete d->m_screenFont;
|
|
d->m_screenFont = new TQFont( font() );
|
|
d->m_screenFont->setPointSizeFloat( pointSize );
|
|
delete d->m_screenFontMetrics;
|
|
d->m_screenFontMetrics = 0;
|
|
//kdDebug(32500) << "KoTextFormat::screenFont created new font with size " << pointSize << endl;
|
|
}
|
|
return *d->m_screenFont;
|
|
}
|
|
|
|
const TQFontMetrics& KoTextFormat::screenFontMetrics( const KoTextZoomHandler* zh ) const
|
|
{
|
|
TQFont f = screenFont(zh); // don't move inside the if!
|
|
|
|
if ( !d->m_screenFontMetrics ) // not calculated, or invalidated by screenFont above
|
|
{
|
|
//kdDebug(32500) << this << " KoTextFormat::screenFontMetrics pointSize=" << pointSize << " d->m_screenFont->pointSizeFloat()=" << d->m_screenFont->pointSizeFloat() << endl;
|
|
d->m_screenFontMetrics = new TQFontMetrics( f );
|
|
//kdDebug(32500) << "KoTextFormat::screenFontMetrics created new metrics with size " << pointSize << " height:" << d->m_screenFontMetrics->height() << endl;
|
|
}
|
|
return *d->m_screenFontMetrics;
|
|
}
|
|
|
|
const TQFontMetrics& KoTextFormat::refFontMetrics() const
|
|
{
|
|
TQFont f = refFont();
|
|
|
|
if ( !d->m_refFontMetrics )
|
|
{
|
|
//kdDebug(32500) << this << " KoTextFormat::refFontMetrics pointSize=" << pointSize << " d->m_refFont->pointSizeFloat()=" << d->m_refFont->pointSizeFloat() << endl;
|
|
d->m_refFontMetrics = new TQFontMetrics( f );
|
|
//kdDebug(32500) << "KoTextFormat::refFontMetrics created new metrics with size " << pointSize << " height:" << d->m_refFontMetrics->height() << endl;
|
|
}
|
|
return *d->m_refFontMetrics;
|
|
}
|
|
|
|
TQFont KoTextFormat::smallCapsFont( const KoTextZoomHandler* zh, bool applyZoom ) const
|
|
{
|
|
TQFont font = applyZoom ? screenFont( zh ) : refFont();
|
|
TQFontMetrics fm = refFontMetrics(); // only used for proportions, so applyZoom doesn't matter
|
|
double pointSize = font.pointSize() * ((double)fm.boundingRect("x").height()/(double)fm.boundingRect("X").height());
|
|
font.setPointSizeFloat( pointSize );
|
|
return font;
|
|
}
|
|
|
|
int KoTextFormat::charWidth( const KoTextZoomHandler* zh, bool applyZoom, const KoTextStringChar* c,
|
|
const KoTextParag* parag, int i ) const
|
|
{
|
|
ushort tqunicode = c->c.tqunicode();
|
|
if ( !c->charStop || tqunicode == 0xad || tqunicode == 0x2028 )
|
|
return 0;
|
|
Q_ASSERT( !c->isCustom() ); // actually it's a bit stupid to call this for custom items
|
|
if( c->isCustom() ) {
|
|
if( c->customItem()->placement() == KoTextCustomItem::PlaceInline ) {
|
|
// customitem width is in LU pixels. Convert to 100%-zoom-pixels (pt2pt==pix2pix)
|
|
double w = KoTextZoomHandler::layoutUnitPtToPt( c->customItem()->width );
|
|
return tqRound( applyZoom ? ( w * zh->zoomFactorX() ) : w );
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
int pixelww;
|
|
int r = c->c.row();
|
|
if( /*r < 0x06 || r > 0x1f*/ r < 0x06 || (r > 0x1f && !(r > 0xd7 && r < 0xe0)) )
|
|
{
|
|
// Small caps -> we can't use the cached font metrics from KoTextFormat
|
|
if ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.upper() != c->c )
|
|
{
|
|
pixelww = TQFontMetrics( smallCapsFont( zh, applyZoom ) ).width( displayedChar( c->c ) );
|
|
}
|
|
else
|
|
// Use the cached font metrics from KoTextFormat
|
|
if ( applyZoom )
|
|
{
|
|
if ( r ) {
|
|
pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
|
|
} else {
|
|
// Use the m_screenWidths[] array when possible, even faster
|
|
Q_ASSERT( tqunicode < 256 );
|
|
pixelww = d->m_screenWidths[ tqunicode ];
|
|
// Not in cache yet -> calculate
|
|
if ( pixelww == 0 ) {
|
|
pixelww = this->screenFontMetrics( zh ).width( displayedChar( c->c ) );
|
|
Q_ASSERT( pixelww < 65535 );
|
|
d->m_screenWidths[ tqunicode ] = pixelww;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
pixelww = this->refFontMetrics().width( displayedChar( c->c ) );
|
|
}
|
|
}
|
|
else {
|
|
// Complex text. We need some hacks to get the right metric here
|
|
bool smallCaps = ( attributeFont() == KoTextFormat::ATT_SMALL_CAPS && c->c.upper() != c->c );
|
|
const TQFontMetrics& fontMetrics = smallCaps ? smallCapsFont( zh, applyZoom ) : applyZoom ? screenFontMetrics( zh ) : refFontMetrics();
|
|
TQString str;
|
|
int pos = 0;
|
|
if( i > 8 )
|
|
pos = i - 8;
|
|
int off = i - pos;
|
|
int end = TQMIN( parag->length(), i + 8 );
|
|
while ( pos < end ) {
|
|
str += displayedChar( parag->at(pos)->c );
|
|
pos++;
|
|
}
|
|
pixelww = fontMetrics.charWidth( str, off );
|
|
}
|
|
|
|
#if 0
|
|
kdDebug(32500) << "KoTextFormat::charWidth: char=" << TQString(c->c) << " format=" << key()
|
|
<< ", applyZoom=" << applyZoom << " pixel-width=" << pixelww << endl;
|
|
#endif
|
|
return pixelww;
|
|
}
|
|
|
|
int KoTextFormat::height() const
|
|
{
|
|
if ( d->m_refHeight < 0 )
|
|
{
|
|
// Calculate height using 100%-zoom font
|
|
int h = refFontMetrics().height()+TQABS(offsetFromBaseLine());
|
|
if ( vAlign() == KoTextFormat::AlignSuperScript )
|
|
h += refFontMetrics().height()/2;
|
|
else if ( vAlign() == KoTextFormat::AlignSubScript )
|
|
h += refFontMetrics().height()/6;
|
|
|
|
// Add room for the shadow
|
|
if ( d->m_shadowDistanceY != 0 ) {
|
|
// pt -> pixel (at 100% zoom)
|
|
h += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiY() ) ) * TQABS( d->m_shadowDistanceY ) );
|
|
}
|
|
|
|
//kdDebug(32500) << "KoTextFormat::height 100%-zoom font says h=" << h << " in LU:" << KoTextZoomHandler::ptToLayoutUnitPt(h) << endl;
|
|
// Then scale to LU
|
|
d->m_refHeight = tqRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
|
|
}
|
|
return d->m_refHeight;
|
|
}
|
|
|
|
int KoTextFormat::offsetX() const // in LU pixels
|
|
{
|
|
int off = 0;
|
|
#if 0
|
|
// Shadow on left -> character is moved to the right
|
|
// Wrong if next char has no shadow (they'll run into each other)
|
|
// Somehow we should only do this if x == 0 (in the formatter)
|
|
if ( d->m_shadowDistanceX < 0 )
|
|
{
|
|
double lupt = KoTextZoomHandler::ptToLayoutUnitPt( TQABS( d->m_shadowDistanceX ) );
|
|
off += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiX() ) ) * lupt );
|
|
}
|
|
#endif
|
|
return off;
|
|
}
|
|
|
|
int KoTextFormat::offsetY() const // in LU pixels
|
|
{
|
|
int off = 0;
|
|
#if 0
|
|
// Shadow on top -> character is moved down
|
|
if ( d->m_shadowDistanceY < 0 )
|
|
{
|
|
double lupt = KoTextZoomHandler::ptToLayoutUnitPt( TQABS( d->m_shadowDistanceY ) );
|
|
off += (int)(POINT_TO_INCH( static_cast<double>( KoGlobal::dpiY() ) ) * lupt );
|
|
}
|
|
#endif
|
|
return off;
|
|
}
|
|
|
|
TQString KoTextFormat::displayedString( const TQString& str )const
|
|
{
|
|
switch ( m_attributeFont ) {
|
|
case ATT_NONE:
|
|
return str;
|
|
case ATT_UPPER:
|
|
case ATT_SMALL_CAPS:
|
|
return str.upper();
|
|
case ATT_LOWER:
|
|
return str.lower();
|
|
default:
|
|
kdDebug(32500)<<" Error in AttributeStyle \n";
|
|
return str;
|
|
}
|
|
}
|
|
|
|
TQChar KoTextFormat::displayedChar( TQChar c )const
|
|
{
|
|
if ( c.tqunicode() == 0xa0 ) // nbsp
|
|
return ' ';
|
|
switch ( m_attributeFont ) {
|
|
case ATT_NONE:
|
|
return c;
|
|
case ATT_SMALL_CAPS:
|
|
case ATT_UPPER:
|
|
return c.upper();
|
|
case ATT_LOWER:
|
|
return c.lower();
|
|
default:
|
|
kdDebug(32500)<<" Error in AttributeStyle \n";
|
|
return c;
|
|
}
|
|
}
|
|
|
|
int KoTextFormat::ascent() const
|
|
{
|
|
if ( d->m_refAscent < 0 )
|
|
{
|
|
// Calculate ascent using 100%-zoom font
|
|
int h = refFontMetrics().ascent();
|
|
if ( offsetFromBaseLine()>0 )
|
|
h += offsetFromBaseLine();
|
|
if ( vAlign() == KoTextFormat::AlignSuperScript )
|
|
h += refFontMetrics().height()/2;
|
|
// Then scale to LU
|
|
d->m_refAscent = tqRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
|
|
//d->m_refAscent += offsetY();
|
|
}
|
|
return d->m_refAscent;
|
|
}
|
|
|
|
int KoTextFormat::descent() const
|
|
{
|
|
if ( d->m_refDescent < 0 )
|
|
{
|
|
// Calculate descent using 100%-zoom font
|
|
int h = refFontMetrics().descent();
|
|
if ( offsetFromBaseLine()<0 )
|
|
h -= offsetFromBaseLine();
|
|
// Then scale to LU
|
|
d->m_refDescent = tqRound( KoTextZoomHandler::ptToLayoutUnitPt( h ) );
|
|
//d->m_refDescent += offsetY();
|
|
}
|
|
return d->m_refDescent;
|
|
}
|
|
|
|
int KoTextFormat::charWidthLU( const KoTextStringChar* c, const KoTextParag* parag, int i ) const
|
|
{
|
|
// Hmm, we add precision to the least precise one!
|
|
// TODO: We should instead implement it here in LU, and let charWidth call it...
|
|
return KoTextZoomHandler::ptToLayoutUnitPt( charWidth( 0L, false, c, parag, i ) );
|
|
}
|
|
|
|
int KoTextFormat::width( const TQChar& ch ) const
|
|
{
|
|
// Warning this doesn't take into account the shadow
|
|
return KoTextZoomHandler::ptToLayoutUnitPt( refFontMetrics().width( ch ) );
|
|
}
|
|
|
|
void KoTextFormat::applyCharStyle( KoCharStyle *_style )
|
|
{
|
|
d->m_charStyle = _style;
|
|
}
|
|
|
|
KoCharStyle *KoTextFormat::style() const
|
|
{
|
|
return d->m_charStyle;
|
|
}
|
|
|
|
TQString KoTextFormat::shadowAsCss( double shadowDistanceX, double shadowDistanceY, const TQColor& shadowColor )
|
|
{
|
|
// http://www.w3.org/TR/REC-CSS2/text.html#text-shadow-props
|
|
// none | [<color> || <length (h)> <length (v)> <length (blur radius, not used here)>] ...
|
|
// => none or color length length
|
|
if ( shadowDistanceX != 0 || shadowDistanceY != 0 )
|
|
{
|
|
TQString css = shadowColor.name() + " ";
|
|
css += TQString::number(shadowDistanceX) + "pt ";
|
|
css += TQString::number(shadowDistanceY) + "pt";
|
|
return css;
|
|
}
|
|
return "none";
|
|
}
|
|
|
|
TQString KoTextFormat::shadowAsCss() const
|
|
{
|
|
return shadowAsCss( d->m_shadowDistanceX, d->m_shadowDistanceY, d->m_shadowColor );
|
|
}
|
|
|
|
void KoTextFormat::parseShadowFromCss( const TQString& _css )
|
|
{
|
|
TQString css = _css.simplifyWhiteSpace();
|
|
if ( css.isEmpty() || css == "none" )
|
|
{
|
|
d->m_shadowDistanceX = 0;
|
|
d->m_shadowDistanceY = 0;
|
|
d->m_shadowColor = TQColor();
|
|
} else
|
|
{
|
|
TQStringList tokens = TQStringList::split(' ', css);
|
|
if ( tokens.isEmpty() ) {
|
|
kdWarning(32500) << "Parse error in text-shadow: " << css << endl;
|
|
return;
|
|
}
|
|
// Check which token looks like a color
|
|
TQColor col( tokens.first() );
|
|
if ( col.isValid() )
|
|
tokens.pop_front();
|
|
else if ( tokens.count() > 1 )
|
|
{
|
|
col.setNamedColor( tokens.last() );
|
|
if ( col.isValid() )
|
|
tokens.pop_back();
|
|
}
|
|
d->m_shadowColor = col; // whether valid or not
|
|
// Parse x distance
|
|
if ( !tokens.isEmpty() ) {
|
|
d->m_shadowDistanceX = KoUnit::parseValue( tokens.first() );
|
|
tokens.pop_front();
|
|
}
|
|
// Parse y distance
|
|
if ( !tokens.isEmpty() ) {
|
|
d->m_shadowDistanceY = KoUnit::parseValue( tokens.first() );
|
|
tokens.pop_front();
|
|
}
|
|
// We ignore whatever else is in the string (e.g. blur radius, other shadows)
|
|
|
|
}
|
|
update();
|
|
}
|
|
|
|
TQColor KoTextFormat::shadowColor() const
|
|
{
|
|
if ( d->m_shadowColor.isValid() )
|
|
return d->m_shadowColor;
|
|
else // CSS says "[If] no color has been specified, the shadow will have the same color as the [text] itself"
|
|
return col;
|
|
}
|
|
|
|
int KoTextFormat::shadowX( KoTextZoomHandler *zh ) const
|
|
{
|
|
return zh->zoomItX( d->m_shadowDistanceX );
|
|
}
|
|
|
|
int KoTextFormat::shadowY( KoTextZoomHandler *zh ) const
|
|
{
|
|
return zh->zoomItY( d->m_shadowDistanceY );
|
|
}
|
|
|
|
//static
|
|
TQString KoTextFormat::underlineStyleToString( KoTextFormat::UnderlineStyle _lineType )
|
|
{
|
|
TQString strLineType;
|
|
switch ( _lineType )
|
|
{
|
|
case KoTextFormat::U_SOLID:
|
|
strLineType ="solid";
|
|
break;
|
|
case KoTextFormat::U_DASH:
|
|
strLineType ="dash";
|
|
break;
|
|
case KoTextFormat::U_DOT:
|
|
strLineType ="dot";
|
|
break;
|
|
case KoTextFormat::U_DASH_DOT:
|
|
strLineType="dashdot";
|
|
break;
|
|
case KoTextFormat::U_DASH_DOT_DOT:
|
|
strLineType="dashdotdot";
|
|
break;
|
|
}
|
|
return strLineType;
|
|
}
|
|
|
|
TQString KoTextFormat::strikeOutStyleToString( KoTextFormat::StrikeOutStyle _lineType )
|
|
{
|
|
TQString strLineType;
|
|
switch ( _lineType )
|
|
{
|
|
case KoTextFormat::S_SOLID:
|
|
strLineType ="solid";
|
|
break;
|
|
case KoTextFormat::S_DASH:
|
|
strLineType ="dash";
|
|
break;
|
|
case KoTextFormat::S_DOT:
|
|
strLineType ="dot";
|
|
break;
|
|
case KoTextFormat::S_DASH_DOT:
|
|
strLineType="dashdot";
|
|
break;
|
|
case KoTextFormat::S_DASH_DOT_DOT:
|
|
strLineType="dashdotdot";
|
|
break;
|
|
}
|
|
return strLineType;
|
|
}
|
|
|
|
KoTextFormat::UnderlineStyle KoTextFormat::stringToUnderlineStyle( const TQString & _str )
|
|
{
|
|
if ( _str =="solid")
|
|
return KoTextFormat::U_SOLID;
|
|
else if ( _str =="dash" )
|
|
return KoTextFormat::U_DASH;
|
|
else if ( _str =="dot" )
|
|
return KoTextFormat::U_DOT;
|
|
else if ( _str =="dashdot")
|
|
return KoTextFormat::U_DASH_DOT;
|
|
else if ( _str=="dashdotdot")
|
|
return KoTextFormat::U_DASH_DOT_DOT;
|
|
else
|
|
return KoTextFormat::U_SOLID;
|
|
}
|
|
|
|
KoTextFormat::StrikeOutStyle KoTextFormat::stringToStrikeOutStyle( const TQString & _str )
|
|
{
|
|
if ( _str =="solid")
|
|
return KoTextFormat::S_SOLID;
|
|
else if ( _str =="dash" )
|
|
return KoTextFormat::S_DASH;
|
|
else if ( _str =="dot" )
|
|
return KoTextFormat::S_DOT;
|
|
else if ( _str =="dashdot")
|
|
return KoTextFormat::S_DASH_DOT;
|
|
else if ( _str=="dashdotdot")
|
|
return KoTextFormat::S_DASH_DOT_DOT;
|
|
else
|
|
return KoTextFormat::S_SOLID;
|
|
}
|
|
|
|
TQString KoTextFormat::attributeFontToString( KoTextFormat::AttributeStyle _attr )
|
|
{
|
|
if (_attr == KoTextFormat::ATT_NONE )
|
|
return TQString("none");
|
|
else if ( _attr == KoTextFormat::ATT_UPPER )
|
|
return TQString("uppercase");
|
|
else if ( _attr == KoTextFormat::ATT_LOWER )
|
|
return TQString("lowercase");
|
|
else if ( _attr == KoTextFormat::ATT_SMALL_CAPS )
|
|
return TQString("smallcaps");
|
|
else
|
|
return TQString("none");
|
|
}
|
|
|
|
KoTextFormat::AttributeStyle KoTextFormat::stringToAttributeFont( const TQString & _str )
|
|
{
|
|
if ( _str == "none" )
|
|
return KoTextFormat::ATT_NONE;
|
|
else if ( _str == "uppercase")
|
|
return KoTextFormat::ATT_UPPER;
|
|
else if ( _str == "lowercase")
|
|
return KoTextFormat::ATT_LOWER;
|
|
else if ( _str == "smallcaps" )
|
|
return KoTextFormat::ATT_SMALL_CAPS;
|
|
else
|
|
return KoTextFormat::ATT_NONE;
|
|
}
|
|
|
|
|
|
void KoTextFormat::setHyphenation( bool b )
|
|
{
|
|
if ( d->m_bHyphenation == b )
|
|
return;
|
|
d->m_bHyphenation = b;
|
|
update();
|
|
|
|
}
|
|
|
|
void KoTextFormat::setUnderLineWidth( double ulw )
|
|
{
|
|
if ( d->m_underLineWidth == ulw )
|
|
return;
|
|
d->m_underLineWidth = ulw;
|
|
update();
|
|
|
|
}
|
|
|
|
void KoTextFormat::setLanguage( const TQString & _lang)
|
|
{
|
|
if ( m_language == _lang )
|
|
return;
|
|
m_language = _lang;
|
|
update();
|
|
}
|
|
|
|
TQStringList KoTextFormat::underlineTypeList()
|
|
{
|
|
TQStringList lst;
|
|
lst <<i18n("Underline Style", "None");
|
|
lst <<i18n("Single");
|
|
lst <<i18n("Double");
|
|
lst <<i18n("Simple Bold");
|
|
lst <<i18n("Wave");
|
|
return lst;
|
|
}
|
|
|
|
TQStringList KoTextFormat::strikeOutTypeList()
|
|
{
|
|
TQStringList lst;
|
|
lst <<i18n("Strikeout Style", "None");
|
|
lst <<i18n("Single");
|
|
lst <<i18n("Double");
|
|
lst <<i18n("Simple Bold");
|
|
return lst;
|
|
}
|
|
|
|
TQStringList KoTextFormat::fontAttributeList()
|
|
{
|
|
TQStringList lst;
|
|
lst <<i18n("Normal");
|
|
lst <<i18n("Uppercase");
|
|
lst <<i18n("Lowercase");
|
|
lst <<i18n("Small Caps");
|
|
return lst;
|
|
}
|
|
|
|
TQStringList KoTextFormat::underlineStyleList()
|
|
{
|
|
TQStringList lst;
|
|
lst <<"_________"; // SOLID
|
|
lst <<"___ ___ __"; // DASH
|
|
lst <<"_ _ _ _ _ _"; // DOT
|
|
lst <<"___ _ ___ _"; // DASH_DOT
|
|
lst <<"___ _ _ ___"; // DASH_DOT_DOT
|
|
return lst;
|
|
}
|
|
|
|
TQStringList KoTextFormat::strikeOutStyleList()
|
|
{
|
|
TQStringList lst;
|
|
lst <<"_________"; // SOLID
|
|
lst <<"___ ___ __"; // DASH
|
|
lst <<"_ _ _ _ _ _"; // DOT
|
|
lst <<"___ _ ___ _"; // DASH_DOT
|
|
lst <<"___ _ _ ___"; // DASH_DOT_DOT
|
|
return lst;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
void KoTextFormat::printDebug()
|
|
{
|
|
TQString col = color().isValid() ? color().name() : TQString("(default)");
|
|
kdDebug(32500) << "format '" << key() << "' (" << (void*)this << "):"
|
|
<< " refcount: " << ref
|
|
<< " realfont: " << TQFontInfo( font() ).family()
|
|
<< " color: " << col << " shadow=" << shadowAsCss() << endl;
|
|
}
|
|
#endif
|
|
|
|
////////////////
|
|
|
|
KoTextFormatCollection::KoTextFormatCollection()
|
|
: cKey( 307 )//, sheet( 0 )
|
|
{
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
|
|
#endif
|
|
defFormat = new KoTextFormat( TQApplication::font(), TQColor(), KGlobal::locale()->language(), false );
|
|
lastFormat = cres = 0;
|
|
cflags = -1;
|
|
cKey.setAutoDelete( TRUE );
|
|
cachedFormat = 0;
|
|
}
|
|
|
|
KoTextFormatCollection::KoTextFormatCollection( const TQFont& defaultFont, const TQColor& defaultColor, const TQString & defaultLanguage, bool defaultHyphenation )
|
|
: cKey( 307 )
|
|
{
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << "KoTextFormatCollection::KoTextFormatCollection " << this << endl;
|
|
#endif
|
|
defFormat = new KoTextFormat( defaultFont, defaultColor, defaultLanguage, defaultHyphenation );
|
|
lastFormat = cres = 0;
|
|
cflags = -1;
|
|
cKey.setAutoDelete( TRUE );
|
|
cachedFormat = 0;
|
|
}
|
|
|
|
KoTextFormatCollection::~KoTextFormatCollection()
|
|
{
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << "KoTextFormatCollection::~KoTextFormatCollection " << this << endl;
|
|
#endif
|
|
delete defFormat;
|
|
defFormat = 0;
|
|
}
|
|
|
|
KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *f )
|
|
{
|
|
if ( f->parent() == this || f == defFormat ) {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(f) need '" << f->key() << "', best case!" << endl;
|
|
#endif
|
|
lastFormat = const_cast<KoTextFormat*>(f);
|
|
lastFormat->addRef();
|
|
return lastFormat;
|
|
}
|
|
|
|
if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(f) need '" << f->key() << "', good case!" << endl;
|
|
#endif
|
|
lastFormat->addRef();
|
|
return lastFormat;
|
|
}
|
|
|
|
#if 0 // #### disabled, because if this format is not in the
|
|
// formatcollection, it doesn't get the painter through
|
|
// KoTextFormatCollection::setPainter() which breaks printing on
|
|
// windows
|
|
if ( f->isAnchor() ) {
|
|
lastFormat = createFormat( *f );
|
|
lastFormat->collection = 0;
|
|
return lastFormat;
|
|
}
|
|
#endif
|
|
|
|
KoTextFormat *fm = cKey.find( f->key() );
|
|
if ( fm ) {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(f) need '" << f->key() << "', normal case!" << endl;
|
|
#endif
|
|
lastFormat = fm;
|
|
lastFormat->addRef();
|
|
return lastFormat;
|
|
}
|
|
|
|
if ( f->key() == defFormat->key() )
|
|
return defFormat;
|
|
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(f) need '" << f->key() << "', worst case!" << endl;
|
|
#endif
|
|
lastFormat = createFormat( *f );
|
|
lastFormat->collection = this;
|
|
cKey.insert( lastFormat->key(), lastFormat );
|
|
Q_ASSERT( f->key() == lastFormat->key() );
|
|
return lastFormat;
|
|
}
|
|
|
|
KoTextFormat *KoTextFormatCollection::format( const KoTextFormat *of, const KoTextFormat *nf, int flags )
|
|
{
|
|
if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << "', best case!" << endl;
|
|
#endif
|
|
cres->addRef();
|
|
return cres;
|
|
}
|
|
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(of,nf," << flags << ") calling createFormat(of=" << of << " " << of->key() << ")" << endl;
|
|
#endif
|
|
cres = createFormat( *of );
|
|
kof = of->key();
|
|
knf = nf->key();
|
|
cflags = flags;
|
|
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(of,nf," << flags << ") calling copyFormat(nf=" << nf << " " << nf->key() << ")" << endl;
|
|
#endif
|
|
cres->copyFormat( *nf, flags );
|
|
|
|
KoTextFormat *fm = cKey.find( cres->key() );
|
|
if ( !fm ) {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", worst case!" << endl;
|
|
#endif
|
|
cres->collection = this;
|
|
cKey.insert( cres->key(), cres );
|
|
} else {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format(of,nf,flags) mix of '" << of->key() << "' and '" << nf->key() << ", good case!" << endl;
|
|
#endif
|
|
delete cres;
|
|
cres = fm;
|
|
cres->addRef();
|
|
}
|
|
|
|
return cres;
|
|
}
|
|
|
|
#if 0
|
|
KoTextFormat *KoTextFormatCollection::format( const TQFont &f, const TQColor &c, const TQString & language, bool hyphen )
|
|
{
|
|
if ( cachedFormat && cfont == f && ccol == c ) {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - best case" << endl;
|
|
#endif
|
|
cachedFormat->addRef();
|
|
return cachedFormat;
|
|
}
|
|
|
|
TQString key = KoTextFormat::getKey( f, c, FALSE, KoTextFormat::AlignNormal );
|
|
cachedFormat = cKey.find( key );
|
|
cfont = f;
|
|
ccol = c;
|
|
|
|
if ( cachedFormat ) {
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - good case" << endl;
|
|
#endif
|
|
cachedFormat->addRef();
|
|
return cachedFormat;
|
|
}
|
|
|
|
if ( key == defFormat->key() )
|
|
return defFormat;
|
|
|
|
cachedFormat = createFormat( f, c, language, hyphen );
|
|
cachedFormat->collection = this;
|
|
cKey.insert( cachedFormat->key(), cachedFormat );
|
|
if ( cachedFormat->key() != key )
|
|
kdWarning() << "ASSERT: keys for format not identical: '" << cachedFormat->key() << " '" << key << "'" << endl;
|
|
#ifdef DEBUG_COLLECTION
|
|
kdDebug(32500) << " format of font and col '" << cachedFormat->key() << "' - worst case" << endl;
|
|
#endif
|
|
return cachedFormat;
|
|
}
|
|
#endif
|
|
|
|
void KoTextFormatCollection::remove( KoTextFormat *f )
|
|
{
|
|
if ( lastFormat == f )
|
|
lastFormat = 0;
|
|
if ( cres == f )
|
|
cres = 0;
|
|
if ( cachedFormat == f )
|
|
cachedFormat = 0;
|
|
cKey.remove( f->key() );
|
|
}
|
|
|
|
void KoTextFormatCollection::zoomChanged()
|
|
{
|
|
TQDictIterator<KoTextFormat> it( cKey );
|
|
for ( ; it.current(); ++it ) {
|
|
it.current()->zoomChanged();
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
void KoTextFormatCollection::setPainter( TQPainter *p )
|
|
{
|
|
TQDictIterator<KoTextFormat> it( cKey );
|
|
KoTextFormat *f;
|
|
while ( ( f = it.current() ) ) {
|
|
++it;
|
|
f->setPainter( p );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
void KoTextFormatCollection::debug()
|
|
{
|
|
kdDebug(32500) << "------------ KoTextFormatCollection: debug --------------- BEGIN" << endl;
|
|
kdDebug(32500) << "Default Format: '" << defFormat->key() << "' (" << (void*)defFormat << "): realfont: " << TQFontInfo( defFormat->font() ).family() << endl;
|
|
TQDictIterator<KoTextFormat> it( cKey );
|
|
for ( ; it.current(); ++it ) {
|
|
Q_ASSERT(it.currentKey() == it.current()->key());
|
|
if(it.currentKey() != it.current()->key())
|
|
kdDebug(32500) << "**** MISMATCH key=" << it.currentKey() << " (see line below for format)" << endl;
|
|
it.current()->printDebug();
|
|
}
|
|
kdDebug(32500) << "------------ KoTextFormatCollection: debug --------------- END" << endl;
|
|
}
|
|
#endif
|