From 9abb26127c0b088ce749683673f12126b504a46c Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Tue, 22 Oct 2013 11:30:06 +0800 Subject: [PATCH] Can read .xlsx files with fill styles now --- examples/xlsx/readwrite/main.cpp | 1 + src/xlsx/xlsxstyles.cpp | 100 ++++++++++++++++++++++++--- src/xlsx/xlsxstyles_p.h | 3 + src/xlsx/xlsxutility.cpp | 11 +++ src/xlsx/xlsxutility_p.h | 2 + src/xlsx/xlsxxmlreader.cpp | 5 ++ src/xlsx/xlsxxmlreader_p.h | 7 +- tests/auto/styles/tst_stylestest.cpp | 45 ++++++++++++ 8 files changed, 163 insertions(+), 11 deletions(-) diff --git a/examples/xlsx/readwrite/main.cpp b/examples/xlsx/readwrite/main.cpp index 8590e61..1c5b98f 100644 --- a/examples/xlsx/readwrite/main.cpp +++ b/examples/xlsx/readwrite/main.cpp @@ -12,6 +12,7 @@ int main() QXlsx::Format *format = xlsx.createFormat(); format->setFontColor(QColor(Qt::blue)); format->setFontSize(15); + format->setPatternBackgroundColor(QColor(Qt::gray)); xlsx.write("A1", "Hello Qt!", format); xlsx.write("A2", 500); xlsx.saveAs("first.xlsx"); diff --git a/src/xlsx/xlsxstyles.cpp b/src/xlsx/xlsxstyles.cpp index eb20cc2..1c7429a 100755 --- a/src/xlsx/xlsxstyles.cpp +++ b/src/xlsx/xlsxstyles.cpp @@ -26,6 +26,7 @@ #include "xlsxxmlwriter_p.h" #include "xlsxxmlreader_p.h" #include "xlsxformat_p.h" +#include "xlsxutility_p.h" #include #include #include @@ -560,7 +561,7 @@ bool Styles::readFonts(XmlStreamReader &reader) if (reader.name() != QLatin1String("font")) return false; QSharedPointer font(new FontData); - while(reader.readNextStartElement()) { + while((reader.readNextStartElement(),true)) { //read until font endelement. if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("b")) { font->bold = true; @@ -596,11 +597,7 @@ bool Styles::readFonts(XmlStreamReader &reader) QXmlStreamAttributes attributes = reader.attributes(); if (attributes.hasAttribute(QLatin1String("rgb"))) { QString colorString = attributes.value(QLatin1String("rgb")).toString(); - if (colorString.length() == 8) { - font->color.setRed(colorString.mid(2,2).toInt(0, 16)); - font->color.setGreen(colorString.mid(4,2).toInt(0, 16)); - font->color.setBlue(colorString.mid(6,2).toInt(0, 16)); - } + font->color = fromARGBString(colorString); } else if (attributes.hasAttribute(QLatin1String("indexed"))) { } else if (attributes.hasAttribute(QLatin1String("theme"))) { @@ -627,8 +624,82 @@ bool Styles::readFonts(XmlStreamReader &reader) bool Styles::readFills(XmlStreamReader &reader) { + Q_ASSERT(reader.name() == QLatin1String("fills")); - return false; + QXmlStreamAttributes attributes = reader.attributes(); + int count = attributes.value(QLatin1String("count")).toInt(); + for (int i=0; i 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; + } + + QSharedPointer fill(new FillData); + while((reader.readNextStartElement(), true)) { //read until fill endelement + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("patternFill")) { + QXmlStreamAttributes attributes = reader.attributes(); + QString pattern = attributes.value(QLatin1String("patternType")).toString(); + fill->pattern = patternValues.contains(pattern) ? patternValues[pattern] : Format::PatternNone; + } else if (reader.name() == QLatin1String("fgColor")) { + QXmlStreamAttributes attributes = reader.attributes(); + if (attributes.hasAttribute(QLatin1String("rgb"))) { + QColor c = fromARGBString(attributes.value(QLatin1String("rgb")).toString()); + if (fill->pattern == Format::PatternSolid) + fill->bgColor = c; + else + fill->fgColor = c; + } + } else if (reader.name() == QLatin1String("bgColor")) { + QXmlStreamAttributes attributes = reader.attributes(); + if (attributes.hasAttribute(QLatin1String("rgb"))) { + QColor c = fromARGBString(attributes.value(QLatin1String("rgb")).toString()); + if (fill->pattern == Format::PatternSolid) + fill->fgColor = c; + else + fill->bgColor = c; + } + } + } + + if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fill")) + break; + } + + m_fillsList.append(fill); + m_fillsHash.insert(fill->key(), fill); + fill->setIndex(m_fillsList.size()-1);//first call key(), then setIndex() + + return true; } bool Styles::readBorders(XmlStreamReader &reader) @@ -663,7 +734,20 @@ bool Styles::readCellXfs(XmlStreamReader &reader) if (xfAttrs.hasAttribute(QLatin1String("applyFont"))) { int fontIndex = xfAttrs.value(QLatin1String("fontId")).toInt(); - format->d_func()->fontData = *m_fontsList[fontIndex]; + if (fontIndex >= m_fontsList.size()) { + qDebug("Error read styles.xml, cellXfs fontId"); + } else { + format->d_func()->fontData = *m_fontsList[fontIndex]; + } + } + + if (xfAttrs.hasAttribute(QLatin1String("applyFill"))) { + int id = xfAttrs.value(QLatin1String("fillId")).toInt(); + if (id >= m_fillsList.size()) { + qDebug("Error read styles.xml, cellXfs fillId"); + } else { + format->d_func()->fillData = *m_fillsList[id]; + } } addFormat(format); diff --git a/src/xlsx/xlsxstyles_p.h b/src/xlsx/xlsxstyles_p.h index 78adba6..f969dee 100755 --- a/src/xlsx/xlsxstyles_p.h +++ b/src/xlsx/xlsxstyles_p.h @@ -32,6 +32,7 @@ #include class QIODevice; +class StylesTest; namespace QXlsx { @@ -59,6 +60,7 @@ public: private: friend class Format; + friend class StylesTest; void writeNumFmts(XmlStreamWriter &writer); void writeFonts(XmlStreamWriter &writer); @@ -72,6 +74,7 @@ private: bool readNumFmts(XmlStreamReader &reader); bool readFonts(XmlStreamReader &reader); bool readFills(XmlStreamReader &reader); + bool readFill(XmlStreamReader &reader); bool readBorders(XmlStreamReader &reader); bool readCellXfs(XmlStreamReader &reader); diff --git a/src/xlsx/xlsxutility.cpp b/src/xlsx/xlsxutility.cpp index 8b7cb0f..5e30289 100755 --- a/src/xlsx/xlsxutility.cpp +++ b/src/xlsx/xlsxutility.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace QXlsx { @@ -51,6 +52,16 @@ QStringList splitPath(const QString &path) return QStringList()< namespace QXlsx { -class XmlStreamReader : public QXmlStreamReader +class XLSX_AUTOTEST_EXPORT XmlStreamReader : public QXmlStreamReader { public: - XmlStreamReader(QIODevice *device); + explicit XmlStreamReader(QIODevice *device); + explicit XmlStreamReader(const QByteArray &data); }; } // namespace QXlsx diff --git a/tests/auto/styles/tst_stylestest.cpp b/tests/auto/styles/tst_stylestest.cpp index cd003bc..4d92d2e 100644 --- a/tests/auto/styles/tst_stylestest.cpp +++ b/tests/auto/styles/tst_stylestest.cpp @@ -1,5 +1,7 @@ #include "private/xlsxstyles_p.h" +#include "private/xlsxxmlreader_p.h" #include "xlsxformat.h" +#include "private/xlsxformat_p.h" #include #include @@ -15,6 +17,10 @@ private Q_SLOTS: void testAddFormat(); void testAddFormat2(); void testSolidFillBackgroundColor(); + + void testReadFonts(); + void testReadFills(); + void testReaderBorders(); }; StylesTest::StylesTest() @@ -73,6 +79,45 @@ void StylesTest::testSolidFillBackgroundColor() QVERIFY(xmlData.contains("")); } +void StylesTest::testReadFonts() +{ + QByteArray xmlData = "" + "" + "" + "" + "" + ""; + QXlsx::Styles styles(true); + QXlsx::XmlStreamReader reader(xmlData); + reader.readNextStartElement();//So current node is fonts + styles.readFonts(reader); + + QCOMPARE(styles.m_fontsList.size(), 3); +} + +void StylesTest::testReadFills() +{ + QByteArray xmlData = "" + "" + "" + "" + "" + ""; + QXlsx::Styles styles(true); + QXlsx::XmlStreamReader reader(xmlData); + reader.readNextStartElement();//So current node is fonts + styles.readFills(reader); + + QCOMPARE(styles.m_fillsList.size(), 4); + QCOMPARE(styles.m_fillsList[3]->pattern, QXlsx::Format::PatternSolid); + QCOMPARE(styles.m_fillsList[3]->bgColor, QColor(Qt::gray));//for solid pattern, bg vs. fg color! +} + +void StylesTest::testReaderBorders() +{ + +} + QTEST_APPLESS_MAIN(StylesTest) #include "tst_stylestest.moc"