Fix Issue 7: Cell string misplacement when rich text exist
A private class RichString has been added. More work is needed
This commit is contained in:
+4
-2
@@ -31,7 +31,8 @@ HEADERS += $$PWD/xlsxdocpropscore_p.h \
|
||||
$$PWD/xlsxcell_p.h \
|
||||
$$PWD/xlsxdatavalidation.h \
|
||||
$$PWD/xlsxdatavalidation_p.h \
|
||||
$$PWD/xlsxcellrange.h
|
||||
$$PWD/xlsxcellrange.h \
|
||||
$$PWD/xlsxrichstring_p.h
|
||||
|
||||
SOURCES += $$PWD/xlsxdocpropscore.cpp \
|
||||
$$PWD/xlsxdocpropsapp.cpp \
|
||||
@@ -53,4 +54,5 @@ SOURCES += $$PWD/xlsxdocpropscore.cpp \
|
||||
$$PWD/xlsxdocument.cpp \
|
||||
$$PWD/xlsxcell.cpp \
|
||||
$$PWD/xlsxdatavalidation.cpp \
|
||||
$$PWD/xlsxcellrange.cpp
|
||||
$$PWD/xlsxcellrange.cpp \
|
||||
$$PWD/xlsxrichstring.cpp
|
||||
|
||||
@@ -121,4 +121,16 @@ QDateTime Cell::dateTime() const
|
||||
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
|
||||
|
||||
@@ -58,6 +58,8 @@ public:
|
||||
bool isDateTime() const;
|
||||
QDateTime dateTime() const;
|
||||
|
||||
bool isRichString() const;
|
||||
|
||||
~Cell();
|
||||
private:
|
||||
friend class Worksheet;
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#include "xlsxglobal.h"
|
||||
#include "xlsxcell.h"
|
||||
#include "xlsxcellrange.h"
|
||||
#include "xlsxrichstring_p.h"
|
||||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE_XLSX
|
||||
|
||||
@@ -43,6 +46,8 @@ public:
|
||||
Format *format;
|
||||
CellRange range; //used for arrayFormula
|
||||
|
||||
RichString richString;
|
||||
|
||||
Worksheet *parent;
|
||||
Cell *q_ptr;
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@ QT_BEGIN_NAMESPACE_XLSX
|
||||
class Styles;
|
||||
class Worksheet;
|
||||
class WorksheetPrivate;
|
||||
class RichString;
|
||||
|
||||
class FormatPrivate;
|
||||
class Q_XLSX_EXPORT Format
|
||||
@@ -214,6 +215,7 @@ private:
|
||||
friend class Styles;
|
||||
friend class Worksheet;
|
||||
friend class WorksheetPrivate;
|
||||
friend class RichString;
|
||||
friend class ::FormatTest;
|
||||
|
||||
Format();
|
||||
|
||||
@@ -160,8 +160,7 @@ bool Package::parsePackage(QIODevice *packageDevice)
|
||||
//In normal case this should be sharedStrings.xml which in xl
|
||||
QString name = rels_sharedStrings[0].target;
|
||||
QString path = xlworkbook_Dir + QLatin1String("/") + name;
|
||||
QSharedPointer<SharedStrings> sst= SharedStrings::loadFromXmlData(zipReader.fileData(path));
|
||||
m_document->workbook()->d_ptr->sharedStrings = sst;
|
||||
m_document->workbook()->d_ptr->sharedStrings->loadFromXmlData(zipReader.fileData(path));
|
||||
}
|
||||
|
||||
//load theme
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -22,6 +22,7 @@
|
||||
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "xlsxrichstring_p.h"
|
||||
#include "xlsxsharedstrings_p.h"
|
||||
#include "xlsxxmlwriter_p.h"
|
||||
#include "xlsxxmlreader_p.h"
|
||||
@@ -44,6 +45,11 @@ int SharedStrings::count() const
|
||||
}
|
||||
|
||||
int SharedStrings::addSharedString(const QString &string)
|
||||
{
|
||||
return addSharedString(RichString(string));
|
||||
}
|
||||
|
||||
int SharedStrings::addSharedString(const RichString &string)
|
||||
{
|
||||
m_stringCount += 1;
|
||||
|
||||
@@ -70,6 +76,11 @@ void SharedStrings::incRefByStringIndex(int idx)
|
||||
}
|
||||
|
||||
void SharedStrings::removeSharedString(const QString &string)
|
||||
{
|
||||
removeSharedString(RichString(string));
|
||||
}
|
||||
|
||||
void SharedStrings::removeSharedString(const RichString &string)
|
||||
{
|
||||
if (!m_stringTable.contains(string))
|
||||
return;
|
||||
@@ -89,20 +100,25 @@ void SharedStrings::removeSharedString(const QString &string)
|
||||
}
|
||||
|
||||
int SharedStrings::getSharedStringIndex(const QString &string) const
|
||||
{
|
||||
return getSharedStringIndex(RichString(string));
|
||||
}
|
||||
|
||||
int SharedStrings::getSharedStringIndex(const RichString &string) const
|
||||
{
|
||||
if (m_stringTable.contains(string))
|
||||
return m_stringTable[string].index;
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString SharedStrings::getSharedString(int index) const
|
||||
RichString SharedStrings::getSharedString(int index) const
|
||||
{
|
||||
if (index < m_stringList.count() && index >= 0)
|
||||
return m_stringList[index];
|
||||
return QString();
|
||||
return RichString();
|
||||
}
|
||||
|
||||
QStringList SharedStrings::getSharedStrings() const
|
||||
QList<RichString> SharedStrings::getSharedStrings() const
|
||||
{
|
||||
return m_stringList;
|
||||
}
|
||||
@@ -117,16 +133,29 @@ void SharedStrings::saveToXmlFile(QIODevice *device) const
|
||||
writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount));
|
||||
writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringTable.size()));
|
||||
|
||||
foreach (QString string, m_stringList) {
|
||||
foreach (RichString string, m_stringList) {
|
||||
writer.writeStartElement(QStringLiteral("si"));
|
||||
if (string.contains(QRegularExpression(QStringLiteral("^<r>"))) || string.contains(QRegularExpression(QStringLiteral("</r>$")))) {
|
||||
//Rich text string,
|
||||
// writer.writeCharacters(string);
|
||||
if (string.isRichString()) {
|
||||
//Rich text 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 {
|
||||
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.writeCharacters(string);
|
||||
}
|
||||
writer.writeCharacters(pString);
|
||||
writer.writeEndElement();//t
|
||||
}
|
||||
writer.writeEndElement();//si
|
||||
@@ -146,6 +175,56 @@ QByteArray SharedStrings::saveToXmlData() const
|
||||
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)
|
||||
{
|
||||
XmlStreamReader reader(device);
|
||||
@@ -157,15 +236,7 @@ bool SharedStrings::loadFromXmlFile(QIODevice *device)
|
||||
QXmlStreamAttributes attributes = reader.attributes();
|
||||
count = attributes.value(QLatin1String("uniqueCount")).toString().toInt();
|
||||
} else if (reader.name() == QLatin1String("si")) {
|
||||
if (reader.readNextStartElement()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
readString(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define XLSXSHAREDSTRINGS_H
|
||||
|
||||
#include "xlsxglobal.h"
|
||||
#include "xlsxrichstring_p.h"
|
||||
#include <QHash>
|
||||
#include <QStringList>
|
||||
#include <QSharedPointer>
|
||||
@@ -34,6 +35,9 @@ class QIODevice;
|
||||
|
||||
namespace QXlsx {
|
||||
|
||||
class XmlStreamReader;
|
||||
class RichString;
|
||||
|
||||
class XlsxSharedStringInfo
|
||||
{
|
||||
public:
|
||||
@@ -53,12 +57,15 @@ public:
|
||||
int count() const;
|
||||
|
||||
int addSharedString(const QString &string);
|
||||
int addSharedString(const RichString &string);
|
||||
void removeSharedString(const QString &string);
|
||||
void removeSharedString(const RichString &string);
|
||||
void incRefByStringIndex(int idx);
|
||||
|
||||
int getSharedStringIndex(const QString &string) const;
|
||||
QString getSharedString(int index) const;
|
||||
QStringList getSharedStrings() const;
|
||||
int getSharedStringIndex(const RichString &string) const;
|
||||
RichString getSharedString(int index) const;
|
||||
QList<RichString> getSharedStrings() const;
|
||||
|
||||
void saveToXmlFile(QIODevice *device) const;
|
||||
QByteArray saveToXmlData() const;
|
||||
@@ -66,8 +73,12 @@ public:
|
||||
bool loadFromXmlData(const QByteArray &data);
|
||||
|
||||
private:
|
||||
QHash<QString, XlsxSharedStringInfo> m_stringTable; //for fast lookup
|
||||
QStringList m_stringList;
|
||||
void readString(XmlStreamReader &reader); // <si>
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "xlsxrichstring_p.h"
|
||||
#include "xlsxworksheet.h"
|
||||
#include "xlsxworksheet_p.h"
|
||||
#include "xlsxworkbook.h"
|
||||
@@ -1163,7 +1164,21 @@ void WorksheetPrivate::writeCellData(XmlStreamWriter &writer, int row, int col,
|
||||
} else if (cell->dataType() == Cell::InlineString) {
|
||||
writer.writeAttribute(QStringLiteral("t"), QStringLiteral("inlineStr"));
|
||||
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
|
||||
} else if (cell->dataType() == Cell::Numeric){
|
||||
double value = cell->value().toDouble();
|
||||
@@ -1874,8 +1889,10 @@ void WorksheetPrivate::readSheetData(XmlStreamReader &reader)
|
||||
if (reader.name() == QLatin1String("v")) {
|
||||
int sst_idx = reader.readElementText().toInt();
|
||||
sharedStrings()->incRefByStringIndex(sst_idx);
|
||||
QString value = sharedStrings()->getSharedString(sst_idx);
|
||||
QSharedPointer<Cell> data(new Cell(value ,Cell::String, format, q));
|
||||
RichString rs = sharedStrings()->getSharedString(sst_idx);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1884,6 +1901,7 @@ void WorksheetPrivate::readSheetData(XmlStreamReader &reader)
|
||||
while (!(reader.name() == QLatin1String("c") && reader.tokenType() == QXmlStreamReader::EndElement)) {
|
||||
reader.readNextStartElement();
|
||||
if (reader.tokenType() == QXmlStreamReader::StartElement) {
|
||||
//:Todo, add rich text read support
|
||||
if (reader.name() == QLatin1String("t")) {
|
||||
QString value = reader.readElementText();
|
||||
QSharedPointer<Cell> data(new Cell(value, Cell::InlineString, format, q));
|
||||
|
||||
+2
-1
@@ -9,4 +9,5 @@ SUBDIRS=\
|
||||
document \
|
||||
sharedstrings \
|
||||
styles \
|
||||
format
|
||||
format \
|
||||
richstring
|
||||
|
||||
@@ -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/\\\"
|
||||
@@ -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"
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "private/xlsxsharedstrings_p.h"
|
||||
#include "private/xlsxrichstring_p.h"
|
||||
#include <QString>
|
||||
#include <QtTest>
|
||||
#include <QXmlStreamReader>
|
||||
@@ -27,6 +28,19 @@ void SharedStringsTest::testAddSharedString()
|
||||
QXlsx::SharedStrings sst;
|
||||
sst.addSharedString("Hello Qt!");
|
||||
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 Qt!");
|
||||
|
||||
@@ -46,8 +60,8 @@ void SharedStringsTest::testAddSharedString()
|
||||
}
|
||||
}
|
||||
|
||||
QCOMPARE(count, 4);
|
||||
QCOMPARE(uniqueCount, 3);
|
||||
QCOMPARE(count, 8);
|
||||
QCOMPARE(uniqueCount, 5);
|
||||
}
|
||||
|
||||
void SharedStringsTest::testRemoveSharedString()
|
||||
@@ -88,6 +102,17 @@ void SharedStringsTest::testLoadXmlData()
|
||||
QXlsx::SharedStrings sst;
|
||||
sst.addSharedString("Hello Qt!");
|
||||
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 Qt!");
|
||||
QByteArray xmlData = sst.saveToXmlData();
|
||||
@@ -95,10 +120,11 @@ void SharedStringsTest::testLoadXmlData()
|
||||
QSharedPointer<QXlsx::SharedStrings> sst2(new QXlsx::SharedStrings);
|
||||
sst2->loadFromXmlData(xmlData);
|
||||
|
||||
QCOMPARE(sst2->getSharedString(0), QStringLiteral("Hello Qt!"));
|
||||
QCOMPARE(sst2->getSharedString(2), QStringLiteral("Hello World"));
|
||||
QCOMPARE(sst2->getSharedString(0).toPlainString(), QStringLiteral("Hello Qt!"));
|
||||
QCOMPARE(sst2->getSharedString(2), rs);
|
||||
QCOMPARE(sst2->getSharedString(4).toPlainString(), QStringLiteral("Hello World"));
|
||||
QCOMPARE(sst2->getSharedStringIndex("Hello Qt!"), 0);
|
||||
QCOMPARE(sst2->getSharedStringIndex("Hello World"), 2);
|
||||
QCOMPARE(sst2->getSharedStringIndex("Hello World"), 4);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(SharedStringsTest)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "private/xlsxworksheet_p.h"
|
||||
#include "private/xlsxxmlreader_p.h"
|
||||
#include "private/xlsxsharedstrings_p.h"
|
||||
#include "private/xlsxrichstring_p.h"
|
||||
|
||||
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=\"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()
|
||||
@@ -136,11 +137,11 @@ void WorksheetTest::testWriteHyperlinks()
|
||||
QVERIFY2(xmldata.contains("<hyperlink ref=\"D1\" r:id=\"rId4\"/>"), "mail");
|
||||
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(1), 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(3), QStringLiteral("xyz@debao.me"));
|
||||
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(4), QStringLiteral("xyz@debao.me?subject=Test"));
|
||||
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(0).toPlainString(), QStringLiteral("http://qt-project.org"));
|
||||
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(1).toPlainString(), QStringLiteral("http://qt-project.org/abc"));
|
||||
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(2).toPlainString(), QStringLiteral("http://qt-project.org/abc.html#test"));
|
||||
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(3).toPlainString(), QStringLiteral("xyz@debao.me"));
|
||||
QCOMPARE(sheet.d_ptr->sharedStrings()->getSharedString(4).toPlainString(), QStringLiteral("xyz@debao.me?subject=Test"));
|
||||
}
|
||||
|
||||
void WorksheetTest::testWriteDataValidations()
|
||||
|
||||
Reference in New Issue
Block a user