Mercurial > clickerconvert
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 |