Browse Source

Fix Issue 7: Cell string misplacement when rich text exist

A private class RichString has been added. More work is needed
master
Debao Zhang 12 years ago
parent
commit
00350d4251
  1. 6
      src/xlsx/qtxlsx.pri
  2. 12
      src/xlsx/xlsxcell.cpp
  3. 2
      src/xlsx/xlsxcell.h
  4. 5
      src/xlsx/xlsxcell_p.h
  5. 2
      src/xlsx/xlsxformat.h
  6. 3
      src/xlsx/xlsxpackage.cpp
  7. 173
      src/xlsx/xlsxrichstring.cpp
  8. 79
      src/xlsx/xlsxrichstring_p.h
  9. 107
      src/xlsx/xlsxsharedstrings.cpp
  10. 19
      src/xlsx/xlsxsharedstrings_p.h
  11. 24
      src/xlsx/xlsxworksheet.cpp
  12. 3
      tests/auto/auto.pro
  13. 12
      tests/auto/richstring/richstring.pro
  14. 41
      tests/auto/richstring/tst_richstringtest.cpp
  15. 36
      tests/auto/sharedstrings/tst_sharedstringstest.cpp
  16. 13
      tests/auto/worksheet/tst_worksheet.cpp

6
src/xlsx/qtxlsx.pri

@ -31,7 +31,8 @@ HEADERS += $$PWD/xlsxdocpropscore_p.h \
$$PWD/xlsxcell_p.h \ $$PWD/xlsxcell_p.h \
$$PWD/xlsxdatavalidation.h \ $$PWD/xlsxdatavalidation.h \
$$PWD/xlsxdatavalidation_p.h \ $$PWD/xlsxdatavalidation_p.h \
$$PWD/xlsxcellrange.h $$PWD/xlsxcellrange.h \
$$PWD/xlsxrichstring_p.h
SOURCES += $$PWD/xlsxdocpropscore.cpp \ SOURCES += $$PWD/xlsxdocpropscore.cpp \
$$PWD/xlsxdocpropsapp.cpp \ $$PWD/xlsxdocpropsapp.cpp \
@ -53,4 +54,5 @@ SOURCES += $$PWD/xlsxdocpropscore.cpp \
$$PWD/xlsxdocument.cpp \ $$PWD/xlsxdocument.cpp \
$$PWD/xlsxcell.cpp \ $$PWD/xlsxcell.cpp \
$$PWD/xlsxdatavalidation.cpp \ $$PWD/xlsxdatavalidation.cpp \
$$PWD/xlsxcellrange.cpp $$PWD/xlsxcellrange.cpp \
$$PWD/xlsxrichstring.cpp

12
src/xlsx/xlsxcell.cpp

@ -121,4 +121,16 @@ QDateTime Cell::dateTime() const
return datetimeFromNumber(d->value.toDouble(), d->parent->workbook()->isDate1904()); return datetimeFromNumber(d->value.toDouble(), d->parent->workbook()->isDate1904());
} }
/*!
* Returns whether the cell is probably a rich string or not
*/
bool Cell::isRichString() const
{
Q_D(const Cell);
if (d->dataType != String && d->dataType != InlineString)
return false;
return d->richString.isRichString();
}
QT_END_NAMESPACE_XLSX QT_END_NAMESPACE_XLSX

2
src/xlsx/xlsxcell.h

@ -58,6 +58,8 @@ public:
bool isDateTime() const; bool isDateTime() const;
QDateTime dateTime() const; QDateTime dateTime() const;
bool isRichString() const;
~Cell(); ~Cell();
private: private:
friend class Worksheet; friend class Worksheet;

5
src/xlsx/xlsxcell_p.h

@ -28,6 +28,9 @@
#include "xlsxglobal.h" #include "xlsxglobal.h"
#include "xlsxcell.h" #include "xlsxcell.h"
#include "xlsxcellrange.h" #include "xlsxcellrange.h"
#include "xlsxrichstring_p.h"
#include <QList>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE_XLSX QT_BEGIN_NAMESPACE_XLSX
@ -43,6 +46,8 @@ public:
Format *format; Format *format;
CellRange range; //used for arrayFormula CellRange range; //used for arrayFormula
RichString richString;
Worksheet *parent; Worksheet *parent;
Cell *q_ptr; Cell *q_ptr;
}; };

2
src/xlsx/xlsxformat.h

@ -38,6 +38,7 @@ QT_BEGIN_NAMESPACE_XLSX
class Styles; class Styles;
class Worksheet; class Worksheet;
class WorksheetPrivate; class WorksheetPrivate;
class RichString;
class FormatPrivate; class FormatPrivate;
class Q_XLSX_EXPORT Format class Q_XLSX_EXPORT Format
@ -214,6 +215,7 @@ private:
friend class Styles; friend class Styles;
friend class Worksheet; friend class Worksheet;
friend class WorksheetPrivate; friend class WorksheetPrivate;
friend class RichString;
friend class ::FormatTest; friend class ::FormatTest;
Format(); Format();

3
src/xlsx/xlsxpackage.cpp

@ -160,8 +160,7 @@ bool Package::parsePackage(QIODevice *packageDevice)
//In normal case this should be sharedStrings.xml which in xl //In normal case this should be sharedStrings.xml which in xl
QString name = rels_sharedStrings[0].target; QString name = rels_sharedStrings[0].target;
QString path = xlworkbook_Dir + QLatin1String("/") + name; QString path = xlworkbook_Dir + QLatin1String("/") + name;
QSharedPointer<SharedStrings> sst= SharedStrings::loadFromXmlData(zipReader.fileData(path)); m_document->workbook()->d_ptr->sharedStrings->loadFromXmlData(zipReader.fileData(path));
m_document->workbook()->d_ptr->sharedStrings = sst;
} }
//load theme //load theme

173
src/xlsx/xlsxrichstring.cpp

@ -0,0 +1,173 @@
/****************************************************************************
** Copyright (c) 2013 Debao Zhang <hello@debao.me>
** All right reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
** "Software"), to deal in the Software without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Software, and to
** permit persons to whom the Software is furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**
****************************************************************************/
#include "xlsxrichstring_p.h"
QT_BEGIN_NAMESPACE_XLSX
RichString::RichString()
:m_dirty(true)
{
}
RichString::RichString(const QString text)
:m_dirty(true)
{
addFragment(text, 0);
}
bool RichString::isRichString() const
{
if (fragmentCount() > 1) //Is this enough??
return true;
return false;
}
bool RichString::isEmtpy() const
{
return m_fragmentTexts.size() == 0;
}
QString RichString::toPlainString() const
{
if (isEmtpy())
return QString();
if (m_fragmentTexts.size() == 1)
return m_fragmentTexts[0];
return m_fragmentTexts.join(QString());
}
int RichString::fragmentCount() const
{
return m_fragmentTexts.size();
}
void RichString::addFragment(const QString &text, Format *format)
{
m_fragmentTexts.append(text);
m_fragmentFormats.append(format);
m_dirty = true;
}
QString RichString::fragmentText(int index) const
{
if (index < 0 || index >= fragmentCount())
return QString();
return m_fragmentTexts[index];
}
Format *RichString::fragmentFormat(int index) const
{
if (index < 0 || index >= fragmentCount())
return 0;
return m_fragmentFormats[index];
}
/*!
* \internal
*/
QByteArray RichString::idKey() const
{
if (m_dirty) {
RichString *rs = const_cast<RichString *>(this);
QByteArray bytes;
if (!isRichString()) {
bytes = toPlainString().toUtf8();
} else {
//Generate a hash value base on QByteArray ?
bytes.append("@@QtXlsxRichString=");
for (int i=0; i<fragmentCount(); ++i) {
bytes.append("@Text");
bytes.append(m_fragmentTexts[i].toUtf8());
bytes.append("@Format");
if (m_fragmentFormats[i])
bytes.append(m_fragmentFormats[i]->fontKey());
}
}
rs->m_idKey = bytes;
rs->m_dirty = false;
}
return m_idKey;
}
bool operator==(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return false;
return rs1.idKey() == rs2.idKey();
}
bool operator!=(const RichString &rs1, const RichString &rs2)
{
if (rs1.fragmentCount() != rs2.fragmentCount())
return true;
return rs1.idKey() != rs2.idKey();
}
/*!
* \internal
*/
bool operator<(const RichString &rs1, const RichString &rs2)
{
return rs1.idKey() < rs2.idKey();
}
bool operator ==(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return true;
return false;
}
bool operator !=(const RichString &rs1, const QString &rs2)
{
if (rs1.fragmentCount() == 1 && rs1.fragmentText(0) == rs2) //format == 0
return false;
return true;
}
bool operator ==(const QString &rs1, const RichString &rs2)
{
return rs2 == rs1;
}
bool operator !=(const QString &rs1, const RichString &rs2)
{
return rs2 != rs1;
}
uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW
{
return qHash(rs.idKey(), seed);
}
QT_END_NAMESPACE_XLSX

79
src/xlsx/xlsxrichstring_p.h

@ -0,0 +1,79 @@
/****************************************************************************
** Copyright (c) 2013 Debao Zhang <hello@debao.me>
** All right reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
** "Software"), to deal in the Software without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Software, and to
** permit persons to whom the Software is furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**
****************************************************************************/
#ifndef XLSXRICHSTRING_P_H
#define XLSXRICHSTRING_P_H
#include "xlsxglobal.h"
#include "xlsxformat.h"
#include <QStringList>
QT_BEGIN_NAMESPACE_XLSX
class RichString;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
XLSX_AUTOTEST_EXPORT uint qHash(const RichString &rs, uint seed = 0) Q_DECL_NOTHROW;
class XLSX_AUTOTEST_EXPORT RichString
{
public:
RichString();
explicit RichString(const QString text);
bool isRichString() const;
bool isEmtpy() const;
QString toPlainString() const;
int fragmentCount() const;
void addFragment(const QString &text, Format *format);
QString fragmentText(int index) const;
Format *fragmentFormat(int index) const;
private:
friend XLSX_AUTOTEST_EXPORT uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW;
friend XLSX_AUTOTEST_EXPORT bool operator==(const RichString &rs1, const RichString &rs2);
friend XLSX_AUTOTEST_EXPORT bool operator!=(const RichString &rs1, const RichString &rs2);
friend XLSX_AUTOTEST_EXPORT bool operator<(const RichString &rs1, const RichString &rs2);
QByteArray idKey() const;
QStringList m_fragmentTexts;
QList<Format *> m_fragmentFormats;
QByteArray m_idKey;
bool m_dirty;
};
XLSX_AUTOTEST_EXPORT bool operator==(const RichString &rs1, const RichString &rs2);
XLSX_AUTOTEST_EXPORT bool operator!=(const RichString &rs1, const RichString &rs2);
XLSX_AUTOTEST_EXPORT bool operator<(const RichString &rs1, const RichString &rs2);
XLSX_AUTOTEST_EXPORT bool operator==(const RichString &rs1, const QString &rs2);
XLSX_AUTOTEST_EXPORT bool operator==(const QString &rs1, const RichString &rs2);
XLSX_AUTOTEST_EXPORT bool operator!=(const RichString &rs1, const QString &rs2);
XLSX_AUTOTEST_EXPORT bool operator!=(const QString &rs1, const RichString &rs2);
QT_END_NAMESPACE_XLSX
Q_DECLARE_METATYPE(QXlsx::RichString);
#endif // XLSXRICHSTRING_P_H

107
src/xlsx/xlsxsharedstrings.cpp

@ -22,6 +22,7 @@
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
** **
****************************************************************************/ ****************************************************************************/
#include "xlsxrichstring_p.h"
#include "xlsxsharedstrings_p.h" #include "xlsxsharedstrings_p.h"
#include "xlsxxmlwriter_p.h" #include "xlsxxmlwriter_p.h"
#include "xlsxxmlreader_p.h" #include "xlsxxmlreader_p.h"
@ -44,6 +45,11 @@ int SharedStrings::count() const
} }
int SharedStrings::addSharedString(const QString &string) int SharedStrings::addSharedString(const QString &string)
{
return addSharedString(RichString(string));
}
int SharedStrings::addSharedString(const RichString &string)
{ {
m_stringCount += 1; m_stringCount += 1;
@ -70,6 +76,11 @@ void SharedStrings::incRefByStringIndex(int idx)
} }
void SharedStrings::removeSharedString(const QString &string) void SharedStrings::removeSharedString(const QString &string)
{
removeSharedString(RichString(string));
}
void SharedStrings::removeSharedString(const RichString &string)
{ {
if (!m_stringTable.contains(string)) if (!m_stringTable.contains(string))
return; return;
@ -89,20 +100,25 @@ void SharedStrings::removeSharedString(const QString &string)
} }
int SharedStrings::getSharedStringIndex(const QString &string) const int SharedStrings::getSharedStringIndex(const QString &string) const
{
return getSharedStringIndex(RichString(string));
}
int SharedStrings::getSharedStringIndex(const RichString &string) const
{ {
if (m_stringTable.contains(string)) if (m_stringTable.contains(string))
return m_stringTable[string].index; return m_stringTable[string].index;
return -1; return -1;
} }
QString SharedStrings::getSharedString(int index) const RichString SharedStrings::getSharedString(int index) const
{ {
if (index < m_stringList.count() && index >= 0) if (index < m_stringList.count() && index >= 0)
return m_stringList[index]; return m_stringList[index];
return QString(); return RichString();
} }
QStringList SharedStrings::getSharedStrings() const QList<RichString> SharedStrings::getSharedStrings() const
{ {
return m_stringList; return m_stringList;
} }
@ -117,16 +133,29 @@ void SharedStrings::saveToXmlFile(QIODevice *device) const
writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount)); writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount));
writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringTable.size())); writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringTable.size()));
foreach (QString string, m_stringList) { foreach (RichString string, m_stringList) {
writer.writeStartElement(QStringLiteral("si")); writer.writeStartElement(QStringLiteral("si"));
if (string.contains(QRegularExpression(QStringLiteral("^<r>"))) || string.contains(QRegularExpression(QStringLiteral("</r>$")))) { if (string.isRichString()) {
//Rich text string, //Rich text string
// writer.writeCharacters(string); for (int i=0; i<string.fragmentCount(); ++i) {
if (string.fragmentFormat(i)) {
writer.writeStartElement(QStringLiteral("rPr"));
//:Todo
writer.writeEndElement();// rPr
}
writer.writeStartElement(QStringLiteral("t"));
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(string.fragmentText(i));
writer.writeEndElement();// t
}
} else { } else {
writer.writeStartElement(QStringLiteral("t")); writer.writeStartElement(QStringLiteral("t"));
if (string.contains(QRegularExpression(QStringLiteral("^\\s"))) || string.contains(QRegularExpression(QStringLiteral("\\s$")))) QString pString = string.toPlainString();
if (pString.contains(QRegularExpression(QStringLiteral("^\\s")))
|| pString.contains(QRegularExpression(QStringLiteral("\\s$")))) {
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve")); writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(string); }
writer.writeCharacters(pString);
writer.writeEndElement();//t writer.writeEndElement();//t
} }
writer.writeEndElement();//si writer.writeEndElement();//si
@ -146,6 +175,56 @@ QByteArray SharedStrings::saveToXmlData() const
return data; return data;
} }
void SharedStrings::readString(XmlStreamReader &reader)
{
Q_ASSERT(reader.name() == QLatin1String("si"));
RichString richString;
while (!(reader.name() == QLatin1String("si") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("r"))
readRichStringPart(reader, richString);
else if (reader.name() == QLatin1String("t"))
readPlainStringPart(reader, richString);
}
}
int idx = m_stringList.size();
m_stringTable[richString] = XlsxSharedStringInfo(idx, 0);
m_stringList.append(richString);
}
void SharedStrings::readRichStringPart(XmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("r"));
QString text;
Format *format=0;
while (!(reader.name() == QLatin1String("r") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("rPr")) {
//:Todo
} else if (reader.name() == QLatin1String("t")) {
text = reader.readElementText();
}
}
}
richString.addFragment(text, format);
}
void SharedStrings::readPlainStringPart(XmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("t"));
//QXmlStreamAttributes attributes = reader.attributes();
QString text = reader.readElementText();
richString.addFragment(text, 0);
}
bool SharedStrings::loadFromXmlFile(QIODevice *device) bool SharedStrings::loadFromXmlFile(QIODevice *device)
{ {
XmlStreamReader reader(device); XmlStreamReader reader(device);
@ -157,15 +236,7 @@ bool SharedStrings::loadFromXmlFile(QIODevice *device)
QXmlStreamAttributes attributes = reader.attributes(); QXmlStreamAttributes attributes = reader.attributes();
count = attributes.value(QLatin1String("uniqueCount")).toString().toInt(); count = attributes.value(QLatin1String("uniqueCount")).toString().toInt();
} else if (reader.name() == QLatin1String("si")) { } else if (reader.name() == QLatin1String("si")) {
if (reader.readNextStartElement()) { readString(reader);
if (reader.name() == QLatin1String("t")) {
// QXmlStreamAttributes attributes = reader.attributes();
QString string = reader.readElementText();
int idx = m_stringList.size();
m_stringTable[string] = XlsxSharedStringInfo(idx, 0);
m_stringList.append(string);
}
}
} }
} }
} }

19
src/xlsx/xlsxsharedstrings_p.h

@ -26,6 +26,7 @@
#define XLSXSHAREDSTRINGS_H #define XLSXSHAREDSTRINGS_H
#include "xlsxglobal.h" #include "xlsxglobal.h"
#include "xlsxrichstring_p.h"
#include <QHash> #include <QHash>
#include <QStringList> #include <QStringList>
#include <QSharedPointer> #include <QSharedPointer>
@ -34,6 +35,9 @@ class QIODevice;
namespace QXlsx { namespace QXlsx {
class XmlStreamReader;
class RichString;
class XlsxSharedStringInfo class XlsxSharedStringInfo
{ {
public: public:
@ -53,12 +57,15 @@ public:
int count() const; int count() const;
int addSharedString(const QString &string); int addSharedString(const QString &string);
int addSharedString(const RichString &string);
void removeSharedString(const QString &string); void removeSharedString(const QString &string);
void removeSharedString(const RichString &string);
void incRefByStringIndex(int idx); void incRefByStringIndex(int idx);
int getSharedStringIndex(const QString &string) const; int getSharedStringIndex(const QString &string) const;
QString getSharedString(int index) const; int getSharedStringIndex(const RichString &string) const;
QStringList getSharedStrings() const; RichString getSharedString(int index) const;
QList<RichString> getSharedStrings() const;
void saveToXmlFile(QIODevice *device) const; void saveToXmlFile(QIODevice *device) const;
QByteArray saveToXmlData() const; QByteArray saveToXmlData() const;
@ -66,8 +73,12 @@ public:
bool loadFromXmlData(const QByteArray &data); bool loadFromXmlData(const QByteArray &data);
private: private:
QHash<QString, XlsxSharedStringInfo> m_stringTable; //for fast lookup void readString(XmlStreamReader &reader); // <si>
QStringList m_stringList; void readRichStringPart(XmlStreamReader &reader, RichString &rich); // <r>
void readPlainStringPart(XmlStreamReader &reader, RichString &rich); // <v>
QHash<RichString, XlsxSharedStringInfo> m_stringTable; //for fast lookup
QList<RichString> m_stringList;
int m_stringCount; int m_stringCount;
}; };

24
src/xlsx/xlsxworksheet.cpp

@ -22,6 +22,7 @@
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
** **
****************************************************************************/ ****************************************************************************/
#include "xlsxrichstring_p.h"
#include "xlsxworksheet.h" #include "xlsxworksheet.h"
#include "xlsxworksheet_p.h" #include "xlsxworksheet_p.h"
#include "xlsxworkbook.h" #include "xlsxworkbook.h"
@ -1163,7 +1164,21 @@ void WorksheetPrivate::writeCellData(XmlStreamWriter &writer, int row, int col,
} else if (cell->dataType() == Cell::InlineString) { } else if (cell->dataType() == Cell::InlineString) {
writer.writeAttribute(QStringLiteral("t"), QStringLiteral("inlineStr")); writer.writeAttribute(QStringLiteral("t"), QStringLiteral("inlineStr"));
writer.writeStartElement(QStringLiteral("is")); writer.writeStartElement(QStringLiteral("is"));
writer.writeTextElement(QStringLiteral("t"), cell->value().toString()); if (cell->isRichString()) {
//Rich text string
RichString string = cell->d_ptr->richString;
for (int i=0; i<string.fragmentCount(); ++i) {
writer.writeStartElement(QStringLiteral("rPr"));
//:Todo
writer.writeEndElement();// rPr
writer.writeStartElement(QStringLiteral("t"));
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(string.fragmentText(i));
writer.writeEndElement();// t
}
} else {
writer.writeTextElement(QStringLiteral("t"), cell->value().toString());
}
writer.writeEndElement();//is writer.writeEndElement();//is
} else if (cell->dataType() == Cell::Numeric){ } else if (cell->dataType() == Cell::Numeric){
double value = cell->value().toDouble(); double value = cell->value().toDouble();
@ -1874,8 +1889,10 @@ void WorksheetPrivate::readSheetData(XmlStreamReader &reader)
if (reader.name() == QLatin1String("v")) { if (reader.name() == QLatin1String("v")) {
int sst_idx = reader.readElementText().toInt(); int sst_idx = reader.readElementText().toInt();
sharedStrings()->incRefByStringIndex(sst_idx); sharedStrings()->incRefByStringIndex(sst_idx);
QString value = sharedStrings()->getSharedString(sst_idx); RichString rs = sharedStrings()->getSharedString(sst_idx);
QSharedPointer<Cell> data(new Cell(value ,Cell::String, format, q)); QSharedPointer<Cell> data(new Cell(rs.toPlainString() ,Cell::String, format, q));
if (rs.isRichString())
data->d_ptr->richString = rs;
cellTable[pos.x()][pos.y()] = QSharedPointer<Cell>(data); cellTable[pos.x()][pos.y()] = QSharedPointer<Cell>(data);
} }
} }
@ -1884,6 +1901,7 @@ void WorksheetPrivate::readSheetData(XmlStreamReader &reader)
while (!(reader.name() == QLatin1String("c") && reader.tokenType() == QXmlStreamReader::EndElement)) { while (!(reader.name() == QLatin1String("c") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement(); reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.tokenType() == QXmlStreamReader::StartElement) {
//:Todo, add rich text read support
if (reader.name() == QLatin1String("t")) { if (reader.name() == QLatin1String("t")) {
QString value = reader.readElementText(); QString value = reader.readElementText();
QSharedPointer<Cell> data(new Cell(value, Cell::InlineString, format, q)); QSharedPointer<Cell> data(new Cell(value, Cell::InlineString, format, q));

3
tests/auto/auto.pro

@ -9,4 +9,5 @@ SUBDIRS=\
document \ document \
sharedstrings \ sharedstrings \
styles \ styles \
format format \
richstring

12
tests/auto/richstring/richstring.pro

@ -0,0 +1,12 @@
QT += testlib xlsx xlsx-private
CONFIG += testcase
DEFINES += XLSX_TEST
TARGET = tst_richstringtest
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += tst_richstringtest.cpp
DEFINES += SRCDIR=\\\"$$PWD/\\\"

41
tests/auto/richstring/tst_richstringtest.cpp

@ -0,0 +1,41 @@
#include "private/xlsxrichstring_p.h"
#include <QtTest>
#include <QDebug>
class RichstringTest : public QObject
{
Q_OBJECT
public:
RichstringTest();
private Q_SLOTS:
void testEqual();
};
RichstringTest::RichstringTest()
{
}
void RichstringTest::testEqual()
{
QXlsx::RichString rs;
rs.addFragment("Hello", 0);
rs.addFragment(" RichText", 0);
QXlsx::RichString rs2;
rs2.addFragment("Hello", 0);
rs2.addFragment(" Qt!", 0);
QXlsx::RichString rs3;
rs3.addFragment("Hello", 0);
rs3.addFragment(" Qt!", 0);
QVERIFY2(rs2 != rs, "Failure");
QVERIFY2(rs2 == rs3, "Failure");
QVERIFY2(rs2 != QStringLiteral("Hello Qt!"), "Failure");
}
QTEST_APPLESS_MAIN(RichstringTest)
#include "tst_richstringtest.moc"

36
tests/auto/sharedstrings/tst_sharedstringstest.cpp

@ -1,4 +1,5 @@
#include "private/xlsxsharedstrings_p.h" #include "private/xlsxsharedstrings_p.h"
#include "private/xlsxrichstring_p.h"
#include <QString> #include <QString>
#include <QtTest> #include <QtTest>
#include <QXmlStreamReader> #include <QXmlStreamReader>
@ -27,6 +28,19 @@ void SharedStringsTest::testAddSharedString()
QXlsx::SharedStrings sst; QXlsx::SharedStrings sst;
sst.addSharedString("Hello Qt!"); sst.addSharedString("Hello Qt!");
sst.addSharedString("Xlsx Writer"); sst.addSharedString("Xlsx Writer");
QXlsx::RichString rs;
rs.addFragment("Hello", 0);
rs.addFragment(" RichText", 0);
sst.addSharedString(rs);
for (int i=0; i<3; ++i) {
QXlsx::RichString rs2;
rs2.addFragment("Hello", 0);
rs2.addFragment(" Qt!", 0);
sst.addSharedString(rs2);
}
sst.addSharedString("Hello World"); sst.addSharedString("Hello World");
sst.addSharedString("Hello Qt!"); sst.addSharedString("Hello Qt!");
@ -46,8 +60,8 @@ void SharedStringsTest::testAddSharedString()
} }
} }
QCOMPARE(count, 4); QCOMPARE(count, 8);
QCOMPARE(uniqueCount, 3); QCOMPARE(uniqueCount, 5);
} }
void SharedStringsTest::testRemoveSharedString() void SharedStringsTest::testRemoveSharedString()
@ -88,6 +102,17 @@ void SharedStringsTest::testLoadXmlData()
QXlsx::SharedStrings sst; QXlsx::SharedStrings sst;
sst.addSharedString("Hello Qt!"); sst.addSharedString("Hello Qt!");
sst.addSharedString("Xlsx Writer"); sst.addSharedString("Xlsx Writer");
QXlsx::RichString rs;
rs.addFragment("Hello", 0);
rs.addFragment(" RichText", 0);
sst.addSharedString(rs);
for (int i=0; i<3; ++i) {
QXlsx::RichString rs2;
rs2.addFragment("Hello", 0);
rs2.addFragment(" Qt!", 0);
sst.addSharedString(rs2);
}
sst.addSharedString("Hello World"); sst.addSharedString("Hello World");
sst.addSharedString("Hello Qt!"); sst.addSharedString("Hello Qt!");
QByteArray xmlData = sst.saveToXmlData(); QByteArray xmlData = sst.saveToXmlData();
@ -95,10 +120,11 @@ void SharedStringsTest::testLoadXmlData()
QSharedPointer<QXlsx::SharedStrings> sst2(new QXlsx::SharedStrings); QSharedPointer<QXlsx::SharedStrings> sst2(new QXlsx::SharedStrings);
sst2->loadFromXmlData(xmlData); sst2->loadFromXmlData(xmlData);
QCOMPARE(sst2->getSharedString(0), QStringLiteral("Hello Qt!")); QCOMPARE(sst2->getSharedString(0).toPlainString(), QStringLiteral("Hello Qt!"));
QCOMPARE(sst2->getSharedString(2), QStringLiteral("Hello World")); QCOMPARE(sst2->getSharedString(2), rs);
QCOMPARE(sst2->getSharedString(4).toPlainString(), QStringLiteral("Hello World"));
QCOMPARE(sst2->getSharedStringIndex("Hello Qt!"), 0); QCOMPARE(sst2->getSharedStringIndex("Hello Qt!"), 0);
QCOMPARE(sst2->getSharedStringIndex("Hello World"), 2); QCOMPARE(sst2->getSharedStringIndex("Hello World"), 4);
} }
QTEST_APPLESS_MAIN(SharedStringsTest) QTEST_APPLESS_MAIN(SharedStringsTest)

13
tests/auto/worksheet/tst_worksheet.cpp

@ -8,6 +8,7 @@
#include "private/xlsxworksheet_p.h" #include "private/xlsxworksheet_p.h"
#include "private/xlsxxmlreader_p.h" #include "private/xlsxxmlreader_p.h"
#include "private/xlsxsharedstrings_p.h" #include "private/xlsxsharedstrings_p.h"
#include "private/xlsxrichstring_p.h"
class WorksheetTest : public QObject class WorksheetTest : public QObject
{ {
@ -116,7 +117,7 @@ void WorksheetTest::testWriteCells()
QVERIFY2(xmldata.contains("<c r=\"A5\" t=\"str\"><f>44+33</f><v>0</v></c>"), "formula"); QVERIFY2(xmldata.contains("<c r=\"A5\" t=\"str\"><f>44+33</f><v>0</v></c>"), "formula");
QVERIFY2(xmldata.contains("<c r=\"B5\" t=\"str\"><f>44+33</f><v>77</v></c>"), "formula"); QVERIFY2(xmldata.contains("<c r=\"B5\" t=\"str\"><f>44+33</f><v>77</v></c>"), "formula");
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(0), QStringLiteral("Hello")); QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(0).toPlainString(), QStringLiteral("Hello"));
} }
void WorksheetTest::testWriteHyperlinks() void WorksheetTest::testWriteHyperlinks()
@ -136,11 +137,11 @@ void WorksheetTest::testWriteHyperlinks()
QVERIFY2(xmldata.contains("<hyperlink ref=\"D1\" r:id=\"rId4\"/>"), "mail"); QVERIFY2(xmldata.contains("<hyperlink ref=\"D1\" r:id=\"rId4\"/>"), "mail");
QVERIFY2(xmldata.contains("<hyperlink ref=\"E1\" r:id=\"rId5\"/>"), "mail with subject"); QVERIFY2(xmldata.contains("<hyperlink ref=\"E1\" r:id=\"rId5\"/>"), "mail with subject");
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(0), QStringLiteral("http://qt-project.org")); QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(0).toPlainString(), QStringLiteral("http://qt-project.org"));
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(1), QStringLiteral("http://qt-project.org/abc")); QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(1).toPlainString(), QStringLiteral("http://qt-project.org/abc"));
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(2), QStringLiteral("http://qt-project.org/abc.html#test")); QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(2).toPlainString(), QStringLiteral("http://qt-project.org/abc.html#test"));
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(3), QStringLiteral("xyz@debao.me")); QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(3).toPlainString(), QStringLiteral("xyz@debao.me"));
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(4), QStringLiteral("xyz@debao.me?subject=Test")); QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(4).toPlainString(), QStringLiteral("xyz@debao.me?subject=Test"));
} }
void WorksheetTest::testWriteDataValidations() void WorksheetTest::testWriteDataValidations()

Loading…
Cancel
Save