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