// xlsxstyles.cpp #include "xlsxcolor_p.h" #include "xlsxformat_p.h" #include "xlsxglobal.h" #include "xlsxstyles_p.h" #include "xlsxutility_p.h" #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE_XLSX /* When loading from existing .xlsx file. we should create a clean styles object. otherwise, default formats should be added. */ Styles::Styles(CreateFlag flag) : AbstractOOXmlFile(flag) , m_nextCustomNumFmtId(176) , m_isIndexedColorsDefault(true) , m_emptyFormatAdded(false) { //! Fix me. Should the custom num fmt Id starts with 164 or 176 or others?? //! Fix me! Where should we put these register code? // issue #172, #89 #if QT_VERSION >= 0x060000 // Qt 6.0 or over if (QMetaType::fromName("XlsxColor").isRegistered()) #else if (QMetaType::type("XlsxColor") == QMetaType::UnknownType) #endif { qRegisterMetaType("XlsxColor"); #if QT_VERSION >= 0x060000 // Qt 6 /// TODO: #else // Qt 5 qRegisterMetaTypeStreamOperators("XlsxColor"); QMetaType::registerDebugStreamOperator(); #endif } if (flag == F_NewFromScratch) { // Add default Format Format defaultFmt; addXfFormat(defaultFmt); // Add another fill format Format fillFmt; fillFmt.setFillPattern(Format::PatternGray125); m_fillsList.append(fillFmt); m_fillsHash.insert(fillFmt.fillKey(), fillFmt); } } Styles::~Styles() { } Format Styles::xfFormat(int idx) const { if (idx < 0 || idx >= m_xf_formatsList.size()) return Format(); return m_xf_formatsList[idx]; } Format Styles::dxfFormat(int idx) const { if (idx < 0 || idx >= m_dxf_formatsList.size()) return Format(); return m_dxf_formatsList[idx]; } // dev74 issue#57 void Styles::fixNumFmt(const Format &format) { if (!format.hasNumFmtData()) return; if (format.hasProperty(FormatPrivate::P_NumFmt_Id) && !format.stringProperty(FormatPrivate::P_NumFmt_FormatCode).isEmpty()) { return; } if (m_builtinNumFmtsHash.isEmpty()) { m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0); m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1); m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2); m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3); m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);($#,##0)"), 5); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);[Red]($#,##0)"), 6); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);($#,##0.00)"), 7); // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);[Red]($#,##0.00)"), // 8); m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9); m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10); m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11); m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12); m_builtinNumFmtsHash.insert(QStringLiteral("# ?\?/??"), 13); // Note: "??/" is a c++ trigraph, so escape one "?" m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14); m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15); m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16); m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17); m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18); m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19); m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20); m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21); m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22); m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37); m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38); m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39); m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40); // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0_);_(* (#,##0);_(* // \"-\"_);_(_)"), 41); m_builtinNumFmtsHash.insert(QStringLiteral("_($* // #,##0_);_($* (#,##0);_($* \"-\"_);_(_)"), 42); // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0.00_);_(* (#,##0.00);_(* // \"-\"??_);_(_)"), 43); m_builtinNumFmtsHash.insert(QStringLiteral("_($* // #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(_)"), 44); m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45); m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46); m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47); m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48); m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49); // dev74 // m_builtinNumFmtsHash.insert(QStringLiteral("0.####"), 176); } const auto &str = format.numberFormat(); if (!str.isEmpty()) { // Assign proper number format index const auto &it = m_builtinNumFmtsHash.constFind(str); if (it != m_builtinNumFmtsHash.constEnd()) { const_cast(&format)->fixNumberFormat(it.value(), str); } else { auto cIt = m_customNumFmtsHash.constFind(str); if (cIt != m_customNumFmtsHash.constEnd()) { const_cast(&format)->fixNumberFormat(cIt.value()->formatIndex, str); } else { // Assign a new fmt Id. const_cast(&format)->fixNumberFormat(m_nextCustomNumFmtId, str); auto fmt = std::make_shared(); fmt->formatIndex = m_nextCustomNumFmtId; fmt->formatString = str; m_customNumFmtIdMap.insert(m_nextCustomNumFmtId, fmt); m_customNumFmtsHash.insert(str, fmt); m_nextCustomNumFmtId += 1; } } } else { const auto id = format.numberFormatIndex(); // Assign proper format code, this is needed by dxf format const auto &it = m_customNumFmtIdMap.constFind(id); if (it != m_customNumFmtIdMap.constEnd()) { const_cast(&format)->fixNumberFormat(id, it.value()->formatString); } else { bool found = false; for (auto &&it = m_builtinNumFmtsHash.constBegin(); it != m_builtinNumFmtsHash.constEnd(); ++it) { if (it.value() == id) { const_cast(&format)->fixNumberFormat(id, it.key()); found = true; break; } } if (!found) { // Wrong numFmt const_cast(&format)->fixNumberFormat(id, QStringLiteral("General")); } } } } /* Assign index to Font/Fill/Border and Format When \a force is true, add the format to the format list, even other format has the same key have been in. This is useful when reading existing .xlsx files which may contains duplicated formats. */ void Styles::addXfFormat(const Format &format, bool force) { if (format.isEmpty()) { // Try do something for empty Format. if (m_emptyFormatAdded && !force) return; m_emptyFormatAdded = true; } // numFmt if (format.hasNumFmtData() && !format.hasProperty(FormatPrivate::P_NumFmt_Id)) { fixNumFmt(format); } // Font const auto &fontIt = m_fontsHash.constFind(format.fontKey()); if (format.hasFontData() && !format.fontIndexValid()) { // Assign proper font index, if has font data. if (fontIt == m_fontsHash.constEnd()) const_cast(&format)->setFontIndex(m_fontsList.size()); else const_cast(&format)->setFontIndex(fontIt->fontIndex()); } if (fontIt == m_fontsHash.constEnd()) { // Still a valid font if the format has no fontData. (All font properties are default) m_fontsList.append(format); m_fontsHash[format.fontKey()] = format; } // Fill const auto &fillIt = m_fillsHash.constFind(format.fillKey()); if (format.hasFillData() && !format.fillIndexValid()) { // Assign proper fill index, if has fill data. if (fillIt == m_fillsHash.constEnd()) const_cast(&format)->setFillIndex(m_fillsList.size()); else const_cast(&format)->setFillIndex(fillIt->fillIndex()); } if (fillIt == m_fillsHash.constEnd()) { // Still a valid fill if the format has no fillData. (All fill properties are default) m_fillsList.append(format); m_fillsHash[format.fillKey()] = format; } // Border const auto &borderIt = m_bordersHash.constFind(format.borderKey()); if (format.hasBorderData() && !format.borderIndexValid()) { // Assign proper border index, if has border data. if (borderIt == m_bordersHash.constEnd()) const_cast(&format)->setBorderIndex(m_bordersList.size()); else const_cast(&format)->setBorderIndex(borderIt->borderIndex()); } if (borderIt == m_bordersHash.constEnd()) { // Still a valid border if the format has no borderData. (All border properties are default) m_bordersList.append(format); m_bordersHash[format.borderKey()] = format; } // Format const auto &formatIt = m_xf_formatsHash.constFind(format.formatKey()); if (!format.isEmpty() && !format.xfIndexValid()) { if (formatIt == m_xf_formatsHash.constEnd()) const_cast(&format)->setXfIndex(m_xf_formatsList.size()); else const_cast(&format)->setXfIndex(formatIt->xfIndex()); } if (formatIt == m_xf_formatsHash.constEnd() || force) { m_xf_formatsList.append(format); m_xf_formatsHash[format.formatKey()] = format; } } void Styles::addDxfFormat(const Format &format, bool force) { // numFmt if (format.hasNumFmtData()) { fixNumFmt(format); } const auto &formatIt = m_dxf_formatsHash.constFind(format.formatKey()); if (!format.isEmpty() && !format.dxfIndexValid()) { if (formatIt == m_dxf_formatsHash.constEnd()) // m_xf_formatsHash.constEnd()) // issue #108 { const_cast(&format)->setDxfIndex(m_dxf_formatsList.size()); } else { const_cast(&format)->setDxfIndex(formatIt->dxfIndex()); } } if (formatIt == m_xf_formatsHash.constEnd() || force) { m_dxf_formatsList.append(format); m_dxf_formatsHash[format.formatKey()] = format; } } void Styles::saveToXmlFile(QIODevice *device) const { QXmlStreamWriter writer(device); writer.writeStartDocument(QStringLiteral("1.0"), true); writer.writeStartElement(QStringLiteral("styleSheet")); writer.writeAttribute( QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main")); writeNumFmts(writer); writeFonts(writer); writeFills(writer); writeBorders(writer); writer.writeStartElement(QStringLiteral("cellStyleXfs")); writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1")); writer.writeStartElement(QStringLiteral("xf")); writer.writeAttribute(QStringLiteral("numFmtId"), QStringLiteral("0")); writer.writeAttribute(QStringLiteral("fontId"), QStringLiteral("0")); writer.writeAttribute(QStringLiteral("fillId"), QStringLiteral("0")); writer.writeAttribute(QStringLiteral("borderId"), QStringLiteral("0")); writer.writeEndElement(); // xf writer.writeEndElement(); // cellStyleXfs writeCellXfs(writer); writer.writeStartElement(QStringLiteral("cellStyles")); writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1")); writer.writeStartElement(QStringLiteral("cellStyle")); writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Normal")); writer.writeAttribute(QStringLiteral("xfId"), QStringLiteral("0")); writer.writeAttribute(QStringLiteral("builtinId"), QStringLiteral("0")); writer.writeEndElement(); // cellStyle writer.writeEndElement(); // cellStyles writeDxfs(writer); writer.writeStartElement(QStringLiteral("tableStyles")); writer.writeAttribute(QStringLiteral("count"), QStringLiteral("0")); writer.writeAttribute(QStringLiteral("defaultTableStyle"), QStringLiteral("TableStyleMedium9")); writer.writeAttribute(QStringLiteral("defaultPivotStyle"), QStringLiteral("PivotStyleLight16")); writer.writeEndElement(); // tableStyles writeColors(writer); writer.writeEndElement(); // styleSheet writer.writeEndDocument(); } void Styles::writeNumFmts(QXmlStreamWriter &writer) const { if (m_customNumFmtIdMap.isEmpty()) return; writer.writeStartElement(QStringLiteral("numFmts")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_customNumFmtIdMap.count())); QMapIterator> it(m_customNumFmtIdMap); while (it.hasNext()) { it.next(); writer.writeEmptyElement(QStringLiteral("numFmt")); writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(it.value()->formatIndex)); writer.writeAttribute(QStringLiteral("formatCode"), it.value()->formatString); } writer.writeEndElement(); // numFmts } /* */ void Styles::writeFonts(QXmlStreamWriter &writer) const { writer.writeStartElement(QStringLiteral("fonts")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_fontsList.count())); for (const auto &font : m_fontsList) { writeFont(writer, font, false); } writer.writeEndElement(); // fonts } void Styles::writeFont(QXmlStreamWriter &writer, const Format &format, bool isDxf) const { writer.writeStartElement(QStringLiteral("font")); // The condense and extend elements are mainly used in dxf format if (format.hasProperty(FormatPrivate::P_Font_Condense) && !format.boolProperty(FormatPrivate::P_Font_Condense)) { writer.writeEmptyElement(QStringLiteral("condense")); writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); } if (format.hasProperty(FormatPrivate::P_Font_Extend) && !format.boolProperty(FormatPrivate::P_Font_Extend)) { writer.writeEmptyElement(QStringLiteral("extend")); writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0")); } if (format.fontBold()) writer.writeEmptyElement(QStringLiteral("b")); if (format.fontItalic()) writer.writeEmptyElement(QStringLiteral("i")); if (format.fontStrikeOut()) writer.writeEmptyElement(QStringLiteral("strike")); if (format.fontOutline()) writer.writeEmptyElement(QStringLiteral("outline")); if (format.boolProperty(FormatPrivate::P_Font_Shadow)) writer.writeEmptyElement(QStringLiteral("shadow")); if (format.hasProperty(FormatPrivate::P_Font_Underline)) { Format::FontUnderline u = format.fontUnderline(); if (u != Format::FontUnderlineNone) { writer.writeEmptyElement(QStringLiteral("u")); if (u == Format::FontUnderlineDouble) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double")); else if (u == Format::FontUnderlineSingleAccounting) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting")); else if (u == Format::FontUnderlineDoubleAccounting) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting")); } } if (format.hasProperty(FormatPrivate::P_Font_Script)) { Format::FontScript s = format.fontScript(); if (s != Format::FontScriptNormal) { writer.writeEmptyElement(QStringLiteral("vertAlign")); if (s == Format::FontScriptSuper) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript")); else writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript")); } } if (!isDxf && format.hasProperty(FormatPrivate::P_Font_Size)) { writer.writeEmptyElement(QStringLiteral("sz")); writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize())); } if (format.hasProperty(FormatPrivate::P_Font_Color)) { auto color = format.property(FormatPrivate::P_Font_Color).value(); color.saveToXml(writer); } if (!isDxf) { if (!format.fontName().isEmpty()) { writer.writeEmptyElement(QStringLiteral("name")); writer.writeAttribute(QStringLiteral("val"), format.fontName()); } if (format.hasProperty(FormatPrivate::P_Font_Charset)) { writer.writeEmptyElement(QStringLiteral("charset")); writer.writeAttribute( QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Charset))); } if (format.hasProperty(FormatPrivate::P_Font_Family)) { writer.writeEmptyElement(QStringLiteral("family")); writer.writeAttribute( QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family))); } if (format.hasProperty(FormatPrivate::P_Font_Scheme)) { writer.writeEmptyElement(QStringLiteral("scheme")); writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme)); } } writer.writeEndElement(); // font } void Styles::writeFills(QXmlStreamWriter &writer) const { writer.writeStartElement(QStringLiteral("fills")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_fillsList.size())); for (const auto &fill : m_fillsList) { writeFill(writer, fill); } writer.writeEndElement(); // fills } void Styles::writeFill(QXmlStreamWriter &writer, const Format &fill, bool isDxf) const { static const QMap patternStrings = { {Format::PatternNone, QStringLiteral("none")}, {Format::PatternSolid, QStringLiteral("solid")}, {Format::PatternMediumGray, QStringLiteral("mediumGray")}, {Format::PatternDarkGray, QStringLiteral("darkGray")}, {Format::PatternLightGray, QStringLiteral("lightGray")}, {Format::PatternDarkHorizontal, QStringLiteral("darkHorizontal")}, {Format::PatternDarkVertical, QStringLiteral("darkVertical")}, {Format::PatternDarkDown, QStringLiteral("darkDown")}, {Format::PatternDarkUp, QStringLiteral("darkUp")}, {Format::PatternDarkGrid, QStringLiteral("darkGrid")}, {Format::PatternDarkTrellis, QStringLiteral("darkTrellis")}, {Format::PatternLightHorizontal, QStringLiteral("lightHorizontal")}, {Format::PatternLightVertical, QStringLiteral("lightVertical")}, {Format::PatternLightDown, QStringLiteral("lightDown")}, {Format::PatternLightUp, QStringLiteral("lightUp")}, {Format::PatternLightTrellis, QStringLiteral("lightTrellis")}, {Format::PatternGray125, QStringLiteral("gray125")}, {Format::PatternGray0625, QStringLiteral("gray0625")}, {Format::PatternLightGrid, QStringLiteral("lightGrid")}}; writer.writeStartElement(QStringLiteral("fill")); writer.writeStartElement(QStringLiteral("patternFill")); Format::FillPattern pattern = fill.fillPattern(); // For normal fill formats, Excel prefer to outputting the default "none" attribute // But for dxf, Excel prefer to omitting the default "none" // Though not make any difference, but it make easier to compare origin files with generate // files during debug if (!(pattern == Format::PatternNone && isDxf)) writer.writeAttribute(QStringLiteral("patternType"), patternStrings[pattern]); // For a solid fill, Excel reverses the role of foreground and background colours if (fill.fillPattern() == Format::PatternSolid) { if (fill.hasProperty(FormatPrivate::P_Fill_BgColor)) fill.property(FormatPrivate::P_Fill_BgColor) .value() .saveToXml(writer, QStringLiteral("fgColor")); if (fill.hasProperty(FormatPrivate::P_Fill_FgColor)) fill.property(FormatPrivate::P_Fill_FgColor) .value() .saveToXml(writer, QStringLiteral("bgColor")); } else { if (fill.hasProperty(FormatPrivate::P_Fill_FgColor)) fill.property(FormatPrivate::P_Fill_FgColor) .value() .saveToXml(writer, QStringLiteral("fgColor")); if (fill.hasProperty(FormatPrivate::P_Fill_BgColor)) fill.property(FormatPrivate::P_Fill_BgColor) .value() .saveToXml(writer, QStringLiteral("bgColor")); } writer.writeEndElement(); // patternFill writer.writeEndElement(); // fill } void Styles::writeBorders(QXmlStreamWriter &writer) const { writer.writeStartElement(QStringLiteral("borders")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_bordersList.count())); for (const auto &border : m_bordersList) { writeBorder(writer, border); } writer.writeEndElement(); // borders } void Styles::writeBorder(QXmlStreamWriter &writer, const Format &border, bool isDxf) const { writer.writeStartElement(QStringLiteral("border")); if (border.hasProperty(FormatPrivate::P_Border_DiagonalType)) { Format::DiagonalBorderType t = border.diagonalBorderType(); if (t == Format::DiagonalBorderUp) { writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); } else if (t == Format::DiagonalBorderDown) { writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); } else if (t == Format::DiagnoalBorderBoth) { writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1")); writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1")); } } writeSubBorder(writer, QStringLiteral("left"), border.leftBorderStyle(), border.property(FormatPrivate::P_Border_LeftColor).value()); writeSubBorder(writer, QStringLiteral("right"), border.rightBorderStyle(), border.property(FormatPrivate::P_Border_RightColor).value()); writeSubBorder(writer, QStringLiteral("top"), border.topBorderStyle(), border.property(FormatPrivate::P_Border_TopColor).value()); writeSubBorder(writer, QStringLiteral("bottom"), border.bottomBorderStyle(), border.property(FormatPrivate::P_Border_BottomColor).value()); // Condition DXF formats don't allow diagonal style if (!isDxf) writeSubBorder(writer, QStringLiteral("diagonal"), border.diagonalBorderStyle(), border.property(FormatPrivate::P_Border_DiagonalColor).value()); if (isDxf) { // writeSubBorder(writer, QStringLiteral("vertical"), ); // writeSubBorder(writer, QStringLiteral("horizontal"), ); } writer.writeEndElement(); // border } void Styles::writeSubBorder(QXmlStreamWriter &writer, const QString &type, int style, const XlsxColor &color) const { if (style == Format::BorderNone) { writer.writeEmptyElement(type); return; } static const QMap stylesString = { {Format::BorderNone, QStringLiteral("none")}, {Format::BorderThin, QStringLiteral("thin")}, {Format::BorderMedium, QStringLiteral("medium")}, {Format::BorderDashed, QStringLiteral("dashed")}, {Format::BorderDotted, QStringLiteral("dotted")}, {Format::BorderThick, QStringLiteral("thick")}, {Format::BorderDouble, QStringLiteral("double")}, {Format::BorderHair, QStringLiteral("hair")}, {Format::BorderMediumDashed, QStringLiteral("mediumDashed")}, {Format::BorderDashDot, QStringLiteral("dashDot")}, {Format::BorderMediumDashDot, QStringLiteral("mediumDashDot")}, {Format::BorderDashDotDot, QStringLiteral("dashDotDot")}, {Format::BorderMediumDashDotDot, QStringLiteral("mediumDashDotDot")}, {Format::BorderSlantDashDot, QStringLiteral("slantDashDot")}}; writer.writeStartElement(type); writer.writeAttribute(QStringLiteral("style"), stylesString[style]); color.saveToXml(writer); // write color element writer.writeEndElement(); // type } void Styles::writeCellXfs(QXmlStreamWriter &writer) const { writer.writeStartElement(QStringLiteral("cellXfs")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size())); for (const Format &format : m_xf_formatsList) { int xf_id = 0; writer.writeStartElement(QStringLiteral("xf")); writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex())); writer.writeAttribute(QStringLiteral("fontId"), QString::number(format.fontIndex())); writer.writeAttribute(QStringLiteral("fillId"), QString::number(format.fillIndex())); writer.writeAttribute(QStringLiteral("borderId"), QString::number(format.borderIndex())); writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id)); if (format.hasNumFmtData()) writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1")); if (format.hasFontData()) writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1")); if (format.hasFillData()) writer.writeAttribute(QStringLiteral("applyFill"), QStringLiteral("1")); if (format.hasBorderData()) writer.writeAttribute(QStringLiteral("applyBorder"), QStringLiteral("1")); if (format.hasAlignmentData()) writer.writeAttribute(QStringLiteral("applyAlignment"), QStringLiteral("1")); if (format.hasAlignmentData()) { writer.writeEmptyElement(QStringLiteral("alignment")); if (format.hasProperty(FormatPrivate::P_Alignment_AlignH)) { switch (format.horizontalAlignment()) { case Format::AlignLeft: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("left")); break; case Format::AlignHCenter: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("center")); break; case Format::AlignRight: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("right")); break; case Format::AlignHFill: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("fill")); break; case Format::AlignHJustify: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("justify")); break; case Format::AlignHMerge: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("centerContinuous")); break; case Format::AlignHDistributed: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("distributed")); break; default: break; } } if (format.hasProperty(FormatPrivate::P_Alignment_AlignV)) { switch (format.verticalAlignment()) { case Format::AlignTop: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("top")); break; case Format::AlignVCenter: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("center")); break; case Format::AlignVJustify: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("justify")); break; case Format::AlignVDistributed: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("distributed")); break; default: break; } } if (format.hasProperty(FormatPrivate::P_Alignment_Indent)) writer.writeAttribute(QStringLiteral("indent"), QString::number(format.indent())); if (format.hasProperty(FormatPrivate::P_Alignment_Wrap) && format.textWrap()) writer.writeAttribute(QStringLiteral("wrapText"), QStringLiteral("1")); if (format.hasProperty(FormatPrivate::P_Alignment_ShinkToFit) && format.shrinkToFit()) writer.writeAttribute(QStringLiteral("shrinkToFit"), QStringLiteral("1")); if (format.hasProperty(FormatPrivate::P_Alignment_Rotation)) writer.writeAttribute(QStringLiteral("textRotation"), QString::number(format.rotation())); } writer.writeEndElement(); // xf } writer.writeEndElement(); // cellXfs } void Styles::writeDxfs(QXmlStreamWriter &writer) const { writer.writeStartElement(QStringLiteral("dxfs")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_dxf_formatsList.size())); for (const Format &format : m_dxf_formatsList) writeDxf(writer, format); writer.writeEndElement(); // dxfs } void Styles::writeDxf(QXmlStreamWriter &writer, const Format &format) const { writer.writeStartElement(QStringLiteral("dxf")); if (format.hasFontData()) writeFont(writer, format, true); if (format.hasNumFmtData()) { writer.writeEmptyElement(QStringLiteral("numFmt")); writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex())); writer.writeAttribute(QStringLiteral("formatCode"), format.numberFormat()); } if (format.hasFillData()) writeFill(writer, format, true); if (format.hasBorderData()) writeBorder(writer, format, true); writer.writeEndElement(); // dxf } void Styles::writeColors(QXmlStreamWriter &writer) const { if (m_isIndexedColorsDefault) // Don't output the default indexdeColors return; writer.writeStartElement(QStringLiteral("colors")); writer.writeStartElement(QStringLiteral("indexedColors")); for (const QColor &color : m_indexedColors) { writer.writeEmptyElement(QStringLiteral("rgbColor")); writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(color)); } writer.writeEndElement(); // indexedColors writer.writeEndElement(); // colors } bool Styles::readNumFmts(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("numFmts")); const auto &attributes = reader.attributes(); const auto hasCount = attributes.hasAttribute(QLatin1String("count")); const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; // Read until we find the numFmts end tag or .... while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("numFmts"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("numFmt")) { const auto &attributes = reader.attributes(); auto fmt = std::make_shared(); fmt->formatIndex = attributes.value(QLatin1String("numFmtId")).toInt(); fmt->formatString = attributes.value(QLatin1String("formatCode")).toString(); if (fmt->formatIndex >= m_nextCustomNumFmtId) m_nextCustomNumFmtId = fmt->formatIndex + 1; m_customNumFmtIdMap.insert(fmt->formatIndex, fmt); m_customNumFmtsHash.insert(fmt->formatString, fmt); } } } if (reader.hasError()) qWarning() << reader.errorString(); if (hasCount && (count != m_customNumFmtIdMap.size())) qWarning("error read custom numFmts"); return true; } bool Styles::readFonts(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("fonts")); const auto &attributes = reader.attributes(); const auto hasCount = attributes.hasAttribute(QLatin1String("count")); const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fonts"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("font")) { Format format; readFont(reader, format); m_fontsList.append(format); m_fontsHash.insert(format.fontKey(), format); if (format.isValid()) format.setFontIndex(m_fontsList.size() - 1); } } } if (reader.hasError()) qWarning() << reader.errorString(); if (hasCount && (count != m_fontsList.size())) qWarning("error read fonts"); return true; } bool Styles::readFont(QXmlStreamReader &reader, Format &format) { Q_ASSERT(reader.name() == QLatin1String("font")); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("font"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { const auto &attributes = reader.attributes(); if (reader.name() == QLatin1String("name")) { format.setFontName(attributes.value(QLatin1String("val")).toString()); } else if (reader.name() == QLatin1String("charset")) { format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toInt()); } else if (reader.name() == QLatin1String("family")) { format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toInt()); } else if (reader.name() == QLatin1String("b")) { format.setFontBold(true); } else if (reader.name() == QLatin1String("i")) { format.setFontItalic(true); } else if (reader.name() == QLatin1String("strike")) { format.setFontStrikeOut(true); } else if (reader.name() == QLatin1String("outline")) { format.setFontOutline(true); } else if (reader.name() == QLatin1String("shadow")) { format.setProperty(FormatPrivate::P_Font_Shadow, true); } else if (reader.name() == QLatin1String("condense")) { format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toInt()); } else if (reader.name() == QLatin1String("extend")) { format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toInt()); } else if (reader.name() == QLatin1String("color")) { XlsxColor color; color.loadFromXml(reader); format.setProperty(FormatPrivate::P_Font_Color, color); } else if (reader.name() == QLatin1String("sz")) { const auto sz = attributes.value(QLatin1String("val")).toInt(); format.setFontSize(sz); } else if (reader.name() == QLatin1String("u")) { QString value = attributes.value(QLatin1String("val")).toString(); if (value == QLatin1String("double")) format.setFontUnderline(Format::FontUnderlineDouble); else if (value == QLatin1String("doubleAccounting")) format.setFontUnderline(Format::FontUnderlineDoubleAccounting); else if (value == QLatin1String("singleAccounting")) format.setFontUnderline(Format::FontUnderlineSingleAccounting); else format.setFontUnderline(Format::FontUnderlineSingle); } else if (reader.name() == QLatin1String("vertAlign")) { QString value = attributes.value(QLatin1String("val")).toString(); if (value == QLatin1String("superscript")) format.setFontScript(Format::FontScriptSuper); else if (value == QLatin1String("subscript")) format.setFontScript(Format::FontScriptSub); } else if (reader.name() == QLatin1String("scheme")) { format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString()); } } } return true; } bool Styles::readFills(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("fills")); const auto &attributes = reader.attributes(); const auto hasCount = attributes.hasAttribute(QLatin1String("count")); const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fills"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("fill")) { Format fill; readFill(reader, fill); m_fillsList.append(fill); m_fillsHash.insert(fill.fillKey(), fill); if (fill.isValid()) fill.setFillIndex(m_fillsList.size() - 1); } } } if (reader.hasError()) qWarning() << reader.errorString(); if (hasCount && (count != m_fillsList.size())) qWarning("error read fills"); return true; } bool Styles::readFill(QXmlStreamReader &reader, Format &fill) { Q_ASSERT(reader.name() == QLatin1String("fill")); static const QMap patternValues = { {QStringLiteral("none"), Format::PatternNone}, {QStringLiteral("solid"), Format::PatternSolid}, {QStringLiteral("mediumGray"), Format::PatternMediumGray}, {QStringLiteral("darkGray"), Format::PatternDarkGray}, {QStringLiteral("lightGray"), Format::PatternLightGray}, {QStringLiteral("darkHorizontal"), Format::PatternDarkHorizontal}, {QStringLiteral("darkVertical"), Format::PatternDarkVertical}, {QStringLiteral("darkDown"), Format::PatternDarkDown}, {QStringLiteral("darkUp"), Format::PatternDarkUp}, {QStringLiteral("darkGrid"), Format::PatternDarkGrid}, {QStringLiteral("darkTrellis"), Format::PatternDarkTrellis}, {QStringLiteral("lightHorizontal"), Format::PatternLightHorizontal}, {QStringLiteral("lightVertical"), Format::PatternLightVertical}, {QStringLiteral("lightDown"), Format::PatternLightDown}, {QStringLiteral("lightUp"), Format::PatternLightUp}, {QStringLiteral("lightTrellis"), Format::PatternLightTrellis}, {QStringLiteral("gray125"), Format::PatternGray125}, {QStringLiteral("gray0625"), Format::PatternGray0625}, {QStringLiteral("lightGrid"), Format::PatternLightGrid}}; while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fill"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("patternFill")) { const auto &attributes = reader.attributes(); if (attributes.hasAttribute(QLatin1String("patternType"))) { const auto &it = patternValues.constFind( attributes.value(QLatin1String("patternType")).toString()); fill.setFillPattern(it != patternValues.constEnd() ? it.value() : Format::PatternNone); // parse foreground and background colors if they exist while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("patternFill"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("fgColor")) { XlsxColor c; if (c.loadFromXml(reader)) { if (fill.fillPattern() == Format::PatternSolid) fill.setProperty(FormatPrivate::P_Fill_BgColor, c); else fill.setProperty(FormatPrivate::P_Fill_FgColor, c); } } else if (reader.name() == QLatin1String("bgColor")) { XlsxColor c; if (c.loadFromXml(reader)) { if (fill.fillPattern() == Format::PatternSolid) fill.setProperty(FormatPrivate::P_Fill_FgColor, c); else fill.setProperty(FormatPrivate::P_Fill_BgColor, c); } } } } } } } } return true; } bool Styles::readBorders(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("borders")); const auto &attributes = reader.attributes(); const auto hasCount = attributes.hasAttribute(QLatin1String("count")); const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("borders"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("border")) { Format border; readBorder(reader, border); m_bordersList.append(border); m_bordersHash.insert(border.borderKey(), border); if (border.isValid()) border.setBorderIndex(m_bordersList.size() - 1); } } } if (reader.hasError()) qWarning() << reader.errorString(); if (hasCount && (count != m_bordersList.size())) qWarning("error read borders"); return true; } bool Styles::readBorder(QXmlStreamReader &reader, Format &border) { Q_ASSERT(reader.name() == QLatin1String("border")); const auto &attributes = reader.attributes(); const auto isUp = attributes.hasAttribute(QLatin1String("diagonalUp")); const auto isDown = attributes.hasAttribute(QLatin1String("diagonalDown")); if (isUp && isDown) border.setDiagonalBorderType(Format::DiagnoalBorderBoth); else if (isUp) border.setDiagonalBorderType(Format::DiagonalBorderUp); else if (isDown) border.setDiagonalBorderType(Format::DiagonalBorderDown); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("left") || reader.name() == QLatin1String("right") || reader.name() == QLatin1String("top") || reader.name() == QLatin1String("bottom") || reader.name() == QLatin1String("diagonal")) { Format::BorderStyle style(Format::BorderNone); XlsxColor color; readSubBorder(reader, reader.name().toString(), style, color); if (reader.name() == QLatin1String("left")) { border.setLeftBorderStyle(style); if (!color.isInvalid()) border.setProperty(FormatPrivate::P_Border_LeftColor, color); } else if (reader.name() == QLatin1String("right")) { border.setRightBorderStyle(style); if (!color.isInvalid()) border.setProperty(FormatPrivate::P_Border_RightColor, color); } else if (reader.name() == QLatin1String("top")) { border.setTopBorderStyle(style); if (!color.isInvalid()) border.setProperty(FormatPrivate::P_Border_TopColor, color); } else if (reader.name() == QLatin1String("bottom")) { border.setBottomBorderStyle(style); if (!color.isInvalid()) border.setProperty(FormatPrivate::P_Border_BottomColor, color); } else if (reader.name() == QLatin1String("diagonal")) { border.setDiagonalBorderStyle(style); if (!color.isInvalid()) border.setProperty(FormatPrivate::P_Border_DiagonalColor, color); } } } if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border")) break; } return true; } bool Styles::readCellStyleXfs(QXmlStreamReader &reader) { Q_UNUSED(reader); return true; } bool Styles::readSubBorder(QXmlStreamReader &reader, const QString &name, Format::BorderStyle &style, XlsxColor &color) { Q_ASSERT(reader.name() == name); static const QMap stylesStringsMap = { {QStringLiteral("none"), Format::BorderNone}, {QStringLiteral("thin"), Format::BorderThin}, {QStringLiteral("medium"), Format::BorderMedium}, {QStringLiteral("dashed"), Format::BorderDashed}, {QStringLiteral("dotted"), Format::BorderDotted}, {QStringLiteral("thick"), Format::BorderThick}, {QStringLiteral("double"), Format::BorderDouble}, {QStringLiteral("hair"), Format::BorderHair}, {QStringLiteral("mediumDashed"), Format::BorderMediumDashed}, {QStringLiteral("dashDot"), Format::BorderDashDot}, {QStringLiteral("mediumDashDot"), Format::BorderMediumDashDot}, {QStringLiteral("dashDotDot"), Format::BorderDashDotDot}, {QStringLiteral("mediumDashDotDot"), Format::BorderMediumDashDotDot}, {QStringLiteral("slantDashDot"), Format::BorderSlantDashDot}}; const auto &attributes = reader.attributes(); if (attributes.hasAttribute(QLatin1String("style"))) { QString styleString = attributes.value(QLatin1String("style")).toString(); const auto &it = stylesStringsMap.constFind(styleString); if (it != stylesStringsMap.constEnd()) { // get style style = it.value(); while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("color")) color.loadFromXml(reader); } } } } return true; } bool Styles::readCellXfs(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("cellXfs")); const auto &attributes = reader.attributes(); const auto hasCount = attributes.hasAttribute(QLatin1String("count")); const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("cellXfs"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("xf")) { Format format; const auto &xfAttrs = reader.attributes(); // qDebug()<formatString); } } if (xfAttrs.hasAttribute(QLatin1String("fontId"))) { const auto fontIndex = xfAttrs.value(QLatin1String("fontId")).toInt(); if (fontIndex >= m_fontsList.size()) { qDebug("Error read styles.xml, cellXfs fontId"); } else { const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFont")).toString()); if (apply) { Format fontFormat = m_fontsList[fontIndex]; for (int i = FormatPrivate::P_Font_STARTID; i < FormatPrivate::P_Font_ENDID; ++i) { if (fontFormat.hasProperty(i)) format.setProperty(i, fontFormat.property(i)); } } } } if (xfAttrs.hasAttribute(QLatin1String("fillId"))) { const auto id = xfAttrs.value(QLatin1String("fillId")).toInt(); if (id >= m_fillsList.size()) { qDebug("Error read styles.xml, cellXfs fillId"); } else { // dev20 branch // NOTE: MIcrosoft Excel does not have 'applyFill' tag. // // bool apply = // parseXsdBoolean(xfAttrs.value(QLatin1String("applyFill")).toString()); if // (apply) { Format fillFormat = m_fillsList[id]; for (int i = FormatPrivate::P_Fill_STARTID; i < FormatPrivate::P_Fill_ENDID; ++i) { if (fillFormat.hasProperty(i)) format.setProperty(i, fillFormat.property(i)); } } } } if (xfAttrs.hasAttribute(QLatin1String("borderId"))) { const auto id = xfAttrs.value(QLatin1String("borderId")).toInt(); if (id >= m_bordersList.size()) { qDebug("Error read styles.xml, cellXfs borderId"); } else { const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyBorder")).toString()); if (apply) { Format borderFormat = m_bordersList[id]; for (int i = FormatPrivate::P_Border_STARTID; i < FormatPrivate::P_Border_ENDID; ++i) { if (borderFormat.hasProperty(i)) format.setProperty(i, borderFormat.property(i)); } } } } const auto apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyAlignment")).toString()); if (apply) { reader.readNextStartElement(); if (reader.name() == QLatin1String("alignment")) { const auto &alignAttrs = reader.attributes(); if (alignAttrs.hasAttribute(QLatin1String("horizontal"))) { static const QMap alignStringMap = {{QStringLiteral("left"), Format::AlignLeft}, {QStringLiteral("center"), Format::AlignHCenter}, {QStringLiteral("right"), Format::AlignRight}, {QStringLiteral("justify"), Format::AlignHJustify}, {QStringLiteral("centerContinuous"), Format::AlignHMerge}, {QStringLiteral("distributed"), Format::AlignHDistributed}}; const auto &it = alignStringMap.constFind( alignAttrs.value(QLatin1String("horizontal")).toString()); if (it != alignStringMap.constEnd()) format.setHorizontalAlignment(it.value()); } if (alignAttrs.hasAttribute(QLatin1String("vertical"))) { static const QMap alignStringMap = { {QStringLiteral("top"), Format::AlignTop}, {QStringLiteral("center"), Format::AlignVCenter}, {QStringLiteral("justify"), Format::AlignVJustify}, {QStringLiteral("distributed"), Format::AlignVDistributed}}; const auto &it = alignStringMap.constFind( alignAttrs.value(QLatin1String("vertical")).toString()); if (it != alignStringMap.constEnd()) format.setVerticalAlignment(it.value()); } if (alignAttrs.hasAttribute(QLatin1String("indent"))) { const auto indent = alignAttrs.value(QLatin1String("indent")).toInt(); format.setIndent(indent); } if (alignAttrs.hasAttribute(QLatin1String("textRotation"))) { const auto rotation = alignAttrs.value(QLatin1String("textRotation")).toInt(); format.setRotation(rotation); } if (alignAttrs.hasAttribute(QLatin1String("wrapText"))) format.setTextWrap(true); if (alignAttrs.hasAttribute(QLatin1String("shrinkToFit"))) format.setShrinkToFit(true); } } addXfFormat(format, true); } } } if (reader.hasError()) qWarning() << reader.errorString(); if (hasCount && (count != m_xf_formatsList.size())) qWarning("error read CellXfs"); return true; } bool Styles::readDxfs(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("dxfs")); const auto &attributes = reader.attributes(); const auto hasCount = attributes.hasAttribute(QLatin1String("count")); const auto count = hasCount ? attributes.value(QLatin1String("count")).toInt() : -1; while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("dxfs"))) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("dxf")) readDxf(reader); } } if (reader.hasError()) qWarning() << reader.errorString(); if (hasCount && (count != m_dxf_formatsList.size())) qWarning("error read dxfs"); return true; } bool Styles::readDxf(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("dxf")); Format format; while (!reader.atEnd() && !(reader.name() == QLatin1String("dxf") && reader.tokenType() == QXmlStreamReader::EndElement)) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("numFmt")) { const auto &attributes = reader.attributes(); const auto id = attributes.value(QLatin1String("numFmtId")).toInt(); QString code = attributes.value(QLatin1String("formatCode")).toString(); format.setNumberFormat(id, code); } else if (reader.name() == QLatin1String("font")) { readFont(reader, format); } else if (reader.name() == QLatin1String("fill")) { readFill(reader, format); } else if (reader.name() == QLatin1String("border")) { readBorder(reader, format); } } } addDxfFormat(format, true); return true; } bool Styles::readColors(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("colors")); while (!reader.atEnd() && !(reader.name() == QLatin1String("colors") && reader.tokenType() == QXmlStreamReader::EndElement)) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("indexedColors")) { readIndexedColors(reader); } else if (reader.name() == QLatin1String("mruColors")) { } } } return true; } bool Styles::readIndexedColors(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("indexedColors")); m_indexedColors.clear(); while (!reader.atEnd() && !(reader.name() == QLatin1String("indexedColors") && reader.tokenType() == QXmlStreamReader::EndElement)) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("rgbColor")) { const auto &color = reader.attributes().value(QLatin1String("rgb")).toString(); m_indexedColors.append(XlsxColor::fromARGBString(color)); } } } if (!m_indexedColors.isEmpty()) m_isIndexedColorsDefault = false; return true; } bool Styles::loadFromXmlFile(QIODevice *device) { QXmlStreamReader reader(device); while (!reader.atEnd()) { QXmlStreamReader::TokenType token = reader.readNext(); if (token == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("numFmts")) { readNumFmts(reader); } else if (reader.name() == QLatin1String("fonts")) { readFonts(reader); } else if (reader.name() == QLatin1String("fills")) { readFills(reader); } else if (reader.name() == QLatin1String("borders")) { readBorders(reader); } else if (reader.name() == QLatin1String("cellStyleXfs")) { readCellStyleXfs(reader); } else if (reader.name() == QLatin1String("cellXfs")) { readCellXfs(reader); } else if (reader.name() == QLatin1String("cellStyles")) { // cellStyles } else if (reader.name() == QLatin1String("dxfs")) { readDxfs(reader); } else if (reader.name() == QLatin1String("colors")) { readColors(reader); } } if (reader.hasError()) { qDebug() << "Error when read style file: " << reader.errorString(); } } return true; } QColor Styles::getColorByIndex(int idx) { if (m_indexedColors.isEmpty()) { m_indexedColors = { QColor(QRgba64::fromArgb32(0xFF000000)), QColor(QRgba64::fromArgb32(0xFFFFFFFF)), QColor(QRgba64::fromArgb32(0xFFFF0000)), QColor(QRgba64::fromArgb32(0xFF00FF00)), QColor(QRgba64::fromArgb32(0xFF0000FF)), QColor(QRgba64::fromArgb32(0xFFFFFF00)), QColor(QRgba64::fromArgb32(0xFFFF00FF)), QColor(QRgba64::fromArgb32(0xFF00FFFF)), QColor(QRgba64::fromArgb32(0xFF000000)), QColor(QRgba64::fromArgb32(0xFFFFFFFF)), QColor(QRgba64::fromArgb32(0xFFFF0000)), QColor(QRgba64::fromArgb32(0xFF00FF00)), QColor(QRgba64::fromArgb32(0xFF0000FF)), QColor(QRgba64::fromArgb32(0xFFFFFF00)), QColor(QRgba64::fromArgb32(0xFFFF00FF)), QColor(QRgba64::fromArgb32(0xFF00FFFF)), QColor(QRgba64::fromArgb32(0xFF800000)), QColor(QRgba64::fromArgb32(0xFF008000)), QColor(QRgba64::fromArgb32(0xFF000080)), QColor(QRgba64::fromArgb32(0xFF808000)), QColor(QRgba64::fromArgb32(0xFF800080)), QColor(QRgba64::fromArgb32(0xFF008080)), QColor(QRgba64::fromArgb32(0xFFC0C0C0)), QColor(QRgba64::fromArgb32(0xFF808080)), QColor(QRgba64::fromArgb32(0xFF9999FF)), QColor(QRgba64::fromArgb32(0xFF993366)), QColor(QRgba64::fromArgb32(0xFFFFFFCC)), QColor(QRgba64::fromArgb32(0xFFCCFFFF)), QColor(QRgba64::fromArgb32(0xFF660066)), QColor(QRgba64::fromArgb32(0xFFFF8080)), QColor(QRgba64::fromArgb32(0xFF0066CC)), QColor(QRgba64::fromArgb32(0xFFCCCCFF)), QColor(QRgba64::fromArgb32(0xFF000080)), QColor(QRgba64::fromArgb32(0xFFFF00FF)), QColor(QRgba64::fromArgb32(0xFFFFFF00)), QColor(QRgba64::fromArgb32(0xFF00FFFF)), QColor(QRgba64::fromArgb32(0xFF800080)), QColor(QRgba64::fromArgb32(0xFF800000)), QColor(QRgba64::fromArgb32(0xFF008080)), QColor(QRgba64::fromArgb32(0xFF0000FF)), QColor(QRgba64::fromArgb32(0xFF00CCFF)), QColor(QRgba64::fromArgb32(0xFFCCFFFF)), QColor(QRgba64::fromArgb32(0xFFCCFFCC)), QColor(QRgba64::fromArgb32(0xFFFFFF99)), QColor(QRgba64::fromArgb32(0xFF99CCFF)), QColor(QRgba64::fromArgb32(0xFFFF99CC)), QColor(QRgba64::fromArgb32(0xFFCC99FF)), QColor(QRgba64::fromArgb32(0xFFFFCC99)), QColor(QRgba64::fromArgb32(0xFF3366FF)), QColor(QRgba64::fromArgb32(0xFF33CCCC)), QColor(QRgba64::fromArgb32(0xFF99CC00)), QColor(QRgba64::fromArgb32(0xFFFFCC00)), QColor(QRgba64::fromArgb32(0xFFFF9900)), QColor(QRgba64::fromArgb32(0xFFFF6600)), QColor(QRgba64::fromArgb32(0xFF666699)), QColor(QRgba64::fromArgb32(0xFF969696)), QColor(QRgba64::fromArgb32(0xFF003366)), QColor(QRgba64::fromArgb32(0xFF339966)), QColor(QRgba64::fromArgb32(0xFF003300)), QColor(QRgba64::fromArgb32(0xFF333300)), QColor(QRgba64::fromArgb32(0xFF993300)), QColor(QRgba64::fromArgb32(0xFF993366)), QColor(QRgba64::fromArgb32(0xFF333399)), QColor(QRgba64::fromArgb32(0xFF333333)), }; m_isIndexedColorsDefault = true; } if (idx < 0 || idx >= m_indexedColors.size()) return QColor(); return m_indexedColors[idx]; } QT_END_NAMESPACE_XLSX