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