File indexing completed on 2025-03-23 03:32:51
0001 // xlsxstyles.cpp 0002 0003 #include <QtGlobal> 0004 #include <QXmlStreamWriter> 0005 #include <QXmlStreamReader> 0006 #include <QFile> 0007 #include <QMap> 0008 #include <QDataStream> 0009 #include <QDebug> 0010 #include <QBuffer> 0011 0012 #include "xlsxglobal.h" 0013 #include "xlsxstyles_p.h" 0014 #include "xlsxformat_p.h" 0015 #include "xlsxutility_p.h" 0016 #include "xlsxcolor_p.h" 0017 0018 QT_BEGIN_NAMESPACE_XLSX 0019 0020 /* 0021 When loading from existing .xlsx file. we should create a clean styles object. 0022 otherwise, default formats should be added. 0023 0024 */ 0025 Styles::Styles(CreateFlag flag) 0026 : AbstractOOXmlFile(flag), m_nextCustomNumFmtId(176), m_isIndexedColorsDefault(true) 0027 , m_emptyFormatAdded(false) 0028 { 0029 //!Fix me. Should the custom num fmt Id starts with 164 or 176 or others?? 0030 0031 //!Fix me! Where should we put these register code? 0032 0033 // issue #172, #89 0034 #if QT_VERSION >= 0x060000 // Qt 6.0 or over 0035 if (QMetaType::fromName("XlsxColor").isRegistered()) 0036 #else 0037 if (QMetaType::type("XlsxColor") == QMetaType::UnknownType) 0038 #endif 0039 { 0040 qRegisterMetaType<XlsxColor>("XlsxColor"); 0041 0042 #if QT_VERSION >= 0x060000 0043 // Qt 6 0044 0045 ///TODO: 0046 0047 #else 0048 // Qt 5 0049 0050 qRegisterMetaTypeStreamOperators<XlsxColor>("XlsxColor"); 0051 0052 QMetaType::registerDebugStreamOperator<XlsxColor>(); 0053 0054 #endif 0055 } 0056 0057 if (flag == F_NewFromScratch) { 0058 //Add default Format 0059 Format defaultFmt; 0060 addXfFormat(defaultFmt); 0061 0062 //Add another fill format 0063 Format fillFmt; 0064 fillFmt.setFillPattern(Format::PatternGray125); 0065 m_fillsList.append(fillFmt); 0066 m_fillsHash.insert(fillFmt.fillKey(), fillFmt); 0067 } 0068 } 0069 0070 Styles::~Styles() 0071 { 0072 } 0073 0074 Format Styles::xfFormat(int idx) const 0075 { 0076 if (idx <0 || idx >= m_xf_formatsList.size()) 0077 return Format(); 0078 0079 return m_xf_formatsList[idx]; 0080 } 0081 0082 Format Styles::dxfFormat(int idx) const 0083 { 0084 if (idx <0 || idx >= m_dxf_formatsList.size()) 0085 return Format(); 0086 0087 return m_dxf_formatsList[idx]; 0088 } 0089 0090 // dev74 issue#57 0091 void Styles::fixNumFmt(const Format &format) 0092 { 0093 if (!format.hasNumFmtData()) 0094 return; 0095 0096 if (format.hasProperty(FormatPrivate::P_NumFmt_Id) 0097 && !format.stringProperty(FormatPrivate::P_NumFmt_FormatCode).isEmpty()) 0098 { 0099 return; 0100 } 0101 0102 if ( m_builtinNumFmtsHash.isEmpty() ) 0103 { 0104 m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0); 0105 m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1); 0106 m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2); 0107 m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3); 0108 m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4); 0109 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);($#,##0)"), 5); 0110 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);[Red]($#,##0)"), 6); 0111 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);($#,##0.00)"), 7); 0112 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);[Red]($#,##0.00)"), 8); 0113 m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9); 0114 m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10); 0115 m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11); 0116 m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12); 0117 m_builtinNumFmtsHash.insert(QStringLiteral("# ?\?/??"), 13);// Note: "??/" is a c++ trigraph, so escape one "?" 0118 m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14); 0119 m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15); 0120 m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16); 0121 m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17); 0122 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18); 0123 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19); 0124 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20); 0125 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21); 0126 m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22); 0127 0128 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37); 0129 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38); 0130 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39); 0131 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40); 0132 // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(_)"), 41); 0133 // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(_)"), 42); 0134 // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(_)"), 43); 0135 // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(_)"), 44); 0136 m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45); 0137 m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46); 0138 m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47); 0139 m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48); 0140 m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49); 0141 0142 // dev74 0143 // m_builtinNumFmtsHash.insert(QStringLiteral("0.####"), 176); 0144 0145 } 0146 0147 const auto& str = format.numberFormat(); 0148 if (!str.isEmpty()) 0149 { 0150 QHash<QString, QSharedPointer<XlsxFormatNumberData> >::ConstIterator cIt; 0151 //Assign proper number format index 0152 const auto& it = m_builtinNumFmtsHash.constFind(str); 0153 if (it != m_builtinNumFmtsHash.constEnd()) 0154 { 0155 const_cast<Format *>(&format)->fixNumberFormat(it.value(), str); 0156 } 0157 else if ((cIt = m_customNumFmtsHash.constFind(str)) != m_customNumFmtsHash.constEnd()) 0158 { 0159 const_cast<Format *>(&format)->fixNumberFormat(cIt.value()->formatIndex, str); 0160 } 0161 else 0162 { 0163 //Assign a new fmt Id. 0164 const_cast<Format *>(&format)->fixNumberFormat(m_nextCustomNumFmtId, str); 0165 0166 QSharedPointer<XlsxFormatNumberData> fmt(new XlsxFormatNumberData); 0167 fmt->formatIndex = m_nextCustomNumFmtId; 0168 fmt->formatString = str; 0169 m_customNumFmtIdMap.insert(m_nextCustomNumFmtId, fmt); 0170 m_customNumFmtsHash.insert(str, fmt); 0171 0172 m_nextCustomNumFmtId += 1; 0173 } 0174 } 0175 else 0176 { 0177 const auto id = format.numberFormatIndex(); 0178 //Assign proper format code, this is needed by dxf format 0179 const auto& it = m_customNumFmtIdMap.constFind(id); 0180 if (it != m_customNumFmtIdMap.constEnd()) 0181 { 0182 const_cast<Format *>(&format)->fixNumberFormat(id, it.value()->formatString); 0183 } 0184 else 0185 { 0186 bool found = false; 0187 for ( auto&& it = m_builtinNumFmtsHash.constBegin() ; it != m_builtinNumFmtsHash.constEnd() ; ++it ) 0188 { 0189 if (it.value() == id) 0190 { 0191 const_cast<Format *>(&format)->fixNumberFormat(id, it.key()); 0192 found = true; 0193 break; 0194 } 0195 } 0196 0197 if (!found) 0198 { 0199 //Wrong numFmt 0200 const_cast<Format *>(&format)->fixNumberFormat(id, QStringLiteral("General")); 0201 } 0202 } 0203 } 0204 } 0205 0206 /* 0207 Assign index to Font/Fill/Border and Format 0208 0209 When \a force is true, add the format to the format list, even other format has 0210 the same key have been in. 0211 This is useful when reading existing .xlsx files which may contains duplicated formats. 0212 */ 0213 void Styles::addXfFormat(const Format &format, bool force) 0214 { 0215 if (format.isEmpty()) 0216 { 0217 //Try do something for empty Format. 0218 if (m_emptyFormatAdded && !force) 0219 return; 0220 0221 m_emptyFormatAdded = true; 0222 } 0223 0224 //numFmt 0225 if (format.hasNumFmtData() && 0226 !format.hasProperty(FormatPrivate::P_NumFmt_Id)) 0227 { 0228 fixNumFmt(format); 0229 } 0230 0231 //Font 0232 const auto& fontIt = m_fontsHash.constFind(format.fontKey()); 0233 if (format.hasFontData() && !format.fontIndexValid()) 0234 { 0235 //Assign proper font index, if has font data. 0236 if (fontIt == m_fontsHash.constEnd()) 0237 const_cast<Format *>(&format)->setFontIndex(m_fontsList.size()); 0238 else 0239 const_cast<Format *>(&format)->setFontIndex(fontIt->fontIndex()); 0240 } 0241 if (fontIt == m_fontsHash.constEnd()) 0242 { 0243 //Still a valid font if the format has no fontData. (All font properties are default) 0244 m_fontsList.append(format); 0245 m_fontsHash[format.fontKey()] = format; 0246 } 0247 0248 //Fill 0249 const auto& fillIt = m_fillsHash.constFind(format.fillKey()); 0250 if (format.hasFillData() && !format.fillIndexValid()) { 0251 //Assign proper fill index, if has fill data. 0252 if (fillIt == m_fillsHash.constEnd()) 0253 const_cast<Format *>(&format)->setFillIndex(m_fillsList.size()); 0254 else 0255 const_cast<Format *>(&format)->setFillIndex(fillIt->fillIndex()); 0256 } 0257 if (fillIt == m_fillsHash.constEnd()) { 0258 //Still a valid fill if the format has no fillData. (All fill properties are default) 0259 m_fillsList.append(format); 0260 m_fillsHash[format.fillKey()] = format; 0261 } 0262 0263 //Border 0264 const auto& borderIt = m_bordersHash.constFind(format.borderKey()); 0265 if (format.hasBorderData() && !format.borderIndexValid()) { 0266 //Assign proper border index, if has border data. 0267 if (borderIt == m_bordersHash.constEnd()) 0268 const_cast<Format *>(&format)->setBorderIndex(m_bordersList.size()); 0269 else 0270 const_cast<Format *>(&format)->setBorderIndex(borderIt->borderIndex()); 0271 } 0272 if (borderIt == m_bordersHash.constEnd()) { 0273 //Still a valid border if the format has no borderData. (All border properties are default) 0274 m_bordersList.append(format); 0275 m_bordersHash[format.borderKey()] = format; 0276 } 0277 0278 //Format 0279 const auto& formatIt = m_xf_formatsHash.constFind(format.formatKey()); 0280 if (!format.isEmpty() && !format.xfIndexValid()) 0281 { 0282 if (formatIt == m_xf_formatsHash.constEnd()) 0283 const_cast<Format *>(&format)->setXfIndex(m_xf_formatsList.size()); 0284 else 0285 const_cast<Format *>(&format)->setXfIndex(formatIt->xfIndex()); 0286 } 0287 0288 if (formatIt == m_xf_formatsHash.constEnd() || 0289 force) 0290 { 0291 m_xf_formatsList.append(format); 0292 m_xf_formatsHash[format.formatKey()] = format; 0293 } 0294 } 0295 0296 void Styles::addDxfFormat(const Format &format, bool force) 0297 { 0298 //numFmt 0299 if ( format.hasNumFmtData() ) 0300 { 0301 fixNumFmt(format); 0302 } 0303 0304 const auto& formatIt = m_dxf_formatsHash.constFind(format.formatKey()); 0305 if ( !format.isEmpty() && 0306 !format.dxfIndexValid() ) 0307 { 0308 if (formatIt == m_dxf_formatsHash.constEnd() ) // m_xf_formatsHash.constEnd()) // issue #108 0309 { 0310 const_cast<Format *>(&format)->setDxfIndex( m_dxf_formatsList.size() ); 0311 } 0312 else 0313 { 0314 const_cast<Format *>(&format)->setDxfIndex( formatIt->dxfIndex() ); 0315 } 0316 } 0317 0318 if (formatIt == m_xf_formatsHash.constEnd() || 0319 force ) 0320 { 0321 m_dxf_formatsList.append(format); 0322 m_dxf_formatsHash[ format.formatKey() ] = format; 0323 } 0324 } 0325 0326 void Styles::saveToXmlFile(QIODevice *device) const 0327 { 0328 QXmlStreamWriter writer(device); 0329 0330 writer.writeStartDocument(QStringLiteral("1.0"), true); 0331 writer.writeStartElement(QStringLiteral("styleSheet")); 0332 writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main")); 0333 0334 writeNumFmts(writer); 0335 writeFonts(writer); 0336 writeFills(writer); 0337 writeBorders(writer); 0338 0339 writer.writeStartElement(QStringLiteral("cellStyleXfs")); 0340 writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1")); 0341 writer.writeStartElement(QStringLiteral("xf")); 0342 writer.writeAttribute(QStringLiteral("numFmtId"), QStringLiteral("0")); 0343 writer.writeAttribute(QStringLiteral("fontId"), QStringLiteral("0")); 0344 writer.writeAttribute(QStringLiteral("fillId"), QStringLiteral("0")); 0345 writer.writeAttribute(QStringLiteral("borderId"), QStringLiteral("0")); 0346 writer.writeEndElement();//xf 0347 writer.writeEndElement();//cellStyleXfs 0348 0349 writeCellXfs(writer); 0350 0351 writer.writeStartElement(QStringLiteral("cellStyles")); 0352 writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1")); 0353 writer.writeStartElement(QStringLiteral("cellStyle")); 0354 writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Normal")); 0355 writer.writeAttribute(QStringLiteral("xfId"), QStringLiteral("0")); 0356 writer.writeAttribute(QStringLiteral("builtinId"), QStringLiteral("0")); 0357 writer.writeEndElement();//cellStyle 0358 writer.writeEndElement();//cellStyles 0359 0360 writeDxfs(writer); 0361 0362 writer.writeStartElement(QStringLiteral("tableStyles")); 0363 writer.writeAttribute(QStringLiteral("count"), QStringLiteral("0")); 0364 writer.writeAttribute(QStringLiteral("defaultTableStyle"), QStringLiteral("TableStyleMedium9")); 0365 writer.writeAttribute(QStringLiteral("defaultPivotStyle"), QStringLiteral("PivotStyleLight16")); 0366 writer.writeEndElement();//tableStyles 0367 0368 writeColors(writer); 0369 0370 writer.writeEndElement();//styleSheet 0371 writer.writeEndDocument(); 0372 } 0373 0374 void Styles::writeNumFmts(QXmlStreamWriter &writer) const 0375 { 0376 if (m_customNumFmtIdMap.size() == 0) 0377 return; 0378 0379 writer.writeStartElement(QStringLiteral("numFmts")); 0380 writer.writeAttribute(QStringLiteral("count"), QString::number(m_customNumFmtIdMap.count())); 0381 0382 QMapIterator<int, QSharedPointer<XlsxFormatNumberData> > it(m_customNumFmtIdMap); 0383 while (it.hasNext()) { 0384 it.next(); 0385 writer.writeEmptyElement(QStringLiteral("numFmt")); 0386 writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(it.value()->formatIndex)); 0387 writer.writeAttribute(QStringLiteral("formatCode"), it.value()->formatString); 0388 } 0389 writer.writeEndElement();//numFmts 0390 } 0391 0392 /* 0393 */ 0394 void Styles::writeFonts(QXmlStreamWriter &writer) const 0395 { 0396 writer.writeStartElement(QStringLiteral("fonts")); 0397 writer.writeAttribute(QStringLiteral("count"), QString::number(m_fontsList.count())); 0398 for (const auto &font : m_fontsList) { 0399 writeFont(writer, font, false); 0400 } 0401 writer.writeEndElement();//fonts 0402 } 0403 0404 void Styles::writeFont(QXmlStreamWriter &writer, const Format &format, bool isDxf) const 0405 { 0406 writer.writeStartElement(QStringLiteral("font")); 0407 0408 //The condense and extend elements are mainly used in dxf format 0409 if (format.hasProperty(FormatPrivate::P_Font_Condense) 0410 && !format.boolProperty(FormatPrivate::P_Font_Condense)) { 0411 writer.writeEmptyElement(QStringLiteral("condense")); 0412 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); 0413 } 0414 if (format.hasProperty(FormatPrivate::P_Font_Extend) 0415 && !format.boolProperty(FormatPrivate::P_Font_Extend)) { 0416 writer.writeEmptyElement(QStringLiteral("extend")); 0417 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); 0418 } 0419 0420 if (format.fontBold()) 0421 writer.writeEmptyElement(QStringLiteral("b")); 0422 if (format.fontItalic()) 0423 writer.writeEmptyElement(QStringLiteral("i")); 0424 if (format.fontStrikeOut()) 0425 writer.writeEmptyElement(QStringLiteral("strike")); 0426 if (format.fontOutline()) 0427 writer.writeEmptyElement(QStringLiteral("outline")); 0428 if (format.boolProperty(FormatPrivate::P_Font_Shadow)) 0429 writer.writeEmptyElement(QStringLiteral("shadow")); 0430 if (format.hasProperty(FormatPrivate::P_Font_Underline)) { 0431 Format::FontUnderline u = format.fontUnderline(); 0432 if (u != Format::FontUnderlineNone) { 0433 writer.writeEmptyElement(QStringLiteral("u")); 0434 if (u== Format::FontUnderlineDouble) 0435 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double")); 0436 else if (u == Format::FontUnderlineSingleAccounting) 0437 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting")); 0438 else if (u == Format::FontUnderlineDoubleAccounting) 0439 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting")); 0440 } 0441 } 0442 if (format.hasProperty(FormatPrivate::P_Font_Script)) { 0443 Format::FontScript s = format.fontScript(); 0444 if (s != Format::FontScriptNormal) { 0445 writer.writeEmptyElement(QStringLiteral("vertAlign")); 0446 if (s == Format::FontScriptSuper) 0447 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript")); 0448 else 0449 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript")); 0450 } 0451 } 0452 0453 if (!isDxf && format.hasProperty(FormatPrivate::P_Font_Size)) { 0454 writer.writeEmptyElement(QStringLiteral("sz")); 0455 writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize())); 0456 } 0457 0458 if (format.hasProperty(FormatPrivate::P_Font_Color)) { 0459 XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>(); 0460 color.saveToXml(writer); 0461 } 0462 0463 if (!isDxf) { 0464 if (!format.fontName().isEmpty()) { 0465 writer.writeEmptyElement(QStringLiteral("name")); 0466 writer.writeAttribute(QStringLiteral("val"), format.fontName()); 0467 } 0468 if (format.hasProperty(FormatPrivate::P_Font_Charset)) { 0469 writer.writeEmptyElement(QStringLiteral("charset")); 0470 writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Charset))); 0471 } 0472 if (format.hasProperty(FormatPrivate::P_Font_Family)) { 0473 writer.writeEmptyElement(QStringLiteral("family")); 0474 writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family))); 0475 } 0476 0477 if (format.hasProperty(FormatPrivate::P_Font_Scheme)) { 0478 writer.writeEmptyElement(QStringLiteral("scheme")); 0479 writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme)); 0480 } 0481 } 0482 writer.writeEndElement(); //font 0483 } 0484 0485 void Styles::writeFills(QXmlStreamWriter &writer) const 0486 { 0487 writer.writeStartElement(QStringLiteral("fills")); 0488 writer.writeAttribute(QStringLiteral("count"), QString::number(m_fillsList.size())); 0489 0490 for (const auto &fill : m_fillsList) { 0491 writeFill(writer, fill); 0492 } 0493 0494 writer.writeEndElement(); //fills 0495 } 0496 0497 void Styles::writeFill(QXmlStreamWriter &writer, const Format &fill, bool isDxf) const 0498 { 0499 static const QMap<int, QString> patternStrings = { 0500 {Format::PatternNone, QStringLiteral("none")}, 0501 {Format::PatternSolid, QStringLiteral("solid")}, 0502 {Format::PatternMediumGray, QStringLiteral("mediumGray")}, 0503 {Format::PatternDarkGray, QStringLiteral("darkGray")}, 0504 {Format::PatternLightGray, QStringLiteral("lightGray")}, 0505 {Format::PatternDarkHorizontal, QStringLiteral("darkHorizontal")}, 0506 {Format::PatternDarkVertical, QStringLiteral("darkVertical")}, 0507 {Format::PatternDarkDown, QStringLiteral("darkDown")}, 0508 {Format::PatternDarkUp, QStringLiteral("darkUp")}, 0509 {Format::PatternDarkGrid, QStringLiteral("darkGrid")}, 0510 {Format::PatternDarkTrellis, QStringLiteral("darkTrellis")}, 0511 {Format::PatternLightHorizontal, QStringLiteral("lightHorizontal")}, 0512 {Format::PatternLightVertical, QStringLiteral("lightVertical")}, 0513 {Format::PatternLightDown, QStringLiteral("lightDown")}, 0514 {Format::PatternLightUp, QStringLiteral("lightUp")}, 0515 {Format::PatternLightTrellis, QStringLiteral("lightTrellis")}, 0516 {Format::PatternGray125, QStringLiteral("gray125")}, 0517 {Format::PatternGray0625, QStringLiteral("gray0625")}, 0518 {Format::PatternLightGrid, QStringLiteral("lightGrid")} 0519 }; 0520 0521 writer.writeStartElement(QStringLiteral("fill")); 0522 writer.writeStartElement(QStringLiteral("patternFill")); 0523 Format::FillPattern pattern = fill.fillPattern(); 0524 // For normal fill formats, Excel prefer to outputing the default "none" attribute 0525 // But for dxf, Excel prefer to omiting the default "none" 0526 // Though not make any difference, but it make easier to compare origin files with generate files during debug 0527 if (!(pattern == Format::PatternNone && isDxf)) 0528 writer.writeAttribute(QStringLiteral("patternType"), patternStrings[pattern]); 0529 // For a solid fill, Excel reverses the role of foreground and background colours 0530 if (fill.fillPattern() == Format::PatternSolid) { 0531 if (fill.hasProperty(FormatPrivate::P_Fill_BgColor)) 0532 fill.property(FormatPrivate::P_Fill_BgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("fgColor")); 0533 if (fill.hasProperty(FormatPrivate::P_Fill_FgColor)) 0534 fill.property(FormatPrivate::P_Fill_FgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("bgColor")); 0535 } else { 0536 if (fill.hasProperty(FormatPrivate::P_Fill_FgColor)) 0537 fill.property(FormatPrivate::P_Fill_FgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("fgColor")); 0538 if (fill.hasProperty(FormatPrivate::P_Fill_BgColor)) 0539 fill.property(FormatPrivate::P_Fill_BgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("bgColor")); 0540 } 0541 writer.writeEndElement();//patternFill 0542 writer.writeEndElement();//fill 0543 } 0544 0545 void Styles::writeBorders(QXmlStreamWriter &writer) const 0546 { 0547 writer.writeStartElement(QStringLiteral("borders")); 0548 writer.writeAttribute(QStringLiteral("count"), QString::number(m_bordersList.count())); 0549 0550 for (const auto &border : m_bordersList) { 0551 writeBorder(writer, border); 0552 } 0553 0554 writer.writeEndElement();//borders 0555 } 0556 0557 void Styles::writeBorder(QXmlStreamWriter &writer, const Format &border, bool isDxf) const 0558 { 0559 writer.writeStartElement(QStringLiteral("border")); 0560 if (border.hasProperty(FormatPrivate::P_Border_DiagonalType)) { 0561 Format::DiagonalBorderType t = border.diagonalBorderType(); 0562 if (t == Format::DiagonalBorderUp) { 0563 writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); 0564 } else if (t == Format::DiagonalBorderDown) { 0565 writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); 0566 } else if (t == Format::DiagnoalBorderBoth) { 0567 writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); 0568 writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); 0569 } 0570 } 0571 0572 writeSubBorder(writer, QStringLiteral("left"), border.leftBorderStyle(), border.property(FormatPrivate::P_Border_LeftColor).value<XlsxColor>()); 0573 writeSubBorder(writer, QStringLiteral("right"), border.rightBorderStyle(), border.property(FormatPrivate::P_Border_RightColor).value<XlsxColor>()); 0574 writeSubBorder(writer, QStringLiteral("top"), border.topBorderStyle(), border.property(FormatPrivate::P_Border_TopColor).value<XlsxColor>()); 0575 writeSubBorder(writer, QStringLiteral("bottom"), border.bottomBorderStyle(), border.property(FormatPrivate::P_Border_BottomColor).value<XlsxColor>()); 0576 0577 //Condition DXF formats don't allow diagonal style 0578 if (!isDxf) 0579 writeSubBorder(writer, QStringLiteral("diagonal"), border.diagonalBorderStyle(), border.property(FormatPrivate::P_Border_DiagonalColor).value<XlsxColor>()); 0580 0581 if (isDxf) { 0582 // writeSubBorder(wirter, QStringLiteral("vertical"), ); 0583 // writeSubBorder(writer, QStringLiteral("horizontal"), ); 0584 } 0585 0586 writer.writeEndElement();//border 0587 } 0588 0589 void Styles::writeSubBorder(QXmlStreamWriter &writer, const QString &type, int style, const XlsxColor &color) const 0590 { 0591 if (style == Format::BorderNone) { 0592 writer.writeEmptyElement(type); 0593 return; 0594 } 0595 0596 static const QMap<int, QString> stylesString = { 0597 {Format::BorderNone, QStringLiteral("none")}, 0598 {Format::BorderThin, QStringLiteral("thin")}, 0599 {Format::BorderMedium, QStringLiteral("medium")}, 0600 {Format::BorderDashed, QStringLiteral("dashed")}, 0601 {Format::BorderDotted, QStringLiteral("dotted")}, 0602 {Format::BorderThick, QStringLiteral("thick")}, 0603 {Format::BorderDouble, QStringLiteral("double")}, 0604 {Format::BorderHair, QStringLiteral("hair")}, 0605 {Format::BorderMediumDashed, QStringLiteral("mediumDashed")}, 0606 {Format::BorderDashDot, QStringLiteral("dashDot")}, 0607 {Format::BorderMediumDashDot, QStringLiteral("mediumDashDot")}, 0608 {Format::BorderDashDotDot, QStringLiteral("dashDotDot")}, 0609 {Format::BorderMediumDashDotDot, QStringLiteral("mediumDashDotDot")}, 0610 {Format::BorderSlantDashDot, QStringLiteral("slantDashDot")} 0611 }; 0612 0613 writer.writeStartElement(type); 0614 writer.writeAttribute(QStringLiteral("style"), stylesString[style]); 0615 color.saveToXml(writer); //write color element 0616 0617 writer.writeEndElement();//type 0618 } 0619 0620 void Styles::writeCellXfs(QXmlStreamWriter &writer) const 0621 { 0622 writer.writeStartElement(QStringLiteral("cellXfs")); 0623 writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size())); 0624 for (const Format &format : m_xf_formatsList) { 0625 int xf_id = 0; 0626 writer.writeStartElement(QStringLiteral("xf")); 0627 writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex())); 0628 writer.writeAttribute(QStringLiteral("fontId"), QString::number(format.fontIndex())); 0629 writer.writeAttribute(QStringLiteral("fillId"), QString::number(format.fillIndex())); 0630 writer.writeAttribute(QStringLiteral("borderId"), QString::number(format.borderIndex())); 0631 writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id)); 0632 if (format.hasNumFmtData()) 0633 writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1")); 0634 if (format.hasFontData()) 0635 writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1")); 0636 if (format.hasFillData()) 0637 writer.writeAttribute(QStringLiteral("applyFill"), QStringLiteral("1")); 0638 if (format.hasBorderData()) 0639 writer.writeAttribute(QStringLiteral("applyBorder"), QStringLiteral("1")); 0640 if (format.hasAlignmentData()) 0641 writer.writeAttribute(QStringLiteral("applyAlignment"), QStringLiteral("1")); 0642 0643 if (format.hasAlignmentData()) { 0644 writer.writeEmptyElement(QStringLiteral("alignment")); 0645 if (format.hasProperty(FormatPrivate::P_Alignment_AlignH)) { 0646 switch (format.horizontalAlignment()) { 0647 case Format::AlignLeft: 0648 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("left")); 0649 break; 0650 case Format::AlignHCenter: 0651 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("center")); 0652 break; 0653 case Format::AlignRight: 0654 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("right")); 0655 break; 0656 case Format::AlignHFill: 0657 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("fill")); 0658 break; 0659 case Format::AlignHJustify: 0660 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("justify")); 0661 break; 0662 case Format::AlignHMerge: 0663 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("centerContinuous")); 0664 break; 0665 case Format::AlignHDistributed: 0666 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("distributed")); 0667 break; 0668 default: 0669 break; 0670 } 0671 } 0672 0673 if (format.hasProperty(FormatPrivate::P_Alignment_AlignV)) { 0674 switch (format.verticalAlignment()) { 0675 case Format::AlignTop: 0676 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("top")); 0677 break; 0678 case Format::AlignVCenter: 0679 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("center")); 0680 break; 0681 case Format::AlignVJustify: 0682 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("justify")); 0683 break; 0684 case Format::AlignVDistributed: 0685 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("distributed")); 0686 break; 0687 default: 0688 break; 0689 } 0690 } 0691 if (format.hasProperty(FormatPrivate::P_Alignment_Indent)) 0692 writer.writeAttribute(QStringLiteral("indent"), QString::number(format.indent())); 0693 if (format.hasProperty(FormatPrivate::P_Alignment_Wrap) && format.textWrap()) 0694 writer.writeAttribute(QStringLiteral("wrapText"), QStringLiteral("1")); 0695 if (format.hasProperty(FormatPrivate::P_Alignment_ShinkToFit) && format.shrinkToFit()) 0696 writer.writeAttribute(QStringLiteral("shrinkToFit"), QStringLiteral("1")); 0697 if (format.hasProperty(FormatPrivate::P_Alignment_Rotation)) 0698 writer.writeAttribute(QStringLiteral("textRotation"), QString::number(format.rotation())); 0699 } 0700 0701 writer.writeEndElement();//xf 0702 } 0703 writer.writeEndElement();//cellXfs 0704 } 0705 0706 void Styles::writeDxfs(QXmlStreamWriter &writer) const 0707 { 0708 writer.writeStartElement(QStringLiteral("dxfs")); 0709 writer.writeAttribute(QStringLiteral("count"), QString::number(m_dxf_formatsList.size())); 0710 for (const Format &format : m_dxf_formatsList) 0711 writeDxf(writer, format); 0712 writer.writeEndElement(); //dxfs 0713 } 0714 0715 void Styles::writeDxf(QXmlStreamWriter &writer, const Format &format) const 0716 { 0717 writer.writeStartElement(QStringLiteral("dxf")); 0718 0719 if (format.hasFontData()) 0720 writeFont(writer, format, true); 0721 0722 if (format.hasNumFmtData()) { 0723 writer.writeEmptyElement(QStringLiteral("numFmt")); 0724 writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex())); 0725 writer.writeAttribute(QStringLiteral("formatCode"), format.numberFormat()); 0726 } 0727 0728 if (format.hasFillData()) 0729 writeFill(writer, format, true); 0730 0731 if (format.hasBorderData()) 0732 writeBorder(writer, format, true); 0733 0734 writer.writeEndElement();//dxf 0735 } 0736 0737 void Styles::writeColors(QXmlStreamWriter &writer) const 0738 { 0739 if (m_isIndexedColorsDefault) //Don't output the default indexdeColors 0740 return; 0741 0742 writer.writeStartElement(QStringLiteral("colors")); 0743 0744 writer.writeStartElement(QStringLiteral("indexedColors")); 0745 for (const QColor &color : m_indexedColors) { 0746 writer.writeEmptyElement(QStringLiteral("rgbColor")); 0747 writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(color)); 0748 } 0749 0750 writer.writeEndElement();//indexedColors 0751 0752 writer.writeEndElement();//colors 0753 } 0754 0755 bool Styles::readNumFmts(QXmlStreamReader &reader) 0756 { 0757 Q_ASSERT(reader.name() == QLatin1String("numFmts")); 0758 const auto& attributes = reader.attributes(); 0759 const auto hasCount = attributes.hasAttribute(QLatin1String("count")); 0760 const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; 0761 0762 //Read utill we find the numFmts end tag or .... 0763 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0764 && reader.name() == QLatin1String("numFmts"))) { 0765 reader.readNextStartElement(); 0766 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0767 if (reader.name() == QLatin1String("numFmt")) { 0768 const auto& attributes = reader.attributes(); 0769 QSharedPointer<XlsxFormatNumberData> fmt (new XlsxFormatNumberData); 0770 fmt->formatIndex = attributes.value(QLatin1String("numFmtId")).toInt(); 0771 fmt->formatString = attributes.value(QLatin1String("formatCode")).toString(); 0772 if (fmt->formatIndex >= m_nextCustomNumFmtId) 0773 m_nextCustomNumFmtId = fmt->formatIndex + 1; 0774 m_customNumFmtIdMap.insert(fmt->formatIndex, fmt); 0775 m_customNumFmtsHash.insert(fmt->formatString, fmt); 0776 } 0777 } 0778 } 0779 0780 if (reader.hasError()) 0781 qWarning()<<reader.errorString(); 0782 0783 if (hasCount && (count != m_customNumFmtIdMap.size())) 0784 qWarning("error read custom numFmts"); 0785 0786 return true; 0787 } 0788 0789 bool Styles::readFonts(QXmlStreamReader &reader) 0790 { 0791 Q_ASSERT(reader.name() == QLatin1String("fonts")); 0792 const auto& attributes = reader.attributes(); 0793 const auto hasCount = attributes.hasAttribute(QLatin1String("count")); 0794 const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; 0795 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0796 && reader.name() == QLatin1String("fonts"))) { 0797 reader.readNextStartElement(); 0798 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0799 if (reader.name() == QLatin1String("font")) { 0800 Format format; 0801 readFont(reader, format); 0802 m_fontsList.append(format); 0803 m_fontsHash.insert(format.fontKey(), format); 0804 if (format.isValid()) 0805 format.setFontIndex(m_fontsList.size()-1); 0806 } 0807 } 0808 } 0809 if (reader.hasError()) 0810 qWarning()<<reader.errorString(); 0811 0812 if (hasCount && (count != m_fontsList.size())) 0813 qWarning("error read fonts"); 0814 return true; 0815 } 0816 0817 bool Styles::readFont(QXmlStreamReader &reader, Format &format) 0818 { 0819 Q_ASSERT(reader.name() == QLatin1String("font")); 0820 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0821 && reader.name() == QLatin1String("font"))) { 0822 reader.readNextStartElement(); 0823 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0824 const auto& attributes = reader.attributes(); 0825 if (reader.name() == QLatin1String("name")) { 0826 format.setFontName(attributes.value(QLatin1String("val")).toString()); 0827 } else if (reader.name() == QLatin1String("charset")) { 0828 format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toInt()); 0829 } else if (reader.name() == QLatin1String("family")) { 0830 format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toInt()); 0831 } else if (reader.name() == QLatin1String("b")) { 0832 format.setFontBold(true); 0833 } else if (reader.name() == QLatin1String("i")) { 0834 format.setFontItalic(true); 0835 } else if (reader.name() == QLatin1String("strike")) { 0836 format.setFontStrikeOut(true); 0837 } else if (reader.name() == QLatin1String("outline")) { 0838 format.setFontOutline(true); 0839 } else if (reader.name() == QLatin1String("shadow")) { 0840 format.setProperty(FormatPrivate::P_Font_Shadow, true); 0841 } else if (reader.name() == QLatin1String("condense")) { 0842 format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toInt()); 0843 } else if (reader.name() == QLatin1String("extend")) { 0844 format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toInt()); 0845 } else if (reader.name() == QLatin1String("color")) { 0846 XlsxColor color; 0847 color.loadFromXml(reader); 0848 format.setProperty(FormatPrivate::P_Font_Color, color); 0849 } else if (reader.name() == QLatin1String("sz")) { 0850 const auto sz = attributes.value(QLatin1String("val")).toInt(); 0851 format.setFontSize(sz); 0852 } else if (reader.name() == QLatin1String("u")) { 0853 QString value = attributes.value(QLatin1String("val")).toString(); 0854 if (value == QLatin1String("double")) 0855 format.setFontUnderline(Format::FontUnderlineDouble); 0856 else if (value == QLatin1String("doubleAccounting")) 0857 format.setFontUnderline(Format::FontUnderlineDoubleAccounting); 0858 else if (value == QLatin1String("singleAccounting")) 0859 format.setFontUnderline(Format::FontUnderlineSingleAccounting); 0860 else 0861 format.setFontUnderline(Format::FontUnderlineSingle); 0862 } else if (reader.name() == QLatin1String("vertAlign")) { 0863 QString value = attributes.value(QLatin1String("val")).toString(); 0864 if (value == QLatin1String("superscript")) 0865 format.setFontScript(Format::FontScriptSuper); 0866 else if (value == QLatin1String("subscript")) 0867 format.setFontScript(Format::FontScriptSub); 0868 } else if (reader.name() == QLatin1String("scheme")) { 0869 format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString()); 0870 } 0871 } 0872 } 0873 return true; 0874 } 0875 0876 bool Styles::readFills(QXmlStreamReader &reader) 0877 { 0878 Q_ASSERT(reader.name() == QLatin1String("fills")); 0879 0880 const auto& attributes = reader.attributes(); 0881 const auto hasCount = attributes.hasAttribute(QLatin1String("count")); 0882 const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; 0883 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0884 && reader.name() == QLatin1String("fills"))) { 0885 reader.readNextStartElement(); 0886 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0887 if (reader.name() == QLatin1String("fill")) { 0888 Format fill; 0889 readFill(reader, fill); 0890 m_fillsList.append(fill); 0891 m_fillsHash.insert(fill.fillKey(), fill); 0892 if (fill.isValid()) 0893 fill.setFillIndex(m_fillsList.size()-1); 0894 } 0895 } 0896 } 0897 if (reader.hasError()) 0898 qWarning()<<reader.errorString(); 0899 0900 if (hasCount && (count != m_fillsList.size())) 0901 qWarning("error read fills"); 0902 return true; 0903 } 0904 0905 bool Styles::readFill(QXmlStreamReader &reader, Format &fill) 0906 { 0907 Q_ASSERT(reader.name() == QLatin1String("fill")); 0908 0909 static const QMap<QString, Format::FillPattern> patternValues = { 0910 {QStringLiteral("none"), Format::PatternNone}, 0911 {QStringLiteral("solid"), Format::PatternSolid}, 0912 {QStringLiteral("mediumGray"), Format::PatternMediumGray}, 0913 {QStringLiteral("darkGray"), Format::PatternDarkGray}, 0914 {QStringLiteral("lightGray"), Format::PatternLightGray}, 0915 {QStringLiteral("darkHorizontal"), Format::PatternDarkHorizontal}, 0916 {QStringLiteral("darkVertical"), Format::PatternDarkVertical}, 0917 {QStringLiteral("darkDown"), Format::PatternDarkDown}, 0918 {QStringLiteral("darkUp"), Format::PatternDarkUp}, 0919 {QStringLiteral("darkGrid"), Format::PatternDarkGrid}, 0920 {QStringLiteral("darkTrellis"), Format::PatternDarkTrellis}, 0921 {QStringLiteral("lightHorizontal"), Format::PatternLightHorizontal}, 0922 {QStringLiteral("lightVertical"), Format::PatternLightVertical}, 0923 {QStringLiteral("lightDown"), Format::PatternLightDown}, 0924 {QStringLiteral("lightUp"), Format::PatternLightUp}, 0925 {QStringLiteral("lightTrellis"), Format::PatternLightTrellis}, 0926 {QStringLiteral("gray125"), Format::PatternGray125}, 0927 {QStringLiteral("gray0625"), Format::PatternGray0625}, 0928 {QStringLiteral("lightGrid"), Format::PatternLightGrid} 0929 }; 0930 0931 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fill"))) { 0932 reader.readNextStartElement(); 0933 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0934 if (reader.name() == QLatin1String("patternFill")) { 0935 const auto& attributes = reader.attributes(); 0936 if (attributes.hasAttribute(QLatin1String("patternType"))) { 0937 const auto& it = patternValues.constFind(attributes.value(QLatin1String("patternType")).toString()); 0938 fill.setFillPattern(it != patternValues.constEnd() ? it.value() : Format::PatternNone); 0939 0940 //parse foreground and background colors if they exist 0941 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("patternFill"))) { 0942 reader.readNextStartElement(); 0943 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0944 if (reader.name() == QLatin1String("fgColor")) { 0945 XlsxColor c; 0946 if ( c.loadFromXml(reader) ) 0947 { 0948 if (fill.fillPattern() == Format::PatternSolid) 0949 fill.setProperty(FormatPrivate::P_Fill_BgColor, c); 0950 else 0951 fill.setProperty(FormatPrivate::P_Fill_FgColor, c); 0952 } 0953 } else if (reader.name() == QLatin1String("bgColor")) { 0954 XlsxColor c; 0955 if ( c.loadFromXml(reader) ) 0956 { 0957 if (fill.fillPattern() == Format::PatternSolid) 0958 fill.setProperty(FormatPrivate::P_Fill_FgColor, c); 0959 else 0960 fill.setProperty(FormatPrivate::P_Fill_BgColor, c); 0961 } 0962 } 0963 } 0964 } 0965 } 0966 } 0967 } 0968 } 0969 0970 return true; 0971 } 0972 0973 bool Styles::readBorders(QXmlStreamReader &reader) 0974 { 0975 Q_ASSERT(reader.name() == QLatin1String("borders")); 0976 0977 const auto& attributes = reader.attributes(); 0978 const auto hasCount = attributes.hasAttribute(QLatin1String("count")); 0979 const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; 0980 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 0981 && reader.name() == QLatin1String("borders"))) { 0982 reader.readNextStartElement(); 0983 if (reader.tokenType() == QXmlStreamReader::StartElement) { 0984 if (reader.name() == QLatin1String("border")) { 0985 Format border; 0986 readBorder(reader, border); 0987 m_bordersList.append(border); 0988 m_bordersHash.insert(border.borderKey(), border); 0989 if (border.isValid()) 0990 border.setBorderIndex(m_bordersList.size()-1); 0991 } 0992 } 0993 } 0994 0995 if (reader.hasError()) 0996 qWarning()<<reader.errorString(); 0997 0998 if (hasCount && (count != m_bordersList.size())) 0999 qWarning("error read borders"); 1000 1001 return true; 1002 } 1003 1004 bool Styles::readBorder(QXmlStreamReader &reader, Format &border) 1005 { 1006 Q_ASSERT(reader.name() == QLatin1String("border")); 1007 1008 const auto& attributes = reader.attributes(); 1009 const auto isUp = attributes.hasAttribute(QLatin1String("diagonalUp")); 1010 const auto isDown = attributes.hasAttribute(QLatin1String("diagonalDown")); 1011 if (isUp && isDown) 1012 border.setDiagonalBorderType(Format::DiagnoalBorderBoth); 1013 else if (isUp) 1014 border.setDiagonalBorderType(Format::DiagonalBorderUp); 1015 else if (isDown) 1016 border.setDiagonalBorderType(Format::DiagonalBorderDown); 1017 1018 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border"))) { 1019 reader.readNextStartElement(); 1020 if (reader.tokenType() == QXmlStreamReader::StartElement) { 1021 if (reader.name() == QLatin1String("left") || reader.name() == QLatin1String("right") 1022 || reader.name() == QLatin1String("top") || reader.name() == QLatin1String("bottom") 1023 || reader.name() == QLatin1String("diagonal") ) { 1024 Format::BorderStyle style(Format::BorderNone); 1025 XlsxColor color; 1026 readSubBorder(reader, reader.name().toString(), style, color); 1027 1028 if (reader.name() == QLatin1String("left")) { 1029 border.setLeftBorderStyle(style); 1030 if (!color.isInvalid()) 1031 border.setProperty(FormatPrivate::P_Border_LeftColor, color); 1032 } else if (reader.name() == QLatin1String("right")) { 1033 border.setRightBorderStyle(style); 1034 if (!color.isInvalid()) 1035 border.setProperty(FormatPrivate::P_Border_RightColor, color); 1036 } else if (reader.name() == QLatin1String("top")) { 1037 border.setTopBorderStyle(style); 1038 if (!color.isInvalid()) 1039 border.setProperty(FormatPrivate::P_Border_TopColor, color); 1040 } else if (reader.name() == QLatin1String("bottom")) { 1041 border.setBottomBorderStyle(style); 1042 if (!color.isInvalid()) 1043 border.setProperty(FormatPrivate::P_Border_BottomColor, color); 1044 } else if (reader.name() == QLatin1String("diagonal")) { 1045 border.setDiagonalBorderStyle(style); 1046 if (!color.isInvalid()) 1047 border.setProperty(FormatPrivate::P_Border_DiagonalColor, color); 1048 } 1049 } 1050 } 1051 1052 if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border")) 1053 break; 1054 } 1055 1056 return true; 1057 } 1058 1059 bool Styles::readCellStyleXfs(QXmlStreamReader &reader) 1060 { 1061 Q_UNUSED(reader); 1062 return true; 1063 } 1064 1065 bool Styles::readSubBorder(QXmlStreamReader &reader, const QString &name, Format::BorderStyle &style, XlsxColor &color) 1066 { 1067 Q_ASSERT(reader.name() == name); 1068 1069 static const QMap<QString, Format::BorderStyle> stylesStringsMap = { 1070 {QStringLiteral("none"), Format::BorderNone}, 1071 {QStringLiteral("thin"), Format::BorderThin}, 1072 {QStringLiteral("medium"), Format::BorderMedium}, 1073 {QStringLiteral("dashed"), Format::BorderDashed}, 1074 {QStringLiteral("dotted"), Format::BorderDotted}, 1075 {QStringLiteral("thick"), Format::BorderThick}, 1076 {QStringLiteral("double"), Format::BorderDouble}, 1077 {QStringLiteral("hair"), Format::BorderHair}, 1078 {QStringLiteral("mediumDashed"), Format::BorderMediumDashed}, 1079 {QStringLiteral("dashDot"), Format::BorderDashDot}, 1080 {QStringLiteral("mediumDashDot"), Format::BorderMediumDashDot}, 1081 {QStringLiteral("dashDotDot"), Format::BorderDashDotDot}, 1082 {QStringLiteral("mediumDashDotDot"), Format::BorderMediumDashDotDot}, 1083 {QStringLiteral("slantDashDot"), Format::BorderSlantDashDot} 1084 }; 1085 1086 const auto& attributes = reader.attributes(); 1087 if (attributes.hasAttribute(QLatin1String("style"))) { 1088 QString styleString = attributes.value(QLatin1String("style")).toString(); 1089 const auto& it = stylesStringsMap.constFind(styleString); 1090 if (it != stylesStringsMap.constEnd()) { 1091 //get style 1092 style = it.value(); 1093 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) { 1094 reader.readNextStartElement(); 1095 if (reader.tokenType() == QXmlStreamReader::StartElement) { 1096 if (reader.name() == QLatin1String("color")) 1097 color.loadFromXml(reader); 1098 } 1099 } 1100 } 1101 } 1102 1103 return true; 1104 } 1105 1106 bool Styles::readCellXfs(QXmlStreamReader &reader) 1107 { 1108 Q_ASSERT(reader.name() == QLatin1String("cellXfs")); 1109 const auto& attributes = reader.attributes(); 1110 const auto hasCount = attributes.hasAttribute(QLatin1String("count")); 1111 const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; 1112 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 1113 && reader.name() == QLatin1String("cellXfs"))) { 1114 reader.readNextStartElement(); 1115 if (reader.tokenType() == QXmlStreamReader::StartElement) { 1116 if (reader.name() == QLatin1String("xf")) { 1117 1118 Format format; 1119 const auto& xfAttrs = reader.attributes(); 1120 1121 // qDebug()<<reader.name()<<reader.tokenString()<<" ........."; 1122 // for (int i=0; i<xfAttrs.size(); ++i) 1123 // qDebug()<<"... "<<i<<" "<<xfAttrs[i].name()<<xfAttrs[i].value(); 1124 1125 if (xfAttrs.hasAttribute(QLatin1String("numFmtId"))) { 1126 const auto numFmtIndex = xfAttrs.value(QLatin1String("numFmtId")).toInt(); 1127 const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyNumberFormat")).toString()); 1128 if(apply) { 1129 const auto& it = m_customNumFmtIdMap.constFind(numFmtIndex); 1130 if (it == m_customNumFmtIdMap.constEnd()) 1131 format.setNumberFormatIndex(numFmtIndex); 1132 else 1133 format.setNumberFormat(numFmtIndex, it.value()->formatString); 1134 } 1135 } 1136 1137 if (xfAttrs.hasAttribute(QLatin1String("fontId"))) { 1138 const auto fontIndex = xfAttrs.value(QLatin1String("fontId")).toInt(); 1139 if (fontIndex >= m_fontsList.size()) { 1140 qDebug("Error read styles.xml, cellXfs fontId"); 1141 } else { 1142 const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFont")).toString()); 1143 if(apply) { 1144 Format fontFormat = m_fontsList[fontIndex]; 1145 for (int i=FormatPrivate::P_Font_STARTID; i<FormatPrivate::P_Font_ENDID; ++i) { 1146 if (fontFormat.hasProperty(i)) 1147 format.setProperty(i, fontFormat.property(i)); 1148 } 1149 } 1150 } 1151 } 1152 1153 if (xfAttrs.hasAttribute(QLatin1String("fillId"))) { 1154 const auto id = xfAttrs.value(QLatin1String("fillId")).toInt(); 1155 if (id >= m_fillsList.size()) { 1156 qDebug("Error read styles.xml, cellXfs fillId"); 1157 } else { 1158 1159 // dev20 branch 1160 // NOTE: MIcrosoft Excel does not have 'applyFill' tag. 1161 // 1162 1163 // bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFill")).toString()); 1164 // if (apply) 1165 1166 { 1167 Format fillFormat = m_fillsList[id]; 1168 for (int i=FormatPrivate::P_Fill_STARTID; i<FormatPrivate::P_Fill_ENDID; ++i) 1169 { 1170 if (fillFormat.hasProperty(i)) 1171 format.setProperty(i, fillFormat.property(i)); 1172 } 1173 } 1174 1175 } 1176 } 1177 1178 if (xfAttrs.hasAttribute(QLatin1String("borderId"))) { 1179 const auto id = xfAttrs.value(QLatin1String("borderId")).toInt(); 1180 if (id >= m_bordersList.size()) { 1181 qDebug("Error read styles.xml, cellXfs borderId"); 1182 } else { 1183 const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyBorder")).toString()); 1184 if(apply) { 1185 Format borderFormat = m_bordersList[id]; 1186 for (int i=FormatPrivate::P_Border_STARTID; i<FormatPrivate::P_Border_ENDID; ++i) { 1187 if (borderFormat.hasProperty(i)) 1188 format.setProperty(i, borderFormat.property(i)); 1189 } 1190 } 1191 } 1192 } 1193 1194 const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyAlignment")).toString()); 1195 if(apply) { 1196 reader.readNextStartElement(); 1197 if (reader.name() == QLatin1String("alignment")) { 1198 const auto& alignAttrs = reader.attributes(); 1199 1200 if (alignAttrs.hasAttribute(QLatin1String("horizontal"))) { 1201 static const QMap<QString, Format::HorizontalAlignment> alignStringMap = { 1202 {QStringLiteral("left"), Format::AlignLeft}, 1203 {QStringLiteral("center"), Format::AlignHCenter}, 1204 {QStringLiteral("right"), Format::AlignRight}, 1205 {QStringLiteral("justify"), Format::AlignHJustify}, 1206 {QStringLiteral("centerContinuous"), Format::AlignHMerge}, 1207 {QStringLiteral("distributed"), Format::AlignHDistributed} 1208 }; 1209 1210 const auto& it = alignStringMap.constFind(alignAttrs.value(QLatin1String("horizontal")).toString()); 1211 if (it != alignStringMap.constEnd()) 1212 format.setHorizontalAlignment(it.value()); 1213 } 1214 1215 if (alignAttrs.hasAttribute(QLatin1String("vertical"))) { 1216 static const QMap<QString, Format::VerticalAlignment> alignStringMap = { 1217 {QStringLiteral("top"), Format::AlignTop}, 1218 {QStringLiteral("center"), Format::AlignVCenter}, 1219 {QStringLiteral("justify"), Format::AlignVJustify}, 1220 {QStringLiteral("distributed"), Format::AlignVDistributed} 1221 }; 1222 1223 const auto& it = alignStringMap.constFind(alignAttrs.value(QLatin1String("vertical")).toString()); 1224 if (it != alignStringMap.constEnd()) 1225 format.setVerticalAlignment(it.value()); 1226 } 1227 1228 if (alignAttrs.hasAttribute(QLatin1String("indent"))) { 1229 const auto indent = alignAttrs.value(QLatin1String("indent")).toInt(); 1230 format.setIndent(indent); 1231 } 1232 1233 if (alignAttrs.hasAttribute(QLatin1String("textRotation"))) { 1234 const auto rotation = alignAttrs.value(QLatin1String("textRotation")).toInt(); 1235 format.setRotation(rotation); 1236 } 1237 1238 if (alignAttrs.hasAttribute(QLatin1String("wrapText"))) 1239 format.setTextWrap(true); 1240 1241 if (alignAttrs.hasAttribute(QLatin1String("shrinkToFit"))) 1242 format.setShrinkToFit(true); 1243 1244 } 1245 } 1246 1247 addXfFormat(format, true); 1248 } 1249 } 1250 } 1251 1252 if (reader.hasError()) 1253 qWarning()<<reader.errorString(); 1254 1255 if (hasCount && (count != m_xf_formatsList.size())) 1256 qWarning("error read CellXfs"); 1257 1258 return true; 1259 } 1260 1261 bool Styles::readDxfs(QXmlStreamReader &reader) 1262 { 1263 Q_ASSERT(reader.name() == QLatin1String("dxfs")); 1264 const auto& attributes = reader.attributes(); 1265 const auto hasCount = attributes.hasAttribute(QLatin1String("count")); 1266 const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; 1267 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement 1268 && reader.name() == QLatin1String("dxfs"))) { 1269 reader.readNextStartElement(); 1270 if (reader.tokenType() == QXmlStreamReader::StartElement) { 1271 if (reader.name() == QLatin1String("dxf")) 1272 readDxf(reader); 1273 } 1274 } 1275 if (reader.hasError()) 1276 qWarning()<<reader.errorString(); 1277 1278 if (hasCount && (count != m_dxf_formatsList.size())) 1279 qWarning("error read dxfs"); 1280 1281 return true; 1282 } 1283 1284 bool Styles::readDxf(QXmlStreamReader &reader) 1285 { 1286 Q_ASSERT(reader.name() == QLatin1String("dxf")); 1287 Format format; 1288 while (!reader.atEnd() && !(reader.name() == QLatin1String("dxf") && reader.tokenType() == QXmlStreamReader::EndElement)) { 1289 reader.readNextStartElement(); 1290 if (reader.tokenType() == QXmlStreamReader::StartElement) { 1291 if (reader.name() == QLatin1String("numFmt")) { 1292 const auto& attributes = reader.attributes(); 1293 const auto id = attributes.value(QLatin1String("numFmtId")).toInt(); 1294 QString code = attributes.value(QLatin1String("formatCode")).toString(); 1295 format.setNumberFormat(id, code); 1296 } else if (reader.name() == QLatin1String("font")) { 1297 readFont(reader, format); 1298 } else if (reader.name() == QLatin1String("fill")) { 1299 readFill(reader, format); 1300 } else if (reader.name() == QLatin1String("border")) { 1301 readBorder(reader, format); 1302 } 1303 } 1304 } 1305 addDxfFormat(format, true); 1306 return true; 1307 } 1308 1309 bool Styles::readColors(QXmlStreamReader &reader) 1310 { 1311 Q_ASSERT(reader.name() == QLatin1String("colors")); 1312 while (!reader.atEnd() && !(reader.name() == QLatin1String("colors") && reader.tokenType() == QXmlStreamReader::EndElement)) { 1313 reader.readNextStartElement(); 1314 if (reader.tokenType() == QXmlStreamReader::StartElement) { 1315 if (reader.name() == QLatin1String("indexedColors")) { 1316 readIndexedColors(reader); 1317 } else if (reader.name() == QLatin1String("mruColors")) { 1318 1319 } 1320 } 1321 } 1322 return true; 1323 } 1324 1325 bool Styles::readIndexedColors(QXmlStreamReader &reader) 1326 { 1327 Q_ASSERT(reader.name() == QLatin1String("indexedColors")); 1328 m_indexedColors.clear(); 1329 while (!reader.atEnd() && !(reader.name() == QLatin1String("indexedColors") && reader.tokenType() == QXmlStreamReader::EndElement)) { 1330 reader.readNextStartElement(); 1331 if (reader.tokenType() == QXmlStreamReader::StartElement) { 1332 if (reader.name() == QLatin1String("rgbColor")) { 1333 const auto& color = reader.attributes().value(QLatin1String("rgb")).toString(); 1334 m_indexedColors.append(XlsxColor::fromARGBString(color)); 1335 } 1336 } 1337 } 1338 if (!m_indexedColors.isEmpty()) 1339 m_isIndexedColorsDefault = false; 1340 return true; 1341 } 1342 1343 bool Styles::loadFromXmlFile(QIODevice *device) 1344 { 1345 QXmlStreamReader reader(device); 1346 while (!reader.atEnd()) { 1347 QXmlStreamReader::TokenType token = reader.readNext(); 1348 if (token == QXmlStreamReader::StartElement) { 1349 if (reader.name() == QLatin1String("numFmts")) { 1350 readNumFmts(reader); 1351 } else if (reader.name() == QLatin1String("fonts")) { 1352 readFonts(reader); 1353 } else if (reader.name() == QLatin1String("fills")) { 1354 readFills(reader); 1355 } else if (reader.name() == QLatin1String("borders")) { 1356 readBorders(reader); 1357 } else if (reader.name() == QLatin1String("cellStyleXfs")) { 1358 1359 readCellStyleXfs(reader); 1360 1361 } else if (reader.name() == QLatin1String("cellXfs")) { 1362 readCellXfs(reader); 1363 } else if (reader.name() == QLatin1String("cellStyles")) { 1364 1365 // cellStyles 1366 1367 } else if (reader.name() == QLatin1String("dxfs")) { 1368 readDxfs(reader); 1369 } else if (reader.name() == QLatin1String("colors")) { 1370 readColors(reader); 1371 } 1372 } 1373 1374 if (reader.hasError()) { 1375 qDebug()<<"Error when read style file: "<<reader.errorString(); 1376 } 1377 } 1378 return true; 1379 } 1380 1381 QColor Styles::getColorByIndex(int idx) 1382 { 1383 if (m_indexedColors.isEmpty()) { 1384 m_indexedColors = { 1385 QColor(QRgba64::fromArgb32(0x000000)), QColor(QRgba64::fromArgb32(0xFFFFFF)), QColor(QRgba64::fromArgb32(0xFF0000)), QColor(QRgba64::fromArgb32(0x00FF00)), 1386 QColor(QRgba64::fromArgb32(0x0000FF)), QColor(QRgba64::fromArgb32(0xFFFF00)), QColor(QRgba64::fromArgb32(0xFF00FF)), QColor(QRgba64::fromArgb32(0x00FFFF)), 1387 QColor(QRgba64::fromArgb32(0x000000)), QColor(QRgba64::fromArgb32(0xFFFFFF)), QColor(QRgba64::fromArgb32(0xFF0000)), QColor(QRgba64::fromArgb32(0x00FF00)), 1388 QColor(QRgba64::fromArgb32(0x0000FF)), QColor(QRgba64::fromArgb32(0xFFFF00)), QColor(QRgba64::fromArgb32(0xFF00FF)), QColor(QRgba64::fromArgb32(0x00FFFF)), 1389 QColor(QRgba64::fromArgb32(0x800000)), QColor(QRgba64::fromArgb32(0x008000)), QColor(QRgba64::fromArgb32(0x000080)), QColor(QRgba64::fromArgb32(0x808000)), 1390 QColor(QRgba64::fromArgb32(0x800080)), QColor(QRgba64::fromArgb32(0x008080)), QColor(QRgba64::fromArgb32(0xC0C0C0)), QColor(QRgba64::fromArgb32(0x808080)), 1391 QColor(QRgba64::fromArgb32(0x9999FF)), QColor(QRgba64::fromArgb32(0x993366)), QColor(QRgba64::fromArgb32(0xFFFFCC)), QColor(QRgba64::fromArgb32(0xCCFFFF)), 1392 QColor(QRgba64::fromArgb32(0x660066)), QColor(QRgba64::fromArgb32(0xFF8080)), QColor(QRgba64::fromArgb32(0x0066CC)), QColor(QRgba64::fromArgb32(0xCCCCFF)), 1393 QColor(QRgba64::fromArgb32(0x000080)), QColor(QRgba64::fromArgb32(0xFF00FF)), QColor(QRgba64::fromArgb32(0xFFFF00)), QColor(QRgba64::fromArgb32(0x00FFFF)), 1394 QColor(QRgba64::fromArgb32(0x800080)), QColor(QRgba64::fromArgb32(0x800000)), QColor(QRgba64::fromArgb32(0x008080)), QColor(QRgba64::fromArgb32(0x0000FF)), 1395 QColor(QRgba64::fromArgb32(0x00CCFF)), QColor(QRgba64::fromArgb32(0xCCFFFF)), QColor(QRgba64::fromArgb32(0xCCFFCC)), QColor(QRgba64::fromArgb32(0xFFFF99)), 1396 QColor(QRgba64::fromArgb32(0x99CCFF)), QColor(QRgba64::fromArgb32(0xFF99CC)), QColor(QRgba64::fromArgb32(0xCC99FF)), QColor(QRgba64::fromArgb32(0xFFCC99)), 1397 QColor(QRgba64::fromArgb32(0x3366FF)), QColor(QRgba64::fromArgb32(0x33CCCC)), QColor(QRgba64::fromArgb32(0x99CC00)), QColor(QRgba64::fromArgb32(0xFFCC00)), 1398 QColor(QRgba64::fromArgb32(0xFF9900)), QColor(QRgba64::fromArgb32(0xFF6600)), QColor(QRgba64::fromArgb32(0x666699)), QColor(QRgba64::fromArgb32(0x969696)), 1399 QColor(QRgba64::fromArgb32(0x003366)), QColor(QRgba64::fromArgb32(0x339966)), QColor(QRgba64::fromArgb32(0x003300)), QColor(QRgba64::fromArgb32(0x333300)), 1400 QColor(QRgba64::fromArgb32(0x993300)), QColor(QRgba64::fromArgb32(0x993366)), QColor(QRgba64::fromArgb32(0x333399)), QColor(QRgba64::fromArgb32(0x333333)), 1401 }; 1402 m_isIndexedColorsDefault = true; 1403 } 1404 if (idx < 0 || idx >= m_indexedColors.size()) 1405 return QColor(); 1406 return m_indexedColors[idx]; 1407 } 1408 1409 QT_END_NAMESPACE_XLSX