Browse Source

Can read .xlsx files with fill styles now

master
Debao Zhang 11 years ago
parent
commit
9abb26127c
  1. 1
      examples/xlsx/readwrite/main.cpp
  2. 100
      src/xlsx/xlsxstyles.cpp
  3. 3
      src/xlsx/xlsxstyles_p.h
  4. 11
      src/xlsx/xlsxutility.cpp
  5. 2
      src/xlsx/xlsxutility_p.h
  6. 5
      src/xlsx/xlsxxmlreader.cpp
  7. 7
      src/xlsx/xlsxxmlreader_p.h
  8. 45
      tests/auto/styles/tst_stylestest.cpp

1
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");

100
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 <QFile>
#include <QMap>
#include <QDataStream>
@ -560,7 +561,7 @@ bool Styles::readFonts(XmlStreamReader &reader)
if (reader.name() != QLatin1String("font"))
return false;
QSharedPointer<FontData> 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<count; ++i) {
reader.readNextStartElement();
if (reader.name() != QLatin1String("fill") || reader.tokenType() != QXmlStreamReader::StartElement)
return false;
readFill(reader);
}
return true;
}
bool Styles::readFill(XmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("fill"));
static QMap<QString, Format::FillPattern> 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<FillData> 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);

3
src/xlsx/xlsxstyles_p.h

@ -32,6 +32,7 @@
#include <QStringList>
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);

11
src/xlsx/xlsxutility.cpp

@ -29,6 +29,7 @@
#include <QRegularExpression>
#include <QMap>
#include <QStringList>
#include <QColor>
namespace QXlsx {
@ -51,6 +52,16 @@ QStringList splitPath(const QString &path)
return QStringList()<<path.left(idx)<<path.mid(idx+1);
}
QColor fromARGBString(const QString &c)
{
Q_ASSERT(c.length() == 8);
QColor color;
color.setRed(c.mid(2, 2).toInt(0, 16));
color.setGreen(c.mid(4, 2).toInt(0, 16));
color.setBlue(c.mid(6, 2).toInt(0, 16));
return color;
}
QPoint xl_cell_to_rowcol(const QString &cell_str)
{
if (cell_str.isEmpty())

2
src/xlsx/xlsxutility_p.h

@ -29,11 +29,13 @@
class QPoint;
class QString;
class QStringList;
class QColor;
namespace QXlsx {
XLSX_AUTOTEST_EXPORT int intPow(int x, int p);
XLSX_AUTOTEST_EXPORT QStringList splitPath(const QString &path);
XLSX_AUTOTEST_EXPORT QColor fromARGBString(const QString &c);
XLSX_AUTOTEST_EXPORT QPoint xl_cell_to_rowcol(const QString &cell_str);
XLSX_AUTOTEST_EXPORT QString xl_col_to_name(int col_num);

5
src/xlsx/xlsxxmlreader.cpp

@ -32,4 +32,9 @@ XmlStreamReader::XmlStreamReader(QIODevice *device) :
{
}
XmlStreamReader::XmlStreamReader(const QByteArray &data) :
QXmlStreamReader(data)
{
}
} // namespace QXlsx

7
src/xlsx/xlsxxmlreader_p.h

@ -25,15 +25,16 @@
#ifndef QXLSX_XLSXXMLREADER_H
#define QXLSX_XLSXXMLREADER_H
#include "xlsxglobal.h"
#include <QXmlStreamReader>
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

45
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 <QString>
#include <QtTest>
@ -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("<patternFill patternType=\"solid\"><fgColor rgb=\"FFff0000\"/>"));
}
void StylesTest::testReadFonts()
{
QByteArray xmlData = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
"<fonts count=\"3\">"
"<font><sz val=\"11\"/><name val=\"Calibri\"/><family val=\"2\"/><scheme val=\"minor\"/></font>"
"<font><sz val=\"15\"/><color rgb=\"FFff0000\"/><name val=\"Calibri\"/><family val=\"2\"/><scheme val=\"minor\"/></font>"
"<font><b/><u val=\"double\"/><sz val=\"11\"/><name val=\"Calibri\"/><family val=\"2\"/><scheme val=\"minor\"/></font>"
"</fonts>";
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 = "<fills count=\"4\">"
"<fill><patternFill patternType=\"none\"/></fill>"
"<fill><patternFill patternType=\"gray125\"/></fill>"
"<fill><patternFill patternType=\"lightUp\"/></fill>"
"<fill><patternFill patternType=\"solid\"><fgColor rgb=\"FFa0a0a4\"/></patternFill></fill>"
"</fills>";
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"

Loading…
Cancel
Save