File indexing completed on 2025-01-19 13:27:36

0001 /*
0002  * This file is part of Office 2007 Filters for Calligra
0003  *
0004  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
0005  *
0006  * Contact: Suresh Chande suresh.chande@nokia.com
0007  *
0008  * This library is free software; you can redistribute it and/or
0009  * modify it under the terms of the GNU Lesser General Public License
0010  * version 2.1 as published by the Free Software Foundation.
0011  *
0012  * This library is distributed in the hope that it will be useful, but
0013  * WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library; if not, write to the Free Software
0019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020  * 02110-1301 USA
0021  *
0022  */
0023 
0024 #include "XlsxUtils.h"
0025 #include "XlsxXmlStylesReader.h"
0026 #include "XlsxImport.h"
0027 
0028 #include "NumberFormatParser.h"
0029 
0030 #include <MsooXmlSchemas.h>
0031 #include <MsooXmlUtils.h>
0032 #include <KoXmlWriter.h>
0033 #include <styles/KoCharacterStyle.h>
0034 #include <KoGenStyles.h>
0035 
0036 #undef MSOOXML_CURRENT_NS
0037 #define MSOOXML_CURRENT_CLASS XlsxXmlStylesReader
0038 #define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
0039 
0040 #include <MsooXmlReader_p.h>
0041 
0042 #include <QMap>
0043 #include <QGlobalStatic>
0044 
0045 #include <math.h>
0046 
0047 //----------------------------------------------------------
0048 
0049 //! @see http://www.w3.org/TR/CSS2/box.html#value-def-border-style
0050 //! @see http://www.w3.org/TR/CSS2/box.html#value-def-border-width
0051 KoFilter::ConversionStatus XlsxXmlStylesReader::readAttributes(const QXmlStreamAttributes& attrs, QString& borderStyle)
0052 {
0053     QString s;
0054 //! @todo more styles
0055     TRY_READ_ATTR_WITHOUT_NS_INTO(style, s)
0056     if (s == QLatin1String("dashed") || s == QLatin1String("dotted") || s == QLatin1String("double")) {
0057         borderStyle = s;
0058     }
0059     else if (s == QLatin1String("medium") || s == QLatin1String("thick") || s == QLatin1String("thin"))
0060     {
0061         borderStyle = s + " solid";
0062     }
0063     else if (s == QLatin1String("none")) {
0064         borderStyle = QLatin1String("hidden");
0065     }
0066     else if (!s.isEmpty()) {
0067         borderStyle = QLatin1String("solid"); // fallback
0068     }
0069     qCDebug(lcXlsxImport) << "style:" << s << "set to:" << borderStyle;
0070     return KoFilter::OK;
0071 }
0072 
0073 static QColor applyPatternDensity(const QColor& bg, const QColor& fg, qreal percent)
0074 {
0075     QColor result;
0076 
0077     if (bg.isValid()) {
0078         result = QColor( bg.red() * percent,
0079                          bg.green() * percent,
0080                          bg.blue() * percent,
0081                          bg.alpha() );
0082     }
0083     if (fg.isValid()) {
0084         result = QColor( result.red()   + fg.red() * ( 1.0 - percent ),
0085                          result.green() + fg.green() * ( 1.0 - percent ),
0086                          result.blue()  + fg.blue() * ( 1.0 - percent ),
0087                          bg.isValid() ? bg.alpha() : fg.alpha() );
0088     }
0089 
0090     return result;
0091 }
0092 
0093 //----------------------------------------------------------
0094 
0095 XlsxStyles::XlsxStyles()
0096 {
0097     // fill the default number formats
0098     // from Office Open XML Part 4 - Markup Language Reference, p. 1974
0099     numberFormatStrings[ 1 ] = QLatin1String( "0" );
0100     numberFormatStrings[ 2 ] = QLatin1String( "0.00" );
0101     numberFormatStrings[ 3 ] = QLatin1String( "#,##0" );
0102     numberFormatStrings[ 4 ] = QLatin1String( "#,##0.00" );
0103     numberFormatStrings[ 9 ] = QLatin1String( "0%" );
0104     numberFormatStrings[ 10 ] = QLatin1String( "0.00%" );
0105     numberFormatStrings[ 11 ] = QLatin1String( "0.00E+00" );
0106     numberFormatStrings[ 12 ] = QLatin1String( "# ?/?" );
0107     numberFormatStrings[ 13 ] = QLatin1String( "# \?\?/\?\?" );
0108     numberFormatStrings[ 14 ] = QLatin1String( "mm-dd-yy" );
0109     numberFormatStrings[ 15 ] = QLatin1String( "d-mmm-yy" );
0110     numberFormatStrings[ 16 ] = QLatin1String( "d-mmm" );
0111     numberFormatStrings[ 17 ] = QLatin1String( "mmm-yy" );
0112     numberFormatStrings[ 18 ] = QLatin1String( "h:mm AM/PM" );
0113     numberFormatStrings[ 19 ] = QLatin1String( "h:mm:ss AM/PM" );
0114     numberFormatStrings[ 20 ] = QLatin1String( "h:mm" );
0115     numberFormatStrings[ 21 ] = QLatin1String( "h:mm:ss" );
0116     numberFormatStrings[ 22 ] = QLatin1String( "m/d/yy h:mm" );
0117     numberFormatStrings[ 37 ] = QLatin1String( "#,##0 ;(#,##0)" );
0118     numberFormatStrings[ 38 ] = QLatin1String( "#,##0 ;[Red](#,##0)" );
0119     numberFormatStrings[ 39 ] = QLatin1String( "#,##0.00;(#,##0.00)" );
0120     numberFormatStrings[ 40 ] = QLatin1String( "#,##0.00;[Red](#,##0.00)" );
0121     numberFormatStrings[ 45 ] = QLatin1String( "mm:ss" );
0122     numberFormatStrings[ 46 ] = QLatin1String( "[h]:mm:ss" );
0123     numberFormatStrings[ 47 ] = QLatin1String( "mmss.0" );
0124     numberFormatStrings[ 48 ] = QLatin1String( "##0.0E+0" );
0125     numberFormatStrings[ 49 ] = QLatin1String( "@" );
0126 }
0127 
0128 XlsxStyles::~XlsxStyles()
0129 {
0130     for (int i = 0; i < fontStyles.size(); i++)
0131         delete fontStyles[i];
0132     for (int i = 0; i < fillStyles.size(); i++)
0133         delete fillStyles[i];
0134     for (int i = 0; i < cellFormats.size(); i++)
0135         delete cellFormats[i];
0136     for (int i = 0; i < borderStyles.size(); i++)
0137         delete borderStyles[i];
0138 }
0139 
0140 void XlsxStyles::setCellFormat(XlsxCellFormat *format, int cellFormatIndex)
0141 {
0142 //    format->styles = this;
0143     delete cellFormats[cellFormatIndex];
0144     cellFormats[cellFormatIndex] = format;
0145 }
0146 
0147 //----------------------------------------------------------
0148 //! default values based on Annex A, p. 4476
0149 XlsxCellFormat::XlsxCellFormat()
0150  : applyAlignment(true), applyBorder(true), applyFill(true), applyFont(true),
0151    applyNumberFormat(true), applyProtection(true),
0152    borderId(-1), fillId(-1), fontId(-1), numFmtId(-1),
0153    pivotButton(false), quotePrefix(false), xfId(-1),
0154    horizontalAlignment(GeneralHorizontalAlignment),
0155    verticalAlignment(NoVerticalAlignment),
0156    wrapText(false),
0157    shrinkToFit(false),
0158    textRotation(0)
0159 {
0160 }
0161 
0162 XlsxCellFormat::~XlsxCellFormat()
0163 {
0164 }
0165 
0166 class ST_HorizontalAlignment_fromStringMap : public QMap<QString, XlsxCellFormat::ST_HorizontalAlignment>
0167 {
0168 public:
0169     ST_HorizontalAlignment_fromStringMap() {
0170         insert(QString(), XlsxCellFormat::GeneralHorizontalAlignment);
0171         insert(QLatin1String("general"), XlsxCellFormat::GeneralHorizontalAlignment);
0172         insert(QLatin1String("center"), XlsxCellFormat::CenterHorizontalAlignment);
0173         insert(QLatin1String("centerContinuous"), XlsxCellFormat::CenterContinuousHorizontalAlignment);
0174         insert(QLatin1String("distributed"), XlsxCellFormat::DistributedHorizontalAlignment);
0175         insert(QLatin1String("fill"), XlsxCellFormat::FillHorizontalAlignment);
0176         insert(QLatin1String("justify"), XlsxCellFormat::JustifyHorizontalAlignment);
0177         insert(QLatin1String("left"), XlsxCellFormat::LeftHorizontalAlignment);
0178         insert(QLatin1String("right"), XlsxCellFormat::RightHorizontalAlignment);
0179     }
0180 };
0181 
0182 Q_GLOBAL_STATIC(ST_HorizontalAlignment_fromStringMap, s_ST_HorizontalAlignmentValues)
0183 
0184 void XlsxCellFormat::setHorizontalAlignment(const QString& alignment)
0185 {
0186     horizontalAlignment = s_ST_HorizontalAlignmentValues->value(alignment);
0187 }
0188 
0189 class ST_VerticalAlignment_fromStringMap : public QMap<QString, XlsxCellFormat::ST_VerticalAlignment>
0190 {
0191 public:
0192     ST_VerticalAlignment_fromStringMap() {
0193         insert(QString(), XlsxCellFormat::NoVerticalAlignment);
0194         insert(QLatin1String("bottom"), XlsxCellFormat::BottomVerticalAlignment);
0195         insert(QLatin1String("center"), XlsxCellFormat::CenterVerticalAlignment);
0196         insert(QLatin1String("distributed"), XlsxCellFormat::DistributedVerticalAlignment);
0197         insert(QLatin1String("justify"), XlsxCellFormat::JustifyVerticalAlignment);
0198         insert(QLatin1String("top"), XlsxCellFormat::TopVerticalAlignment);
0199     }
0200 };
0201 
0202 Q_GLOBAL_STATIC(ST_VerticalAlignment_fromStringMap, s_ST_VerticalAlignmentValues)
0203 
0204 void XlsxCellFormat::setVerticalAlignment(const QString& alignment)
0205 {
0206     verticalAlignment = s_ST_VerticalAlignmentValues->value(alignment);
0207 }
0208 
0209 //! CASE #S1600
0210 void XlsxCellFormat::setupCellStyleAlignment(KoGenStyle* cellStyle) const
0211 {
0212 //! @todo FillHorizontalAlignment, JustifyHorizontalAlignment
0213     int wrapOption = -1; // "don't know"
0214     if (wrapText)
0215         wrapOption = 1;
0216     //special case: 255 indicates vertical rotation without rotated characters (I couldn't find that documented though)
0217     const bool verticalTtb = textRotation == 255;
0218     if (verticalTtb)
0219         cellStyle->addProperty("style:direction", "ttb");
0220     else if (textRotation != 0) {
0221         unsigned angle = textRotation;
0222         if (angle > 90) angle = 360 - (angle - 90);
0223         cellStyle->addProperty("style:rotation-angle", QString::number(angle));
0224     }
0225 
0226     if (shrinkToFit)
0227         cellStyle->addProperty("style:shrink-to-fit", "true");
0228 
0229     switch (horizontalAlignment) {
0230     case CenterHorizontalAlignment:
0231     case CenterContinuousHorizontalAlignment:
0232     case DistributedHorizontalAlignment:
0233         cellStyle->addProperty("fo:text-align", "center", KoGenStyle::ParagraphType);
0234         if (horizontalAlignment == DistributedHorizontalAlignment)
0235             wrapOption = 1;
0236         break;
0237     case GeneralHorizontalAlignment: // ok?
0238         if (verticalTtb) // Excel centers vertical text by default, so mimic that
0239             cellStyle->addProperty("fo:text-align", "center", KoGenStyle::ParagraphType);
0240         if (textRotation > 90 && textRotation < 180) // Excel right aligns rotated text for some angles
0241             cellStyle->addProperty("fo:text-align", "end", KoGenStyle::ParagraphType);
0242         break;
0243     case LeftHorizontalAlignment:
0244         cellStyle->addProperty("fo:text-align", "start", KoGenStyle::ParagraphType);
0245         break;
0246     case RightHorizontalAlignment:
0247         cellStyle->addProperty("fo:text-align", "end", KoGenStyle::ParagraphType);
0248         break;
0249     case JustifyHorizontalAlignment:
0250         cellStyle->addProperty("fo:text-align", "justify", KoGenStyle::ParagraphType);
0251         wrapOption = 1;
0252         break;
0253     case FillHorizontalAlignment:
0254     default:;
0255     }
0256 
0257     switch (verticalAlignment) {
0258     case CenterVerticalAlignment:
0259         cellStyle->addProperty("style:vertical-align", "middle");
0260         break;
0261     case TopVerticalAlignment:
0262         cellStyle->addProperty("style:vertical-align", "top");
0263         break;
0264     case JustifyVerticalAlignment: // ok?
0265     case DistributedVerticalAlignment:
0266         cellStyle->addProperty("style:vertical-align", "top");
0267         cellStyle->addProperty("calligra:vertical-distributed", "distributed");
0268         wrapOption = 1;
0269         break;
0270     case NoVerticalAlignment:
0271     case BottomVerticalAlignment:
0272         cellStyle->addProperty("style:vertical-align", "bottom");
0273         break;
0274     default:;
0275     }
0276 
0277     if (wrapOption == 0 || wrapOption == 1)
0278         cellStyle->addProperty("fo:wrap-option", wrapOption ? "wrap" : "no-wrap");
0279 }
0280 
0281 //! See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#text-align
0282 bool XlsxCellFormat::setupCellStyle(
0283     const XlsxStyles *styles,
0284     KoGenStyle* cellStyle) const
0285 {
0286     qCDebug(lcXlsxImport) << "fontId:" << fontId << "fillId:" << fillId << "borderId:" << borderId;
0287     if (applyAlignment) {
0288         setupCellStyleAlignment(cellStyle);
0289     }
0290     if (applyFont && fontId >= 0) {
0291         KoGenStyle* fontStyle = styles->fontStyle(fontId);
0292         if (!fontStyle) {
0293             qCWarning(lcXlsxImport) << "No font with ID:" << fontId;
0294             return false;
0295         }
0296         KoGenStyle::copyPropertiesFromStyle(*fontStyle, *cellStyle, KoGenStyle::TextType);
0297     }
0298     if (applyFill && fillId >= 0) {
0299         KoGenStyle *fillStyle = styles->fillStyle(fillId);
0300         if (!fillStyle) {
0301             qCWarning(lcXlsxImport) << "No fill with ID:" << fillId;
0302             return false;
0303         }
0304         KoGenStyle::copyPropertiesFromStyle(*fillStyle, *cellStyle, KoGenStyle::TableCellType);
0305     }
0306     if (applyBorder && borderId >= 0) {
0307         KoGenStyle *borderStyle = styles->borderStyle(borderId);
0308         if (borderStyle) {
0309             KoGenStyle::copyPropertiesFromStyle(*borderStyle, *cellStyle, KoGenStyle::TableCellType);
0310         }
0311     }
0312     return true;
0313 }
0314 
0315 //----------------------------------------------------------
0316 
0317 XlsxXmlStylesReaderContext::XlsxXmlStylesReaderContext(XlsxStyles& _styles, bool _skipFirstPart,
0318     XlsxImport* _import, MSOOXML::DrawingMLTheme* _themes)
0319         : styles(&_styles), skipFirstPart(_skipFirstPart), import(_import), themes(_themes)
0320 {
0321     // This is default array of colors from the spec
0322     colorIndices.push_back("000000");
0323     colorIndices.push_back("FFFFFF");
0324     colorIndices.push_back("FF0000");
0325     colorIndices.push_back("00FF00");
0326     colorIndices.push_back("0000FF");
0327     colorIndices.push_back("FFFF00");
0328     colorIndices.push_back("FF00FF");
0329     colorIndices.push_back("00FFFF");
0330     colorIndices.push_back("000000");
0331     colorIndices.push_back("FFFFFF");
0332     colorIndices.push_back("FF0000");
0333     colorIndices.push_back("00FF00");
0334     colorIndices.push_back("0000FF");
0335     colorIndices.push_back("FFFF00");
0336     colorIndices.push_back("FF00FF");
0337     colorIndices.push_back("00FFFF");
0338     colorIndices.push_back("800000");
0339     colorIndices.push_back("008000");
0340     colorIndices.push_back("000080");
0341     colorIndices.push_back("808000");
0342     colorIndices.push_back("800080");
0343     colorIndices.push_back("008080");
0344     colorIndices.push_back("C0C0C0");
0345     colorIndices.push_back("808080");
0346     colorIndices.push_back("9999FF");
0347     colorIndices.push_back("993366");
0348     colorIndices.push_back("FFFFCC");
0349     colorIndices.push_back("CCFFFF");
0350     colorIndices.push_back("660066");
0351     colorIndices.push_back("FF8080");
0352     colorIndices.push_back("0066CC");
0353     colorIndices.push_back("CCCCFF");
0354     colorIndices.push_back("000080");
0355     colorIndices.push_back("FF00FF");
0356     colorIndices.push_back("FFFF00");
0357     colorIndices.push_back("00FFFF");
0358     colorIndices.push_back("800080");
0359     colorIndices.push_back("800000");
0360     colorIndices.push_back("008080");
0361     colorIndices.push_back("0000FF");
0362     colorIndices.push_back("00CCFF");
0363     colorIndices.push_back("CCFFFF");
0364     colorIndices.push_back("CCFFCC");
0365     colorIndices.push_back("FFFF99");
0366     colorIndices.push_back("99CCFF");
0367     colorIndices.push_back("FF99CC");
0368     colorIndices.push_back("CC99FF");
0369     colorIndices.push_back("FFCC99");
0370     colorIndices.push_back("3366FF");
0371     colorIndices.push_back("33CCCC");
0372     colorIndices.push_back("99CC00");
0373     colorIndices.push_back("FFCC00");
0374     colorIndices.push_back("FF9900");
0375     colorIndices.push_back("FF6600");
0376     colorIndices.push_back("666699");
0377     colorIndices.push_back("969696");
0378     colorIndices.push_back("003366");
0379     colorIndices.push_back("339966");
0380     colorIndices.push_back("003300");
0381     colorIndices.push_back("333300");
0382     colorIndices.push_back("993300");
0383     colorIndices.push_back("993366");
0384     colorIndices.push_back("333399");
0385     colorIndices.push_back("333333");
0386 }
0387 
0388 class XlsxXmlStylesReader::Private
0389 {
0390 public:
0391     Private() {
0392     }
0393     ~Private() {
0394     }
0395 private:
0396 };
0397 
0398 XlsxXmlStylesReader::XlsxXmlStylesReader(KoOdfWriters *writers)
0399         : XlsxXmlCommonReader(writers)
0400         , m_context(0)
0401         , d(new Private)
0402 {
0403     init();
0404 }
0405 
0406 XlsxXmlStylesReader::~XlsxXmlStylesReader()
0407 {
0408     delete d;
0409 }
0410 
0411 void XlsxXmlStylesReader::init()
0412 {
0413     m_defaultNamespace = "";
0414     m_cellFormatIndex = 0;
0415     m_currentFontStyle = 0;
0416     m_currentFillStyle = 0;
0417     m_currentCellFormat = 0;
0418 }
0419 
0420 KoFilter::ConversionStatus XlsxXmlStylesReader::read(MSOOXML::MsooXmlReaderContext* context)
0421 {
0422     m_context = dynamic_cast<XlsxXmlStylesReaderContext*>(context);
0423     Q_ASSERT(m_context);
0424     m_colorIndices = m_context->colorIndices;
0425     m_themes = m_context->themes;
0426     const KoFilter::ConversionStatus result = readInternal();
0427     m_context = 0;
0428     if (result == KoFilter::OK)
0429         return KoFilter::OK;
0430     return result;
0431 }
0432 
0433 KoFilter::ConversionStatus XlsxXmlStylesReader::readInternal()
0434 {
0435     qCDebug(lcXlsxImport) << "=============================";
0436     readNext();
0437     if (!isStartDocument()) {
0438         return KoFilter::WrongFormat;
0439     }
0440 
0441     // sst
0442     readNext();
0443     qCDebug(lcXlsxImport) << *this << namespaceUri();
0444 
0445     if (!expectEl("styleSheet")) {
0446         return KoFilter::WrongFormat;
0447     }
0448     if (!expectNS(MSOOXML::Schemas::spreadsheetml)) {
0449         return KoFilter::WrongFormat;
0450     }
0451 
0452     QXmlStreamNamespaceDeclarations namespaces(namespaceDeclarations());
0453     for (int i = 0; i < namespaces.count(); i++) {
0454         qCDebug(lcXlsxImport) << "NS prefix:" << namespaces[i].prefix() << "uri:" << namespaces[i].namespaceUri();
0455     }
0456 //! @todo find out whether the namespace returned by namespaceUri()
0457 //!       is exactly the same ref as the element of namespaceDeclarations()
0458     if (!namespaces.contains(QXmlStreamNamespaceDeclaration(QString(), MSOOXML::Schemas::spreadsheetml))) {
0459         raiseError(i18n("Namespace \"%1\" not found", QLatin1String(MSOOXML::Schemas::spreadsheetml)));
0460         return KoFilter::WrongFormat;
0461     }
0462 //! @todo expect other namespaces too...
0463 
0464     // Read the style-sheet.
0465     TRY_READ(styleSheet)
0466 
0467     // Once finished reading the style-sheets we can translate the MSExcel number-formattings
0468     // to ODF number-formattings. We do this here cause m_context->styles->numberFormatStrings
0469     // is filled now, not allowed to change from here on and it greatly improves the performance
0470     // if we do the whole conversation only once right now and use the result later.
0471     for(QMap< int, QString >::ConstIterator it = m_context->styles->numberFormatStrings.constBegin(); it != m_context->styles->numberFormatStrings.constEnd(); ++it) {
0472         const KoGenStyle style = NumberFormatParser::parse( it.value(), mainStyles );
0473         //m_context->styles->numberFormatStyles[ it.key() ] = style;
0474         if ( style.type() != KoGenStyle::ParagraphAutoStyle ) {
0475             QString styleName = mainStyles->insert( style, "N" );
0476             m_context->styles->numberFormatStyleNames[ it.key() ] = styleName;
0477         }
0478     }
0479 
0480     qCDebug(lcXlsxImport) << "===========finished============";
0481     return KoFilter::OK;
0482 }
0483 
0484 #undef CURRENT_EL
0485 #define CURRENT_EL styleSheet
0486 //! styleSheet handler (Style Sheet)
0487 /*! ECMA-376, 18.8.39, p. 1993.
0488  This is the root element of the Styles part.
0489 
0490  Child elements:
0491  - [done] borders (Borders) §18.8.5
0492  - cellStyles (Cell Styles) §18.8.8
0493  - cellStyleXfs (Formatting Records) §18.8.9
0494  - [done] cellXfs (Cell Formats) §18.8.10
0495  - [done] colors (Colors) §18.8.11
0496  - [done] dxfs (Formats) §18.8.15
0497  - extLst (Future Feature Data Storage Area) §18.2.10
0498  - [done] fills (Fills) §18.8.21
0499  - [done] fonts (Fonts) §18.8.23
0500  - [done] numFmts (Number Formats) §18.8.31
0501  - tableStyles (Table Styles) §18.8.42
0502 */
0503 KoFilter::ConversionStatus XlsxXmlStylesReader::read_styleSheet()
0504 {
0505     READ_PROLOGUE
0506 
0507     int counter = 0;
0508     while (!atEnd()) {
0509         readNext();
0510         qCDebug(lcXlsxImport) << *this;
0511         BREAK_IF_END_OF(CURRENT_EL)
0512         if (isStartElement()) {
0513             // In the first round we read potential color overrides
0514             if (m_context->skipFirstPart) {
0515                 TRY_READ_IF(colors)
0516                 SKIP_UNKNOWN
0517             }
0518             else {
0519                 if (counter == 40) {
0520                     // set the progress by the position of what was read
0521                     qreal progress = 5 + 25 * device()->pos() / device()->size();
0522                     m_context->import->reportProgress(progress);
0523                     counter = 0;
0524                 }
0525                 ++counter;
0526                 TRY_READ_IF(fonts)
0527                 ELSE_TRY_READ_IF(fills)
0528                 ELSE_TRY_READ_IF(numFmts)
0529                 ELSE_TRY_READ_IF(cellXfs)
0530                 ELSE_TRY_READ_IF(borders)
0531                 ELSE_TRY_READ_IF(dxfs)
0532                 SKIP_UNKNOWN
0533             }
0534 //! @todo add ELSE_WRONG_FORMAT
0535         }
0536     }
0537     READ_EPILOGUE
0538 }
0539 
0540 #undef CURRENT_EL
0541 #define CURRENT_EL fonts
0542 //! fonts handler (Fonts)
0543 /*! ECMA-376, 18.8.23, p. 1964.
0544  This element contains all font definitions for this workbook.
0545 
0546  Child elements:
0547  - [done] font (Font) §18.8.22
0548 
0549  Parent elements:
0550  - [done] styleSheet (§18.8.39)
0551 */
0552 KoFilter::ConversionStatus XlsxXmlStylesReader::read_fonts()
0553 {
0554     READ_PROLOGUE
0555     if (!m_context->styles->fontStyles.isEmpty()) {
0556         raiseUnexpectedSecondOccurenceOfElError(STRINGIFY(CURRENT_EL));
0557     }
0558     const QXmlStreamAttributes attrs(attributes());
0559     TRY_READ_ATTR_WITHOUT_NS(count)
0560     uint countNumber = 0;
0561     STRING_TO_INT(count, countNumber, "styleSheet/fonts@count")
0562     m_context->styles->fontStyles.resize(countNumber);
0563     uint fontStyleIndex = 0;
0564 
0565     while (!atEnd()) {
0566         readNext();
0567         qCDebug(lcXlsxImport) << *this;
0568         BREAK_IF_END_OF(CURRENT_EL)
0569         if (isStartElement()) {
0570             if (QUALIFIED_NAME_IS(font)) {
0571                 m_currentFontStyle = new KoGenStyle(KoGenStyle::TextAutoStyle, "text");
0572                 if (fontStyleIndex >= (uint)m_context->styles->fontStyles.size()) {
0573                     raiseError(i18n("Declared number of font styles too small (%1)", m_context->styles->fontStyles.size()));
0574                     return KoFilter::WrongFormat;
0575                 }
0576                 TRY_READ(font)
0577                 m_context->styles->fontStyles[fontStyleIndex] = m_currentFontStyle;
0578                 m_currentFontStyle = 0;
0579                 fontStyleIndex++;
0580             }
0581             ELSE_WRONG_FORMAT
0582         }
0583     }
0584     READ_EPILOGUE
0585 }
0586 
0587 #undef CURRENT_EL
0588 #define CURRENT_EL numFmts
0589 //! numFmts handler (Number formats)
0590 /*! ECMA-376, 18.8.31, p. 1981.
0591  This element defines the number formats in this workbook, consisting of a sequence of numFmt records,
0592  where each numFmt record defines a particular number format, indicating how to format and render
0593  the numeric value of a cell.
0594 
0595  Child elements:
0596  - [done] numFmt (Format Definition) §18.8.30
0597  Parent elements:
0598  - [done] styleSheet (§18.8.39)
0599 */
0600 KoFilter::ConversionStatus XlsxXmlStylesReader::read_numFmts()
0601 {
0602     READ_PROLOGUE
0603 #if 0
0604     //this code just reads the count out of the attributes and convert it to a integer. 
0605     //it is currently not needed, but maybe we will need it later on.
0606     const QXmlStreamAttributes attrs(attributes());
0607     TRY_READ_ATTR_WITHOUT_NS( count )
0608     int countNumber = 0;
0609     STRING_TO_INT( count, countNumber, "styleSheet/numFmts@count" );
0610 #endif
0611 
0612     while( !atEnd() )
0613     {
0614         readNext();
0615         BREAK_IF_END_OF(CURRENT_EL)
0616         if( isStartElement() )
0617         {
0618             TRY_READ_IF( numFmt )
0619             ELSE_WRONG_FORMAT
0620         }
0621     }
0622 
0623     READ_EPILOGUE
0624 }
0625 
0626 #undef CURRENT_EL
0627 #define CURRENT_EL numFmt
0628 //! numFmt handler (Number format)
0629 /*! ECMA-376, 18.8.30, p. 1973.
0630  This element specifies number format properties which indicate how to format and render
0631  the numeric value of a cell.
0632 
0633  No child elements.
0634 
0635  Parent elements:
0636  - dxf (§18.8.14)
0637  - ndxf (§18.11.1.4)
0638  - [done] numFmts (§18.8.31)
0639  - odxf (§18.11.1.6)
0640 */
0641 KoFilter::ConversionStatus XlsxXmlStylesReader::read_numFmt()
0642 {
0643     READ_PROLOGUE
0644 
0645     const QXmlStreamAttributes attrs(attributes());
0646     TRY_READ_ATTR_WITHOUT_NS( numFmtId )
0647     int id = -1;
0648     STRING_TO_INT(numFmtId, id, "numFmt@numFmtId")
0649 
0650     TRY_READ_ATTR_WITHOUT_NS( formatCode );
0651     if (id >= 0 && !formatCode.isEmpty()) {
0652         m_context->styles->numberFormatStrings[ id ] = formatCode;
0653     }
0654 
0655     readNext();
0656     READ_EPILOGUE
0657 }
0658 
0659 #undef CURRENT_EL
0660 #define CURRENT_EL font
0661 //! font handler (Font)
0662 /*! ECMA-376, 18.8.22, p. 1964.
0663  This element defines the properties for one of the fonts used in this workbook.
0664 
0665  Child elements:
0666  - [done] b (Bold) §18.8.2
0667  - charset (Character Set) §18.4.1
0668  - [done] color (Data Bar Color) §18.3.1.15
0669  - condense (Condense) §18.8.12
0670  - extend (Extend) §18.8.17
0671  - family (Font Family) §18.8.18
0672  - [done] i (Italic) §18.8.26
0673  - [done] name (Font Name) §18.8.29
0674  - [done] outline (Outline) §18.4.2
0675  - [done] scheme (Scheme) §18.8.35
0676  - shadow (Shadow) §18.8.36
0677  - [done] strike (Strike Through) §18.4.10
0678  - [done] sz (Font Size) §18.4.11
0679  - [done] u (Underline) §18.4.13
0680  - [done] vertAlign (Vertical Alignment) §18.4.14
0681 
0682  Parent elements:
0683  - [done] dxf (§18.8.14)
0684  - [done] fonts (§18.8.23)
0685  - ndxf (§18.11.1.4)
0686  - odxf (§18.11.1.6)
0687 
0688  @todo support all child elements
0689 */
0690 KoFilter::ConversionStatus XlsxXmlStylesReader::read_font()
0691 {
0692     READ_PROLOGUE
0693 
0694     MSOOXML::Utils::AutoPtrSetter<KoGenStyle> currentFontStyleSetter(m_currentFontStyle);
0695 
0696     m_currentTextStyleProperties = new KoCharacterStyle;
0697 
0698     while (!atEnd()) {
0699         readNext();
0700         BREAK_IF_END_OF(CURRENT_EL)
0701         if (isStartElement()) {
0702             TRY_READ_IF(sz)
0703             ELSE_TRY_READ_IF(name)
0704             ELSE_TRY_READ_IF(b)
0705             ELSE_TRY_READ_IF(i)
0706             else if (name() == "color") {
0707                 m_currentColor = QColor();
0708                 TRY_READ(color)
0709                 if (m_currentColor.isValid()) {
0710                     m_currentTextStyleProperties->setForeground(QBrush(m_currentColor));
0711                 }
0712             }
0713             ELSE_TRY_READ_IF(color)
0714             ELSE_TRY_READ_IF(strike)
0715             ELSE_TRY_READ_IF(u)
0716             ELSE_TRY_READ_IF(vertAlign)
0717             ELSE_TRY_READ_IF(scheme)
0718             ELSE_TRY_READ_IF(outline)
0719             SKIP_UNKNOWN
0720 //! @todo add ELSE_WRONG_FORMAT
0721         }
0722     }
0723 
0724     m_currentTextStyleProperties->saveOdf(*m_currentFontStyle);
0725     delete m_currentTextStyleProperties;
0726     m_currentTextStyleProperties = 0;
0727 
0728     currentFontStyleSetter.release();
0729 
0730     READ_EPILOGUE
0731 }
0732 
0733 #undef CURRENT_EL
0734 #define CURRENT_EL name
0735 //! name handler (Font Name)
0736 /*! ECMA-376, 18.8.29, p. 1973.
0737  This element specifies the face name of this font.
0738 
0739  Parent elements:
0740  - [done] font (§18.8.22)
0741 
0742  Child elements:
0743  - none
0744 */
0745 KoFilter::ConversionStatus XlsxXmlStylesReader::read_name()
0746 {
0747     Q_ASSERT(m_currentFontStyle);
0748 
0749     READ_PROLOGUE
0750     const QXmlStreamAttributes attrs(attributes());
0751     TRY_READ_ATTR_WITHOUT_NS(val)
0752 
0753     if (!val.isEmpty()) {
0754         m_currentFontStyle->addProperty("fo:font-family", val);
0755     }
0756 
0757     readNext();
0758     READ_EPILOGUE
0759 }
0760 
0761 #undef CURRENT_EL
0762 #define CURRENT_EL dxfs
0763 /*
0764  Parent elements:
0765  - [done] styleSheet (§18.8.39)
0766 
0767  Child elements:
0768  - [done] dxf (Formatting) §18.8.14
0769 
0770 */
0771 KoFilter::ConversionStatus XlsxXmlStylesReader::read_dxfs()
0772 {
0773     READ_PROLOGUE
0774 
0775     while (!atEnd()) {
0776         readNext();
0777         BREAK_IF_END_OF(CURRENT_EL)
0778         if (isStartElement()) {
0779             TRY_READ_IF(dxf)
0780             ELSE_WRONG_FORMAT
0781         }
0782     }
0783 
0784     READ_EPILOGUE
0785 }
0786 
0787 #undef CURRENT_EL
0788 #define CURRENT_EL dxf
0789 /*
0790  Parent elements:
0791  - [done] dxfs (§18.8.15);
0792  - rfmt (§18.11.1.17)
0793 
0794  Child elements:
0795  - [done] alignment (Alignment) §18.8.1
0796  - [done] border (Border) §18.8.4
0797  - extLst (Future Feature Data Storage Area) §18.2.10
0798  - [done] fill (Fill) §18.8.20
0799  - [done] font (Font) §18.8.22
0800  - numFmt (Number Format) §18.8.30
0801  - protection (Protection Properties) §18.8.33
0802 
0803 */
0804 KoFilter::ConversionStatus XlsxXmlStylesReader::read_dxf()
0805 {
0806     READ_PROLOGUE
0807 
0808     KoGenStyle cellStyle(KoGenStyle::TableCellStyle, "table-cell");
0809 
0810     m_currentFontStyle = new KoGenStyle(KoGenStyle::TextAutoStyle, "text");
0811     m_currentFillStyle = new KoGenStyle(KoGenStyle::TableCellAutoStyle, "table-cell");
0812     m_currentBorderStyle = new KoGenStyle(KoGenStyle::TableCellAutoStyle, "table-cell");
0813     m_currentCellFormat = new XlsxCellFormat;
0814 
0815     while (!atEnd()) {
0816         readNext();
0817         BREAK_IF_END_OF(CURRENT_EL)
0818         if (isStartElement()) {
0819             TRY_READ_IF(font)
0820             ELSE_TRY_READ_IF(fill)
0821             ELSE_TRY_READ_IF(border)
0822             ELSE_TRY_READ_IF(alignment)
0823             SKIP_UNKNOWN
0824         }
0825     }
0826     KoGenStyle::copyPropertiesFromStyle(*m_currentFontStyle, cellStyle, KoGenStyle::TextType);
0827     KoGenStyle::copyPropertiesFromStyle(*m_currentFillStyle, cellStyle, KoGenStyle::TableCellType);
0828     KoGenStyle::copyPropertiesFromStyle(*m_currentBorderStyle, cellStyle, KoGenStyle::TableCellType);
0829     m_currentCellFormat->setupCellStyleAlignment(&cellStyle);
0830 
0831     m_context->styles->conditionalStyles.insert(m_context->styles->conditionalStyles.size() + 1,
0832        mainStyles->insert(cellStyle, "ConditionalStyle"));
0833 
0834     delete m_currentFontStyle;
0835     m_currentFontStyle = 0;
0836     delete m_currentFillStyle;
0837     m_currentFillStyle = 0;
0838     delete m_currentBorderStyle;
0839     m_currentBorderStyle = 0;
0840     delete m_currentCellFormat;
0841     m_currentCellFormat = 0;
0842 
0843     READ_EPILOGUE
0844 }
0845 
0846 #undef CURRENT_EL
0847 #define CURRENT_EL cellXfs
0848 //! cellXfs handler (Cell Formats)
0849 /*! ECMA-376, 18.8.10, p. 1956.
0850  This element contains the master formatting records (xf) which define
0851  the formatting applied to cells in this workbook.
0852 
0853  Child elements:
0854  - [done] xf (Format) §18.8.45
0855 
0856  Parent elements:
0857  - [done] styleSheet (§18.8.39)
0858 
0859  @note cellStyleXfs: the standard states that both the cell style xf records and cell xf records
0860        must be read to understand the full set of formatting applied to a cell.
0861        In MSO, only the cell xf record defines the formatting applied to a cell.
0862        See <a href="http://www.documentinteropinitiative.org/implnotes/implementationnotelist.aspx?id=dd2615fe-aa8d-4a06-a415-13389919cf36&specname=ecma-376">here</a>.
0863 */
0864 KoFilter::ConversionStatus XlsxXmlStylesReader::read_cellXfs()
0865 {
0866     READ_PROLOGUE
0867     if (!m_context->styles->cellFormats.isEmpty()) {
0868         raiseUnexpectedSecondOccurenceOfElError(STRINGIFY(CURRENT_EL));
0869     }
0870     const QXmlStreamAttributes attrs(attributes());
0871     TRY_READ_ATTR_WITHOUT_NS(count)
0872     uint countNumber = 0;
0873     STRING_TO_INT(count, countNumber, "styleSheet/cellXfs@count")
0874     m_context->styles->cellFormats.resize(countNumber);
0875     m_cellFormatIndex = 0;
0876 
0877     while (!atEnd()) {
0878         readNext();
0879         qCDebug(lcXlsxImport) << *this;
0880         BREAK_IF_END_OF(CURRENT_EL)
0881         if (isStartElement()) {
0882             TRY_READ_IF(xf)
0883             ELSE_WRONG_FORMAT
0884         }
0885     }
0886     READ_EPILOGUE
0887 }
0888 
0889 #undef CURRENT_EL
0890 #define CURRENT_EL xf
0891 //! xf handler (Format)
0892 /*! ECMA-376, 18.8.45, p. 1999.
0893  A single xf element describes all of the formatting for a cell.
0894 
0895  Parent elements:
0896  - cellStyleXfs (§18.8.9)
0897  - [done] cellXfs (§18.8.10)
0898  - extLst (Future Feature Data Storage Area) §18.2.10
0899 
0900  Child elements:
0901  - [done] alignment (Alignment) §18.8.1
0902  - protection (Protection Properties) §18.8.33
0903 
0904  Attributes:
0905  - applyAlignment
0906  - applyBorder
0907  - applyFill
0908  - applyFont
0909  - applyNumberFormat
0910  - applyProtection
0911  - [done] borderId
0912  - fillId
0913  - [done] fontId
0914  - numFmtId
0915  - pivotButton
0916  - quotePrefix
0917  - xfId
0918 
0919  @todo support all attributes and elements
0920 */
0921 KoFilter::ConversionStatus XlsxXmlStylesReader::read_xf()
0922 {
0923     READ_PROLOGUE
0924 
0925     if (m_cellFormatIndex >= (uint)m_context->styles->cellFormats.size()) {
0926         raiseError(i18n("Declared number of cell formats too small (%1)", m_context->styles->cellFormats.size()));
0927         return KoFilter::WrongFormat;
0928     }
0929 
0930     qCDebug(lcXlsxImport) << "cell format #" << m_cellFormatIndex;
0931     m_currentCellFormat = new XlsxCellFormat;
0932     MSOOXML::Utils::AutoPtrSetter<XlsxCellFormat> currentCellFormatSetter(m_currentCellFormat);
0933 
0934     // -- read attrs --
0935     const QXmlStreamAttributes attrs(attributes());
0936     m_currentCellFormat->applyAlignment = readBooleanAttr("applyAlignment", true);
0937     m_currentCellFormat->applyBorder = readBooleanAttr("applyBorder", true);
0938     m_currentCellFormat->applyFill = readBooleanAttr("applyFill", true);
0939     m_currentCellFormat->applyFont = readBooleanAttr("applyFont", true);
0940     m_currentCellFormat->applyNumberFormat = readBooleanAttr("applyNumberFormat", true);
0941     m_currentCellFormat->applyProtection = readBooleanAttr("applyProtection", true);
0942 
0943     TRY_READ_ATTR_WITHOUT_NS(borderId)
0944     STRING_TO_INT(borderId, m_currentCellFormat->borderId, "xf@borderId")
0945 
0946     TRY_READ_ATTR_WITHOUT_NS(fillId)
0947     STRING_TO_INT(fillId, m_currentCellFormat->fillId, "xf@fillId")
0948 
0949     TRY_READ_ATTR_WITHOUT_NS(fontId)
0950     STRING_TO_INT(fontId, m_currentCellFormat->fontId, "xf@fontId")
0951 
0952     TRY_READ_ATTR_WITHOUT_NS(numFmtId)
0953     STRING_TO_INT(numFmtId, m_currentCellFormat->numFmtId, "xf@numFmtId")
0954 
0955     m_currentCellFormat->pivotButton = readBooleanAttr("pivotButton");
0956     m_currentCellFormat->quotePrefix = readBooleanAttr("quotePrefix");
0957 
0958     TRY_READ_ATTR_WITHOUT_NS(xfId)
0959     STRING_TO_INT(xfId, m_currentCellFormat->xfId, "xf@xfId")
0960 
0961     while (!atEnd()) {
0962         readNext();
0963         qCDebug(lcXlsxImport) << *this;
0964         BREAK_IF_END_OF(CURRENT_EL)
0965         if (isStartElement()) {
0966             TRY_READ_IF(alignment)
0967             SKIP_UNKNOWN
0968         }
0969     }
0970 
0971     currentCellFormatSetter.release();
0972     m_context->styles->setCellFormat(m_currentCellFormat, m_cellFormatIndex);
0973     m_currentCellFormat = 0;
0974     m_cellFormatIndex++;
0975 
0976     READ_EPILOGUE
0977 }
0978 
0979 #undef CURRENT_EL
0980 #define CURRENT_EL alignment
0981 //! alignment handler (Alignment)
0982 /*! ECMA-376, 18.8.1, p. 1944.
0983  Formatting information pertaining to text alignment in cells.
0984 
0985  No child elements.
0986 
0987  Parent elements:
0988  - dxf (§18.8.14)
0989  - ndxf (§18.11.1.4)
0990  - odxf (§18.11.1.6)
0991  - [done] xf (§18.8.45)
0992 */
0993 KoFilter::ConversionStatus XlsxXmlStylesReader::read_alignment()
0994 {
0995     Q_ASSERT(m_currentCellFormat);
0996 
0997     READ_PROLOGUE
0998     const QXmlStreamAttributes attrs(attributes());
0999     m_currentCellFormat->setHorizontalAlignment(attrs.value("horizontal").toString());
1000     qCDebug(lcXlsxImport) << "horizontalAlignment:" << m_currentCellFormat->horizontalAlignment;
1001     m_currentCellFormat->setVerticalAlignment(attrs.value("vertical").toString());
1002     qCDebug(lcXlsxImport) << "verticalAlignment:" << m_currentCellFormat->verticalAlignment;
1003     const bool wrap = readBooleanAttr("wrapText", false);
1004     m_currentCellFormat->wrapText = wrap;
1005     const bool shrinkToFit = readBooleanAttr("shrinkToFit", false);
1006     m_currentCellFormat->shrinkToFit = shrinkToFit;
1007     const uint textRotation = attributes().value("textRotation").toString().toUInt();
1008     m_currentCellFormat->textRotation = textRotation;
1009 
1010 //! @todo more attributes
1011 
1012     readNext();
1013     READ_EPILOGUE
1014 }
1015 
1016 #undef CURRENT_EL
1017 #define CURRENT_EL fills
1018 //! fills handler (Fills)
1019 /*! ECMA-376, 18.8.21, p. 1963.
1020  This element defines the cell fills portion of the Styles part, consisting of a sequence of fill records.
1021  A cell fill consists of a background color, foreground color, and pattern to be applied across the cell.
1022 
1023  Child elements:
1024  - [done] fill (Fill) §18.8.20
1025  Parent elements:
1026  - [done] styleSheet (§18.8.39)
1027 */
1028 KoFilter::ConversionStatus XlsxXmlStylesReader::read_fills()
1029 {
1030     READ_PROLOGUE
1031     if (!m_context->styles->fillStyles.isEmpty()) {
1032         raiseUnexpectedSecondOccurenceOfElError(STRINGIFY(CURRENT_EL));
1033     }
1034     const QXmlStreamAttributes attrs(attributes());
1035     TRY_READ_ATTR_WITHOUT_NS(count)
1036     uint countNumber = 0;
1037     STRING_TO_INT(count, countNumber, "styleSheet/fills@count")
1038     m_context->styles->fillStyles.resize(countNumber);
1039     uint fillStyleIndex = 0;
1040 
1041     while (!atEnd()) {
1042         readNext();
1043         qCDebug(lcXlsxImport) << *this;
1044         BREAK_IF_END_OF(CURRENT_EL)
1045         if (isStartElement()) {
1046             if (QUALIFIED_NAME_IS(fill)) {
1047                 m_currentFillStyle = new KoGenStyle(KoGenStyle::TableCellAutoStyle, "table-cell");
1048                 if (fillStyleIndex >= (uint)m_context->styles->fillStyles.size()) {
1049                     raiseError(i18n("Declared number of fill styles too small (%1)", m_context->styles->fillStyles.size()));
1050                     return KoFilter::WrongFormat;
1051                 }
1052                 TRY_READ(fill)
1053                 m_context->styles->fillStyles[fillStyleIndex] = m_currentFillStyle;
1054                 m_currentFillStyle = 0;
1055                 fillStyleIndex++;
1056             }
1057             ELSE_WRONG_FORMAT
1058         }
1059     }
1060     READ_EPILOGUE
1061 }
1062 
1063 #undef CURRENT_EL
1064 #define CURRENT_EL fill
1065 //! fill handler (Fill)
1066 /*! ECMA-376, 18.8.20, p. 1962.
1067  This element specifies fill formatting.
1068 
1069  Child elements:
1070  - [done] gradientFill (Gradient) §18.8.24
1071  - [done] patternFill (Pattern) §18.8.32
1072 
1073  Parent elements:
1074  - dxf (§18.8.14)
1075  - [done] fills (§18.8.21)
1076  - ndxf (§18.11.1.4)
1077  - odxf (§18.11.1.6)
1078 */
1079 KoFilter::ConversionStatus XlsxXmlStylesReader::read_fill()
1080 {
1081     READ_PROLOGUE
1082 
1083     while (!atEnd()) {
1084         readNext();
1085         BREAK_IF_END_OF(CURRENT_EL)
1086         if (isStartElement()) {
1087             TRY_READ_IF(gradientFill)
1088             ELSE_TRY_READ_IF(patternFill)
1089             ELSE_WRONG_FORMAT
1090         }
1091     }
1092 
1093     READ_EPILOGUE
1094 }
1095 
1096 #undef CURRENT_EL
1097 #define CURRENT_EL patternFill
1098 //! patternFill handler (Pattern)
1099 /*! ECMA-376, 18.8.22, p. 1990.
1100  This element is used to specify cell fill information for pattern and solid color cell fills.
1101 
1102  Child elements:
1103  - [done] bgColor (Background Color) §18.8.3
1104  - [done] fgColor (Foreground Color) §18.8.19
1105  Parent elements:
1106  - [done] fill (§18.8.20)
1107 */
1108 KoFilter::ConversionStatus XlsxXmlStylesReader::read_patternFill()
1109 {
1110     Q_ASSERT(m_currentFillStyle);
1111     READ_PROLOGUE
1112     const QXmlStreamAttributes attrs(attributes());
1113 
1114     TRY_READ_ATTR_WITHOUT_NS(patternType)
1115 
1116     m_currentBgColor = QColor();
1117     m_currentFgColor = QColor();
1118 
1119     while (!atEnd()) {
1120         readNext();
1121         BREAK_IF_END_OF(CURRENT_EL)
1122         if (isStartElement()) {
1123             TRY_READ_IF(bgColor)
1124             ELSE_TRY_READ_IF(fgColor)
1125             ELSE_WRONG_FORMAT
1126         }
1127     }
1128 
1129     qreal percent = 0;
1130 
1131     const QByteArray p(patternType.toLatin1());
1132     if (p.isEmpty() || p == MsooXmlReader::constNone) {
1133         // 100% background
1134         percent = 1;
1135     }
1136     else if (p == "solid") {
1137         // 100% foreground
1138         percent = 0;
1139     }
1140     else if (p.startsWith("dark")) {
1141         if (p == "darkDown") {
1142             percent = 0.5;
1143         }
1144         else if (p == "darkGray") {
1145             percent = 0.25;
1146         }
1147         else if (p == "darkGrid") {
1148             percent = 0.5;
1149         }
1150         else if (p == "darkHorizontal") {
1151             percent = 0.5;
1152         }
1153         else if (p == "darkTrellis") {
1154             percent = 0.25;
1155         }
1156         else if (p == "darkUp") {
1157             percent = 0.5;
1158         }
1159         else if (p == "darkVertical") {
1160             percent = 0.5;
1161         }
1162     }
1163     else if (p.startsWith("light")) {
1164         if (p == "lightDown") {
1165             percent = 0.75;
1166         }
1167         else if (p == "lightGray") {
1168             percent = 0.75;
1169         }
1170         else if (p == "lightGrid") {
1171             percent = 0.5625;
1172         }
1173         else if (p == "lightHorizontal") {
1174             percent = 0.75;
1175         }
1176         else if (p == "lightTrellis") {
1177             percent = 0.625;
1178         }
1179         else if (p == "lightUp") {
1180             percent = 0.75;
1181         }
1182         else if (p == "lightVertical") {
1183             percent = 0.5;
1184         }
1185     }
1186     else if (p == "mediumGray") {
1187         percent = 0.5;
1188     }
1189     else if (p == "gray0625") {
1190         percent = 0.9375;
1191     }
1192     else if (p == "gray125") {
1193         percent = 0.875;
1194     }
1195     else {
1196         qCWarning(lcXlsxImport) << "unknown value" << p << "of patterFill@patternType; defaulting to \"none\"";
1197         percent = 0;
1198     }
1199 
1200     QColor color = applyPatternDensity(m_currentBgColor, m_currentFgColor, percent);
1201     if (color.isValid()) {
1202         m_currentFillStyle->addProperty("fo:background-color", color.name());
1203     }
1204 
1205     READ_EPILOGUE
1206 }
1207 
1208 #undef CURRENT_EL
1209 #define CURRENT_EL bgColor
1210 //! bgColor handler (Background Color)
1211 /*! ECMA-376, 18.8.3, p. 1948.
1212  Background color of the cell fill pattern. Cell fill patterns operate with two colors:
1213  a background color and a foreground color. These combine together to make a patterned cell fill.
1214 
1215  Parent elements:
1216  - [done] patternFill (§18.8.20)
1217 
1218  Child elements:
1219  - none
1220 
1221  @todo support all elements
1222 */
1223 KoFilter::ConversionStatus XlsxXmlStylesReader::read_bgColor()
1224 {
1225     READ_PROLOGUE
1226 
1227     const QXmlStreamAttributes attrs(attributes());
1228 
1229     TRY_READ_ATTR_WITHOUT_NS(indexed)
1230     TRY_READ_ATTR_WITHOUT_NS(rgb)
1231     TRY_READ_ATTR_WITHOUT_NS(theme)
1232     TRY_READ_ATTR_WITHOUT_NS(tint)
1233 
1234     if (!indexed.isEmpty()) {
1235         int index = indexed.toInt();
1236         if (index >= 0 && index < 64) {
1237             m_currentBgColor = QString("#%1").arg(m_context->colorIndices.at(index));
1238         }
1239     }
1240     if (!rgb.isEmpty()) {
1241         m_currentBgColor = QString("#" + rgb.right(rgb.length()-2));
1242     }
1243     if (!theme.isEmpty()) {
1244         // Xlsx seems to switch these indices
1245         if (theme == "0" ) {
1246             theme = "1";
1247         }
1248         else if (theme == "1" ) {
1249             theme = "0";
1250         }
1251         else if (theme == "2") {
1252             theme = "3";
1253         }
1254         else if (theme == "3") {
1255             theme = "2";
1256         }
1257         MSOOXML::DrawingMLColorSchemeItemBase *colorItemBase = m_context->themes->colorScheme.value(theme);
1258         if (colorItemBase) {
1259             m_currentBgColor = colorItemBase->value();
1260         }
1261     }
1262     if (!tint.isEmpty()) {
1263         m_currentBgColor = tintedColor(m_currentBgColor, tint.toDouble());
1264     }
1265 
1266     readNext();
1267     READ_EPILOGUE
1268 }
1269 
1270 #undef CURRENT_EL
1271 #define CURRENT_EL fgColor
1272 //! fgColor handler (Foreground  Color)
1273 /*! ECMA-376, 18.8.19, p. 1961.
1274  Foreground color of the cell fill pattern. Cell fill patterns operate with two colors:
1275  a background color and a foreground color. These combine together to make a patterned cell fill.
1276 
1277  No child elements.
1278 
1279  Parent elements:
1280  - [done] patternFill (§18.8.20)
1281 
1282  @todo support all elements
1283 */
1284 KoFilter::ConversionStatus XlsxXmlStylesReader::read_fgColor()
1285 {
1286     READ_PROLOGUE
1287 
1288     const QXmlStreamAttributes attrs(attributes());
1289 
1290     TRY_READ_ATTR_WITHOUT_NS(indexed)
1291     TRY_READ_ATTR_WITHOUT_NS(rgb)
1292     TRY_READ_ATTR_WITHOUT_NS(theme)
1293     TRY_READ_ATTR_WITHOUT_NS(tint)
1294 
1295     if (!indexed.isEmpty()) {
1296         int index = indexed.toInt();
1297         if (index >= 0 && index < 64) {
1298             m_currentFgColor = QString("#%1").arg(m_context->colorIndices.at(index));
1299         }
1300     }
1301     if (!rgb.isEmpty()) {
1302         m_currentFgColor = QString("#" + rgb.right(rgb.length()-2));
1303     }
1304     if (!theme.isEmpty()) {
1305         // Xlsx seems to switch these indices
1306         if (theme == "0" ) {
1307             theme = "1";
1308         }
1309         else if (theme == "1" ) {
1310             theme = "0";
1311         }
1312         else if (theme == "2") {
1313             theme = "3";
1314         }
1315         else if (theme == "3") {
1316             theme = "2";
1317         }
1318         MSOOXML::DrawingMLColorSchemeItemBase *colorItemBase = m_context->themes->colorScheme.value(theme);
1319         if (colorItemBase) {
1320             m_currentFgColor = colorItemBase->value();
1321         }
1322     }
1323     if (!tint.isEmpty()) {
1324         m_currentFgColor = tintedColor(m_currentFgColor, tint.toDouble());
1325     }
1326 
1327     readNext();
1328     READ_EPILOGUE
1329 }
1330 
1331 #undef CURRENT_EL
1332 #define CURRENT_EL gradientFill
1333 //! gradientFill handler (Pattern)
1334 /*! ECMA-376, 18.8.24, p. 1965.
1335  This element defines a gradient-style cell fill.
1336  Gradient cell fills can use one or two colors as the end points of color interpolation.
1337 
1338  Child elements:
1339  - stop (Gradient Stop) §18.8.38
1340  Parent elements:
1341  - [done] fill (§18.8.20)
1342 
1343  @todo support all elements
1344 */
1345 KoFilter::ConversionStatus XlsxXmlStylesReader::read_gradientFill()
1346 {
1347     Q_ASSERT(m_currentFillStyle);
1348     READ_PROLOGUE
1349 
1350 //! @todo read attributes for gradientFill
1351 
1352     while (!atEnd()) {
1353         readNext();
1354         BREAK_IF_END_OF(CURRENT_EL)
1355         if (isStartElement()) {
1356 //! @todo            TRY_READ_IF(stop)
1357 //todo            ELSE_WRONG_FORMAT
1358         }
1359     }
1360     READ_EPILOGUE
1361 }
1362 
1363 #undef CURRENT_EL
1364 #define CURRENT_EL borders
1365 //! 18.8.5 borders (Borders), p. 1951
1366 /*
1367  Parent elements:
1368  - [done] styleSheet (§18.8.39)
1369 
1370  Child elements:
1371  - [done] border (Border) §18.8.4
1372 
1373 */
1374 //! @todo support all elements
1375 KoFilter::ConversionStatus XlsxXmlStylesReader::read_borders()
1376 {
1377     READ_PROLOGUE
1378     if (!m_context->styles->borderStyles.isEmpty()) {
1379         raiseUnexpectedSecondOccurenceOfElError(STRINGIFY(CURRENT_EL));
1380     }
1381     const QXmlStreamAttributes attrs(attributes());
1382     TRY_READ_ATTR_WITHOUT_NS(count)
1383     uint countNumber = 0;
1384     STRING_TO_INT(count, countNumber, "styleSheet/borders@count")
1385     m_context->styles->borderStyles.resize(countNumber);
1386     uint borderStyleIndex = 0;
1387 
1388     while (!atEnd()) {
1389         readNext();
1390         BREAK_IF_END_OF(CURRENT_EL)
1391         if (isStartElement()) {
1392             if (QUALIFIED_NAME_IS(border)) {
1393                 m_currentBorderStyle = new KoGenStyle(KoGenStyle::TableCellAutoStyle, "table-cell");
1394                 if (borderStyleIndex >= (uint)m_context->styles->borderStyles.size()) {
1395                     raiseError(i18n("Declared number of fill styles too small (%1)", m_context->styles->borderStyles.size()));
1396                     return KoFilter::WrongFormat;
1397                 }
1398                 TRY_READ(border)
1399                 m_context->styles->borderStyles[borderStyleIndex] = m_currentBorderStyle;
1400                 m_currentBorderStyle = 0;
1401                 borderStyleIndex++;
1402             }
1403             ELSE_WRONG_FORMAT
1404         }
1405     }
1406     READ_EPILOGUE
1407 }
1408 
1409 #undef CURRENT_EL
1410 #define CURRENT_EL border
1411 //! 18.8.4 border (Border), p. 1949
1412 //! @todo support all elements
1413 KoFilter::ConversionStatus XlsxXmlStylesReader::read_border()
1414 {
1415     READ_PROLOGUE
1416     diagonalDirections = 0;
1417 
1418     if (readBooleanAttr("diagonalUp")) {
1419         diagonalDirections |= XlsxXmlStylesReader::DiagonalUp;
1420     }
1421     if (readBooleanAttr("diagonalDown")) {
1422         diagonalDirections |= XlsxXmlStylesReader::DiagonalDown;
1423     }
1424 
1425     while (!atEnd()) {
1426         readNext();
1427         BREAK_IF_END_OF(CURRENT_EL)
1428         if (isStartElement()) {
1429             TRY_READ_IF(bottom)
1430             ELSE_TRY_READ_IF(diagonal)
1431 //! @todo            ELSE_TRY_READ_IF(end)
1432 //! @todo (dxf only)            ELSE_TRY_READ_IF(horizontal)
1433             ELSE_TRY_READ_IF(left)
1434 //! @todo            ELSE_TRY_READ_IF(start)
1435             ELSE_TRY_READ_IF(right)
1436             ELSE_TRY_READ_IF(top)
1437             SKIP_UNKNOWN
1438 //! @todo (dxf only)            ELSE_TRY_READ_IF(vertical)
1439 //todo            ELSE_WRONG_FORMAT
1440         }
1441     }
1442 
1443     READ_EPILOGUE
1444 }
1445 
1446 #undef CURRENT_EL
1447 #define CURRENT_EL bottom
1448 //! 18.8.6 bottom (Bottom Border), p. 1952
1449 //! @todo support all elements
1450 KoFilter::ConversionStatus XlsxXmlStylesReader::read_bottom()
1451 {
1452     READ_PROLOGUE
1453     const QXmlStreamAttributes attrs(attributes());
1454 
1455     QString borderString;
1456     RETURN_IF_ERROR(readAttributes(attrs, borderString))
1457 
1458     m_currentColor = QColor();
1459 
1460     while (!atEnd()) {
1461         readNext();
1462         BREAK_IF_END_OF(CURRENT_EL)
1463         if (isStartElement()) {
1464             TRY_READ_IF(color)
1465             ELSE_WRONG_FORMAT
1466         }
1467     }
1468 
1469     if (m_currentColor.isValid()) {
1470         borderString += " " + m_currentColor.name();
1471     }
1472 
1473     if (!borderString.isEmpty()) {
1474         m_currentBorderStyle->addProperty("fo:border-bottom", borderString);
1475     }
1476 
1477     READ_EPILOGUE
1478 }
1479 
1480 #undef CURRENT_EL
1481 #define CURRENT_EL top
1482 //! 18.8.6 bottom (Bottom Border), p. 1952
1483 //! @todo support all elements
1484 KoFilter::ConversionStatus XlsxXmlStylesReader::read_top()
1485 {
1486     READ_PROLOGUE
1487     const QXmlStreamAttributes attrs(attributes());
1488 
1489     QString borderString;
1490     RETURN_IF_ERROR(readAttributes(attrs, borderString))
1491 
1492     m_currentColor = QColor();
1493 
1494     while (!atEnd()) {
1495         readNext();
1496         BREAK_IF_END_OF(CURRENT_EL)
1497         if (isStartElement()) {
1498             TRY_READ_IF(color)
1499             ELSE_WRONG_FORMAT
1500         }
1501     }
1502 
1503     if (m_currentColor.isValid()) {
1504         borderString += " " + m_currentColor.name();
1505     }
1506 
1507     if (!borderString.isEmpty()) {
1508         m_currentBorderStyle->addProperty("fo:border-top", borderString);
1509     }
1510 
1511     READ_EPILOGUE
1512 }
1513 
1514 #undef CURRENT_EL
1515 #define CURRENT_EL left
1516 //! @todo support all elements
1517 KoFilter::ConversionStatus XlsxXmlStylesReader::read_left()
1518 {
1519     READ_PROLOGUE
1520     const QXmlStreamAttributes attrs(attributes());
1521 
1522     QString borderString;
1523     RETURN_IF_ERROR(readAttributes(attrs, borderString))
1524 
1525     m_currentColor = QColor();
1526 
1527     while (!atEnd()) {
1528         readNext();
1529         BREAK_IF_END_OF(CURRENT_EL)
1530         if (isStartElement()) {
1531             TRY_READ_IF(color)
1532             ELSE_WRONG_FORMAT
1533         }
1534     }
1535 
1536     if (m_currentColor.isValid()) {
1537         borderString += " " + m_currentColor.name();
1538     }
1539 
1540     if (!borderString.isEmpty()) {
1541         m_currentBorderStyle->addProperty("fo:border-left", borderString);
1542     }
1543 
1544     READ_EPILOGUE
1545 }
1546 
1547 #undef CURRENT_EL
1548 #define CURRENT_EL right
1549 //! @todo support all elements
1550 KoFilter::ConversionStatus XlsxXmlStylesReader::read_right()
1551 {
1552     READ_PROLOGUE
1553     const QXmlStreamAttributes attrs(attributes());
1554 
1555     QString borderString;
1556     RETURN_IF_ERROR(readAttributes(attrs, borderString))
1557 
1558     m_currentColor = QColor();
1559 
1560     while (!atEnd()) {
1561         readNext();
1562         BREAK_IF_END_OF(CURRENT_EL)
1563         if (isStartElement()) {
1564             TRY_READ_IF(color)
1565             ELSE_WRONG_FORMAT
1566         }
1567     }
1568 
1569     if (m_currentColor.isValid()) {
1570         borderString += " " + m_currentColor.name();
1571     }
1572 
1573     if (!borderString.isEmpty()) {
1574         m_currentBorderStyle->addProperty("fo:border-right", borderString);
1575     }
1576 
1577     READ_EPILOGUE
1578 }
1579 
1580 #undef CURRENT_EL
1581 #define CURRENT_EL diagonal
1582 //! @todo support all elements
1583 KoFilter::ConversionStatus XlsxXmlStylesReader::read_diagonal()
1584 {
1585     READ_PROLOGUE
1586     const QXmlStreamAttributes attrs(attributes());
1587 
1588     QString borderString;
1589     RETURN_IF_ERROR(readAttributes(attrs, borderString))
1590 
1591     m_currentColor = QColor();
1592 
1593     while (!atEnd()) {
1594         readNext();
1595         BREAK_IF_END_OF(CURRENT_EL)
1596         if (isStartElement()) {
1597             TRY_READ_IF(color)
1598             ELSE_WRONG_FORMAT
1599         }
1600     }
1601 
1602     if (m_currentColor.isValid()) {
1603         borderString += " " + m_currentColor.name();
1604     }
1605 
1606     if (!borderString.isEmpty()) {
1607        if (diagonalDirections & DiagonalUp) {
1608             m_currentBorderStyle->addProperty("style:diagonal-bl-tr", borderString);
1609         }
1610         if (diagonalDirections & DiagonalDown) {
1611             m_currentBorderStyle->addProperty("style:diagonal-tl-br", borderString);
1612         }
1613     }
1614 
1615     READ_EPILOGUE
1616 }
1617 
1618 #undef CURRENT_EL
1619 #define CURRENT_EL colors
1620 /*
1621  Parent elements:
1622  - [done] styleSheet (§18.8.39)
1623 
1624  Child elements:
1625  - [done] indexedColors (Color Indexes) §18.8.27
1626  - mruColors (MRU Colors) §18.8.28
1627 */
1628 KoFilter::ConversionStatus XlsxXmlStylesReader::read_colors()
1629 {
1630     READ_PROLOGUE
1631 
1632     m_colorIndex = 0;
1633 
1634     while (!atEnd()) {
1635         readNext();
1636         BREAK_IF_END_OF(CURRENT_EL)
1637         if (isStartElement()) {
1638             TRY_READ_IF(indexedColors)
1639             SKIP_UNKNOWN
1640         }
1641     }
1642     READ_EPILOGUE
1643 }
1644 
1645 #undef CURRENT_EL
1646 #define CURRENT_EL indexedColors
1647 /*
1648  Parent elements:
1649  - [done] colors (§18.8.11)
1650 
1651  Child elements:
1652  - [done] rgbColor (RGB Color) §18.8.34
1653 */
1654 KoFilter::ConversionStatus XlsxXmlStylesReader::read_indexedColors()
1655 {
1656     READ_PROLOGUE
1657 
1658     // In this element, we override the default colors
1659 
1660     while (!atEnd()) {
1661         readNext();
1662         BREAK_IF_END_OF(CURRENT_EL)
1663         if (isStartElement()) {
1664             TRY_READ_IF(rgbColor)
1665             ELSE_WRONG_FORMAT
1666         }
1667     }
1668     READ_EPILOGUE
1669 }
1670 
1671 #undef CURRENT_EL
1672 #define CURRENT_EL rgbColor
1673 /*
1674  Parent elements:
1675  - [done] indexedColors (§18.8.27)
1676 
1677  Child elements:
1678  - none
1679 */
1680 KoFilter::ConversionStatus XlsxXmlStylesReader::read_rgbColor()
1681 {
1682     READ_PROLOGUE
1683     const QXmlStreamAttributes attrs(attributes());
1684 
1685     TRY_READ_ATTR_WITHOUT_NS(rgb)
1686     if (!rgb.isEmpty()) {
1687         m_context->colorIndices[m_colorIndex] = rgb.right(rgb.length()-2);
1688     }
1689     ++m_colorIndex;
1690     readNext();
1691     READ_EPILOGUE
1692 }
1693