comparison src/xlsx/xlsxsharedstrings.cpp @ 1:93d3106bb9a4

Add qt xlsx library
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 22 Mar 2016 10:38:08 +0100
parents
children
comparison
equal deleted inserted replaced
0:49cd5cc0b072 1:93d3106bb9a4
1 /****************************************************************************
2 ** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me>
3 ** All right reserved.
4 **
5 ** Permission is hereby granted, free of charge, to any person obtaining
6 ** a copy of this software and associated documentation files (the
7 ** "Software"), to deal in the Software without restriction, including
8 ** without limitation the rights to use, copy, modify, merge, publish,
9 ** distribute, sublicense, and/or sell copies of the Software, and to
10 ** permit persons to whom the Software is furnished to do so, subject to
11 ** the following conditions:
12 **
13 ** The above copyright notice and this permission notice shall be
14 ** included in all copies or substantial portions of the Software.
15 **
16 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 **
24 ****************************************************************************/
25 #include "xlsxrichstring.h"
26 #include "xlsxsharedstrings_p.h"
27 #include "xlsxutility_p.h"
28 #include "xlsxformat_p.h"
29 #include "xlsxcolor_p.h"
30 #include <QXmlStreamWriter>
31 #include <QXmlStreamReader>
32 #include <QDir>
33 #include <QFile>
34 #include <QDebug>
35 #include <QBuffer>
36
37 namespace QXlsx {
38
39 /*
40 * Note that, when we open an existing .xlsx file (broken file?),
41 * duplicated string items may exist in the shared string table.
42 *
43 * In such case, the size of stringList will larger than stringTable.
44 * Duplicated items can be removed once we loaded all the worksheets.
45 */
46
47 SharedStrings::SharedStrings(CreateFlag flag)
48 :AbstractOOXmlFile(flag)
49 {
50 m_stringCount = 0;
51 }
52
53 int SharedStrings::count() const
54 {
55 return m_stringCount;
56 }
57
58 bool SharedStrings::isEmpty() const
59 {
60 return m_stringList.isEmpty();
61 }
62
63 int SharedStrings::addSharedString(const QString &string)
64 {
65 return addSharedString(RichString(string));
66 }
67
68 int SharedStrings::addSharedString(const RichString &string)
69 {
70 m_stringCount += 1;
71
72 if (m_stringTable.contains(string)) {
73 XlsxSharedStringInfo &item = m_stringTable[string];
74 item.count += 1;
75 return item.index;
76 }
77
78 int index = m_stringList.size();
79 m_stringTable[string] = XlsxSharedStringInfo(index);
80 m_stringList.append(string);
81 return index;
82 }
83
84 void SharedStrings::incRefByStringIndex(int idx)
85 {
86 if (idx <0 || idx >= m_stringList.size()) {
87 qDebug("SharedStrings: invlid index");
88 return;
89 }
90
91 addSharedString(m_stringList[idx]);
92 }
93
94 /*
95 * Broken, don't use.
96 */
97 void SharedStrings::removeSharedString(const QString &string)
98 {
99 removeSharedString(RichString(string));
100 }
101
102 /*
103 * Broken, don't use.
104 */
105 void SharedStrings::removeSharedString(const RichString &string)
106 {
107 if (!m_stringTable.contains(string))
108 return;
109
110 m_stringCount -= 1;
111
112 XlsxSharedStringInfo &item = m_stringTable[string];
113 item.count -= 1;
114
115 if (item.count <= 0) {
116 for (int i=item.index+1; i<m_stringList.size(); ++i)
117 m_stringTable[m_stringList[i]].index -= 1;
118
119 m_stringList.removeAt(item.index);
120 m_stringTable.remove(string);
121 }
122 }
123
124 int SharedStrings::getSharedStringIndex(const QString &string) const
125 {
126 return getSharedStringIndex(RichString(string));
127 }
128
129 int SharedStrings::getSharedStringIndex(const RichString &string) const
130 {
131 if (m_stringTable.contains(string))
132 return m_stringTable[string].index;
133 return -1;
134 }
135
136 RichString SharedStrings::getSharedString(int index) const
137 {
138 if (index < m_stringList.count() && index >= 0)
139 return m_stringList[index];
140 return RichString();
141 }
142
143 QList<RichString> SharedStrings::getSharedStrings() const
144 {
145 return m_stringList;
146 }
147
148 void SharedStrings::writeRichStringPart_rPr(QXmlStreamWriter &writer, const Format &format) const
149 {
150 if (!format.hasFontData())
151 return;
152
153 if (format.fontBold())
154 writer.writeEmptyElement(QStringLiteral("b"));
155 if (format.fontItalic())
156 writer.writeEmptyElement(QStringLiteral("i"));
157 if (format.fontStrikeOut())
158 writer.writeEmptyElement(QStringLiteral("strike"));
159 if (format.fontOutline())
160 writer.writeEmptyElement(QStringLiteral("outline"));
161 if (format.boolProperty(FormatPrivate::P_Font_Shadow))
162 writer.writeEmptyElement(QStringLiteral("shadow"));
163 if (format.hasProperty(FormatPrivate::P_Font_Underline)) {
164 Format::FontUnderline u = format.fontUnderline();
165 if (u != Format::FontUnderlineNone) {
166 writer.writeEmptyElement(QStringLiteral("u"));
167 if (u== Format::FontUnderlineDouble)
168 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double"));
169 else if (u == Format::FontUnderlineSingleAccounting)
170 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting"));
171 else if (u == Format::FontUnderlineDoubleAccounting)
172 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting"));
173 }
174 }
175 if (format.hasProperty(FormatPrivate::P_Font_Script)) {
176 Format::FontScript s = format.fontScript();
177 if (s != Format::FontScriptNormal) {
178 writer.writeEmptyElement(QStringLiteral("vertAlign"));
179 if (s == Format::FontScriptSuper)
180 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript"));
181 else
182 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript"));
183 }
184 }
185
186 if (format.hasProperty(FormatPrivate::P_Font_Size)) {
187 writer.writeEmptyElement(QStringLiteral("sz"));
188 writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize()));
189 }
190
191 if (format.hasProperty(FormatPrivate::P_Font_Color)) {
192 XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>();
193 color.saveToXml(writer);
194 }
195
196 if (!format.fontName().isEmpty()) {
197 writer.writeEmptyElement(QStringLiteral("rFont"));
198 writer.writeAttribute(QStringLiteral("val"), format.fontName());
199 }
200 if (format.hasProperty(FormatPrivate::P_Font_Family)) {
201 writer.writeEmptyElement(QStringLiteral("family"));
202 writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family)));
203 }
204
205 if (format.hasProperty(FormatPrivate::P_Font_Scheme)) {
206 writer.writeEmptyElement(QStringLiteral("scheme"));
207 writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme));
208 }
209 }
210
211 void SharedStrings::saveToXmlFile(QIODevice *device) const
212 {
213 QXmlStreamWriter writer(device);
214
215 if (m_stringList.size() != m_stringTable.size()) {
216 //Duplicated string items exist in m_stringList
217 //Clean up can not be done here, as the indices
218 //have been used when we save the worksheets part.
219 }
220
221 writer.writeStartDocument(QStringLiteral("1.0"), true);
222 writer.writeStartElement(QStringLiteral("sst"));
223 writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
224 writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount));
225 writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringList.size()));
226
227 foreach (RichString string, m_stringList) {
228 writer.writeStartElement(QStringLiteral("si"));
229 if (string.isRichString()) {
230 //Rich text string
231 for (int i=0; i<string.fragmentCount(); ++i) {
232 writer.writeStartElement(QStringLiteral("r"));
233 if (string.fragmentFormat(i).hasFontData()) {
234 writer.writeStartElement(QStringLiteral("rPr"));
235 writeRichStringPart_rPr(writer, string.fragmentFormat(i));
236 writer.writeEndElement();// rPr
237 }
238 writer.writeStartElement(QStringLiteral("t"));
239 if (isSpaceReserveNeeded(string.fragmentText(i)))
240 writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
241 writer.writeCharacters(string.fragmentText(i));
242 writer.writeEndElement();// t
243
244 writer.writeEndElement(); //r
245 }
246 } else {
247 writer.writeStartElement(QStringLiteral("t"));
248 QString pString = string.toPlainString();
249 if (isSpaceReserveNeeded(pString))
250 writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve"));
251 writer.writeCharacters(pString);
252 writer.writeEndElement();//t
253 }
254 writer.writeEndElement();//si
255 }
256
257 writer.writeEndElement(); //sst
258 writer.writeEndDocument();
259 }
260
261 void SharedStrings::readString(QXmlStreamReader &reader)
262 {
263 Q_ASSERT(reader.name() == QLatin1String("si"));
264
265 RichString richString;
266
267 while (!reader.atEnd() && !(reader.name() == QLatin1String("si") && reader.tokenType() == QXmlStreamReader::EndElement)) {
268 reader.readNextStartElement();
269 if (reader.tokenType() == QXmlStreamReader::StartElement) {
270 if (reader.name() == QLatin1String("r"))
271 readRichStringPart(reader, richString);
272 else if (reader.name() == QLatin1String("t"))
273 readPlainStringPart(reader, richString);
274 }
275 }
276
277 int idx = m_stringList.size();
278 m_stringTable[richString] = XlsxSharedStringInfo(idx, 0);
279 m_stringList.append(richString);
280 }
281
282 void SharedStrings::readRichStringPart(QXmlStreamReader &reader, RichString &richString)
283 {
284 Q_ASSERT(reader.name() == QLatin1String("r"));
285
286 QString text;
287 Format format;
288 while (!reader.atEnd() && !(reader.name() == QLatin1String("r") && reader.tokenType() == QXmlStreamReader::EndElement)) {
289 reader.readNextStartElement();
290 if (reader.tokenType() == QXmlStreamReader::StartElement) {
291 if (reader.name() == QLatin1String("rPr")) {
292 format = readRichStringPart_rPr(reader);
293 } else if (reader.name() == QLatin1String("t")) {
294 text = reader.readElementText();
295 }
296 }
297 }
298 richString.addFragment(text, format);
299 }
300
301 void SharedStrings::readPlainStringPart(QXmlStreamReader &reader, RichString &richString)
302 {
303 Q_ASSERT(reader.name() == QLatin1String("t"));
304
305 //QXmlStreamAttributes attributes = reader.attributes();
306
307 QString text = reader.readElementText();
308 richString.addFragment(text, Format());
309 }
310
311 Format SharedStrings::readRichStringPart_rPr(QXmlStreamReader &reader)
312 {
313 Q_ASSERT(reader.name() == QLatin1String("rPr"));
314 Format format;
315 while (!reader.atEnd() && !(reader.name() == QLatin1String("rPr") && reader.tokenType() == QXmlStreamReader::EndElement)) {
316 reader.readNextStartElement();
317 if (reader.tokenType() == QXmlStreamReader::StartElement) {
318 QXmlStreamAttributes attributes = reader.attributes();
319 if (reader.name() == QLatin1String("rFont")) {
320 format.setFontName(attributes.value(QLatin1String("val")).toString());
321 } else if (reader.name() == QLatin1String("charset")) {
322 format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toString().toInt());
323 } else if (reader.name() == QLatin1String("family")) {
324 format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toString().toInt());
325 } else if (reader.name() == QLatin1String("b")) {
326 format.setFontBold(true);
327 } else if (reader.name() == QLatin1String("i")) {
328 format.setFontItalic(true);
329 } else if (reader.name() == QLatin1String("strike")) {
330 format.setFontStrikeOut(true);
331 } else if (reader.name() == QLatin1String("outline")) {
332 format.setFontOutline(true);
333 } else if (reader.name() == QLatin1String("shadow")) {
334 format.setProperty(FormatPrivate::P_Font_Shadow, true);
335 } else if (reader.name() == QLatin1String("condense")) {
336 format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toString().toInt());
337 } else if (reader.name() == QLatin1String("extend")) {
338 format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toString().toInt());
339 } else if (reader.name() == QLatin1String("color")) {
340 XlsxColor color;
341 color.loadFromXml(reader);
342 format.setProperty(FormatPrivate::P_Font_Color, color);
343 } else if (reader.name() == QLatin1String("sz")) {
344 format.setFontSize(attributes.value(QLatin1String("val")).toString().toInt());
345 } else if (reader.name() == QLatin1String("u")) {
346 QString value = attributes.value(QLatin1String("val")).toString();
347 if (value == QLatin1String("double"))
348 format.setFontUnderline(Format::FontUnderlineDouble);
349 else if (value == QLatin1String("doubleAccounting"))
350 format.setFontUnderline(Format::FontUnderlineDoubleAccounting);
351 else if (value == QLatin1String("singleAccounting"))
352 format.setFontUnderline(Format::FontUnderlineSingleAccounting);
353 else
354 format.setFontUnderline(Format::FontUnderlineSingle);
355 } else if (reader.name() == QLatin1String("vertAlign")) {
356 QString value = attributes.value(QLatin1String("val")).toString();
357 if (value == QLatin1String("superscript"))
358 format.setFontScript(Format::FontScriptSuper);
359 else if (value == QLatin1String("subscript"))
360 format.setFontScript(Format::FontScriptSub);
361 } else if (reader.name() == QLatin1String("scheme")) {
362 format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString());
363 }
364 }
365 }
366 return format;
367 }
368
369 bool SharedStrings::loadFromXmlFile(QIODevice *device)
370 {
371 QXmlStreamReader reader(device);
372 int count = 0;
373 bool hasUniqueCountAttr=true;
374 while (!reader.atEnd()) {
375 QXmlStreamReader::TokenType token = reader.readNext();
376 if (token == QXmlStreamReader::StartElement) {
377 if (reader.name() == QLatin1String("sst")) {
378 QXmlStreamAttributes attributes = reader.attributes();
379 if ((hasUniqueCountAttr = attributes.hasAttribute(QLatin1String("uniqueCount"))))
380 count = attributes.value(QLatin1String("uniqueCount")).toString().toInt();
381 } else if (reader.name() == QLatin1String("si")) {
382 readString(reader);
383 }
384 }
385 }
386
387 if (hasUniqueCountAttr && m_stringList.size() != count) {
388 qDebug("Error: Shared string count");
389 return false;
390 }
391
392 if (m_stringList.size() != m_stringTable.size()) {
393 //qDebug("Warning: Duplicated items exist in shared string table.");
394 //Nothing we can do here, as indices of the strings will be used when loading sheets.
395 }
396
397 return true;
398 }
399
400 } //namespace
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)