Warning, file /office/calligra/libs/odf/KoColumns.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "KoColumns.h"
0021 
0022 #include "KoXmlWriter.h"
0023 #include "KoGenStyle.h"
0024 #include "KoXmlReader.h"
0025 #include "KoXmlNS.h"
0026 #include "KoUnit.h"
0027 #include "OdfDebug.h"
0028 
0029 static const int defaultColumnCount = 1;
0030 static const KoColumns::SeparatorStyle defaultSeparatorStyle = KoColumns::None;
0031 static const int defaultSeparatorHeight = 100;
0032 static const  Qt::GlobalColor defaultSeparatorColor = Qt::black;
0033 static const KoColumns::SeparatorVerticalAlignment defaultSeparatorVerticalAlignment = KoColumns::AlignTop;
0034 static const int defaultColumnGapWidth = 17; // in pt, ~ 6mm
0035 
0036 
0037 
0038 const char * KoColumns::separatorStyleString(KoColumns::SeparatorStyle separatorStyle)
0039 {
0040     const char * result;
0041 
0042     //  skip KoColumns::None, is default
0043     if (separatorStyle == Solid) {
0044         result = "solid";
0045     } else if (separatorStyle == Dotted) {
0046         result = "dotted";
0047     } else if (separatorStyle == Dashed) {
0048         result = "dashed";
0049     } else if (separatorStyle == DotDashed) {
0050         result = "dot-dashed";
0051     } else {
0052         result = "none";
0053     }
0054 
0055     return result;
0056 }
0057 
0058 const char * KoColumns::separatorVerticalAlignmentString(KoColumns::SeparatorVerticalAlignment separatorVerticalAlignment)
0059 {
0060     const char * result;
0061 
0062     //  skip KoColumns::AlignTop, is default
0063     if (separatorVerticalAlignment == AlignVCenter) {
0064         result = "middle";
0065     } else if (separatorVerticalAlignment == AlignBottom) {
0066         result = "bottom";
0067     } else {
0068         result = "top";
0069     }
0070 
0071     return result;
0072 }
0073 
0074 KoColumns::SeparatorVerticalAlignment KoColumns::parseSeparatorVerticalAlignment(const QString &value)
0075 {
0076     // default to AlignTop
0077     SeparatorVerticalAlignment result = defaultSeparatorVerticalAlignment;
0078 
0079     if (! value.isEmpty()) {
0080         // skip "top", is default
0081         if (value == QLatin1String("middle")) {
0082             result = AlignVCenter;
0083         } else if (value == QLatin1String("bottom")) {
0084             result = AlignBottom;
0085         }
0086     }
0087 
0088     return result;
0089 }
0090 
0091 QColor KoColumns::parseSeparatorColor(const QString &value)
0092 {
0093     QColor result(value);
0094 
0095     if (! result.isValid())
0096         // default is black, cmp. ODF 1.2 ยง19.467
0097         result = QColor(defaultSeparatorColor);
0098 
0099     return result;
0100 }
0101 
0102 // TODO: see if there is another parse method somewhere which can be used here
0103 int KoColumns::parseSeparatorHeight(const QString &value)
0104 {
0105     int result = defaultSeparatorHeight;
0106 
0107     // only try to convert if it ends with a %, so is also not empty
0108     if (value.endsWith(QLatin1Char('%'))) {
0109         bool ok = false;
0110         // try to convert
0111         result = value.leftRef(value.length()-1).toInt(&ok);
0112         // reset to 100% if conversion failed (which sets result to 0)
0113         if (! ok) {
0114             result = defaultSeparatorHeight;
0115         }
0116     }
0117 
0118     return result;
0119 }
0120 
0121 KoColumns::SeparatorStyle KoColumns::parseSeparatorStyle(const QString &value)
0122 {
0123     SeparatorStyle result = None;
0124     if (! value.isEmpty()) {
0125         //  skip "none", is default
0126         if (value == QLatin1String("solid")) {
0127             result = Solid;
0128         } else if (value == QLatin1String("dotted")) {
0129             result = Dotted;
0130         } else if (value == QLatin1String("dashed")) {
0131             result = Dashed;
0132         } else if (value == QLatin1String("dot-dashed")) {
0133             result = DotDashed;
0134         }
0135     }
0136 
0137     return result;
0138 }
0139 
0140 int KoColumns::parseRelativeWidth(const QString &value)
0141 {
0142     int result = 0;
0143 
0144     // only try to convert if it ends with a *, so is also not empty
0145     if (value.endsWith(QLatin1Char('*'))) {
0146         bool ok = false;
0147         // try to convert
0148         result = value.leftRef(value.length()-1).toInt(&ok);
0149         if (! ok) {
0150             result = 0;
0151         }
0152     }
0153 
0154     return result;
0155 }
0156 
0157 KoColumns::KoColumns()
0158   : count(defaultColumnCount)
0159   , gapWidth(defaultColumnGapWidth)
0160   , separatorStyle(defaultSeparatorStyle)
0161   , separatorColor(defaultSeparatorColor)
0162   , separatorVerticalAlignment(defaultSeparatorVerticalAlignment)
0163   , separatorHeight(defaultSeparatorHeight)
0164 {
0165 }
0166 
0167 void KoColumns::reset()
0168 {
0169     count = defaultColumnCount;
0170     gapWidth = defaultColumnGapWidth;
0171     separatorStyle = defaultSeparatorStyle;
0172     separatorColor = QColor(defaultSeparatorColor);
0173     separatorVerticalAlignment = defaultSeparatorVerticalAlignment;
0174     separatorHeight = defaultSeparatorHeight;
0175 }
0176 
0177 bool KoColumns::operator==(const KoColumns& rhs) const {
0178     return
0179         count == rhs.count &&
0180         (columnData.isEmpty() && rhs.columnData.isEmpty() ?
0181              (qAbs(gapWidth - rhs.gapWidth) <= 1E-10) :
0182              (columnData == rhs.columnData));
0183 }
0184 
0185 bool KoColumns::operator!=(const KoColumns& rhs) const {
0186     return
0187         count != rhs.count ||
0188         (columnData.isEmpty() && rhs.columnData.isEmpty() ?
0189              qAbs(gapWidth - rhs.gapWidth) > 1E-10 :
0190              ! (columnData == rhs.columnData));
0191 }
0192 
0193 void KoColumns::loadOdf(const KoXmlElement &style)
0194 {
0195     KoXmlElement columnsElement = KoXml::namedItemNS(style, KoXmlNS::style, "columns");
0196     if (!columnsElement.isNull()) {
0197         count = columnsElement.attributeNS(KoXmlNS::fo, "column-count").toInt();
0198         if (count < 1)
0199             count = 1;
0200         gapWidth = KoUnit::parseValue(columnsElement.attributeNS(KoXmlNS::fo, "column-gap"));
0201 
0202         KoXmlElement columnSep = KoXml::namedItemNS(columnsElement, KoXmlNS::style, "column-sep");
0203         if (! columnSep.isNull()) {
0204             separatorStyle = parseSeparatorStyle(columnSep.attributeNS(KoXmlNS::style, "style"));
0205             separatorWidth = KoUnit::parseValue(columnSep.attributeNS(KoXmlNS::style, "width"));
0206             separatorHeight = parseSeparatorHeight(columnSep.attributeNS(KoXmlNS::style, "height"));
0207             separatorColor = parseSeparatorColor(columnSep.attributeNS(KoXmlNS::style, "color"));
0208             separatorVerticalAlignment =
0209                 parseSeparatorVerticalAlignment(columnSep.attributeNS(KoXmlNS::style, "vertical-align"));
0210         }
0211 
0212         KoXmlElement columnElement;
0213         forEachElement(columnElement, columnsElement) {
0214             if(columnElement.localName() != QLatin1String("column") ||
0215                columnElement.namespaceURI() != KoXmlNS::style)
0216                 continue;
0217 
0218             ColumnDatum datum;
0219             datum.leftMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "start-indent"), 0.0);
0220             datum.rightMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "end-indent"), 0.0);
0221             datum.topMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-before"), 0.0);
0222             datum.bottomMargin = KoUnit::parseValue(columnElement.attributeNS(KoXmlNS::fo, "space-after"), 0.0);
0223             datum.relativeWidth = parseRelativeWidth(columnElement.attributeNS(KoXmlNS::style, "rel-width"));
0224             // on a bad relativeWidth just drop all data
0225             if (datum.relativeWidth <= 0) {
0226                 columnData.clear();
0227                 break;
0228             }
0229 
0230             columnData.append(datum);
0231         }
0232 
0233         if (! columnData.isEmpty() && count != columnData.count()) {
0234             warnOdf << "Found not as many <style:column> elements as attribute fo:column-count has set:"<< count;
0235             columnData.clear();
0236         }
0237     } else {
0238         reset();
0239     }
0240 }
0241 
0242 void KoColumns::saveOdf(KoGenStyle &style) const
0243 {
0244     if (count > 1) {
0245         QBuffer buffer;
0246         buffer.open(QIODevice::WriteOnly);
0247         KoXmlWriter writer(&buffer);
0248 
0249         writer.startElement("style:columns");
0250         writer.addAttribute("fo:column-count", count);
0251         if (columnData.isEmpty()) {
0252             writer.addAttributePt("fo:column-gap", gapWidth);
0253         }
0254 
0255         if (separatorStyle != KoColumns::None) {
0256             writer.startElement("style:column-sep");
0257             writer.addAttribute("style:style", separatorStyleString(separatorStyle));
0258             writer.addAttributePt("style:width", separatorWidth);
0259             writer.addAttribute("style:height", QString::number(separatorHeight)+QLatin1Char('%'));
0260             writer.addAttribute("style:color", separatorColor.name());
0261             writer.addAttribute("style:vertical-align", separatorVerticalAlignmentString(separatorVerticalAlignment));
0262             writer.endElement(); // style:column-sep
0263         }
0264 
0265         foreach(const ColumnDatum &cd, columnData) {
0266             writer.startElement("style:column");
0267             writer.addAttributePt("fo:start-indent", cd.leftMargin);
0268             writer.addAttributePt("fo:end-indent", cd.rightMargin);
0269             writer.addAttributePt("fo:space-before", cd.topMargin);
0270             writer.addAttributePt("fo:space-after", cd.bottomMargin);
0271             writer.addAttribute("style:rel-width", QString::number(cd.relativeWidth)+QLatin1Char('*'));
0272             writer.endElement(); // style:column
0273         }
0274 
0275         writer.endElement(); // style:columns
0276 
0277         QString contentElement = QString::fromUtf8(buffer.buffer(), buffer.buffer().size());
0278         style.addChildElement("style:columns", contentElement);
0279     }
0280 }