Browse Source

Don't lost rich text information

master
Debao Zhang 11 years ago
parent
commit
04934a8543
  1. 2
      src/xlsx/xlsxformat.h
  2. 11
      src/xlsx/xlsxrichstring.cpp
  3. 3
      src/xlsx/xlsxrichstring_p.h
  4. 136
      src/xlsx/xlsxsharedstrings.cpp
  5. 3
      src/xlsx/xlsxsharedstrings_p.h
  6. 11
      src/xlsx/xlsxworksheet.cpp
  7. 33
      tests/auto/sharedstrings/tst_sharedstringstest.cpp

2
src/xlsx/xlsxformat.h

@ -39,6 +39,7 @@ class Styles;
class Worksheet; class Worksheet;
class WorksheetPrivate; class WorksheetPrivate;
class RichString; class RichString;
class SharedStrings;
class FormatPrivate; class FormatPrivate;
class Q_XLSX_EXPORT Format class Q_XLSX_EXPORT Format
@ -216,6 +217,7 @@ private:
friend class Worksheet; friend class Worksheet;
friend class WorksheetPrivate; friend class WorksheetPrivate;
friend class RichString; friend class RichString;
friend class SharedStrings;
friend class ::FormatTest; friend class ::FormatTest;
Format(); Format();

11
src/xlsx/xlsxrichstring.cpp

@ -87,6 +87,17 @@ Format *RichString::fragmentFormat(int index) const
return m_fragmentFormats[index]; return m_fragmentFormats[index];
} }
/*!
* \internal
*/
Format *RichString::createFormat()
{
Format *format = new Format();
m_createdFormats.append(QSharedPointer<Format>(format));
return format;
}
/*! /*!
* \internal * \internal
*/ */

3
src/xlsx/xlsxrichstring_p.h

@ -28,6 +28,7 @@
#include "xlsxglobal.h" #include "xlsxglobal.h"
#include "xlsxformat.h" #include "xlsxformat.h"
#include <QStringList> #include <QStringList>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE_XLSX QT_BEGIN_NAMESPACE_XLSX
@ -49,6 +50,7 @@ public:
QString fragmentText(int index) const; QString fragmentText(int index) const;
Format *fragmentFormat(int index) const; Format *fragmentFormat(int index) const;
Format *createFormat();
private: private:
friend XLSX_AUTOTEST_EXPORT uint qHash(const RichString &rs, uint seed) Q_DECL_NOTHROW; 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);
@ -61,6 +63,7 @@ private:
QList<Format *> m_fragmentFormats; QList<Format *> m_fragmentFormats;
QByteArray m_idKey; QByteArray m_idKey;
bool m_dirty; bool m_dirty;
QList<QSharedPointer<Format> > m_createdFormats;
}; };

136
src/xlsx/xlsxsharedstrings.cpp

@ -26,6 +26,8 @@
#include "xlsxsharedstrings_p.h" #include "xlsxsharedstrings_p.h"
#include "xlsxxmlwriter_p.h" #include "xlsxxmlwriter_p.h"
#include "xlsxxmlreader_p.h" #include "xlsxxmlreader_p.h"
#include "xlsxutility_p.h"
#include "xlsxformat_p.h"
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QRegularExpression> #include <QRegularExpression>
@ -123,6 +125,65 @@ QList<RichString> SharedStrings::getSharedStrings() const
return m_stringList; return m_stringList;
} }
void SharedStrings::writeRichStringPart_rPr(XmlStreamWriter &writer, Format *format) const
{
if (!format)
return;
FontData *font = &format->d_ptr->fontData;
if (font->bold)
writer.writeEmptyElement(QStringLiteral("b"));
if (font->italic)
writer.writeEmptyElement(QStringLiteral("i"));
if (font->strikeOut)
writer.writeEmptyElement(QStringLiteral("strike"));
if (font->outline)
writer.writeEmptyElement(QStringLiteral("outline"));
if (font->shadow)
writer.writeEmptyElement(QStringLiteral("shadow"));
if (font->underline != Format::FontUnderlineNone) {
writer.writeEmptyElement(QStringLiteral("u"));
if (font->underline == Format::FontUnderlineDouble)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double"));
else if (font->underline == Format::FontUnderlineSingleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting"));
else if (font->underline == Format::FontUnderlineDoubleAccounting)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting"));
}
if (font->scirpt != Format::FontScriptNormal) {
writer.writeEmptyElement(QStringLiteral("vertAlign"));
if (font->scirpt == Format::FontScriptSuper)
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript"));
else
writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript"));
}
writer.writeEmptyElement(QStringLiteral("sz"));
writer.writeAttribute(QStringLiteral("val"), QString::number(font->size));
if (font->color.isValid()) {
writer.writeEmptyElement(QStringLiteral("color"));
QString color = font->color.name();
writer.writeAttribute(QStringLiteral("rgb"), QStringLiteral("FF")+color.mid(1));//remove #
} else if (!font->themeColor.isEmpty()) {
writer.writeEmptyElement(QStringLiteral("color"));
QStringList themes = font->themeColor.split(QLatin1Char(':'));
writer.writeAttribute(QStringLiteral("theme"), themes[0]);
if (!themes[1].isEmpty())
writer.writeAttribute(QStringLiteral("tint"), themes[1]);
}
writer.writeEmptyElement(QStringLiteral("rFont"));
writer.writeAttribute(QStringLiteral("val"), font->name);
writer.writeEmptyElement(QStringLiteral("family"));
writer.writeAttribute(QStringLiteral("val"), QString::number(font->family));
if (font->name == QLatin1String("Calibri")) {
writer.writeEmptyElement(QStringLiteral("scheme"));
writer.writeAttribute(QStringLiteral("val"), font->scheme);
}
}
void SharedStrings::saveToXmlFile(QIODevice *device) const void SharedStrings::saveToXmlFile(QIODevice *device) const
{ {
XmlStreamWriter writer(device); XmlStreamWriter writer(device);
@ -138,15 +199,21 @@ void SharedStrings::saveToXmlFile(QIODevice *device) const
if (string.isRichString()) { if (string.isRichString()) {
//Rich text string //Rich text string
for (int i=0; i<string.fragmentCount(); ++i) { for (int i=0; i<string.fragmentCount(); ++i) {
writer.writeStartElement(QStringLiteral("r"));
if (string.fragmentFormat(i)) { if (string.fragmentFormat(i)) {
writer.writeStartElement(QStringLiteral("rPr")); writer.writeStartElement(QStringLiteral("rPr"));
//:Todo writeRichStringPart_rPr(writer, string.fragmentFormat(i));
writer.writeEndElement();// rPr writer.writeEndElement();// rPr
} }
writer.writeStartElement(QStringLiteral("t")); writer.writeStartElement(QStringLiteral("t"));
if (string.fragmentText(i).contains(QRegularExpression(QStringLiteral("^\\s")))
|| string.fragmentText(i).contains(QRegularExpression(QStringLiteral("\\s$")))) {
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve")); writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
}
writer.writeCharacters(string.fragmentText(i)); writer.writeCharacters(string.fragmentText(i));
writer.writeEndElement();// t writer.writeEndElement();// t
writer.writeEndElement(); //r
} }
} else { } else {
writer.writeStartElement(QStringLiteral("t")); writer.writeStartElement(QStringLiteral("t"));
@ -206,7 +273,7 @@ void SharedStrings::readRichStringPart(XmlStreamReader &reader, RichString &rich
reader.readNextStartElement(); reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.tokenType() == QXmlStreamReader::StartElement) {
if (reader.name() == QLatin1String("rPr")) { if (reader.name() == QLatin1String("rPr")) {
//:Todo format = readRichStringPart_rPr(reader, richString);
} else if (reader.name() == QLatin1String("t")) { } else if (reader.name() == QLatin1String("t")) {
text = reader.readElementText(); text = reader.readElementText();
} }
@ -225,6 +292,71 @@ void SharedStrings::readPlainStringPart(XmlStreamReader &reader, RichString &ric
richString.addFragment(text, 0); richString.addFragment(text, 0);
} }
Format *SharedStrings::readRichStringPart_rPr(XmlStreamReader &reader, RichString &richString)
{
Q_ASSERT(reader.name() == QLatin1String("rPr"));
Format *format = richString.createFormat();
while (!(reader.name() == QLatin1String("rPr") && reader.tokenType() == QXmlStreamReader::EndElement)) {
reader.readNextStartElement();
if (reader.tokenType() == QXmlStreamReader::StartElement) {
QXmlStreamAttributes attributes = reader.attributes();
if (reader.name() == QLatin1String("rFont")) {
format->setFontName(attributes.value(QLatin1String("val")).toString());
} else if (reader.name() == QLatin1String("charset")) {
format->d_ptr->fontData.charset = attributes.value(QLatin1String("val")).toString().toInt();
} else if (reader.name() == QLatin1String("family")) {
format->d_ptr->fontData.family = attributes.value(QLatin1String("val")).toString().toInt();
} else if (reader.name() == QLatin1String("b")) {
format->setFontBold(true);
} else if (reader.name() == QLatin1String("i")) {
format->setFontItalic(true);
} else if (reader.name() == QLatin1String("strike")) {
format->setFontStrikeOut(true);
} else if (reader.name() == QLatin1String("outline")) {
format->setFontOutline(true);
} else if (reader.name() == QLatin1String("shadow")) {
format->d_ptr->fontData.shadow = true;
} else if (reader.name() == QLatin1String("condense")) {
format->d_ptr->fontData.condense = attributes.value(QLatin1String("val")).toString().toInt();
} else if (reader.name() == QLatin1String("extend")) {
format->d_ptr->fontData.extend = attributes.value(QLatin1String("val")).toString().toInt();
} else if (reader.name() == QLatin1String("color")) {
if (attributes.hasAttribute(QLatin1String("rgb"))) {
QString colorString = attributes.value(QLatin1String("rgb")).toString();
format->setFontColor(fromARGBString(colorString));
} else if (attributes.hasAttribute(QLatin1String("indexed"))) {
// color = getColorByIndex(attributes.value(QLatin1String("indexed")).toString().toInt());
} else if (attributes.hasAttribute(QLatin1String("theme"))) {
QString theme = attributes.value(QLatin1String("theme")).toString();
QString tint = attributes.value(QLatin1String("tint")).toString();
format->d_ptr->fontData.themeColor = theme + QLatin1Char(':') + tint;
}
} else if (reader.name() == QLatin1String("sz")) {
format->setFontSize(attributes.value(QLatin1String("val")).toString().toInt());
} else if (reader.name() == QLatin1String("u")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("double"))
format->setFontUnderline(Format::FontUnderlineDouble);
else if (value == QLatin1String("doubleAccounting"))
format->setFontUnderline(Format::FontUnderlineDoubleAccounting);
else if (value == QLatin1String("singleAccounting"))
format->setFontUnderline(Format::FontUnderlineSingleAccounting);
else
format->setFontUnderline(Format::FontUnderlineSingle);
} else if (reader.name() == QLatin1String("vertAlign")) {
QString value = attributes.value(QLatin1String("val")).toString();
if (value == QLatin1String("superscript"))
format->setFontScript(Format::FontScriptSuper);
else if (value == QLatin1String("subscript"))
format->setFontScript(Format::FontScriptSub);
} else if (reader.name() == QLatin1String("scheme")) {
format->d_ptr->fontData.scheme = attributes.value(QLatin1String("val")).toString();
}
}
}
return format;
}
bool SharedStrings::loadFromXmlFile(QIODevice *device) bool SharedStrings::loadFromXmlFile(QIODevice *device)
{ {
XmlStreamReader reader(device); XmlStreamReader reader(device);

3
src/xlsx/xlsxsharedstrings_p.h

@ -36,6 +36,7 @@ class QIODevice;
namespace QXlsx { namespace QXlsx {
class XmlStreamReader; class XmlStreamReader;
class XmlStreamWriter;
class RichString; class RichString;
class XlsxSharedStringInfo class XlsxSharedStringInfo
@ -76,6 +77,8 @@ private:
void readString(XmlStreamReader &reader); // <si> void readString(XmlStreamReader &reader); // <si>
void readRichStringPart(XmlStreamReader &reader, RichString &rich); // <r> void readRichStringPart(XmlStreamReader &reader, RichString &rich); // <r>
void readPlainStringPart(XmlStreamReader &reader, RichString &rich); // <v> void readPlainStringPart(XmlStreamReader &reader, RichString &rich); // <v>
Format *readRichStringPart_rPr(XmlStreamReader &reader, RichString &richString);
void writeRichStringPart_rPr(XmlStreamWriter &writer, Format *format) const;
QHash<RichString, XlsxSharedStringInfo> m_stringTable; //for fast lookup QHash<RichString, XlsxSharedStringInfo> m_stringTable; //for fast lookup
QList<RichString> m_stringList; QList<RichString> m_stringList;

11
src/xlsx/xlsxworksheet.cpp

@ -1158,7 +1158,12 @@ void WorksheetPrivate::writeCellData(XmlStreamWriter &writer, int row, int col,
writer.writeAttribute(QStringLiteral("s"), QString::number(colsInfoHelper[col]->format->xfIndex())); writer.writeAttribute(QStringLiteral("s"), QString::number(colsInfoHelper[col]->format->xfIndex()));
if (cell->dataType() == Cell::String) { if (cell->dataType() == Cell::String) {
int sst_idx = sharedStrings()->getSharedStringIndex(cell->value().toString()); int sst_idx;
if (cell->isRichString())
sst_idx = sharedStrings()->getSharedStringIndex(cell->d_ptr->richString);
else
sst_idx = sharedStrings()->getSharedStringIndex(cell->value().toString());
writer.writeAttribute(QStringLiteral("t"), QStringLiteral("s")); writer.writeAttribute(QStringLiteral("t"), QStringLiteral("s"));
writer.writeTextElement(QStringLiteral("v"), QString::number(sst_idx)); writer.writeTextElement(QStringLiteral("v"), QString::number(sst_idx));
} else if (cell->dataType() == Cell::InlineString) { } else if (cell->dataType() == Cell::InlineString) {
@ -1168,13 +1173,17 @@ void WorksheetPrivate::writeCellData(XmlStreamWriter &writer, int row, int col,
//Rich text string //Rich text string
RichString string = cell->d_ptr->richString; RichString string = cell->d_ptr->richString;
for (int i=0; i<string.fragmentCount(); ++i) { for (int i=0; i<string.fragmentCount(); ++i) {
writer.writeStartElement(QStringLiteral("r"));
if (string.fragmentFormat(i)) {
writer.writeStartElement(QStringLiteral("rPr")); writer.writeStartElement(QStringLiteral("rPr"));
//:Todo //:Todo
writer.writeEndElement();// rPr writer.writeEndElement();// rPr
}
writer.writeStartElement(QStringLiteral("t")); writer.writeStartElement(QStringLiteral("t"));
writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve")); writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
writer.writeCharacters(string.fragmentText(i)); writer.writeCharacters(string.fragmentText(i));
writer.writeEndElement();// t writer.writeEndElement();// t
writer.writeEndElement(); // r
} }
} else { } else {
writer.writeTextElement(QStringLiteral("t"), cell->value().toString()); writer.writeTextElement(QStringLiteral("t"), cell->value().toString());

33
tests/auto/sharedstrings/tst_sharedstringstest.cpp

@ -1,5 +1,6 @@
#include "private/xlsxsharedstrings_p.h" #include "private/xlsxsharedstrings_p.h"
#include "private/xlsxrichstring_p.h" #include "private/xlsxrichstring_p.h"
#include "xlsxformat.h"
#include <QString> #include <QString>
#include <QtTest> #include <QtTest>
#include <QXmlStreamReader> #include <QXmlStreamReader>
@ -16,6 +17,7 @@ private Q_SLOTS:
void testRemoveSharedString(); void testRemoveSharedString();
void testLoadXmlData(); void testLoadXmlData();
void testLoadRichStringXmlData();
}; };
@ -127,6 +129,37 @@ void SharedStringsTest::testLoadXmlData()
QCOMPARE(sst2->getSharedStringIndex("Hello World"), 4); QCOMPARE(sst2->getSharedStringIndex("Hello World"), 4);
} }
void SharedStringsTest::testLoadRichStringXmlData()
{
QByteArray xmlData = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
"<sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"1\" uniqueCount=\"1\">"
"<si>"
"<r><t>e=mc</t></r>"
"<r>"
"<rPr><vertAlign val=\"superscript\"/>"
"<sz val=\"11\"/>"
"<rFont val=\"MyFontName\"/>"
"<family val=\"3\"/>"
"<charset val=\"134\"/>"
"<scheme val=\"minor\"/>"
"</rPr>"
"<t>2</t></r>"
"</si>"
"</sst>";
QSharedPointer<QXlsx::SharedStrings> sst(new QXlsx::SharedStrings);
sst->loadFromXmlData(xmlData);
QXlsx::RichString rs = sst->getSharedString(0);
QVERIFY(rs.fragmentText(0) == "e=mc");
QVERIFY(rs.fragmentText(1) == "2");
QVERIFY(rs.fragmentFormat(0) == 0);
QXlsx::Format *format = rs.fragmentFormat(1);
QCOMPARE(format->fontName(), QString("MyFontName"));
// QCOMPARE(format->fontFamily(), 3);
QCOMPARE(format->fontScript(), QXlsx::Format::FontScriptSuper);
QCOMPARE(format->fontSize(), 11);
}
QTEST_APPLESS_MAIN(SharedStringsTest) QTEST_APPLESS_MAIN(SharedStringsTest)
#include "tst_sharedstringstest.moc" #include "tst_sharedstringstest.moc"

Loading…
Cancel
Save