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