1 /* This file is part of the KDE project
2  *
3  * Copyright (C) 2009 Inge Wallin <inge@lysator.liu.se>
4  * Copyright (C) 2009 Thomas Zander <zander@kde.org>
5  * Copyright (C) 2011 Pierre Ducroquet <pinaraf@pinaraf.info>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 // clazy:excludeall=qstring-arg
24 #include "KoBorder.h"
25 
26 #include <QPainter>
27 
28 #include <OdfDebug.h>
29 
30 #include <KoUnit.h>
31 #include <KoXmlNS.h>
32 #include <KoXmlReader.h>
33 #include <KoStyleStack.h>
34 
35 
36 class KoBorderPrivate : public QSharedData
37 {
38 public:
39     KoBorderPrivate();
40     ~KoBorderPrivate();
41 
42     QMap<KoBorder::BorderSide, KoBorder::BorderData> data;
43 };
44 
KoBorderPrivate()45 KoBorderPrivate::KoBorderPrivate()
46 {
47 }
48 
~KoBorderPrivate()49 KoBorderPrivate::~KoBorderPrivate()
50 {
51 }
52 
BorderData()53 KoBorder::BorderData::BorderData()
54     : style(KoBorder::BorderNone)
55     , outerPen(QPen())
56     , innerPen(QPen())
57     , spacing(0)
58 {
59     outerPen.setWidthF(0.0f);
60     innerPen.setWidthF(0.0f);
61 }
62 
operator ==(const KoBorder::BorderData & other) const63 bool KoBorder::BorderData::operator==(const KoBorder::BorderData& other) const
64 {
65     // Left Borders
66     if (style == BorderNone && other.style == BorderNone) {
67         // If both styles are None, then the rest of the values don't
68         // need to be compared.
69         ;
70     }
71     else if (style != other.style) {
72         // If any of them are non-None, and they are different, the
73         // borders are also different.
74         return false;
75     }
76     else {
77         // Here we know that the border styles are the same, now
78         // compare the rest of the values.
79         if (outerPen != other.outerPen)
80             return false;
81 
82         // If the border style == BorderDouble, then compare a couple
83         // of other values too.
84         if (style == BorderDouble) {
85             if (innerPen != other.innerPen)
86                 return false;
87             if (spacing != other.spacing)
88                 return false;
89         }
90     }
91 
92     return true;
93 }
94 
95 // ----------------------------------------------------------------
96 
KoBorder()97 KoBorder::KoBorder()
98     : d(new KoBorderPrivate)
99 {
100 }
101 
KoBorder(const KoBorder & kb)102 KoBorder::KoBorder(const KoBorder &kb)
103     : d(kb.d)
104 {
105 }
106 
~KoBorder()107 KoBorder::~KoBorder()
108 {
109     // No delete because d is a QSharedDataPointer.
110 }
111 
112 
113 // ----------------------------------------------------------------
114 //                             operators
115 
operator =(const KoBorder & other)116 KoBorder &KoBorder::operator=(const KoBorder &other)
117 {
118     d = other.d;
119 
120     return *this;
121 }
122 
operator ==(const KoBorder & other) const123 bool KoBorder::operator==(const KoBorder &other) const
124 {
125     if (d.data() == other.d.data())
126         return true;
127 
128 
129     if (d->data.size() != other.d->data.size())
130         return false;
131 
132     for (auto i = d->data.constBegin(); i != d->data.constEnd(); ++i) {
133         if (!other.d->data.contains(i.key()))
134             return false;
135         if (!(other.d->data[i.key()] == i.value()))
136             return false;
137     }
138 
139     return true;
140 }
141 
142 
143 // ----------------------------------------------------------------
144 //                 public, non-class functions
145 
odfBorderStyle(const QString & borderstyle,bool * converted)146 KoBorder::BorderStyle KoBorder::odfBorderStyle(const QString &borderstyle, bool *converted)
147 {
148     // Note: the styles marked "Not odf compatible" below are legacies
149     //       from the old words format.  There are also lots of border
150     //       styles in the MS DOC that we may have to handle at some point.
151     if (converted)
152         *converted = true;
153     if (borderstyle == "none")
154         return BorderNone;
155     if (borderstyle == "solid")
156         return BorderSolid;
157     if (borderstyle == "dashed")
158         return BorderDashed;
159     if (borderstyle == "dotted")
160         return BorderDotted;
161     if (borderstyle == "dot-dash")
162         return BorderDashDot;
163     if (borderstyle == "dot-dot-dash")
164         return BorderDashDotDot;
165     if (borderstyle == "double")
166         return BorderDouble;
167     if (borderstyle == "groove")   // Not odf compatible -- see above
168         return BorderGroove;
169     if (borderstyle == "ridge")   // Not odf compatible -- see above
170         return BorderRidge;
171     if (borderstyle == "inset")   // Not odf compatible -- see above
172         return BorderInset;
173     if (borderstyle == "outset")   // Not odf compatible -- see above
174         return BorderOutset;
175     if (borderstyle == "dash-largegap")
176         return KoBorder::BorderDashedLong;
177     if (borderstyle == "slash") // not officially odf, but we support it anyway
178         return KoBorder::BorderSlash;
179     if (borderstyle == "wave") // not officially odf, but we support it anyway
180         return KoBorder::BorderWave;
181     if (borderstyle == "double-wave") // not officially odf, but we support it anyway
182         return KoBorder::BorderDoubleWave;
183 
184     if (converted)
185         *converted = false;
186 
187     return BorderSolid;
188 }
189 
odfBorderStyleString(BorderStyle borderstyle)190 QString KoBorder::odfBorderStyleString(BorderStyle borderstyle)
191 {
192     switch (borderstyle) {
193     case BorderDashed:
194         return QString("dashed");
195     case BorderDotted:
196         return QString("dotted");
197     case BorderDashDot:
198         return QString("dot-dash");
199     case BorderDashDotDot:
200         return QString("dot-dot-dash");
201     case BorderDouble:
202         return QString("double");
203     case BorderGroove:
204         return QString("groove"); // not odf -- see above
205     case BorderRidge:
206         return QString("ridge"); // not odf -- see above
207     case BorderInset:
208         return QString("inset"); // not odf -- see above
209     case BorderOutset:
210         return QString("outset"); // not odf -- see above
211     case BorderSolid:
212         return QString("solid");
213     case BorderNone:
214         return QString("none");
215 
216     default:
217         // Handle unknown types as solid.
218         return QString("solid");
219     }
220 }
221 
msoBorderStyleString(BorderStyle borderstyle)222 QString KoBorder::msoBorderStyleString(BorderStyle borderstyle)
223 {
224     switch (borderstyle) {
225     case KoBorder::BorderDashedLong:
226         return QString("dash-largegap");
227     case KoBorder::BorderSlash:
228         return QString("slash"); // not officially odf, but we support it anyway
229     case KoBorder::BorderWave:
230         return QString("wave"); // not officially odf, but we support it anyway
231     case KoBorder::BorderDoubleWave:
232         return QString("double-wave"); // not officially odf, but we support it anyway
233 
234     default:
235         // Handle remaining styles as odf type style.
236         return odfBorderStyleString(borderstyle);
237     }
238 }
239 
240 
241 // ----------------------------------------------------------------
242 //                         Getters and Setters
243 
244 
setBorderStyle(BorderSide side,BorderStyle style)245 void KoBorder::setBorderStyle(BorderSide side, BorderStyle style)
246 {
247     if (d->data[side].style == style) {
248         return;
249     }
250 
251     if (!d->data.contains(side)) {
252         BorderData data;
253         data.style = style;
254         d->data[side] = data;
255     } else {
256         d->data[side].style = style;
257     }
258 
259     // Make a best effort to create the best possible dash pattern for the chosen style.
260     // FIXME: KoTableCellStyle::setEdge() should call this function.
261     BorderData &edge = d->data[side];
262     qreal width = edge.outerPen.widthF();
263     qreal innerWidth = 0;
264     qreal middleWidth = 0;
265     qreal space = 0;
266     QVector<qreal> dashes;
267     switch (style) {
268     case KoBorder::BorderNone:
269         width = 0.0;
270         break;
271     case KoBorder::BorderDouble:
272         innerWidth = space = edge.outerPen.width() / 3; //some nice default look
273         width -= (space + innerWidth);
274         edge.outerPen.setStyle(Qt::SolidLine);
275         break;
276     case KoBorder::BorderDotted:
277         dashes << 1 << 1;
278         edge.outerPen.setDashPattern(dashes);
279         break;
280     case KoBorder::BorderDashed:
281         dashes << 4 << 1;
282         edge.outerPen.setDashPattern(dashes);
283         break;
284     case KoBorder::BorderDashedLong: {
285         dashes << 4 << 4;
286         edge.outerPen.setDashPattern(dashes);
287         break;
288     }
289     case KoBorder::BorderTriple:
290         innerWidth = middleWidth = space = width/6;
291         width -= (space + innerWidth);
292         edge.outerPen.setStyle(Qt::SolidLine);
293         break;
294     case KoBorder::BorderDashDot:
295         dashes << 3 << 3<< 7 << 3;
296         edge.outerPen.setDashPattern(dashes);
297         break;
298     case KoBorder::BorderDashDotDot:
299         dashes << 2 << 2<< 6 << 2 << 2 << 2;
300         edge.outerPen.setDashPattern(dashes);
301         break;
302     case KoBorder::BorderWave:
303         edge.outerPen.setStyle(Qt::SolidLine);
304         break;
305     case KoBorder::BorderSlash:
306         edge.outerPen.setStyle(Qt::SolidLine);
307         break;
308     case KoBorder::BorderDoubleWave:
309         innerWidth = space = width/3; //some nice default look
310         width -= (space + innerWidth);
311         edge.outerPen.setStyle(Qt::SolidLine);
312         break;
313     default:
314         edge.outerPen.setStyle(Qt::SolidLine);
315         break;
316     }
317     edge.outerPen.setJoinStyle(Qt::MiterJoin);
318     edge.outerPen.setCapStyle(Qt::FlatCap);
319     edge.outerPen.setWidthF(width);
320 
321     edge.spacing = space;
322     edge.innerPen = edge.outerPen;
323     edge.innerPen.setWidthF(innerWidth);
324 }
325 
borderStyle(BorderSide side) const326 KoBorder::BorderStyle KoBorder::borderStyle(BorderSide side) const
327 {
328     if (!d->data.contains(side)) {
329         return BorderNone;
330     } else {
331         return d->data[side].style;
332     }
333 }
334 
setBorderColor(BorderSide side,const QColor & color)335 void KoBorder::setBorderColor(BorderSide side, const QColor &color)
336 {
337     if (!d->data.contains(side)) {
338         BorderData data;
339         data.outerPen.setColor(color);
340         d->data[side] = data;
341     } else {
342         d->data[side].outerPen.setColor(color);
343     }
344 }
345 
borderColor(BorderSide side) const346 QColor KoBorder::borderColor(BorderSide side) const
347 {
348     if (!d->data.contains(side)) {
349         return QColor();
350     } else {
351         return d->data[side].outerPen.color();
352     }
353 }
354 
setBorderWidth(BorderSide side,qreal width)355 void KoBorder::setBorderWidth(BorderSide side, qreal width)
356 {
357     if (!d->data.contains(side)) {
358         BorderData data;
359         data.outerPen.setWidthF(width);
360         d->data[side] = data;
361     } else {
362         d->data[side].outerPen.setWidthF(width);
363     }
364 }
365 
borderWidth(BorderSide side) const366 qreal KoBorder::borderWidth(BorderSide side) const
367 {
368     if (!d->data.contains(side)) {
369         return 0;
370     } else {
371         if (d->data[side].style == BorderDouble)
372             return (d->data[side].outerPen.widthF() + d->data[side].innerPen.widthF()
373                     + d->data[side].spacing);
374         else
375             return d->data[side].outerPen.widthF();
376     }
377 }
378 
setOuterBorderWidth(BorderSide side,qreal width)379 void KoBorder::setOuterBorderWidth(BorderSide side, qreal width)
380 {
381     if (!d->data.contains(side)) {
382         BorderData data;
383         data.outerPen.setWidthF(width);
384         d->data[side] = data;
385     } else {
386         d->data[side].outerPen.setWidthF(width);
387     }
388 }
389 
outerBorderWidth(BorderSide side) const390 qreal KoBorder::outerBorderWidth(BorderSide side) const
391 {
392     if (!d->data.contains(side)) {
393         return 0;
394     } else {
395         return d->data[side].outerPen.widthF();
396     }
397 }
398 
setInnerBorderWidth(BorderSide side,qreal width)399 void KoBorder::setInnerBorderWidth(BorderSide side, qreal width)
400 {
401     if (!d->data.contains(side)) {
402         BorderData data;
403         data.innerPen.setWidthF(width);
404         d->data[side] = data;
405     } else {
406         d->data[side].innerPen.setWidthF(width);
407     }
408 }
409 
innerBorderWidth(BorderSide side) const410 qreal KoBorder::innerBorderWidth(BorderSide side) const
411 {
412     if (!d->data.contains(side)) {
413         return 0;
414     } else {
415         return d->data[side].innerPen.widthF();
416     }
417 }
418 
setBorderSpacing(BorderSide side,qreal width)419 void KoBorder::setBorderSpacing(BorderSide side, qreal width)
420 {
421     if (!d->data.contains(side)) {
422         BorderData data;
423         data.spacing = width;
424         d->data[side] = data;
425     } else {
426         d->data[side].spacing = width;
427     }
428 }
429 
borderSpacing(BorderSide side) const430 qreal KoBorder::borderSpacing(BorderSide side) const
431 {
432     if (!d->data.contains(side)) {
433         return 0;
434     } else {
435         return d->data[side].spacing;
436     }
437 }
438 
439 
borderData(BorderSide side) const440 KoBorder::BorderData KoBorder::borderData(BorderSide side) const
441 {
442     return d->data.value(side, BorderData());
443 }
444 
setBorderData(BorderSide side,const BorderData & data)445 void KoBorder::setBorderData(BorderSide side, const BorderData &data)
446 {
447     d->data[side] = data;
448 }
449 
450 
451 // -------------------------------
452 
hasBorder() const453 bool KoBorder::hasBorder() const
454 {
455     if (borderStyle(LeftBorder) != BorderNone && borderWidth(LeftBorder) > 0.0)
456         return true;
457     if (borderStyle(RightBorder) != BorderNone && borderWidth(RightBorder) > 0.0)
458         return true;
459     if (borderStyle(TopBorder) != BorderNone && borderWidth(TopBorder) > 0.0)
460         return true;
461     if (borderStyle(BottomBorder) != BorderNone && borderWidth(BottomBorder) > 0.0)
462         return true;
463     if (borderStyle(TlbrBorder) != BorderNone && borderWidth(TlbrBorder) > 0.0)
464         return true;
465     if (borderStyle(BltrBorder) != BorderNone && borderWidth(BltrBorder) > 0.0)
466         return true;
467     return false;
468 }
469 
hasBorder(KoBorder::BorderSide side) const470 bool KoBorder::hasBorder(KoBorder::BorderSide side) const
471 {
472     return borderStyle(side) != BorderNone && borderWidth(side) > 0.0;
473 }
474 
475 
476 // ----------------------------------------------------------------
477 //                         painting
478 
479 
paint(QPainter & painter,const QRectF & borderRect,BorderPaintArea whereToPaint) const480 void KoBorder::paint(QPainter &painter, const QRectF &borderRect,
481                      BorderPaintArea whereToPaint) const
482 {
483     Q_UNUSED(whereToPaint);
484     // In tables it is apparently best practice to paint the
485     // horizontal lines over the vertical ones.  So let's use the same
486     // strategy here.
487 
488     QPointF start;
489     QPointF end;
490 
491     // FIXME: Make KoBorder store pointers to BorderData instead.  This is very inefficient.
492     BorderData leftEdge = borderData(KoBorder::LeftBorder);
493     BorderData rightEdge = borderData(KoBorder::RightBorder);
494     BorderData topEdge = borderData(KoBorder::TopBorder);
495     BorderData bottomEdge = borderData(KoBorder::BottomBorder);
496 
497     // Left border
498     if (hasBorder(LeftBorder)) {
499         start = borderRect.topLeft();
500         end   = borderRect.bottomLeft();
501         paintBorderSide(painter, start, end, &leftEdge, true,
502                         hasBorder(TopBorder) ? &topEdge : 0,
503                         hasBorder(BottomBorder) ? &bottomEdge : 0,
504                         1);
505     }
506 
507     // Right border
508     if (hasBorder(RightBorder)) {
509         start = borderRect.topRight();
510         end   = borderRect.bottomRight();
511         paintBorderSide(painter, start, end, &rightEdge, true,
512                         hasBorder(TopBorder) ? &topEdge : 0,
513                         hasBorder(BottomBorder) ? &bottomEdge : 0,
514                         -1);
515     }
516 
517     // Top border
518     if (hasBorder(TopBorder)) {
519         start = borderRect.topLeft();
520         end   = borderRect.topRight();
521         paintBorderSide(painter, start, end, &topEdge, false,
522                         hasBorder(LeftBorder) ? &leftEdge : 0,
523                         hasBorder(RightBorder) ? &rightEdge : 0,
524                         1);
525     }
526 
527     // Bottom border
528     if (hasBorder(BottomBorder)) {
529         start = borderRect.bottomLeft();
530         end   = borderRect.bottomRight();
531         paintBorderSide(painter, start, end, &bottomEdge, false,
532                         hasBorder(LeftBorder) ? &leftEdge : 0,
533                         hasBorder(RightBorder) ? &rightEdge : 0,
534                         -1);
535     }
536 
537     // FIXME: Diagonal borders
538 }
539 
paintBorderSide(QPainter & painter,QPointF lineStart,QPointF lineEnd,BorderData * borderData,bool isVertical,BorderData * neighbour1,BorderData * neighbour2,int inwardsAcross) const540 void KoBorder::paintBorderSide(QPainter &painter, QPointF lineStart, QPointF lineEnd,
541                                BorderData *borderData, bool isVertical,
542                                BorderData *neighbour1, BorderData *neighbour2,
543                                int inwardsAcross) const
544 {
545     // Adjust the outer line so that it is inside the boundary.
546     qreal displacement = borderData->outerPen.widthF() / qreal(2.0);
547     if (isVertical) {
548         lineStart.setX(lineStart.x() + inwardsAcross * displacement);
549         lineEnd.setX(lineEnd.x() + inwardsAcross * displacement);
550     }
551     else {
552         lineStart.setY(lineStart.y() + inwardsAcross * displacement);
553         lineEnd.setY(lineEnd.y() + inwardsAcross * displacement);
554     }
555 
556     painter.setPen(borderData->outerPen);
557     painter.drawLine(lineStart, lineEnd);
558 
559     if (borderData->style == BorderDouble) {
560         displacement = (borderData->outerPen.widthF() / qreal(2.0)
561                         + borderData->spacing
562                         + borderData->innerPen.widthF() / qreal(2.0));
563         if (isVertical) {
564             lineStart.setX(lineStart.x() + inwardsAcross * displacement);
565             lineEnd.setX(lineEnd.x() + inwardsAcross * displacement);
566         }
567         else {
568             lineStart.setY(lineStart.y() + inwardsAcross * displacement);
569             lineEnd.setY(lineEnd.y() + inwardsAcross * displacement);
570         }
571 
572         // Adjust for neigboring inner lines.
573         if (neighbour1 && neighbour1->style == BorderDouble) {
574             displacement = neighbour1->outerPen.widthF() + neighbour1->spacing;
575             if (isVertical) {
576                 lineStart.setY(lineStart.y() + displacement);
577             }
578             else {
579                 lineStart.setX(lineStart.x() + displacement);
580             }
581         }
582         if (neighbour2 && neighbour2->style == BorderDouble) {
583             displacement = neighbour2->outerPen.widthF() + neighbour2->spacing;
584             if (isVertical) {
585                 lineEnd.setY(lineEnd.y() - displacement);
586             }
587             else {
588                 lineEnd.setX(lineEnd.x() - displacement);
589             }
590         }
591 
592         // Draw the inner line.
593         painter.setPen(borderData->innerPen);
594         painter.drawLine(lineStart, lineEnd);
595     }
596 }
597 
598 
599 // ----------------------------------------------------------------
600 //                         static functions
601 
602 
parseOdfBorder(const QString & border,QColor * color,KoBorder::BorderStyle * borderStyle,bool * hasBorderStyle,qreal * borderWidth,bool * hasBorderWidth)603 void parseOdfBorder(const QString &border, QColor *color,
604                     KoBorder::BorderStyle *borderStyle, bool *hasBorderStyle,
605                     qreal *borderWidth, bool *hasBorderWidth)
606 {
607     *hasBorderStyle = false;
608     *hasBorderWidth = false;
609 
610     if (!border.isEmpty() && border != "none" && border != "hidden") {
611         QStringList borderData = border.split(' ', QString::SkipEmptyParts);
612         if (borderData.length() > 0)
613         {
614             const QColor borderColor = QColor(borderData.last());
615             if (borderColor.isValid()) {
616                 *color = borderColor;
617                 borderData.removeLast();
618             }
619 
620             bool converted = false;
621             const KoBorder::BorderStyle parsedBorderStyle = KoBorder::odfBorderStyle(borderData.last(), &converted);
622             if (converted) {
623                 *hasBorderStyle = true;
624                 borderData.removeLast();
625                 *borderStyle = parsedBorderStyle;
626             }
627 
628             if (!borderData.isEmpty()) {
629                 const qreal parsedBorderWidth = KoUnit::parseValue(borderData[0], 1.0);
630                 *borderWidth = parsedBorderWidth;
631                 *hasBorderWidth = true;
632             }
633         }
634     }
635 }
636 
637 // ----------------------------------------------------------------
638 //                         load and save
639 
loadOdf(const KoXmlElement & style)640 bool KoBorder::loadOdf(const KoXmlElement &style)
641 {
642     bool result = false;
643 
644     QString borderString;
645     bool hasSpecialBorder;
646     QString specialBorderString;
647     if (style.hasAttributeNS(KoXmlNS::fo, "border")) {
648         borderString = style.attributeNS(KoXmlNS::fo, "border");
649         if (borderString == "none") {
650             // We use the "false" to indicate that there is no border
651             // rather than that the parsing has failed.
652             return false;
653         }
654 
655         result = true;
656         if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder"))) {
657             specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder");
658         }
659         parseAndSetBorder(borderString, hasSpecialBorder, specialBorderString);
660     }
661     else {
662         // No common border attributes, check for the individual ones.
663         if (style.hasAttributeNS(KoXmlNS::fo, "border-left")) {
664             result = true;
665             borderString = style.attributeNS(KoXmlNS::fo, "border-left");
666             if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-left"))) {
667                 specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-left");
668             }
669             parseAndSetBorder(LeftBorder, borderString, hasSpecialBorder, specialBorderString);
670         }
671         if (style.hasAttributeNS(KoXmlNS::fo, "border-top")) {
672             result = true;
673             borderString = style.attributeNS(KoXmlNS::fo, "border-top");
674             if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-top"))) {
675                 specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-top");
676             }
677             parseAndSetBorder(TopBorder, borderString, hasSpecialBorder, specialBorderString);
678         }
679         if (style.hasAttributeNS(KoXmlNS::fo, "border-right")) {
680             result = true;
681             borderString = style.attributeNS(KoXmlNS::fo, "border-right");
682             if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-right"))) {
683                 specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-right");
684             }
685             parseAndSetBorder(RightBorder, borderString, hasSpecialBorder, specialBorderString);
686         }
687         if (style.hasAttributeNS(KoXmlNS::fo, "border-bottom")) {
688             result = true;
689             borderString = style.attributeNS(KoXmlNS::fo, "border-bottom");
690             if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-bottom"))) {
691                 specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-bottom");
692             }
693             parseAndSetBorder(BottomBorder, borderString, hasSpecialBorder, specialBorderString);
694         }
695     }
696 
697     // Diagonals are treated individually and are NOT part of <style:border>.
698     if (style.hasAttributeNS(KoXmlNS::style, "diagonal-tl-br")) {
699         result = true;
700         borderString = style.attributeNS(KoXmlNS::fo, "border-tl-br");
701         if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-tl-br"))) {
702             specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-tl-br");
703         }
704         parseAndSetBorder(TlbrBorder, borderString, hasSpecialBorder, specialBorderString);
705     }
706     if (style.hasAttributeNS(KoXmlNS::style, "diagonal-bl-tr")) {
707         result = true;
708         borderString = style.attributeNS(KoXmlNS::fo, "border-bl-tr");
709         if ((hasSpecialBorder = style.hasAttributeNS(KoXmlNS::calligra, "specialborder-bl-tr"))) {
710             specialBorderString = style.attributeNS(KoXmlNS::calligra, "specialborder-bl-tr");
711         }
712         parseAndSetBorder(BltrBorder, borderString, hasSpecialBorder, specialBorderString);
713     }
714 
715     // Handle double borders.
716     if (style.hasAttributeNS(KoXmlNS::style, "border-line-width")) {
717         result = true;
718         QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width");
719         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
720             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
721             setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
722             setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
723             setOuterBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
724 
725             setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
726             setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
727             setOuterBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
728 
729             setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
730             setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
731             setOuterBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
732 
733             setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
734             setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
735             setOuterBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
736         }
737     }
738     else {
739         if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-left")) {
740             result = true;
741             QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-left");
742             if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
743                 QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
744                 setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
745                 setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
746                 setOuterBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
747             }
748         }
749         if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-top")) {
750             result = true;
751             QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-top");
752             if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
753                 QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
754                 setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
755                 setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
756                 setOuterBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
757             }
758         }
759         if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-right")) {
760             result = true;
761             QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-right");
762             if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
763                 QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
764                 setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
765                 setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
766                 setOuterBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
767             }
768         }
769         if (style.hasAttributeNS(KoXmlNS::style, "border-line-width-bottom")) {
770             result = true;
771             QString borderLineWidth = style.attributeNS(KoXmlNS::style, "border-line-width-bottom");
772             if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
773                 QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
774                 setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
775                 setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
776                 setOuterBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
777             }
778         }
779     }
780 
781     if (style.hasAttributeNS(KoXmlNS::style, "diagonal-tl-br-widths")) {
782         result = true;
783         QString borderLineWidth = style.attributeNS(KoXmlNS::style, "diagonal-tl-br-widths");
784         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
785             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
786             setInnerBorderWidth(TlbrBorder, KoUnit::parseValue(blw[0], 0.1));
787             setBorderSpacing(TlbrBorder, KoUnit::parseValue(blw[1], 1.0));
788             setOuterBorderWidth(TlbrBorder, KoUnit::parseValue(blw[2], 0.1));
789         }
790     }
791     if (style.hasAttributeNS(KoXmlNS::style, "diagonal-bl-tr-widths")) {
792         result = true;
793         QString borderLineWidth = style.attributeNS(KoXmlNS::style, "diagonal-bl-tr-widths");
794         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
795             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
796             setInnerBorderWidth(BltrBorder, KoUnit::parseValue(blw[0], 0.1));
797             setBorderSpacing(BltrBorder, KoUnit::parseValue(blw[1], 1.0));
798             setOuterBorderWidth(BltrBorder, KoUnit::parseValue(blw[2], 0.1));
799         }
800     }
801     return result;
802 }
803 
loadOdf(const KoStyleStack & styleStack)804 bool KoBorder::loadOdf(const KoStyleStack &styleStack)
805 {
806     bool result = false;
807 
808     QString borderString;
809     bool hasSpecialBorder;
810     QString specialBorderString;
811     if (styleStack.hasProperty(KoXmlNS::fo, "border")) {
812         result = true;
813         borderString = styleStack.property(KoXmlNS::fo, "border");
814         if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder"))) {
815             specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder");
816         }
817         parseAndSetBorder(borderString, hasSpecialBorder, specialBorderString);
818     }
819 
820     // Even if there are common border attributes, check for the
821     // individual ones since they have precedence.
822 
823     if (styleStack.hasProperty(KoXmlNS::fo, "border-left")) {
824         result = true;
825         borderString = styleStack.property(KoXmlNS::fo, "border-left");
826         if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-left"))) {
827             specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-left");
828         }
829         parseAndSetBorder(LeftBorder, borderString, hasSpecialBorder, specialBorderString);
830     }
831     if (styleStack.hasProperty(KoXmlNS::fo, "border-top")) {
832         result = true;
833         borderString = styleStack.property(KoXmlNS::fo, "border-top");
834         if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-top"))) {
835             specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-top");
836         }
837         parseAndSetBorder(TopBorder, borderString, hasSpecialBorder, specialBorderString);
838     }
839     if (styleStack.hasProperty(KoXmlNS::fo, "border-right")) {
840         result = true;
841         borderString = styleStack.property(KoXmlNS::fo, "border-right");
842         if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-right"))) {
843             specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-right");
844         }
845         parseAndSetBorder(RightBorder, borderString, hasSpecialBorder, specialBorderString);
846 
847     }
848     if (styleStack.hasProperty(KoXmlNS::fo, "border-bottom")) {
849         result = true;
850         borderString = styleStack.property(KoXmlNS::fo, "border-bottom");
851         if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-bottom"))) {
852             specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-bottom");
853         }
854         parseAndSetBorder(BottomBorder, borderString, hasSpecialBorder, specialBorderString);
855     }
856 
857     // Diagonals are treated individually and are NOT part of <style:border>.
858     if (styleStack.hasProperty(KoXmlNS::style, "diagonal-tl-br")) {
859         result = true;
860         borderString = styleStack.property(KoXmlNS::fo, "border-tl-br");
861         if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-tl-br"))) {
862             specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-tl-br");
863         }
864         parseAndSetBorder(TlbrBorder, borderString, hasSpecialBorder, specialBorderString);
865     }
866     if (styleStack.hasProperty(KoXmlNS::style, "diagonal-bl-tr")) {
867         result = true;
868         borderString = styleStack.property(KoXmlNS::fo, "border-bl-tr");
869         if ((hasSpecialBorder = styleStack.hasProperty(KoXmlNS::calligra, "specialborder-bl-tr"))) {
870             specialBorderString = styleStack.property(KoXmlNS::calligra, "specialborder-bl-tr");
871         }
872         parseAndSetBorder(BltrBorder, borderString, hasSpecialBorder, specialBorderString);
873     }
874 
875     // Handle double borders.
876     if (styleStack.hasProperty(KoXmlNS::style, "border-line-width")) {
877         result = true;
878         QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width");
879         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
880             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
881             setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
882             setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
883             setOuterBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
884 
885             setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
886             setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
887             setOuterBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
888 
889             setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
890             setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
891             setOuterBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
892 
893             setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
894             setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
895             setOuterBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
896         }
897     }
898     // Even if there are common border attributes, check for the
899     // individual ones since they have precedence.
900 
901     if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-left")) {
902         result = true;
903         QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-left");
904         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
905             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
906             setInnerBorderWidth(LeftBorder, KoUnit::parseValue(blw[0], 0.1));
907             setBorderSpacing(LeftBorder, KoUnit::parseValue(blw[1], 1.0));
908             setOuterBorderWidth(LeftBorder, KoUnit::parseValue(blw[2], 0.1));
909         }
910     }
911     if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-top")) {
912         result = true;
913         QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-top");
914         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
915             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
916             setInnerBorderWidth(TopBorder, KoUnit::parseValue(blw[0], 0.1));
917             setBorderSpacing(TopBorder, KoUnit::parseValue(blw[1], 1.0));
918             setOuterBorderWidth(TopBorder, KoUnit::parseValue(blw[2], 0.1));
919         }
920     }
921     if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-right")) {
922         result = true;
923         QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-right");
924         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
925             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
926             setInnerBorderWidth(RightBorder, KoUnit::parseValue(blw[0], 0.1));
927             setBorderSpacing(RightBorder, KoUnit::parseValue(blw[1], 1.0));
928             setOuterBorderWidth(RightBorder, KoUnit::parseValue(blw[2], 0.1));
929         }
930     }
931     if (styleStack.hasProperty(KoXmlNS::style, "border-line-width-bottom")) {
932         result = true;
933         QString borderLineWidth = styleStack.property(KoXmlNS::style, "border-line-width-bottom");
934         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
935             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
936             setInnerBorderWidth(BottomBorder, KoUnit::parseValue(blw[0], 0.1));
937             setBorderSpacing(BottomBorder, KoUnit::parseValue(blw[1], 1.0));
938             setOuterBorderWidth(BottomBorder, KoUnit::parseValue(blw[2], 0.1));
939         }
940     }
941 
942     // Diagonals are treated individually and are NOT part of <style:border>.
943     if (styleStack.hasProperty(KoXmlNS::style, "diagonal-tl-br-widths")) {
944         result = true;
945         QString borderLineWidth = styleStack.property(KoXmlNS::style, "diagonal-tl-br-widths");
946         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
947             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
948             setInnerBorderWidth(TlbrBorder, KoUnit::parseValue(blw[0], 0.1));
949             setBorderSpacing(TlbrBorder, KoUnit::parseValue(blw[1], 1.0));
950             setOuterBorderWidth(TlbrBorder, KoUnit::parseValue(blw[2], 0.1));
951         }
952     }
953     if (styleStack.hasProperty(KoXmlNS::style, "diagonal-bl-tr-widths")) {
954         result = true;
955         QString borderLineWidth = styleStack.property(KoXmlNS::style, "diagonal-bl-tr-widths");
956         if (!borderLineWidth.isEmpty() && borderLineWidth != "none" && borderLineWidth != "hidden") {
957             QStringList blw = borderLineWidth.split(' ', QString::SkipEmptyParts);
958             setInnerBorderWidth(BltrBorder, KoUnit::parseValue(blw[0], 0.1));
959             setBorderSpacing(BltrBorder, KoUnit::parseValue(blw[1], 1.0));
960             setOuterBorderWidth(BltrBorder, KoUnit::parseValue(blw[2], 0.1));
961         }
962     }
963 
964     return result;
965 }
966 
967 
968 // Private
parseAndSetBorder(const QString & borderString,bool hasSpecialBorder,const QString & specialBorderString)969 void KoBorder::parseAndSetBorder(const QString &borderString,
970                                  bool hasSpecialBorder, const QString &specialBorderString)
971 {
972     if (borderString == "none") {
973         return;
974     }
975 
976     //debugOdf << "*** *** Found border: " << border;
977     QColor bordersColor;
978     BorderStyle bordersStyle;
979     qreal bordersWidth;
980     bool foundStyle;
981     bool foundWidth;
982     parseOdfBorder(borderString, &bordersColor, &bordersStyle, &foundStyle,
983                    &bordersWidth, &foundWidth);
984     if (bordersColor.isValid()) {
985         setBorderColor(LeftBorder, bordersColor);
986         setBorderColor(TopBorder, bordersColor);
987         setBorderColor(RightBorder, bordersColor);
988         setBorderColor(BottomBorder, bordersColor);
989     }
990     if (hasSpecialBorder) {
991         bordersStyle = KoBorder::odfBorderStyle(specialBorderString, &foundStyle);
992     }
993 
994     if (foundStyle) {
995         setBorderStyle(LeftBorder, bordersStyle);
996         setBorderStyle(TopBorder, bordersStyle);
997         setBorderStyle(RightBorder, bordersStyle);
998         setBorderStyle(BottomBorder, bordersStyle);
999     }
1000     if (foundWidth) {
1001         setBorderWidth(LeftBorder, bordersWidth);
1002         setBorderWidth(TopBorder, bordersWidth);
1003         setBorderWidth(RightBorder, bordersWidth);
1004         setBorderWidth(BottomBorder, bordersWidth);
1005     }
1006 }
1007 
1008 // Private
parseAndSetBorder(const BorderSide borderSide,const QString & borderString,bool hasSpecialBorder,const QString & specialBorderString)1009 void KoBorder::parseAndSetBorder(const BorderSide borderSide, const QString &borderString,
1010                                  bool hasSpecialBorder, const QString &specialBorderString)
1011 {
1012     QColor borderColor;
1013     BorderStyle borderStyle;
1014     qreal borderWidth;
1015     bool foundStyle;
1016     bool foundWidth;
1017 
1018     parseOdfBorder(borderString, &borderColor, &borderStyle, &foundStyle,
1019                    &borderWidth, &foundWidth);
1020     if (borderColor.isValid()) {
1021         setBorderColor(borderSide, borderColor);
1022     }
1023     if (hasSpecialBorder) {
1024         borderStyle = KoBorder::odfBorderStyle(specialBorderString, &foundStyle);
1025     }
1026 
1027     if (foundStyle) {
1028         setBorderStyle(borderSide, borderStyle);
1029     }
1030     if (foundWidth) {
1031         setBorderWidth(borderSide, borderWidth);
1032     }
1033 }
1034 
saveOdf(KoGenStyle & style,KoGenStyle::PropertyType type) const1035 void KoBorder::saveOdf(KoGenStyle &style, KoGenStyle::PropertyType type) const
1036 {
1037     // Get the strings that describe respective borders.
1038     QString leftBorderString = QString("%1pt %2 %3")
1039                                  .arg(QString::number(borderWidth(LeftBorder)),
1040                                       odfBorderStyleString(borderStyle(LeftBorder)),
1041                                       borderColor(LeftBorder).name());
1042     QString rightBorderString =  QString("%1pt %2 %3")
1043                                   .arg(QString::number(borderWidth(RightBorder)),
1044                                        odfBorderStyleString(borderStyle(RightBorder)),
1045                                        borderColor(RightBorder).name());
1046     QString topBorderString = QString("%1pt %2 %3")
1047                                 .arg(QString::number(borderWidth(TopBorder)),
1048                                      odfBorderStyleString(borderStyle(TopBorder)),
1049                                      borderColor(TopBorder).name());
1050     QString bottomBorderString = QString("%1pt %2 %3")
1051                                    .arg(QString::number(borderWidth(BottomBorder)),
1052                                         odfBorderStyleString(borderStyle(BottomBorder)),
1053                                         borderColor(BottomBorder).name());
1054 
1055     QString tlbrBorderString = QString("%1pt %2 %3")
1056                                 .arg(QString::number(borderWidth(TlbrBorder)),
1057                                      odfBorderStyleString(borderStyle(TlbrBorder)),
1058                                      borderColor(TlbrBorder).name());
1059     QString trblBorderString = QString("%1pt %2 %3")
1060                                    .arg(QString::number(borderWidth(BltrBorder)),
1061                                         odfBorderStyleString(borderStyle(BltrBorder)),
1062                                         borderColor(BltrBorder).name());
1063 
1064     // Get the strings that describe respective special borders (for special mso support).
1065     QString leftBorderSpecialString = msoBorderStyleString(borderStyle(LeftBorder));
1066     QString rightBorderSpecialString = msoBorderStyleString(borderStyle(RightBorder));
1067     QString topBorderSpecialString = msoBorderStyleString(borderStyle(TopBorder));
1068     QString bottomBorderSpecialString = msoBorderStyleString(borderStyle(BottomBorder));
1069     //QString tlbrBorderSpecialString = msoBorderStyleString(borderStyle(TlbrBorder));
1070     //QString trblBorderSpecialString = msoBorderStyleString(borderStyle(BltrBorder));
1071 
1072     // Check if we can save all borders in one fo:border attribute, or
1073     // if we have to use several different ones like fo:border-left, etc.
1074     if (leftBorderString == rightBorderString
1075         && leftBorderString == topBorderString
1076         && leftBorderString == bottomBorderString) {
1077 
1078         // Yes, they were all the same, so use only fo:border
1079         style.addProperty("fo:border", leftBorderString, type);
1080         style.addProperty("calligra:specialborder-left", leftBorderSpecialString, type);
1081         style.addProperty("calligra:specialborder-right", rightBorderSpecialString, type);
1082         style.addProperty("calligra:specialborder-top", topBorderSpecialString, type);
1083         style.addProperty("calligra:specialborder-bottom", bottomBorderSpecialString, type);
1084     } else {
1085         // No, they were different, so use the individual borders.
1086         //if (leftBorderStyle() != BorderNone)
1087             style.addProperty("fo:border-left", leftBorderString, type);
1088             style.addProperty("calligra:specialborder-left", leftBorderSpecialString, type);
1089         //if (rightBorderStyle() != BorderNone)
1090             style.addProperty("fo:border-right", rightBorderString, type);
1091             style.addProperty("calligra:specialborder-right", rightBorderSpecialString, type);
1092         //if (topBorderStyle() != BorderNone)
1093             style.addProperty("fo:border-top", topBorderString, type);
1094             style.addProperty("calligra:specialborder-top", topBorderSpecialString, type);
1095         //if (bottomBorderStyle() != BorderNone)
1096             style.addProperty("fo:border-bottom", bottomBorderString, type);
1097             style.addProperty("calligra:specialborder-bottom", bottomBorderSpecialString, type);
1098     }
1099 
1100     if (style.type() != KoGenStyle::PageLayoutStyle) {
1101         //if (tlbrBorderStyle() != BorderNone) {
1102             style.addProperty("style:diagonal-tl-br", tlbrBorderString, type);
1103         //}
1104         //if (trblBorderStyle() != BorderNone) {
1105             style.addProperty("style:diagonal-bl-tr", trblBorderString, type);
1106         //}
1107     }
1108 
1109     // Handle double borders
1110     QString leftBorderLineWidth = QString("%1pt %2pt %3pt")
1111                                     .arg(QString::number(innerBorderWidth(LeftBorder)),
1112                                          QString::number(borderSpacing(LeftBorder)),
1113                                          QString::number(outerBorderWidth(LeftBorder)));
1114     QString rightBorderLineWidth = QString("%1pt %2pt %3pt")
1115                                      .arg(QString::number(innerBorderWidth(RightBorder)),
1116                                           QString::number(borderSpacing(RightBorder)),
1117                                           QString::number(outerBorderWidth(RightBorder)));
1118     QString topBorderLineWidth = QString("%1pt %2pt %3pt")
1119                                    .arg(QString::number(innerBorderWidth(TopBorder)),
1120                                         QString::number(borderSpacing(TopBorder)),
1121                                         QString::number(outerBorderWidth(TopBorder)));
1122     QString bottomBorderLineWidth = QString("%1pt %2pt %3pt")
1123                                       .arg(QString::number(innerBorderWidth(BottomBorder)),
1124                                            QString::number(borderSpacing(BottomBorder)),
1125                                            QString::number(outerBorderWidth(BottomBorder)));
1126 
1127     QString tlbrBorderLineWidth = QString("%1pt %2pt %3pt")
1128                                    .arg(QString::number(innerBorderWidth(TlbrBorder)),
1129                                         QString::number(borderSpacing(TlbrBorder)),
1130                                         QString::number(outerBorderWidth(TlbrBorder)));
1131     QString trblBorderLineWidth = QString("%1pt %2pt %3pt")
1132                                       .arg(QString::number(innerBorderWidth(BltrBorder)),
1133                                            QString::number(borderSpacing(BltrBorder)),
1134                                            QString::number(outerBorderWidth(BltrBorder)));
1135 
1136     if (leftBorderLineWidth == rightBorderLineWidth
1137         && leftBorderLineWidth == topBorderLineWidth
1138         && leftBorderLineWidth == bottomBorderLineWidth
1139         && borderStyle(LeftBorder) == borderStyle(RightBorder)
1140         && borderStyle(TopBorder) == borderStyle(BottomBorder)
1141         && borderStyle(TopBorder) == borderStyle(LeftBorder)
1142         && (borderStyle(LeftBorder) == BorderDouble || borderStyle(LeftBorder) == BorderDoubleWave)) {
1143         style.addProperty("style:border-line-width", leftBorderLineWidth, type);
1144     } else {
1145         if (borderStyle(LeftBorder) == BorderDouble || borderStyle(LeftBorder) == BorderDoubleWave)
1146             style.addProperty("style:border-line-width-left", leftBorderLineWidth, type);
1147         if (borderStyle(RightBorder) == BorderDouble || borderStyle(RightBorder) == BorderDoubleWave)
1148             style.addProperty("style:border-line-width-right", rightBorderLineWidth, type);
1149         if (borderStyle(TopBorder) == BorderDouble || borderStyle(TopBorder) == BorderDoubleWave)
1150             style.addProperty("style:border-line-width-top", topBorderLineWidth, type);
1151         if (borderStyle(BottomBorder) == BorderDouble || borderStyle(BottomBorder) == BorderDoubleWave)
1152             style.addProperty("style:border-line-width-bottom", bottomBorderLineWidth, type);
1153     }
1154 
1155     if (style.type() != KoGenStyle::PageLayoutStyle) {
1156         if (borderStyle(TlbrBorder) == BorderDouble || borderStyle(TlbrBorder) == BorderDoubleWave) {
1157             style.addProperty("style:diagonal-tl-br-widths", tlbrBorderLineWidth, type);
1158         }
1159         if (borderStyle(BltrBorder) == BorderDouble || borderStyle(BltrBorder) == BorderDoubleWave) {
1160             style.addProperty("style:diagonal-bl-tr-widths", trblBorderLineWidth, type);
1161         }
1162     }
1163 }
1164