/**************************************************************************** ** Copyright (c) 2013-2014 Debao Zhang ** All right reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the ** "Software"), to deal in the Software without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Software, and to ** permit persons to whom the Software is furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be ** included in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** ****************************************************************************/ #include "xlsxstyles_p.h" #include "xlsxformat_p.h" #include "xlsxutility_p.h" #include "xlsxcolor_p.h" #include #include #include #include #include #include #include namespace QXlsx { /* 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? if (QMetaType::type("XlsxColor") == QMetaType::UnknownType) { qRegisterMetaType("XlsxColor"); qRegisterMetaTypeStreamOperators("XlsxColor"); #if QT_VERSION >= 0x050200 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]; } 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); } const QString str = format.numberFormat(); if (!str.isEmpty()) { //Assign proper number format index if (m_builtinNumFmtsHash.contains(str)) { const_cast(&format)->fixNumberFormat(m_builtinNumFmtsHash[str], str); } else if (m_customNumFmtsHash.contains(str)) { const_cast(&format)->fixNumberFormat(m_customNumFmtsHash[str]->formatIndex, str); } else { //Assign a new fmt Id. const_cast(&format)->fixNumberFormat(m_nextCustomNumFmtId, str); QSharedPointer fmt(new XlsxFormatNumberData); fmt->formatIndex = m_nextCustomNumFmtId; fmt->formatString = str; m_customNumFmtIdMap.insert(m_nextCustomNumFmtId, fmt); m_customNumFmtsHash.insert(str, fmt); m_nextCustomNumFmtId += 1; } } else { int id = format.numberFormatIndex(); //Assign proper format code, this is needed by dxf format if (m_customNumFmtIdMap.contains(id)) { const_cast(&format)->fixNumberFormat(id, m_customNumFmtIdMap[id]->formatString); } else { QHashIterator it(m_builtinNumFmtsHash); bool find=false; while (it.hasNext()) { it.next(); if (it.value() == id) const_cast(&format)->fixNumberFormat(id, it.key()); find = true; break; } if (!find) { //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 if (format.hasFontData() && !format.fontIndexValid()) { //Assign proper font index, if has font data. if (!m_fontsHash.contains(format.fontKey())) const_cast(&format)->setFontIndex(m_fontsList.size()); else const_cast(&format)->setFontIndex(m_fontsHash[format.fontKey()].fontIndex()); } if (!m_fontsHash.contains(format.fontKey())) { //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 if (format.hasFillData() && !format.fillIndexValid()) { //Assign proper fill index, if has fill data. if (!m_fillsHash.contains(format.fillKey())) const_cast(&format)->setFillIndex(m_fillsList.size()); else const_cast(&format)->setFillIndex(m_fillsHash[format.fillKey()].fillIndex()); } if (!m_fillsHash.contains(format.fillKey())) { //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 if (format.hasBorderData() && !format.borderIndexValid()) { //Assign proper border index, if has border data. if (!m_bordersHash.contains(format.borderKey())) const_cast(&format)->setBorderIndex(m_bordersList.size()); else const_cast(&format)->setBorderIndex(m_bordersHash[format.borderKey()].borderIndex()); } if (!m_bordersHash.contains(format.borderKey())) { //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 if (!format.isEmpty() && !format.xfIndexValid()) { if (m_xf_formatsHash.contains(format.formatKey())) const_cast(&format)->setXfIndex(m_xf_formatsHash[format.formatKey()].xfIndex()); else const_cast(&format)->setXfIndex(m_xf_formatsList.size()); } if (!m_xf_formatsHash.contains(format.formatKey()) || 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); if (!format.isEmpty() && !format.dxfIndexValid()) { if (m_dxf_formatsHash.contains(format.formatKey())) const_cast(&format)->setDxfIndex(m_dxf_formatsHash[format.formatKey()].dxfIndex()); else const_cast(&format)->setDxfIndex(m_dxf_formatsList.size()); } if (!m_dxf_formatsHash.contains(format.formatKey()) || 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.size() == 0) 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 (int i=0; i(); 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 (int i=0; i patternStrings; if (patternStrings.isEmpty()) { patternStrings[Format::PatternNone] = QStringLiteral("none"); patternStrings[Format::PatternSolid] = QStringLiteral("solid"); patternStrings[Format::PatternMediumGray] = QStringLiteral("mediumGray"); patternStrings[Format::PatternDarkGray] = QStringLiteral("darkGray"); patternStrings[Format::PatternLightGray] = QStringLiteral("lightGray"); patternStrings[Format::PatternDarkHorizontal] = QStringLiteral("darkHorizontal"); patternStrings[Format::PatternDarkVertical] = QStringLiteral("darkVertical"); patternStrings[Format::PatternDarkDown] = QStringLiteral("darkDown"); patternStrings[Format::PatternDarkUp] = QStringLiteral("darkUp"); patternStrings[Format::PatternDarkGrid] = QStringLiteral("darkGrid"); patternStrings[Format::PatternDarkTrellis] = QStringLiteral("darkTrellis"); patternStrings[Format::PatternLightHorizontal] = QStringLiteral("lightHorizontal"); patternStrings[Format::PatternLightVertical] = QStringLiteral("lightVertical"); patternStrings[Format::PatternLightDown] = QStringLiteral("lightDown"); patternStrings[Format::PatternLightUp] = QStringLiteral("lightUp"); patternStrings[Format::PatternLightTrellis] = QStringLiteral("lightTrellis"); patternStrings[Format::PatternGray125] = QStringLiteral("gray125"); patternStrings[Format::PatternGray0625] = QStringLiteral("gray0625"); patternStrings[Format::PatternLightGrid] = QStringLiteral("lightGrid"); } writer.writeStartElement(QStringLiteral("fill")); writer.writeStartElement(QStringLiteral("patternFill")); Format::FillPattern pattern = fill.fillPattern(); // For normal fill formats, Excel prefer to outputing the default "none" attribute // But for dxf, Excel prefer to omiting 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 (int i=0; i()); 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(wirter, 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 QMap stylesString; if (stylesString.isEmpty()) { stylesString[Format::BorderNone] = QStringLiteral("none"); stylesString[Format::BorderThin] = QStringLiteral("thin"); stylesString[Format::BorderMedium] = QStringLiteral("medium"); stylesString[Format::BorderDashed] = QStringLiteral("dashed"); stylesString[Format::BorderDotted] = QStringLiteral("dotted"); stylesString[Format::BorderThick] = QStringLiteral("thick"); stylesString[Format::BorderDouble] = QStringLiteral("double"); stylesString[Format::BorderHair] = QStringLiteral("hair"); stylesString[Format::BorderMediumDashed] = QStringLiteral("mediumDashed"); stylesString[Format::BorderDashDot] = QStringLiteral("dashDot"); stylesString[Format::BorderMediumDashDot] = QStringLiteral("mediumDashDot"); stylesString[Format::BorderDashDotDot] = QStringLiteral("dashDotDot"); stylesString[Format::BorderMediumDashDotDot] = QStringLiteral("mediumDashDotDot"); stylesString[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())); foreach (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())); foreach (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")); foreach(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")); QXmlStreamAttributes attributes = reader.attributes(); bool hasCount = attributes.hasAttribute(QLatin1String("count")); int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1; //Read utill 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")) { QXmlStreamAttributes attributes = reader.attributes(); QSharedPointer fmt (new XlsxFormatNumberData); fmt->formatIndex = attributes.value(QLatin1String("numFmtId")).toString().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()< patternValues; if (patternValues.isEmpty()) { patternValues[QStringLiteral("none")] = Format::PatternNone; patternValues[QStringLiteral("solid")] = Format::PatternSolid; patternValues[QStringLiteral("mediumGray")] = Format::PatternMediumGray; patternValues[QStringLiteral("darkGray")] = Format::PatternDarkGray; patternValues[QStringLiteral("lightGray")] = Format::PatternLightGray; patternValues[QStringLiteral("darkHorizontal")] = Format::PatternDarkHorizontal; patternValues[QStringLiteral("darkVertical")] = Format::PatternDarkVertical; patternValues[QStringLiteral("darkDown")] = Format::PatternDarkDown; patternValues[QStringLiteral("darkUp")] = Format::PatternDarkUp; patternValues[QStringLiteral("darkGrid")] = Format::PatternDarkGrid; patternValues[QStringLiteral("darkTrellis")] = Format::PatternDarkTrellis; patternValues[QStringLiteral("lightHorizontal")] = Format::PatternLightHorizontal; patternValues[QStringLiteral("lightVertical")] = Format::PatternLightVertical; patternValues[QStringLiteral("lightDown")] = Format::PatternLightDown; patternValues[QStringLiteral("lightUp")] = Format::PatternLightUp; patternValues[QStringLiteral("lightTrellis")] = Format::PatternLightTrellis; patternValues[QStringLiteral("gray125")] = Format::PatternGray125; patternValues[QStringLiteral("gray0625")] = Format::PatternGray0625; patternValues[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")) { QXmlStreamAttributes attributes = reader.attributes(); if (attributes.hasAttribute(QLatin1String("patternType"))) { QString pattern = attributes.value(QLatin1String("patternType")).toString(); fill.setFillPattern(patternValues.contains(pattern) ? patternValues[pattern] : Format::PatternNone); } } else if (reader.name() == QLatin1String("fgColor")) { XlsxColor c; 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; 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")); QXmlStreamAttributes attributes = reader.attributes(); bool hasCount = attributes.hasAttribute(QLatin1String("count")); int count = hasCount ? attributes.value(QLatin1String("count")).toString().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()< stylesStringsMap; if (stylesStringsMap.isEmpty()) { stylesStringsMap[QStringLiteral("none")] = Format::BorderNone; stylesStringsMap[QStringLiteral("thin")] = Format::BorderThin; stylesStringsMap[QStringLiteral("medium")] = Format::BorderMedium; stylesStringsMap[QStringLiteral("dashed")] = Format::BorderDashed; stylesStringsMap[QStringLiteral("dotted")] = Format::BorderDotted; stylesStringsMap[QStringLiteral("thick")] = Format::BorderThick; stylesStringsMap[QStringLiteral("double")] = Format::BorderDouble; stylesStringsMap[QStringLiteral("hair")] = Format::BorderHair; stylesStringsMap[QStringLiteral("mediumDashed")] = Format::BorderMediumDashed; stylesStringsMap[QStringLiteral("dashDot")] = Format::BorderDashDot; stylesStringsMap[QStringLiteral("mediumDashDot")] = Format::BorderMediumDashDot; stylesStringsMap[QStringLiteral("dashDotDot")] = Format::BorderDashDotDot; stylesStringsMap[QStringLiteral("mediumDashDotDot")] = Format::BorderMediumDashDotDot; stylesStringsMap[QStringLiteral("slantDashDot")] = Format::BorderSlantDashDot; } QXmlStreamAttributes attributes = reader.attributes(); if (attributes.hasAttribute(QLatin1String("style"))) { QString styleString = attributes.value(QLatin1String("style")).toString(); if (stylesStringsMap.contains(styleString)) { //get style style = stylesStringsMap[styleString]; 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")); QXmlStreamAttributes attributes = reader.attributes(); bool hasCount = attributes.hasAttribute(QLatin1String("count")); int count = hasCount ? attributes.value(QLatin1String("count")).toString().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; QXmlStreamAttributes xfAttrs = reader.attributes(); // qDebug()<formatString); } if (xfAttrs.hasAttribute(QLatin1String("applyFont"))) { int fontIndex = xfAttrs.value(QLatin1String("fontId")).toString().toInt(); if (fontIndex >= m_fontsList.size()) { qDebug("Error read styles.xml, cellXfs fontId"); } else { Format fontFormat = m_fontsList[fontIndex]; for (int i=FormatPrivate::P_Font_STARTID; i= m_fillsList.size()) { qDebug("Error read styles.xml, cellXfs fillId"); } else { Format fillFormat = m_fillsList[id]; for (int i=FormatPrivate::P_Fill_STARTID; i= m_bordersList.size()) { qDebug("Error read styles.xml, cellXfs borderId"); } else { Format borderFormat = m_bordersList[id]; for (int i=FormatPrivate::P_Border_STARTID; i alignStringMap; if (alignStringMap.isEmpty()) { alignStringMap.insert(QStringLiteral("left"), Format::AlignLeft); alignStringMap.insert(QStringLiteral("center"), Format::AlignHCenter); alignStringMap.insert(QStringLiteral("right"), Format::AlignRight); alignStringMap.insert(QStringLiteral("justify"), Format::AlignHJustify); alignStringMap.insert(QStringLiteral("centerContinuous"), Format::AlignHMerge); alignStringMap.insert(QStringLiteral("distributed"), Format::AlignHDistributed); } QString str = alignAttrs.value(QLatin1String("horizontal")).toString(); if (alignStringMap.contains(str)) format.setHorizontalAlignment(alignStringMap[str]); } if (alignAttrs.hasAttribute(QLatin1String("vertical"))) { static QMap alignStringMap; if (alignStringMap.isEmpty()) { alignStringMap.insert(QStringLiteral("top"), Format::AlignTop); alignStringMap.insert(QStringLiteral("center"), Format::AlignVCenter); alignStringMap.insert(QStringLiteral("justify"), Format::AlignVJustify); alignStringMap.insert(QStringLiteral("distributed"), Format::AlignVDistributed); } QString str = alignAttrs.value(QLatin1String("vertical")).toString(); if (alignStringMap.contains(str)) format.setVerticalAlignment(alignStringMap[str]); } if (alignAttrs.hasAttribute(QLatin1String("indent"))) { int indent = alignAttrs.value(QLatin1String("indent")).toString().toInt(); format.setIndent(indent); } if (alignAttrs.hasAttribute(QLatin1String("textRotation"))) { int rotation = alignAttrs.value(QLatin1String("textRotation")).toString().toInt(); format.setRotation(rotation); } if (alignAttrs.hasAttribute(QLatin1String("wrapText"))) format.setTextWarp(true); if (alignAttrs.hasAttribute(QLatin1String("shrinkToFit"))) format.setShrinkToFit(true); } } addXfFormat(format, true); } } } if (reader.hasError()) qWarning()<= m_indexedColors.size()) return QColor(); return m_indexedColors[idx]; } } //namespace QXlsx