From 0d7863f420a6f1e446f1e043a994d368023c4045 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Wed, 30 Oct 2013 13:14:03 +0800 Subject: [PATCH] Add defineName support --- examples/xlsx/definename/definename.pro | 9 ++++ examples/xlsx/definename/main.cpp | 33 ++++++++++++ examples/xlsx/xlsx.pro | 3 +- src/xlsx/xlsxdocument.cpp | 15 ++++++ src/xlsx/xlsxdocument.h | 2 + src/xlsx/xlsxworkbook.cpp | 67 ++++++++++++++++++++++--- src/xlsx/xlsxworkbook.h | 2 +- src/xlsx/xlsxworkbook_p.h | 18 +++++++ 8 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 examples/xlsx/definename/definename.pro create mode 100644 examples/xlsx/definename/main.cpp diff --git a/examples/xlsx/definename/definename.pro b/examples/xlsx/definename/definename.pro new file mode 100644 index 0000000..d2ba173 --- /dev/null +++ b/examples/xlsx/definename/definename.pro @@ -0,0 +1,9 @@ +TARGET = definename + +#include(../../../src/xlsx/qtxlsx.pri) +QT+=xlsx + +CONFIG += console +CONFIG -= app_bundle + +SOURCES += main.cpp diff --git a/examples/xlsx/definename/main.cpp b/examples/xlsx/definename/main.cpp new file mode 100644 index 0000000..75ff2e8 --- /dev/null +++ b/examples/xlsx/definename/main.cpp @@ -0,0 +1,33 @@ +#include +#include "xlsxdocument.h" + +QTXLSX_USE_NAMESPACE + +int main() +{ + //![0] + Document xlsx; + for (int i=0; i<10; ++i) { + xlsx.write(i, 0, i); + xlsx.write(i, 1, i*i); + xlsx.write(i, 2, i*i*i); + } + //![0] + //![1] + xlsx.defineName("MyCol_1", "=Sheet1!$A$1:$A$10"); + xlsx.defineName("MyCol_2", "=Sheet1!$B$1:$B$10", "This is comments"); + xlsx.defineName("MyCol_3", "=Sheet1!$C$1:$C$10", "", "Sheet1"); + xlsx.defineName("Factor", "=0.5"); + //![1] + //![2] + xlsx.write(10, 0, "=SUM(MyCol_1)"); + xlsx.write(10, 1, "=SUM(MyCol_2)"); + xlsx.write(10, 2, "=SUM(MyCol_3)"); + xlsx.write(11, 0, "=SUM(MyCol_1)*Factor"); + xlsx.write(11, 1, "=SUM(MyCol_2)*Factor"); + xlsx.write(11, 2, "=SUM(MyCol_3)*Factor"); + //![2] + + xlsx.save(); + return 0; +} diff --git a/examples/xlsx/xlsx.pro b/examples/xlsx/xlsx.pro index 37ab891..decde8e 100644 --- a/examples/xlsx/xlsx.pro +++ b/examples/xlsx/xlsx.pro @@ -6,5 +6,6 @@ SUBDIRS = hello style \ rowcolumn \ numberformat \ readwrite \ - datavalidation + datavalidation \ + definename diff --git a/src/xlsx/xlsxdocument.cpp b/src/xlsx/xlsxdocument.cpp index 4790d4e..3013ce3 100644 --- a/src/xlsx/xlsxdocument.cpp +++ b/src/xlsx/xlsxdocument.cpp @@ -208,6 +208,21 @@ Cell *Document::cellAt(int row, int col) const return currentWorksheet()->cellAt(row, col); } +/*! + * \brief Create a defined name in the workbook. + * \param name The defined name + * \param formula The cell or range that the defined name refers to. + * \param comment + * \param scope The name of one worksheet, or empty which means golbal scope. + * \return Return false if the name invalid. + */ +bool Document::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope) +{ + Q_D(Document); + + return d->workbook->defineName(name, formula, comment, scope); +} + /*! Return the range that contains cell data. */ diff --git a/src/xlsx/xlsxdocument.h b/src/xlsx/xlsxdocument.h index 29a2a87..137df0b 100644 --- a/src/xlsx/xlsxdocument.h +++ b/src/xlsx/xlsxdocument.h @@ -67,6 +67,8 @@ public: Cell *cellAt(const QString &cell) const; Cell *cellAt(int row, int col) const; + bool defineName(const QString &name, const QString &formula, const QString &comment=QString(), const QString &scope=QString()); + CellRange dimension() const; QString documentProperty(const QString &name) const; diff --git a/src/xlsx/xlsxworkbook.cpp b/src/xlsx/xlsxworkbook.cpp index 8f8e989..714672d 100755 --- a/src/xlsx/xlsxworkbook.cpp +++ b/src/xlsx/xlsxworkbook.cpp @@ -124,10 +124,33 @@ void Workbook::setDefaultDateFormat(const QString &format) d->defaultDateFormat = format; } -void Workbook::defineName(const QString &name, const QString &formula) +/*! + * \brief Create a defined name in the workbook. + * \param name The defined name + * \param formula The cell or range that the defined name refers to. + * \param comment + * \param scope The name of one worksheet, or empty which means golbal scope. + * \return Return false if the name invalid. + */ +bool Workbook::defineName(const QString &name, const QString &formula, const QString &comment, const QString &scope) { - Q_UNUSED(name); - Q_UNUSED(formula); + Q_D(Workbook); + + //Remove the = sign from the formula if it exists. + QString formulaString = formula; + if (formulaString.startsWith(QLatin1Char('='))) + formulaString = formula.mid(1); + + int id=-1; + for (int i=0; iworksheets.size(); ++i) { + if (d->worksheets[i]->sheetName() == scope) { + id = i; + break; + } + } + + d->definedNamesList.append(XlsxDefineNameData(name, formulaString, comment, id)); + return true; } Worksheet *Workbook::addWorksheet(const QString &name) @@ -310,8 +333,27 @@ void Workbook::saveToXmlFile(QIODevice *device) } writer.writeEndElement();//sheets -// writer.writeStartElement(QStringLiteral("definedNames")); -// writer.writeEndElement();//definedNames + if (!d->definedNamesList.isEmpty()) { + writer.writeStartElement(QStringLiteral("definedNames")); + foreach (XlsxDefineNameData data, d->definedNamesList) { + writer.writeStartElement(QStringLiteral("definedName")); + writer.writeAttribute(QStringLiteral("name"), data.name); + if (!data.comment.isEmpty()) + writer.writeAttribute(QStringLiteral("comment"), data.comment); + if (data.sheetId != -1) { + //find the local index of the sheet. + for (int i=0; iworksheets.size(); ++i) { + if (d->worksheets[i]->sheetId() == data.sheetId) { + writer.writeAttribute(QStringLiteral("localSheetId"), QString::number(i)); + break; + } + } + } + writer.writeCharacters(data.formula); + writer.writeEndElement();//definedName + } + writer.writeEndElement();//definedNames + } writer.writeStartElement(QStringLiteral("calcPr")); writer.writeAttribute(QStringLiteral("calcId"), QStringLiteral("124519")); @@ -370,10 +412,23 @@ QSharedPointer Workbook::loadFromXmlFile(QIODevice *device) book->d_func()->firstsheet = attrs.value(QLatin1String("firstSheet")).toInt(); if (attrs.hasAttribute(QLatin1String("activeTab"))) book->d_func()->activesheet = attrs.value(QLatin1String("activeTab")).toInt(); - } } } + } else if (reader.name() == QLatin1String("definedName")) { + QXmlStreamAttributes attrs = reader.attributes(); + XlsxDefineNameData data; + + data.name = attrs.value(QLatin1String("name")).toString(); + if (attrs.hasAttribute(QLatin1String("comment"))) + data.comment = attrs.value(QLatin1String("comment")).toString(); + if (attrs.hasAttribute(QLatin1String("localSheetId"))) { + int localId = attrs.value(QLatin1String("localSheetId")).toInt(); + int sheetId = book->d_func()->sheetItemInfoList[localId].sheetId; + data.sheetId = sheetId; + } + data.formula = reader.readElementText(); + book->d_func()->definedNamesList.append(data); } } } diff --git a/src/xlsx/xlsxworkbook.h b/src/xlsx/xlsxworkbook.h index 198285a..55f7b25 100755 --- a/src/xlsx/xlsxworkbook.h +++ b/src/xlsx/xlsxworkbook.h @@ -58,7 +58,7 @@ public: Format *createFormat(); // void addChart(); - void defineName(const QString &name, const QString &formula); + bool defineName(const QString &name, const QString &formula, const QString &comment=QString(), const QString &scope=QString()); bool isDate1904() const; void setDate1904(bool date1904); bool isStringsToNumbersEnabled() const; diff --git a/src/xlsx/xlsxworkbook_p.h b/src/xlsx/xlsxworkbook_p.h index daced11..bf59dd8 100644 --- a/src/xlsx/xlsxworkbook_p.h +++ b/src/xlsx/xlsxworkbook_p.h @@ -40,6 +40,23 @@ struct XlsxSheetItemInfo QString state; }; +struct XlsxDefineNameData +{ + XlsxDefineNameData() + :sheetId(-1) + {} + XlsxDefineNameData(const QString &name, const QString &formula, const QString &comment, int sheetId=-1) + :name(name), formula(formula), comment(comment), sheetId(sheetId) + { + + } + QString name; + QString formula; + QString comment; + //using internal sheetId, instead of the localSheetId(order in the workbook) + int sheetId; +}; + class WorkbookPrivate { Q_DECLARE_PUBLIC(Workbook) @@ -53,6 +70,7 @@ public: QSharedPointer styles; QList images; QList drawings; + QList definedNamesList; QList sheetItemInfoList;//Data from xml file