Document::read() works for shared formula now.
This commit is contained in:
@@ -30,5 +30,12 @@ int main()
|
||||
qDebug()<<xlsx.read("A7");
|
||||
//![1]
|
||||
|
||||
//![2]
|
||||
for (int row=1; row<10; ++row) {
|
||||
if (QXlsx::Cell *cell=xlsx.cellAt(row, 1))
|
||||
qDebug()<<cell->value();
|
||||
}
|
||||
//![2]
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -81,6 +81,11 @@ int main()
|
||||
|
||||
//Make sure that read/write works well.
|
||||
Document xlsx2("Book1.xlsx");
|
||||
Worksheet *sharedFormulaSheet = dynamic_cast<Worksheet*>(xlsx2.sheet("SharedFormula"));
|
||||
for (int row=2; row<20; ++row) {
|
||||
qDebug()<<sharedFormulaSheet->read(row, 4);
|
||||
}
|
||||
|
||||
xlsx2.saveAs("Book2.xlsx");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "xlsxutility_p.h"
|
||||
#include "xlsxcellreference.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QPoint>
|
||||
@@ -145,4 +146,82 @@ bool isSpaceReserveNeeded(const QString &s)
|
||||
return !s.isEmpty() && (spaces.contains(s.at(0))||spaces.contains(s.at(s.length()-1)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert shared formula for non-root cells.
|
||||
*
|
||||
* For example, if "B1:B10" have shared formula "=A1*A1", this function will return "=A2*A2"
|
||||
* for "B2" cell, "=A3*A3" for "B3" cell, etc.
|
||||
*
|
||||
* Note, the formula "=A1*A1" for B1 can also be written as "=RC[-1]*RC[-1]", which is the same
|
||||
* for all other cells. In other words, this formula is shared.
|
||||
*
|
||||
* For long run, we need a formula parser.
|
||||
*/
|
||||
QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell)
|
||||
{
|
||||
//Find all the "[A-Z]+[0-9]+" patterns in the rootFormula.
|
||||
QList<QPair<QString, bool> > segments;
|
||||
|
||||
QString segment;
|
||||
bool inQuote = false;
|
||||
int cellFlag = 0; //-1, 0, 1, 2 ==> Invalid, Empty, A-Z ready, A1 ready
|
||||
foreach (QChar ch, rootFormula) {
|
||||
if (inQuote) {
|
||||
segment.append(ch);
|
||||
if (ch == QLatin1Char('"')) {
|
||||
segments.append(qMakePair(segment, false));
|
||||
segment = QString();
|
||||
inQuote = false;
|
||||
cellFlag = 0;
|
||||
}
|
||||
} else {
|
||||
if (ch == QLatin1Char('"')) {
|
||||
segments.append(qMakePair(segment, false));
|
||||
segment = QString(ch);
|
||||
inQuote = true;
|
||||
} else if (ch >= QLatin1Char('A') && ch <=QLatin1Char('Z')) {
|
||||
if (cellFlag == 0 || cellFlag == 1) {
|
||||
segment.append(ch);
|
||||
} else {
|
||||
segments.append(qMakePair(segment, (cellFlag == 2)));
|
||||
segment = QString(ch); //start new "A1" segment
|
||||
}
|
||||
cellFlag = 1;
|
||||
} else if (ch >= QLatin1Char('0') && ch <=QLatin1Char('9')) {
|
||||
segment.append(ch);
|
||||
if (cellFlag == 1)
|
||||
cellFlag = 2;
|
||||
} else {
|
||||
if (cellFlag == 2) {
|
||||
segments.append(qMakePair(segment, true)); //find one "A1" segment
|
||||
segment = QString(ch);
|
||||
} else {
|
||||
segment.append(ch);
|
||||
}
|
||||
cellFlag = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!segment.isEmpty())
|
||||
segments.append(qMakePair(segment, (cellFlag == 2)));
|
||||
|
||||
//Replace "A1" segment with proper one.
|
||||
QStringList result;
|
||||
typedef QPair<QString, bool> PairType;
|
||||
foreach (PairType p, segments) {
|
||||
if (p.second) {
|
||||
CellReference oldRef(p.first);
|
||||
CellReference newRef(oldRef.row()-rootCell.row()+cell.row(),
|
||||
oldRef.column()-rootCell.column()+cell.column());
|
||||
result.append(newRef.toString());
|
||||
} else {
|
||||
result.append(p.first);
|
||||
}
|
||||
}
|
||||
|
||||
//OK
|
||||
return result.join(QString());
|
||||
}
|
||||
|
||||
} //namespace QXlsx
|
||||
|
||||
@@ -45,6 +45,7 @@ class QDateTime;
|
||||
class QTime;
|
||||
|
||||
namespace QXlsx {
|
||||
class CellReference;
|
||||
|
||||
XLSX_AUTOTEST_EXPORT bool parseXsdBoolean(const QString &value, bool defaultValue=false);
|
||||
|
||||
@@ -58,5 +59,7 @@ XLSX_AUTOTEST_EXPORT double timeToNumber(const QTime &t);
|
||||
XLSX_AUTOTEST_EXPORT QString createSafeSheetName(const QString &nameProposal);
|
||||
XLSX_AUTOTEST_EXPORT bool isSpaceReserveNeeded(const QString &string);
|
||||
|
||||
XLSX_AUTOTEST_EXPORT QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell);
|
||||
|
||||
} //QXlsx
|
||||
#endif // XLSXUTILITY_H
|
||||
|
||||
@@ -512,11 +512,28 @@ QVariant Worksheet::read(const CellReference &row_column) const
|
||||
*/
|
||||
QVariant Worksheet::read(int row, int column) const
|
||||
{
|
||||
Q_D(const Worksheet);
|
||||
|
||||
Cell *cell = cellAt(row, column);
|
||||
if (!cell)
|
||||
return QVariant();
|
||||
if (cell->hasFormula() && cell->formula().formulaType() == CellFormula::NormalType)
|
||||
|
||||
if (cell->hasFormula()) {
|
||||
if (cell->formula().formulaType() == CellFormula::NormalType) {
|
||||
return QVariant(QLatin1String("=")+cell->formula().formulaText());
|
||||
} else if (cell->formula().formulaType() == CellFormula::SharedType) {
|
||||
if (!cell->formula().formulaText().isEmpty()) {
|
||||
return QVariant(QLatin1String("=")+cell->formula().formulaText());
|
||||
} else {
|
||||
const CellFormula &rootFormula = d->sharedFormulaMap[cell->formula().sharedIndex()];
|
||||
CellReference rootCellRef = rootFormula.reference().topLeft();
|
||||
QString rootFormulaText = rootFormula.formulaText();
|
||||
QString newFormulaText = convertSharedFormula(rootFormulaText, rootCellRef, CellReference(row, column));
|
||||
return QVariant(QLatin1String("=")+newFormulaText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cell->isDateTime()) {
|
||||
double val = cell->value().toDouble();
|
||||
QDateTime dt = cell->dateTime();
|
||||
@@ -526,6 +543,7 @@ QVariant Worksheet::read(int row, int column) const
|
||||
return dt.date();
|
||||
return dt;
|
||||
}
|
||||
|
||||
return cell->value();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "private/xlsxutility_p.h"
|
||||
#include "xlsxcellreference.h"
|
||||
#include <QString>
|
||||
#include <QtTest>
|
||||
#include <QDateTime>
|
||||
@@ -46,6 +47,9 @@ private Q_SLOTS:
|
||||
|
||||
void test_createSafeSheetName_data();
|
||||
void test_createSafeSheetName();
|
||||
|
||||
void test_convertSharedFormula_data();
|
||||
void test_convertSharedFormula();
|
||||
};
|
||||
|
||||
UtilityTest::UtilityTest()
|
||||
@@ -148,6 +152,30 @@ void UtilityTest::test_createSafeSheetName()
|
||||
QCOMPARE(QXlsx::createSafeSheetName(original), result);
|
||||
}
|
||||
|
||||
void UtilityTest::test_convertSharedFormula_data()
|
||||
{
|
||||
QTest::addColumn<QString>("original");
|
||||
QTest::addColumn<QString>("rootCell");
|
||||
QTest::addColumn<QString>("cell");
|
||||
QTest::addColumn<QString>("result");
|
||||
|
||||
QTest::newRow("[Simple B2]") << QString("A1*A1")<<QString("B1")<<QString("B2")<<QString("A2*A2");
|
||||
QTest::newRow("[Simple C1]") << QString("A1*A1")<<QString("B1")<<QString("C1")<<QString("B1*B1");
|
||||
QTest::newRow("[Simple D9]") << QString("A1*A1")<<QString("B1")<<QString("D9")<<QString("C9*C9");
|
||||
|
||||
QTest::newRow("[C4]") << QString("A1*B8")<<QString("C1")<<QString("C4")<<QString("A4*B11");
|
||||
QTest::newRow("[C4]") << QString("TAN(A1+B2*B3)+COS(A1-B2)")<<QString("C1")<<QString("C4")<<QString("TAN(A4+B5*B6)+COS(A4-B5)");
|
||||
}
|
||||
|
||||
void UtilityTest::test_convertSharedFormula()
|
||||
{
|
||||
QFETCH(QString, original);
|
||||
QFETCH(QString, rootCell);
|
||||
QFETCH(QString, cell);
|
||||
QFETCH(QString, result);
|
||||
|
||||
QCOMPARE(QXlsx::convertSharedFormula(original, rootCell, cell), result);
|
||||
}
|
||||
QTEST_APPLESS_MAIN(UtilityTest)
|
||||
|
||||
#include "tst_utilitytest.moc"
|
||||
|
||||
Reference in New Issue
Block a user