1/* This file is part of the KDE project
2 Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3 Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
4 Copyright 2003 Norbert Andres <nandres@web.de>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22// Local
23#include "Style.h"
24
25#include <QBrush>
26#include <QHash>
27#include <QPen>
28
29#include <kdebug.h>
30#include <kglobal.h>
31#include <klocale.h>
32
33#include <KoGenStyles.h>
34#include <KoGlobal.h>
35#include <KoOdfStylesReader.h>
36#include <KoOdfGraphicStyles.h>
37#include <KoStyleStack.h>
38#include <KoUnit.h>
39#include <KoXmlNS.h>
40#include <KoXmlWriter.h>
41#include <KoOdfWorkaround.h>
42
43#include "Condition.h"
44#include "Currency.h"
45#include "Global.h"
46#include "StyleManager.h"
47#include "Util.h"
48
49using namespace Calligra::Sheets;
50
51/////////////////////////////////////////////////////////////////////////////
52//
53// SubStyles
54//
55/////////////////////////////////////////////////////////////////////////////
56
57namespace Calligra
58{
59namespace Sheets
60{
61
62static uint calculateValue(QPen const & pen)
63{
64 uint n = pen.color().red() + pen.color().green() + pen.color().blue();
65 n += 1000 * pen.width();
66 n += 10000 * (uint) pen.style();
67 return n;
68}
69
70// specialized debug method
71template<>
72QString SubStyleOne<Style::CurrencyFormat, Currency>::debugData(bool withName) const
73{
74 QString out; if (withName) out = name(Style::CurrencyFormat) + ' '; QDebug qdbg(&out); qdbg << value1.symbol(); return out;
75}
76
77template<Style::Key key>
78class PenStyle : public SubStyleOne<key, QPen>
79{
80public:
81 PenStyle(const QPen& p = Qt::NoPen) : SubStyleOne<key, QPen>(p) {}
82};
83
84template<Style::Key key>
85class BorderPenStyle : public PenStyle<key>
86{
87public:
88 BorderPenStyle(const QPen& p = Qt::NoPen) : PenStyle<key>(p), value(calculateValue(p)) {}
89 int value;
90};
91
92QString SubStyle::name(Style::Key key)
93{
94 QString name;
95 switch (key) {
96 case Style::DefaultStyleKey: name = "Default style"; break;
97 case Style::NamedStyleKey: name = "Named style"; break;
98 case Style::LeftPen: name = "Left pen"; break;
99 case Style::RightPen: name = "Right pen"; break;
100 case Style::TopPen: name = "Top pen"; break;
101 case Style::BottomPen: name = "Bottom pen"; break;
102 case Style::FallDiagonalPen: name = "Fall diagonal pen"; break;
103 case Style::GoUpDiagonalPen: name = "Go up diagonal pen"; break;
104 case Style::HorizontalAlignment: name = "Horz. alignment"; break;
105 case Style::VerticalAlignment: name = "Vert. alignment"; break;
106 case Style::MultiRow: name = "Wrap text"; break;
107 case Style::VerticalText: name = "Vertical text"; break;
108 case Style::Angle: name = "Angle"; break;
109 case Style::Indentation: name = "Indentation"; break;
110 case Style::ShrinkToFit: name = "Shrink to Fit"; break;
111 case Style::Prefix: name = "Prefix"; break;
112 case Style::Postfix: name = "Postfix"; break;
113 case Style::Precision: name = "Precision"; break;
114 case Style::ThousandsSep: name = "Thousands separator"; break;
115 case Style::FormatTypeKey: name = "Format type"; break;
116 case Style::FloatFormatKey: name = "Float format"; break;
117 case Style::FloatColorKey: name = "Float color"; break;
118 case Style::CurrencyFormat: name = "Currency"; break;
119 case Style::CustomFormat: name = "Custom format"; break;
120 case Style::BackgroundBrush: name = "Background brush"; break;
121 case Style::BackgroundColor: name = "Background color"; break;
122 case Style::FontColor: name = "Font color"; break;
123 case Style::FontFamily: name = "Font family"; break;
124 case Style::FontSize: name = "Font size"; break;
125 case Style::FontBold: name = "Font bold"; break;
126 case Style::FontItalic: name = "Font italic"; break;
127 case Style::FontStrike: name = "Font strikeout"; break;
128 case Style::FontUnderline: name = "Font underline"; break;
129 case Style::DontPrintText: name = "Do not print text"; break;
130 case Style::NotProtected: name = "Not protected"; break;
131 case Style::HideAll: name = "Hide all"; break;
132 case Style::HideFormula: name = "Hide formula"; break;
133 }
134 return name;
135}
136
137SharedSubStyle SharedSubStyle::s_defaultStyle(new SubStyle());
138
139} // namespace Sheets
140} // namespace Calligra
141
142/////////////////////////////////////////////////////////////////////////////
143//
144// Style::Private
145//
146/////////////////////////////////////////////////////////////////////////////
147
148class Style::Private : public QSharedData
149{
150public:
151 QHash<Key, SharedSubStyle> subStyles;
152};
153
154
155/////////////////////////////////////////////////////////////////////////////
156//
157// Style
158//
159/////////////////////////////////////////////////////////////////////////////
160
161Style::Style()
162 : d(new Private)
163{
164}
165
166Style::Style(const Style& style)
167 : d(style.d)
168{
169}
170
171Style::~Style()
172{
173}
174
175Style::StyleType Style::type() const
176{
177 return AUTO;
178}
179
180QString Style::parentName() const
181{
182 if (!d->subStyles.contains(NamedStyleKey))
183 return QString();
184 return static_cast<const NamedStyle*>(d->subStyles[NamedStyleKey].data())->name;
185}
186
187void Style::setParentName(const QString& name)
188{
189 d->subStyles.insert(NamedStyleKey, SharedSubStyle(new NamedStyle(name)));
190}
191
192void Style::clearAttribute(Key key)
193{
194 d->subStyles.remove(key);
195}
196
197bool Style::hasAttribute(Key key) const
198{
199 return d->subStyles.contains(key);
200}
201
202void Style::loadAttributes(const QList<SharedSubStyle>& subStyles)
203{
204 d->subStyles.clear();
205 for (int i = 0; i < subStyles.count(); ++i) {
206 // already existing items are replaced
207 d->subStyles.insert(subStyles[i]->type(), subStyles[i]);
208 }
209}
210
211void Style::loadOdfStyle(KoOdfStylesReader& stylesReader, const KoXmlElement& element,
212 Conditions& conditions, const StyleManager* styleManager,
213 const ValueParser *parser)
214{
215 // NOTE Stefan: Do not fill the style stack with the parent styles!
216 KoStyleStack styleStack;
217 styleStack.push(element);
218
219 styleStack.setTypeProperties("table-cell");
220 loadOdfTableCellProperties(stylesReader, styleStack);
221
222 styleStack.setTypeProperties("text");
223 loadOdfTextProperties(stylesReader, styleStack);
224
225 styleStack.setTypeProperties("paragraph");
226 loadOdfParagraphProperties(stylesReader, styleStack);
227
228 KoXmlElement e;
229 forEachElement(e, element) {
230 if (e.namespaceURI() == KoXmlNS::style && e.localName() == "map")
231 conditions.loadOdfConditions(e, parser, styleManager);
232 }
233
234 loadOdfDataStyle(stylesReader, element, conditions, styleManager, parser);
235}
236
237typedef QPair<QString,QString> StringPair;
238
239void Style::loadOdfDataStyle(KoOdfStylesReader& stylesReader, const KoXmlElement& element,
240 Conditions& conditions, const StyleManager* styleManager,
241 const ValueParser *parser)
242{
243 QString str;
244 if (element.hasAttributeNS(KoXmlNS::style, "data-style-name")) {
245 const QString styleName = element.attributeNS(KoXmlNS::style, "data-style-name", QString());
246 loadOdfDataStyle(stylesReader, styleName, conditions, styleManager, parser);
247 }
248}
249
250void Style::loadOdfDataStyle(KoOdfStylesReader &stylesReader, const QString &styleName, Conditions &conditions, const StyleManager *styleManager, const ValueParser *parser)
251{
252 if (stylesReader.dataFormats().contains(styleName)) {
253 Style* theStyle = this;
254
255 QPair<KoOdfNumberStyles::NumericStyleFormat, KoXmlElement*> dataStylePair = stylesReader.dataFormats()[styleName];
256
257 const KoOdfNumberStyles::NumericStyleFormat& dataStyle = dataStylePair.first;
258 const QList<QPair<QString,QString> > styleMaps = dataStyle.styleMaps;
259 if(styleMaps.count() > 0) {
260 theStyle = new Style();
261 for (QList<QPair<QString,QString> >::const_iterator it = styleMaps.begin(); it != styleMaps.end(); ++it) {
262 const Conditional c = conditions.loadOdfCondition(it->first, it->second, QString(), parser);
263 if (styleManager->style(c.styleName) == 0) {
264 CustomStyle* const s = new CustomStyle(c.styleName);
265 s->loadOdfDataStyle(stylesReader, c.styleName, conditions, styleManager, parser);
266 const_cast<StyleManager*>(styleManager)->insertStyle(s);
267 }
268 }
269 }
270
271 KoStyleStack styleStack;
272 styleStack.push(*dataStylePair.second);
273 styleStack.setTypeProperties("text");
274 theStyle->loadOdfTextProperties(stylesReader, styleStack);
275
276 QString tmp = dataStyle.prefix;
277 if (!tmp.isEmpty()) {
278 theStyle->setPrefix(tmp);
279 }
280 tmp = dataStyle.suffix;
281 if (!tmp.isEmpty()) {
282 theStyle->setPostfix(tmp);
283 }
284 // determine data formatting
285 switch (dataStyle.type) {
286 case KoOdfNumberStyles::Number:
287 theStyle->setFormatType(Format::Number);
288 if (!dataStyle.currencySymbol.isEmpty())
289 theStyle->setCurrency(numberCurrency(dataStyle.currencySymbol));
290 else
291 theStyle->setCurrency(numberCurrency(dataStyle.formatStr));
292 break;
293 case KoOdfNumberStyles::Scientific:
294 theStyle->setFormatType(Format::Scientific);
295 break;
296 case KoOdfNumberStyles::Currency:
297 kDebug(36003) << " currency-symbol:" << dataStyle.currencySymbol;
298 if (!dataStyle.currencySymbol.isEmpty())
299 theStyle->setCurrency(numberCurrency(dataStyle.currencySymbol));
300 else
301 theStyle->setCurrency(numberCurrency(dataStyle.formatStr));
302 break;
303 case KoOdfNumberStyles::Percentage:
304 theStyle->setFormatType(Format::Percentage);
305 break;
306 case KoOdfNumberStyles::Fraction:
307 // determine format of fractions, dates and times by using the
308 // formatting string
309 tmp = dataStyle.formatStr;
310 if (!tmp.isEmpty()) {
311 theStyle->setFormatType(Style::fractionType(tmp));
312 }
313 break;
314 case KoOdfNumberStyles::Date:
315 // determine format of fractions, dates and times by using the
316 // formatting string
317 tmp = dataStyle.formatStr;
318 if (!tmp.isEmpty()) {
319 theStyle->setFormatType(Style::dateType(tmp));
320 }
321 break;
322 case KoOdfNumberStyles::Time:
323 // determine format of fractions, dates and times by using the
324 // formatting string
325 tmp = dataStyle.formatStr;
326 if (!tmp.isEmpty()) {
327 theStyle->setFormatType(Style::timeType(tmp));
328 }
329 break;
330 case KoOdfNumberStyles::Boolean:
331 theStyle->setFormatType(Format::Number);
332 break;
333 case KoOdfNumberStyles::Text:
334 theStyle->setFormatType(Format::Text);
335 break;
336 }
337
338 if (dataStyle.precision > -1) {
339 // special handling for precision
340 // The Style default (-1) and the storage default (0) differ.
341 // The maximum is 10. Replace the Style value 0 with -11, which always results
342 // in a storage value < 0 and is interpreted as Style value 0.
343 int precision = dataStyle.precision;
344 if (type() == AUTO && precision == 0)
345 precision = -11;
346 theStyle->setPrecision(precision);
347 }
348
349 theStyle->setThousandsSep(dataStyle.thousandsSep);
350
351 theStyle->setCustomFormat(dataStyle.formatStr);
352
353 if(styleMaps.count() > 0) {
354 conditions.setDefaultStyle(*theStyle);
355 delete theStyle;
356 }
357 }
358}
359
360void Style::loadOdfParagraphProperties(KoOdfStylesReader& stylesReader, const KoStyleStack& styleStack)
361{
362 Q_UNUSED(stylesReader);
363 kDebug(36003) << "\t paragraph-properties";
364 if (styleStack.hasProperty(KoXmlNS::fo, "text-align")) {
365 QString str = styleStack.property(KoXmlNS::fo, "text-align");
366 if (str == "center")
367 setHAlign(Style::Center);
368 else if (str == "end" || str=="right")
369 setHAlign(Style::Right);
370 else if (str == "start" || str=="left")
371 setHAlign(Style::Left);
372 else if (str == "justify")
373 setHAlign(Style::Justified);
374 else
375 setHAlign(Style::HAlignUndefined);
376 kDebug(36003) << "\t\t text-align:" << str;
377 }
378
379 if (styleStack.hasProperty(KoXmlNS::fo, "margin-left")) {
380 //todo fix me
381 setIndentation(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "margin-left"), 0.0));
382 }
383}
384
385void Style::loadOdfTableCellProperties(KoOdfStylesReader& stylesReader, const KoStyleStack& styleStack)
386{
387 QString str;
388 if (styleStack.hasProperty(KoXmlNS::style, "vertical-align")) {
389 str = styleStack.property(KoXmlNS::style, "vertical-align");
390 if (str == "bottom")
391 setVAlign(Style::Bottom);
392 else if (str == "top")
393 setVAlign(Style::Top);
394 else if (str == "middle")
395 setVAlign(Style::Middle);
396 else
397 setVAlign(Style::VAlignUndefined);
398 }
399 if (styleStack.property(KoXmlNS::calligra, "vertical-distributed") == "distributed") {
400 if (valign() == Style::Top)
401 setVAlign(Style::VJustified);
402 else
403 setVAlign(Style::VDistributed);
404 }
405 if (styleStack.hasProperty(KoXmlNS::fo, "background-color")) {
406 str = styleStack.property(KoXmlNS::fo, "background-color");
407 if (str == "transparent") {
408 kDebug(36003) << "\t\t fo:background-color: transparent";
409 setBackgroundColor(QColor());
410 } else {
411 QColor color(str);
412 if (color.isValid()) {
413 kDebug(36003) << "\t\t fo:background-color:" << color.name();
414 setBackgroundColor(color);
415 }
416 }
417 }
418
419 if (styleStack.hasProperty(KoXmlNS::fo, "wrap-option") && (styleStack.property(KoXmlNS::fo, "wrap-option") == "wrap")) {
420 setWrapText(true);
421 }
422 if (styleStack.hasProperty(KoXmlNS::style, "cell-protect")) {
423 str = styleStack.property(KoXmlNS::style, "cell-protect");
424#ifndef NWORKAROUND_ODF_BUGS
425 KoOdfWorkaround::fixBadFormulaHiddenForStyleCellProtect(str);
426#endif
427 if (str == "none")
428 setNotProtected(true);
429 else if (str == "hidden-and-protected")
430 setHideAll(true);
431 else if (str == "protected formula-hidden" || str == "formula-hidden protected")
432 setHideFormula(true);
433 else if (str == "formula-hidden") {
434 setNotProtected(true);
435 setHideFormula(true);
436 }
437 }
438 if (styleStack.hasProperty(KoXmlNS::style, "print-content") &&
439 (styleStack.property(KoXmlNS::style, "print-content") == "false")) {
440 setDontPrintText(true);
441 }
442 if (styleStack.hasProperty(KoXmlNS::style, "shrink-to-fit") &&
443 (styleStack.property(KoXmlNS::style, "shrink-to-fit") == "true")) {
444 setShrinkToFit(true);
445 }
446 if (styleStack.hasProperty(KoXmlNS::style, "direction") &&
447 (styleStack.property(KoXmlNS::style, "direction") == "ttb")) {
448 setVerticalText(true);
449 }
450 if (styleStack.hasProperty(KoXmlNS::style, "rotation-angle")) {
451 bool ok;
452 int a = styleStack.property(KoXmlNS::style, "rotation-angle").toInt(&ok);
453 kDebug(36003) << " rotation-angle :" << a;
454 if (a != 0) {
455 setAngle(-a);
456 }
457 }
458 if (styleStack.hasProperty(KoXmlNS::fo, "border")) {
459 str = styleStack.property(KoXmlNS::fo, "border");
460 QPen pen = Odf::decodePen(str);
461 setLeftBorderPen(pen);
462 setTopBorderPen(pen);
463 setBottomBorderPen(pen);
464 setRightBorderPen(pen);
465 }
466 if (styleStack.hasProperty(KoXmlNS::fo, "border-left")) {
467 str = styleStack.property(KoXmlNS::fo, "border-left");
468 setLeftBorderPen(Odf::decodePen(str));
469 }
470 if (styleStack.hasProperty(KoXmlNS::fo, "border-right")) {
471 str = styleStack.property(KoXmlNS::fo, "border-right");
472 setRightBorderPen(Odf::decodePen(str));
473 }
474 if (styleStack.hasProperty(KoXmlNS::fo, "border-top")) {
475 str = styleStack.property(KoXmlNS::fo, "border-top");
476 setTopBorderPen(Odf::decodePen(str));
477 }
478 if (styleStack.hasProperty(KoXmlNS::fo, "border-bottom")) {
479 str = styleStack.property(KoXmlNS::fo, "border-bottom");
480 setBottomBorderPen(Odf::decodePen(str));
481 }
482 if (styleStack.hasProperty(KoXmlNS::style, "diagonal-tl-br")) {
483 str = styleStack.property(KoXmlNS::style, "diagonal-tl-br");
484 setFallDiagonalPen(Odf::decodePen(str));
485 }
486 if (styleStack.hasProperty(KoXmlNS::style, "diagonal-bl-tr")) {
487 str = styleStack.property(KoXmlNS::style, "diagonal-bl-tr");
488 setGoUpDiagonalPen(Odf::decodePen(str));
489 }
490
491 if (styleStack.hasProperty(KoXmlNS::draw, "style-name") || styleStack.hasProperty(KoXmlNS::calligra, "fill-style-name")) {
492 QString styleName = styleStack.hasProperty(KoXmlNS::calligra, "fill-style-name") ? styleStack.property(KoXmlNS::calligra, "fill-style-name")
493 : styleStack.property(KoXmlNS::draw, "style-name");
494 kDebug(36003) << " style name :" << styleName;
495
496 const KoXmlElement * style = stylesReader.findStyle(styleName, "graphic");
497 kDebug(36003) << " style :" << style;
498 if (style) {
499 KoStyleStack drawStyleStack;
500 drawStyleStack.push(*style);
501 drawStyleStack.setTypeProperties("graphic");
502 if (drawStyleStack.hasProperty(KoXmlNS::draw, "fill")) {
503 const QString fill = drawStyleStack.property(KoXmlNS::draw, "fill");
504 kDebug(36003) << " load object gradient fill type :" << fill;
505
506 if (fill == "solid" || fill == "hatch") {
507 kDebug(36003) << " Style ******************************************************";
508 setBackgroundBrush(KoOdfGraphicStyles::loadOdfFillStyle(drawStyleStack, fill, stylesReader));
509
510 } else
511 kDebug(36003) << " fill style not supported into kspread :" << fill;
512 }
513 }
514 }
515}
516
517void Style::loadOdfTextProperties(KoOdfStylesReader& stylesReader, const KoStyleStack& styleStack)
518{
519 Q_UNUSED(stylesReader);
520 // fo:font-size="13pt"
521 // fo:font-style="italic"
522 // style:text-underline="double"
523 // style:text-underline-color="font-color"
524 // fo:font-weight="bold"
525 kDebug(36003) << "\t text-properties";
526 if (styleStack.hasProperty(KoXmlNS::fo, "font-family")) {
527 setFontFamily(styleStack.property(KoXmlNS::fo, "font-family")); // FIXME Stefan: sanity check
528 kDebug(36003) << "\t\t fo:font-family:" << fontFamily();
529 }
530 if (styleStack.hasProperty(KoXmlNS::fo, "font-size")) {
531 setFontSize((int) KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "font-size"), 10.0)); // FIXME Stefan: fallback to default
532 kDebug(36003) << "\t\t fo:font-size:" << fontSize();
533 }
534 if (styleStack.hasProperty(KoXmlNS::fo, "font-style")) {
535 if (styleStack.property(KoXmlNS::fo, "font-style") == "italic") { // "normal", "oblique"
536 setFontItalic(true);
537 kDebug(36003) << "\t\t fo:font-style:" << "italic";
538 }
539 }
540 if (styleStack.hasProperty(KoXmlNS::fo, "font-weight")) {
541 if (styleStack.property(KoXmlNS::fo, "font-weight") == "bold") { // "normal", "100", "200", ...
542 setFontBold(true);
543 kDebug(36003) << "\t\t fo:font-weight:" << "bold";
544 }
545 }
546 if (styleStack.hasProperty(KoXmlNS::style, "text-underline-style")) {
547 if (styleStack.property(KoXmlNS::style, "text-underline-style") != "none") {
548 setFontUnderline(true);
549 kDebug(36003) << "\t\t style:text-underline-style:" << "solid (actually: !none)";
550 }
551 }
552 if (styleStack.hasProperty(KoXmlNS::style, "text-underline-width")) {
553 //TODO
554 }
555 if (styleStack.hasProperty(KoXmlNS::style, "text-underline-color")) {
556 //TODO
557 }
558 if (styleStack.hasProperty(KoXmlNS::fo, "color")) {
559 QColor color = QColor(styleStack.property(KoXmlNS::fo, "color"));
560 if (color.isValid()) {
561 setFontColor(color);
562 kDebug(36003) << "\t\t fo:color:" << color.name();
563 }
564 }
565 if (styleStack.hasProperty(KoXmlNS::style, "text-line-through-style")) {
566 if (styleStack.property(KoXmlNS::style, "text-line-through-style") != "none"
567 /*&& styleStack.property("text-line-through-style")=="solid"*/) {
568 setFontStrikeOut(true);
569 kDebug(36003) << "\t\t text-line-through-style:" << "solid (actually: !none)";
570 }
571 }
572 if (styleStack.hasProperty(KoXmlNS::style, "font-name")) {
573 QString fontName = styleStack.property(KoXmlNS::style, "font-name");
574 kDebug(36003) << "\t\t style:font-name:" << fontName;
575 const KoXmlElement * style = stylesReader.findStyle(fontName);
576 // TODO: sanity check that it is a font-face style?
577 kDebug(36003) << "\t\t\t style:" << style;
578 if (style) {
579 setFontFamily(style->attributeNS(KoXmlNS::svg, "font-family"));
580 kDebug(36003) << "\t\t\t svg:font-family:" << fontFamily();
581 }
582 }
583}
584
585static QString convertDateFormat(const QString& date)
586{
587 QString result = date;
588 result.replace("%Y", "yyyy");
589 result.replace("%y", "yy");
590 result.replace("%n", "M");
591 result.replace("%m", "MM");
592 result.replace("%e", "d");
593 result.replace("%d", "dd");
594 result.replace("%b", "MMM");
595 result.replace("%B", "MMMM");
596 result.replace("%a", "ddd");
597 result.replace("%A", "dddd");
598 return result;
599}
600
601Format::Type Style::dateType(const QString &_f)
602{
603 const QString dateFormatShort = convertDateFormat(KGlobal::locale()->dateFormatShort());
604 const QString dateFormat = convertDateFormat(KGlobal::locale()->dateFormat());
605 QString _format = _f;
606 _format.replace(' ', '-');
607
608 if (_format == "d-MMM-yy" || _format == "dd-MMM-yy")
609 return Format::Date1;
610 else if (_format == "dd-MMM-yyyy")
611 return Format::Date2;
612 else if (_format == "d-MM")
613 return Format::Date3;
614 else if (_format == "dd-MM") //TODO ???????
615 return Format::Date4;
616 else if (_format == "dd/MM/yy")
617 return Format::Date5;
618 else if (_format == "dd/MM/yyyy")
619 return Format::Date6;
620 else if (_format == "MMM-yy")
621 return Format::Date7;
622 else if (_format == "MMMM-yy")
623 return Format::Date8;
624 else if (_format == "MMMM-yyyy")
625 return Format::Date9;
626 else if (_format == "MMMMM-yy" || _format == "X-yy")
627 return Format::Date10;
628 else if (_format == "dd/MMM")
629 return Format::Date11;
630 else if (_format == "dd/MM")
631 return Format::Date12;
632 else if (_format == "dd/MMM/yyyy")
633 return Format::Date13;
634 else if (_format == "yyyy/MMM/dd")
635 return Format::Date14;
636 else if (_format == "yyyy-MMM-dd")
637 return Format::Date15;
638 else if (_format == "yyyy-MM-dd")
639 return Format::Date16;
640 else if (_format == "d MMMM yyyy")
641 return Format::Date17;
642 else if (_format == "MM/dd/yyyy")
643 return Format::Date18;
644 else if (_format == "MM/dd/yy")
645 return Format::Date19;
646 else if (_format == "MMM/dd/yy")
647 return Format::Date20;
648 else if (_format == "MMM/dd/yyyy")
649 return Format::Date21;
650 else if (_format == "MMM-yyyy")
651 return Format::Date22;
652 else if (_format == "yyyy")
653 return Format::Date23;
654 else if (_format == "yy")
655 return Format::Date24;
656 else if (_format == "yyyy/MM/dd")
657 return Format::Date25;
658 else if (_format == "yyyy/MMM/dd")
659 return Format::Date26;
660 else if (_format == "MMM/yy")
661 return Format::Date27;
662 else if (_format == "MMM/yyyy")
663 return Format::Date28;
664 else if (_format == "MMMM/yy")
665 return Format::Date29;
666 else if (_format == "MMMM/yyyy")
667 return Format::Date30;
668 else if (_format == "dd-MM")
669 return Format::Date31;
670 else if (_format == "MM/yy")
671 return Format::Date32;
672 else if (_format == "MM-yy")
673 return Format::Date33;
674 else if (QRegExp("^[d]+[\\s]*[d]{1,2}[\\s]+[M]{1,4}[\\s]+[y]{2,2}$").indexIn(_f) >= 0)
675 return Format::Date34;
676 else if (QRegExp("^[d]+[\\s]*[d]{1,2}[\\s]+[M]{1,}[\\s]+[y]{2,4}$").indexIn(_f) >= 0)
677 return Format::Date35;
678 else if (_format == dateFormatShort)
679 return Format::ShortDate;
680 else if (_format == dateFormat)
681 return Format::TextDate;
682 else {
683 kDebug() << "Unhandled date format=" << _format;
684 return Format::ShortDate;
685 }
686}
687
688Format::Type Style::timeType(const QString &_format)
689{
690 if (_format == "h:mm AP")
691 return Format::Time1;
692 else if (_format == "h:mm:ss AP")
693 return Format::Time2;
694 else if (_format == "hh \\h mm \\m\\i\\n ss \\s")
695 return Format::Time3;
696 else if (_format == "hh:mm")
697 return Format::Time4;
698 else if (_format == "hh:mm:ss")
699 return Format::Time5;
700 else if (_format == "m:ss")
701 return Format::Time6;
702 else if (_format == "h:mm:ss")
703 return Format::Time7;
704 else if (_format == "h:mm")
705 return Format::Time8;
706 else
707 return Format::Time;
708}
709
710Currency Style::numberCurrency(const QString &_format)
711{
712 // Look up if a prefix or postfix is in the currency table,
713 // return the currency symbol to use for formatting purposes.
714 if(!_format.isEmpty()) {
715 QString f = QString(_format.at(0));
716 Currency currStart = Currency(f);
717 if (currStart.index() > 1)
718 return currStart;
719 f = QString(_format.at(_format.size()-1));
720 Currency currEnd = Currency(f);
721 if (currEnd.index() > 1)
722 return currEnd;
723 }
724 return Currency(QString());
725}
726
727Format::Type Style::fractionType(const QString &_format)
728{
729 if (_format.endsWith(QLatin1String("/2")))
730 return Format::fraction_half;
731 else if (_format.endsWith(QLatin1String("/4")))
732 return Format::fraction_quarter;
733 else if (_format.endsWith(QLatin1String("/8")))
734 return Format::fraction_eighth;
735 else if (_format.endsWith(QLatin1String("/16")))
736 return Format::fraction_sixteenth;
737 else if (_format.endsWith(QLatin1String("/10")))
738 return Format::fraction_tenth;
739 else if (_format.endsWith(QLatin1String("/100")))
740 return Format::fraction_hundredth;
741 else if (_format.endsWith(QLatin1String("/?")))
742 return Format::fraction_one_digit;
743 else if (_format.endsWith(QLatin1String("/??")))
744 return Format::fraction_two_digits;
745 else if (_format.endsWith(QLatin1String("/???")))
746 return Format::fraction_three_digits;
747 else
748 return Format::fraction_three_digits;
749}
750
751QString Style::saveOdfStyleNumeric(KoGenStyle &style, KoGenStyles &mainStyles,
752 Format::Type _style,
753 const QString &_prefix, const QString &_postfix,
754 int _precision, const QString& symbol,
755 bool thousandsSep)
756{
757// kDebug(36003) ;
758 QString styleName;
759 QString valueType;
760 switch (_style) {
761 case Format::Number:
762 styleName = saveOdfStyleNumericNumber(mainStyles, _style, _precision, _prefix, _postfix, thousandsSep);
763 valueType = "float";
764 break;
765 case Format::Text:
766 styleName = saveOdfStyleNumericText(mainStyles, _style, _precision, _prefix, _postfix);
767 valueType = "string";
768 break;
769 case Format::Money:
770 styleName = saveOdfStyleNumericMoney(mainStyles, _style, symbol, _precision, _prefix, _postfix);
771 valueType = "currency";
772 break;
773 case Format::Percentage:
774 styleName = saveOdfStyleNumericPercentage(mainStyles, _style, _precision, _prefix, _postfix);
775 valueType = "percentage";
776 break;
777 case Format::Scientific:
778 styleName = saveOdfStyleNumericScientific(mainStyles, _style, _prefix, _postfix, _precision, thousandsSep);
779 valueType = "float";
780 break;
781 case Format::ShortDate:
782 case Format::TextDate:
783 styleName = saveOdfStyleNumericDate(mainStyles, _style, _prefix, _postfix);
784 valueType = "date";
785 break;
786 case Format::Time:
787 case Format::SecondeTime:
788 case Format::Time1:
789 case Format::Time2:
790 case Format::Time3:
791 case Format::Time4:
792 case Format::Time5:
793 case Format::Time6:
794 case Format::Time7:
795 case Format::Time8:
796 styleName = saveOdfStyleNumericTime(mainStyles, _style, _prefix, _postfix);
797 valueType = "time";
798 break;
799 case Format::fraction_half:
800 case Format::fraction_quarter:
801 case Format::fraction_eighth:
802 case Format::fraction_sixteenth:
803 case Format::fraction_tenth:
804 case Format::fraction_hundredth:
805 case Format::fraction_one_digit:
806 case Format::fraction_two_digits:
807 case Format::fraction_three_digits:
808 styleName = saveOdfStyleNumericFraction(mainStyles, _style, _prefix, _postfix);
809 valueType = "float";
810 break;
811 case Format::Date1:
812 case Format::Date2:
813 case Format::Date3:
814 case Format::Date4:
815 case Format::Date5:
816 case Format::Date6:
817 case Format::Date7:
818 case Format::Date8:
819 case Format::Date9:
820 case Format::Date10:
821 case Format::Date11:
822 case Format::Date12:
823 case Format::Date13:
824 case Format::Date14:
825 case Format::Date15:
826 case Format::Date16:
827 case Format::Date17:
828 case Format::Date18:
829 case Format::Date19:
830 case Format::Date20:
831 case Format::Date21:
832 case Format::Date22:
833 case Format::Date23:
834 case Format::Date24:
835 case Format::Date25:
836 case Format::Date26:
837 case Format::Date27:
838 case Format::Date28:
839 case Format::Date29:
840 case Format::Date30:
841 case Format::Date31:
842 case Format::Date32:
843 case Format::Date33:
844 case Format::Date34:
845 case Format::Date35:
846 styleName = saveOdfStyleNumericDate(mainStyles, _style, _prefix, _postfix);
847 valueType = "date";
848 break;
849 case Format::Custom:
850 styleName = saveOdfStyleNumericCustom(mainStyles, _style, _prefix, _postfix);
851 break;
852 case Format::Generic:
853 case Format::None:
854 if (_precision > -1 || !_prefix.isEmpty() || !_postfix.isEmpty()) {
855 styleName = saveOdfStyleNumericNumber(mainStyles, _style, _precision, _prefix, _postfix, thousandsSep);
856 valueType = "float";
857 }
858 break;
859 case Format::DateTime:
860 default:
861 ;
862 }
863 if (!styleName.isEmpty()) {
864 style.addAttribute("style:data-style-name", styleName);
865 }
866 return styleName;
867}
868
869QString Style::saveOdfStyleNumericNumber(KoGenStyles& mainStyles, Format::Type /*_style*/, int _precision,
870 const QString& _prefix, const QString& _postfix, bool thousandsSep)
871{
872 QString format;
873 if (_precision == -1)
874 format = '0';
875 else {
876 QString tmp;
877 for (int i = 0; i < _precision; i++) {
878 tmp += '0';
879 }
880 format = "0." + tmp;
881 }
882 return KoOdfNumberStyles::saveOdfNumberStyle(mainStyles, format, _prefix, _postfix, thousandsSep);
883}
884
885QString Style::saveOdfStyleNumericText(KoGenStyles& /*mainStyles*/, Format::Type /*_style*/, int /*_precision*/,
886 const QString& /*_prefix*/, const QString& /*_postfix*/)
887{
888 return "";
889}
890
891QString Style::saveOdfStyleNumericMoney(KoGenStyles& mainStyles, Format::Type /*_style*/,
892 const QString& symbol, int _precision,
893 const QString& _prefix, const QString& _postfix)
894{
895 QString format;
896 if (_precision == -1)
897 format = '0';
898 else {
899 QString tmp;
900 for (int i = 0; i < _precision; i++) {
901 tmp += '0';
902 }
903 format = "0." + tmp;
904 }
905 return KoOdfNumberStyles::saveOdfCurrencyStyle(mainStyles, format, symbol, _prefix, _postfix);
906}
907
908QString Style::saveOdfStyleNumericPercentage(KoGenStyles&mainStyles, Format::Type /*_style*/, int _precision,
909 const QString& _prefix, const QString& _postfix)
910{
911 //<number:percentage-style style:name="N106" style:family="data-style">
912 //<number:number number:decimal-places="6" number:min-integer-digits="1"/>
913 //<number:text>%</number:text>
914 //</number:percentage-style>
915 //TODO add decimal etc.
916 QString format;
917 if (_precision == -1)
918 format = '0';
919 else {
920 QString tmp;
921 for (int i = 0; i < _precision; i++) {
922 tmp += '0';
923 }
924 format = "0." + tmp;
925 }
926 return KoOdfNumberStyles::saveOdfPercentageStyle(mainStyles, format, _prefix, _postfix);
927}
928
929
930QString Style::saveOdfStyleNumericScientific(KoGenStyles&mainStyles, Format::Type /*_style*/,
931 const QString &_prefix, const QString &_suffix, int _precision, bool thousandsSep)
932{
933 //<number:number-style style:name="N60" style:family="data-style">
934 // <number:scientific-number number:decimal-places="2" number:min-integer-digits="1" number:min-exponent-digits="3"/>
935 //</number:number-style>
936 QString format;
937 if (_precision == -1)
938 format = "0E+00";
939 else {
940 QString tmp;
941 for (int i = 0; i < _precision; i++) {
942 tmp += '0';
943 }
944 format = "0." + tmp + "E+00";
945 }
946 return KoOdfNumberStyles::saveOdfScientificStyle(mainStyles, format, _prefix, _suffix, thousandsSep);
947}
948
949QString Style::saveOdfStyleNumericDate(KoGenStyles&mainStyles, Format::Type _style,
950 const QString& _prefix, const QString& _postfix)
951{
952 QString format;
953 bool locale = false;
954 switch (_style) {
955 //TODO fixme use locale of kspread and not kglobal
956 case Format::ShortDate:
957 format = KGlobal::locale()->dateFormatShort();
958 locale = true;
959 break;
960 case Format::TextDate:
961 format = KGlobal::locale()->dateFormat();
962 locale = true;
963 break;
964 case Format::Date1:
965 format = "dd-MMM-yy";
966 break;
967 case Format::Date2:
968 format = "dd-MMM-yyyy";
969 break;
970 case Format::Date3:
971 format = "dd-M";
972 break;
973 case Format::Date4:
974 format = "dd-MM";
975 break;
976 case Format::Date5:
977 format = "dd/MM/yy";
978 break;
979 case Format::Date6:
980 format = "dd/MM/yyyy";
981 break;
982 case Format::Date7:
983 format = "MMM-yy";
984 break;
985 case Format::Date8:
986 format = "MMMM-yy";
987 break;
988 case Format::Date9:
989 format = "MMMM-yyyy";
990 break;
991 case Format::Date10:
992 format = "MMMMM-yy";
993 break;
994 case Format::Date11:
995 format = "dd/MMM";
996 break;
997 case Format::Date12:
998 format = "dd/MM";
999 break;
1000 case Format::Date13:
1001 format = "dd/MMM/yyyy";
1002 break;
1003 case Format::Date14:
1004 format = "yyyy/MMM/dd";
1005 break;
1006 case Format::Date15:
1007 format = "yyyy-MMM-dd";
1008 break;
1009 case Format::Date16:
1010 format = "yyyy/MM/dd";
1011 break;
1012 case Format::Date17:
1013 format = "d MMMM yyyy";
1014 break;
1015 case Format::Date18:
1016 format = "MM/dd/yyyy";
1017 break;
1018 case Format::Date19:
1019 format = "MM/dd/yy";
1020 break;
1021 case Format::Date20:
1022 format = "MMM/dd/yy";
1023 break;
1024 case Format::Date21:
1025 format = "MMM/dd/yyyy";
1026 break;
1027 case Format::Date22:
1028 format = "MMM-yyyy";
1029 break;
1030 case Format::Date23:
1031 format = "yyyy";
1032 break;
1033 case Format::Date24:
1034 format = "yy";
1035 break;
1036 case Format::Date25:
1037 format = "yyyy/MM/dd";
1038 break;
1039 case Format::Date26:
1040 format = "yyyy/MMM/dd";
1041 break;
1042 case Format::Date27:
1043 format = "MMM/yy";
1044 break;
1045 case Format::Date28:
1046 format = "MMM/yyyy";
1047 break;
1048 case Format::Date29:
1049 format = "MMMM/yy";
1050 break;
1051 case Format::Date30:
1052 format = "MMMM/yyyy";
1053 break;
1054 case Format::Date31:
1055 format = "dd-MM";
1056 break;
1057 case Format::Date32:
1058 format = "MM/yy";
1059 break;
1060 case Format::Date33:
1061 format = "MM-yy";
1062 break;
1063 case Format::Date34:
1064 format = "ddd d MMM yyyy";
1065 break;
1066 case Format::Date35:
1067 format = "dddd d MMM yyyy";
1068 break;
1069 default:
1070 kDebug(36003) << "this date format is not defined ! :" << _style;
1071 break;
1072 }
1073 return KoOdfNumberStyles::saveOdfDateStyle(mainStyles, format, locale, _prefix, _postfix);
1074}
1075
1076QString Style::saveOdfStyleNumericCustom(KoGenStyles& /*mainStyles*/, Format::Type /*_style*/,
1077 const QString& /*_prefix*/, const QString& /*_postfix*/)
1078{
1079 //TODO
1080 //<number:date-style style:name="N50" style:family="data-style" number:automatic-order="true" number:format-source="language">
1081 //<number:month/>
1082 //<number:text>/</number:text>
1083 //<number:day/>
1084 //<number:text>/</number:text>
1085 //<number:year/>
1086 //<number:text> </number:text>
1087 //<number:hours number:style="long"/>
1088 //<number:text>:</number:text>
1089 //<number:minutes number:style="long"/>
1090 // <number:text> </number:text>
1091 //<number:am-pm/>
1092 //</number:date-style>
1093 return "";
1094}
1095
1096QString Style::saveOdfStyleNumericTime(KoGenStyles& mainStyles, Format::Type _style,
1097 const QString& _prefix, const QString& _postfix)
1098{
1099 //<number:time-style style:name="N42" style:family="data-style">
1100 //<number:hours number:style="long"/>
1101 //<number:text>:</number:text>
1102 //<number:minutes number:style="long"/>
1103 //<number:text> </number:text>
1104 //<number:am-pm/>
1105 //</number:time-style>
1106
1107 QString format;
1108 bool locale = false;
1109 //TODO use format
1110 switch (_style) {
1111 case Format::Time: //TODO FIXME
1112 format = "hh:mm:ss";
1113 break;
1114 case Format::SecondeTime: //TODO FIXME
1115 format = "hh:mm";
1116 break;
1117 case Format::Time1:
1118 format = "h:mm AP";
1119 break;
1120 case Format::Time2:
1121 format = "h:mm:ss AP";
1122 break;
1123 case Format::Time3: // 9 h 01 min 28 s
1124 format = "hh \\h mm \\m\\i\\n ss \\s";
1125 break;
1126 case Format::Time4:
1127 format = "hh:mm";
1128 break;
1129 case Format::Time5:
1130 format = "hh:mm:ss";
1131 break;
1132 case Format::Time6:
1133 format = "m:ss";
1134 break;
1135 case Format::Time7:
1136 format = "h:mm:ss";
1137 break;
1138 case Format::Time8:
1139 format = "h:mm";
1140 break;
1141 default:
1142 kDebug(36003) << "time format not defined :" << _style;
1143 break;
1144 }
1145 return KoOdfNumberStyles::saveOdfTimeStyle(mainStyles, format, locale, _prefix, _postfix);
1146}
1147
1148
1149QString Style::saveOdfStyleNumericFraction(KoGenStyles &mainStyles, Format::Type formatType,
1150 const QString &_prefix, const QString &_suffix)
1151{
1152 //<number:number-style style:name="N71" style:family="data-style">
1153 //<number:fraction number:min-integer-digits="0" number:min-numerator-digits="2" number:min-denominator-digits="2"/>
1154 //</number:number-style>
1155 QString format;
1156 switch (formatType) {
1157 case Format::fraction_half:
1158 format = "# ?/2";
1159 break;
1160 case Format::fraction_quarter:
1161 format = "# ?/4";
1162 break;
1163 case Format::fraction_eighth:
1164 format = "# ?/8";
1165 break;
1166 case Format::fraction_sixteenth:
1167 format = "# ?/16";
1168 break;
1169 case Format::fraction_tenth:
1170 format = "# ?/10";
1171 break;
1172 case Format::fraction_hundredth:
1173 format = "# ?/100";
1174 break;
1175 case Format::fraction_one_digit:
1176 format = "# ?/?";
1177 break;
1178 case Format::fraction_two_digits:
1179 format = "# \?\?/\?\?";
1180 break;
1181 case Format::fraction_three_digits:
1182 format = "# \?\?\?/\?\?\?";
1183 break;
1184 default:
1185 kDebug(36003) << " fraction format not defined :" << formatType;
1186 break;
1187 }
1188
1189 return KoOdfNumberStyles::saveOdfFractionStyle(mainStyles, format, _prefix, _suffix);
1190}
1191
1192QString Style::saveOdf(KoGenStyle& style, KoGenStyles& mainStyles,
1193 const StyleManager* manager) const
1194{
1195 // list of substyles to store
1196 QSet<Key> keysToStore;
1197
1198 if (isDefault()) {
1199 if (style.isEmpty()) {
1200 style = KoGenStyle(KoGenStyle::TableCellStyle, "table-cell");
1201 style.setDefaultStyle(true);
1202 // don't i18n'ize "Default" in this case
1203 return "Default"; // mainStyles.insert( style, "Default", KoGenStyles::DontAddNumberToName );
1204 }
1205 // no attributes to store here
1206 return mainStyles.insert(style, "ce");
1207 } else if (hasAttribute(NamedStyleKey)) {
1208 // it's not really the parent name in this case
1209 CustomStyle* namedStyle = manager->style(parentName());
1210 // remove substyles already present in named style
1211 if (namedStyle)
1212 keysToStore = difference(*namedStyle);
1213 // no differences and not an automatic style yet
1214 if (style.isEmpty() &&
1215 (keysToStore.count() == 0 ||
1216 (keysToStore.count() == 1 && keysToStore.toList().first() == NamedStyleKey))) {
1217 return manager->openDocumentName(parentName());
1218 }
1219 } else
1220 keysToStore = QSet<Key>::fromList(d->subStyles.keys());
1221
1222 // Calligra::Sheets::Style is definitly an OASIS auto style,
1223 // but don't overwrite it, if it already exists
1224 if (style.isEmpty())
1225 style = KoGenStyle(KoGenStyle::TableCellAutoStyle, "table-cell");
1226
1227 // doing the real work
1228 saveOdfStyle(keysToStore, style, mainStyles, manager);
1229 return mainStyles.insert(style, "ce");
1230}
1231
1232void Style::saveOdfStyle(const QSet<Key>& keysToStore, KoGenStyle &style,
1233 KoGenStyles &mainStyles, const StyleManager* manager) const
1234{
1235#ifndef NDEBUG
1236 //if (type() == BUILTIN )
1237 // kDebug(36006) <<"BUILTIN";
1238 //else if (type() == CUSTOM )
1239 // kDebug(36006) <<"CUSTOM";
1240 //else if (type() == AUTO )
1241 // kDebug(36006) <<"AUTO";
1242#endif
1243
1244 if (!isDefault() && hasAttribute(NamedStyleKey)) {
1245 const QString parentName = manager->openDocumentName(this->parentName());
1246 if (!parentName.isEmpty())
1247 style.addAttribute("style:parent-style-name", parentName);
1248 }
1249
1250 if (keysToStore.contains(HorizontalAlignment)) {
1251 QString value;
1252 switch (halign()) {
1253 case Center:
1254 value = "center";
1255 break;
1256 case Right:
1257 value = "end";
1258 break;
1259 case Left:
1260 value = "start";
1261 break;
1262 case Justified:
1263 value = "justify";
1264 break;
1265 case HAlignUndefined:
1266 break;
1267 }
1268 if (!value.isEmpty()) {
1269 style.addProperty("style:text-align-source", "fix"); // table-cell-properties
1270 style.addProperty("fo:text-align", value, KoGenStyle::ParagraphType);
1271 }
1272 }
1273
1274 if (keysToStore.contains(VerticalAlignment)) {
1275 QString value;
1276 switch (valign()) {
1277 case Top:
1278 case VJustified:
1279 value = "top";
1280 break;
1281 case Middle:
1282 case VDistributed:
1283 value = "middle";
1284 break;
1285 case Bottom:
1286 value = "bottom";
1287 break;
1288 case VAlignUndefined:
1289 default:
1290 break;
1291 }
1292 if (!value.isEmpty()) // sanity
1293 style.addProperty("style:vertical-align", value);
1294
1295 if (valign() == VJustified || valign() == VDistributed)
1296 style.addProperty("calligra:vertical-distributed", "distributed");
1297 }
1298
1299 if (keysToStore.contains(BackgroundColor) && backgroundColor().isValid())
1300 style.addProperty("fo:background-color", colorName(backgroundColor()));
1301
1302 if (keysToStore.contains(MultiRow) && wrapText())
1303 style.addProperty("fo:wrap-option", "wrap");
1304
1305 if (keysToStore.contains(VerticalText) && verticalText()) {
1306 style.addProperty("style:direction", "ttb");
1307 style.addProperty("style:rotation-angle", "0");
1308 style.addProperty("style:rotation-align", "none");
1309 }
1310
1311 if (keysToStore.contains(ShrinkToFit) && shrinkToFit())
1312 style.addProperty("style:shrink-to-fit", "true");
1313
1314#if 0
1315 if (keysToStore.contains(FloatFormat))
1316 format.setAttribute("float", (int) floatFormat());
1317
1318 if (keysToStore.contains(FloatColor))
1319 format.setAttribute("floatcolor", (int)floatColor());
1320
1321 if (keysToStore.contains(CustomFormat) && !customFormat().isEmpty())
1322 format.setAttribute("custom", customFormat());
1323
1324 if (keysToStore.contains(Format::Type) && formatType() == Money) {
1325 format.setAttribute("type", (int) currency().type);
1326 format.setAttribute("symbol", currency().symbol);
1327 }
1328#endif
1329 if (keysToStore.contains(Angle) && angle() != 0) {
1330 style.addProperty("style:rotation-align", "none");
1331 style.addProperty("style:rotation-angle", QString::number(-1.0 * angle()));
1332 }
1333
1334 if (keysToStore.contains(Indentation) && indentation() != 0.0) {
1335 style.addPropertyPt("fo:margin-left", indentation(), KoGenStyle::ParagraphType);
1336 //FIXME
1337 //if ( a == HAlignUndefined )
1338 //currentCellStyle.addProperty("fo:text-align", "start" );
1339 }
1340
1341 if (keysToStore.contains(DontPrintText) && keysToStore.contains(DontPrintText))
1342 style.addProperty("style:print-content", "false");
1343
1344 // protection
1345 bool hideAll = false;
1346 bool hideFormula = false;
1347 bool isNotProtected = false;
1348
1349 if (keysToStore.contains(NotProtected))
1350 isNotProtected = notProtected();
1351
1352 if (keysToStore.contains(HideAll))
1353 hideAll = this->hideAll();
1354
1355 if (keysToStore.contains(HideFormula))
1356 hideFormula = this->hideFormula();
1357
1358 if (hideAll)
1359 style.addProperty("style:cell-protect", "hidden-and-protected");
1360 else {
1361 if (isNotProtected && !hideFormula)
1362 style.addProperty("style:cell-protect", "none");
1363 else if (isNotProtected && hideFormula)
1364 style.addProperty("style:cell-protect", "formula-hidden");
1365 else if (hideFormula)
1366 style.addProperty("style:cell-protect", "protected formula-hidden");
1367 else if (keysToStore.contains(NotProtected) && !isNotProtected)
1368 // write out, only if it is explicitly set
1369 style.addProperty("style:cell-protect", "protected");
1370 }
1371
1372 // borders
1373 // NOTE Stefan: QPen api docs:
1374 // A line width of zero indicates a cosmetic pen. This means
1375 // that the pen width is always drawn one pixel wide,
1376 // independent of the transformation set on the painter.
1377 if (keysToStore.contains(LeftPen) && keysToStore.contains(RightPen) &&
1378 keysToStore.contains(TopPen) && keysToStore.contains(BottomPen) &&
1379 (leftBorderPen() == topBorderPen()) &&
1380 (leftBorderPen() == rightBorderPen()) &&
1381 (leftBorderPen() == bottomBorderPen())) {
1382 if (leftBorderPen().style() != Qt::NoPen)
1383 style.addProperty("fo:border", Odf::encodePen(leftBorderPen()));
1384 } else {
1385 if (keysToStore.contains(LeftPen) && (leftBorderPen().style() != Qt::NoPen))
1386 style.addProperty("fo:border-left", Odf::encodePen(leftBorderPen()));
1387
1388 if (keysToStore.contains(RightPen) && (rightBorderPen().style() != Qt::NoPen))
1389 style.addProperty("fo:border-right", Odf::encodePen(rightBorderPen()));
1390
1391 if (keysToStore.contains(TopPen) && (topBorderPen().style() != Qt::NoPen))
1392 style.addProperty("fo:border-top", Odf::encodePen(topBorderPen()));
1393
1394 if (keysToStore.contains(BottomPen) && (bottomBorderPen().style() != Qt::NoPen))
1395 style.addProperty("fo:border-bottom", Odf::encodePen(bottomBorderPen()));
1396 }
1397 if (keysToStore.contains(FallDiagonalPen) && (fallDiagonalPen().style() != Qt::NoPen)) {
1398 style.addProperty("style:diagonal-tl-br", Odf::encodePen(fallDiagonalPen()));
1399 }
1400 if (keysToStore.contains(GoUpDiagonalPen) && (goUpDiagonalPen().style() != Qt::NoPen)) {
1401 style.addProperty("style:diagonal-bl-tr", Odf::encodePen(goUpDiagonalPen()));
1402 }
1403
1404 // font
1405 if (keysToStore.contains(FontFamily)) { // !fontFamily().isEmpty() == true
1406 style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
1407 }
1408 if (keysToStore.contains(FontSize)) { // fontSize() != 0
1409 style.addPropertyPt("fo:font-size", fontSize(), KoGenStyle::TextType);
1410 }
1411
1412 if (keysToStore.contains(FontBold) && bold())
1413 style.addProperty("fo:font-weight", "bold", KoGenStyle::TextType);
1414
1415 if (keysToStore.contains(FontItalic) && italic())
1416 style.addProperty("fo:font-style", "italic", KoGenStyle::TextType);
1417
1418 if (keysToStore.contains(FontUnderline) && underline()) {
1419 //style:text-underline-style="solid" style:text-underline-width="auto"
1420 style.addProperty("style:text-underline-style", "solid", KoGenStyle::TextType);
1421 //copy from oo-129
1422 style.addProperty("style:text-underline-width", "auto", KoGenStyle::TextType);
1423 style.addProperty("style:text-underline-color", "font-color", KoGenStyle::TextType);
1424 }
1425
1426 if (keysToStore.contains(FontStrike) && strikeOut())
1427 style.addProperty("style:text-line-through-style", "solid", KoGenStyle::TextType);
1428
1429 if (keysToStore.contains(FontColor) && fontColor().isValid()) { // always save
1430 style.addProperty("fo:color", colorName(fontColor()), KoGenStyle::TextType);
1431 }
1432
1433 //I don't think there is a reason why the background brush should be saved if it is null,
1434 //but remove the check if it causes problems. -- Robert Knight <robertknight@gmail.com>
1435 if (keysToStore.contains(BackgroundBrush) && (backgroundBrush().style() != Qt::NoBrush)) {
1436 QString tmp = saveOdfBackgroundStyle(mainStyles, backgroundBrush());
1437 if (!tmp.isEmpty())
1438 style.addProperty("calligra:fill-style-name", tmp);
1439 }
1440
1441 QString _prefix;
1442 QString _postfix;
1443 int _precision = -1;
1444 if (keysToStore.contains(Prefix) && !prefix().isEmpty())
1445 _prefix = prefix();
1446 if (keysToStore.contains(Postfix) && !postfix().isEmpty())
1447 _postfix = postfix();
1448 if (keysToStore.contains(Precision) && precision() != -1)
1449 _precision = precision();
1450 bool _thousandsSep = false;
1451 if (keysToStore.contains(ThousandsSep)) {
1452 _thousandsSep = thousandsSep();
1453 }
1454
1455 QString currencyCode;
1456 if (keysToStore.contains(FormatTypeKey) && formatType() == Format::Money) {
1457 currencyCode = currency().code();
1458 }
1459
1460 QString numericStyle = saveOdfStyleNumeric(style, mainStyles, formatType(),
1461 _prefix, _postfix, _precision,
1462 currencyCode, _thousandsSep);
1463 if (!numericStyle.isEmpty())
1464 style.addAttribute("style:data-style-name", numericStyle);
1465}
1466
1467QString Style::saveOdfBackgroundStyle(KoGenStyles &mainStyles, const QBrush &brush)
1468{
1469 KoGenStyle styleobjectauto = KoGenStyle(KoGenStyle::GraphicAutoStyle, "graphic");
1470 KoOdfGraphicStyles::saveOdfFillStyle(styleobjectauto, mainStyles, brush);
1471 return mainStyles.insert(styleobjectauto, "gr");
1472}
1473
1474void Style::saveXML(QDomDocument& doc, QDomElement& format, const StyleManager* styleManager) const
1475{
1476 // list of substyles to store
1477 QSet<Key> keysToStore;
1478
1479 if (d->subStyles.contains(NamedStyleKey)) {
1480 const CustomStyle* namedStyle = styleManager->style(parentName());
1481 // check, if it's an unmodified named style
1482 keysToStore = difference(*namedStyle);
1483 if (type() == AUTO) {
1484 const QList<Key> keys = keysToStore.toList();
1485 if ((keysToStore.count() == 0) ||
1486 (keysToStore.count() == 1 && keysToStore.toList().first() == NamedStyleKey)) {
1487 // just save the name and we are done.
1488 format.setAttribute("style-name", parentName());
1489 return;
1490 } else
1491 format.setAttribute("parent", parentName());
1492 } else { // custom style
1493 if (d->subStyles.contains(NamedStyleKey))
1494 format.setAttribute("parent", parentName());
1495 }
1496 } else
1497 keysToStore = QSet<Key>::fromList(d->subStyles.keys());
1498
1499 if (keysToStore.contains(HorizontalAlignment) && halign() != HAlignUndefined)
1500 format.setAttribute(type() == AUTO ? "align" : "alignX", (int) halign());
1501
1502 if (keysToStore.contains(VerticalAlignment) && valign() != VAlignUndefined)
1503 format.setAttribute("alignY", (int) valign());
1504
1505 if (keysToStore.contains(BackgroundColor) && backgroundColor().isValid())
1506 format.setAttribute("bgcolor", backgroundColor().name());
1507
1508 if (keysToStore.contains(MultiRow) && wrapText())
1509 format.setAttribute("multirow", "yes");
1510
1511 if (keysToStore.contains(VerticalText) && verticalText())
1512 format.setAttribute("verticaltext", "yes");
1513
1514 if (keysToStore.contains(ShrinkToFit) && shrinkToFit())
1515 format.setAttribute("shrinktofit", "yes");
1516
1517 if (keysToStore.contains(Precision))
1518 format.setAttribute("precision", precision());
1519
1520 if (keysToStore.contains(Prefix) && !prefix().isEmpty())
1521 format.setAttribute("prefix", prefix());
1522
1523 if (keysToStore.contains(Postfix) && !postfix().isEmpty())
1524 format.setAttribute("postfix", postfix());
1525
1526 if (keysToStore.contains(FloatFormatKey))
1527 format.setAttribute("float", (int) floatFormat());
1528
1529 if (keysToStore.contains(FloatColorKey))
1530 format.setAttribute("floatcolor", (int)floatColor());
1531
1532 if (keysToStore.contains(FormatTypeKey))
1533 format.setAttribute("format", (int) formatType());
1534
1535 if (keysToStore.contains(CustomFormat) && !customFormat().isEmpty())
1536 format.setAttribute("custom", customFormat());
1537
1538 if (keysToStore.contains(FormatTypeKey) && formatType() == Format::Money) {
1539 format.setAttribute("type", (int) currency().index());
1540 format.setAttribute("symbol", currency().symbol());
1541 }
1542
1543 if (keysToStore.contains(Angle))
1544 format.setAttribute("angle", angle());
1545
1546 if (keysToStore.contains(Indentation))
1547 format.setAttribute("indent", indentation());
1548
1549 if (keysToStore.contains(DontPrintText))
1550 format.setAttribute("dontprinttext", printText() ? "no" : "yes");
1551
1552 if (keysToStore.contains(NotProtected))
1553 format.setAttribute("noprotection", notProtected() ? "yes" : "no");
1554
1555 if (keysToStore.contains(HideAll))
1556 format.setAttribute("hideall", hideAll() ? "yes" : "no");
1557
1558 if (keysToStore.contains(HideFormula))
1559 format.setAttribute("hideformula", hideFormula() ? "yes" : "no");
1560
1561 if (type() == AUTO) {
1562 if (keysToStore.contains(FontFamily) ||
1563 keysToStore.contains(FontSize) ||
1564 keysToStore.contains(FontBold) ||
1565 keysToStore.contains(FontItalic) ||
1566 keysToStore.contains(FontStrike) ||
1567 keysToStore.contains(FontUnderline)) {
1568 format.appendChild(NativeFormat::createElement("font", font(), doc));
1569 }
1570 } else { // custom style
1571 if (keysToStore.contains(FontFamily))
1572 format.setAttribute("font-family", fontFamily());
1573 if (keysToStore.contains(FontSize))
1574 format.setAttribute("font-size", fontSize());
1575 if (keysToStore.contains(FontBold) || keysToStore.contains(FontItalic) ||
1576 keysToStore.contains(FontUnderline) || keysToStore.contains(FontStrike)) {
1577 enum FontFlags {
1578 FBold = 0x01,
1579 FUnderline = 0x02,
1580 FItalic = 0x04,
1581 FStrike = 0x08
1582 };
1583 int fontFlags = 0;
1584 fontFlags |= bold() ? FBold : 0;
1585 fontFlags |= italic() ? FItalic : 0;
1586 fontFlags |= underline() ? FUnderline : 0;
1587 fontFlags |= strikeOut() ? FStrike : 0;
1588 format.setAttribute("font-flags", fontFlags);
1589 }
1590 }
1591
1592 if (keysToStore.contains(FontColor) && fontColor().isValid())
1593 format.appendChild(NativeFormat::createElement("pen", fontColor(), doc));
1594
1595 if (keysToStore.contains(BackgroundBrush)) {
1596 format.setAttribute("brushcolor", backgroundBrush().color().name());
1597 format.setAttribute("brushstyle", (int) backgroundBrush().style());
1598 }
1599
1600 if (keysToStore.contains(LeftPen)) {
1601 QDomElement left = doc.createElement("left-border");
1602 left.appendChild(NativeFormat::createElement("pen", leftBorderPen(), doc));
1603 format.appendChild(left);
1604 }
1605
1606 if (keysToStore.contains(TopPen)) {
1607 QDomElement top = doc.createElement("top-border");
1608 top.appendChild(NativeFormat::createElement("pen", topBorderPen(), doc));
1609 format.appendChild(top);
1610 }
1611
1612 if (keysToStore.contains(RightPen)) {
1613 QDomElement right = doc.createElement("right-border");
1614 right.appendChild(NativeFormat::createElement("pen", rightBorderPen(), doc));
1615 format.appendChild(right);
1616 }
1617
1618 if (keysToStore.contains(BottomPen)) {
1619 QDomElement bottom = doc.createElement("bottom-border");
1620 bottom.appendChild(NativeFormat::createElement("pen", bottomBorderPen(), doc));
1621 format.appendChild(bottom);
1622 }
1623
1624 if (keysToStore.contains(FallDiagonalPen)) {
1625 QDomElement fallDiagonal = doc.createElement("fall-diagonal");
1626 fallDiagonal.appendChild(NativeFormat::createElement("pen", fallDiagonalPen(), doc));
1627 format.appendChild(fallDiagonal);
1628 }
1629
1630 if (keysToStore.contains(GoUpDiagonalPen)) {
1631 QDomElement goUpDiagonal = doc.createElement("up-diagonal");
1632 goUpDiagonal.appendChild(NativeFormat::createElement("pen", goUpDiagonalPen(), doc));
1633 format.appendChild(goUpDiagonal);
1634 }
1635}
1636
1637bool Style::loadXML(KoXmlElement& format, Paste::Mode mode)
1638{
1639 if (format.hasAttribute("style-name")) {
1640 // Simply set the style name and we are done.
1641 insertSubStyle(NamedStyleKey, format.attribute("style-name"));
1642 return true;
1643 } else if (format.hasAttribute("parent"))
1644 insertSubStyle(NamedStyleKey, format.attribute("parent"));
1645
1646 bool ok;
1647 if (format.hasAttribute(type() == AUTO ? "align" : "alignX")) {
1648 HAlign a = (HAlign) format.attribute(type() == AUTO ? "align" : "alignX").toInt(&ok);
1649 if (!ok)
1650 return false;
1651 if ((unsigned int) a >= 1 && (unsigned int) a <= 4) {
1652 setHAlign(a);
1653 }
1654 }
1655 if (format.hasAttribute("alignY")) {
1656 VAlign a = (VAlign) format.attribute("alignY").toInt(&ok);
1657 if (!ok)
1658 return false;
1659 if ((unsigned int) a >= 1 && (unsigned int) a < 4) {
1660 setVAlign(a);
1661 }
1662 }
1663
1664 if (format.hasAttribute("bgcolor")) {
1665 QColor color(format.attribute("bgcolor"));
1666 if (color.isValid())
1667 setBackgroundColor(color);
1668 }
1669
1670 if (format.hasAttribute("multirow")) {
1671 setWrapText(true);
1672 }
1673
1674 if (format.hasAttribute("shrinktofit")) {
1675 setShrinkToFit(true);
1676 }
1677
1678 if (format.hasAttribute("precision")) {
1679 int i = format.attribute("precision").toInt(&ok);
1680 if (i < -1) {
1681 kDebug(36003) << "Value out of range Cell::precision=" << i;
1682 return false;
1683 }
1684 // special handling for precision
1685 // The Style default (-1) and the storage default (0) differ.
1686 if (type() == AUTO && i == -1)
1687 i = 0;
1688 // The maximum is 10. Replace the Style value 0 with -11, which always results
1689 // in a storage value < 0 and is interpreted as Style value 0.
1690 else if (type() == AUTO && i == 0)
1691 i = -11;
1692 setPrecision(i);
1693 }
1694
1695 if (format.hasAttribute("float")) {
1696 FloatFormat a = (FloatFormat)format.attribute("float").toInt(&ok);
1697 if (!ok)
1698 return false;
1699 if ((unsigned int) a >= 1 && (unsigned int) a <= 3) {
1700 setFloatFormat(a);
1701 }
1702 }
1703
1704 if (format.hasAttribute("floatcolor")) {
1705 FloatColor a = (FloatColor) format.attribute("floatcolor").toInt(&ok);
1706 if (!ok) return false;
1707 if ((unsigned int) a >= 1 && (unsigned int) a <= 2) {
1708 setFloatColor(a);
1709 }
1710 }
1711
1712 if (format.hasAttribute("format")) {
1713 int fo = format.attribute("format").toInt(&ok);
1714 if (! ok)
1715 return false;
1716 setFormatType(static_cast<Format::Type>(fo));
1717 }
1718 if (format.hasAttribute("custom")) {
1719 setCustomFormat(format.attribute("custom"));
1720 }
1721 if (formatType() == Format::Money) {
1722 ok = true;
1723 Currency currency;
1724 if (format.hasAttribute("type")) {
1725 currency = Currency(format.attribute("type").toInt(&ok));
1726 if (!ok) {
1727 if (format.hasAttribute("symbol"))
1728 currency = Currency(format.attribute("symbol"));
1729 }
1730 } else if (format.hasAttribute("symbol"))
1731 currency = Currency(format.attribute("symbol"));
1732 setCurrency(currency);
1733 }
1734 if (format.hasAttribute("angle")) {
1735 setAngle(format.attribute("angle").toInt(&ok));
1736 if (!ok)
1737 return false;
1738 }
1739 if (format.hasAttribute("indent")) {
1740 setIndentation(format.attribute("indent").toDouble(&ok));
1741 if (!ok)
1742 return false;
1743 }
1744 if (format.hasAttribute("dontprinttext")) {
1745 setDontPrintText(true);
1746 }
1747
1748 if (format.hasAttribute("noprotection")) {
1749 setNotProtected(true);
1750 }
1751
1752 if (format.hasAttribute("hideall")) {
1753 setHideAll(true);
1754 }
1755
1756 if (format.hasAttribute("hideformula")) {
1757 setHideFormula(true);
1758 }
1759
1760 if (type() == AUTO) {
1761 KoXmlElement fontElement = format.namedItem("font").toElement();
1762 if (!fontElement.isNull()) {
1763 QFont font(NativeFormat::toFont(fontElement));
1764 setFontFamily(font.family());
1765 setFontSize(font.pointSize());
1766 if (font.italic())
1767 setFontItalic(true);
1768 if (font.bold())
1769 setFontBold(true);
1770 if (font.underline())
1771 setFontUnderline(true);
1772 if (font.strikeOut())
1773 setFontStrikeOut(true);
1774 }
1775 } else { // custom style
1776 if (format.hasAttribute("font-family"))
1777 setFontFamily(format.attribute("font-family"));
1778 if (format.hasAttribute("font-size")) {
1779 setFontSize(format.attribute("font-size").toInt(&ok));
1780 if (!ok)
1781 return false;
1782 }
1783 if (format.hasAttribute("font-flags")) {
1784 int fontFlags = format.attribute("font-flags").toInt(&ok);
1785 if (!ok)
1786 return false;
1787
1788 enum FontFlags {
1789 FBold = 0x01,
1790 FUnderline = 0x02,
1791 FItalic = 0x04,
1792 FStrike = 0x08
1793 };
1794 setFontBold(fontFlags & FBold);
1795 setFontItalic(fontFlags & FItalic);
1796 setFontUnderline(fontFlags & FUnderline);
1797 setFontStrikeOut(fontFlags & FStrike);
1798 }
1799 }
1800
1801 if (format.hasAttribute("brushcolor")) {
1802 QColor color(format.attribute("brushcolor"));
1803 if (color.isValid()) {
1804 QBrush brush = backgroundBrush();
1805 brush.setColor(color);
1806 setBackgroundBrush(brush);
1807 }
1808 }
1809
1810 if (format.hasAttribute("brushstyle")) {
1811 QBrush brush = backgroundBrush();
1812 brush.setStyle((Qt::BrushStyle) format.attribute("brushstyle").toInt(&ok));
1813 if (!ok)
1814 return false;
1815 setBackgroundBrush(brush);
1816 }
1817
1818 KoXmlElement pen = format.namedItem("pen").toElement();
1819 if (!pen.isNull()) {
1820 setFontColor(NativeFormat::toPen(pen).color());
1821 }
1822
1823 if (mode != Paste::NoBorder) {
1824 KoXmlElement left = format.namedItem("left-border").toElement();
1825 if (!left.isNull()) {
1826 KoXmlElement pen = left.namedItem("pen").toElement();
1827 if (!pen.isNull())
1828 setLeftBorderPen(NativeFormat::toPen(pen));
1829 }
1830
1831 KoXmlElement top = format.namedItem("top-border").toElement();
1832 if (!top.isNull()) {
1833 KoXmlElement pen = top.namedItem("pen").toElement();
1834 if (!pen.isNull())
1835 setTopBorderPen(NativeFormat::toPen(pen));
1836 }
1837
1838 KoXmlElement right = format.namedItem("right-border").toElement();
1839 if (!right.isNull()) {
1840 KoXmlElement pen = right.namedItem("pen").toElement();
1841 if (!pen.isNull())
1842 setRightBorderPen(NativeFormat::toPen(pen));
1843 }
1844
1845 KoXmlElement bottom = format.namedItem("bottom-border").toElement();
1846 if (!bottom.isNull()) {
1847 KoXmlElement pen = bottom.namedItem("pen").toElement();
1848 if (!pen.isNull())
1849 setBottomBorderPen(NativeFormat::toPen(pen));
1850 }
1851
1852 KoXmlElement fallDiagonal = format.namedItem("fall-diagonal").toElement();
1853 if (!fallDiagonal.isNull()) {
1854 KoXmlElement pen = fallDiagonal.namedItem("pen").toElement();
1855 if (!pen.isNull())
1856 setFallDiagonalPen(NativeFormat::toPen(pen));
1857 }
1858
1859 KoXmlElement goUpDiagonal = format.namedItem("up-diagonal").toElement();
1860 if (!goUpDiagonal.isNull()) {
1861 KoXmlElement pen = goUpDiagonal.namedItem("pen").toElement();
1862 if (!pen.isNull())
1863 setGoUpDiagonalPen(NativeFormat::toPen(pen));
1864 }
1865 }
1866
1867 if (format.hasAttribute("prefix")) {
1868 setPrefix(format.attribute("prefix"));
1869 }
1870 if (format.hasAttribute("postfix")) {
1871 setPostfix(format.attribute("postfix"));
1872 }
1873
1874 return true;
1875}
1876
1877uint Style::bottomPenValue() const
1878{
1879 if (!d->subStyles.contains(BottomPen))
1880 return BorderPenStyle<BottomPen>().value;
1881 return static_cast<const BorderPenStyle<BottomPen>*>(d->subStyles[BottomPen].data())->value;
1882}
1883
1884uint Style::rightPenValue() const
1885{
1886 if (!d->subStyles.contains(RightPen))
1887 return BorderPenStyle<RightPen>().value;
1888 return static_cast<const BorderPenStyle<RightPen>*>(d->subStyles[RightPen].data())->value;
1889}
1890
1891uint Style::leftPenValue() const
1892{
1893 if (!d->subStyles.contains(LeftPen))
1894 return BorderPenStyle<LeftPen>().value;
1895 return static_cast<const BorderPenStyle<LeftPen>*>(d->subStyles[LeftPen].data())->value;
1896}
1897
1898uint Style::topPenValue() const
1899{
1900 if (!d->subStyles.contains(TopPen))
1901 return BorderPenStyle<TopPen>().value;
1902 return static_cast<const BorderPenStyle<TopPen>*>(d->subStyles[TopPen].data())->value;
1903}
1904
1905QColor Style::fontColor() const
1906{
1907 if (!d->subStyles.contains(FontColor))
1908 return SubStyleOne<FontColor, QColor>().value1;
1909 return static_cast<const SubStyleOne<FontColor, QColor>*>(d->subStyles[FontColor].data())->value1;
1910}
1911
1912QColor Style::backgroundColor() const
1913{
1914 if (!d->subStyles.contains(BackgroundColor))
1915 return SubStyleOne<BackgroundColor, QColor>().value1;
1916 return static_cast<const SubStyleOne<BackgroundColor, QColor>*>(d->subStyles[BackgroundColor].data())->value1;
1917}
1918
1919QPen Style::rightBorderPen() const
1920{
1921 if (!d->subStyles.contains(RightPen))
1922 return BorderPenStyle<RightPen>().value1;
1923 return static_cast<const BorderPenStyle<RightPen>*>(d->subStyles[RightPen].data())->value1;
1924}
1925
1926QPen Style::bottomBorderPen() const
1927{
1928 if (!d->subStyles.contains(BottomPen))
1929 return BorderPenStyle<BottomPen>().value1;
1930 return static_cast<const BorderPenStyle<BottomPen>*>(d->subStyles[BottomPen].data())->value1;
1931}
1932
1933QPen Style::leftBorderPen() const
1934{
1935 if (!d->subStyles.contains(LeftPen))
1936 return BorderPenStyle<LeftPen>().value1;
1937 return static_cast<const BorderPenStyle<LeftPen>*>(d->subStyles[LeftPen].data())->value1;
1938}
1939
1940QPen Style::topBorderPen() const
1941{
1942 if (!d->subStyles.contains(TopPen))
1943 return BorderPenStyle<TopPen>().value1;
1944 return static_cast<const BorderPenStyle<TopPen>*>(d->subStyles[TopPen].data())->value1;
1945}
1946
1947QPen Style::fallDiagonalPen() const
1948{
1949 if (!d->subStyles.contains(FallDiagonalPen))
1950 return PenStyle<FallDiagonalPen>().value1;
1951 return static_cast<const PenStyle<FallDiagonalPen>*>(d->subStyles[FallDiagonalPen].data())->value1;
1952}
1953
1954QPen Style::goUpDiagonalPen() const
1955{
1956 if (!d->subStyles.contains(GoUpDiagonalPen))
1957 return PenStyle<GoUpDiagonalPen>().value1;
1958 return static_cast<const PenStyle<GoUpDiagonalPen>*>(d->subStyles[GoUpDiagonalPen].data())->value1;
1959}
1960
1961QBrush Style::backgroundBrush() const
1962{
1963 if (!d->subStyles.contains(BackgroundBrush))
1964 return SubStyleOne<BackgroundBrush, QBrush>().value1;
1965 return static_cast<const SubStyleOne<BackgroundBrush, QBrush>*>(d->subStyles[BackgroundBrush].data())->value1;
1966}
1967
1968QString Style::customFormat() const
1969{
1970 if (!d->subStyles.contains(CustomFormat))
1971 return SubStyleOne<CustomFormat, QString>().value1;
1972 return static_cast<const SubStyleOne<CustomFormat, QString>*>(d->subStyles[CustomFormat].data())->value1;
1973}
1974
1975QString Style::prefix() const
1976{
1977 if (!d->subStyles.contains(Prefix))
1978 return SubStyleOne<Prefix, QString>().value1;
1979 return static_cast<const SubStyleOne<Prefix, QString>*>(d->subStyles[Prefix].data())->value1;
1980}
1981
1982QString Style::postfix() const
1983{
1984 if (!d->subStyles.contains(Postfix))
1985 return SubStyleOne<Postfix, QString>().value1;
1986 return static_cast<const SubStyleOne<Postfix, QString>*>(d->subStyles[Postfix].data())->value1;
1987}
1988
1989QString Style::fontFamily() const
1990{
1991 if (!d->subStyles.contains(FontFamily))
1992 return KoGlobal::defaultFont().family(); // SubStyleOne<FontFamily, QString>().value1;
1993 return static_cast<const SubStyleOne<FontFamily, QString>*>(d->subStyles[FontFamily].data())->value1;
1994}
1995
1996Style::HAlign Style::halign() const
1997{
1998 if (!d->subStyles.contains(HorizontalAlignment))
1999 return SubStyleOne<HorizontalAlignment, Style::HAlign>().value1;
2000 return static_cast<const SubStyleOne<HorizontalAlignment, Style::HAlign>*>(d->subStyles[HorizontalAlignment].data())->value1;
2001}
2002
2003Style::VAlign Style::valign() const
2004{
2005 if (!d->subStyles.contains(VerticalAlignment))
2006 return SubStyleOne<VerticalAlignment, Style::VAlign>().value1;
2007 return static_cast<const SubStyleOne<VerticalAlignment, Style::VAlign>*>(d->subStyles[VerticalAlignment].data())->value1;
2008}
2009
2010Style::FloatFormat Style::floatFormat() const
2011{
2012 if (!d->subStyles.contains(FloatFormatKey))
2013 return SubStyleOne<FloatFormatKey, FloatFormat>().value1;
2014 return static_cast<const SubStyleOne<FloatFormatKey, FloatFormat>*>(d->subStyles[FloatFormatKey].data())->value1;
2015}
2016
2017Style::FloatColor Style::floatColor() const
2018{
2019 if (!d->subStyles.contains(FloatColorKey))
2020 return SubStyleOne<FloatColorKey, FloatColor>().value1;
2021 return static_cast<const SubStyleOne<FloatColorKey, FloatColor>*>(d->subStyles[FloatColorKey].data())->value1;
2022}
2023
2024Format::Type Style::formatType() const
2025{
2026 if (!d->subStyles.contains(FormatTypeKey))
2027 return SubStyleOne<FormatTypeKey, Format::Type>().value1;
2028 return static_cast<const SubStyleOne<FormatTypeKey, Format::Type>*>(d->subStyles[FormatTypeKey].data())->value1;
2029}
2030
2031Currency Style::currency() const
2032{
2033 if (!d->subStyles.contains(CurrencyFormat))
2034 return Currency();
2035 return static_cast<const SubStyleOne<CurrencyFormat, Currency>*>(d->subStyles[CurrencyFormat].data())->value1;
2036}
2037
2038QFont Style::font() const
2039{
2040 QFont font;
2041 font.setFamily(fontFamily());
2042 font.setPointSize(fontSize());
2043 font.setBold(bold());
2044 font.setItalic(italic());
2045 font.setUnderline(underline());
2046 font.setStrikeOut(strikeOut());
2047 return font;
2048}
2049
2050bool Style::bold() const
2051{
2052 if (!d->subStyles.contains(FontBold))
2053 return SubStyleOne<FontBold, bool>().value1;
2054 return static_cast<const SubStyleOne<FontBold, bool>*>(d->subStyles[FontBold].data())->value1;
2055}
2056
2057bool Style::italic() const
2058{
2059 if (!d->subStyles.contains(FontItalic))
2060 return SubStyleOne<FontItalic, bool>().value1;
2061 return static_cast<const SubStyleOne<FontItalic, bool>*>(d->subStyles[FontItalic].data())->value1;
2062}
2063
2064bool Style::underline() const
2065{
2066 if (!d->subStyles.contains(FontUnderline))
2067 return SubStyleOne<FontUnderline, bool>().value1;
2068 return static_cast<const SubStyleOne<FontUnderline, bool>*>(d->subStyles[FontUnderline].data())->value1;
2069}
2070
2071bool Style::strikeOut() const
2072{
2073 if (!d->subStyles.contains(FontStrike))
2074 return SubStyleOne<FontStrike, bool>().value1;
2075 return static_cast<const SubStyleOne<FontStrike, bool>*>(d->subStyles[FontStrike].data())->value1;
2076}
2077
2078int Style::fontSize() const
2079{
2080 if (!d->subStyles.contains(FontSize))
2081 return KoGlobal::defaultFont().pointSize(); //SubStyleOne<FontSize, int>().value1;
2082 return static_cast<const SubStyleOne<FontSize, int>*>(d->subStyles[FontSize].data())->value1;
2083}
2084
2085int Style::precision() const
2086{
2087 if (!d->subStyles.contains(Precision))
2088 return -1; //SubStyleOne<Precision, int>().value1;
2089 return static_cast<const SubStyleOne<Precision, int>*>(d->subStyles[Precision].data())->value1;
2090}
2091
2092bool Style::thousandsSep() const
2093{
2094 if (!d->subStyles.contains(ThousandsSep))
2095 return false;
2096 return static_cast<const SubStyleOne<ThousandsSep, bool>*>(d->subStyles[ThousandsSep].data())->value1;
2097}
2098
2099int Style::angle() const
2100{
2101 if (!d->subStyles.contains(Angle))
2102 return SubStyleOne<Angle, int>().value1;
2103 return static_cast<const SubStyleOne<Angle, int>*>(d->subStyles[Angle].data())->value1;
2104}
2105
2106double Style::indentation() const
2107{
2108 if (!d->subStyles.contains(Indentation))
2109 return SubStyleOne<Indentation, int>().value1;
2110 return static_cast<const SubStyleOne<Indentation, int>*>(d->subStyles[Indentation].data())->value1;
2111}
2112
2113bool Style::shrinkToFit() const
2114{
2115 if (!d->subStyles.contains(ShrinkToFit))
2116 return SubStyleOne<ShrinkToFit, bool>().value1;
2117 return static_cast<const SubStyleOne<ShrinkToFit, bool>*>(d->subStyles[ShrinkToFit].data())->value1;
2118}
2119
2120bool Style::verticalText() const
2121{
2122 if (!d->subStyles.contains(VerticalText))
2123 return SubStyleOne<VerticalText, bool>().value1;
2124 return static_cast<const SubStyleOne<VerticalText, bool>*>(d->subStyles[VerticalText].data())->value1;
2125}
2126
2127bool Style::wrapText() const
2128{
2129 if (!d->subStyles.contains(MultiRow))
2130 return SubStyleOne<MultiRow, bool>().value1;
2131 return static_cast<const SubStyleOne<MultiRow, bool>*>(d->subStyles[MultiRow].data())->value1;
2132}
2133
2134bool Style::printText() const
2135{
2136 if (!d->subStyles.contains(DontPrintText))
2137 return !SubStyleOne<DontPrintText, bool>().value1;
2138 return !static_cast<const SubStyleOne<DontPrintText, bool>*>(d->subStyles[DontPrintText].data())->value1;
2139}
2140
2141bool Style::hideAll() const
2142{
2143 if (!d->subStyles.contains(HideAll))
2144 return SubStyleOne<HideAll, bool>().value1;
2145 return static_cast<const SubStyleOne<HideAll, bool>*>(d->subStyles[HideAll].data())->value1;
2146}
2147
2148bool Style::hideFormula() const
2149{
2150 if (!d->subStyles.contains(HideFormula))
2151 return SubStyleOne<HideFormula, bool>().value1;
2152 return static_cast<const SubStyleOne<HideFormula, bool>*>(d->subStyles[HideFormula].data())->value1;
2153}
2154
2155bool Style::notProtected() const
2156{
2157 if (!d->subStyles.contains(NotProtected))
2158 return SubStyleOne<NotProtected, bool>().value1;
2159 return static_cast<const SubStyleOne<NotProtected, bool>*>(d->subStyles[NotProtected].data())->value1;
2160}
2161
2162bool Style::isDefault() const
2163{
2164 return isEmpty() || d->subStyles.contains(DefaultStyleKey);
2165}
2166
2167bool Style::isEmpty() const
2168{
2169 return d->subStyles.isEmpty();
2170}
2171
2172void Style::setHAlign(HAlign align)
2173{
2174 insertSubStyle(HorizontalAlignment, align);
2175}
2176
2177void Style::setVAlign(VAlign align)
2178{
2179 insertSubStyle(VerticalAlignment, align);
2180}
2181
2182void Style::setFont(QFont const & font)
2183{
2184 insertSubStyle(FontFamily, font.family());
2185 insertSubStyle(FontSize, font.pointSize());
2186 insertSubStyle(FontBold, font.bold());
2187 insertSubStyle(FontItalic, font.italic());
2188 insertSubStyle(FontStrike, font.strikeOut());
2189 insertSubStyle(FontUnderline, font.underline());
2190}
2191
2192void Style::setFontFamily(QString const & family)
2193{
2194 insertSubStyle(FontFamily, family);
2195}
2196
2197void Style::setFontBold(bool enabled)
2198{
2199 insertSubStyle(FontBold, enabled);
2200}
2201
2202void Style::setFontItalic(bool enabled)
2203{
2204 insertSubStyle(FontItalic, enabled);
2205}
2206
2207void Style::setFontUnderline(bool enabled)
2208{
2209 insertSubStyle(FontUnderline, enabled);
2210}
2211
2212void Style::setFontStrikeOut(bool enabled)
2213{
2214 insertSubStyle(FontStrike, enabled);
2215}
2216
2217void Style::setFontSize(int size)
2218{
2219 insertSubStyle(FontSize, size);
2220}
2221
2222void Style::setFontColor(QColor const & color)
2223{
2224 insertSubStyle(FontColor, color);
2225}
2226
2227void Style::setBackgroundColor(QColor const & color)
2228{
2229 insertSubStyle(BackgroundColor, color);
2230}
2231
2232void Style::setRightBorderPen(QPen const & pen)
2233{
2234 insertSubStyle(RightPen, pen);
2235}
2236
2237void Style::setBottomBorderPen(QPen const & pen)
2238{
2239 insertSubStyle(BottomPen, pen);
2240}
2241
2242void Style::setLeftBorderPen(QPen const & pen)
2243{
2244 insertSubStyle(LeftPen, pen);
2245}
2246
2247void Style::setTopBorderPen(QPen const & pen)
2248{
2249 insertSubStyle(TopPen, pen);
2250}
2251
2252void Style::setFallDiagonalPen(QPen const & pen)
2253{
2254 insertSubStyle(FallDiagonalPen, pen);
2255}
2256
2257void Style::setGoUpDiagonalPen(QPen const & pen)
2258{
2259 insertSubStyle(GoUpDiagonalPen, pen);
2260}
2261
2262void Style::setAngle(int angle)
2263{
2264 insertSubStyle(Angle, angle);
2265}
2266
2267void Style::setIndentation(double indent)
2268{
2269 insertSubStyle(Indentation, indent);
2270}
2271
2272void Style::setBackgroundBrush(QBrush const & brush)
2273{
2274 insertSubStyle(BackgroundBrush, brush);
2275}
2276
2277void Style::setFloatFormat(FloatFormat format)
2278{
2279 insertSubStyle(FloatFormatKey, format);
2280}
2281
2282void Style::setFloatColor(FloatColor color)
2283{
2284 insertSubStyle(FloatColorKey, color);
2285}
2286
2287void Style::setFormatType(Format::Type format)
2288{
2289 insertSubStyle(FormatTypeKey, format);
2290}
2291
2292void Style::setCustomFormat(QString const & strFormat)
2293{
2294 insertSubStyle(CustomFormat, strFormat);
2295}
2296
2297void Style::setPrecision(int precision)
2298{
2299 insertSubStyle(Precision, precision);
2300}
2301
2302void Style::setThousandsSep(bool thousandsSep)
2303{
2304 insertSubStyle(ThousandsSep, thousandsSep);
2305}
2306
2307void Style::setPrefix(QString const & prefix)
2308{
2309 insertSubStyle(Prefix, prefix);
2310}
2311
2312void Style::setPostfix(QString const & postfix)
2313{
2314 insertSubStyle(Postfix, postfix);
2315}
2316
2317void Style::setCurrency(Currency const & currency)
2318{
2319 QVariant variant;
2320 variant.setValue(currency);
2321 insertSubStyle(CurrencyFormat, variant);
2322}
2323
2324void Style::setWrapText(bool enable)
2325{
2326 insertSubStyle(MultiRow, enable);
2327}
2328
2329void Style::setHideAll(bool enable)
2330{
2331 insertSubStyle(HideAll, enable);
2332}
2333
2334void Style::setHideFormula(bool enable)
2335{
2336 insertSubStyle(HideFormula, enable);
2337}
2338
2339void Style::setNotProtected(bool enable)
2340{
2341 insertSubStyle(NotProtected, enable);
2342}
2343
2344void Style::setDontPrintText(bool enable)
2345{
2346 insertSubStyle(DontPrintText, enable);
2347}
2348
2349void Style::setVerticalText(bool enable)
2350{
2351 insertSubStyle(VerticalText, enable);
2352}
2353
2354void Style::setShrinkToFit(bool enable)
2355{
2356 insertSubStyle(ShrinkToFit, enable);
2357}
2358
2359void Style::setDefault()
2360{
2361 insertSubStyle(DefaultStyleKey, true);
2362}
2363
2364void Style::clear()
2365{
2366 d->subStyles.clear();
2367}
2368
2369QString Style::colorName(const QColor& color)
2370{
2371 static QMap<QRgb, QString> map;
2372 QRgb rgb = color.rgb();
2373 if (!map.contains(rgb)) {
2374 map[rgb] = color.name();
2375 return map[rgb];
2376 } else {
2377 return map[rgb];
2378 }
2379}
2380
2381bool Style::compare(const SubStyle* one, const SubStyle* two)
2382{
2383 if (!one || !two)
2384 return one == two;
2385 if (one->type() != two->type())
2386 return false;
2387 switch (one->type()) {
2388 case DefaultStyleKey:
2389 return true;
2390 case NamedStyleKey:
2391 return static_cast<const NamedStyle*>(one)->name == static_cast<const NamedStyle*>(two)->name;
2392 // borders
2393 case LeftPen:
2394 return static_cast<const SubStyleOne<LeftPen, QPen>*>(one)->value1 == static_cast<const SubStyleOne<LeftPen, QPen>*>(two)->value1;
2395 case RightPen:
2396 return static_cast<const SubStyleOne<RightPen, QPen>*>(one)->value1 == static_cast<const SubStyleOne<RightPen, QPen>*>(two)->value1;
2397 case TopPen:
2398 return static_cast<const SubStyleOne<TopPen, QPen>*>(one)->value1 == static_cast<const SubStyleOne<TopPen, QPen>*>(two)->value1;
2399 case BottomPen:
2400 return static_cast<const SubStyleOne<BottomPen, QPen>*>(one)->value1 == static_cast<const SubStyleOne<BottomPen, QPen>*>(two)->value1;
2401 case FallDiagonalPen:
2402 return static_cast<const SubStyleOne<FallDiagonalPen, QPen>*>(one)->value1 == static_cast<const SubStyleOne<FallDiagonalPen, QPen>*>(two)->value1;
2403 case GoUpDiagonalPen:
2404 return static_cast<const SubStyleOne<GoUpDiagonalPen, QPen>*>(one)->value1 == static_cast<const SubStyleOne<GoUpDiagonalPen, QPen>*>(two)->value1;
2405 // layout
2406 case HorizontalAlignment:
2407 return static_cast<const SubStyleOne<HorizontalAlignment, HAlign>*>(one)->value1 == static_cast<const SubStyleOne<HorizontalAlignment, HAlign>*>(two)->value1;
2408 case VerticalAlignment:
2409 return static_cast<const SubStyleOne<VerticalAlignment, VAlign>*>(one)->value1 == static_cast<const SubStyleOne<VerticalAlignment, VAlign>*>(two)->value1;
2410 case MultiRow:
2411 return static_cast<const SubStyleOne<MultiRow, bool>*>(one)->value1 == static_cast<const SubStyleOne<MultiRow, bool>*>(two)->value1;
2412 case VerticalText:
2413 return static_cast<const SubStyleOne<VerticalText, bool>*>(one)->value1 == static_cast<const SubStyleOne<VerticalText, bool>*>(two)->value1;
2414 case ShrinkToFit:
2415 return static_cast<const SubStyleOne<ShrinkToFit, bool>*>(one)->value1 == static_cast<const SubStyleOne<ShrinkToFit, bool>*>(two)->value1;
2416 case Angle:
2417 return static_cast<const SubStyleOne<Angle, int>*>(one)->value1 == static_cast<const SubStyleOne<Angle, int>*>(two)->value1;
2418 case Indentation:
2419 return static_cast<const SubStyleOne<Indentation, int>*>(one)->value1 == static_cast<const SubStyleOne<Indentation, int>*>(two)->value1;
2420 // content format
2421 case Prefix:
2422 return static_cast<const SubStyleOne<Prefix, QString>*>(one)->value1 == static_cast<const SubStyleOne<Prefix, QString>*>(two)->value1;
2423 case Postfix:
2424 return static_cast<const SubStyleOne<Postfix, QString>*>(one)->value1 == static_cast<const SubStyleOne<Postfix, QString>*>(two)->value1;
2425 case Precision:
2426 return static_cast<const SubStyleOne<Precision, int>*>(one)->value1 == static_cast<const SubStyleOne<Precision, int>*>(two)->value1;
2427 case ThousandsSep:
2428 return static_cast<const SubStyleOne<ThousandsSep, bool>*>(one)->value1 == static_cast<const SubStyleOne<ThousandsSep, bool>*>(two)->value1;
2429 case FormatTypeKey:
2430 return static_cast<const SubStyleOne<FormatTypeKey, Format::Type>*>(one)->value1 == static_cast<const SubStyleOne<FormatTypeKey, Format::Type>*>(two)->value1;
2431 case FloatFormatKey:
2432 return static_cast<const SubStyleOne<FloatFormatKey, FloatFormat>*>(one)->value1 == static_cast<const SubStyleOne<FloatFormatKey, FloatFormat>*>(two)->value1;
2433 case FloatColorKey:
2434 return static_cast<const SubStyleOne<FloatColorKey, FloatColor>*>(one)->value1 == static_cast<const SubStyleOne<FloatColorKey, FloatColor>*>(two)->value1;
2435 case CurrencyFormat: {
2436 Currency currencyOne = static_cast<const SubStyleOne<CurrencyFormat, Currency>*>(one)->value1;
2437 Currency currencyTwo = static_cast<const SubStyleOne<CurrencyFormat, Currency>*>(two)->value1;
2438 if (currencyOne != currencyTwo)
2439 return false;
2440 return true;
2441 }
2442 case CustomFormat:
2443 return static_cast<const SubStyleOne<CustomFormat, QString>*>(one)->value1 == static_cast<const SubStyleOne<CustomFormat, QString>*>(two)->value1;
2444 // background
2445 case BackgroundBrush:
2446 return static_cast<const SubStyleOne<BackgroundBrush, QBrush>*>(one)->value1 == static_cast<const SubStyleOne<BackgroundBrush, QBrush>*>(two)->value1;
2447 case BackgroundColor:
2448 return static_cast<const SubStyleOne<BackgroundColor, QColor>*>(one)->value1 == static_cast<const SubStyleOne<BackgroundColor, QColor>*>(two)->value1;
2449 // font
2450 case FontColor:
2451 return static_cast<const SubStyleOne<FontColor, QColor>*>(one)->value1 == static_cast<const SubStyleOne<FontColor, QColor>*>(two)->value1;
2452 case FontFamily:
2453 return static_cast<const SubStyleOne<FontFamily, QString>*>(one)->value1 == static_cast<const SubStyleOne<FontFamily, QString>*>(two)->value1;
2454 case FontSize:
2455 return static_cast<const SubStyleOne<FontSize, int>*>(one)->value1 == static_cast<const SubStyleOne<FontSize, int>*>(two)->value1;
2456 case FontBold:
2457 return static_cast<const SubStyleOne<FontBold, bool>*>(one)->value1 == static_cast<const SubStyleOne<FontBold, bool>*>(two)->value1;
2458 case FontItalic:
2459 return static_cast<const SubStyleOne<FontItalic, bool>*>(one)->value1 == static_cast<const SubStyleOne<FontItalic, bool>*>(two)->value1;
2460 case FontStrike:
2461 return static_cast<const SubStyleOne<FontStrike, bool>*>(one)->value1 == static_cast<const SubStyleOne<FontStrike, bool>*>(two)->value1;
2462 case FontUnderline:
2463 return static_cast<const SubStyleOne<FontUnderline, bool>*>(one)->value1 == static_cast<const SubStyleOne<FontUnderline, bool>*>(two)->value1;
2464 //misc
2465 case DontPrintText:
2466 return static_cast<const SubStyleOne<DontPrintText, bool>*>(one)->value1 == static_cast<const SubStyleOne<DontPrintText, bool>*>(two)->value1;
2467 case NotProtected:
2468 return static_cast<const SubStyleOne<NotProtected, bool>*>(one)->value1 == static_cast<const SubStyleOne<NotProtected, bool>*>(two)->value1;
2469 case HideAll:
2470 return static_cast<const SubStyleOne<HideAll, bool>*>(one)->value1 == static_cast<const SubStyleOne<HideAll, bool>*>(two)->value1;
2471 case HideFormula:
2472 return static_cast<const SubStyleOne<HideFormula, bool>*>(one)->value1 == static_cast<const SubStyleOne<HideFormula, bool>*>(two)->value1;
2473 default:
2474 return false;
2475 }
2476}
2477
2478bool Style::operator==(const Style& other) const
2479{
2480 if (other.isEmpty())
2481 return isEmpty() ? true : false;
2482 const QSet<Key> keys = QSet<Key>::fromList(d->subStyles.keys() + other.d->subStyles.keys());
2483 const QSet<Key>::ConstIterator end = keys.constEnd();
2484 for (QSet<Key>::ConstIterator it = keys.constBegin(); it != end; ++it) {
2485 if (!compare(d->subStyles.value(*it).data(), other.d->subStyles.value(*it).data()))
2486 return false;
2487 }
2488 return true;
2489}
2490
2491uint Calligra::Sheets::qHash(const Style& style)
2492{
2493 uint hash = 0;
2494 foreach (const SharedSubStyle& ss, style.subStyles()) {
2495 hash ^= ss->koHash();
2496 }
2497 return hash;
2498}
2499
2500void Style::operator=(const Style & other)
2501{
2502 d = other.d;
2503}
2504
2505Style Style::operator-(const Style& other) const
2506{
2507 Style style;
2508 const QSet<Key> keys = difference(other);
2509 const QSet<Key>::ConstIterator end = keys.constEnd();
2510 for (QSet<Key>::ConstIterator it = keys.constBegin(); it != end; ++it)
2511 style.insertSubStyle(d->subStyles[*it]);
2512 return style;
2513}
2514
2515void Style::merge(const Style& style)
2516{
2517 const QList<SharedSubStyle> subStyles(style.subStyles());
2518// kDebug(36006) <<"merging" << subStyles.count() <<" attributes.";
2519 for (int i = 0; i < subStyles.count(); ++i) {
2520// kDebug(36006) << subStyles[i]->debugData();
2521 insertSubStyle(subStyles[i]);
2522 }
2523}
2524
2525QSet<Style::Key> Style::difference(const Style& other) const
2526{
2527 QSet<Key> result;
2528 const QSet<Key> keys = QSet<Key>::fromList(d->subStyles.keys() + other.d->subStyles.keys());
2529 const QSet<Key>::ConstIterator end = keys.constEnd();
2530 for (QSet<Key>::ConstIterator it = keys.constBegin(); it != end; ++it) {
2531 if (!other.d->subStyles.contains(*it))
2532 result.insert(*it);
2533 else if (d->subStyles.contains(*it)) { // both contain this key
2534 if (!compare(d->subStyles.value(*it).data(), other.d->subStyles.value(*it).data()))
2535 result.insert(*it);
2536 }
2537 }
2538 return result;
2539}
2540
2541void Style::dump() const
2542{
2543 for (int i = 0; i < subStyles().count(); ++i)
2544 subStyles()[i]->dump();
2545}
2546
2547QTextCharFormat Style::asCharFormat() const
2548{
2549 QTextCharFormat format;
2550 format.setFont(font());
2551 format.setFontWeight(bold() ? QFont::Bold : QFont::Normal);
2552 format.setFontItalic(italic());
2553 format.setFontUnderline(underline());
2554 format.setFontStrikeOut(strikeOut());
2555 return format;
2556}
2557
2558
2559QList<SharedSubStyle> Style::subStyles() const
2560{
2561 return d->subStyles.values();
2562}
2563
2564SharedSubStyle Style::createSubStyle(Key key, const QVariant& value)
2565{
2566 SharedSubStyle newSubStyle;
2567 switch (key) {
2568 // special cases
2569 case DefaultStyleKey:
2570 newSubStyle = new SubStyle();
2571 break;
2572 case NamedStyleKey:
2573 newSubStyle = new NamedStyle(value.value<QString>());
2574 break;
2575 case LeftPen:
2576 newSubStyle = new BorderPenStyle<LeftPen>(value.value<QPen>());
2577 break;
2578 case RightPen:
2579 newSubStyle = new BorderPenStyle<RightPen>(value.value<QPen>());
2580 break;
2581 case TopPen:
2582 newSubStyle = new BorderPenStyle<TopPen>(value.value<QPen>());
2583 break;
2584 case BottomPen:
2585 newSubStyle = new BorderPenStyle<BottomPen>(value.value<QPen>());
2586 break;
2587 case FallDiagonalPen:
2588 newSubStyle = new BorderPenStyle<FallDiagonalPen>(value.value<QPen>());
2589 break;
2590 case GoUpDiagonalPen:
2591 newSubStyle = new BorderPenStyle<GoUpDiagonalPen>(value.value<QPen>());
2592 break;
2593 // layout
2594 case HorizontalAlignment:
2595 newSubStyle = new SubStyleOne<HorizontalAlignment, HAlign>((HAlign)value.value<int>());
2596 break;
2597 case VerticalAlignment:
2598 newSubStyle = new SubStyleOne<VerticalAlignment, VAlign>((VAlign)value.value<int>());
2599 break;
2600 case MultiRow:
2601 newSubStyle = new SubStyleOne<MultiRow, bool>(value.value<bool>());
2602 break;
2603 case VerticalText:
2604 newSubStyle = new SubStyleOne<VerticalText, bool>(value.value<bool>());
2605 break;
2606 case Angle:
2607 newSubStyle = new SubStyleOne<Angle, int>(value.value<int>());
2608 break;
2609 case Indentation:
2610 newSubStyle = new SubStyleOne<Indentation, int>(value.value<int>());
2611 break;
2612 case ShrinkToFit:
2613 newSubStyle = new SubStyleOne<ShrinkToFit,bool>(value.value<bool>());
2614 break;
2615 // content format
2616 case Prefix:
2617 newSubStyle = new SubStyleOne<Prefix, QString>(value.value<QString>());
2618 break;
2619 case Postfix:
2620 newSubStyle = new SubStyleOne<Postfix, QString>(value.value<QString>());
2621 break;
2622 case Precision:
2623 newSubStyle = new SubStyleOne<Precision, int>(value.value<int>());
2624 break;
2625 case ThousandsSep:
2626 newSubStyle = new SubStyleOne<ThousandsSep, bool>(value.value<bool>());
2627 break;
2628 case FormatTypeKey:
2629 newSubStyle = new SubStyleOne<FormatTypeKey, Format::Type>((Format::Type)value.value<int>());
2630 break;
2631 case FloatFormatKey:
2632 newSubStyle = new SubStyleOne<FloatFormatKey, FloatFormat>((FloatFormat)value.value<int>());
2633 break;
2634 case FloatColorKey:
2635 newSubStyle = new SubStyleOne<FloatColorKey, FloatColor>((FloatColor)value.value<int>());
2636 break;
2637 case CurrencyFormat:
2638 newSubStyle = new SubStyleOne<CurrencyFormat, Currency>(value.value<Currency>());
2639 break;
2640 case CustomFormat:
2641 newSubStyle = new SubStyleOne<CustomFormat, QString>(value.value<QString>());
2642 break;
2643 // background
2644 case BackgroundBrush:
2645 newSubStyle = new SubStyleOne<BackgroundBrush, QBrush>(value.value<QBrush>());
2646 break;
2647 case BackgroundColor:
2648 newSubStyle = new SubStyleOne<BackgroundColor, QColor>(value.value<QColor>());
2649 break;
2650 // font
2651 case FontColor:
2652 newSubStyle = new SubStyleOne<FontColor, QColor>(value.value<QColor>());
2653 break;
2654 case FontFamily:
2655 newSubStyle = new SubStyleOne<FontFamily, QString>(value.value<QString>());
2656 break;
2657 case FontSize:
2658 newSubStyle = new SubStyleOne<FontSize, int>(value.value<int>());
2659 break;
2660 case FontBold:
2661 newSubStyle = new SubStyleOne<FontBold, bool>(value.value<bool>());
2662 break;
2663 case FontItalic:
2664 newSubStyle = new SubStyleOne<FontItalic, bool>(value.value<bool>());
2665 break;
2666 case FontStrike:
2667 newSubStyle = new SubStyleOne<FontStrike, bool>(value.value<bool>());
2668 break;
2669 case FontUnderline:
2670 newSubStyle = new SubStyleOne<FontUnderline, bool>(value.value<bool>());
2671 break;
2672 //misc
2673 case DontPrintText:
2674 newSubStyle = new SubStyleOne<DontPrintText, bool>(value.value<bool>());
2675 break;
2676 case NotProtected:
2677 newSubStyle = new SubStyleOne<NotProtected, bool>(value.value<bool>());
2678 break;
2679 case HideAll:
2680 newSubStyle = new SubStyleOne<HideAll, bool>(value.value<bool>());
2681 break;
2682 case HideFormula:
2683 newSubStyle = new SubStyleOne<HideFormula, bool>(value.value<bool>());
2684 break;
2685 }
2686 return newSubStyle;
2687}
2688
2689void Style::insertSubStyle(Key key, const QVariant& value)
2690{
2691 const SharedSubStyle subStyle = createSubStyle(key, value);
2692 Q_ASSERT(!!subStyle);
2693 insertSubStyle(subStyle);
2694}
2695
2696void Style::insertSubStyle(const SharedSubStyle& subStyle)
2697{
2698 if (!subStyle)
2699 return;
2700 releaseSubStyle(subStyle->type());
2701 d->subStyles.insert(subStyle->type(), subStyle);
2702}
2703
2704bool Style::releaseSubStyle(Key key)
2705{
2706 if (!d->subStyles.contains(key))
2707 return false;
2708
2709 d->subStyles.remove(key);
2710 return true;
2711}
2712
2713/////////////////////////////////////////////////////////////////////////////
2714//
2715// CustomStyle::Private
2716//
2717/////////////////////////////////////////////////////////////////////////////
2718
2719class CustomStyle::Private : public QSharedData
2720{
2721public:
2722 QString name;
2723 StyleType type;
2724};
2725
2726
2727/////////////////////////////////////////////////////////////////////////////
2728//
2729// CustomStyle
2730//
2731/////////////////////////////////////////////////////////////////////////////
2732
2733CustomStyle::CustomStyle()
2734 : Style()
2735 , d(new Private)
2736{
2737 d->name = "Default";
2738 d->type = BUILTIN;
2739 setDefault();
2740}
2741
2742CustomStyle::CustomStyle(QString const & name, CustomStyle * parent)
2743 : Style()
2744 , d(new Private)
2745{
2746 d->name = name;
2747 d->type = CUSTOM;
2748 if (parent)
2749 setParentName(parent->name());
2750}
2751
2752CustomStyle::CustomStyle(const CustomStyle& style)
2753 : Style(style), d(style.d)
2754{
2755}
2756
2757CustomStyle::~CustomStyle()
2758{
2759}
2760
2761CustomStyle& CustomStyle::operator=(const CustomStyle& style)
2762{
2763 Style::operator=(style);
2764 d = style.d;
2765 return *this;
2766}
2767
2768Style::StyleType CustomStyle::type() const
2769{
2770 return d->type;
2771}
2772
2773void CustomStyle::setType(StyleType type)
2774{
2775 Q_ASSERT(type != AUTO);
2776 d->type = type;
2777}
2778
2779const QString& CustomStyle::name() const
2780{
2781 return d->name;
2782}
2783
2784void CustomStyle::setName(QString const & name)
2785{
2786 d->name = name;
2787}
2788
2789QString CustomStyle::saveOdf(KoGenStyle& style, KoGenStyles &mainStyles,
2790 const StyleManager* manager) const
2791{
2792 Q_ASSERT(!name().isEmpty());
2793 // default style does not need display name
2794 if (!isDefault())
2795 style.addAttribute("style:display-name", name());
2796
2797 // doing the real work
2798 QSet<Key> keysToStore;
2799 for (int i = 0; i < subStyles().count(); ++i)
2800 keysToStore.insert(subStyles()[i].data()->type());
2801 saveOdfStyle(keysToStore, style, mainStyles, manager);
2802
2803 if (isDefault()) {
2804 style.setDefaultStyle(true);
2805 // don't i18n'ize "Default" in this case
2806 return mainStyles.insert(style, "Default", KoGenStyles::DontAddNumberToName);
2807 }
2808
2809 // this is a custom style
2810 return mainStyles.insert(style, "custom-style");
2811}
2812
2813void CustomStyle::loadOdf(KoOdfStylesReader& stylesReader, const KoXmlElement& style,
2814 const QString& name, Conditions& conditions,
2815 const StyleManager* styleManager, const ValueParser *parser)
2816{
2817 setName(name);
2818 if (style.hasAttributeNS(KoXmlNS::style, "parent-style-name"))
2819 setParentName(style.attributeNS(KoXmlNS::style, "parent-style-name", QString()));
2820
2821 setType(CUSTOM);
2822
2823 Style::loadOdfStyle(stylesReader, style, conditions, styleManager, parser);
2824}
2825
2826void CustomStyle::save(QDomDocument& doc, QDomElement& styles, const StyleManager* styleManager)
2827{
2828 if (name().isEmpty())
2829 return;
2830
2831 QDomElement style(doc.createElement("style"));
2832 style.setAttribute("type", (int) type());
2833 if (!parentName().isNull())
2834 style.setAttribute("parent", parentName());
2835 style.setAttribute("name", name());
2836
2837 QDomElement format(doc.createElement("format"));
2838 saveXML(doc, format, styleManager);
2839 style.appendChild(format);
2840
2841 styles.appendChild(style);
2842}
2843
2844bool CustomStyle::loadXML(KoXmlElement const & style, QString const & name)
2845{
2846 setName(name);
2847
2848 if (style.hasAttribute("parent"))
2849 setParentName(style.attribute("parent"));
2850
2851 if (!style.hasAttribute("type"))
2852 return false;
2853
2854 bool ok = true;
2855 setType((StyleType) style.attribute("type").toInt(&ok));
2856 if (!ok)
2857 return false;
2858
2859 KoXmlElement f(style.namedItem("format").toElement());
2860 if (!f.isNull())
2861 if (!Style::loadXML(f))
2862 return false;
2863
2864 return true;
2865}
2866
2867int CustomStyle::usage() const
2868{
2869 return d->ref;
2870}
2871