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

22
src/xlsx/xlsxcellformula.cpp

@ -24,6 +24,7 @@
****************************************************************************/
#include "xlsxcellformula.h"
#include "xlsxcellformula_p.h"
#include "xlsxutility_p.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
@ -31,7 +32,7 @@
QT_BEGIN_NAMESPACE_XLSX
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
if (formula.startsWith(QLatin1String("=")))
@ -42,7 +43,8 @@ CellFormulaPrivate::CellFormulaPrivate(const QString &formula_, const CellRange
CellFormulaPrivate::CellFormulaPrivate(const CellFormulaPrivate &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.
*/
QString CellFormula::formulaContent() const
QString CellFormula::formulaText() const
{
return d ? d->formula : QString();
}
@ -190,10 +192,14 @@ bool CellFormula::saveToXml(QXmlStreamWriter &writer) const
writer.writeAttribute(QStringLiteral("t"), t);
if (d->reference.isValid())
writer.writeAttribute(QStringLiteral("ref"), d->reference.toString());
if (d->ca)
writer.writeAttribute(QStringLiteral("ca"), QStringLiteral("1"));
if (d->type == CellFormula::SharedType)
writer.writeAttribute(QStringLiteral("si"), QString::number(d->si));
writer.writeCharacters(d->formula);
if (!d->formula.isEmpty())
writer.writeCharacters(d->formula);
writer.writeEndElement(); //f
return true;
@ -220,10 +226,14 @@ bool CellFormula::loadFromXml(QXmlStreamReader &reader)
if (attributes.hasAttribute(QLatin1String("ref"))) {
QString refString = attributes.value(QLatin1String("ref")).toString();
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();
return true;
}

6
src/xlsx/xlsxcellformula.h

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

3
src/xlsx/xlsxcellformula_p.h

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

42
src/xlsx/xlsxworksheet.cpp

@ -513,7 +513,7 @@ QVariant Worksheet::read(int row, int column) const
if (!cell)
return QVariant();
if (cell->hasFormula() && cell->formula().formulaType() == CellFormula::NormalType)
return QVariant(QLatin1String("=")+cell->formula().formulaContent());
return QVariant(QLatin1String("=")+cell->formula().formulaText());
if (cell->isDateTime()) {
double val = cell->value().toDouble();
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.
*/
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);
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);
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));
data->d_ptr->formula = formula;
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;
}
@ -1896,7 +1928,11 @@ void WorksheetPrivate::loadXmlSheetData(QXmlStreamReader &reader)
while (!reader.atEnd() && !(reader.name() == QLatin1String("c") && reader.tokenType() == QXmlStreamReader::EndElement)) {
if (reader.readNextStartElement()) {
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")) {
QString value = reader.readElementText();
if (cellType == Cell::SharedStringType) {

2
src/xlsx/xlsxworksheet_p.h

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

Loading…
Cancel
Save