Browse Source

Can read .xlsx files with font styles now

master
Debao Zhang 12 years ago
parent
commit
b56d86aab4
  1. 6
      examples/xlsx/readwrite/main.cpp
  2. 6
      src/xlsx/xlsxpackage.cpp
  3. 212
      src/xlsx/xlsxstyles.cpp
  4. 19
      src/xlsx/xlsxstyles_p.h
  5. 10
      src/xlsx/xlsxworksheet.cpp

6
examples/xlsx/readwrite/main.cpp

@ -1,4 +1,5 @@
#include "xlsxdocument.h"
#include "xlsxformat.h"
int main()
{
@ -8,7 +9,10 @@ int main()
xlsx.setDocumentProperty("title", "This is an example spreadsheet");
xlsx.setDocumentProperty("creator", "Qt Xlsx Library");
xlsx.setSheetName("First Sheet");
xlsx.write("A1", "Hello Qt!");
QXlsx::Format *format = xlsx.createFormat();
format->setFontColor(QColor(Qt::blue));
format->setFontSize(15);
xlsx.write("A1", "Hello Qt!", format);
xlsx.write("A2", 500);
xlsx.saveAs("first.xlsx");
//![0]

6
src/xlsx/xlsxpackage.cpp

@ -147,7 +147,11 @@ bool Package::parsePackage(QIODevice *packageDevice)
QList<XlsxRelationship> rels_styles = xlworkbook_Rels.documentRelationships(QStringLiteral("/styles"));
if (!rels_styles.isEmpty()) {
//In normal case this should be styles.xml which in xl
//:Todo
QString name = rels_styles[0].target;
QString path = xlworkbook_Dir + QLatin1String("/") + name;
QSharedPointer<Styles> styles (new Styles(true));
styles->loadFromXmlData(zipReader.fileData(path));
m_document->workbook()->d_ptr->styles = styles;
}
//load sharedStrings

212
src/xlsx/xlsxstyles.cpp

@ -24,6 +24,7 @@
****************************************************************************/
#include "xlsxstyles_p.h"
#include "xlsxxmlwriter_p.h"
#include "xlsxxmlreader_p.h"
#include "xlsxformat_p.h"
#include <QFile>
#include <QMap>
@ -34,15 +35,17 @@
namespace QXlsx {
Styles::Styles()
Styles::Styles(bool createEmpty)
{
//Add default Format
addFormat(createFormat());
//Add another fill format
QSharedPointer<FillData> fill = QSharedPointer<FillData>(new FillData);
fill->pattern = Format::PatternGray125;
m_fillsList.append(fill);
m_fillsHash[fill->key()] = fill;
if (!createEmpty) {
//Add default Format
addFormat(createFormat());
//Add another fill format
QSharedPointer<FillData> fill = QSharedPointer<FillData>(new FillData);
fill->pattern = Format::PatternGray125;
m_fillsList.append(fill);
m_fillsHash[fill->key()] = fill;
}
}
Styles::~Styles()
@ -57,6 +60,14 @@ Format *Styles::createFormat()
return format;
}
Format *Styles::xfFormat(int idx) const
{
if (idx <0 || idx > m_xf_formatsList.size())
return 0;
return m_xf_formatsList[idx];
}
/*
Assign index to Font/Fill/Border and Format
*/
@ -111,12 +122,14 @@ void Styles::addFormat(Format *format)
if (m_builtinNumFmtsHash.contains(str)) {
format->setNumFmt(m_builtinNumFmtsHash[str], str);
} else if (m_customNumFmtsHash.contains(str)) {
format->setNumFmt(m_customNumFmtsHash[str], str);
format->setNumFmt(m_customNumFmtsHash[str]->formatIndex, str);
} else {
int idx = 164 + m_customNumFmts.size();
m_customNumFmts.append(str);
m_customNumFmtsHash.insert(str, idx);
format->setNumFmt(idx, str);
QSharedPointer<NumberData> fmt(new NumberData(format->d_func()->numberData));
m_customNumFmts.append(fmt);
m_customNumFmtsHash.insert(str, fmt);
}
}
@ -243,7 +256,7 @@ void Styles::writeNumFmts(XmlStreamWriter &writer)
for (int i=0; i<m_customNumFmts.size(); ++i) {
writer.writeEmptyElement(QStringLiteral("numFmt"));
writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(164 + i));
writer.writeAttribute(QStringLiteral("formatCode"), m_customNumFmts[i]);
writer.writeAttribute(QStringLiteral("formatCode"), m_customNumFmts[i]->formatString);
}
writer.writeEndElement();//numFmts
}
@ -518,13 +531,182 @@ void Styles::writeDxfs(XmlStreamWriter &writer)
writer.writeEndElement(); //dxfs
}
QSharedPointer<Styles> Styles::loadFromXmlFile(QIODevice *device)
bool Styles::readNumFmts(XmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("numFmts"));
QXmlStreamAttributes attributes = reader.attributes();
int count = attributes.value(QLatin1String("count")).toInt();
for (int i=0; i<count; ++i) {
reader.readNextStartElement();
if (reader.name() != QLatin1String("numFmt"))
return false;
QXmlStreamAttributes attributes = reader.attributes();
QSharedPointer<NumberData> fmt (new NumberData);
fmt->formatIndex = attributes.value(QLatin1String("numFmtId")).toInt();
fmt->formatString = attributes.value(QLatin1String("formatCode")).toString();
m_customNumFmts.append(fmt);
m_customNumFmtsHash.insert(fmt->formatString, fmt);
}
return true;
}
bool Styles::readFonts(XmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("fonts"));
QXmlStreamAttributes attributes = reader.attributes();
int count = attributes.value(QLatin1String("count")).toInt();
for (int i=0; i<count; ++i) {
reader.readNextStartElement();
if (reader.name() != QLatin1String("font"))
return false;
QSharedPointer<FontData> font(new FontData);
while(reader.readNextStartElement()) {
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("b")) {
font->bold = true;
} else if (reader.name() == QLatin1String("i")) {
font->italic = true;
} else if (reader.name() == QLatin1String("strike")) {
font->strikeOut = true;
} else if (reader.name() == QLatin1String("outline")) {
font->outline = true;
} else if (reader.name() == QLatin1String("shadow")) {
font->shadow = true;
} else if (reader.name() == QLatin1String("u")) {
QXmlStreamAttributes attributes = reader.attributes();
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("double"))
font->underline = Format::FontUnderlineDouble;
else if (value == QLatin1String("doubleAccounting"))
font->underline = Format::FontUnderlineDoubleAccounting;
else if (value == QLatin1String("singleAccounting"))
font->underline = Format::FontUnderlineSingleAccounting;
else
font->underline = Format::FontUnderlineSingle;
} else if (reader.name() == QLatin1String("vertAligh")) {
QXmlStreamAttributes attributes = reader.attributes();
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("superscript"))
font->scirpt = Format::FontScriptSuper;
else
font->scirpt = Format::FontScriptSub;
} else if (reader.name() == QLatin1String("sz")) {
font->size = reader.attributes().value(QLatin1String("val")).toInt();
} else if (reader.name() == QLatin1String("color")) {
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));
}
} else if (attributes.hasAttribute(QLatin1String("indexed"))) {
} else if (attributes.hasAttribute(QLatin1String("theme"))) {
}
} else if (reader.name() == QLatin1String("name")) {
font->name = reader.attributes().value(QLatin1String("val")).toString();
} else if (reader.name() == QLatin1String("family")) {
font->family = reader.attributes().value(QLatin1String("val")).toInt();
} else if (reader.name() == QLatin1String("scheme")) {
font->scheme = reader.attributes().value(QLatin1String("val")).toString();
}
}
return QSharedPointer<Styles>(new Styles);
if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("font"))
break;
}
m_fontsList.append(font);
m_fontsHash.insert(font->key(), font);
font->setIndex(m_fontsList.size()-1);//first call key(), then setIndex()
}
return true;
}
bool Styles::readFills(XmlStreamReader &reader)
{
return false;
}
bool Styles::readBorders(XmlStreamReader &reader)
{
return false;
}
bool Styles::readCellXfs(XmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("cellXfs"));
QXmlStreamAttributes attributes = reader.attributes();
int count = attributes.value(QLatin1String("count")).toInt();
for (int i=0; i<count; ++i) {
reader.readNextStartElement();
if (reader.name() != QLatin1String("xf"))
return false;
Format *format = createFormat();
QXmlStreamAttributes xfAttrs = reader.attributes();
// qDebug()<<reader.name()<<reader.tokenString()<<" .........";
// for (int i=0; i<xfAttrs.size(); ++i)
// qDebug()<<"... "<<i<<" "<<xfAttrs[i].name()<<xfAttrs[i].value();
if (xfAttrs.hasAttribute(QLatin1String("applyNumberFormat"))) {
int numFmtIndex = xfAttrs.value(QLatin1String("numFmtId")).toInt();
if (numFmtIndex < 164) {
format->setNumberFormatIndex(numFmtIndex);
} else {
format->d_func()->numberData = *m_customNumFmts[numFmtIndex-164];
}
}
if (xfAttrs.hasAttribute(QLatin1String("applyFont"))) {
int fontIndex = xfAttrs.value(QLatin1String("fontId")).toInt();
format->d_func()->fontData = *m_fontsList[fontIndex];
}
addFormat(format);
//Find the endElement of xf
while (!(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("xf")))
reader.readNextStartElement();
}
return true;
}
bool Styles::loadFromXmlFile(QIODevice *device)
{
XmlStreamReader reader(device);
while(!reader.atEnd()) {
QXmlStreamReader::TokenType token = reader.readNext();
if (token = QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("numFmts")) {
readNumFmts(reader);
} else if (reader.name() == QLatin1String("fonts")) {
readFonts(reader);
} else if (reader.name() == QLatin1String("fills")) {
readFills(reader);
} else if (reader.name() == QLatin1String("borders")) {
readBorders(reader);
} else if (reader.name() == QLatin1String("cellStyleXfs")) {
} else if (reader.name() == QLatin1String("cellXfs")) {
readCellXfs(reader);
} else if (reader.name() == QLatin1String("cellStyles")) {
}
}
if (reader.hasError()) {
qDebug()<<"Error when read style file: "<<reader.errorString();
}
}
return true;
}
QSharedPointer<Styles> Styles::loadFromXmlData(const QByteArray &data)
bool Styles::loadFromXmlData(const QByteArray &data)
{
QBuffer buffer;
buffer.setData(data);

19
src/xlsx/xlsxstyles_p.h

@ -36,23 +36,26 @@ class QIODevice;
namespace QXlsx {
class Format;
struct NumberData;
struct FontData;
struct FillData;
struct BorderData;
class XmlStreamWriter;
class XmlStreamReader;
class XLSX_AUTOTEST_EXPORT Styles
{
public:
Styles();
Styles(bool createEmpty=false);
~Styles();
Format *createFormat();
void addFormat(Format *format);
Format *xfFormat(int idx) const;
QByteArray saveToXmlData();
void saveToXmlFile(QIODevice *device);
static QSharedPointer<Styles> loadFromXmlFile(QIODevice *device);
static QSharedPointer<Styles> loadFromXmlData(const QByteArray &data);
bool loadFromXmlFile(QIODevice *device);
bool loadFromXmlData(const QByteArray &data);
private:
friend class Format;
@ -66,9 +69,15 @@ private:
void writeCellXfs(XmlStreamWriter &writer);
void writeDxfs(XmlStreamWriter &writer);
bool readNumFmts(XmlStreamReader &reader);
bool readFonts(XmlStreamReader &reader);
bool readFills(XmlStreamReader &reader);
bool readBorders(XmlStreamReader &reader);
bool readCellXfs(XmlStreamReader &reader);
QHash<QString, int> m_builtinNumFmtsHash;
QStringList m_customNumFmts;
QHash<QString, int> m_customNumFmtsHash;
QList<QSharedPointer<NumberData> > m_customNumFmts;
QHash<QString, QSharedPointer<NumberData> > m_customNumFmtsHash;
QList<QSharedPointer<FontData> > m_fontsList; //Keep a copy of unique fonts
QList<QSharedPointer<FillData> > m_fillsList; //Keep a copy of unique fills
QList<QSharedPointer<BorderData> > m_bordersList; //Keep a copy of unique borders

10
src/xlsx/xlsxworksheet.cpp

@ -1104,6 +1104,12 @@ bool Worksheet::loadFromXmlFile(QIODevice *device)
QString r = attributes.value(QLatin1String("r")).toString();
QPoint pos = xl_cell_to_rowcol(r);
Format *format = 0;
if (attributes.hasAttribute(QLatin1String("s"))) {
int idx = attributes.value(QLatin1String("s")).toInt();
format = d->workbook->styles()->xfFormat(idx);
}
if (attributes.hasAttribute(QLatin1String("t"))) {
QString type = attributes.value(QLatin1String("t")).toString();
if (type == QLatin1String("s")) {
@ -1112,7 +1118,7 @@ bool Worksheet::loadFromXmlFile(QIODevice *device)
if (reader.name() == QLatin1String("v")) {
QString value = reader.readElementText();
d->workbook->sharedStrings()->incRefByStringIndex(value.toInt());
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::String);
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::String, format);
d->cellTable[pos.x()][pos.y()] = QSharedPointer<XlsxCellData>(data);
}
}
@ -1121,7 +1127,7 @@ bool Worksheet::loadFromXmlFile(QIODevice *device)
reader.readNextStartElement();
if (reader.name() == QLatin1String("v")) {
QString value = reader.readElementText();
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::Number);
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::Number, format);
d->cellTable[pos.x()][pos.y()] = QSharedPointer<XlsxCellData>(data);
}
}

Loading…
Cancel
Save