andre@1: /**************************************************************************** andre@1: ** Copyright (c) 2013-2014 Debao Zhang andre@1: ** All right reserved. andre@1: ** andre@1: ** Permission is hereby granted, free of charge, to any person obtaining andre@1: ** a copy of this software and associated documentation files (the andre@1: ** "Software"), to deal in the Software without restriction, including andre@1: ** without limitation the rights to use, copy, modify, merge, publish, andre@1: ** distribute, sublicense, and/or sell copies of the Software, and to andre@1: ** permit persons to whom the Software is furnished to do so, subject to andre@1: ** the following conditions: andre@1: ** andre@1: ** The above copyright notice and this permission notice shall be andre@1: ** included in all copies or substantial portions of the Software. andre@1: ** andre@1: ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, andre@1: ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF andre@1: ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND andre@1: ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE andre@1: ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION andre@1: ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION andre@1: ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. andre@1: ** andre@1: ****************************************************************************/ andre@1: #include "xlsxstyles_p.h" andre@1: #include "xlsxformat_p.h" andre@1: #include "xlsxutility_p.h" andre@1: #include "xlsxcolor_p.h" andre@1: #include andre@1: #include andre@1: #include andre@1: #include andre@1: #include andre@1: #include andre@1: #include andre@1: andre@1: namespace QXlsx { andre@1: andre@1: /* andre@1: When loading from existing .xlsx file. we should create a clean styles object. andre@1: otherwise, default formats should be added. andre@1: andre@1: */ andre@1: Styles::Styles(CreateFlag flag) andre@1: : AbstractOOXmlFile(flag), m_nextCustomNumFmtId(176), m_isIndexedColorsDefault(true) andre@1: , m_emptyFormatAdded(false) andre@1: { andre@1: //!Fix me. Should the custom num fmt Id starts with 164 or 176 or others?? andre@1: andre@1: //!Fix me! Where should we put these register code? andre@1: if (QMetaType::type("XlsxColor") == QMetaType::UnknownType) { andre@1: qRegisterMetaType("XlsxColor"); andre@1: qRegisterMetaTypeStreamOperators("XlsxColor"); andre@1: #if QT_VERSION >= 0x050200 andre@1: QMetaType::registerDebugStreamOperator(); andre@1: #endif andre@1: } andre@1: andre@1: if (flag == F_NewFromScratch) { andre@1: //Add default Format andre@1: Format defaultFmt; andre@1: addXfFormat(defaultFmt); andre@1: andre@1: //Add another fill format andre@1: Format fillFmt; andre@1: fillFmt.setFillPattern(Format::PatternGray125); andre@1: m_fillsList.append(fillFmt); andre@1: m_fillsHash.insert(fillFmt.fillKey(), fillFmt); andre@1: } andre@1: } andre@1: andre@1: Styles::~Styles() andre@1: { andre@1: } andre@1: andre@1: Format Styles::xfFormat(int idx) const andre@1: { andre@1: if (idx <0 || idx >= m_xf_formatsList.size()) andre@1: return Format(); andre@1: andre@1: return m_xf_formatsList[idx]; andre@1: } andre@1: andre@1: Format Styles::dxfFormat(int idx) const andre@1: { andre@1: if (idx <0 || idx >= m_dxf_formatsList.size()) andre@1: return Format(); andre@1: andre@1: return m_dxf_formatsList[idx]; andre@1: } andre@1: andre@1: void Styles::fixNumFmt(const Format &format) andre@1: { andre@1: if (!format.hasNumFmtData()) andre@1: return; andre@1: andre@1: if (format.hasProperty(FormatPrivate::P_NumFmt_Id) andre@1: && !format.stringProperty(FormatPrivate::P_NumFmt_FormatCode).isEmpty()) { andre@1: return; andre@1: } andre@1: andre@1: if (m_builtinNumFmtsHash.isEmpty()) { andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);($#,##0)"), 5); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);[Red]($#,##0)"), 6); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);($#,##0.00)"), 7); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);[Red]($#,##0.00)"), 8); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("# ?\?/??"), 13);// Note: "??/" is a c++ trigraph, so escape one "?" andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22); andre@1: andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(_)"), 41); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(_)"), 42); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(_)"), 43); andre@1: // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(_)"), 44); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48); andre@1: m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49); andre@1: } andre@1: andre@1: const QString str = format.numberFormat(); andre@1: if (!str.isEmpty()) { andre@1: //Assign proper number format index andre@1: if (m_builtinNumFmtsHash.contains(str)) { andre@1: const_cast(&format)->fixNumberFormat(m_builtinNumFmtsHash[str], str); andre@1: } else if (m_customNumFmtsHash.contains(str)) { andre@1: const_cast(&format)->fixNumberFormat(m_customNumFmtsHash[str]->formatIndex, str); andre@1: } else { andre@1: //Assign a new fmt Id. andre@1: const_cast(&format)->fixNumberFormat(m_nextCustomNumFmtId, str); andre@1: andre@1: QSharedPointer fmt(new XlsxFormatNumberData); andre@1: fmt->formatIndex = m_nextCustomNumFmtId; andre@1: fmt->formatString = str; andre@1: m_customNumFmtIdMap.insert(m_nextCustomNumFmtId, fmt); andre@1: m_customNumFmtsHash.insert(str, fmt); andre@1: andre@1: m_nextCustomNumFmtId += 1; andre@1: } andre@1: } else { andre@1: int id = format.numberFormatIndex(); andre@1: //Assign proper format code, this is needed by dxf format andre@1: if (m_customNumFmtIdMap.contains(id)) { andre@1: const_cast(&format)->fixNumberFormat(id, m_customNumFmtIdMap[id]->formatString); andre@1: } else { andre@1: QHashIterator it(m_builtinNumFmtsHash); andre@1: bool find=false; andre@1: while (it.hasNext()) { andre@1: it.next(); andre@1: if (it.value() == id) { andre@1: const_cast(&format)->fixNumberFormat(id, it.key()); andre@1: find = true; andre@1: break; andre@1: } andre@1: } andre@1: andre@1: if (!find) { andre@1: //Wrong numFmt andre@1: const_cast(&format)->fixNumberFormat(id, QStringLiteral("General")); andre@1: } andre@1: } andre@1: } andre@1: } andre@1: andre@1: /* andre@1: Assign index to Font/Fill/Border and Format andre@1: andre@1: When \a force is true, add the format to the format list, even other format has andre@1: the same key have been in. andre@1: This is useful when reading existing .xlsx files which may contains duplicated formats. andre@1: */ andre@1: void Styles::addXfFormat(const Format &format, bool force) andre@1: { andre@1: if (format.isEmpty()) { andre@1: //Try do something for empty Format. andre@1: if (m_emptyFormatAdded && !force) andre@1: return; andre@1: m_emptyFormatAdded = true; andre@1: } andre@1: andre@1: //numFmt andre@1: if (format.hasNumFmtData() && !format.hasProperty(FormatPrivate::P_NumFmt_Id)) andre@1: fixNumFmt(format); andre@1: andre@1: //Font andre@1: if (format.hasFontData() && !format.fontIndexValid()) { andre@1: //Assign proper font index, if has font data. andre@1: if (!m_fontsHash.contains(format.fontKey())) andre@1: const_cast(&format)->setFontIndex(m_fontsList.size()); andre@1: else andre@1: const_cast(&format)->setFontIndex(m_fontsHash[format.fontKey()].fontIndex()); andre@1: } andre@1: if (!m_fontsHash.contains(format.fontKey())) { andre@1: //Still a valid font if the format has no fontData. (All font properties are default) andre@1: m_fontsList.append(format); andre@1: m_fontsHash[format.fontKey()] = format; andre@1: } andre@1: andre@1: //Fill andre@1: if (format.hasFillData() && !format.fillIndexValid()) { andre@1: //Assign proper fill index, if has fill data. andre@1: if (!m_fillsHash.contains(format.fillKey())) andre@1: const_cast(&format)->setFillIndex(m_fillsList.size()); andre@1: else andre@1: const_cast(&format)->setFillIndex(m_fillsHash[format.fillKey()].fillIndex()); andre@1: } andre@1: if (!m_fillsHash.contains(format.fillKey())) { andre@1: //Still a valid fill if the format has no fillData. (All fill properties are default) andre@1: m_fillsList.append(format); andre@1: m_fillsHash[format.fillKey()] = format; andre@1: } andre@1: andre@1: //Border andre@1: if (format.hasBorderData() && !format.borderIndexValid()) { andre@1: //Assign proper border index, if has border data. andre@1: if (!m_bordersHash.contains(format.borderKey())) andre@1: const_cast(&format)->setBorderIndex(m_bordersList.size()); andre@1: else andre@1: const_cast(&format)->setBorderIndex(m_bordersHash[format.borderKey()].borderIndex()); andre@1: } andre@1: if (!m_bordersHash.contains(format.borderKey())) { andre@1: //Still a valid border if the format has no borderData. (All border properties are default) andre@1: m_bordersList.append(format); andre@1: m_bordersHash[format.borderKey()] = format; andre@1: } andre@1: andre@1: //Format andre@1: if (!format.isEmpty() && !format.xfIndexValid()) { andre@1: if (m_xf_formatsHash.contains(format.formatKey())) andre@1: const_cast(&format)->setXfIndex(m_xf_formatsHash[format.formatKey()].xfIndex()); andre@1: else andre@1: const_cast(&format)->setXfIndex(m_xf_formatsList.size()); andre@1: } andre@1: if (!m_xf_formatsHash.contains(format.formatKey()) || force) { andre@1: m_xf_formatsList.append(format); andre@1: m_xf_formatsHash[format.formatKey()] = format; andre@1: } andre@1: } andre@1: andre@1: void Styles::addDxfFormat(const Format &format, bool force) andre@1: { andre@1: //numFmt andre@1: if (format.hasNumFmtData()) andre@1: fixNumFmt(format); andre@1: andre@1: if (!format.isEmpty() && !format.dxfIndexValid()) { andre@1: if (m_dxf_formatsHash.contains(format.formatKey())) andre@1: const_cast(&format)->setDxfIndex(m_dxf_formatsHash[format.formatKey()].dxfIndex()); andre@1: else andre@1: const_cast(&format)->setDxfIndex(m_dxf_formatsList.size()); andre@1: } andre@1: if (!m_dxf_formatsHash.contains(format.formatKey()) || force) { andre@1: m_dxf_formatsList.append(format); andre@1: m_dxf_formatsHash[format.formatKey()] = format; andre@1: } andre@1: } andre@1: andre@1: void Styles::saveToXmlFile(QIODevice *device) const andre@1: { andre@1: QXmlStreamWriter writer(device); andre@1: andre@1: writer.writeStartDocument(QStringLiteral("1.0"), true); andre@1: writer.writeStartElement(QStringLiteral("styleSheet")); andre@1: writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main")); andre@1: andre@1: writeNumFmts(writer); andre@1: writeFonts(writer); andre@1: writeFills(writer); andre@1: writeBorders(writer); andre@1: andre@1: writer.writeStartElement(QStringLiteral("cellStyleXfs")); andre@1: writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1")); andre@1: writer.writeStartElement(QStringLiteral("xf")); andre@1: writer.writeAttribute(QStringLiteral("numFmtId"), QStringLiteral("0")); andre@1: writer.writeAttribute(QStringLiteral("fontId"), QStringLiteral("0")); andre@1: writer.writeAttribute(QStringLiteral("fillId"), QStringLiteral("0")); andre@1: writer.writeAttribute(QStringLiteral("borderId"), QStringLiteral("0")); andre@1: writer.writeEndElement();//xf andre@1: writer.writeEndElement();//cellStyleXfs andre@1: andre@1: writeCellXfs(writer); andre@1: andre@1: writer.writeStartElement(QStringLiteral("cellStyles")); andre@1: writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1")); andre@1: writer.writeStartElement(QStringLiteral("cellStyle")); andre@1: writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Normal")); andre@1: writer.writeAttribute(QStringLiteral("xfId"), QStringLiteral("0")); andre@1: writer.writeAttribute(QStringLiteral("builtinId"), QStringLiteral("0")); andre@1: writer.writeEndElement();//cellStyle andre@1: writer.writeEndElement();//cellStyles andre@1: andre@1: writeDxfs(writer); andre@1: andre@1: writer.writeStartElement(QStringLiteral("tableStyles")); andre@1: writer.writeAttribute(QStringLiteral("count"), QStringLiteral("0")); andre@1: writer.writeAttribute(QStringLiteral("defaultTableStyle"), QStringLiteral("TableStyleMedium9")); andre@1: writer.writeAttribute(QStringLiteral("defaultPivotStyle"), QStringLiteral("PivotStyleLight16")); andre@1: writer.writeEndElement();//tableStyles andre@1: andre@1: writeColors(writer); andre@1: andre@1: writer.writeEndElement();//styleSheet andre@1: writer.writeEndDocument(); andre@1: } andre@1: andre@1: void Styles::writeNumFmts(QXmlStreamWriter &writer) const andre@1: { andre@1: if (m_customNumFmtIdMap.size() == 0) andre@1: return; andre@1: andre@1: writer.writeStartElement(QStringLiteral("numFmts")); andre@1: writer.writeAttribute(QStringLiteral("count"), QString::number(m_customNumFmtIdMap.count())); andre@1: andre@1: QMapIterator > it(m_customNumFmtIdMap); andre@1: while (it.hasNext()) { andre@1: it.next(); andre@1: writer.writeEmptyElement(QStringLiteral("numFmt")); andre@1: writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(it.value()->formatIndex)); andre@1: writer.writeAttribute(QStringLiteral("formatCode"), it.value()->formatString); andre@1: } andre@1: writer.writeEndElement();//numFmts andre@1: } andre@1: andre@1: /* andre@1: */ andre@1: void Styles::writeFonts(QXmlStreamWriter &writer) const andre@1: { andre@1: writer.writeStartElement(QStringLiteral("fonts")); andre@1: writer.writeAttribute(QStringLiteral("count"), QString::number(m_fontsList.count())); andre@1: for (int i=0; i(); andre@1: color.saveToXml(writer); andre@1: } andre@1: andre@1: if (!isDxf) { andre@1: if (!format.fontName().isEmpty()) { andre@1: writer.writeEmptyElement(QStringLiteral("name")); andre@1: writer.writeAttribute(QStringLiteral("val"), format.fontName()); andre@1: } andre@1: if (format.hasProperty(FormatPrivate::P_Font_Charset)) { andre@1: writer.writeEmptyElement(QStringLiteral("charset")); andre@1: writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Charset))); andre@1: } andre@1: if (format.hasProperty(FormatPrivate::P_Font_Family)) { andre@1: writer.writeEmptyElement(QStringLiteral("family")); andre@1: writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family))); andre@1: } andre@1: andre@1: if (format.hasProperty(FormatPrivate::P_Font_Scheme)) { andre@1: writer.writeEmptyElement(QStringLiteral("scheme")); andre@1: writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme)); andre@1: } andre@1: } andre@1: writer.writeEndElement(); //font andre@1: } andre@1: andre@1: void Styles::writeFills(QXmlStreamWriter &writer) const andre@1: { andre@1: writer.writeStartElement(QStringLiteral("fills")); andre@1: writer.writeAttribute(QStringLiteral("count"), QString::number(m_fillsList.size())); andre@1: andre@1: for (int i=0; i patternStrings; andre@1: if (patternStrings.isEmpty()) { andre@1: patternStrings[Format::PatternNone] = QStringLiteral("none"); andre@1: patternStrings[Format::PatternSolid] = QStringLiteral("solid"); andre@1: patternStrings[Format::PatternMediumGray] = QStringLiteral("mediumGray"); andre@1: patternStrings[Format::PatternDarkGray] = QStringLiteral("darkGray"); andre@1: patternStrings[Format::PatternLightGray] = QStringLiteral("lightGray"); andre@1: patternStrings[Format::PatternDarkHorizontal] = QStringLiteral("darkHorizontal"); andre@1: patternStrings[Format::PatternDarkVertical] = QStringLiteral("darkVertical"); andre@1: patternStrings[Format::PatternDarkDown] = QStringLiteral("darkDown"); andre@1: patternStrings[Format::PatternDarkUp] = QStringLiteral("darkUp"); andre@1: patternStrings[Format::PatternDarkGrid] = QStringLiteral("darkGrid"); andre@1: patternStrings[Format::PatternDarkTrellis] = QStringLiteral("darkTrellis"); andre@1: patternStrings[Format::PatternLightHorizontal] = QStringLiteral("lightHorizontal"); andre@1: patternStrings[Format::PatternLightVertical] = QStringLiteral("lightVertical"); andre@1: patternStrings[Format::PatternLightDown] = QStringLiteral("lightDown"); andre@1: patternStrings[Format::PatternLightUp] = QStringLiteral("lightUp"); andre@1: patternStrings[Format::PatternLightTrellis] = QStringLiteral("lightTrellis"); andre@1: patternStrings[Format::PatternGray125] = QStringLiteral("gray125"); andre@1: patternStrings[Format::PatternGray0625] = QStringLiteral("gray0625"); andre@1: patternStrings[Format::PatternLightGrid] = QStringLiteral("lightGrid"); andre@1: } andre@1: andre@1: writer.writeStartElement(QStringLiteral("fill")); andre@1: writer.writeStartElement(QStringLiteral("patternFill")); andre@1: Format::FillPattern pattern = fill.fillPattern(); andre@1: // For normal fill formats, Excel prefer to outputing the default "none" attribute andre@1: // But for dxf, Excel prefer to omiting the default "none" andre@1: // Though not make any difference, but it make easier to compare origin files with generate files during debug andre@1: if (!(pattern == Format::PatternNone && isDxf)) andre@1: writer.writeAttribute(QStringLiteral("patternType"), patternStrings[pattern]); andre@1: // For a solid fill, Excel reverses the role of foreground and background colours andre@1: if (fill.fillPattern() == Format::PatternSolid) { andre@1: if (fill.hasProperty(FormatPrivate::P_Fill_BgColor)) andre@1: fill.property(FormatPrivate::P_Fill_BgColor).value().saveToXml(writer, QStringLiteral("fgColor")); andre@1: if (fill.hasProperty(FormatPrivate::P_Fill_FgColor)) andre@1: fill.property(FormatPrivate::P_Fill_FgColor).value().saveToXml(writer, QStringLiteral("bgColor")); andre@1: } else { andre@1: if (fill.hasProperty(FormatPrivate::P_Fill_FgColor)) andre@1: fill.property(FormatPrivate::P_Fill_FgColor).value().saveToXml(writer, QStringLiteral("fgColor")); andre@1: if (fill.hasProperty(FormatPrivate::P_Fill_BgColor)) andre@1: fill.property(FormatPrivate::P_Fill_BgColor).value().saveToXml(writer, QStringLiteral("bgColor")); andre@1: } andre@1: writer.writeEndElement();//patternFill andre@1: writer.writeEndElement();//fill andre@1: } andre@1: andre@1: void Styles::writeBorders(QXmlStreamWriter &writer) const andre@1: { andre@1: writer.writeStartElement(QStringLiteral("borders")); andre@1: writer.writeAttribute(QStringLiteral("count"), QString::number(m_bordersList.count())); andre@1: for (int i=0; i()); andre@1: writeSubBorder(writer, QStringLiteral("right"), border.rightBorderStyle(), border.property(FormatPrivate::P_Border_RightColor).value()); andre@1: writeSubBorder(writer, QStringLiteral("top"), border.topBorderStyle(), border.property(FormatPrivate::P_Border_TopColor).value()); andre@1: writeSubBorder(writer, QStringLiteral("bottom"), border.bottomBorderStyle(), border.property(FormatPrivate::P_Border_BottomColor).value()); andre@1: andre@1: //Condition DXF formats don't allow diagonal style andre@1: if (!isDxf) andre@1: writeSubBorder(writer, QStringLiteral("diagonal"), border.diagonalBorderStyle(), border.property(FormatPrivate::P_Border_DiagonalColor).value()); andre@1: andre@1: if (isDxf) { andre@1: // writeSubBorder(wirter, QStringLiteral("vertical"), ); andre@1: // writeSubBorder(writer, QStringLiteral("horizontal"), ); andre@1: } andre@1: andre@1: writer.writeEndElement();//border andre@1: } andre@1: andre@1: void Styles::writeSubBorder(QXmlStreamWriter &writer, const QString &type, int style, const XlsxColor &color) const andre@1: { andre@1: if (style == Format::BorderNone) { andre@1: writer.writeEmptyElement(type); andre@1: return; andre@1: } andre@1: andre@1: static QMap stylesString; andre@1: if (stylesString.isEmpty()) { andre@1: stylesString[Format::BorderNone] = QStringLiteral("none"); andre@1: stylesString[Format::BorderThin] = QStringLiteral("thin"); andre@1: stylesString[Format::BorderMedium] = QStringLiteral("medium"); andre@1: stylesString[Format::BorderDashed] = QStringLiteral("dashed"); andre@1: stylesString[Format::BorderDotted] = QStringLiteral("dotted"); andre@1: stylesString[Format::BorderThick] = QStringLiteral("thick"); andre@1: stylesString[Format::BorderDouble] = QStringLiteral("double"); andre@1: stylesString[Format::BorderHair] = QStringLiteral("hair"); andre@1: stylesString[Format::BorderMediumDashed] = QStringLiteral("mediumDashed"); andre@1: stylesString[Format::BorderDashDot] = QStringLiteral("dashDot"); andre@1: stylesString[Format::BorderMediumDashDot] = QStringLiteral("mediumDashDot"); andre@1: stylesString[Format::BorderDashDotDot] = QStringLiteral("dashDotDot"); andre@1: stylesString[Format::BorderMediumDashDotDot] = QStringLiteral("mediumDashDotDot"); andre@1: stylesString[Format::BorderSlantDashDot] = QStringLiteral("slantDashDot"); andre@1: } andre@1: andre@1: writer.writeStartElement(type); andre@1: writer.writeAttribute(QStringLiteral("style"), stylesString[style]); andre@1: color.saveToXml(writer); //write color element andre@1: andre@1: writer.writeEndElement();//type andre@1: } andre@1: andre@1: void Styles::writeCellXfs(QXmlStreamWriter &writer) const andre@1: { andre@1: writer.writeStartElement(QStringLiteral("cellXfs")); andre@1: writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size())); andre@1: foreach (const Format &format, m_xf_formatsList) { andre@1: int xf_id = 0; andre@1: writer.writeStartElement(QStringLiteral("xf")); andre@1: writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex())); andre@1: writer.writeAttribute(QStringLiteral("fontId"), QString::number(format.fontIndex())); andre@1: writer.writeAttribute(QStringLiteral("fillId"), QString::number(format.fillIndex())); andre@1: writer.writeAttribute(QStringLiteral("borderId"), QString::number(format.borderIndex())); andre@1: writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id)); andre@1: if (format.hasNumFmtData()) andre@1: writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1")); andre@1: if (format.hasFontData()) andre@1: writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1")); andre@1: if (format.hasFillData()) andre@1: writer.writeAttribute(QStringLiteral("applyFill"), QStringLiteral("1")); andre@1: if (format.hasBorderData()) andre@1: writer.writeAttribute(QStringLiteral("applyBorder"), QStringLiteral("1")); andre@1: if (format.hasAlignmentData()) andre@1: writer.writeAttribute(QStringLiteral("applyAlignment"), QStringLiteral("1")); andre@1: andre@1: if (format.hasAlignmentData()) { andre@1: writer.writeEmptyElement(QStringLiteral("alignment")); andre@1: if (format.hasProperty(FormatPrivate::P_Alignment_AlignH)) { andre@1: switch (format.horizontalAlignment()) { andre@1: case Format::AlignLeft: andre@1: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("left")); andre@1: break; andre@1: case Format::AlignHCenter: andre@1: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("center")); andre@1: break; andre@1: case Format::AlignRight: andre@1: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("right")); andre@1: break; andre@1: case Format::AlignHFill: andre@1: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("fill")); andre@1: break; andre@1: case Format::AlignHJustify: andre@1: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("justify")); andre@1: break; andre@1: case Format::AlignHMerge: andre@1: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("centerContinuous")); andre@1: break; andre@1: case Format::AlignHDistributed: andre@1: writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("distributed")); andre@1: break; andre@1: default: andre@1: break; andre@1: } andre@1: } andre@1: andre@1: if (format.hasProperty(FormatPrivate::P_Alignment_AlignV)) { andre@1: switch (format.verticalAlignment()) { andre@1: case Format::AlignTop: andre@1: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("top")); andre@1: break; andre@1: case Format::AlignVCenter: andre@1: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("center")); andre@1: break; andre@1: case Format::AlignVJustify: andre@1: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("justify")); andre@1: break; andre@1: case Format::AlignVDistributed: andre@1: writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("distributed")); andre@1: break; andre@1: default: andre@1: break; andre@1: } andre@1: } andre@1: if (format.hasProperty(FormatPrivate::P_Alignment_Indent)) andre@1: writer.writeAttribute(QStringLiteral("indent"), QString::number(format.indent())); andre@1: if (format.hasProperty(FormatPrivate::P_Alignment_Wrap) && format.textWrap()) andre@1: writer.writeAttribute(QStringLiteral("wrapText"), QStringLiteral("1")); andre@1: if (format.hasProperty(FormatPrivate::P_Alignment_ShinkToFit) && format.shrinkToFit()) andre@1: writer.writeAttribute(QStringLiteral("shrinkToFit"), QStringLiteral("1")); andre@1: if (format.hasProperty(FormatPrivate::P_Alignment_Rotation)) andre@1: writer.writeAttribute(QStringLiteral("textRotation"), QString::number(format.rotation())); andre@1: } andre@1: andre@1: writer.writeEndElement();//xf andre@1: } andre@1: writer.writeEndElement();//cellXfs andre@1: } andre@1: andre@1: void Styles::writeDxfs(QXmlStreamWriter &writer) const andre@1: { andre@1: writer.writeStartElement(QStringLiteral("dxfs")); andre@1: writer.writeAttribute(QStringLiteral("count"), QString::number(m_dxf_formatsList.size())); andre@1: foreach (const Format &format, m_dxf_formatsList) andre@1: writeDxf(writer, format); andre@1: writer.writeEndElement(); //dxfs andre@1: } andre@1: andre@1: void Styles::writeDxf(QXmlStreamWriter &writer, const Format &format) const andre@1: { andre@1: writer.writeStartElement(QStringLiteral("dxf")); andre@1: andre@1: if (format.hasFontData()) andre@1: writeFont(writer, format, true); andre@1: andre@1: if (format.hasNumFmtData()) { andre@1: writer.writeEmptyElement(QStringLiteral("numFmt")); andre@1: writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex())); andre@1: writer.writeAttribute(QStringLiteral("formatCode"), format.numberFormat()); andre@1: } andre@1: andre@1: if (format.hasFillData()) andre@1: writeFill(writer, format, true); andre@1: andre@1: if (format.hasBorderData()) andre@1: writeBorder(writer, format, true); andre@1: andre@1: writer.writeEndElement();//dxf andre@1: } andre@1: andre@1: void Styles::writeColors(QXmlStreamWriter &writer) const andre@1: { andre@1: if (m_isIndexedColorsDefault) //Don't output the default indexdeColors andre@1: return; andre@1: andre@1: writer.writeStartElement(QStringLiteral("colors")); andre@1: andre@1: writer.writeStartElement(QStringLiteral("indexedColors")); andre@1: foreach(QColor color, m_indexedColors) { andre@1: writer.writeEmptyElement(QStringLiteral("rgbColor")); andre@1: writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(color)); andre@1: } andre@1: andre@1: writer.writeEndElement();//indexedColors andre@1: andre@1: writer.writeEndElement();//colors andre@1: } andre@1: andre@1: bool Styles::readNumFmts(QXmlStreamReader &reader) andre@1: { andre@1: Q_ASSERT(reader.name() == QLatin1String("numFmts")); andre@1: QXmlStreamAttributes attributes = reader.attributes(); andre@1: bool hasCount = attributes.hasAttribute(QLatin1String("count")); andre@1: int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1; andre@1: andre@1: //Read utill we find the numFmts end tag or .... andre@1: while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement andre@1: && reader.name() == QLatin1String("numFmts"))) { andre@1: reader.readNextStartElement(); andre@1: if (reader.tokenType() == QXmlStreamReader::StartElement) { andre@1: if (reader.name() == QLatin1String("numFmt")) { andre@1: QXmlStreamAttributes attributes = reader.attributes(); andre@1: QSharedPointer fmt (new XlsxFormatNumberData); andre@1: fmt->formatIndex = attributes.value(QLatin1String("numFmtId")).toString().toInt(); andre@1: fmt->formatString = attributes.value(QLatin1String("formatCode")).toString(); andre@1: if (fmt->formatIndex >= m_nextCustomNumFmtId) andre@1: m_nextCustomNumFmtId = fmt->formatIndex + 1; andre@1: m_customNumFmtIdMap.insert(fmt->formatIndex, fmt); andre@1: m_customNumFmtsHash.insert(fmt->formatString, fmt); andre@1: } andre@1: } andre@1: } andre@1: andre@1: if (reader.hasError()) andre@1: qWarning()< patternValues; andre@1: if (patternValues.isEmpty()) { andre@1: patternValues[QStringLiteral("none")] = Format::PatternNone; andre@1: patternValues[QStringLiteral("solid")] = Format::PatternSolid; andre@1: patternValues[QStringLiteral("mediumGray")] = Format::PatternMediumGray; andre@1: patternValues[QStringLiteral("darkGray")] = Format::PatternDarkGray; andre@1: patternValues[QStringLiteral("lightGray")] = Format::PatternLightGray; andre@1: patternValues[QStringLiteral("darkHorizontal")] = Format::PatternDarkHorizontal; andre@1: patternValues[QStringLiteral("darkVertical")] = Format::PatternDarkVertical; andre@1: patternValues[QStringLiteral("darkDown")] = Format::PatternDarkDown; andre@1: patternValues[QStringLiteral("darkUp")] = Format::PatternDarkUp; andre@1: patternValues[QStringLiteral("darkGrid")] = Format::PatternDarkGrid; andre@1: patternValues[QStringLiteral("darkTrellis")] = Format::PatternDarkTrellis; andre@1: patternValues[QStringLiteral("lightHorizontal")] = Format::PatternLightHorizontal; andre@1: patternValues[QStringLiteral("lightVertical")] = Format::PatternLightVertical; andre@1: patternValues[QStringLiteral("lightDown")] = Format::PatternLightDown; andre@1: patternValues[QStringLiteral("lightUp")] = Format::PatternLightUp; andre@1: patternValues[QStringLiteral("lightTrellis")] = Format::PatternLightTrellis; andre@1: patternValues[QStringLiteral("gray125")] = Format::PatternGray125; andre@1: patternValues[QStringLiteral("gray0625")] = Format::PatternGray0625; andre@1: patternValues[QStringLiteral("lightGrid")] = Format::PatternLightGrid; andre@1: } andre@1: andre@1: while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fill"))) { andre@1: reader.readNextStartElement(); andre@1: if (reader.tokenType() == QXmlStreamReader::StartElement) { andre@1: if (reader.name() == QLatin1String("patternFill")) { andre@1: QXmlStreamAttributes attributes = reader.attributes(); andre@1: if (attributes.hasAttribute(QLatin1String("patternType"))) { andre@1: QString pattern = attributes.value(QLatin1String("patternType")).toString(); andre@1: fill.setFillPattern(patternValues.contains(pattern) ? patternValues[pattern] : Format::PatternNone); andre@1: andre@1: //parse foreground and background colors if they exist andre@1: while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("patternFill"))) { andre@1: reader.readNextStartElement(); andre@1: if (reader.tokenType() == QXmlStreamReader::StartElement) { andre@1: if (reader.name() == QLatin1String("fgColor")) { andre@1: XlsxColor c; andre@1: c.loadFromXml(reader); andre@1: if (fill.fillPattern() == Format::PatternSolid) andre@1: fill.setProperty(FormatPrivate::P_Fill_BgColor, c); andre@1: else andre@1: fill.setProperty(FormatPrivate::P_Fill_FgColor, c); andre@1: } else if (reader.name() == QLatin1String("bgColor")) { andre@1: XlsxColor c; andre@1: c.loadFromXml(reader); andre@1: if (fill.fillPattern() == Format::PatternSolid) andre@1: fill.setProperty(FormatPrivate::P_Fill_FgColor, c); andre@1: else andre@1: fill.setProperty(FormatPrivate::P_Fill_BgColor, c); andre@1: } andre@1: } andre@1: } andre@1: } andre@1: } andre@1: } andre@1: } andre@1: andre@1: return true; andre@1: } andre@1: andre@1: bool Styles::readBorders(QXmlStreamReader &reader) andre@1: { andre@1: Q_ASSERT(reader.name() == QLatin1String("borders")); andre@1: andre@1: QXmlStreamAttributes attributes = reader.attributes(); andre@1: bool hasCount = attributes.hasAttribute(QLatin1String("count")); andre@1: int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1; andre@1: while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement andre@1: && reader.name() == QLatin1String("borders"))) { andre@1: reader.readNextStartElement(); andre@1: if (reader.tokenType() == QXmlStreamReader::StartElement) { andre@1: if (reader.name() == QLatin1String("border")) { andre@1: Format border; andre@1: readBorder(reader, border); andre@1: m_bordersList.append(border); andre@1: m_bordersHash.insert(border.borderKey(), border); andre@1: if (border.isValid()) andre@1: border.setBorderIndex(m_bordersList.size()-1); andre@1: } andre@1: } andre@1: } andre@1: andre@1: if (reader.hasError()) andre@1: qWarning()< stylesStringsMap; andre@1: if (stylesStringsMap.isEmpty()) { andre@1: stylesStringsMap[QStringLiteral("none")] = Format::BorderNone; andre@1: stylesStringsMap[QStringLiteral("thin")] = Format::BorderThin; andre@1: stylesStringsMap[QStringLiteral("medium")] = Format::BorderMedium; andre@1: stylesStringsMap[QStringLiteral("dashed")] = Format::BorderDashed; andre@1: stylesStringsMap[QStringLiteral("dotted")] = Format::BorderDotted; andre@1: stylesStringsMap[QStringLiteral("thick")] = Format::BorderThick; andre@1: stylesStringsMap[QStringLiteral("double")] = Format::BorderDouble; andre@1: stylesStringsMap[QStringLiteral("hair")] = Format::BorderHair; andre@1: stylesStringsMap[QStringLiteral("mediumDashed")] = Format::BorderMediumDashed; andre@1: stylesStringsMap[QStringLiteral("dashDot")] = Format::BorderDashDot; andre@1: stylesStringsMap[QStringLiteral("mediumDashDot")] = Format::BorderMediumDashDot; andre@1: stylesStringsMap[QStringLiteral("dashDotDot")] = Format::BorderDashDotDot; andre@1: stylesStringsMap[QStringLiteral("mediumDashDotDot")] = Format::BorderMediumDashDotDot; andre@1: stylesStringsMap[QStringLiteral("slantDashDot")] = Format::BorderSlantDashDot; andre@1: } andre@1: andre@1: QXmlStreamAttributes attributes = reader.attributes(); andre@1: if (attributes.hasAttribute(QLatin1String("style"))) { andre@1: QString styleString = attributes.value(QLatin1String("style")).toString(); andre@1: if (stylesStringsMap.contains(styleString)) { andre@1: //get style andre@1: style = stylesStringsMap[styleString]; andre@1: while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) { andre@1: reader.readNextStartElement(); andre@1: if (reader.tokenType() == QXmlStreamReader::StartElement) { andre@1: if (reader.name() == QLatin1String("color")) andre@1: color.loadFromXml(reader); andre@1: } andre@1: } andre@1: } andre@1: } andre@1: andre@1: return true; andre@1: } andre@1: andre@1: bool Styles::readCellXfs(QXmlStreamReader &reader) andre@1: { andre@1: Q_ASSERT(reader.name() == QLatin1String("cellXfs")); andre@1: QXmlStreamAttributes attributes = reader.attributes(); andre@1: bool hasCount = attributes.hasAttribute(QLatin1String("count")); andre@1: int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1; andre@1: while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement andre@1: && reader.name() == QLatin1String("cellXfs"))) { andre@1: reader.readNextStartElement(); andre@1: if (reader.tokenType() == QXmlStreamReader::StartElement) { andre@1: if (reader.name() == QLatin1String("xf")) { andre@1: andre@1: Format format; andre@1: QXmlStreamAttributes xfAttrs = reader.attributes(); andre@1: andre@1: // qDebug()<formatString); andre@1: } andre@1: } andre@1: andre@1: if (xfAttrs.hasAttribute(QLatin1String("fontId"))) { andre@1: int fontIndex = xfAttrs.value(QLatin1String("fontId")).toString().toInt(); andre@1: if (fontIndex >= m_fontsList.size()) { andre@1: qDebug("Error read styles.xml, cellXfs fontId"); andre@1: } else { andre@1: bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFont")).toString()); andre@1: if(apply) { andre@1: Format fontFormat = m_fontsList[fontIndex]; andre@1: for (int i=FormatPrivate::P_Font_STARTID; i= m_fillsList.size()) { andre@1: qDebug("Error read styles.xml, cellXfs fillId"); andre@1: } else { andre@1: bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFill")).toString()); andre@1: if(apply) { andre@1: Format fillFormat = m_fillsList[id]; andre@1: for (int i=FormatPrivate::P_Fill_STARTID; i= m_bordersList.size()) { andre@1: qDebug("Error read styles.xml, cellXfs borderId"); andre@1: } else { andre@1: bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyBorder")).toString()); andre@1: if(apply) { andre@1: Format borderFormat = m_bordersList[id]; andre@1: for (int i=FormatPrivate::P_Border_STARTID; i alignStringMap; andre@1: if (alignStringMap.isEmpty()) { andre@1: alignStringMap.insert(QStringLiteral("left"), Format::AlignLeft); andre@1: alignStringMap.insert(QStringLiteral("center"), Format::AlignHCenter); andre@1: alignStringMap.insert(QStringLiteral("right"), Format::AlignRight); andre@1: alignStringMap.insert(QStringLiteral("justify"), Format::AlignHJustify); andre@1: alignStringMap.insert(QStringLiteral("centerContinuous"), Format::AlignHMerge); andre@1: alignStringMap.insert(QStringLiteral("distributed"), Format::AlignHDistributed); andre@1: } andre@1: QString str = alignAttrs.value(QLatin1String("horizontal")).toString(); andre@1: if (alignStringMap.contains(str)) andre@1: format.setHorizontalAlignment(alignStringMap[str]); andre@1: } andre@1: andre@1: if (alignAttrs.hasAttribute(QLatin1String("vertical"))) { andre@1: static QMap alignStringMap; andre@1: if (alignStringMap.isEmpty()) { andre@1: alignStringMap.insert(QStringLiteral("top"), Format::AlignTop); andre@1: alignStringMap.insert(QStringLiteral("center"), Format::AlignVCenter); andre@1: alignStringMap.insert(QStringLiteral("justify"), Format::AlignVJustify); andre@1: alignStringMap.insert(QStringLiteral("distributed"), Format::AlignVDistributed); andre@1: } andre@1: QString str = alignAttrs.value(QLatin1String("vertical")).toString(); andre@1: if (alignStringMap.contains(str)) andre@1: format.setVerticalAlignment(alignStringMap[str]); andre@1: } andre@1: andre@1: if (alignAttrs.hasAttribute(QLatin1String("indent"))) { andre@1: int indent = alignAttrs.value(QLatin1String("indent")).toString().toInt(); andre@1: format.setIndent(indent); andre@1: } andre@1: andre@1: if (alignAttrs.hasAttribute(QLatin1String("textRotation"))) { andre@1: int rotation = alignAttrs.value(QLatin1String("textRotation")).toString().toInt(); andre@1: format.setRotation(rotation); andre@1: } andre@1: andre@1: if (alignAttrs.hasAttribute(QLatin1String("wrapText"))) andre@1: format.setTextWarp(true); andre@1: andre@1: if (alignAttrs.hasAttribute(QLatin1String("shrinkToFit"))) andre@1: format.setShrinkToFit(true); andre@1: andre@1: } andre@1: } andre@1: andre@1: addXfFormat(format, true); andre@1: } andre@1: } andre@1: } andre@1: andre@1: if (reader.hasError()) andre@1: qWarning()<= m_indexedColors.size()) andre@1: return QColor(); andre@1: return m_indexedColors[idx]; andre@1: } andre@1: andre@1: } //namespace QXlsx