diff --git a/README.md b/README.md index 8e0f157..4a40350 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ The library, the header files, and the feature file will be installed to your sy ## References * https://github.com/jmcnamara/XlsxWriter +* http://openpyxl.readthedocs.org * http://officeopenxml.com/anatomyofOOXML-xlsx.php * http://www.libxl.com * http://closedxml.codeplex.com/ diff --git a/examples/xlsx/readwrite/doc/src/readwrite.qdoc b/examples/xlsx/readwrite/doc/src/readwrite.qdoc new file mode 100644 index 0000000..4e8fffa --- /dev/null +++ b/examples/xlsx/readwrite/doc/src/readwrite.qdoc @@ -0,0 +1,10 @@ +/*! + \title Xlsx Readwrite Example + \example readwrite + \brief Open an existing xlsx file, modify and save it. + + \ingroup qtxlsx + + This example demonstrates how to modify an existing + .xlsx file with Qt Xlsx Library. +*/ diff --git a/examples/xlsx/readwrite/main.cpp b/examples/xlsx/readwrite/main.cpp new file mode 100644 index 0000000..d0eddcd --- /dev/null +++ b/examples/xlsx/readwrite/main.cpp @@ -0,0 +1,18 @@ +#include "xlsxdocument.h" + +int main() +{ + //Generate a simple xlsx file at first. + QXlsx::Document xlsx; + xlsx.write("A1", "Hello Qt!"); + xlsx.write("A2", 500); + xlsx.saveAs("first.xlsx"); + + //Read, edit, save + QXlsx::Document xlsx2("first.xlsx"); + xlsx2.addWorksheet("Second"); + xlsx2.write("A1", "Hello Qt again!"); + xlsx2.saveAs("second.xlsx"); + + return 0; +} diff --git a/examples/xlsx/readwrite/readwrite.pro b/examples/xlsx/readwrite/readwrite.pro new file mode 100644 index 0000000..29b1278 --- /dev/null +++ b/examples/xlsx/readwrite/readwrite.pro @@ -0,0 +1,12 @@ +TARGET = mergecells + +#include(../../../src/xlsx/qtxlsx.pri) +QT += xlsx + +TARGET = readwrite +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + +SOURCES += main.cpp diff --git a/examples/xlsx/xlsx.pro b/examples/xlsx/xlsx.pro index db7d416..0ac7146 100644 --- a/examples/xlsx/xlsx.pro +++ b/examples/xlsx/xlsx.pro @@ -4,5 +4,6 @@ SUBDIRS = hello style \ image \ mergecells \ rowcolumn \ - numberformat + numberformat \ + readwrite diff --git a/src/xlsx/doc/src/qtxlsx-index.qdoc b/src/xlsx/doc/src/qtxlsx-index.qdoc index 62d048f..c82b0a3 100644 --- a/src/xlsx/doc/src/qtxlsx-index.qdoc +++ b/src/xlsx/doc/src/qtxlsx-index.qdoc @@ -110,5 +110,6 @@ \li \l{Xlsx Hello Example} \li \l{Xlsx Style Example} \li \l{Xlsx DocProperties Example} + \li \l{Xlsx Readwrite Example} \endlist */ diff --git a/src/xlsx/xlsxdocument.h b/src/xlsx/xlsxdocument.h index 07e90fb..0309d53 100644 --- a/src/xlsx/xlsxdocument.h +++ b/src/xlsx/xlsxdocument.h @@ -28,6 +28,7 @@ #include "xlsxglobal.h" #include +#include class QIODevice; class QImage; diff --git a/src/xlsx/xlsxpackage.cpp b/src/xlsx/xlsxpackage.cpp index f697059..efe53e7 100644 --- a/src/xlsx/xlsxpackage.cpp +++ b/src/xlsx/xlsxpackage.cpp @@ -25,6 +25,8 @@ #include "xlsxpackage_p.h" #include "xlsxworkbook.h" #include "xlsxworksheet.h" +#include "xlsxworkbook_p.h" +#include "xlsxutility_p.h" #include "xlsxcontenttypes_p.h" #include "xlsxsharedstrings_p.h" #include "xlsxdocpropscore_p.h" @@ -38,6 +40,8 @@ #include "xlsxdocument.h" #include #include +#include +#include namespace QXlsx { @@ -125,17 +129,59 @@ bool Package::parsePackage(QIODevice *packageDevice) m_document->setDocumentProperty(name, props.property(name)); } - //load workbook now + //load workbook now, Get the workbook file path from the root rels file + //In normal case, this should be "xl/workbook.xml" QList rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument")); - if (!rels_xl.isEmpty()) { - //Get the app property file name if it exists. - //In normal case, this should be "xl/workbook.xml" - QString xlworkbook_Name = rels_xl[0].target; + if (rels_xl.isEmpty()) + return false; + QString xlworkbook_Path = rels_xl[0].target; + QStringList xlworkbook_PathList = splitPath(xlworkbook_Path); + QString xlworkbook_Dir = xlworkbook_PathList[0]; + QString xlworkbook_Name = xlworkbook_PathList[1]; + QSharedPointer book = Workbook::loadFromXmlData(zipReader.fileData(xlworkbook_Path)); + QList > sheetNameIdPairList = book->d_func()->sheetNameIdPairList; + Relationships xlworkbook_Rels = Relationships::loadFromXmlData( + zipReader.fileData(xlworkbook_Dir+QStringLiteral("/_rels/")+xlworkbook_Name+QStringLiteral(".rels"))); + + //load styles + QList rels_styles = xlworkbook_Rels.documentRelationships(QStringLiteral("/styles")); + if (!rels_styles.isEmpty()) { + //In normal case this should be styles.xml which in xl + //:Todo + } + + //load sharedStrings + QList rels_sharedStrings = xlworkbook_Rels.documentRelationships(QStringLiteral("/sharedStrings")); + if (!rels_sharedStrings.isEmpty()) { + //In normal case this should be sharedStrings.xml which in xl + QString name = rels_sharedStrings[0].target; + QString path = xlworkbook_Dir + QLatin1String("/") + name; + QSharedPointer sst= SharedStrings::loadFromXmlData(zipReader.fileData(path)); + m_document->workbook()->d_ptr->sharedStrings = sst; + } - //ToDo: Read the workbook here! + //load theme + QList rels_theme = xlworkbook_Rels.documentRelationships(QStringLiteral("/theme")); + if (!rels_theme.isEmpty()) { + //In normal case this should be theme/theme1.xml which in xl + //:Todo } - return false; + //load worksheets + QList rels_worksheets = xlworkbook_Rels.documentRelationships(QStringLiteral("/worksheet")); + if (rels_worksheets.isEmpty()) + return false; + + for (int i=0; i pair = sheetNameIdPairList[i]; + QString worksheet_rId = pair.second; + QString name = xlworkbook_Rels.getRelationshipById(worksheet_rId).target; + QString worksheet_path = xlworkbook_Dir + QLatin1String("/") + name; + Worksheet *sheet = m_document->workbook()->addWorksheet(pair.first); + sheet->loadFromXmlData(zipReader.fileData(worksheet_path)); + } + + return true; } bool Package::createPackage(QIODevice *package) diff --git a/src/xlsx/xlsxsharedstrings.cpp b/src/xlsx/xlsxsharedstrings.cpp index d463278..25f26fb 100755 --- a/src/xlsx/xlsxsharedstrings.cpp +++ b/src/xlsx/xlsxsharedstrings.cpp @@ -59,6 +59,11 @@ int SharedStrings::addSharedString(const QString &string) return index; } +void SharedStrings::incRefByStringIndex(int idx) +{ + addSharedString(m_stringList[idx]); +} + void SharedStrings::removeSharedString(const QString &string) { if (!m_stringTable.contains(string)) diff --git a/src/xlsx/xlsxsharedstrings_p.h b/src/xlsx/xlsxsharedstrings_p.h index 7d4b5cf..19bd255 100755 --- a/src/xlsx/xlsxsharedstrings_p.h +++ b/src/xlsx/xlsxsharedstrings_p.h @@ -54,6 +54,7 @@ public: int addSharedString(const QString &string); void removeSharedString(const QString &string); + void incRefByStringIndex(int idx); int getSharedStringIndex(const QString &string) const; QString getSharedString(int index) const; diff --git a/src/xlsx/xlsxutility.cpp b/src/xlsx/xlsxutility.cpp index 4487304..8b7cb0f 100755 --- a/src/xlsx/xlsxutility.cpp +++ b/src/xlsx/xlsxutility.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace QXlsx { @@ -41,6 +42,15 @@ int intPow(int x, int p) else return x * tmp * tmp; } +QStringList splitPath(const QString &path) +{ + int idx = path.lastIndexOf(QLatin1Char('/')); + if (idx == -1) + return QStringList()< Workbook::loadFromXmlData(const QByteArray &data) return loadFromXmlFile(&buffer); } -void Workbook::addWorksheet(const QString &name, QSharedPointer sheet) -{ - Q_D(Workbook); - - sheet->setSheetName(name); - d->worksheets.append(sheet); -} - QT_END_NAMESPACE_XLSX diff --git a/src/xlsx/xlsxworkbook.h b/src/xlsx/xlsxworkbook.h index ecb9932..607198d 100755 --- a/src/xlsx/xlsxworkbook.h +++ b/src/xlsx/xlsxworkbook.h @@ -78,7 +78,6 @@ private: QByteArray saveToXmlData(); static QSharedPointer loadFromXmlFile(QIODevice *device); static QSharedPointer loadFromXmlData(const QByteArray &data); - void addWorksheet(const QString &name, QSharedPointer sheet); SharedStrings *sharedStrings(); Styles *styles(); diff --git a/src/xlsx/xlsxworksheet.cpp b/src/xlsx/xlsxworksheet.cpp index 7a40b1a..93ef038 100755 --- a/src/xlsx/xlsxworksheet.cpp +++ b/src/xlsx/xlsxworksheet.cpp @@ -1074,9 +1074,9 @@ QByteArray Worksheet::saveToXmlData() return data; } -QSharedPointer Worksheet::loadFromXmlFile(QIODevice *device) +bool Worksheet::loadFromXmlFile(QIODevice *device) { - Worksheet *sheet = new Worksheet(QStringLiteral("Sheet9999")); + Q_D(Worksheet); XmlStreamReader reader(device); while(!reader.atEnd()) { @@ -1088,16 +1088,16 @@ QSharedPointer Worksheet::loadFromXmlFile(QIODevice *device) if (range.size() == 2) { QPoint start = xl_cell_to_rowcol(range[0]); QPoint end = xl_cell_to_rowcol(range[1]); - sheet->d_func()->dim_rowmin = start.x(); - sheet->d_func()->dim_colmin = start.y(); - sheet->d_func()->dim_rowmax = end.x(); - sheet->d_func()->dim_colmax = end.y(); + d->dim_rowmin = start.x(); + d->dim_colmin = start.y(); + d->dim_rowmax = end.x(); + d->dim_colmax = end.y(); } else { QPoint p = xl_cell_to_rowcol(range[0]); - sheet->d_func()->dim_rowmin = p.x(); - sheet->d_func()->dim_colmin = p.y(); - sheet->d_func()->dim_rowmax = p.x(); - sheet->d_func()->dim_colmax = p.y(); + d->dim_rowmin = p.x(); + d->dim_colmin = p.y(); + d->dim_rowmax = p.x(); + d->dim_colmax = p.y(); } } else if (reader.name() == QLatin1String("c")) { QXmlStreamAttributes attributes = reader.attributes(); @@ -1111,8 +1111,9 @@ QSharedPointer Worksheet::loadFromXmlFile(QIODevice *device) reader.readNextStartElement(); if (reader.name() == QLatin1String("v")) { QString value = reader.readElementText(); + d->workbook->sharedStrings()->incRefByStringIndex(value.toInt()); XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::String); - sheet->d_func()->cellTable[pos.x()][pos.y()] = QSharedPointer(data); + d->cellTable[pos.x()][pos.y()] = QSharedPointer(data); } } } else { @@ -1121,17 +1122,17 @@ QSharedPointer Worksheet::loadFromXmlFile(QIODevice *device) if (reader.name() == QLatin1String("v")) { QString value = reader.readElementText(); XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::Number); - sheet->d_func()->cellTable[pos.x()][pos.y()] = QSharedPointer(data); + d->cellTable[pos.x()][pos.y()] = QSharedPointer(data); } } } } } - return QSharedPointer (sheet); + return true; } -QSharedPointer Worksheet::loadFromXmlData(const QByteArray &data) +bool Worksheet::loadFromXmlData(const QByteArray &data) { QBuffer buffer; buffer.setData(data); diff --git a/src/xlsx/xlsxworksheet.h b/src/xlsx/xlsxworksheet.h index 66c367c..6ea1a86 100755 --- a/src/xlsx/xlsxworksheet.h +++ b/src/xlsx/xlsxworksheet.h @@ -74,8 +74,8 @@ public: void saveToXmlFile(QIODevice *device); QByteArray saveToXmlData(); - static QSharedPointer loadFromXmlFile(QIODevice *device); - static QSharedPointer loadFromXmlData(const QByteArray &data); + bool loadFromXmlFile(QIODevice *device); + bool loadFromXmlData(const QByteArray &data); ~Worksheet(); private: