Document::read() works for shared formula now.
This commit is contained in:
@@ -30,5 +30,12 @@ int main()
|
|||||||
qDebug()<<xlsx.read("A7");
|
qDebug()<<xlsx.read("A7");
|
||||||
//![1]
|
//![1]
|
||||||
|
|
||||||
|
//![2]
|
||||||
|
for (int row=1; row<10; ++row) {
|
||||||
|
if (QXlsx::Cell *cell=xlsx.cellAt(row, 1))
|
||||||
|
qDebug()<<cell->value();
|
||||||
|
}
|
||||||
|
//![2]
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,11 @@ int main()
|
|||||||
|
|
||||||
//Make sure that read/write works well.
|
//Make sure that read/write works well.
|
||||||
Document xlsx2("Book1.xlsx");
|
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");
|
xlsx2.saveAs("Book2.xlsx");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "xlsxutility_p.h"
|
#include "xlsxutility_p.h"
|
||||||
|
#include "xlsxcellreference.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QPoint>
|
#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)));
|
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
|
} //namespace QXlsx
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class QDateTime;
|
|||||||
class QTime;
|
class QTime;
|
||||||
|
|
||||||
namespace QXlsx {
|
namespace QXlsx {
|
||||||
|
class CellReference;
|
||||||
|
|
||||||
XLSX_AUTOTEST_EXPORT bool parseXsdBoolean(const QString &value, bool defaultValue=false);
|
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 QString createSafeSheetName(const QString &nameProposal);
|
||||||
XLSX_AUTOTEST_EXPORT bool isSpaceReserveNeeded(const QString &string);
|
XLSX_AUTOTEST_EXPORT bool isSpaceReserveNeeded(const QString &string);
|
||||||
|
|
||||||
|
XLSX_AUTOTEST_EXPORT QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell);
|
||||||
|
|
||||||
} //QXlsx
|
} //QXlsx
|
||||||
#endif // XLSXUTILITY_H
|
#endif // XLSXUTILITY_H
|
||||||
|
|||||||
@@ -512,11 +512,28 @@ QVariant Worksheet::read(const CellReference &row_column) const
|
|||||||
*/
|
*/
|
||||||
QVariant Worksheet::read(int row, int column) const
|
QVariant Worksheet::read(int row, int column) const
|
||||||
{
|
{
|
||||||
|
Q_D(const Worksheet);
|
||||||
|
|
||||||
Cell *cell = cellAt(row, column);
|
Cell *cell = cellAt(row, column);
|
||||||
if (!cell)
|
if (!cell)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
if (cell->hasFormula() && cell->formula().formulaType() == CellFormula::NormalType)
|
|
||||||
return QVariant(QLatin1String("=")+cell->formula().formulaText());
|
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()) {
|
if (cell->isDateTime()) {
|
||||||
double val = cell->value().toDouble();
|
double val = cell->value().toDouble();
|
||||||
QDateTime dt = cell->dateTime();
|
QDateTime dt = cell->dateTime();
|
||||||
@@ -526,6 +543,7 @@ QVariant Worksheet::read(int row, int column) const
|
|||||||
return dt.date();
|
return dt.date();
|
||||||
return dt;
|
return dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cell->value();
|
return cell->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "private/xlsxutility_p.h"
|
#include "private/xlsxutility_p.h"
|
||||||
|
#include "xlsxcellreference.h"
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
@@ -46,6 +47,9 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void test_createSafeSheetName_data();
|
void test_createSafeSheetName_data();
|
||||||
void test_createSafeSheetName();
|
void test_createSafeSheetName();
|
||||||
|
|
||||||
|
void test_convertSharedFormula_data();
|
||||||
|
void test_convertSharedFormula();
|
||||||
};
|
};
|
||||||
|
|
||||||
UtilityTest::UtilityTest()
|
UtilityTest::UtilityTest()
|
||||||
@@ -148,6 +152,30 @@ void UtilityTest::test_createSafeSheetName()
|
|||||||
QCOMPARE(QXlsx::createSafeSheetName(original), result);
|
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)
|
QTEST_APPLESS_MAIN(UtilityTest)
|
||||||
|
|
||||||
#include "tst_utilitytest.moc"
|
#include "tst_utilitytest.moc"
|
||||||
|
|||||||
Reference in New Issue
Block a user