Fix Issue #46: Add internal support for shared formulas
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user