1 /* This file is part of the KDE project
2  * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
3  * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
4  * Copyright (C) 2008 Roopesh Chander <roop@forwardbias.in>
5  * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
6  * Copyright (C) 2009 KO GmbH <cbo@kogmbh.com>
7  * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 #include "KoTableCellStyle.h"
25 #include "KoTableCellStyle_p.h"
26 
27 #include <KoXmlReaderForward.h>
28 
29 #include <KoGenStyle.h>
30 #include <KoShapeLoadingContext.h>
31 #include <KoOdfGraphicStyles.h>
32 #include "KoParagraphStyle.h"
33 
34 #include <KoTextDebug.h>
35 
36 #include <QTextTableFormat>
37 #include <QTextTableCell>
38 
39 #include <KoUnit.h>
40 #include <KoStyleStack.h>
41 #include <KoOdfLoadingContext.h>
42 #include <KoXmlNS.h>
43 
44 #include "TextDebug.h"
45 
46 #include <cfloat>
47 
rotationAlignmentFromString(const QString & align)48 KoTableCellStyle::RotationAlignment rotationAlignmentFromString(const QString& align)
49 {
50     if (align == "bottom")
51         return KoTableCellStyle::RAlignBottom;
52     if (align == "center")
53         return KoTableCellStyle::RAlignCenter;
54     if (align == "top")
55         return KoTableCellStyle::RAlignTop;
56 
57     return KoTableCellStyle::RAlignNone;
58 }
59 
rotationAlignmentToString(KoTableCellStyle::RotationAlignment align)60 QString rotationAlignmentToString(KoTableCellStyle::RotationAlignment align)
61 {
62     if (align == KoTableCellStyle::RAlignBottom)
63         return "bottom";
64     if (align == KoTableCellStyle::RAlignTop)
65         return "top";
66     if (align == KoTableCellStyle::RAlignCenter)
67         return "center";
68     return "none";
69 }
70 
KoTableCellStylePrivate()71 KoTableCellStylePrivate::KoTableCellStylePrivate()
72     : paragraphStyle(0)
73     , parentStyle(0)
74     , next(0)
75 {
76 }
77 
~KoTableCellStylePrivate()78 KoTableCellStylePrivate::~KoTableCellStylePrivate()
79 {
80 }
81 
setProperty(int key,const QVariant & value)82 void KoTableCellStylePrivate::setProperty(int key, const QVariant &value)
83 {
84     stylesPrivate.add(key, value);
85 }
86 
KoTableCellStyle(QObject * parent)87 KoTableCellStyle::KoTableCellStyle(QObject *parent)
88     : QObject(parent)
89     , d_ptr(new KoTableCellStylePrivate)
90 {
91     Q_D(KoTableCellStyle);
92     d->paragraphStyle = new KoParagraphStyle(this);
93 }
94 
KoTableCellStyle(const QTextTableCellFormat & format,QObject * parent)95 KoTableCellStyle::KoTableCellStyle(const QTextTableCellFormat &format, QObject *parent)
96     : QObject(parent)
97     , d_ptr(new KoTableCellStylePrivate)
98 {
99     Q_D(KoTableCellStyle);
100     d->stylesPrivate = format.properties();
101     d->paragraphStyle = new KoParagraphStyle(this);
102 }
103 
KoTableCellStyle(const KoTableCellStyle & other)104 KoTableCellStyle::KoTableCellStyle(const KoTableCellStyle &other)
105     :QObject(other.parent())
106     , d_ptr(new KoTableCellStylePrivate)
107 {
108     Q_D(KoTableCellStyle);
109 
110     copyProperties(&other);
111     d->paragraphStyle = other.paragraphStyle()->clone(this);
112 }
113 
operator =(const KoTableCellStyle & other)114 KoTableCellStyle& KoTableCellStyle::operator=(const KoTableCellStyle &other)
115 {
116     Q_D(KoTableCellStyle);
117 
118     if (this == &other) {
119         return *this;
120     }
121 
122     copyProperties(&other);
123     d->paragraphStyle = other.paragraphStyle()->clone(this);
124 
125     return *this;
126 }
127 
~KoTableCellStyle()128 KoTableCellStyle::~KoTableCellStyle()
129 {
130     delete d_ptr;
131 }
132 
fromTableCell(const QTextTableCell & tableCell,QObject * parent)133 KoTableCellStyle *KoTableCellStyle::fromTableCell(const QTextTableCell &tableCell, QObject *parent)
134 {
135     QTextTableCellFormat tableCellFormat = tableCell.format().toTableCellFormat();
136     return new KoTableCellStyle(tableCellFormat, parent);
137 }
138 
cleanCharFormat(const QTextCharFormat & charFormat)139 QTextCharFormat KoTableCellStyle::cleanCharFormat(const QTextCharFormat &charFormat)
140 {
141     if (charFormat.isTableCellFormat()) {
142         QTextTableCellFormat format;
143         const QMap<int, QVariant> props = charFormat.properties();
144         QMap<int, QVariant>::const_iterator it = props.begin();
145         while (it != props.end()) {
146             // lets save all Qt's table cell properties
147             if (it.key()>=QTextFormat::TableCellRowSpan && it.key()<QTextFormat::ImageName)
148                 format.setProperty(it.key(), it.value());
149 
150             // lets save all our table cell properties
151             if (it.key()>=StyleId && it.key()<LastCellStyleProperty)
152                 format.setProperty(it.key(), it.value());
153 
154             ++it;
155         }
156         return format;
157     }
158     return QTextCharFormat();
159 }
160 
contentRect(const QRectF & boundingRect) const161 QRectF KoTableCellStyle::contentRect(const QRectF &boundingRect) const
162 {
163     const KoBorder::BorderData &leftEdge = getEdge(KoBorder::LeftBorder);
164     const KoBorder::BorderData &topEdge = getEdge(KoBorder::TopBorder);
165     const KoBorder::BorderData &rightEdge = getEdge(KoBorder::RightBorder);
166     const KoBorder::BorderData &bottomEdge = getEdge(KoBorder::BottomBorder);
167 
168     return boundingRect.adjusted(
169                 leftEdge.outerPen.widthF() + leftEdge.spacing + leftEdge.innerPen.widthF() + propertyDouble(QTextFormat::TableCellLeftPadding),
170                 topEdge.outerPen.widthF() + topEdge .spacing + topEdge .innerPen.widthF() + propertyDouble(QTextFormat::TableCellTopPadding),
171                 - rightEdge.outerPen.widthF() - rightEdge.spacing - rightEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellRightPadding),
172                 - bottomEdge.outerPen.widthF() - bottomEdge.spacing - bottomEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellBottomPadding)
173    );
174 }
175 
boundingRect(const QRectF & contentRect) const176 QRectF KoTableCellStyle::boundingRect(const QRectF &contentRect) const
177 {
178     const KoBorder::BorderData &leftEdge = getEdge(KoBorder::LeftBorder);
179     const KoBorder::BorderData &topEdge = getEdge(KoBorder::TopBorder);
180     const KoBorder::BorderData &rightEdge = getEdge(KoBorder::RightBorder);
181     const KoBorder::BorderData &bottomEdge = getEdge(KoBorder::BottomBorder);
182 
183     return contentRect.adjusted(
184                 - leftEdge.outerPen.widthF() - leftEdge.spacing - leftEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellLeftPadding),
185                 - topEdge.outerPen.widthF() - topEdge.spacing - topEdge.innerPen.widthF() - propertyDouble(QTextFormat::TableCellTopPadding),
186                 rightEdge.outerPen.widthF() + rightEdge.spacing + rightEdge.innerPen.widthF() + propertyDouble(QTextFormat::TableCellRightPadding),
187                 bottomEdge.outerPen.widthF() + bottomEdge.spacing + bottomEdge.innerPen.widthF() + propertyDouble(QTextFormat::TableCellBottomPadding)
188    );
189 }
190 
setParentStyle(KoTableCellStyle * parent)191 void KoTableCellStyle::setParentStyle(KoTableCellStyle *parent)
192 {
193     Q_D(KoTableCellStyle);
194     d->parentStyle = parent;
195 }
196 
setLeftPadding(qreal padding)197 void KoTableCellStyle::setLeftPadding(qreal padding)
198 {
199     setProperty(QTextFormat::TableCellLeftPadding, padding);
200 }
201 
setTopPadding(qreal padding)202 void KoTableCellStyle::setTopPadding(qreal padding)
203 {
204     setProperty(QTextFormat::TableCellTopPadding, padding);
205 }
206 
setRightPadding(qreal padding)207 void KoTableCellStyle::setRightPadding(qreal padding)
208 {
209     setProperty(QTextFormat::TableCellRightPadding, padding);
210 }
211 
setBottomPadding(qreal padding)212 void KoTableCellStyle::setBottomPadding(qreal padding)
213 {
214     setProperty(QTextFormat::TableCellBottomPadding, padding);
215 }
216 
leftPadding() const217 qreal KoTableCellStyle::leftPadding() const
218 {
219     return propertyDouble(QTextFormat::TableCellLeftPadding);
220 }
221 
rightPadding() const222 qreal KoTableCellStyle::rightPadding() const
223 {
224     return propertyDouble(QTextFormat::TableCellRightPadding);
225 }
226 
topPadding() const227 qreal KoTableCellStyle::topPadding() const
228 {
229     return propertyDouble(QTextFormat::TableCellTopPadding);
230 }
231 
bottomPadding() const232 qreal KoTableCellStyle::bottomPadding() const
233 {
234     return propertyDouble(QTextFormat::TableCellBottomPadding);
235 }
236 
setPadding(qreal padding)237 void KoTableCellStyle::setPadding(qreal padding)
238 {
239     setBottomPadding(padding);
240     setTopPadding(padding);
241     setRightPadding(padding);
242     setLeftPadding(padding);
243 }
244 
paragraphStyle() const245 KoParagraphStyle *KoTableCellStyle::paragraphStyle() const
246 {
247     Q_D(const KoTableCellStyle);
248     return d->paragraphStyle;
249 }
250 
shrinkToFit() const251 bool KoTableCellStyle::shrinkToFit() const
252 {
253     return propertyBoolean(ShrinkToFit);
254 }
255 
setShrinkToFit(bool state)256 void KoTableCellStyle::setShrinkToFit(bool state)
257 {
258     setProperty(ShrinkToFit, state);
259 }
260 
setProperty(int key,const QVariant & value)261 void KoTableCellStyle::setProperty(int key, const QVariant &value)
262 {
263     Q_D(KoTableCellStyle);
264     if (d->parentStyle) {
265         QVariant var = d->parentStyle->value(key);
266         if (!var.isNull() && var == value) { // same as parent, so its actually a reset.
267             d->stylesPrivate.remove(key);
268             return;
269         }
270     }
271     d->stylesPrivate.add(key, value);
272 }
273 
remove(int key)274 void KoTableCellStyle::remove(int key)
275 {
276     Q_D(KoTableCellStyle);
277     d->stylesPrivate.remove(key);
278 }
279 
value(int key) const280 QVariant KoTableCellStyle::value(int key) const
281 {
282     Q_D(const KoTableCellStyle);
283     QVariant var = d->stylesPrivate.value(key);
284     if (var.isNull() && d->parentStyle)
285         var = d->parentStyle->value(key);
286     return var;
287 }
288 
hasProperty(int key) const289 bool KoTableCellStyle::hasProperty(int key) const
290 {
291     Q_D(const KoTableCellStyle);
292     return d->stylesPrivate.contains(key);
293 }
294 
propertyDouble(int key) const295 qreal KoTableCellStyle::propertyDouble(int key) const
296 {
297     QVariant variant = value(key);
298     if (variant.isNull())
299         return 0.0;
300     return variant.toDouble();
301 }
302 
propertyPen(int key) const303 QPen KoTableCellStyle::propertyPen(int key) const
304 {
305     const QVariant prop = value(key);
306     if (prop.userType() != QVariant::Pen)
307         return QPen(Qt::NoPen);
308     return qvariant_cast<QPen>(prop);
309 }
310 
propertyInt(int key) const311 int KoTableCellStyle::propertyInt(int key) const
312 {
313     QVariant variant = value(key);
314     if (variant.isNull())
315         return 0;
316     return variant.toInt();
317 }
318 
propertyBoolean(int key) const319 bool KoTableCellStyle::propertyBoolean(int key) const
320 {
321     QVariant variant = value(key);
322     if (variant.isNull())
323         return false;
324     return variant.toBool();
325 }
326 
propertyColor(int key) const327 QColor KoTableCellStyle::propertyColor(int key) const
328 {
329     QVariant variant = value(key);
330     if (variant.isNull()) {
331         return QColor();
332     }
333     return qvariant_cast<QColor>(variant);
334 }
335 
applyStyle(QTextTableCellFormat & format) const336 void KoTableCellStyle::applyStyle(QTextTableCellFormat &format) const
337 {
338     Q_D(const KoTableCellStyle);
339     if (d->parentStyle) {
340         d->parentStyle->applyStyle(format);
341     }
342     QList<int> keys = d->stylesPrivate.keys();
343     for (int i = 0; i < keys.count(); i++) {
344         QVariant variant = d->stylesPrivate.value(keys[i]);
345         format.setProperty(keys[i], variant);
346     }
347     // Hack : build KoBorder here
348     if (d->parentStyle && d->parentStyle->hasProperty(Borders) && this->hasProperty(Borders)) {
349         KoBorder parentBorder = d->parentStyle->borders();
350         KoBorder childBorder = this->borders();
351         if (childBorder.hasBorder(KoBorder::LeftBorder))
352             parentBorder.setBorderData(KoBorder::LeftBorder, childBorder.borderData(KoBorder::LeftBorder));
353         if (childBorder.hasBorder(KoBorder::RightBorder))
354             parentBorder.setBorderData(KoBorder::RightBorder, childBorder.borderData(KoBorder::RightBorder));
355         if (childBorder.hasBorder(KoBorder::TopBorder))
356             parentBorder.setBorderData(KoBorder::TopBorder, childBorder.borderData(KoBorder::TopBorder));
357         if (childBorder.hasBorder(KoBorder::BottomBorder))
358             parentBorder.setBorderData(KoBorder::BottomBorder, childBorder.borderData(KoBorder::BottomBorder));
359         if (childBorder.hasBorder(KoBorder::BltrBorder))
360             parentBorder.setBorderData(KoBorder::BltrBorder, childBorder.borderData(KoBorder::BltrBorder));
361         if (childBorder.hasBorder(KoBorder::TlbrBorder))
362             parentBorder.setBorderData(KoBorder::TlbrBorder, childBorder.borderData(KoBorder::TlbrBorder));
363         format.setProperty(Borders, QVariant::fromValue<KoBorder>(parentBorder));
364     }
365 }
366 
applyStyle(QTextTableCell & cell) const367 void KoTableCellStyle::applyStyle(QTextTableCell &cell) const
368 {
369     Q_D(const KoTableCellStyle);
370     QTextTableCellFormat format = cell.format().toTableCellFormat();
371     applyStyle(format);
372 
373     if (d->paragraphStyle) {
374         d->paragraphStyle->KoCharacterStyle::applyStyle(format);
375     }
376     cell.setFormat(format);
377 }
378 
setBackground(const QBrush & brush)379 void KoTableCellStyle::setBackground(const QBrush &brush)
380 {
381     setProperty(CellBackgroundBrush, brush);
382 }
383 
clearBackground()384 void KoTableCellStyle::clearBackground()
385 {
386     Q_D(KoTableCellStyle);
387     d->stylesPrivate.remove(CellBackgroundBrush);
388 }
389 
background() const390 QBrush KoTableCellStyle::background() const
391 {
392     Q_D(const KoTableCellStyle);
393     QVariant variant = d->stylesPrivate.value(CellBackgroundBrush);
394 
395     if (variant.isNull()) {
396         return QBrush();
397     }
398     return qvariant_cast<QBrush>(variant);
399 }
400 
setWrap(bool state)401 void KoTableCellStyle::setWrap(bool state)
402 {
403     setProperty(Wrap, state);
404 }
405 
wrap() const406 bool KoTableCellStyle::wrap() const
407 {
408     return propertyBoolean(Wrap);
409 }
410 
setAlignment(Qt::Alignment alignment)411 void KoTableCellStyle::setAlignment(Qt::Alignment alignment)
412 {
413     setProperty(VerticalAlignment, (int) alignment);
414 }
415 
alignment() const416 Qt::Alignment KoTableCellStyle::alignment() const
417 {
418     if (propertyInt(VerticalAlignment) == 0)
419         return Qt::AlignTop;
420     return static_cast<Qt::Alignment>(propertyInt(VerticalAlignment));
421 }
422 
parentStyle() const423 KoTableCellStyle *KoTableCellStyle::parentStyle() const
424 {
425     Q_D(const KoTableCellStyle);
426     return d->parentStyle;
427 }
428 
name() const429 QString KoTableCellStyle::name() const
430 {
431     Q_D(const KoTableCellStyle);
432     return d->name;
433 }
434 
setName(const QString & name)435 void KoTableCellStyle::setName(const QString &name)
436 {
437     Q_D(KoTableCellStyle);
438     if (name == d->name)
439         return;
440     d->name = name;
441     emit nameChanged(name);
442 }
443 
styleId() const444 int KoTableCellStyle::styleId() const
445 {
446     return propertyInt(StyleId);
447 }
448 
setStyleId(int id)449 void KoTableCellStyle::setStyleId(int id)
450 {
451     Q_D(KoTableCellStyle);
452     setProperty(StyleId, id); if (d->next == 0) d->next = id;
453 }
454 
masterPageName() const455 QString KoTableCellStyle::masterPageName() const
456 {
457     return value(MasterPageName).toString();
458 }
459 
setMasterPageName(const QString & name)460 void KoTableCellStyle::setMasterPageName(const QString &name)
461 {
462     setProperty(MasterPageName, name);
463 }
464 
setCellProtection(KoTableCellStyle::CellProtectionFlag protection)465 void KoTableCellStyle::setCellProtection(KoTableCellStyle::CellProtectionFlag protection)
466 {
467     setProperty(CellProtection, protection);
468 }
469 
cellProtection() const470 KoTableCellStyle::CellProtectionFlag KoTableCellStyle::cellProtection() const
471 {
472     return (CellProtectionFlag) propertyInt(CellProtection);
473 }
474 
setTextDirection(KoText::Direction value)475 void KoTableCellStyle::setTextDirection(KoText::Direction value)
476 {
477     setProperty(TextWritingMode, value);
478 }
479 
textDirection() const480 KoText::Direction KoTableCellStyle::textDirection() const
481 {
482     return (KoText::Direction) propertyInt(TextWritingMode);
483 }
484 
printContent() const485 bool KoTableCellStyle::printContent() const
486 {
487     return (hasProperty(PrintContent) && propertyBoolean(PrintContent));
488 }
489 
setPrintContent(bool state)490 void KoTableCellStyle::setPrintContent(bool state)
491 {
492     setProperty(PrintContent, state);
493 }
494 
repeatContent() const495 bool KoTableCellStyle::repeatContent() const
496 {
497     return (hasProperty(RepeatContent) && propertyBoolean(RepeatContent));
498 }
499 
setRepeatContent(bool state)500 void KoTableCellStyle::setRepeatContent(bool state)
501 {
502     setProperty(RepeatContent, state);
503 }
504 
decimalPlaces() const505 int KoTableCellStyle::decimalPlaces() const
506 {
507     return propertyInt(DecimalPlaces);
508 }
509 
setDecimalPlaces(int places)510 void KoTableCellStyle::setDecimalPlaces(int places)
511 {
512     setProperty(DecimalPlaces, places);
513 }
514 
alignFromType() const515 bool KoTableCellStyle::alignFromType() const
516 {
517     return (hasProperty(AlignFromType) && propertyBoolean(AlignFromType));
518 }
519 
setAlignFromType(bool state)520 void KoTableCellStyle::setAlignFromType(bool state)
521 {
522     setProperty(AlignFromType, state);
523 }
524 
rotationAngle() const525 qreal KoTableCellStyle::rotationAngle() const
526 {
527     return propertyDouble(RotationAngle);
528 }
529 
setRotationAngle(qreal value)530 void KoTableCellStyle::setRotationAngle(qreal value)
531 {
532     if (value >= 0)
533         setProperty(RotationAngle, value);
534 }
535 
setVerticalGlyphOrientation(bool state)536 void KoTableCellStyle::setVerticalGlyphOrientation(bool state)
537 {
538     setProperty(VerticalGlyphOrientation, state);
539 }
540 
verticalGlyphOrientation() const541 bool KoTableCellStyle::verticalGlyphOrientation() const
542 {
543     if (hasProperty(VerticalGlyphOrientation))
544         return propertyBoolean(VerticalGlyphOrientation);
545     return true;
546 }
547 
setDirection(KoTableCellStyle::CellTextDirection direction)548 void KoTableCellStyle::setDirection(KoTableCellStyle::CellTextDirection direction)
549 {
550     setProperty(Direction, direction);
551 }
552 
borders() const553 KoBorder KoTableCellStyle::borders() const
554 {
555     if (hasProperty(Borders))
556         return value(Borders).value<KoBorder>();
557     return KoBorder();
558 }
559 
setBorders(const KoBorder & borders)560 void KoTableCellStyle::setBorders(const KoBorder& borders)
561 {
562     setProperty(Borders, QVariant::fromValue<KoBorder>(borders));
563 }
564 
shadow() const565 KoShadowStyle KoTableCellStyle::shadow() const
566 {
567     if (hasProperty(Shadow))
568         return value(Shadow).value<KoShadowStyle>();
569     return KoShadowStyle();
570 }
571 
setShadow(const KoShadowStyle & shadow)572 void KoTableCellStyle::setShadow(const KoShadowStyle& shadow)
573 {
574     setProperty(Shadow, QVariant::fromValue<KoShadowStyle>(shadow));
575 }
576 
rotationAlignment() const577 KoTableCellStyle::RotationAlignment KoTableCellStyle::rotationAlignment() const
578 {
579     return static_cast<RotationAlignment>(propertyInt(RotationAlign));
580 }
581 
setRotationAlignment(KoTableCellStyle::RotationAlignment align)582 void KoTableCellStyle::setRotationAlignment(KoTableCellStyle::RotationAlignment align)
583 {
584     setProperty(RotationAlign, align);
585 }
586 
direction() const587 KoTableCellStyle::CellTextDirection KoTableCellStyle::direction() const
588 {
589     if (hasProperty(Direction))
590         return (KoTableCellStyle::CellTextDirection) propertyInt(Direction);
591     return KoTableCellStyle::Default;
592 }
593 
loadOdf(const KoXmlElement * element,KoShapeLoadingContext & scontext)594 void KoTableCellStyle::loadOdf(const KoXmlElement *element, KoShapeLoadingContext &scontext)
595 {
596     KoOdfLoadingContext &context = scontext.odfLoadingContext();
597     Q_D(KoTableCellStyle);
598     if (element->hasAttributeNS(KoXmlNS::style, "display-name"))
599         d->name = element->attributeNS(KoXmlNS::style, "display-name", QString());
600 
601     if (d->name.isEmpty()) // if no style:display-name is given us the style:name
602         d->name = element->attributeNS(KoXmlNS::style, "name", QString());
603 
604     QString masterPage = element->attributeNS(KoXmlNS::style, "master-page-name", QString());
605     if (! masterPage.isEmpty()) {
606         setMasterPageName(masterPage);
607     }
608 
609     paragraphStyle()->loadOdf(element, scontext, true); // load the par and char properties
610 
611     // Borders - we don't handle inheritance unfortunately - hope it's not a big problem
612     KoBorder borders = this->borders();
613     borders.loadOdf(element->namedItemNS(KoXmlNS::style, "table-cell-properties").toElement());
614     setBorders(borders);
615 
616     context.styleStack().save();
617     QString family = element->attributeNS(KoXmlNS::style, "family", "table-cell");
618     context.addStyles(element, family.toLocal8Bit().constData());   // Load all parents - only because we don't support inheritance.
619 
620     context.styleStack().setTypeProperties("table-cell");
621     loadOdfProperties(scontext, context.styleStack());
622 
623     context.styleStack().setTypeProperties("graphic");
624     loadOdfProperties(scontext, context.styleStack());
625 
626     context.styleStack().restore();
627 }
628 
loadOdfProperties(KoShapeLoadingContext & context,KoStyleStack & styleStack)629 void KoTableCellStyle::loadOdfProperties(KoShapeLoadingContext &context, KoStyleStack &styleStack)
630 {
631     // Padding
632     if (styleStack.hasProperty(KoXmlNS::fo, "padding-left"))
633         setLeftPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-left")));
634     if (styleStack.hasProperty(KoXmlNS::fo, "padding-right"))
635         setRightPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-right")));
636     if (styleStack.hasProperty(KoXmlNS::fo, "padding-top"))
637         setTopPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-top")));
638     if (styleStack.hasProperty(KoXmlNS::fo, "padding-bottom"))
639         setBottomPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding-bottom")));
640     if (styleStack.hasProperty(KoXmlNS::fo, "padding"))
641         setPadding(KoUnit::parseValue(styleStack.property(KoXmlNS::fo, "padding")));
642 
643     if (styleStack.hasProperty(KoXmlNS::style, "shadow")) {
644         KoShadowStyle shadow;
645         if (shadow.loadOdf(styleStack.property(KoXmlNS::style, "shadow"))) {
646             setShadow(shadow);
647         }
648     }
649 
650     // The fo:background-color attribute specifies the background color of a cell.
651     if (styleStack.hasProperty(KoXmlNS::fo, "background-color")) {
652         const QString bgcolor = styleStack.property(KoXmlNS::fo, "background-color");
653         QBrush brush = background();
654         if (bgcolor == "transparent")
655             setBackground(Qt::NoBrush);
656         else {
657             if (brush.style() == Qt::NoBrush)
658                 brush.setStyle(Qt::SolidPattern);
659             brush.setColor(bgcolor); // #rrggbb format
660             setBackground(brush);
661         }
662     }
663 
664     QString fillStyle = styleStack.property(KoXmlNS::draw, "fill");
665     if (fillStyle == "solid" || fillStyle == "hatch") {
666         styleStack.save();
667         QBrush brush = KoOdfGraphicStyles::loadOdfFillStyle(styleStack, fillStyle, context.odfLoadingContext().stylesReader());
668         setBackground(brush);
669         styleStack.restore();
670     }
671 
672     if (styleStack.hasProperty(KoXmlNS::style, "shrink-to-fit")) {
673         setShrinkToFit(styleStack.property(KoXmlNS::style, "shrink-to-fit") == "true");
674     }
675 
676     if (styleStack.hasProperty(KoXmlNS::style, "print-content")) {
677         setPrintContent(styleStack.property(KoXmlNS::style, "print-content") == "true");
678     }
679 
680     if (styleStack.hasProperty(KoXmlNS::style, "repeat-content")) {
681         setRepeatContent(styleStack.property(KoXmlNS::style, "repeat-content") == "true");
682     }
683 
684     if (styleStack.hasProperty(KoXmlNS::style, "repeat-content")) {
685         setRepeatContent(styleStack.property(KoXmlNS::style, "repeat-content") == "true");
686     }
687 
688     if (styleStack.hasProperty(KoXmlNS::style, "decimal-places")) {
689         bool ok;
690         int value = styleStack.property(KoXmlNS::style, "decimal-places").toInt(&ok);
691         if (ok)
692             setDecimalPlaces(value);
693     }
694 
695     if (styleStack.hasProperty(KoXmlNS::style, "rotation-angle")) {
696         setRotationAngle(KoUnit::parseAngle(styleStack.property(KoXmlNS::style, "rotation-angle")));
697     }
698 
699     if (styleStack.hasProperty(KoXmlNS::style, "glyph-orientation-vertical"))
700     {
701         setVerticalGlyphOrientation(styleStack.property(KoXmlNS::style, "glyph-orientation-vertical") == "auto");
702     }
703 
704     if (styleStack.hasProperty(KoXmlNS::style, "direction")) {
705         if (styleStack.property(KoXmlNS::style, "direction") == "ltr")
706             setDirection(KoTableCellStyle::LeftToRight);
707         else
708             setDirection(KoTableCellStyle::TopToBottom);
709     }
710 
711     if (styleStack.hasProperty(KoXmlNS::style, "rotation-align")) {
712         setRotationAlignment(rotationAlignmentFromString(styleStack.property(KoXmlNS::style, "rotation-align")));
713     }
714 
715     if (styleStack.hasProperty(KoXmlNS::style, "text-align-source")) {
716         setAlignFromType(styleStack.property(KoXmlNS::style, "text-align-source") == "value-type");
717     }
718 
719     if (styleStack.hasProperty(KoXmlNS::fo, "wrap-option")) {
720         setWrap(styleStack.property(KoXmlNS::fo, "wrap-option") == "wrap");
721     }
722 
723     if (styleStack.hasProperty(KoXmlNS::style, "cell-protect")) {
724         QString protection = styleStack.property(KoXmlNS::style, "cell-protect");
725         if (protection == "none")
726             setCellProtection(NoProtection);
727         else if (protection == "hidden-and-protected")
728             setCellProtection(HiddenAndProtected);
729         else if (protection == "protected")
730             setCellProtection(Protected);
731         else if (protection == "formula-hidden")
732             setCellProtection(FormulaHidden);
733         else if ((protection == "protected formula-hidden") || (protection == "formula-hidden protected"))
734             setCellProtection(ProtectedAndFormulaHidden);
735     }
736     // Alignment
737     const QString verticalAlign(styleStack.property(KoXmlNS::style, "vertical-align"));
738     if (!verticalAlign.isEmpty()) {
739         if (verticalAlign == "automatic")
740             setAlignment((Qt::AlignmentFlag) 0);
741         else
742             setAlignment(KoText::valignmentFromString(verticalAlign));
743     }
744 
745     if (styleStack.hasProperty(KoXmlNS::style, "writing-mode"))
746         setTextDirection(KoText::directionFromString(styleStack.property(KoXmlNS::style, "writing-mode")));
747 }
748 
copyProperties(const KoTableCellStyle * style)749 void KoTableCellStyle::copyProperties(const KoTableCellStyle *style)
750 {
751     Q_D(KoTableCellStyle);
752     const KoTableCellStylePrivate *styleD = static_cast<const KoTableCellStylePrivate*>(style->d_func());
753 
754     d->stylesPrivate = styleD->stylesPrivate;
755     setName(style->name()); // make sure we emit property change
756     d->next = styleD->next;
757     d->parentStyle = styleD->parentStyle;
758 }
759 
clone(QObject * parent)760 KoTableCellStyle *KoTableCellStyle::clone(QObject *parent)
761 {
762     KoTableCellStyle *newStyle = new KoTableCellStyle(parent);
763     newStyle->copyProperties(this);
764     return newStyle;
765 }
766 
767 
operator ==(const KoTableCellStyle & other) const768 bool KoTableCellStyle::operator==(const KoTableCellStyle &other) const
769 {
770     Q_D(const KoTableCellStyle);
771     const KoTableCellStylePrivate *otherD = static_cast<const KoTableCellStylePrivate*>(other.d_func());
772     return otherD->stylesPrivate == d->stylesPrivate;
773 }
774 
removeDuplicates(const KoTableCellStyle & other)775 void KoTableCellStyle::removeDuplicates(const KoTableCellStyle &other)
776 {
777     Q_D(KoTableCellStyle);
778     const KoTableCellStylePrivate *otherD = static_cast<const KoTableCellStylePrivate*>(other.d_func());
779     d->stylesPrivate.removeDuplicates(otherD->stylesPrivate);
780 }
781 
saveOdf(KoGenStyle & style,KoShapeSavingContext & context)782 void KoTableCellStyle::saveOdf(KoGenStyle &style, KoShapeSavingContext &context)
783 {
784     Q_D(KoTableCellStyle);
785     QList<int> keys = d->stylesPrivate.keys();
786     bool donePadding = false;
787     if (hasProperty(QTextFormat::TableCellLeftPadding) &&
788             hasProperty(QTextFormat::TableCellRightPadding) &&
789             hasProperty(QTextFormat::TableCellTopPadding) &&
790             hasProperty(QTextFormat::TableCellBottomPadding) &&
791             leftPadding() == rightPadding() &&
792             topPadding() == bottomPadding() &&
793             topPadding() == leftPadding()) {
794         donePadding = true;
795         style.addPropertyPt("fo:padding", leftPadding(), KoGenStyle::TableCellType);
796     }
797     foreach(int key, keys) {
798         if (key == CellBackgroundBrush) {
799             QBrush backBrush = background();
800             if (backBrush.style() != Qt::NoBrush)
801                 style.addProperty("fo:background-color", backBrush.color().name(), KoGenStyle::TableCellType);
802             else
803                 style.addProperty("fo:background-color", "transparent", KoGenStyle::TableCellType);
804         } else if (key == VerticalAlignment) {
805             if (propertyInt(VerticalAlignment) == 0)
806                 style.addProperty("style:vertical-align", "automatic", KoGenStyle::TableCellType);
807             else
808                 style.addProperty("style:vertical-align", KoText::valignmentToString(alignment()), KoGenStyle::TableCellType);
809         } else if ((key == QTextFormat::TableCellLeftPadding) && (!donePadding)) {
810             style.addPropertyPt("fo:padding-left", leftPadding(), KoGenStyle::TableCellType);
811         } else if ((key == QTextFormat::TableCellRightPadding) && (!donePadding)) {
812             style.addPropertyPt("fo:padding-right", rightPadding(), KoGenStyle::TableCellType);
813         } else if ((key == QTextFormat::TableCellTopPadding) && (!donePadding)) {
814             style.addPropertyPt("fo:padding-top", topPadding(), KoGenStyle::TableCellType);
815         } else if ((key == QTextFormat::TableCellBottomPadding) && (!donePadding)) {
816             style.addPropertyPt("fo:padding-bottom", bottomPadding(), KoGenStyle::TableCellType);
817         } else if (key == ShrinkToFit) {
818             style.addProperty("style:shrink-to-fit", shrinkToFit(), KoGenStyle::TableCellType);
819         } else if (key == PrintContent) {
820             style.addProperty("style:print-content", printContent(), KoGenStyle::TableCellType);
821         } else if (key == RepeatContent) {
822             style.addProperty("style:repeat-content", repeatContent(), KoGenStyle::TableCellType);
823         } else if (key == DecimalPlaces) {
824             style.addProperty("style:decimal-places", decimalPlaces(), KoGenStyle::TableCellType);
825         } else if (key == RotationAngle) {
826             style.addProperty("style:rotation-angle", QString::number(rotationAngle()), KoGenStyle::TableCellType);
827         } else if (key == Wrap) {
828             if (wrap())
829                 style.addProperty("fo:wrap-option", "wrap", KoGenStyle::TableCellType);
830             else
831                 style.addProperty("fo:wrap-option", "no-wrap", KoGenStyle::TableCellType);
832         } else if (key == Direction) {
833             if (direction() == LeftToRight)
834                 style.addProperty("style:direction", "ltr", KoGenStyle::TableCellType);
835             else if (direction() == TopToBottom)
836                 style.addProperty("style:direction", "ttb", KoGenStyle::TableCellType);
837         } else if (key == CellProtection) {
838             if (cellProtection() == NoProtection)
839                 style.addProperty("style:cell-protect", "none", KoGenStyle::TableCellType);
840             else if (cellProtection() == HiddenAndProtected)
841                 style.addProperty("style:cell-protect", "hidden-and-protected", KoGenStyle::TableCellType);
842             else if (cellProtection() == Protected)
843                 style.addProperty("style:cell-protect", "protected", KoGenStyle::TableCellType);
844             else if (cellProtection() == FormulaHidden)
845                 style.addProperty("style:cell-protect", "formula-hidden", KoGenStyle::TableCellType);
846             else if (cellProtection() == ProtectedAndFormulaHidden)
847                 style.addProperty("style:cell-protect", "protected formula-hidden", KoGenStyle::TableCellType);
848         } else if (key == AlignFromType) {
849             if (alignFromType())
850                 style.addProperty("style:text-align-source", "value-type", KoGenStyle::TableCellType);
851             else
852                 style.addProperty("style:text-align-source", "fix", KoGenStyle::TableCellType);
853         } else if (key == RotationAlign) {
854             style.addProperty("style:rotation-align", rotationAlignmentToString(rotationAlignment()), KoGenStyle::TableCellType);
855         } else if (key == TextWritingMode) {
856             style.addProperty("style:writing-mode", KoText::directionToString(textDirection()), KoGenStyle::TableCellType);
857         } else if (key == VerticalGlyphOrientation) {
858             if (verticalGlyphOrientation())
859                 style.addProperty("style:glyph-orientation-vertical", "auto", KoGenStyle::TableCellType);
860             else
861                 style.addProperty("style:glyph-orientation-vertical", "0", KoGenStyle::TableCellType);
862         } else if (key == Borders) {
863             borders().saveOdf(style, KoGenStyle::TableCellType);
864         } else if (key == Shadow) {
865             style.addProperty("style:shadow", shadow().saveOdf());
866         }
867     }
868     if (d->paragraphStyle) {
869         d->paragraphStyle->saveOdf(style, context);
870     }
871 
872 }
873 
setEdge(KoBorder::BorderSide side,KoBorder::BorderStyle style,qreal width,const QColor & color)874 void KoTableCellStyle::setEdge(KoBorder::BorderSide side, KoBorder::BorderStyle style,
875                                qreal width, const QColor &color)
876 {
877     KoBorder::BorderData edge;
878     qreal innerWidth = 0;
879     qreal middleWidth = 0;
880     qreal space = 0;
881     QVector<qreal> dashes;
882     switch (style) {
883     case KoBorder::BorderNone:
884         width = 0.0;
885         break;
886     case KoBorder::BorderDouble:
887         innerWidth = space = width/3; //some nice default look
888         width -= (space + innerWidth);
889         edge.outerPen.setStyle(Qt::SolidLine);
890         break;
891     case KoBorder::BorderDotted:
892         dashes << 1 << 1;
893         edge.outerPen.setDashPattern(dashes);
894         break;
895     case KoBorder::BorderDashed:
896         dashes << 4 << 1;
897         edge.outerPen.setDashPattern(dashes);
898         break;
899     case KoBorder::BorderDashedLong: {
900         dashes << 4 << 4;
901         edge.outerPen.setDashPattern(dashes);
902         break;
903     }
904     case KoBorder::BorderTriple:
905         innerWidth = middleWidth = space = width/6;
906         width -= (space + innerWidth);
907         edge.outerPen.setStyle(Qt::SolidLine);
908         break;
909     case KoBorder::BorderDashDot:
910         dashes << 3 << 3<< 7 << 3;
911         edge.outerPen.setDashPattern(dashes);
912         break;
913     case KoBorder::BorderDashDotDot:
914         dashes << 2 << 2<< 6 << 2 << 2 << 2;
915         edge.outerPen.setDashPattern(dashes);
916         break;
917     case KoBorder::BorderWave:
918         edge.outerPen.setStyle(Qt::SolidLine);
919         break;
920     case KoBorder::BorderSlash:
921         edge.outerPen.setStyle(Qt::SolidLine);
922         break;
923     case KoBorder::BorderDoubleWave:
924         innerWidth = space = width/3; //some nice default look
925         width -= (space + innerWidth);
926         edge.outerPen.setStyle(Qt::SolidLine);
927         break;
928     default:
929         edge.outerPen.setStyle(Qt::SolidLine);
930         break;
931     }
932     edge.outerPen.setColor(color);
933     edge.outerPen.setJoinStyle(Qt::MiterJoin);
934     edge.outerPen.setCapStyle(Qt::FlatCap);
935     edge.outerPen.setWidthF(width);
936 
937     edge.spacing = space;
938     edge.innerPen = edge.outerPen;
939     edge.innerPen.setWidthF(innerWidth);
940     QPen middlePen;
941     middlePen = edge.outerPen;
942     middlePen.setWidthF(middleWidth);
943 
944     setEdge(side, edge, style);
945 }
946 
setEdge(KoBorder::BorderSide side,const KoBorder::BorderData & edge,KoBorder::BorderStyle style)947 void KoTableCellStyle::setEdge(KoBorder::BorderSide side, const KoBorder::BorderData &edge, KoBorder::BorderStyle style)
948 {
949     KoBorder borders = this->borders();
950     KoBorder::BorderData edgeCopy(edge);
951     edgeCopy.style = style;                 // Just for safety.
952     borders.setBorderData(side, edgeCopy);
953     setBorders(borders);
954 }
955 
setEdgeDoubleBorderValues(KoBorder::BorderSide side,qreal innerWidth,qreal space)956 void KoTableCellStyle::setEdgeDoubleBorderValues(KoBorder::BorderSide side, qreal innerWidth, qreal space)
957 {
958     KoBorder::BorderData edge = getEdge(side);
959 
960     qreal totalWidth = edge.outerPen.widthF() + edge.spacing + edge.innerPen.widthF();
961     if (edge.innerPen.widthF() > 0.0) {
962         edge.outerPen.setWidthF(totalWidth - innerWidth - space);
963         edge.spacing = space;
964         edge.innerPen.setWidthF(innerWidth);
965         setEdge(side, edge, getBorderStyle(side));
966     }
967 }
968 
hasBorders() const969 bool KoTableCellStyle::hasBorders() const
970 {
971     return borders().hasBorder();
972 }
973 
leftBorderWidth() const974 qreal KoTableCellStyle::leftBorderWidth() const
975 {
976     const KoBorder::BorderData &edge = getEdge(KoBorder::LeftBorder);
977     return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
978 }
979 
rightBorderWidth() const980 qreal KoTableCellStyle::rightBorderWidth() const
981 {
982     const KoBorder::BorderData &edge = getEdge(KoBorder::RightBorder);
983     return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
984 }
985 
topBorderWidth() const986 qreal KoTableCellStyle::topBorderWidth() const
987 {
988     const KoBorder::BorderData &edge = getEdge(KoBorder::TopBorder);
989     return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
990 }
991 
bottomBorderWidth() const992 qreal KoTableCellStyle::bottomBorderWidth() const
993 {
994     const KoBorder::BorderData &edge = getEdge(KoBorder::BottomBorder);
995     return edge.spacing + edge.innerPen.widthF() + edge.outerPen.widthF();
996 }
997 
leftInnerBorderWidth() const998 qreal KoTableCellStyle::leftInnerBorderWidth() const
999 {
1000     const KoBorder::BorderData &edge = getEdge(KoBorder::LeftBorder);
1001     return edge.innerPen.widthF();
1002 }
1003 
rightInnerBorderWidth() const1004 qreal KoTableCellStyle::rightInnerBorderWidth() const
1005 {
1006     const KoBorder::BorderData &edge = getEdge(KoBorder::RightBorder);
1007     return edge.innerPen.widthF();
1008 }
1009 
topInnerBorderWidth() const1010 qreal KoTableCellStyle::topInnerBorderWidth() const
1011 {
1012     const KoBorder::BorderData &edge = getEdge(KoBorder::TopBorder);
1013     return edge.innerPen.widthF();
1014 }
1015 
bottomInnerBorderWidth() const1016 qreal KoTableCellStyle::bottomInnerBorderWidth() const
1017 {
1018     const KoBorder::BorderData &edge = getEdge(KoBorder::BottomBorder);
1019     return edge.innerPen.widthF();
1020 }
1021 
leftOuterBorderWidth() const1022 qreal KoTableCellStyle::leftOuterBorderWidth() const
1023 {
1024     const KoBorder::BorderData &edge = getEdge(KoBorder::LeftBorder);
1025     return edge.outerPen.widthF();
1026 }
1027 
rightOuterBorderWidth() const1028 qreal KoTableCellStyle::rightOuterBorderWidth() const
1029 {
1030     const KoBorder::BorderData &edge = getEdge(KoBorder::RightBorder);
1031     return edge.outerPen.widthF();
1032 }
1033 
topOuterBorderWidth() const1034 qreal KoTableCellStyle::topOuterBorderWidth() const
1035 {
1036     const KoBorder::BorderData &edge = getEdge(KoBorder::TopBorder);
1037     return edge.outerPen.widthF();
1038 }
1039 
bottomOuterBorderWidth() const1040 qreal KoTableCellStyle::bottomOuterBorderWidth() const
1041 {
1042     const KoBorder::BorderData &edge = getEdge(KoBorder::BottomBorder);
1043     return edge.outerPen.widthF();
1044 }
1045 
getEdge(KoBorder::BorderSide side) const1046 KoBorder::BorderData KoTableCellStyle::getEdge(KoBorder::BorderSide side) const
1047 {
1048     KoBorder border = this->borders();
1049     return border.borderData(side);
1050 }
1051 
getBorderStyle(KoBorder::BorderSide side) const1052 KoBorder::BorderStyle KoTableCellStyle::getBorderStyle(KoBorder::BorderSide side) const
1053 {
1054     KoBorder::BorderData edge = getEdge(side);
1055     return edge.style;
1056 }
1057