diff --git a/examples/xlsx/readwrite/main.cpp b/examples/xlsx/readwrite/main.cpp index f30735b..8590e61 100644 --- a/examples/xlsx/readwrite/main.cpp +++ b/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] diff --git a/src/xlsx/xlsxpackage.cpp b/src/xlsx/xlsxpackage.cpp index efe53e7..925a91c 100644 --- a/src/xlsx/xlsxpackage.cpp +++ b/src/xlsx/xlsxpackage.cpp @@ -147,7 +147,11 @@ bool Package::parsePackage(QIODevice *packageDevice) QList 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 (new Styles(true)); + styles->loadFromXmlData(zipReader.fileData(path)); + m_document->workbook()->d_ptr->styles = styles; } //load sharedStrings diff --git a/src/xlsx/xlsxstyles.cpp b/src/xlsx/xlsxstyles.cpp index b89b516..eb20cc2 100755 --- a/src/xlsx/xlsxstyles.cpp +++ b/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 #include @@ -34,15 +35,17 @@ namespace QXlsx { -Styles::Styles() +Styles::Styles(bool createEmpty) { - //Add default Format - addFormat(createFormat()); - //Add another fill format - QSharedPointer fill = QSharedPointer(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 fill = QSharedPointer(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 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; iformatString); } writer.writeEndElement();//numFmts } @@ -518,13 +531,182 @@ void Styles::writeDxfs(XmlStreamWriter &writer) writer.writeEndElement(); //dxfs } -QSharedPointer 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 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 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(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; isetNumberFormatIndex(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: "< Styles::loadFromXmlData(const QByteArray &data) +bool Styles::loadFromXmlData(const QByteArray &data) { QBuffer buffer; buffer.setData(data); diff --git a/src/xlsx/xlsxstyles_p.h b/src/xlsx/xlsxstyles_p.h index 91faa67..78adba6 100755 --- a/src/xlsx/xlsxstyles_p.h +++ b/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 loadFromXmlFile(QIODevice *device); - static QSharedPointer 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 m_builtinNumFmtsHash; - QStringList m_customNumFmts; - QHash m_customNumFmtsHash; + QList > m_customNumFmts; + QHash > m_customNumFmtsHash; QList > m_fontsList; //Keep a copy of unique fonts QList > m_fillsList; //Keep a copy of unique fills QList > m_bordersList; //Keep a copy of unique borders diff --git a/src/xlsx/xlsxworksheet.cpp b/src/xlsx/xlsxworksheet.cpp index 93ef038..94529b0 100755 --- a/src/xlsx/xlsxworksheet.cpp +++ b/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(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(data); } }