Browse Source

Document::read() works for shared formula now.

master
Debao Zhang 10 years ago
parent
commit
41e3dc1bf7
  1. 7
      examples/xlsx/extractdata/main.cpp
  2. 5
      examples/xlsx/formulas/main.cpp
  3. 79
      src/xlsx/xlsxutility.cpp
  4. 3
      src/xlsx/xlsxutility_p.h
  5. 22
      src/xlsx/xlsxworksheet.cpp
  6. 28
      tests/auto/utility/tst_utilitytest.cpp

7
examples/xlsx/extractdata/main.cpp

@ -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;
} }

5
examples/xlsx/formulas/main.cpp

@ -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;

79
src/xlsx/xlsxutility.cpp

@ -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

3
src/xlsx/xlsxutility_p.h

@ -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

22
src/xlsx/xlsxworksheet.cpp

@ -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();
} }

28
tests/auto/utility/tst_utilitytest.cpp

@ -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"

Loading…
Cancel
Save