Browse Source

Fix Issue #46: Add internal support for shared formulas

master
Debao Zhang 10 years ago
parent
commit
de5a0e52d2
  1. 23
      examples/xlsx/formulas/main.cpp
  2. 22
      src/xlsx/xlsxcellformula.cpp
  3. 6
      src/xlsx/xlsxcellformula.h
  4. 3
      src/xlsx/xlsxcellformula_p.h
  5. 42
      src/xlsx/xlsxworksheet.cpp
  6. 2
      src/xlsx/xlsxworksheet_p.h

23
examples/xlsx/formulas/main.cpp

@ -55,17 +55,30 @@ int main()
Worksheet *sheet = xlsx.currentWorksheet(); Worksheet *sheet = xlsx.currentWorksheet();
for (int row=2; row<20; ++row) { for (int row=2; row<20; ++row) {
sheet->write(row, 2, QString(row%5+1, 'X')); //B2:B19 sheet->write(row, 2, row*2); //B2:B19
sheet->write(row, 3, QString(row%5+1, 'X')); //C2:C19 sheet->write(row, 3, row*3); //C2:C19
sheet->write(row, 5, 100.0 - row); //E2:E19
} }
sheet->writeFormula("C20", CellFormula("SUM(IF((C2:C19=\"X\")*(B2:B19=\"X\"),1,0))", "C20", CellFormula::ArrayType)); sheet->writeFormula("D2", CellFormula("B2:B19+C2:C19", "D2:D19", CellFormula::ArrayType));
sheet->writeFormula("F2", CellFormula("E2:E19*10", "F2:F19", CellFormula::ArrayType));
//![2] //![2]
//![21]
xlsx.addSheet("SharedFormula");
sheet = xlsx.currentWorksheet();
for (int row=2; row<20; ++row) {
sheet->write(row, 2, row*2); //B2:B19
sheet->write(row, 3, row*3); //C2:C19
}
sheet->writeFormula("D2", CellFormula("=B2+C2", "D2:D19", CellFormula::SharedType));
//![21]
//![3] //![3]
xlsx.save(); xlsx.save();
//![3] //![3]
//Make sure that read/write works well.
Document xlsx2("Book1.xlsx");
xlsx2.saveAs("Book2.xlsx");
return 0; return 0;
} }

22
src/xlsx/xlsxcellformula.cpp

@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
#include "xlsxcellformula.h" #include "xlsxcellformula.h"
#include "xlsxcellformula_p.h" #include "xlsxcellformula_p.h"
#include "xlsxutility_p.h"
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QXmlStreamWriter> #include <QXmlStreamWriter>
@ -31,7 +32,7 @@
QT_BEGIN_NAMESPACE_XLSX QT_BEGIN_NAMESPACE_XLSX
CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_) CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange &ref_, CellFormula::FormulaType type_)
:formula(formula_), type(type_), reference(ref_), si(0) :formula(formula_), type(type_), reference(ref_), ca(false), si(0)
{ {
//Remove the formula '=' sign if exists //Remove the formula '=' sign if exists
if (formula.startsWith(QLatin1String("="))) if (formula.startsWith(QLatin1String("=")))
@ -42,7 +43,8 @@ CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange
CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other) CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &other)
: QSharedData(other) : QSharedData(other)
, formula(other.formula), type(other.type), reference(other.reference), si(other.si) , formula(other.formula), type(other.type), reference(other.reference)
, ca(other.ca), si(other.si)
{ {
} }
@ -139,7 +141,7 @@ CellFormula::FormulaType CellFormula::formulaType() const
/*! /*!
* Returns the contents of the formula. * Returns the contents of the formula.
*/ */
QString CellFormula::formulaContent() const QString CellFormula::formulaText() const
{ {
return d ? d->formula : QString(); return d ? d->formula : QString();
} }
@ -190,10 +192,14 @@ bool CellFormula::saveToXml(QXmlStreamWriter &writer) const
writer.writeAttribute(QStringLiteral("t"), t); writer.writeAttribute(QStringLiteral("t"), t);
if (d->reference.isValid()) if (d->reference.isValid())
writer.writeAttribute(QStringLiteral("ref"), d->reference.toString()); writer.writeAttribute(QStringLiteral("ref"), d->reference.toString());
if (d->ca)
writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1"));
if (d->type == CellFormula::SharedType) if (d->type == CellFormula::SharedType)
writer.writeAttribute(QStringLiteral("si"), QString::number(d->si)); writer.writeAttribute(QStringLiteral("si"), QString::number(d->si));
writer.writeCharacters(d->formula); if (!d->formula.isEmpty())
writer.writeCharacters(d->formula);
writer.writeEndElement(); //f writer.writeEndElement(); //f
return true; return true;
@ -220,10 +226,14 @@ bool CellFormula::loadFromXml(QXmlStreamReader &reader)
if (attributes.hasAttribute(QLatin1String("ref"))) { if (attributes.hasAttribute(QLatin1String("ref"))) {
QString refString = attributes.value(QLatin1String("ref")).toString(); QString refString = attributes.value(QLatin1String("ref")).toString();
d->reference = CellRange(refString); d->reference = CellRange(refString);
} else if (attributes.hasAttribute(QLatin1String("si"))) {
d->si = attributes.value(QLatin1String("si")).toString().toInt();
} }
QString ca = attributes.value(QLatin1String("si")).toString();
d->ca = parseXsdBoolean(ca, false);
if (attributes.hasAttribute(QLatin1String("si")))
d->si = attributes.value(QLatin1String("si")).toString().toInt();
d->formula = reader.readElementText(); d->formula = reader.readElementText();
return true; return true;
} }

6
src/xlsx/xlsxcellformula.h

@ -35,6 +35,8 @@ QT_BEGIN_NAMESPACE_XLSX
class CellFormulaPrivate; class CellFormulaPrivate;
class CellRange; class CellRange;
class Worksheet;
class WorksheetPrivate;
class Q_XLSX_EXPORT CellFormula class Q_XLSX_EXPORT CellFormula
{ {
@ -56,7 +58,7 @@ public:
bool isValid() const; bool isValid() const;
FormulaType formulaType() const; FormulaType formulaType() const;
QString formulaContent() const; QString formulaText() const;
CellRange reference() const; CellRange reference() const;
int sharedIndex() const; int sharedIndex() const;
@ -66,6 +68,8 @@ public:
bool saveToXml(QXmlStreamWriter &writer) const; bool saveToXml(QXmlStreamWriter &writer) const;
bool loadFromXml(QXmlStreamReader &reader); bool loadFromXml(QXmlStreamReader &reader);
private: private:
friend class Worksheet;
friend class WorksheetPrivate;
QExplicitlySharedDataPointer<CellFormulaPrivate> d; QExplicitlySharedDataPointer<CellFormulaPrivate> d;
}; };

3
src/xlsx/xlsxcellformula_p.h

@ -55,7 +55,8 @@ public:
QString formula; //formula contents QString formula; //formula contents
CellFormula::FormulaType type; CellFormula::FormulaType type;
CellRange reference; CellRange reference;
int si; bool ca; //Calculate Cell
int si; //Shared group index
}; };
QT_END_NAMESPACE_XLSX QT_END_NAMESPACE_XLSX

42
src/xlsx/xlsxworksheet.cpp

@ -513,7 +513,7 @@ QVariant Worksheet::read(int row, int column) const
if (!cell) if (!cell)
return QVariant(); return QVariant();
if (cell->hasFormula() && cell->formula().formulaType() == CellFormula::NormalType) if (cell->hasFormula() && cell->formula().formulaType() == CellFormula::NormalType)
return QVariant(QLatin1String("=")+cell->formula().formulaContent()); return QVariant(QLatin1String("=")+cell->formula().formulaText());
if (cell->isDateTime()) { if (cell->isDateTime()) {
double val = cell->value().toDouble(); double val = cell->value().toDouble();
QDateTime dt = cell->dateTime(); QDateTime dt = cell->dateTime();
@ -709,7 +709,7 @@ bool Worksheet::writeFormula(const CellReference &row_column, const CellFormula
/*! /*!
Write \a formula to the cell (\a row, \a column) with the \a format and \a result. Write \a formula to the cell (\a row, \a column) with the \a format and \a result.
*/ */
bool Worksheet::writeFormula(int row, int column, const CellFormula &formula, const Format &format, double result) bool Worksheet::writeFormula(int row, int column, const CellFormula &formula_, const Format &format, double result)
{ {
Q_D(Worksheet); Q_D(Worksheet);
if (d->checkDimensions(row, column)) if (d->checkDimensions(row, column))
@ -718,10 +718,42 @@ bool Worksheet::writeFormula(int row, int column, const CellFormula &formula, co
Format fmt = format.isValid() ? format : d->cellFormat(row, column); Format fmt = format.isValid() ? format : d->cellFormat(row, column);
d->workbook->styles()->addXfFormat(fmt); d->workbook->styles()->addXfFormat(fmt);
CellFormula formula = formula_;
formula.d->ca = true;
if (formula.formulaType() == CellFormula::SharedType) {
//Assign proper shared index for shared formula
int si=0;
while(d->sharedFormulaMap.contains(si))
++si;
formula.d->si = si;
d->sharedFormulaMap[si] = formula;
}
QSharedPointer<Cell> data = QSharedPointer<Cell>(new Cell(result, Cell::NumberType, fmt, this)); QSharedPointer<Cell> data = QSharedPointer<Cell>(new Cell(result, Cell::NumberType, fmt, this));
data->d_ptr->formula = formula; data->d_ptr->formula = formula;
d->cellTable[row][column] = data; d->cellTable[row][column] = data;
CellRange range = formula.reference();
if (formula.formulaType() == CellFormula::SharedType) {
CellFormula sf(QString(), CellFormula::SharedType);
sf.d->si = formula.sharedIndex();
for (int r=range.firstRow(); r<=range.lastRow(); ++r) {
for (int c=range.firstColumn(); c<=range.lastColumn(); ++c) {
if (!(r==row && c==column)) {
if(Cell *cell = cellAt(r, c)) {
cell->d_ptr->formula = sf;
} else {
QSharedPointer<Cell> newCell = QSharedPointer<Cell>(new Cell(result, Cell::NumberType, fmt, this));
newCell->d_ptr->formula = sf;
d->cellTable[r][c] = newCell;
}
}
}
}
} else if (formula.formulaType() == CellFormula::SharedType) {
}
return true; return true;
} }
@ -1896,7 +1928,11 @@ void WorksheetPrivate::loadXmlSheetData(QXmlStreamReader &reader)
while (!reader.atEnd() && !(reader.name() == QLatin1String("c") && reader.tokenType() == QXmlStreamReader::EndElement)) { while (!reader.atEnd() && !(reader.name() == QLatin1String("c") && reader.tokenType() == QXmlStreamReader::EndElement)) {
if (reader.readNextStartElement()) { if (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("f")) { if (reader.name() == QLatin1String("f")) {
cell->d_func()->formula.loadFromXml(reader); CellFormula &formula = cell->d_func()->formula;
formula.loadFromXml(reader);
if (formula.formulaType() == CellFormula::SharedType && !formula.formulaText().isEmpty()) {
sharedFormulaMap[formula.sharedIndex()] = formula;
}
} else if (reader.name() == QLatin1String("v")) { } else if (reader.name() == QLatin1String("v")) {
QString value = reader.readElementText(); QString value = reader.readElementText();
if (cellType == Cell::SharedStringType) { if (cellType == Cell::SharedStringType) {

2
src/xlsx/xlsxworksheet_p.h

@ -41,6 +41,7 @@
#include "xlsxcell.h" #include "xlsxcell.h"
#include "xlsxdatavalidation.h" #include "xlsxdatavalidation.h"
#include "xlsxconditionalformatting.h" #include "xlsxconditionalformatting.h"
#include "xlsxcellformula.h"
#include <QImage> #include <QImage>
#include <QSharedPointer> #include <QSharedPointer>
@ -194,6 +195,7 @@ public:
QList<DataValidation> dataValidationsList; QList<DataValidation> dataValidationsList;
QList<ConditionalFormatting> conditionalFormattingList; QList<ConditionalFormatting> conditionalFormattingList;
QMap<int, CellFormula> sharedFormulaMap;
CellRange dimension; CellRange dimension;
int previous_row; int previous_row;

Loading…
Cancel
Save