Browse Source

Improve Document::read() support for shared formula

master
Debao Zhang 10 years ago
parent
commit
c1aca6994e
  1. 68
      src/xlsx/xlsxutility.cpp
  2. 9
      tests/auto/utility/tst_utilitytest.cpp
  3. 6
      tests/auto/worksheet/tst_worksheet.cpp

68
src/xlsx/xlsxutility.cpp

@ -159,62 +159,76 @@ bool isSpaceReserveNeeded(const QString &s)
*/ */
QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell) QString convertSharedFormula(const QString &rootFormula, const CellReference &rootCell, const CellReference &cell)
{ {
//Find all the "[A-Z]+[0-9]+" patterns in the rootFormula. //Find all the "$?[A-Z]+$?[0-9]+" patterns in the rootFormula.
QList<QPair<QString, bool> > segments; QList<QPair<QString, int> > segments;
QString segment; QString segment;
bool inQuote = false; bool inQuote = false;
int cellFlag = 0; //-1, 0, 1, 2 ==> Invalid, Empty, A-Z ready, A1 ready enum RefState{INVALID, PRE_AZ, AZ, PRE_09, _09};
RefState refState = INVALID;
int refFlag = 0; // 0x00, 0x01, 0x02, 0x03 ==> A1, $A1, A$1, $A$1
foreach (QChar ch, rootFormula) { foreach (QChar ch, rootFormula) {
if (inQuote) { if (inQuote) {
segment.append(ch); segment.append(ch);
if (ch == QLatin1Char('"')) { if (ch == QLatin1Char('"'))
segments.append(qMakePair(segment, false));
segment = QString();
inQuote = false; inQuote = false;
cellFlag = 0;
}
} else { } else {
if (ch == QLatin1Char('"')) { if (ch == QLatin1Char('"')) {
segments.append(qMakePair(segment, false));
segment = QString(ch);
inQuote = true; inQuote = true;
refState = INVALID;
segment.append(ch);
} else if (ch == QLatin1Char('$')) {
if (refState == AZ) {
segment.append(ch);
refState = PRE_09;
refFlag |= 0x02;
} else {
segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
segment = QString(ch); //Start new segment.
refState = PRE_AZ;
refFlag = 0x01;
}
} else if (ch >= QLatin1Char('A') && ch <=QLatin1Char('Z')) { } else if (ch >= QLatin1Char('A') && ch <=QLatin1Char('Z')) {
if (cellFlag == 0 || cellFlag == 1) { if (refState == PRE_AZ || refState == AZ) {
segment.append(ch); segment.append(ch);
} else { } else {
segments.append(qMakePair(segment, (cellFlag == 2))); segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
segment = QString(ch); //start new "A1" segment segment = QString(ch); //Start new segment.
refFlag = 0x00;
} }
cellFlag = 1; refState = AZ;
} else if (ch >= QLatin1Char('0') && ch <=QLatin1Char('9')) { } else if (ch >= QLatin1Char('0') && ch <=QLatin1Char('9')) {
segment.append(ch); segment.append(ch);
if (cellFlag == 1)
cellFlag = 2; if (refState == AZ || refState == PRE_09 || refState == _09)
refState = _09;
else
refState = INVALID;
} else { } else {
if (cellFlag == 2) { if (refState == _09) {
segments.append(qMakePair(segment, true)); //find one "A1" segment segments.append(qMakePair(segment, refFlag));
segment = QString(ch); segment = QString(ch); //Start new segment.
} else { } else {
segment.append(ch); segment.append(ch);
} }
cellFlag = -1; refState = INVALID;
} }
} }
} }
if (!segment.isEmpty()) if (!segment.isEmpty())
segments.append(qMakePair(segment, (cellFlag == 2))); segments.append(qMakePair(segment, refState==_09 ? refFlag : -1));
//Replace "A1" segment with proper one. //Replace "A1", "$A1", "A$1" segment with proper one.
QStringList result; QStringList result;
typedef QPair<QString, bool> PairType; typedef QPair<QString, int> PairType;
foreach (PairType p, segments) { foreach (PairType p, segments) {
if (p.second) { //qDebug()<<p.first<<p.second;
if (p.second != -1 && p.second != 3) {
CellReference oldRef(p.first); CellReference oldRef(p.first);
CellReference newRef(oldRef.row()-rootCell.row()+cell.row(), int row = p.second & 0x02 ? oldRef.row() : oldRef.row()-rootCell.row()+cell.row();
oldRef.column()-rootCell.column()+cell.column()); int col = p.second & 0x01 ? oldRef.column() : oldRef.column()-rootCell.column()+cell.column();
result.append(newRef.toString()); result.append(CellReference(row, col).toString(p.second & 0x02, p.second & 0x01));
} else { } else {
result.append(p.first); result.append(p.first);
} }

9
tests/auto/utility/tst_utilitytest.cpp

@ -165,6 +165,15 @@ void UtilityTest::test_convertSharedFormula_data()
QTest::newRow("[C4]") << QString("A1*B8")<<QString("C1")<<QString("C4")<<QString("A4*B11"); 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)"); QTest::newRow("[C4]") << QString("TAN(A1+B2*B3)+COS(A1-B2)")<<QString("C1")<<QString("C4")<<QString("TAN(A4+B5*B6)+COS(A4-B5)");
QTest::newRow("[Mixed B2]") << QString("$A1*A$1")<<QString("B1")<<QString("B2")<<QString("$A2*A$1");
QTest::newRow("[Mixed C1]") << QString("$A1*A$1")<<QString("B1")<<QString("C1")<<QString("$A1*B$1");
QTest::newRow("[Mixed D9]") << QString("$A1*A$1")<<QString("B1")<<QString("D9")<<QString("$A9*C$1");
QTest::newRow("[Mixed C4]") << QString("TAN(A1+B2*$B3)+COS(A1-B$2)")<<QString("C1")<<QString("C4")<<QString("TAN(A4+B5*$B6)+COS(A4-B$2)");
QTest::newRow("[Absolute C4]") << QString("A1*$B$8")<<QString("C1")<<QString("C4")<<QString("A4*$B$8");
QTest::newRow("[Quote]") << QString("=CONCATENATE(\"The B1 $B1 \",B1,\" units\")")<<QString("C1")<<QString("D2")<<QString("=CONCATENATE(\"The B1 $B1 \",C2,\" units\")");
} }
void UtilityTest::test_convertSharedFormula() void UtilityTest::test_convertSharedFormula()

6
tests/auto/worksheet/tst_worksheet.cpp

@ -90,7 +90,6 @@ void WorksheetTest::testSetColumn()
QByteArray xmldata = sheet.saveToXmlData(); QByteArray xmldata = sheet.saveToXmlData();
qDebug()<<xmldata;
QVERIFY(xmldata.contains("<col min=\"1\" max=\"3\"")); //"A:C" QVERIFY(xmldata.contains("<col min=\"1\" max=\"3\"")); //"A:C"
QVERIFY(xmldata.contains("<col min=\"4\" max=\"5\"")); //"D:E" QVERIFY(xmldata.contains("<col min=\"4\" max=\"5\"")); //"D:E"
QVERIFY(xmldata.contains("<col min=\"6\" max=\"6\"")); //"F:F" QVERIFY(xmldata.contains("<col min=\"6\" max=\"6\"")); //"F:F"
@ -110,13 +109,14 @@ void WorksheetTest::testWriteCells()
sheet.writeFormula(5, 2, "44+33", QXlsx::Format(), 77); sheet.writeFormula(5, 2, "44+33", QXlsx::Format(), 77);
QByteArray xmldata = sheet.saveToXmlData(); QByteArray xmldata = sheet.saveToXmlData();
qDebug()<<xmldata;
QVERIFY2(xmldata.contains("<c r=\"A1\"><v>123</v></c>"), "numeric"); QVERIFY2(xmldata.contains("<c r=\"A1\"><v>123</v></c>"), "numeric");
QVERIFY2(xmldata.contains("<c r=\"A2\" t=\"s\"><v>0</v></c>"), "string"); QVERIFY2(xmldata.contains("<c r=\"A2\" t=\"s\"><v>0</v></c>"), "string");
QVERIFY2(xmldata.contains("<c r=\"A3\" t=\"inlineStr\"><is><t>Hello inline</t></is></c>"), "inline string"); QVERIFY2(xmldata.contains("<c r=\"A3\" t=\"inlineStr\"><is><t>Hello inline</t></is></c>"), "inline string");
QVERIFY2(xmldata.contains("<c r=\"A4\" t=\"b\"><v>1</v></c>"), "boolean"); QVERIFY2(xmldata.contains("<c r=\"A4\" t=\"b\"><v>1</v></c>"), "boolean");
QVERIFY2(xmldata.contains("<c r=\"A5\"><f>44+33</f><v>0</v></c>"), "formula"); QVERIFY2(xmldata.contains("<c r=\"A5\"><f ca=\"1\">44+33</f><v>0</v></c>"), "formula");
QVERIFY2(xmldata.contains("<c r=\"B5\"><f>44+33</f><v>77</v></c>"), "formula"); QVERIFY2(xmldata.contains("<c r=\"B5\"><f ca=\"1\">44+33</f><v>77</v></c>"), "formula");
QCOMPARE(sheet.d_func()->sharedStrings()->getSharedString(0).toPlainString(), QStringLiteral("Hello")); QCOMPARE(sheet.d_func()->sharedStrings()->getSharedString(0).toPlainString(), QStringLiteral("Hello"));
} }

Loading…
Cancel
Save