1 /* This file is part of the KDE project
2 * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
3 * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
4 * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
5 * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
6 * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantasic.net>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23 #include "KoCharacterStyle.h"
24
25 #include "Styles_p.h"
26
27 #include <QTextBlock>
28 #include <QTextCursor>
29 #include <QFontDatabase>
30
31 #include <KoOdfLoadingContext.h>
32 #include <KoOdfStylesReader.h>
33 #include <KoXmlNS.h>
34 #include <KoXmlReader.h>
35 #include <KoUnit.h>
36 #include <KoStore.h>
37 #include <KoStoreDevice.h>
38 #include <KoGenStyle.h>
39 #include <KoShadowStyle.h>
40 #include <KoShapeLoadingContext.h>
41 #include <KoStyleStack.h>
42 #include "KoTextDocument.h"
43
44 #ifdef SHOULD_BUILD_FONT_CONVERSION
45 #include <string.h>
46 #include <fontconfig/fontconfig.h>
47 #include <fontconfig/fcfreetype.h>
48 #include <ft2build.h>
49 #include FT_FREETYPE_H
50 #include FT_GLYPH_H
51 #include FT_TYPES_H
52 #include FT_OUTLINE_H
53 #include FT_RENDER_H
54 #include FT_TRUETYPE_TABLES_H
55 #include FT_SFNT_NAMES_H
56 #endif
57
58 #include "TextDebug.h"
59 #include "KoTextDebug.h"
60
61 #ifdef SHOULD_BUILD_FONT_CONVERSION
62 QMap<QString,qreal> textScaleMap;
63 #endif //SHOULD_BUILD_FONT_CONVERSION
64
65 class Q_DECL_HIDDEN KoCharacterStyle::Private
66 {
67 public:
68 Private();
~Private()69 ~Private() { }
70
setProperty(int key,const QVariant & value)71 void setProperty(int key, const QVariant &value) {
72 stylesPrivate.add(key, value);
73 }
propertyDouble(int key) const74 qreal propertyDouble(int key) const {
75 QVariant variant = stylesPrivate.value(key);
76 if (variant.isNull()) {
77 if (parentStyle)
78 return parentStyle->d->propertyDouble(key);
79 else if (defaultStyle)
80 return defaultStyle->d->propertyDouble(key);
81 return 0.0;
82 }
83 return variant.toDouble();
84 }
propertyInt(int key) const85 int propertyInt(int key) const {
86 QVariant variant = stylesPrivate.value(key);
87 if (variant.isNull()) {
88 if (parentStyle)
89 return parentStyle->d->propertyInt(key);
90 else if (defaultStyle)
91 return defaultStyle->d->propertyInt(key);
92 return 0;
93 }
94 return variant.toInt();
95 }
propertyString(int key) const96 QString propertyString(int key) const {
97 QVariant variant = stylesPrivate.value(key);
98 if (variant.isNull()) {
99 if (parentStyle)
100 return parentStyle->d->propertyString(key);
101 else if (defaultStyle)
102 return defaultStyle->d->propertyString(key);
103 return QString();
104 }
105 return qvariant_cast<QString>(variant);
106 }
propertyBoolean(int key) const107 bool propertyBoolean(int key) const {
108 QVariant variant = stylesPrivate.value(key);
109 if (variant.isNull()) {
110 if (parentStyle)
111 return parentStyle->d->propertyBoolean(key);
112 else if (defaultStyle)
113 return defaultStyle->d->propertyBoolean(key);
114 return false;
115 }
116 return variant.toBool();
117 }
propertyColor(int key) const118 QColor propertyColor(int key) const {
119 QVariant variant = stylesPrivate.value(key);
120 if (variant.isNull()) {
121 if (parentStyle)
122 return parentStyle->d->propertyColor(key);
123 else if (defaultStyle)
124 return defaultStyle->d->propertyColor(key);
125 return QColor();
126 }
127 return variant.value<QColor>();
128 }
129
130 // problem with fonts in linux and windows is that true type fonts have more than one metric
131 // they have normal metric placed in font header table
132 // microsoft metric placed in os2 table
133 // apple metric placed in os2 table
134 // ms-word is probably using CreateFontIndirect and GetOutlineTextMetric function to calculate line height
135 // and this functions are using windows gdi environment which is using microsoft font metric placed in os2 table
136 // qt on linux is using normal font metric
137 // this two metrics are different and change from font to font
138 // this font stretch is needed if we want to have exact line height as in ms-word and oo
139 //
140 // font_size * font_stretch = windows_font_height
141 qreal calculateFontYStretch(const QString &fontFamily);
142
143
144 StylePrivate hardCodedDefaultStyle;
145
146 QString name;
147 StylePrivate stylesPrivate;
148 KoCharacterStyle *parentStyle;
149 KoCharacterStyle *defaultStyle;
150 bool m_inUse;
151 };
152
Private()153 KoCharacterStyle::Private::Private()
154 : parentStyle(0), defaultStyle(0), m_inUse(false)
155 {
156 //set the minimal default properties
157 hardCodedDefaultStyle.add(QTextFormat::FontFamily, QString("Sans Serif"));
158 hardCodedDefaultStyle.add(QTextFormat::FontPointSize, 12.0);
159 hardCodedDefaultStyle.add(QTextFormat::ForegroundBrush, QBrush(Qt::black));
160 hardCodedDefaultStyle.add(KoCharacterStyle::FontYStretch, 1);
161 hardCodedDefaultStyle.add(QTextFormat::FontHintingPreference, QFont::PreferNoHinting);
162 }
163
164
ensureMinimalProperties(QTextCharFormat & format) const165 void KoCharacterStyle::ensureMinimalProperties(QTextCharFormat &format) const
166 {
167 if (d->defaultStyle) {
168 QMap<int, QVariant> props = d->defaultStyle->d->stylesPrivate.properties();
169 QMap<int, QVariant>::const_iterator it = props.constBegin();
170 while (it != props.constEnd()) {
171 // in case there is already a foreground color don't apply the use window font color as then the foreground color
172 // should be used.
173 if (it.key() == KoCharacterStyle::UseWindowFontColor && format.hasProperty(QTextFormat::ForegroundBrush)) {
174 ++it;
175 continue;
176 }
177 // in case there is already a use window font color don't apply the foreground brush as this overwrite the foreground color
178 if (it.key() == QTextFormat::ForegroundBrush && format.hasProperty(KoCharacterStyle::UseWindowFontColor)) {
179 ++it;
180 continue;
181 }
182
183 if (!it.value().isNull() && !format.hasProperty(it.key())) {
184 format.setProperty(it.key(), it.value());
185 }
186 ++it;
187 }
188 }
189 QMap<int, QVariant> props = d->hardCodedDefaultStyle.properties();
190 QMap<int, QVariant>::const_iterator it = props.constBegin();
191 while (it != props.constEnd()) {
192 if (!it.value().isNull() && !format.hasProperty(it.key())) {
193 if (it.key() == QTextFormat::ForegroundBrush && format.hasProperty(KoCharacterStyle::UseWindowFontColor)) {
194 ++it;
195 continue;
196 }
197
198 format.setProperty(it.key(), it.value());
199 }
200 ++it;
201 }
202 }
203
calculateFontYStretch(const QString & fontFamily)204 qreal KoCharacterStyle::Private::calculateFontYStretch(const QString &fontFamily)
205 {
206 qreal stretch = 1;
207 #ifdef SHOULD_BUILD_FONT_CONVERSION
208
209 if (textScaleMap.contains(fontFamily)) {
210 return textScaleMap.value(fontFamily);
211 }
212
213 FcResult result = FcResultMatch;
214 FT_Library library;
215 FT_Face face;
216 int id = 0;
217 int error = 0;
218 QByteArray fontName = fontFamily.toLatin1();
219
220 //TODO https://freedesktop.org/software/fontconfig/fontconfig-devel/x19.html
221 // we should specify slant and weight too
222 FcPattern *font = FcPatternBuild (0, FC_FAMILY, FcTypeString,fontName.data(), FC_SIZE, FcTypeDouble, (qreal)11, 0);
223 if (font == 0) {
224 return 1;
225 }
226
227 // find font
228 FcPattern *matched = 0;
229 matched = FcFontMatch (0, font, &result);
230 if (matched == 0) {
231 FcPatternDestroy (font);
232 return 1;
233 }
234
235 // get font family name
236 char * str = 0;
237 result = FcPatternGetString (matched, FC_FAMILY, 0,(FcChar8**) &str);
238 if (result != FcResultMatch || str == 0) {
239 FcPatternDestroy (font);
240 FcPatternDestroy (matched);
241 return 1;
242 }
243
244 // check if right font was found
245 QByteArray foundFontFamily = QByteArray::fromRawData(str, strlen(str));
246 if (foundFontFamily != fontName) {
247 FcPatternDestroy (font);
248 FcPatternDestroy (matched);
249 return 1;
250 }
251
252 // get path to font
253 str = 0;
254 result = FcPatternGetString (matched, FC_FILE, 0,(FcChar8**) &str);
255 if (result != FcResultMatch) {
256 FcPatternDestroy (font);
257 FcPatternDestroy (matched);
258 return 1;
259 }
260
261 // get index of font inside the font file
262 result = FcPatternGetInteger (matched, FC_INDEX, 0, &id);
263 if (result != FcResultMatch) {
264 FcPatternDestroy (font);
265 FcPatternDestroy (matched);
266 return 1;
267 }
268
269 // initialize freetype
270 error = FT_Init_FreeType( &library );
271 if (error) {
272 FcPatternDestroy (font);
273 FcPatternDestroy (matched);
274 return 1;
275 }
276
277 // get font metric
278 error = FT_New_Face (library,(char *) str, id, &face);
279 if (error) {
280 FT_Done_FreeType(library);
281 FcPatternDestroy (font);
282 FcPatternDestroy (matched);
283 return 1;
284 }
285
286 // get font metric os2 table
287 TT_OS2 *os2;
288 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
289 if(os2 == 0) {
290 FT_Done_Face(face);
291 FT_Done_FreeType(library);
292 FcPatternDestroy (font);
293 FcPatternDestroy (matched);
294 return 1;
295 }
296
297 // get font metric header table
298 TT_Header *header;
299 header = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
300 if(header == 0) {
301 FT_Done_Face(face);
302 FT_Done_FreeType(library);
303 FcPatternDestroy (font);
304 FcPatternDestroy (matched);
305 return 1;
306 }
307
308 // check if the data is valid
309 if (header->Units_Per_EM == 0 || (os2->usWinAscent + os2->usWinDescent) == 0) {
310 FT_Done_Face(face);
311 FT_Done_FreeType(library);
312 FcPatternDestroy (font);
313 FcPatternDestroy (matched);
314 return 1;
315 }
316
317 // compute font height stretch
318 // font_size * font_stretch = windows_font_height
319 qreal height = os2->usWinAscent + os2->usWinDescent;
320 height = height * (2048 / header->Units_Per_EM);
321 stretch = (1.215 * height)/2500;
322 stretch = (1.15 * height)/2500; // seems a better guess but probably not right
323
324 FT_Done_Face(face);
325 FT_Done_FreeType(library);
326 FcPatternDestroy (font);
327 FcPatternDestroy (matched);
328
329 textScaleMap.insert(fontFamily, stretch);
330 #else
331 Q_UNUSED(fontFamily);
332 #endif //SHOULD_BUILD_FONT_CONVERSION
333
334 return stretch;
335 }
KoCharacterStyle(QObject * parent)336 KoCharacterStyle::KoCharacterStyle(QObject *parent)
337 : QObject(parent), d(new Private())
338 {
339 }
340
KoCharacterStyle(const QTextCharFormat & format,QObject * parent)341 KoCharacterStyle::KoCharacterStyle(const QTextCharFormat &format, QObject *parent)
342 : QObject(parent), d(new Private())
343 {
344 copyProperties(format);
345 }
346
styleType() const347 KoCharacterStyle::Type KoCharacterStyle::styleType() const
348 {
349 return KoCharacterStyle::CharacterStyle;
350 }
351
copyProperties(const KoCharacterStyle * style)352 void KoCharacterStyle::copyProperties(const KoCharacterStyle *style)
353 {
354 d->stylesPrivate = style->d->stylesPrivate;
355 setName(style->name()); // make sure we emit property change
356 d->parentStyle = style->d->parentStyle;
357 d->defaultStyle = style->d->defaultStyle;
358 }
359
copyProperties(const QTextCharFormat & format)360 void KoCharacterStyle::copyProperties(const QTextCharFormat &format)
361 {
362 d->stylesPrivate = format.properties();
363 }
364
clone(QObject * parent) const365 KoCharacterStyle *KoCharacterStyle::clone(QObject *parent) const
366 {
367 KoCharacterStyle *newStyle = new KoCharacterStyle(parent);
368 newStyle->copyProperties(this);
369 return newStyle;
370 }
371
~KoCharacterStyle()372 KoCharacterStyle::~KoCharacterStyle()
373 {
374 delete d;
375 }
376
setDefaultStyle(KoCharacterStyle * defaultStyle)377 void KoCharacterStyle::setDefaultStyle(KoCharacterStyle *defaultStyle)
378 {
379 d->defaultStyle = defaultStyle;
380 }
381
setParentStyle(KoCharacterStyle * parent)382 void KoCharacterStyle::setParentStyle(KoCharacterStyle *parent)
383 {
384 d->parentStyle = parent;
385 }
386
parentStyle() const387 KoCharacterStyle *KoCharacterStyle::parentStyle() const
388 {
389 return d->parentStyle;
390 }
391
textOutline() const392 QPen KoCharacterStyle::textOutline() const
393 {
394 QVariant variant = value(QTextFormat::TextOutline);
395 if (variant.isNull()) {
396 return QPen(Qt::NoPen);
397 }
398 return qvariant_cast<QPen>(variant);
399 }
400
background() const401 QBrush KoCharacterStyle::background() const
402 {
403 QVariant variant = value(QTextFormat::BackgroundBrush);
404
405 if (variant.isNull()) {
406 return QBrush();
407 }
408 return qvariant_cast<QBrush>(variant);
409 }
410
clearBackground()411 void KoCharacterStyle::clearBackground()
412 {
413 d->stylesPrivate.remove(QTextCharFormat::BackgroundBrush);
414 }
415
foreground() const416 QBrush KoCharacterStyle::foreground() const
417 {
418 QVariant variant = value(QTextFormat::ForegroundBrush);
419 if (variant.isNull()) {
420 return QBrush();
421 }
422 return qvariant_cast<QBrush>(variant);
423 }
424
clearForeground()425 void KoCharacterStyle::clearForeground()
426 {
427 d->stylesPrivate.remove(QTextCharFormat::ForegroundBrush);
428 }
429
applyStyle(QTextCharFormat & format,bool emitSignal) const430 void KoCharacterStyle::applyStyle(QTextCharFormat &format, bool emitSignal) const
431 {
432 if (d->parentStyle) {
433 d->parentStyle->applyStyle(format);
434 }
435
436 bool fontSizeSet = false; // if this style has already set size don't apply the relatives
437 const QMap<int, QVariant> props = d->stylesPrivate.properties();
438 QMap<int, QVariant>::const_iterator it = props.begin();
439 QList<int> clearProperty;
440 while (it != props.end()) {
441 if (!it.value().isNull()) {
442 if (it.key() == KoCharacterStyle::PercentageFontSize && !fontSizeSet) {
443 qreal size = it.value().toDouble() / 100.0;
444 if (format.hasProperty(QTextFormat::FontPointSize)) {
445 size *= format.doubleProperty(QTextFormat::FontPointSize);
446 } else {
447 size *= 12.0;
448 }
449 format.setProperty(QTextFormat::FontPointSize, size);
450 }
451 else if (it.key() == KoCharacterStyle::AdditionalFontSize && !fontSizeSet) {
452 qreal size = it.value().toDouble() / 100.0;
453 if (format.hasProperty(QTextFormat::FontPointSize)) {
454 size += format.doubleProperty(QTextFormat::FontPointSize);
455 } else {
456 size += 12.0;
457 }
458 format.setProperty(QTextFormat::FontPointSize, size);
459 }
460 else if (it.key() == QTextFormat::FontFamily) {
461 if (!props.contains(QTextFormat::FontStyleHint)) {
462 clearProperty.append(QTextFormat::FontStyleHint);
463 }
464 if (!props.contains(QTextFormat::FontFixedPitch)) {
465 clearProperty.append(QTextFormat::FontFixedPitch);
466 }
467 if (!props.contains(KoCharacterStyle::FontCharset)) {
468 clearProperty.append(KoCharacterStyle::FontCharset);
469 }
470 format.setProperty(it.key(), it.value());
471 }
472 else {
473 debugText << "setProperty" << it.key() << it.value();
474 format.setProperty(it.key(), it.value());
475 }
476
477 if (it.key() == QTextFormat::FontPointSize) {
478 fontSizeSet = true;
479 }
480
481 if (it.key() == QTextFormat::ForegroundBrush) {
482 clearProperty.append(KoCharacterStyle::UseWindowFontColor);
483 }
484 else if (it.key() == KoCharacterStyle::UseWindowFontColor) {
485 clearProperty.append(QTextFormat::ForegroundBrush);
486 }
487 }
488 ++it;
489 }
490
491 foreach (int property, clearProperty) {
492 debugText << "clearProperty" << property;
493 format.clearProperty(property);
494 }
495 if (emitSignal) {
496 emit styleApplied(this);
497 d->m_inUse = true;
498 }
499 }
500
autoStyle(const QTextCharFormat & format,QTextCharFormat blockCharFormat) const501 KoCharacterStyle *KoCharacterStyle::autoStyle(const QTextCharFormat &format, QTextCharFormat blockCharFormat) const
502 {
503 KoCharacterStyle *autoStyle = new KoCharacterStyle(format);
504 applyStyle(blockCharFormat, false);
505 ensureMinimalProperties(blockCharFormat);
506 autoStyle->removeDuplicates(blockCharFormat);
507 autoStyle->setParentStyle(const_cast<KoCharacterStyle*>(this));
508 // remove StyleId if it is there as it is not a property of the style itself and will not be written out
509 // so it should not be part of the autostyle. As otherwise it can happen that the StyleId is the only
510 // property left and then we write out an empty style which is unneeded.
511 // we also need to remove the properties of links as they are saved differently
512 autoStyle->d->stylesPrivate.remove(StyleId);
513 autoStyle->d->stylesPrivate.remove(QTextFormat::IsAnchor);
514 autoStyle->d->stylesPrivate.remove(QTextFormat::AnchorHref);
515 autoStyle->d->stylesPrivate.remove(QTextFormat::AnchorName);
516 return autoStyle;
517 }
518
519 struct FragmentData
520 {
FragmentDataFragmentData521 FragmentData(const QTextCharFormat &format, int position, int length)
522 : format(format)
523 , position(position)
524 , length(length)
525 {}
526
527 QTextCharFormat format;
528 int position;
529 int length;
530 };
531
applyStyle(QTextBlock & block) const532 void KoCharacterStyle::applyStyle(QTextBlock &block) const
533 {
534 QTextCursor cursor(block);
535 QTextCharFormat cf = block.charFormat();
536
537 if (!cf.isTableCellFormat()) {
538 cf = KoTextDocument(block.document()).frameCharFormat();
539 }
540
541 applyStyle(cf);
542 ensureMinimalProperties(cf);
543 cursor.setBlockCharFormat(cf);
544
545 // be sure that we keep the InlineInstanceId, anchor information and ChangeTrackerId when applying a style
546
547 QList<FragmentData> fragments;
548 for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
549 QTextFragment currentFragment = it.fragment();
550 if (currentFragment.isValid()) {
551 QTextCharFormat format(cf);
552 QVariant v = currentFragment.charFormat().property(InlineInstanceId);
553 if (!v.isNull()) {
554 format.setProperty(InlineInstanceId, v);
555 }
556
557 v = currentFragment.charFormat().property(ChangeTrackerId);
558 if (!v.isNull()) {
559 format.setProperty(ChangeTrackerId, v);
560 }
561
562 if (currentFragment.charFormat().isAnchor()) {
563 format.setAnchor(true);
564 format.setAnchorHref(currentFragment.charFormat().anchorHref());
565 }
566 fragments.append(FragmentData(format, currentFragment.position(), currentFragment.length()));
567 }
568 }
569
570 foreach (const FragmentData &fragment, fragments) {
571 cursor.setPosition(fragment.position);
572 cursor.setPosition(fragment.position + fragment.length, QTextCursor::KeepAnchor);
573 cursor.setCharFormat(fragment.format);
574 }
575 }
576
applyStyle(QTextCursor * selection) const577 void KoCharacterStyle::applyStyle(QTextCursor *selection) const
578 {
579 // FIXME below should be done for each frament in the selection
580 QTextCharFormat cf = selection->charFormat();
581 applyStyle(cf);
582 ensureMinimalProperties(cf);
583 selection->setCharFormat(cf);
584 }
585
unapplyStyle(QTextCharFormat & format) const586 void KoCharacterStyle::unapplyStyle(QTextCharFormat &format) const
587 {
588 if (d->parentStyle)
589 d->parentStyle->unapplyStyle(format);
590
591 QMap<int, QVariant> props = d->stylesPrivate.properties();
592 QMap<int, QVariant>::const_iterator it = props.constBegin();
593 while (it != props.constEnd()) {
594 if (!it.value().isNull() && it.value() == format.property(it.key())) {
595 format.clearProperty(it.key());
596 }
597 ++it;
598 }
599
600 props = d->hardCodedDefaultStyle.properties();
601 it = props.constBegin();
602 while (it != props.constEnd()) {
603 if (!it.value().isNull() && !format.hasProperty(it.key())) {
604 format.setProperty(it.key(), it.value());
605 }
606 ++it;
607 }
608 }
609
isApplied() const610 bool KoCharacterStyle::isApplied() const
611 {
612 return d->m_inUse;
613 }
614
unapplyStyle(QTextBlock & block) const615 void KoCharacterStyle::unapplyStyle(QTextBlock &block) const
616 {
617 QTextCursor cursor(block);
618 QTextCharFormat cf = cursor.blockCharFormat();
619 unapplyStyle(cf);
620 cursor.setBlockCharFormat(cf);
621
622 if (block.length() == 1) // only the linefeed
623 return;
624 QTextBlock::iterator iter = block.end();
625 do {
626 --iter;
627 QTextFragment fragment = iter.fragment();
628 cursor.setPosition(fragment.position() + 1);
629 cf = cursor.charFormat();
630 unapplyStyle(cf);
631 cursor.setPosition(fragment.position());
632 cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
633 cursor.setCharFormat(cf);
634 } while (iter != block.begin());
635 }
636
637 // OASIS 14.2.29
parseOdfLineWidth(const QString & width,KoCharacterStyle::LineWeight & lineWeight,qreal & lineWidth)638 static void parseOdfLineWidth(const QString &width, KoCharacterStyle::LineWeight &lineWeight, qreal &lineWidth)
639 {
640 lineWidth = 0;
641 lineWeight = KoCharacterStyle::AutoLineWeight;
642 if (width.isEmpty() || width == "auto")
643 lineWeight = KoCharacterStyle::AutoLineWeight;
644 else if (width == "normal")
645 lineWeight = KoCharacterStyle::NormalLineWeight;
646 else if (width == "bold")
647 lineWeight = KoCharacterStyle::BoldLineWeight;
648 else if (width == "thin")
649 lineWeight = KoCharacterStyle::ThinLineWeight;
650 else if (width == "dash")
651 lineWeight = KoCharacterStyle::DashLineWeight;
652 else if (width == "medium")
653 lineWeight = KoCharacterStyle::MediumLineWeight;
654 else if (width == "thick")
655 lineWeight = KoCharacterStyle::ThickLineWeight;
656 else if (width.endsWith('%')) {
657 lineWeight = KoCharacterStyle::PercentLineWeight;
658 lineWidth = width.mid(0, width.length() - 1).toDouble();
659 } else if (width[width.length()-1].isNumber()) {
660 lineWeight = KoCharacterStyle::LengthLineWeight;
661 lineWidth = width.toDouble();
662 } else {
663 lineWeight = KoCharacterStyle::LengthLineWeight;
664 lineWidth = KoUnit::parseValue(width);
665 }
666 }
667
668 // OASIS 14.2.29
importOdfLine(const QString & type,const QString & style,KoCharacterStyle::LineStyle & lineStyle,KoCharacterStyle::LineType & lineType)669 static void importOdfLine(const QString &type, const QString &style, KoCharacterStyle::LineStyle &lineStyle, KoCharacterStyle::LineType &lineType)
670 {
671 lineStyle = KoCharacterStyle::NoLineStyle;
672 lineType = KoCharacterStyle::NoLineType;
673
674 QString fixedType = type;
675 QString fixedStyle = style;
676 if (fixedStyle == "none")
677 fixedType.clear();
678 else if (fixedType.isEmpty() && !fixedStyle.isEmpty())
679 fixedType = "single";
680 else if (!fixedType.isEmpty() && fixedType != "none" && fixedStyle.isEmpty()) {
681 // don't set a style when the type is none
682 fixedStyle = "solid";
683 }
684
685 if (fixedType == "single")
686 lineType = KoCharacterStyle::SingleLine;
687 else if (fixedType == "double")
688 lineType = KoCharacterStyle::DoubleLine;
689
690 if (fixedStyle == "solid")
691 lineStyle = KoCharacterStyle::SolidLine;
692 else if (fixedStyle == "dotted")
693 lineStyle = KoCharacterStyle::DottedLine;
694 else if (fixedStyle == "dash")
695 lineStyle = KoCharacterStyle::DashLine;
696 else if (fixedStyle == "long-dash")
697 lineStyle = KoCharacterStyle::LongDashLine;
698 else if (fixedStyle == "dot-dash")
699 lineStyle = KoCharacterStyle::DotDashLine;
700 else if (fixedStyle == "dot-dot-dash")
701 lineStyle = KoCharacterStyle::DotDotDashLine;
702 else if (fixedStyle == "wave")
703 lineStyle = KoCharacterStyle::WaveLine;
704 }
705
exportOdfLineType(KoCharacterStyle::LineType lineType)706 static QString exportOdfLineType(KoCharacterStyle::LineType lineType)
707 {
708 switch (lineType) {
709 case KoCharacterStyle::NoLineType:
710 return "none";
711 case KoCharacterStyle::SingleLine:
712 return "single";
713 case KoCharacterStyle::DoubleLine:
714 return "double";
715 default:
716 return "";
717 }
718 }
719
exportOdfLineStyle(KoCharacterStyle::LineStyle lineStyle)720 static QString exportOdfLineStyle(KoCharacterStyle::LineStyle lineStyle)
721 {
722 switch (lineStyle) {
723 case KoCharacterStyle::NoLineStyle:
724 return "none";
725 case KoCharacterStyle::SolidLine:
726 return "solid";
727 case KoCharacterStyle::DottedLine:
728 return "dotted";
729 case KoCharacterStyle::DashLine:
730 return "dash";
731 case KoCharacterStyle::LongDashLine:
732 return "long-dash";
733 case KoCharacterStyle::DotDashLine:
734 return "dot-dash";
735 case KoCharacterStyle::DotDotDashLine:
736 return "dot-dot-dash";
737 case KoCharacterStyle::WaveLine:
738 return "wave";
739 default:
740 return "";
741 }
742 }
exportOdfLineMode(KoCharacterStyle::LineMode lineMode)743 static QString exportOdfLineMode(KoCharacterStyle::LineMode lineMode)
744 {
745 switch (lineMode) {
746 case KoCharacterStyle::ContinuousLineMode:
747 return "continuous";
748 case KoCharacterStyle::SkipWhiteSpaceLineMode:
749 return "skip-white-space";
750 default:
751 return "";
752 }
753 }
754
exportOdfLineWidth(KoCharacterStyle::LineWeight lineWeight,qreal lineWidth)755 static QString exportOdfLineWidth(KoCharacterStyle::LineWeight lineWeight, qreal lineWidth)
756 {
757 switch (lineWeight) {
758 case KoCharacterStyle::AutoLineWeight:
759 return "auto";
760 case KoCharacterStyle::NormalLineWeight:
761 return "normal";
762 case KoCharacterStyle::BoldLineWeight:
763 return "bold";
764 case KoCharacterStyle::ThinLineWeight:
765 return "thin";
766 case KoCharacterStyle::DashLineWeight:
767 return "dash";
768 case KoCharacterStyle::MediumLineWeight:
769 return "medium";
770 case KoCharacterStyle::ThickLineWeight:
771 return "thick";
772 case KoCharacterStyle::PercentLineWeight:
773 return QString("%1%").arg(lineWidth);
774 case KoCharacterStyle::LengthLineWeight:
775 return QString("%1pt").arg(lineWidth);
776 default:
777 return QString();
778 }
779 }
780
exportOdfFontStyleHint(QFont::StyleHint hint)781 static QString exportOdfFontStyleHint(QFont::StyleHint hint)
782 {
783 switch (hint) {
784 case QFont::Serif:
785 return "roman";
786 case QFont::SansSerif:
787 return "swiss";
788 case QFont::TypeWriter:
789 return "modern";
790 case QFont::Decorative:
791 return "decorative";
792 case QFont::System:
793 return "system";
794 /*case QFont::Script */
795 default:
796 return "";
797 }
798 }
799
setFontFamily(const QString & family)800 void KoCharacterStyle::setFontFamily(const QString &family)
801 {
802 d->setProperty(QTextFormat::FontFamily, family);
803 setFontYStretch(d->calculateFontYStretch(family));
804 }
fontFamily() const805 QString KoCharacterStyle::fontFamily() const
806 {
807 return d->propertyString(QTextFormat::FontFamily);
808 }
setFontPointSize(qreal size)809 void KoCharacterStyle::setFontPointSize(qreal size)
810 {
811 d->setProperty(QTextFormat::FontPointSize, size);
812 }
clearFontPointSize()813 void KoCharacterStyle::clearFontPointSize() {
814 d->stylesPrivate.remove(QTextFormat::FontPointSize);
815 }
fontPointSize() const816 qreal KoCharacterStyle::fontPointSize() const
817 {
818 return d->propertyDouble(QTextFormat::FontPointSize);
819 }
setFontWeight(int weight)820 void KoCharacterStyle::setFontWeight(int weight)
821 {
822 d->setProperty(QTextFormat::FontWeight, weight);
823 }
fontWeight() const824 int KoCharacterStyle::fontWeight() const
825 {
826 return d->propertyInt(QTextFormat::FontWeight);
827 }
setFontItalic(bool italic)828 void KoCharacterStyle::setFontItalic(bool italic)
829 {
830 d->setProperty(QTextFormat::FontItalic, italic);
831 }
fontItalic() const832 bool KoCharacterStyle::fontItalic() const
833 {
834 return d->propertyBoolean(QTextFormat::FontItalic);
835 }
836 ///TODO Review legacy fontOverline functions and testing (consider removal)
837 /*
838 void KoCharacterStyle::setFontOverline(bool overline)
839 {
840 d->setProperty(QTextFormat::FontOverline, overline);
841 }
842 bool KoCharacterStyle::fontOverline() const
843 {
844 return d->propertyBoolean(QTextFormat::FontOverline);
845 }
846 */
setFontFixedPitch(bool fixedPitch)847 void KoCharacterStyle::setFontFixedPitch(bool fixedPitch)
848 {
849 d->setProperty(QTextFormat::FontFixedPitch, fixedPitch);
850 }
fontFixedPitch() const851 bool KoCharacterStyle::fontFixedPitch() const
852 {
853 return d->propertyBoolean(QTextFormat::FontFixedPitch);
854 }
setFontStyleHint(QFont::StyleHint styleHint)855 void KoCharacterStyle::setFontStyleHint(QFont::StyleHint styleHint)
856 {
857 d->setProperty(QTextFormat::FontStyleHint, styleHint);
858 }
fontStyleHint() const859 QFont::StyleHint KoCharacterStyle::fontStyleHint() const
860 {
861 return static_cast<QFont::StyleHint>(d->propertyInt(QTextFormat::FontStyleHint));
862 }
setFontKerning(bool enable)863 void KoCharacterStyle::setFontKerning(bool enable)
864 {
865 d->setProperty(QTextFormat::FontKerning, enable);
866 }
fontKerning() const867 bool KoCharacterStyle::fontKerning() const
868 {
869 return d->propertyBoolean(QTextFormat::FontKerning);
870 }
setVerticalAlignment(QTextCharFormat::VerticalAlignment alignment)871 void KoCharacterStyle::setVerticalAlignment(QTextCharFormat::VerticalAlignment alignment)
872 {
873 d->setProperty(QTextFormat::TextVerticalAlignment, alignment);
874 }
verticalAlignment() const875 QTextCharFormat::VerticalAlignment KoCharacterStyle::verticalAlignment() const
876 {
877 return static_cast<QTextCharFormat::VerticalAlignment>(d->propertyInt(QTextFormat::TextVerticalAlignment));
878 }
setTextOutline(const QPen & pen)879 void KoCharacterStyle::setTextOutline(const QPen &pen)
880 {
881 d->setProperty(QTextFormat::TextOutline, pen);
882 }
setBackground(const QBrush & brush)883 void KoCharacterStyle::setBackground(const QBrush &brush)
884 {
885 d->setProperty(QTextFormat::BackgroundBrush, brush);
886 }
setForeground(const QBrush & brush)887 void KoCharacterStyle::setForeground(const QBrush &brush)
888 {
889 d->setProperty(QTextFormat::ForegroundBrush, brush);
890 }
setFontAutoColor(bool use)891 void KoCharacterStyle::setFontAutoColor(bool use)
892 {
893 d->setProperty(KoCharacterStyle::UseWindowFontColor, use);
894 }
895
name() const896 QString KoCharacterStyle::name() const
897 {
898 return d->name;
899 }
setName(const QString & name)900 void KoCharacterStyle::setName(const QString &name)
901 {
902 if (name == d->name)
903 return;
904 d->name = name;
905 emit nameChanged(name);
906 }
styleId() const907 int KoCharacterStyle::styleId() const
908 {
909 return d->propertyInt(StyleId);
910 }
setStyleId(int id)911 void KoCharacterStyle::setStyleId(int id)
912 {
913 d->setProperty(StyleId, id);
914 }
font() const915 QFont KoCharacterStyle::font() const
916 {
917 QFont font;
918 if (d->stylesPrivate.contains(QTextFormat::FontFamily))
919 font.setFamily(fontFamily());
920 if (d->stylesPrivate.contains(QTextFormat::FontPointSize))
921 font.setPointSizeF(fontPointSize());
922 if (d->stylesPrivate.contains(QTextFormat::FontWeight))
923 font.setWeight(fontWeight());
924 if (d->stylesPrivate.contains(QTextFormat::FontItalic))
925 font.setItalic(fontItalic());
926 return font;
927 }
setHasHyphenation(bool on)928 void KoCharacterStyle::setHasHyphenation(bool on)
929 {
930 d->setProperty(HasHyphenation, on);
931 }
hasHyphenation() const932 bool KoCharacterStyle::hasHyphenation() const
933 {
934 return d->propertyBoolean(HasHyphenation);
935 }
936
setHyphenationPushCharCount(int count)937 void KoCharacterStyle::setHyphenationPushCharCount(int count)
938 {
939 if (count > 0)
940 d->setProperty(HyphenationPushCharCount, count);
941 else
942 d->stylesPrivate.remove(HyphenationPushCharCount);
943 }
944
hyphenationPushCharCount() const945 int KoCharacterStyle::hyphenationPushCharCount() const
946 {
947 if (hasProperty(HyphenationPushCharCount))
948 return d->propertyInt(HyphenationPushCharCount);
949 return 0;
950 }
951
setHyphenationRemainCharCount(int count)952 void KoCharacterStyle::setHyphenationRemainCharCount(int count)
953 {
954 if (count > 0)
955 d->setProperty(HyphenationRemainCharCount, count);
956 else
957 d->stylesPrivate.remove(HyphenationRemainCharCount);
958 }
959
hyphenationRemainCharCount() const960 int KoCharacterStyle::hyphenationRemainCharCount() const
961 {
962 if (hasProperty(HyphenationRemainCharCount))
963 return d->propertyInt(HyphenationRemainCharCount);
964 return 0;
965 }
966
setStrikeOutStyle(KoCharacterStyle::LineStyle strikeOut)967 void KoCharacterStyle::setStrikeOutStyle(KoCharacterStyle::LineStyle strikeOut)
968 {
969 d->setProperty(StrikeOutStyle, strikeOut);
970 }
971
strikeOutStyle() const972 KoCharacterStyle::LineStyle KoCharacterStyle::strikeOutStyle() const
973 {
974 return (KoCharacterStyle::LineStyle) d->propertyInt(StrikeOutStyle);
975 }
976
setStrikeOutType(LineType lineType)977 void KoCharacterStyle::setStrikeOutType(LineType lineType)
978 {
979 d->setProperty(StrikeOutType, lineType);
980 }
981
strikeOutType() const982 KoCharacterStyle::LineType KoCharacterStyle::strikeOutType() const
983 {
984 return (KoCharacterStyle::LineType) d->propertyInt(StrikeOutType);
985 }
986
setStrikeOutColor(const QColor & color)987 void KoCharacterStyle::setStrikeOutColor(const QColor &color)
988 {
989 d->setProperty(StrikeOutColor, color);
990 }
991
strikeOutColor() const992 QColor KoCharacterStyle::strikeOutColor() const
993 {
994 return d->propertyColor(StrikeOutColor);
995 }
996
setStrikeOutWidth(LineWeight weight,qreal width)997 void KoCharacterStyle::setStrikeOutWidth(LineWeight weight, qreal width)
998 {
999 d->setProperty(KoCharacterStyle::StrikeOutWeight, weight);
1000 d->setProperty(KoCharacterStyle::StrikeOutWidth, width);
1001 }
1002
strikeOutWidth(LineWeight & weight,qreal & width) const1003 void KoCharacterStyle::strikeOutWidth(LineWeight &weight, qreal &width) const
1004 {
1005 weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::StrikeOutWeight);
1006 width = d->propertyDouble(KoCharacterStyle::StrikeOutWidth);
1007 }
setStrikeOutMode(LineMode lineMode)1008 void KoCharacterStyle::setStrikeOutMode(LineMode lineMode)
1009 {
1010 d->setProperty(StrikeOutMode, lineMode);
1011 }
1012
setStrikeOutText(const QString & text)1013 void KoCharacterStyle::setStrikeOutText(const QString &text)
1014 {
1015 d->setProperty(StrikeOutText, text);
1016 }
strikeOutText() const1017 QString KoCharacterStyle::strikeOutText() const
1018 {
1019 return d->propertyString(StrikeOutText);
1020 }
strikeOutMode() const1021 KoCharacterStyle::LineMode KoCharacterStyle::strikeOutMode() const
1022 {
1023 return (KoCharacterStyle::LineMode) d->propertyInt(StrikeOutMode);
1024 }
1025
setOverlineStyle(KoCharacterStyle::LineStyle overline)1026 void KoCharacterStyle::setOverlineStyle(KoCharacterStyle::LineStyle overline)
1027 {
1028 d->setProperty(OverlineStyle, overline);
1029 }
1030
overlineStyle() const1031 KoCharacterStyle::LineStyle KoCharacterStyle::overlineStyle() const
1032 {
1033 return (KoCharacterStyle::LineStyle) d->propertyInt(OverlineStyle);
1034 }
1035
setOverlineType(LineType lineType)1036 void KoCharacterStyle::setOverlineType(LineType lineType)
1037 {
1038 d->setProperty(OverlineType, lineType);
1039 }
1040
overlineType() const1041 KoCharacterStyle::LineType KoCharacterStyle::overlineType() const
1042 {
1043 return (KoCharacterStyle::LineType) d->propertyInt(OverlineType);
1044 }
1045
setOverlineColor(const QColor & color)1046 void KoCharacterStyle::setOverlineColor(const QColor &color)
1047 {
1048 d->setProperty(KoCharacterStyle::OverlineColor, color);
1049 }
1050
overlineColor() const1051 QColor KoCharacterStyle::overlineColor() const
1052 {
1053 return d->propertyColor(KoCharacterStyle::OverlineColor);
1054 }
1055
setOverlineWidth(LineWeight weight,qreal width)1056 void KoCharacterStyle::setOverlineWidth(LineWeight weight, qreal width)
1057 {
1058 d->setProperty(KoCharacterStyle::OverlineWeight, weight);
1059 d->setProperty(KoCharacterStyle::OverlineWidth, width);
1060 }
1061
overlineWidth(LineWeight & weight,qreal & width) const1062 void KoCharacterStyle::overlineWidth(LineWeight &weight, qreal &width) const
1063 {
1064 weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::OverlineWeight);
1065 width = d->propertyDouble(KoCharacterStyle::OverlineWidth);
1066 }
1067
setOverlineMode(LineMode mode)1068 void KoCharacterStyle::setOverlineMode(LineMode mode)
1069 {
1070 d->setProperty(KoCharacterStyle::OverlineMode, mode);
1071 }
1072
overlineMode() const1073 KoCharacterStyle::LineMode KoCharacterStyle::overlineMode() const
1074 {
1075 return static_cast<KoCharacterStyle::LineMode>(d->propertyInt(KoCharacterStyle::OverlineMode));
1076 }
1077
setUnderlineStyle(KoCharacterStyle::LineStyle underline)1078 void KoCharacterStyle::setUnderlineStyle(KoCharacterStyle::LineStyle underline)
1079 {
1080 d->setProperty(UnderlineStyle, underline);
1081 }
1082
underlineStyle() const1083 KoCharacterStyle::LineStyle KoCharacterStyle::underlineStyle() const
1084 {
1085 return (KoCharacterStyle::LineStyle) d->propertyInt(UnderlineStyle);
1086 }
1087
setUnderlineType(LineType lineType)1088 void KoCharacterStyle::setUnderlineType(LineType lineType)
1089 {
1090 d->setProperty(UnderlineType, lineType);
1091 }
1092
underlineType() const1093 KoCharacterStyle::LineType KoCharacterStyle::underlineType() const
1094 {
1095 return (KoCharacterStyle::LineType) d->propertyInt(UnderlineType);
1096 }
1097
setUnderlineColor(const QColor & color)1098 void KoCharacterStyle::setUnderlineColor(const QColor &color)
1099 {
1100 d->setProperty(QTextFormat::TextUnderlineColor, color);
1101 }
1102
underlineColor() const1103 QColor KoCharacterStyle::underlineColor() const
1104 {
1105 return d->propertyColor(QTextFormat::TextUnderlineColor);
1106 }
1107
setUnderlineWidth(LineWeight weight,qreal width)1108 void KoCharacterStyle::setUnderlineWidth(LineWeight weight, qreal width)
1109 {
1110 d->setProperty(KoCharacterStyle::UnderlineWeight, weight);
1111 d->setProperty(KoCharacterStyle::UnderlineWidth, width);
1112 }
1113
underlineWidth(LineWeight & weight,qreal & width) const1114 void KoCharacterStyle::underlineWidth(LineWeight &weight, qreal &width) const
1115 {
1116 weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::UnderlineWeight);
1117 width = d->propertyDouble(KoCharacterStyle::UnderlineWidth);
1118 }
1119
setUnderlineMode(LineMode mode)1120 void KoCharacterStyle::setUnderlineMode(LineMode mode)
1121 {
1122 d->setProperty(KoCharacterStyle::UnderlineMode, mode);
1123 }
1124
underlineMode() const1125 KoCharacterStyle::LineMode KoCharacterStyle::underlineMode() const
1126 {
1127 return static_cast<KoCharacterStyle::LineMode>(d->propertyInt(KoCharacterStyle::UnderlineMode));
1128 }
1129
setFontLetterSpacing(qreal spacing)1130 void KoCharacterStyle::setFontLetterSpacing(qreal spacing)
1131 {
1132 d->setProperty(KoCharacterStyle::FontLetterSpacing, spacing);
1133 }
1134
fontLetterSpacing() const1135 qreal KoCharacterStyle::fontLetterSpacing() const
1136 {
1137 return d->propertyDouble(KoCharacterStyle::FontLetterSpacing);
1138 }
1139
setFontWordSpacing(qreal spacing)1140 void KoCharacterStyle::setFontWordSpacing(qreal spacing)
1141 {
1142 d->setProperty(QTextCharFormat::FontWordSpacing, spacing);
1143 }
1144
fontWordSpacing() const1145 qreal KoCharacterStyle::fontWordSpacing() const
1146 {
1147 return d->propertyDouble(QTextCharFormat::FontWordSpacing);
1148 }
1149
1150
setFontCapitalization(QFont::Capitalization capitalization)1151 void KoCharacterStyle::setFontCapitalization(QFont::Capitalization capitalization)
1152 {
1153 d->setProperty(QTextFormat::FontCapitalization, capitalization);
1154 }
1155
fontCapitalization() const1156 QFont::Capitalization KoCharacterStyle::fontCapitalization() const
1157 {
1158 return (QFont::Capitalization) d->propertyInt(QTextFormat::FontCapitalization);
1159 }
1160
1161
setFontYStretch(qreal stretch)1162 void KoCharacterStyle::setFontYStretch(qreal stretch)
1163 {
1164 d->setProperty(KoCharacterStyle::FontYStretch, stretch);
1165 }
1166
fontYStretch() const1167 qreal KoCharacterStyle::fontYStretch() const
1168 {
1169 return d->propertyDouble(KoCharacterStyle::FontYStretch);
1170 }
1171
setCountry(const QString & country)1172 void KoCharacterStyle::setCountry(const QString &country)
1173 {
1174 if (country.isEmpty())
1175 d->stylesPrivate.remove(KoCharacterStyle::Country);
1176 else
1177 d->setProperty(KoCharacterStyle::Country, country);
1178 }
1179
setLanguage(const QString & language)1180 void KoCharacterStyle::setLanguage(const QString &language)
1181 {
1182 if (language.isEmpty())
1183 d->stylesPrivate.remove(KoCharacterStyle::Language);
1184 else
1185 d->setProperty(KoCharacterStyle::Language, language);
1186 }
1187
country() const1188 QString KoCharacterStyle::country() const
1189 {
1190 return value(KoCharacterStyle::Country).toString();
1191 }
1192
language() const1193 QString KoCharacterStyle::language() const
1194 {
1195 return d->propertyString(KoCharacterStyle::Language);
1196 }
1197
blinking() const1198 bool KoCharacterStyle::blinking() const
1199 {
1200 return d->propertyBoolean(Blink);
1201 }
1202
setBlinking(bool blink)1203 void KoCharacterStyle::setBlinking(bool blink)
1204 {
1205 d->setProperty(KoCharacterStyle::Blink, blink);
1206 }
1207
hasProperty(int key) const1208 bool KoCharacterStyle::hasProperty(int key) const
1209 {
1210 return d->stylesPrivate.contains(key);
1211 }
1212
rotationScaleToString(KoCharacterStyle::RotationScale rotationScale)1213 static QString rotationScaleToString(KoCharacterStyle::RotationScale rotationScale)
1214 {
1215 QString scale = "line-height";
1216 if (rotationScale == KoCharacterStyle::Fixed) {
1217 scale = "fixed";
1218 }
1219 return scale;
1220 }
1221
stringToRotationScale(const QString & scale)1222 static KoCharacterStyle::RotationScale stringToRotationScale(const QString &scale)
1223 {
1224 KoCharacterStyle::RotationScale rotationScale = KoCharacterStyle::LineHeight;
1225 if (scale == "fixed") {
1226 rotationScale = KoCharacterStyle::Fixed;
1227 }
1228 return rotationScale;
1229 }
1230
setTextRotationAngle(qreal angle)1231 void KoCharacterStyle::setTextRotationAngle(qreal angle)
1232 {
1233 d->setProperty(TextRotationAngle, angle);
1234 }
1235
textRotationAngle() const1236 qreal KoCharacterStyle::textRotationAngle() const
1237 {
1238 return d->propertyDouble(TextRotationAngle);
1239 }
1240
setTextRotationScale(RotationScale scale)1241 void KoCharacterStyle::setTextRotationScale(RotationScale scale)
1242 {
1243 d->setProperty(TextRotationScale, rotationScaleToString(scale));
1244 }
1245
textRotationScale() const1246 KoCharacterStyle::RotationScale KoCharacterStyle::textRotationScale() const
1247 {
1248 return stringToRotationScale(d->propertyString(TextRotationScale));
1249 }
1250
setTextScale(int scale)1251 void KoCharacterStyle::setTextScale(int scale)
1252 {
1253 d->setProperty(TextScale, scale);
1254 }
1255
textScale() const1256 int KoCharacterStyle::textScale() const
1257 {
1258 return d->propertyInt(TextScale);
1259 }
1260
setTextShadow(const KoShadowStyle & shadow)1261 void KoCharacterStyle::setTextShadow(const KoShadowStyle& shadow)
1262 {
1263 d->setProperty(TextShadow, qVariantFromValue<KoShadowStyle>(shadow));
1264 }
1265
textShadow() const1266 KoShadowStyle KoCharacterStyle::textShadow() const
1267 {
1268 if (hasProperty(TextShadow)) {
1269 QVariant shadow = value(TextShadow);
1270 if (shadow.canConvert<KoShadowStyle>())
1271 return shadow.value<KoShadowStyle>();
1272 }
1273 return KoShadowStyle();
1274 }
1275
setTextCombine(KoCharacterStyle::TextCombineType type)1276 void KoCharacterStyle::setTextCombine(KoCharacterStyle::TextCombineType type)
1277 {
1278 d->setProperty(TextCombine, type);
1279 }
1280
textCombine() const1281 KoCharacterStyle::TextCombineType KoCharacterStyle::textCombine() const
1282 {
1283 if (hasProperty(TextCombine)) {
1284 return (KoCharacterStyle::TextCombineType) d->propertyInt(TextCombine);
1285 }
1286 return NoTextCombine;
1287 }
1288
textCombineEndChar() const1289 QChar KoCharacterStyle::textCombineEndChar() const
1290 {
1291 if (hasProperty(TextCombineEndChar)) {
1292 QString val = d->propertyString(TextCombineEndChar);
1293 if (val.length() > 0)
1294 return val.at(0);
1295 }
1296 return QChar();
1297 }
1298
setTextCombineEndChar(const QChar & character)1299 void KoCharacterStyle::setTextCombineEndChar(const QChar& character)
1300 {
1301 d->setProperty(TextCombineEndChar, character);
1302 }
1303
textCombineStartChar() const1304 QChar KoCharacterStyle::textCombineStartChar() const
1305 {
1306 if (hasProperty(TextCombineStartChar)) {
1307 QString val = d->propertyString(TextCombineStartChar);
1308 if (val.length() > 0)
1309 return val.at(0);
1310 }
1311 return QChar();
1312 }
1313
setTextCombineStartChar(const QChar & character)1314 void KoCharacterStyle::setTextCombineStartChar(const QChar& character)
1315 {
1316 d->setProperty(TextCombineStartChar, character);
1317 }
1318
setFontRelief(KoCharacterStyle::ReliefType relief)1319 void KoCharacterStyle::setFontRelief(KoCharacterStyle::ReliefType relief)
1320 {
1321 d->setProperty(FontRelief, relief);
1322 }
1323
fontRelief() const1324 KoCharacterStyle::ReliefType KoCharacterStyle::fontRelief() const
1325 {
1326 if (hasProperty(FontRelief))
1327 return (KoCharacterStyle::ReliefType) d->propertyInt(FontRelief);
1328 return KoCharacterStyle::NoRelief;
1329 }
1330
1331
textEmphasizePosition() const1332 KoCharacterStyle::EmphasisPosition KoCharacterStyle::textEmphasizePosition() const
1333 {
1334 if (hasProperty(TextEmphasizePosition))
1335 return (KoCharacterStyle::EmphasisPosition) d->propertyInt(TextEmphasizePosition);
1336 return KoCharacterStyle::EmphasisAbove;
1337 }
1338
setTextEmphasizePosition(KoCharacterStyle::EmphasisPosition position)1339 void KoCharacterStyle::setTextEmphasizePosition(KoCharacterStyle::EmphasisPosition position)
1340 {
1341 d->setProperty(TextEmphasizePosition, position);
1342 }
1343
textEmphasizeStyle() const1344 KoCharacterStyle::EmphasisStyle KoCharacterStyle::textEmphasizeStyle() const
1345 {
1346 if (hasProperty(TextEmphasizeStyle))
1347 return (KoCharacterStyle::EmphasisStyle) d->propertyInt(TextEmphasizeStyle);
1348 return KoCharacterStyle::NoEmphasis;
1349 }
1350
setTextEmphasizeStyle(KoCharacterStyle::EmphasisStyle emphasis)1351 void KoCharacterStyle::setTextEmphasizeStyle(KoCharacterStyle::EmphasisStyle emphasis)
1352 {
1353 d->setProperty(TextEmphasizeStyle, emphasis);
1354 }
1355
setPercentageFontSize(qreal percent)1356 void KoCharacterStyle::setPercentageFontSize(qreal percent)
1357 {
1358 d->setProperty(KoCharacterStyle::PercentageFontSize, percent);
1359 }
1360
percentageFontSize() const1361 qreal KoCharacterStyle::percentageFontSize() const
1362 {
1363 return d->propertyDouble(KoCharacterStyle::PercentageFontSize);
1364 }
1365
setAdditionalFontSize(qreal percent)1366 void KoCharacterStyle::setAdditionalFontSize(qreal percent)
1367 {
1368 d->setProperty(KoCharacterStyle::AdditionalFontSize, percent);
1369 }
1370
additionalFontSize() const1371 qreal KoCharacterStyle::additionalFontSize() const
1372 {
1373 return d->propertyDouble(KoCharacterStyle::AdditionalFontSize);
1374 }
1375
loadOdf(const KoXmlElement * element,KoShapeLoadingContext & scontext,bool loadParents)1376 void KoCharacterStyle::loadOdf(const KoXmlElement *element, KoShapeLoadingContext &scontext,
1377 bool loadParents)
1378 {
1379 KoOdfLoadingContext &context = scontext.odfLoadingContext();
1380 const QString name(element->attributeNS(KoXmlNS::style, "display-name", QString()));
1381 if (!name.isEmpty()) {
1382 d->name = name;
1383 }
1384 else {
1385 d->name = element->attributeNS(KoXmlNS::style, "name", QString());
1386 }
1387
1388 QString family = element->attributeNS(KoXmlNS::style, "family", "text");
1389
1390 context.styleStack().save();
1391 if (loadParents) {
1392 context.addStyles(element, family.toLocal8Bit().constData()); // Load all parent
1393 } else {
1394 context.styleStack().push(*element);
1395 }
1396 context.styleStack().setTypeProperties("text"); // load the style:text-properties
1397 loadOdfProperties(scontext);
1398 context.styleStack().restore();
1399 }
1400
loadOdfProperties(KoShapeLoadingContext & scontext)1401 void KoCharacterStyle::loadOdfProperties(KoShapeLoadingContext &scontext)
1402 {
1403 KoStyleStack &styleStack = scontext.odfLoadingContext().styleStack();
1404
1405 d->stylesPrivate = StylePrivate();
1406
1407 // The fo:color attribute specifies the foreground color of text.
1408 const QString color(styleStack.property(KoXmlNS::fo, "color"));
1409 if (!color.isEmpty()) {
1410 QColor c(color);
1411 if (c.isValid()) { // 3.10.3
1412 setForeground(QBrush(c));
1413 }
1414 }
1415
1416 QString fontName(styleStack.property(KoXmlNS::fo, "font-family"));
1417 if (!fontName.isEmpty()) {
1418 // Specify whether a font has a fixed or variable width.
1419 // These attributes are ignored if there is no corresponding fo:font-family attribute attached to the same formatting properties element.
1420 const QString fontPitch(styleStack.property(KoXmlNS::style, "font-pitch"));
1421 if (!fontPitch.isEmpty()) {
1422 setFontFixedPitch(fontPitch == "fixed");
1423 }
1424
1425 const QString genericFamily(styleStack.property(KoXmlNS::style, "font-family-generic"));
1426 if (!genericFamily.isEmpty()) {
1427 if (genericFamily == "roman")
1428 setFontStyleHint(QFont::Serif);
1429 else if (genericFamily == "swiss")
1430 setFontStyleHint(QFont::SansSerif);
1431 else if (genericFamily == "modern")
1432 setFontStyleHint(QFont::TypeWriter);
1433 else if (genericFamily == "decorative")
1434 setFontStyleHint(QFont::Decorative);
1435 else if (genericFamily == "system")
1436 setFontStyleHint(QFont::System);
1437 else if (genericFamily == "script") {
1438 ; // TODO: no hint available in Qt yet, we should at least store it as a property internally!
1439 }
1440 }
1441
1442 const QString fontCharset(styleStack.property(KoXmlNS::style, "font-charset"));
1443 if (!fontCharset.isEmpty()) {
1444 // this property is not required by Qt, since Qt auto selects the right font based on the text
1445 // The only charset of interest to us is x-symbol - this should disable spell checking
1446 d->setProperty(KoCharacterStyle::FontCharset, fontCharset);
1447 }
1448 }
1449
1450 const QString fontFamily(styleStack.property(KoXmlNS::style, "font-family"));
1451 if (!fontFamily.isEmpty())
1452 fontName = fontFamily;
1453
1454 if (styleStack.hasProperty(KoXmlNS::style, "font-name")) {
1455 // This font name is a reference to a font face declaration.
1456 KoOdfStylesReader &stylesReader = scontext.odfLoadingContext().stylesReader();
1457 const KoXmlElement *fontFace = stylesReader.findStyle(styleStack.property(KoXmlNS::style, "font-name"));
1458 if (fontFace != 0) {
1459 fontName = fontFace->attributeNS(KoXmlNS::svg, "font-family", "");
1460
1461 KoXmlElement fontFaceElem;
1462 forEachElement(fontFaceElem, (*fontFace)) {
1463 if (fontFaceElem.tagName() == "font-face-src") {
1464 KoXmlElement fontUriElem;
1465 forEachElement(fontUriElem, fontFaceElem) {
1466 if (fontUriElem.tagName() == "font-face-uri") {
1467 QString filename = fontUriElem.attributeNS(KoXmlNS::xlink, "href");
1468 KoStore *store = scontext.odfLoadingContext().store();
1469 if (store->open(filename)) {
1470 KoStoreDevice device(store);
1471 QByteArray data = device.readAll();
1472 if (device.open(QIODevice::ReadOnly)) {
1473 QFontDatabase::addApplicationFontFromData(data);
1474 }
1475 }
1476 }
1477 }
1478 }
1479 }
1480 }
1481 }
1482
1483 if (!fontName.isEmpty()) {
1484 // Hmm, the remove "'" could break it's in the middle of the fontname...
1485 fontName = fontName.remove('\'');
1486
1487 // 'Thorndale' is not known outside OpenOffice so we substitute it
1488 // with 'Times New Roman' that looks nearly the same.
1489 if (fontName == "Thorndale")
1490 fontName = "Times New Roman";
1491
1492 // 'StarSymbol' is written by OpenOffice but they actually mean
1493 // 'OpenSymbol'.
1494 if (fontName == "StarSymbol")
1495 fontName = "OpenSymbol";
1496
1497 fontName.remove(QRegExp("\\sCE$")); // Arial CE -> Arial
1498 setFontFamily(fontName);
1499 }
1500
1501 // Specify the size of a font. The value of these attribute is either an absolute length or a percentage
1502 if (styleStack.hasProperty(KoXmlNS::fo, "font-size")) {
1503 const QString fontSize(styleStack.property(KoXmlNS::fo, "font-size"));
1504 if (!fontSize.isEmpty()) {
1505 if (fontSize.endsWith('%')) {
1506 setPercentageFontSize(fontSize.left(fontSize.length() - 1).toDouble());
1507 } else {
1508 setFontPointSize(KoUnit::parseValue(fontSize));
1509 }
1510 }
1511 }
1512 else {
1513 const QString fontSizeRel(styleStack.property(KoXmlNS::style, "font-size-rel"));
1514 if (!fontSizeRel.isEmpty()) {
1515 setAdditionalFontSize(KoUnit::parseValue(fontSizeRel));
1516 }
1517 }
1518
1519 // Specify the weight of a font. The permitted values are normal, bold, and numeric values 100-900, in steps of 100. Unsupported numerical values are rounded off to the next supported value.
1520 const QString fontWeight(styleStack.property(KoXmlNS::fo, "font-weight"));
1521 if (!fontWeight.isEmpty()) { // 3.10.24
1522 int boldness;
1523 if (fontWeight == "normal")
1524 boldness = 50;
1525 else if (fontWeight == "bold")
1526 boldness = 75;
1527 else
1528 // XSL/CSS has 100,200,300...900. Not the same scale as Qt!
1529 // See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
1530 boldness = fontWeight.toInt() / 10;
1531 setFontWeight(boldness);
1532 }
1533
1534 // Specify whether to use normal or italic font face.
1535 const QString fontStyle(styleStack.property(KoXmlNS::fo, "font-style" ));
1536 if (!fontStyle.isEmpty()) { // 3.10.19
1537 if (fontStyle == "italic" || fontStyle == "oblique") { // no difference in kotext
1538 setFontItalic(true);
1539 } else {
1540 setFontItalic(false);
1541 }
1542 }
1543
1544 //TODO
1545 #if 0
1546 d->m_bWordByWord = styleStack.property(KoXmlNS::style, "text-underline-mode") == "skip-white-space";
1547 // TODO style:text-line-through-mode
1548
1549 /*
1550 // OO compat code, to move to OO import filter
1551 d->m_bWordByWord = (styleStack.hasProperty( KoXmlNS::fo, "score-spaces")) // 3.10.25
1552 && (styleStack.property( KoXmlNS::fo, "score-spaces") == "false");
1553 if( styleStack.hasProperty( KoXmlNS::style, "text-crossing-out" )) { // 3.10.6
1554 QString strikeOutType = styleStack.property( KoXmlNS::style, "text-crossing-out" );
1555 if( strikeOutType =="double-line")
1556 m_strikeOutType = S_DOUBLE;
1557 else if( strikeOutType =="single-line")
1558 m_strikeOutType = S_SIMPLE;
1559 else if( strikeOutType =="thick-line")
1560 m_strikeOutType = S_SIMPLE_BOLD;
1561 // not supported by Words: "slash" and "X"
1562 // not supported by OO: stylelines (solid, dash, dot, dashdot, dashdotdot)
1563 }
1564 */
1565 #endif
1566
1567 // overline modes
1568 const QString textOverlineMode(styleStack.property( KoXmlNS::style, "text-overline-mode"));
1569 if (!textOverlineMode.isEmpty()) {
1570 if (textOverlineMode == "skip-white-space") {
1571 setOverlineMode(SkipWhiteSpaceLineMode);
1572 } else if (textOverlineMode == "continuous") {
1573 setOverlineMode(ContinuousLineMode);
1574 }
1575 }
1576
1577 // Specifies whether text is overlined, and if so, whether a single or qreal line will be used for overlining.
1578 const QString textOverlineType(styleStack.property(KoXmlNS::style, "text-overline-type"));
1579 const QString textOverlineStyle(styleStack.property(KoXmlNS::style, "text-overline-style"));
1580 if (!textOverlineType.isEmpty() || !textOverlineStyle.isEmpty()) { // OASIS 14.4.28
1581 LineStyle overlineStyle;
1582 LineType overlineType;
1583
1584 importOdfLine(textOverlineType, textOverlineStyle,
1585 overlineStyle, overlineType);
1586 setOverlineStyle(overlineStyle);
1587 setOverlineType(overlineType);
1588 }
1589
1590 const QString textOverlineWidth(styleStack.property(KoXmlNS::style, "text-overline-width"));
1591 if (!textOverlineWidth.isEmpty()) {
1592 qreal overlineWidth;
1593 LineWeight overlineWeight;
1594 parseOdfLineWidth(textOverlineWidth, overlineWeight, overlineWidth);
1595 setOverlineWidth(overlineWeight, overlineWidth);
1596 }
1597
1598 // Specifies the color that is used to overline text. The value of this attribute is either font-color or a color. If the value is font-color, the current text color is used for overlining.
1599 QString overLineColor = styleStack.property(KoXmlNS::style, "text-overline-color"); // OO 3.10.23, OASIS 14.4.31
1600 if (!overLineColor.isEmpty() && overLineColor != "font-color") {
1601 setOverlineColor(QColor(overLineColor));
1602 } else if (overLineColor == "font-color") {
1603 setOverlineColor(QColor());
1604 }
1605
1606 // underline modes
1607 const QString textUndelineMode(styleStack.property( KoXmlNS::style, "text-underline-mode"));
1608 if (!textUndelineMode.isEmpty()) {
1609 if (textUndelineMode == "skip-white-space") {
1610 setUnderlineMode(SkipWhiteSpaceLineMode);
1611 } else if (textUndelineMode == "continuous") {
1612 setUnderlineMode(ContinuousLineMode);
1613 }
1614 }
1615
1616 // Specifies whether text is underlined, and if so, whether a single or qreal line will be used for underlining.
1617 const QString textUnderlineType(styleStack.property(KoXmlNS::style, "text-underline-type"));
1618 const QString textUnderlineStyle(styleStack.property(KoXmlNS::style, "text-underline-style"));
1619 if (!textUnderlineType.isEmpty() || !textUnderlineStyle.isEmpty()) { // OASIS 14.4.28
1620 LineStyle underlineStyle;
1621 LineType underlineType;
1622
1623 importOdfLine(textUnderlineType, textUnderlineStyle,
1624 underlineStyle, underlineType);
1625 setUnderlineStyle(underlineStyle);
1626 setUnderlineType(underlineType);
1627 }
1628
1629 const QString textUnderlineWidth(styleStack.property(KoXmlNS::style, "text-underline-width"));
1630 if (!textUnderlineWidth.isEmpty()) {
1631 qreal underlineWidth;
1632 LineWeight underlineWeight;
1633 parseOdfLineWidth(textUnderlineWidth, underlineWeight, underlineWidth);
1634 setUnderlineWidth(underlineWeight, underlineWidth);
1635 }
1636
1637 // Specifies the color that is used to underline text. The value of this attribute is either font-color or a color. If the value is font-color, the current text color is used for underlining.
1638 QString underLineColor = styleStack.property(KoXmlNS::style, "text-underline-color"); // OO 3.10.23, OASIS 14.4.31
1639 if (!underLineColor.isEmpty() && underLineColor != "font-color") {
1640 setUnderlineColor(QColor(underLineColor));
1641 } else if (underLineColor == "font-color") {
1642 setUnderlineColor(QColor());
1643 }
1644
1645
1646 const QString textLineThroughType(styleStack.property(KoXmlNS::style, "text-line-through-type"));
1647 const QString textLineThroughStyle(styleStack.property(KoXmlNS::style, "text-line-through-style"));
1648 if (!textLineThroughType.isEmpty() || !textLineThroughStyle.isEmpty()) { // OASIS 14.4.7
1649 KoCharacterStyle::LineStyle throughStyle;
1650 LineType throughType;
1651
1652 importOdfLine(textLineThroughType,textLineThroughStyle,
1653 throughStyle, throughType);
1654
1655 setStrikeOutStyle(throughStyle);
1656 setStrikeOutType(throughType);
1657 const QString textLineThroughText(styleStack.property(KoXmlNS::style, "text-line-through-text"));
1658 if (!textLineThroughText.isEmpty()) {
1659 setStrikeOutText(textLineThroughText);
1660 }
1661 }
1662
1663 const QString textLineThroughWidth(styleStack.property(KoXmlNS::style, "text-line-through-width"));
1664 if (!textLineThroughWidth.isEmpty()) {
1665 qreal throughWidth;
1666 LineWeight throughWeight;
1667 parseOdfLineWidth(textLineThroughWidth, throughWeight, throughWidth);
1668 setStrikeOutWidth(throughWeight, throughWidth);
1669 }
1670
1671 const QString lineThroughColor(styleStack.property(KoXmlNS::style, "text-line-through-color")); // OO 3.10.23, OASIS 14.4.31
1672 if (!lineThroughColor.isEmpty() && lineThroughColor != "font-color") {
1673 setStrikeOutColor(QColor(lineThroughColor));
1674 }
1675
1676 const QString lineThroughMode(styleStack.property(KoXmlNS::style, "text-line-through-mode"));
1677 if (lineThroughMode == "continuous") {
1678 setStrikeOutMode(ContinuousLineMode);
1679 }
1680 else if (lineThroughMode == "skip-white-space") {
1681 setStrikeOutMode(SkipWhiteSpaceLineMode);
1682 }
1683
1684 const QString textPosition(styleStack.property(KoXmlNS::style, "text-position"));
1685 if (!textPosition.isEmpty()) { // OO 3.10.7
1686 if (textPosition.startsWith("super"))
1687 setVerticalAlignment(QTextCharFormat::AlignSuperScript);
1688 else if (textPosition.startsWith("sub"))
1689 setVerticalAlignment(QTextCharFormat::AlignSubScript);
1690 else {
1691 QRegExp re("(-?[\\d.]+)%.*");
1692 if (re.exactMatch(textPosition)) {
1693 int percent = re.capturedTexts()[1].toInt();
1694 if (percent > 0)
1695 setVerticalAlignment(QTextCharFormat::AlignSuperScript);
1696 else if (percent < 0)
1697 setVerticalAlignment(QTextCharFormat::AlignSubScript);
1698 else // set explicit to overwrite inherited text-position's
1699 setVerticalAlignment(QTextCharFormat::AlignNormal);
1700 }
1701 }
1702 }
1703
1704 // The fo:font-variant attribute provides the option to display text as small capitalized letters.
1705 const QString textVariant(styleStack.property(KoXmlNS::fo, "font-variant"));
1706 if (!textVariant.isEmpty()) {
1707 if (textVariant == "small-caps")
1708 setFontCapitalization(QFont::SmallCaps);
1709 else if (textVariant == "normal")
1710 setFontCapitalization(QFont::MixedCase);
1711 }
1712 // The fo:text-transform attribute specifies text transformations to uppercase, lowercase, and capitalization.
1713 else {
1714 const QString textTransform(styleStack.property(KoXmlNS::fo, "text-transform"));
1715 if (!textTransform.isEmpty()) {
1716 if (textTransform == "uppercase")
1717 setFontCapitalization(QFont::AllUppercase);
1718 else if (textTransform == "lowercase")
1719 setFontCapitalization(QFont::AllLowercase);
1720 else if (textTransform == "capitalize")
1721 setFontCapitalization(QFont::Capitalize);
1722 else if (textTransform == "none")
1723 setFontCapitalization(QFont::MixedCase);
1724 }
1725 }
1726
1727 const QString foLanguage(styleStack.property(KoXmlNS::fo, "language"));
1728 if (!foLanguage.isEmpty()) {
1729 setLanguage(foLanguage);
1730 }
1731
1732 const QString foCountry(styleStack.property(KoXmlNS::fo, "country"));
1733 if (!foCountry.isEmpty()) {
1734 setCountry(foCountry);
1735 }
1736
1737 // The fo:background-color attribute specifies the background color of a paragraph.
1738 const QString bgcolor(styleStack.property(KoXmlNS::fo, "background-color"));
1739 if (!bgcolor.isEmpty()) {
1740 QBrush brush = background();
1741 if (bgcolor == "transparent")
1742 brush.setStyle(Qt::NoBrush);
1743 else {
1744 if (brush.style() == Qt::NoBrush)
1745 brush.setStyle(Qt::SolidPattern);
1746 brush.setColor(bgcolor); // #rrggbb format
1747 }
1748 setBackground(brush);
1749 }
1750
1751 // The style:use-window-font-color attribute specifies whether or not the window foreground color should be as used as the foreground color for a light background color and white for a dark background color.
1752 const QString useWindowFont(styleStack.property(KoXmlNS::style, "use-window-font-color"));
1753 if (!useWindowFont.isEmpty()) {
1754 setFontAutoColor(useWindowFont == "true");
1755 }
1756
1757 const QString letterKerning(styleStack.property( KoXmlNS::style, "letter-kerning"));
1758 if (!letterKerning.isEmpty()) {
1759 setFontKerning(letterKerning == "true");
1760 }
1761
1762 const QString letterSpacing(styleStack.property(KoXmlNS::fo, "letter-spacing"));
1763 if ((!letterSpacing.isEmpty()) && (letterSpacing != "normal")) {
1764 qreal space = KoUnit::parseValue(letterSpacing);
1765 setFontLetterSpacing(space);
1766 }
1767
1768 const QString textOutline(styleStack.property(KoXmlNS::style, "text-outline"));
1769 if (!textOutline.isEmpty()) {
1770 if (textOutline == "true") {
1771 setTextOutline(QPen((foreground().style() != Qt::NoBrush)?foreground():QBrush(Qt::black) , 0));
1772 setForeground(Qt::transparent);
1773 } else {
1774 setTextOutline(QPen(Qt::NoPen));
1775 }
1776 }
1777
1778 const QString textRotationAngle(styleStack.property(KoXmlNS::style, "text-rotation-angle"));
1779 if (!textRotationAngle.isEmpty()) {
1780 setTextRotationAngle(KoUnit::parseAngle(textRotationAngle));
1781 }
1782
1783 const QString textRotationScale(styleStack.property(KoXmlNS::style, "text-rotation-scale"));
1784 if (!textRotationScale.isEmpty()) {
1785 setTextRotationScale(stringToRotationScale(textRotationScale));
1786 }
1787
1788 const QString textScale(styleStack.property(KoXmlNS::style, "text-scale"));
1789 if (!textScale.isEmpty()) {
1790 const int scale = (textScale.endsWith('%') ? textScale.left(textScale.length()-1) : textScale).toInt();
1791 setTextScale(scale);
1792 }
1793
1794 const QString textShadow(styleStack.property(KoXmlNS::fo, "text-shadow"));
1795 if (!textShadow.isEmpty()) {
1796 KoShadowStyle shadow;
1797 if (shadow.loadOdf(textShadow))
1798 setTextShadow(shadow);
1799 }
1800
1801 const QString textCombine(styleStack.property(KoXmlNS::style, "text-combine"));
1802 if (!textCombine.isEmpty()) {
1803 if (textCombine == "letters")
1804 setTextCombine(TextCombineLetters);
1805 else if (textCombine == "lines")
1806 setTextCombine(TextCombineLines);
1807 else if (textCombine == "none")
1808 setTextCombine(NoTextCombine);
1809 }
1810
1811 const QString textCombineEndChar(styleStack.property(KoXmlNS::style, "text-combine-end-char"));
1812 if (!textCombineEndChar.isEmpty()) {
1813 setTextCombineEndChar(textCombineEndChar.at(0));
1814 }
1815 const QString textCombineStartChar(styleStack.property(KoXmlNS::style, "text-combine-start-char"));
1816 if (!textCombineStartChar.isEmpty()) {
1817 setTextCombineStartChar(textCombineStartChar.at(0));
1818 }
1819
1820
1821 const QString fontRelief(styleStack.property(KoXmlNS::style, "font-relief"));
1822 if (!fontRelief.isEmpty()) {
1823 if (fontRelief == "none")
1824 setFontRelief(KoCharacterStyle::NoRelief);
1825 else if (fontRelief == "embossed")
1826 setFontRelief(KoCharacterStyle::Embossed);
1827 else if (fontRelief == "engraved")
1828 setFontRelief(KoCharacterStyle::Engraved);
1829 }
1830
1831 const QString fontEmphasize(styleStack.property(KoXmlNS::style, "text-emphasize"));
1832 if (!fontEmphasize.isEmpty()) {
1833 QString style, position;
1834 QStringList parts = fontEmphasize.split(' ');
1835 style = parts[0];
1836 if (parts.length() > 1)
1837 position = parts[1];
1838
1839 if (style == "none") {
1840 setTextEmphasizeStyle(NoEmphasis);
1841 } else if (style == "accent") {
1842 setTextEmphasizeStyle(AccentEmphasis);
1843 } else if (style == "circle") {
1844 setTextEmphasizeStyle(CircleEmphasis);
1845 } else if (style == "disc") {
1846 setTextEmphasizeStyle(DiscEmphasis);
1847 } else if (style == "dot") {
1848 setTextEmphasizeStyle(DotEmphasis);
1849 }
1850
1851 if (position == "below") {
1852 setTextEmphasizePosition(EmphasisBelow);
1853 } else if (position == "above") {
1854 setTextEmphasizePosition(EmphasisAbove);
1855 }
1856 }
1857
1858 if (styleStack.hasProperty(KoXmlNS::fo, "hyphenate"))
1859 setHasHyphenation(styleStack.property(KoXmlNS::fo, "hyphenate") == "true");
1860
1861 if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-remain-char-count")) {
1862 bool ok = false;
1863 int count = styleStack.property(KoXmlNS::fo, "hyphenation-remain-char-count").toInt(&ok);
1864 if (ok)
1865 setHyphenationRemainCharCount(count);
1866 }
1867 if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-push-char-count")) {
1868 bool ok = false;
1869 int count = styleStack.property(KoXmlNS::fo, "hyphenation-push-char-count").toInt(&ok);
1870 if (ok)
1871 setHyphenationPushCharCount(count);
1872 }
1873
1874 if (styleStack.hasProperty(KoXmlNS::style, "text-blinking")) {
1875 setBlinking(styleStack.property(KoXmlNS::style, "text-blinking") == "true");
1876 }
1877
1878
1879 //TODO
1880 #if 0
1881 /*
1882 Missing properties:
1883 style:font-style-name, 3.10.11 - can be ignored, says DV, the other ways to specify a font are more precise
1884 fo:letter-spacing, 3.10.16 - not implemented in kotext
1885 style:text-relief, 3.10.20 - not implemented in kotext
1886 style:text-blinking, 3.10.27 - not implemented in kotext IIRC
1887 style:text-combine, 3.10.29/30 - not implemented, see http://www.w3.org/TR/WD-i18n-format/
1888 style:text-emphasis, 3.10.31 - not implemented in kotext
1889 style:text-scale, 3.10.33 - not implemented in kotext
1890 style:text-rotation-angle, 3.10.34 - not implemented in kotext (kpr rotates whole objects)
1891 style:text-rotation-scale, 3.10.35 - not implemented in kotext (kpr rotates whole objects)
1892 style:punctuation-wrap, 3.10.36 - not implemented in kotext
1893 */
1894
1895 d->m_underLineWidth = 1.0;
1896
1897 generateKey();
1898 addRef();
1899 #endif
1900 }
1901
operator ==(const KoCharacterStyle & other) const1902 bool KoCharacterStyle::operator==(const KoCharacterStyle &other) const
1903 {
1904 return compareCharacterProperties(other);
1905 }
1906
operator !=(const KoCharacterStyle & other) const1907 bool KoCharacterStyle::operator!=(const KoCharacterStyle &other) const
1908 {
1909 return !compareCharacterProperties(other);
1910 }
1911
compareCharacterProperties(const KoCharacterStyle & other) const1912 bool KoCharacterStyle::compareCharacterProperties(const KoCharacterStyle &other) const
1913 {
1914 return other.d->stylesPrivate == d->stylesPrivate;
1915 }
1916
removeDuplicates(const KoCharacterStyle & other)1917 void KoCharacterStyle::removeDuplicates(const KoCharacterStyle &other)
1918 {
1919 // In case the current style doesn't have the flag UseWindowFontColor set but the other has it set and they use the same color
1920 // remove duplicates will remove the color. However to make it work correctly we need to store the color with the style so it
1921 // will be loaded again. We don't store a use-window-font-color="false" as that is not compatible to the way OO/LO does work.
1922 // So save the color and restore it after the remove duplicates
1923 QBrush brush;
1924 if (other.d->propertyBoolean(KoCharacterStyle::UseWindowFontColor) && !d->propertyBoolean(KoCharacterStyle::UseWindowFontColor)) {
1925 brush = foreground();
1926 }
1927
1928 // this properties should need to be kept if there is a font family defined as these are only evaluated if there is also a font family
1929 int keepProperties[] = { QTextFormat::FontStyleHint, QTextFormat::FontFixedPitch, KoCharacterStyle::FontCharset };
1930
1931 QMap<int, QVariant> keep;
1932 for (unsigned int i = 0; i < sizeof(keepProperties)/sizeof(*keepProperties); ++i) {
1933 if (hasProperty(keepProperties[i])) {
1934 keep.insert(keepProperties[i], value(keepProperties[i]));
1935 }
1936 }
1937 this->d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
1938 if (brush.style() != Qt::NoBrush) {
1939 setForeground(brush);
1940 }
1941
1942 // in case the char style has any of the following properties it also needs to have the fontFamily as otherwise
1943 // these values will be ignored when loading according to the odf spec
1944 if (!hasProperty(QTextFormat::FontFamily)) {
1945 if (hasProperty(QTextFormat::FontStyleHint) || hasProperty(QTextFormat::FontFixedPitch) || hasProperty(KoCharacterStyle::FontCharset)) {
1946 QString fontFamily = other.fontFamily();
1947 if (!fontFamily.isEmpty()) {
1948 setFontFamily(fontFamily);
1949 }
1950 }
1951 }
1952 else {
1953 for (QMap<int, QVariant>::const_iterator it(keep.constBegin()); it != keep.constEnd(); ++it) {
1954 this->d->stylesPrivate.add(it.key(), it.value());
1955 }
1956 }
1957 }
1958
removeDuplicates(const QTextCharFormat & otherFormat)1959 void KoCharacterStyle::removeDuplicates(const QTextCharFormat &otherFormat)
1960 {
1961 KoCharacterStyle other(otherFormat);
1962 removeDuplicates(other);
1963 }
1964
remove(int key)1965 void KoCharacterStyle::remove(int key)
1966 {
1967 d->stylesPrivate.remove(key);
1968 }
1969
isEmpty() const1970 bool KoCharacterStyle::isEmpty() const
1971 {
1972 return d->stylesPrivate.isEmpty();
1973 }
1974
saveOdf(KoGenStyle & style) const1975 void KoCharacterStyle::saveOdf(KoGenStyle &style) const
1976 {
1977 if (!d->name.isEmpty() && !style.isDefaultStyle()) {
1978 style.addAttribute("style:display-name", d->name);
1979 }
1980 QList<int> keys = d->stylesPrivate.keys();
1981 Q_FOREACH (int key, keys) {
1982 if (key == QTextFormat::FontWeight) {
1983 bool ok = false;
1984 int boldness = d->stylesPrivate.value(key).toInt(&ok);
1985 if (ok) {
1986 if (boldness == QFont::Normal) {
1987 style.addProperty("fo:font-weight", "normal", KoGenStyle::TextType);
1988 } else if (boldness == QFont::Bold) {
1989 style.addProperty("fo:font-weight", "bold", KoGenStyle::TextType);
1990 } else {
1991 // Remember : Qt and CSS/XSL doesn't have the same scale. Its 100-900 instead of Qts 0-100
1992 style.addProperty("fo:font-weight", qBound(10, boldness, 90) * 10, KoGenStyle::TextType);
1993 }
1994 }
1995 } else if (key == QTextFormat::FontItalic) {
1996 if (d->stylesPrivate.value(key).toBool()) {
1997 style.addProperty("fo:font-style", "italic", KoGenStyle::TextType);
1998 } else {
1999 style.addProperty("fo:font-style", "normal", KoGenStyle::TextType);
2000 }
2001 } else if (key == QTextFormat::FontFamily) {
2002 QString fontFamily = d->stylesPrivate.value(key).toString();
2003 style.addProperty("fo:font-family", fontFamily, KoGenStyle::TextType);
2004 } else if (key == QTextFormat::FontFixedPitch) {
2005 bool fixedPitch = d->stylesPrivate.value(key).toBool();
2006 style.addProperty("style:font-pitch", fixedPitch ? "fixed" : "variable", KoGenStyle::TextType);
2007 // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
2008 style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
2009 } else if (key == QTextFormat::FontStyleHint) {
2010 bool ok = false;
2011 int styleHint = d->stylesPrivate.value(key).toInt(&ok);
2012 if (ok) {
2013 QString generic = exportOdfFontStyleHint((QFont::StyleHint) styleHint);
2014 if (!generic.isEmpty()) {
2015 style.addProperty("style:font-family-generic", generic, KoGenStyle::TextType);
2016 }
2017 // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
2018 style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
2019 }
2020 } else if (key == QTextFormat::FontKerning) {
2021 style.addProperty("style:letter-kerning", fontKerning() ? "true" : "false", KoGenStyle::TextType);
2022 } else if (key == QTextFormat::FontCapitalization) {
2023 switch (fontCapitalization()) {
2024 case QFont::SmallCaps:
2025 style.addProperty("fo:font-variant", "small-caps", KoGenStyle::TextType);
2026 break;
2027 case QFont::MixedCase:
2028 style.addProperty("fo:font-variant", "normal", KoGenStyle::TextType);
2029 style.addProperty("fo:text-transform", "none", KoGenStyle::TextType);
2030 break;
2031 case QFont::AllUppercase:
2032 style.addProperty("fo:text-transform", "uppercase", KoGenStyle::TextType);
2033 break;
2034 case QFont::AllLowercase:
2035 style.addProperty("fo:text-transform", "lowercase", KoGenStyle::TextType);
2036 break;
2037 case QFont::Capitalize:
2038 style.addProperty("fo:text-transform", "capitalize", KoGenStyle::TextType);
2039 break;
2040 }
2041 } else if (key == OverlineStyle) {
2042 bool ok = false;
2043 int styleId = d->stylesPrivate.value(key).toInt(&ok);
2044 if (ok) {
2045 style.addProperty("style:text-overline-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
2046 }
2047 } else if (key == OverlineType) {
2048 bool ok = false;
2049 int type = d->stylesPrivate.value(key).toInt(&ok);
2050 if (ok) {
2051 style.addProperty("style:text-overline-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
2052 }
2053 } else if (key == OverlineColor) {
2054 QColor color = d->stylesPrivate.value(key).value<QColor>();
2055 if (color.isValid())
2056 style.addProperty("style:text-overline-color", color.name(), KoGenStyle::TextType);
2057 else
2058 style.addProperty("style:text-overline-color", "font-color", KoGenStyle::TextType);
2059 } else if (key == OverlineMode) {
2060 bool ok = false;
2061 int mode = d->stylesPrivate.value(key).toInt(&ok);
2062 if (ok) {
2063 style.addProperty("style:text-overline-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
2064 }
2065 } else if (key == OverlineWidth) {
2066 KoCharacterStyle::LineWeight weight;
2067 qreal width;
2068 overlineWidth(weight, width);
2069 style.addProperty("style:text-overline-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
2070 } else if (key == UnderlineStyle) {
2071 bool ok = false;
2072 int styleId = d->stylesPrivate.value(key).toInt(&ok);
2073 if (ok)
2074 style.addProperty("style:text-underline-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
2075 } else if (key == UnderlineType) {
2076 bool ok = false;
2077 int type = d->stylesPrivate.value(key).toInt(&ok);
2078 if (ok)
2079 style.addProperty("style:text-underline-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
2080 } else if (key == QTextFormat::TextUnderlineColor) {
2081 QColor color = d->stylesPrivate.value(key).value<QColor>();
2082 if (color.isValid())
2083 style.addProperty("style:text-underline-color", color.name(), KoGenStyle::TextType);
2084 else
2085 style.addProperty("style:text-underline-color", "font-color", KoGenStyle::TextType);
2086 } else if (key == UnderlineMode) {
2087 bool ok = false;
2088 int mode = d->stylesPrivate.value(key).toInt(&ok);
2089 if (ok)
2090 style.addProperty("style:text-underline-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
2091 } else if (key == UnderlineWidth) {
2092 KoCharacterStyle::LineWeight weight;
2093 qreal width;
2094 underlineWidth(weight, width);
2095 style.addProperty("style:text-underline-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
2096 } else if (key == StrikeOutStyle) {
2097 bool ok = false;
2098 int styleId = d->stylesPrivate.value(key).toInt(&ok);
2099 if (ok)
2100 style.addProperty("style:text-line-through-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
2101 } else if (key == StrikeOutType) {
2102 bool ok = false;
2103 int type = d->stylesPrivate.value(key).toInt(&ok);
2104 if (ok)
2105 style.addProperty("style:text-line-through-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
2106 } else if (key == StrikeOutText) {
2107 style.addProperty("style:text-line-through-text", d->stylesPrivate.value(key).toString(), KoGenStyle::TextType);
2108 } else if (key == StrikeOutColor) {
2109 QColor color = d->stylesPrivate.value(key).value<QColor>();
2110 if (color.isValid())
2111 style.addProperty("style:text-line-through-color", color.name(), KoGenStyle::TextType);
2112 } else if (key == StrikeOutMode) {
2113 bool ok = false;
2114 int mode = d->stylesPrivate.value(key).toInt(&ok);
2115 if (ok)
2116 style.addProperty("style:text-line-through-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
2117 } else if (key == StrikeOutWidth) {
2118 KoCharacterStyle::LineWeight weight;
2119 qreal width;
2120 strikeOutWidth(weight, width);
2121 style.addProperty("style:text-line-through-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
2122 } else if (key == QTextFormat::BackgroundBrush) {
2123 QBrush brush = d->stylesPrivate.value(key).value<QBrush>();
2124 if (brush.style() == Qt::NoBrush)
2125 style.addProperty("fo:background-color", "transparent", KoGenStyle::TextType);
2126 else
2127 style.addProperty("fo:background-color", brush.color().name(), KoGenStyle::TextType);
2128 } else if (key == QTextFormat::ForegroundBrush) {
2129 QBrush brush = d->stylesPrivate.value(key).value<QBrush>();
2130 if (brush.style() != Qt::NoBrush) {
2131 style.addProperty("fo:color", brush.color().name(), KoGenStyle::TextType);
2132 }
2133 } else if (key == KoCharacterStyle::UseWindowFontColor) {
2134 bool use = d->stylesPrivate.value(key).toBool();
2135 style.addProperty("style:use-window-font-color", use ? "true" : "false", KoGenStyle::TextType);
2136 } else if (key == QTextFormat::TextVerticalAlignment) {
2137 if (verticalAlignment() == QTextCharFormat::AlignSuperScript)
2138 style.addProperty("style:text-position", "super", KoGenStyle::TextType);
2139 else if (verticalAlignment() == QTextCharFormat::AlignSubScript)
2140 style.addProperty("style:text-position", "sub", KoGenStyle::TextType);
2141 else if (d->stylesPrivate.contains(QTextFormat::TextVerticalAlignment)) // no superscript or subscript
2142 style.addProperty("style:text-position", "0% 100%", KoGenStyle::TextType);
2143 } else if (key == QTextFormat::FontPointSize) {
2144 // when there is percentageFontSize!=100% property ignore the fontSize property and store the percentage property
2145 if ( (!hasProperty(KoCharacterStyle::PercentageFontSize)) || (percentageFontSize()==100))
2146 style.addPropertyPt("fo:font-size", fontPointSize(), KoGenStyle::TextType);
2147 } else if (key == KoCharacterStyle::PercentageFontSize) {
2148 if(percentageFontSize()!=100) {
2149 style.addProperty("fo:font-size", QString::number(percentageFontSize()) + '%', KoGenStyle::TextType);
2150 }
2151 } else if (key == KoCharacterStyle::Country) {
2152 style.addProperty("fo:country", d->stylesPrivate.value(KoCharacterStyle::Country).toString(), KoGenStyle::TextType);
2153 } else if (key == KoCharacterStyle::Language) {
2154 style.addProperty("fo:language", d->stylesPrivate.value(KoCharacterStyle::Language).toString(), KoGenStyle::TextType);
2155 } else if (key == KoCharacterStyle::FontLetterSpacing) {
2156 qreal space = fontLetterSpacing();
2157 style.addPropertyPt("fo:letter-spacing", space, KoGenStyle::TextType);
2158 } else if (key == QTextFormat::TextOutline) {
2159 QPen outline = textOutline();
2160 style.addProperty("style:text-outline", outline.style() == Qt::NoPen ? "false" : "true", KoGenStyle::TextType);
2161 } else if (key == KoCharacterStyle::FontCharset) {
2162 style.addProperty("style:font-charset", d->stylesPrivate.value(KoCharacterStyle::FontCharset).toString(), KoGenStyle::TextType);
2163 // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
2164 style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
2165 } else if (key == KoCharacterStyle::TextRotationAngle) {
2166 style.addProperty("style:text-rotation-angle", QString::number(textRotationAngle()), KoGenStyle::TextType);
2167 } else if (key == KoCharacterStyle::TextRotationScale) {
2168 RotationScale scale = textRotationScale();
2169 style.addProperty("style:text-rotation-scale", rotationScaleToString(scale), KoGenStyle::TextType);
2170 } else if (key == KoCharacterStyle::TextScale) {
2171 int scale = textScale();
2172 style.addProperty("style:text-scale", QString::number(scale) + '%', KoGenStyle::TextType);
2173 } else if (key == KoCharacterStyle::TextShadow) {
2174 KoShadowStyle shadow = textShadow();
2175 style.addProperty("fo:text-shadow", shadow.saveOdf(), KoGenStyle::TextType);
2176 } else if (key == KoCharacterStyle::TextCombine) {
2177 KoCharacterStyle::TextCombineType textCombineType = textCombine();
2178 switch (textCombineType)
2179 {
2180 case KoCharacterStyle::NoTextCombine:
2181 style.addProperty("style:text-combine", "none", KoGenStyle::TextType);
2182 break;
2183 case KoCharacterStyle::TextCombineLetters:
2184 style.addProperty("style:text-combine", "letters", KoGenStyle::TextType);
2185 break;
2186 case KoCharacterStyle::TextCombineLines:
2187 style.addProperty("style:text-combine", "lines", KoGenStyle::TextType);
2188 break;
2189 }
2190 } else if (key == KoCharacterStyle::TextCombineEndChar) {
2191 style.addProperty("style:text-combine-end-char", textCombineEndChar(), KoGenStyle::TextType);
2192 } else if (key == KoCharacterStyle::TextCombineStartChar) {
2193 style.addProperty("style:text-combine-start-char", textCombineStartChar(), KoGenStyle::TextType);
2194 } else if (key == KoCharacterStyle::FontRelief) {
2195 KoCharacterStyle::ReliefType relief = fontRelief();
2196 switch (relief)
2197 {
2198 case KoCharacterStyle::NoRelief:
2199 style.addProperty("style:font-relief", "none", KoGenStyle::TextType);
2200 break;
2201 case KoCharacterStyle::Embossed:
2202 style.addProperty("style:font-relief", "embossed", KoGenStyle::TextType);
2203 break;
2204 case KoCharacterStyle::Engraved:
2205 style.addProperty("style:font-relief", "engraved", KoGenStyle::TextType);
2206 break;
2207 }
2208 } else if (key == KoCharacterStyle::TextEmphasizeStyle) {
2209 KoCharacterStyle::EmphasisStyle emphasisStyle = textEmphasizeStyle();
2210 KoCharacterStyle::EmphasisPosition position = textEmphasizePosition();
2211 QString odfEmphasis;
2212 switch (emphasisStyle)
2213 {
2214 case KoCharacterStyle::NoEmphasis:
2215 odfEmphasis = "none";
2216 break;
2217 case KoCharacterStyle::AccentEmphasis:
2218 odfEmphasis = "accent";
2219 break;
2220 case KoCharacterStyle::CircleEmphasis:
2221 odfEmphasis = "circle";
2222 break;
2223 case KoCharacterStyle::DiscEmphasis:
2224 odfEmphasis = "disc";
2225 break;
2226 case KoCharacterStyle::DotEmphasis:
2227 odfEmphasis = "dot";
2228 break;
2229 }
2230 if (hasProperty(KoCharacterStyle::TextEmphasizePosition)) {
2231 if (position == KoCharacterStyle::EmphasisAbove)
2232 odfEmphasis += " above";
2233 else
2234 odfEmphasis += " below";
2235 }
2236 style.addProperty("style:text-emphasize", odfEmphasis, KoGenStyle::TextType);
2237 } else if (key == KoCharacterStyle::HasHyphenation) {
2238 if (hasHyphenation())
2239 style.addProperty("fo:hyphenate", "true", KoGenStyle::TextType);
2240 else
2241 style.addProperty("fo:hyphenate", "false", KoGenStyle::TextType);
2242 } else if (key == KoCharacterStyle::HyphenationPushCharCount) {
2243 style.addProperty("fo:hyphenation-push-char-count", hyphenationPushCharCount(), KoGenStyle::TextType);
2244 } else if (key == KoCharacterStyle::HyphenationRemainCharCount) {
2245 style.addProperty("fo:hyphenation-remain-char-count", hyphenationRemainCharCount(), KoGenStyle::TextType);
2246 } else if (key == KoCharacterStyle::Blink) {
2247 style.addProperty("style:text-blinking", blinking(), KoGenStyle::TextType);
2248 }
2249 }
2250 //TODO: font name and family
2251 }
2252
value(int key) const2253 QVariant KoCharacterStyle::value(int key) const
2254 {
2255 QVariant variant = d->stylesPrivate.value(key);
2256 if (variant.isNull()) {
2257 if (d->parentStyle)
2258 variant = d->parentStyle->value(key);
2259 else if (d->defaultStyle)
2260 variant = d->defaultStyle->value(key);
2261 }
2262 return variant;
2263 }
2264
removeHardCodedDefaults()2265 void KoCharacterStyle::removeHardCodedDefaults()
2266 {
2267 d->hardCodedDefaultStyle.clearAll();
2268 }
2269