comparison src/xlsx/xlsxstyles.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 "xlsxstyles_p.h"
26 #include "xlsxformat_p.h"
27 #include "xlsxutility_p.h"
28 #include "xlsxcolor_p.h"
29 #include <QXmlStreamWriter>
30 #include <QXmlStreamReader>
31 #include <QFile>
32 #include <QMap>
33 #include <QDataStream>
34 #include <QDebug>
35 #include <QBuffer>
36
37 namespace QXlsx {
38
39 /*
40 When loading from existing .xlsx file. we should create a clean styles object.
41 otherwise, default formats should be added.
42
43 */
44 Styles::Styles(CreateFlag flag)
45 : AbstractOOXmlFile(flag), m_nextCustomNumFmtId(176), m_isIndexedColorsDefault(true)
46 , m_emptyFormatAdded(false)
47 {
48 //!Fix me. Should the custom num fmt Id starts with 164 or 176 or others??
49
50 //!Fix me! Where should we put these register code?
51 if (QMetaType::type("XlsxColor") == QMetaType::UnknownType) {
52 qRegisterMetaType<XlsxColor>("XlsxColor");
53 qRegisterMetaTypeStreamOperators<XlsxColor>("XlsxColor");
54 #if QT_VERSION >= 0x050200
55 QMetaType::registerDebugStreamOperator<XlsxColor>();
56 #endif
57 }
58
59 if (flag == F_NewFromScratch) {
60 //Add default Format
61 Format defaultFmt;
62 addXfFormat(defaultFmt);
63
64 //Add another fill format
65 Format fillFmt;
66 fillFmt.setFillPattern(Format::PatternGray125);
67 m_fillsList.append(fillFmt);
68 m_fillsHash.insert(fillFmt.fillKey(), fillFmt);
69 }
70 }
71
72 Styles::~Styles()
73 {
74 }
75
76 Format Styles::xfFormat(int idx) const
77 {
78 if (idx <0 || idx >= m_xf_formatsList.size())
79 return Format();
80
81 return m_xf_formatsList[idx];
82 }
83
84 Format Styles::dxfFormat(int idx) const
85 {
86 if (idx <0 || idx >= m_dxf_formatsList.size())
87 return Format();
88
89 return m_dxf_formatsList[idx];
90 }
91
92 void Styles::fixNumFmt(const Format &format)
93 {
94 if (!format.hasNumFmtData())
95 return;
96
97 if (format.hasProperty(FormatPrivate::P_NumFmt_Id)
98 && !format.stringProperty(FormatPrivate::P_NumFmt_FormatCode).isEmpty()) {
99 return;
100 }
101
102 if (m_builtinNumFmtsHash.isEmpty()) {
103 m_builtinNumFmtsHash.insert(QStringLiteral("General"), 0);
104 m_builtinNumFmtsHash.insert(QStringLiteral("0"), 1);
105 m_builtinNumFmtsHash.insert(QStringLiteral("0.00"), 2);
106 m_builtinNumFmtsHash.insert(QStringLiteral("#,##0"), 3);
107 m_builtinNumFmtsHash.insert(QStringLiteral("#,##0.00"), 4);
108 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);($#,##0)"), 5);
109 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0_);[Red]($#,##0)"), 6);
110 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);($#,##0.00)"), 7);
111 // m_builtinNumFmtsHash.insert(QStringLiteral("($#,##0.00_);[Red]($#,##0.00)"), 8);
112 m_builtinNumFmtsHash.insert(QStringLiteral("0%"), 9);
113 m_builtinNumFmtsHash.insert(QStringLiteral("0.00%"), 10);
114 m_builtinNumFmtsHash.insert(QStringLiteral("0.00E+00"), 11);
115 m_builtinNumFmtsHash.insert(QStringLiteral("# ?/?"), 12);
116 m_builtinNumFmtsHash.insert(QStringLiteral("# ?\?/??"), 13);// Note: "??/" is a c++ trigraph, so escape one "?"
117 m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy"), 14);
118 m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm-yy"), 15);
119 m_builtinNumFmtsHash.insert(QStringLiteral("d-mmm"), 16);
120 m_builtinNumFmtsHash.insert(QStringLiteral("mmm-yy"), 17);
121 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm AM/PM"), 18);
122 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss AM/PM"), 19);
123 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm"), 20);
124 m_builtinNumFmtsHash.insert(QStringLiteral("h:mm:ss"), 21);
125 m_builtinNumFmtsHash.insert(QStringLiteral("m/d/yy h:mm"), 22);
126
127 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);(#,##0)"), 37);
128 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0_);[Red](#,##0)"), 38);
129 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);(#,##0.00)"), 39);
130 m_builtinNumFmtsHash.insert(QStringLiteral("(#,##0.00_);[Red](#,##0.00)"), 40);
131 // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(_)"), 41);
132 // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0_);_($* (#,##0);_($* \"-\"_);_(_)"), 42);
133 // m_builtinNumFmtsHash.insert(QStringLiteral("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(_)"), 43);
134 // m_builtinNumFmtsHash.insert(QStringLiteral("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);_(_)"), 44);
135 m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss"), 45);
136 m_builtinNumFmtsHash.insert(QStringLiteral("[h]:mm:ss"), 46);
137 m_builtinNumFmtsHash.insert(QStringLiteral("mm:ss.0"), 47);
138 m_builtinNumFmtsHash.insert(QStringLiteral("##0.0E+0"), 48);
139 m_builtinNumFmtsHash.insert(QStringLiteral("@"), 49);
140 }
141
142 const QString str = format.numberFormat();
143 if (!str.isEmpty()) {
144 //Assign proper number format index
145 if (m_builtinNumFmtsHash.contains(str)) {
146 const_cast<Format *>(&format)->fixNumberFormat(m_builtinNumFmtsHash[str], str);
147 } else if (m_customNumFmtsHash.contains(str)) {
148 const_cast<Format *>(&format)->fixNumberFormat(m_customNumFmtsHash[str]->formatIndex, str);
149 } else {
150 //Assign a new fmt Id.
151 const_cast<Format *>(&format)->fixNumberFormat(m_nextCustomNumFmtId, str);
152
153 QSharedPointer<XlsxFormatNumberData> fmt(new XlsxFormatNumberData);
154 fmt->formatIndex = m_nextCustomNumFmtId;
155 fmt->formatString = str;
156 m_customNumFmtIdMap.insert(m_nextCustomNumFmtId, fmt);
157 m_customNumFmtsHash.insert(str, fmt);
158
159 m_nextCustomNumFmtId += 1;
160 }
161 } else {
162 int id = format.numberFormatIndex();
163 //Assign proper format code, this is needed by dxf format
164 if (m_customNumFmtIdMap.contains(id)) {
165 const_cast<Format *>(&format)->fixNumberFormat(id, m_customNumFmtIdMap[id]->formatString);
166 } else {
167 QHashIterator<QString, int> it(m_builtinNumFmtsHash);
168 bool find=false;
169 while (it.hasNext()) {
170 it.next();
171 if (it.value() == id) {
172 const_cast<Format *>(&format)->fixNumberFormat(id, it.key());
173 find = true;
174 break;
175 }
176 }
177
178 if (!find) {
179 //Wrong numFmt
180 const_cast<Format *>(&format)->fixNumberFormat(id, QStringLiteral("General"));
181 }
182 }
183 }
184 }
185
186 /*
187 Assign index to Font/Fill/Border and Format
188
189 When \a force is true, add the format to the format list, even other format has
190 the same key have been in.
191 This is useful when reading existing .xlsx files which may contains duplicated formats.
192 */
193 void Styles::addXfFormat(const Format &format, bool force)
194 {
195 if (format.isEmpty()) {
196 //Try do something for empty Format.
197 if (m_emptyFormatAdded && !force)
198 return;
199 m_emptyFormatAdded = true;
200 }
201
202 //numFmt
203 if (format.hasNumFmtData() && !format.hasProperty(FormatPrivate::P_NumFmt_Id))
204 fixNumFmt(format);
205
206 //Font
207 if (format.hasFontData() && !format.fontIndexValid()) {
208 //Assign proper font index, if has font data.
209 if (!m_fontsHash.contains(format.fontKey()))
210 const_cast<Format *>(&format)->setFontIndex(m_fontsList.size());
211 else
212 const_cast<Format *>(&format)->setFontIndex(m_fontsHash[format.fontKey()].fontIndex());
213 }
214 if (!m_fontsHash.contains(format.fontKey())) {
215 //Still a valid font if the format has no fontData. (All font properties are default)
216 m_fontsList.append(format);
217 m_fontsHash[format.fontKey()] = format;
218 }
219
220 //Fill
221 if (format.hasFillData() && !format.fillIndexValid()) {
222 //Assign proper fill index, if has fill data.
223 if (!m_fillsHash.contains(format.fillKey()))
224 const_cast<Format *>(&format)->setFillIndex(m_fillsList.size());
225 else
226 const_cast<Format *>(&format)->setFillIndex(m_fillsHash[format.fillKey()].fillIndex());
227 }
228 if (!m_fillsHash.contains(format.fillKey())) {
229 //Still a valid fill if the format has no fillData. (All fill properties are default)
230 m_fillsList.append(format);
231 m_fillsHash[format.fillKey()] = format;
232 }
233
234 //Border
235 if (format.hasBorderData() && !format.borderIndexValid()) {
236 //Assign proper border index, if has border data.
237 if (!m_bordersHash.contains(format.borderKey()))
238 const_cast<Format *>(&format)->setBorderIndex(m_bordersList.size());
239 else
240 const_cast<Format *>(&format)->setBorderIndex(m_bordersHash[format.borderKey()].borderIndex());
241 }
242 if (!m_bordersHash.contains(format.borderKey())) {
243 //Still a valid border if the format has no borderData. (All border properties are default)
244 m_bordersList.append(format);
245 m_bordersHash[format.borderKey()] = format;
246 }
247
248 //Format
249 if (!format.isEmpty() && !format.xfIndexValid()) {
250 if (m_xf_formatsHash.contains(format.formatKey()))
251 const_cast<Format *>(&format)->setXfIndex(m_xf_formatsHash[format.formatKey()].xfIndex());
252 else
253 const_cast<Format *>(&format)->setXfIndex(m_xf_formatsList.size());
254 }
255 if (!m_xf_formatsHash.contains(format.formatKey()) || force) {
256 m_xf_formatsList.append(format);
257 m_xf_formatsHash[format.formatKey()] = format;
258 }
259 }
260
261 void Styles::addDxfFormat(const Format &format, bool force)
262 {
263 //numFmt
264 if (format.hasNumFmtData())
265 fixNumFmt(format);
266
267 if (!format.isEmpty() && !format.dxfIndexValid()) {
268 if (m_dxf_formatsHash.contains(format.formatKey()))
269 const_cast<Format *>(&format)->setDxfIndex(m_dxf_formatsHash[format.formatKey()].dxfIndex());
270 else
271 const_cast<Format *>(&format)->setDxfIndex(m_dxf_formatsList.size());
272 }
273 if (!m_dxf_formatsHash.contains(format.formatKey()) || force) {
274 m_dxf_formatsList.append(format);
275 m_dxf_formatsHash[format.formatKey()] = format;
276 }
277 }
278
279 void Styles::saveToXmlFile(QIODevice *device) const
280 {
281 QXmlStreamWriter writer(device);
282
283 writer.writeStartDocument(QStringLiteral("1.0"), true);
284 writer.writeStartElement(QStringLiteral("styleSheet"));
285 writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main"));
286
287 writeNumFmts(writer);
288 writeFonts(writer);
289 writeFills(writer);
290 writeBorders(writer);
291
292 writer.writeStartElement(QStringLiteral("cellStyleXfs"));
293 writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1"));
294 writer.writeStartElement(QStringLiteral("xf"));
295 writer.writeAttribute(QStringLiteral("numFmtId"), QStringLiteral("0"));
296 writer.writeAttribute(QStringLiteral("fontId"), QStringLiteral("0"));
297 writer.writeAttribute(QStringLiteral("fillId"), QStringLiteral("0"));
298 writer.writeAttribute(QStringLiteral("borderId"), QStringLiteral("0"));
299 writer.writeEndElement();//xf
300 writer.writeEndElement();//cellStyleXfs
301
302 writeCellXfs(writer);
303
304 writer.writeStartElement(QStringLiteral("cellStyles"));
305 writer.writeAttribute(QStringLiteral("count"), QStringLiteral("1"));
306 writer.writeStartElement(QStringLiteral("cellStyle"));
307 writer.writeAttribute(QStringLiteral("name"), QStringLiteral("Normal"));
308 writer.writeAttribute(QStringLiteral("xfId"), QStringLiteral("0"));
309 writer.writeAttribute(QStringLiteral("builtinId"), QStringLiteral("0"));
310 writer.writeEndElement();//cellStyle
311 writer.writeEndElement();//cellStyles
312
313 writeDxfs(writer);
314
315 writer.writeStartElement(QStringLiteral("tableStyles"));
316 writer.writeAttribute(QStringLiteral("count"), QStringLiteral("0"));
317 writer.writeAttribute(QStringLiteral("defaultTableStyle"), QStringLiteral("TableStyleMedium9"));
318 writer.writeAttribute(QStringLiteral("defaultPivotStyle"), QStringLiteral("PivotStyleLight16"));
319 writer.writeEndElement();//tableStyles
320
321 writeColors(writer);
322
323 writer.writeEndElement();//styleSheet
324 writer.writeEndDocument();
325 }
326
327 void Styles::writeNumFmts(QXmlStreamWriter &writer) const
328 {
329 if (m_customNumFmtIdMap.size() == 0)
330 return;
331
332 writer.writeStartElement(QStringLiteral("numFmts"));
333 writer.writeAttribute(QStringLiteral("count"), QString::number(m_customNumFmtIdMap.count()));
334
335 QMapIterator<int, QSharedPointer<XlsxFormatNumberData> > it(m_customNumFmtIdMap);
336 while (it.hasNext()) {
337 it.next();
338 writer.writeEmptyElement(QStringLiteral("numFmt"));
339 writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(it.value()->formatIndex));
340 writer.writeAttribute(QStringLiteral("formatCode"), it.value()->formatString);
341 }
342 writer.writeEndElement();//numFmts
343 }
344
345 /*
346 */
347 void Styles::writeFonts(QXmlStreamWriter &writer) const
348 {
349 writer.writeStartElement(QStringLiteral("fonts"));
350 writer.writeAttribute(QStringLiteral("count"), QString::number(m_fontsList.count()));
351 for (int i=0; i<m_fontsList.size(); ++i)
352 writeFont(writer, m_fontsList[i], false);
353 writer.writeEndElement();//fonts
354 }
355
356 void Styles::writeFont(QXmlStreamWriter &writer, const Format &format, bool isDxf) const
357 {
358 writer.writeStartElement(QStringLiteral("font"));
359
360 //The condense and extend elements are mainly used in dxf format
361 if (format.hasProperty(FormatPrivate::P_Font_Condense)
362 && !format.boolProperty(FormatPrivate::P_Font_Condense)) {
363 writer.writeEmptyElement(QStringLiteral("condense"));
364 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0"));
365 }
366 if (format.hasProperty(FormatPrivate::P_Font_Extend)
367 && !format.boolProperty(FormatPrivate::P_Font_Extend)) {
368 writer.writeEmptyElement(QStringLiteral("extend"));
369 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("0"));
370 }
371
372 if (format.fontBold())
373 writer.writeEmptyElement(QStringLiteral("b"));
374 if (format.fontItalic())
375 writer.writeEmptyElement(QStringLiteral("i"));
376 if (format.fontStrikeOut())
377 writer.writeEmptyElement(QStringLiteral("strike"));
378 if (format.fontOutline())
379 writer.writeEmptyElement(QStringLiteral("outline"));
380 if (format.boolProperty(FormatPrivate::P_Font_Shadow))
381 writer.writeEmptyElement(QStringLiteral("shadow"));
382 if (format.hasProperty(FormatPrivate::P_Font_Underline)) {
383 Format::FontUnderline u = format.fontUnderline();
384 if (u != Format::FontUnderlineNone) {
385 writer.writeEmptyElement(QStringLiteral("u"));
386 if (u== Format::FontUnderlineDouble)
387 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double"));
388 else if (u == Format::FontUnderlineSingleAccounting)
389 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting"));
390 else if (u == Format::FontUnderlineDoubleAccounting)
391 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting"));
392 }
393 }
394 if (format.hasProperty(FormatPrivate::P_Font_Script)) {
395 Format::FontScript s = format.fontScript();
396 if (s != Format::FontScriptNormal) {
397 writer.writeEmptyElement(QStringLiteral("vertAlign"));
398 if (s == Format::FontScriptSuper)
399 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript"));
400 else
401 writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript"));
402 }
403 }
404
405 if (!isDxf && format.hasProperty(FormatPrivate::P_Font_Size)) {
406 writer.writeEmptyElement(QStringLiteral("sz"));
407 writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize()));
408 }
409
410 if (format.hasProperty(FormatPrivate::P_Font_Color)) {
411 XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>();
412 color.saveToXml(writer);
413 }
414
415 if (!isDxf) {
416 if (!format.fontName().isEmpty()) {
417 writer.writeEmptyElement(QStringLiteral("name"));
418 writer.writeAttribute(QStringLiteral("val"), format.fontName());
419 }
420 if (format.hasProperty(FormatPrivate::P_Font_Charset)) {
421 writer.writeEmptyElement(QStringLiteral("charset"));
422 writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Charset)));
423 }
424 if (format.hasProperty(FormatPrivate::P_Font_Family)) {
425 writer.writeEmptyElement(QStringLiteral("family"));
426 writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family)));
427 }
428
429 if (format.hasProperty(FormatPrivate::P_Font_Scheme)) {
430 writer.writeEmptyElement(QStringLiteral("scheme"));
431 writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme));
432 }
433 }
434 writer.writeEndElement(); //font
435 }
436
437 void Styles::writeFills(QXmlStreamWriter &writer) const
438 {
439 writer.writeStartElement(QStringLiteral("fills"));
440 writer.writeAttribute(QStringLiteral("count"), QString::number(m_fillsList.size()));
441
442 for (int i=0; i<m_fillsList.size(); ++i)
443 writeFill(writer, m_fillsList[i]);
444
445 writer.writeEndElement(); //fills
446 }
447
448 void Styles::writeFill(QXmlStreamWriter &writer, const Format &fill, bool isDxf) const
449 {
450 static QMap<int, QString> patternStrings;
451 if (patternStrings.isEmpty()) {
452 patternStrings[Format::PatternNone] = QStringLiteral("none");
453 patternStrings[Format::PatternSolid] = QStringLiteral("solid");
454 patternStrings[Format::PatternMediumGray] = QStringLiteral("mediumGray");
455 patternStrings[Format::PatternDarkGray] = QStringLiteral("darkGray");
456 patternStrings[Format::PatternLightGray] = QStringLiteral("lightGray");
457 patternStrings[Format::PatternDarkHorizontal] = QStringLiteral("darkHorizontal");
458 patternStrings[Format::PatternDarkVertical] = QStringLiteral("darkVertical");
459 patternStrings[Format::PatternDarkDown] = QStringLiteral("darkDown");
460 patternStrings[Format::PatternDarkUp] = QStringLiteral("darkUp");
461 patternStrings[Format::PatternDarkGrid] = QStringLiteral("darkGrid");
462 patternStrings[Format::PatternDarkTrellis] = QStringLiteral("darkTrellis");
463 patternStrings[Format::PatternLightHorizontal] = QStringLiteral("lightHorizontal");
464 patternStrings[Format::PatternLightVertical] = QStringLiteral("lightVertical");
465 patternStrings[Format::PatternLightDown] = QStringLiteral("lightDown");
466 patternStrings[Format::PatternLightUp] = QStringLiteral("lightUp");
467 patternStrings[Format::PatternLightTrellis] = QStringLiteral("lightTrellis");
468 patternStrings[Format::PatternGray125] = QStringLiteral("gray125");
469 patternStrings[Format::PatternGray0625] = QStringLiteral("gray0625");
470 patternStrings[Format::PatternLightGrid] = QStringLiteral("lightGrid");
471 }
472
473 writer.writeStartElement(QStringLiteral("fill"));
474 writer.writeStartElement(QStringLiteral("patternFill"));
475 Format::FillPattern pattern = fill.fillPattern();
476 // For normal fill formats, Excel prefer to outputing the default "none" attribute
477 // But for dxf, Excel prefer to omiting the default "none"
478 // Though not make any difference, but it make easier to compare origin files with generate files during debug
479 if (!(pattern == Format::PatternNone && isDxf))
480 writer.writeAttribute(QStringLiteral("patternType"), patternStrings[pattern]);
481 // For a solid fill, Excel reverses the role of foreground and background colours
482 if (fill.fillPattern() == Format::PatternSolid) {
483 if (fill.hasProperty(FormatPrivate::P_Fill_BgColor))
484 fill.property(FormatPrivate::P_Fill_BgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("fgColor"));
485 if (fill.hasProperty(FormatPrivate::P_Fill_FgColor))
486 fill.property(FormatPrivate::P_Fill_FgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("bgColor"));
487 } else {
488 if (fill.hasProperty(FormatPrivate::P_Fill_FgColor))
489 fill.property(FormatPrivate::P_Fill_FgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("fgColor"));
490 if (fill.hasProperty(FormatPrivate::P_Fill_BgColor))
491 fill.property(FormatPrivate::P_Fill_BgColor).value<XlsxColor>().saveToXml(writer, QStringLiteral("bgColor"));
492 }
493 writer.writeEndElement();//patternFill
494 writer.writeEndElement();//fill
495 }
496
497 void Styles::writeBorders(QXmlStreamWriter &writer) const
498 {
499 writer.writeStartElement(QStringLiteral("borders"));
500 writer.writeAttribute(QStringLiteral("count"), QString::number(m_bordersList.count()));
501 for (int i=0; i<m_bordersList.size(); ++i)
502 writeBorder(writer, m_bordersList[i]);
503 writer.writeEndElement();//borders
504 }
505
506 void Styles::writeBorder(QXmlStreamWriter &writer, const Format &border, bool isDxf) const
507 {
508 writer.writeStartElement(QStringLiteral("border"));
509 if (border.hasProperty(FormatPrivate::P_Border_DiagonalType)) {
510 Format::DiagonalBorderType t = border.diagonalBorderType();
511 if (t == Format::DiagonalBorderUp) {
512 writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1"));
513 } else if (t == Format::DiagonalBorderDown) {
514 writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1"));
515 } else if (t == Format::DiagnoalBorderBoth) {
516 writer.writeAttribute(QStringLiteral("diagonalUp"), QStringLiteral("1"));
517 writer.writeAttribute(QStringLiteral("diagonalDown"), QStringLiteral("1"));
518 }
519 }
520
521 writeSubBorder(writer, QStringLiteral("left"), border.leftBorderStyle(), border.property(FormatPrivate::P_Border_LeftColor).value<XlsxColor>());
522 writeSubBorder(writer, QStringLiteral("right"), border.rightBorderStyle(), border.property(FormatPrivate::P_Border_RightColor).value<XlsxColor>());
523 writeSubBorder(writer, QStringLiteral("top"), border.topBorderStyle(), border.property(FormatPrivate::P_Border_TopColor).value<XlsxColor>());
524 writeSubBorder(writer, QStringLiteral("bottom"), border.bottomBorderStyle(), border.property(FormatPrivate::P_Border_BottomColor).value<XlsxColor>());
525
526 //Condition DXF formats don't allow diagonal style
527 if (!isDxf)
528 writeSubBorder(writer, QStringLiteral("diagonal"), border.diagonalBorderStyle(), border.property(FormatPrivate::P_Border_DiagonalColor).value<XlsxColor>());
529
530 if (isDxf) {
531 // writeSubBorder(wirter, QStringLiteral("vertical"), );
532 // writeSubBorder(writer, QStringLiteral("horizontal"), );
533 }
534
535 writer.writeEndElement();//border
536 }
537
538 void Styles::writeSubBorder(QXmlStreamWriter &writer, const QString &type, int style, const XlsxColor &color) const
539 {
540 if (style == Format::BorderNone) {
541 writer.writeEmptyElement(type);
542 return;
543 }
544
545 static QMap<int, QString> stylesString;
546 if (stylesString.isEmpty()) {
547 stylesString[Format::BorderNone] = QStringLiteral("none");
548 stylesString[Format::BorderThin] = QStringLiteral("thin");
549 stylesString[Format::BorderMedium] = QStringLiteral("medium");
550 stylesString[Format::BorderDashed] = QStringLiteral("dashed");
551 stylesString[Format::BorderDotted] = QStringLiteral("dotted");
552 stylesString[Format::BorderThick] = QStringLiteral("thick");
553 stylesString[Format::BorderDouble] = QStringLiteral("double");
554 stylesString[Format::BorderHair] = QStringLiteral("hair");
555 stylesString[Format::BorderMediumDashed] = QStringLiteral("mediumDashed");
556 stylesString[Format::BorderDashDot] = QStringLiteral("dashDot");
557 stylesString[Format::BorderMediumDashDot] = QStringLiteral("mediumDashDot");
558 stylesString[Format::BorderDashDotDot] = QStringLiteral("dashDotDot");
559 stylesString[Format::BorderMediumDashDotDot] = QStringLiteral("mediumDashDotDot");
560 stylesString[Format::BorderSlantDashDot] = QStringLiteral("slantDashDot");
561 }
562
563 writer.writeStartElement(type);
564 writer.writeAttribute(QStringLiteral("style"), stylesString[style]);
565 color.saveToXml(writer); //write color element
566
567 writer.writeEndElement();//type
568 }
569
570 void Styles::writeCellXfs(QXmlStreamWriter &writer) const
571 {
572 writer.writeStartElement(QStringLiteral("cellXfs"));
573 writer.writeAttribute(QStringLiteral("count"), QString::number(m_xf_formatsList.size()));
574 foreach (const Format &format, m_xf_formatsList) {
575 int xf_id = 0;
576 writer.writeStartElement(QStringLiteral("xf"));
577 writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex()));
578 writer.writeAttribute(QStringLiteral("fontId"), QString::number(format.fontIndex()));
579 writer.writeAttribute(QStringLiteral("fillId"), QString::number(format.fillIndex()));
580 writer.writeAttribute(QStringLiteral("borderId"), QString::number(format.borderIndex()));
581 writer.writeAttribute(QStringLiteral("xfId"), QString::number(xf_id));
582 if (format.hasNumFmtData())
583 writer.writeAttribute(QStringLiteral("applyNumberFormat"), QStringLiteral("1"));
584 if (format.hasFontData())
585 writer.writeAttribute(QStringLiteral("applyFont"), QStringLiteral("1"));
586 if (format.hasFillData())
587 writer.writeAttribute(QStringLiteral("applyFill"), QStringLiteral("1"));
588 if (format.hasBorderData())
589 writer.writeAttribute(QStringLiteral("applyBorder"), QStringLiteral("1"));
590 if (format.hasAlignmentData())
591 writer.writeAttribute(QStringLiteral("applyAlignment"), QStringLiteral("1"));
592
593 if (format.hasAlignmentData()) {
594 writer.writeEmptyElement(QStringLiteral("alignment"));
595 if (format.hasProperty(FormatPrivate::P_Alignment_AlignH)) {
596 switch (format.horizontalAlignment()) {
597 case Format::AlignLeft:
598 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("left"));
599 break;
600 case Format::AlignHCenter:
601 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("center"));
602 break;
603 case Format::AlignRight:
604 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("right"));
605 break;
606 case Format::AlignHFill:
607 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("fill"));
608 break;
609 case Format::AlignHJustify:
610 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("justify"));
611 break;
612 case Format::AlignHMerge:
613 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("centerContinuous"));
614 break;
615 case Format::AlignHDistributed:
616 writer.writeAttribute(QStringLiteral("horizontal"), QStringLiteral("distributed"));
617 break;
618 default:
619 break;
620 }
621 }
622
623 if (format.hasProperty(FormatPrivate::P_Alignment_AlignV)) {
624 switch (format.verticalAlignment()) {
625 case Format::AlignTop:
626 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("top"));
627 break;
628 case Format::AlignVCenter:
629 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("center"));
630 break;
631 case Format::AlignVJustify:
632 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("justify"));
633 break;
634 case Format::AlignVDistributed:
635 writer.writeAttribute(QStringLiteral("vertical"), QStringLiteral("distributed"));
636 break;
637 default:
638 break;
639 }
640 }
641 if (format.hasProperty(FormatPrivate::P_Alignment_Indent))
642 writer.writeAttribute(QStringLiteral("indent"), QString::number(format.indent()));
643 if (format.hasProperty(FormatPrivate::P_Alignment_Wrap) && format.textWrap())
644 writer.writeAttribute(QStringLiteral("wrapText"), QStringLiteral("1"));
645 if (format.hasProperty(FormatPrivate::P_Alignment_ShinkToFit) && format.shrinkToFit())
646 writer.writeAttribute(QStringLiteral("shrinkToFit"), QStringLiteral("1"));
647 if (format.hasProperty(FormatPrivate::P_Alignment_Rotation))
648 writer.writeAttribute(QStringLiteral("textRotation"), QString::number(format.rotation()));
649 }
650
651 writer.writeEndElement();//xf
652 }
653 writer.writeEndElement();//cellXfs
654 }
655
656 void Styles::writeDxfs(QXmlStreamWriter &writer) const
657 {
658 writer.writeStartElement(QStringLiteral("dxfs"));
659 writer.writeAttribute(QStringLiteral("count"), QString::number(m_dxf_formatsList.size()));
660 foreach (const Format &format, m_dxf_formatsList)
661 writeDxf(writer, format);
662 writer.writeEndElement(); //dxfs
663 }
664
665 void Styles::writeDxf(QXmlStreamWriter &writer, const Format &format) const
666 {
667 writer.writeStartElement(QStringLiteral("dxf"));
668
669 if (format.hasFontData())
670 writeFont(writer, format, true);
671
672 if (format.hasNumFmtData()) {
673 writer.writeEmptyElement(QStringLiteral("numFmt"));
674 writer.writeAttribute(QStringLiteral("numFmtId"), QString::number(format.numberFormatIndex()));
675 writer.writeAttribute(QStringLiteral("formatCode"), format.numberFormat());
676 }
677
678 if (format.hasFillData())
679 writeFill(writer, format, true);
680
681 if (format.hasBorderData())
682 writeBorder(writer, format, true);
683
684 writer.writeEndElement();//dxf
685 }
686
687 void Styles::writeColors(QXmlStreamWriter &writer) const
688 {
689 if (m_isIndexedColorsDefault) //Don't output the default indexdeColors
690 return;
691
692 writer.writeStartElement(QStringLiteral("colors"));
693
694 writer.writeStartElement(QStringLiteral("indexedColors"));
695 foreach(QColor color, m_indexedColors) {
696 writer.writeEmptyElement(QStringLiteral("rgbColor"));
697 writer.writeAttribute(QStringLiteral("rgb"), XlsxColor::toARGBString(color));
698 }
699
700 writer.writeEndElement();//indexedColors
701
702 writer.writeEndElement();//colors
703 }
704
705 bool Styles::readNumFmts(QXmlStreamReader &reader)
706 {
707 Q_ASSERT(reader.name() == QLatin1String("numFmts"));
708 QXmlStreamAttributes attributes = reader.attributes();
709 bool hasCount = attributes.hasAttribute(QLatin1String("count"));
710 int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
711
712 //Read utill we find the numFmts end tag or ....
713 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
714 && reader.name() == QLatin1String("numFmts"))) {
715 reader.readNextStartElement();
716 if (reader.tokenType() == QXmlStreamReader::StartElement) {
717 if (reader.name() == QLatin1String("numFmt")) {
718 QXmlStreamAttributes attributes = reader.attributes();
719 QSharedPointer<XlsxFormatNumberData> fmt (new XlsxFormatNumberData);
720 fmt->formatIndex = attributes.value(QLatin1String("numFmtId")).toString().toInt();
721 fmt->formatString = attributes.value(QLatin1String("formatCode")).toString();
722 if (fmt->formatIndex >= m_nextCustomNumFmtId)
723 m_nextCustomNumFmtId = fmt->formatIndex + 1;
724 m_customNumFmtIdMap.insert(fmt->formatIndex, fmt);
725 m_customNumFmtsHash.insert(fmt->formatString, fmt);
726 }
727 }
728 }
729
730 if (reader.hasError())
731 qWarning()<<reader.errorString();
732
733 if (hasCount && (count != m_customNumFmtIdMap.size()))
734 qWarning("error read custom numFmts");
735
736 return true;
737 }
738
739 bool Styles::readFonts(QXmlStreamReader &reader)
740 {
741 Q_ASSERT(reader.name() == QLatin1String("fonts"));
742 QXmlStreamAttributes attributes = reader.attributes();
743 bool hasCount = attributes.hasAttribute(QLatin1String("count"));
744 int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
745 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
746 && reader.name() == QLatin1String("fonts"))) {
747 reader.readNextStartElement();
748 if (reader.tokenType() == QXmlStreamReader::StartElement) {
749 if (reader.name() == QLatin1String("font")) {
750 Format format;
751 readFont(reader, format);
752 m_fontsList.append(format);
753 m_fontsHash.insert(format.fontKey(), format);
754 if (format.isValid())
755 format.setFontIndex(m_fontsList.size()-1);
756 }
757 }
758 }
759 if (reader.hasError())
760 qWarning()<<reader.errorString();
761
762 if (hasCount && (count != m_fontsList.size()))
763 qWarning("error read fonts");
764 return true;
765 }
766
767 bool Styles::readFont(QXmlStreamReader &reader, Format &format)
768 {
769 Q_ASSERT(reader.name() == QLatin1String("font"));
770 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
771 && reader.name() == QLatin1String("font"))) {
772 reader.readNextStartElement();
773 if (reader.tokenType() == QXmlStreamReader::StartElement) {
774 QXmlStreamAttributes attributes = reader.attributes();
775 if (reader.name() == QLatin1String("name")) {
776 format.setFontName(attributes.value(QLatin1String("val")).toString());
777 } else if (reader.name() == QLatin1String("charset")) {
778 format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toString().toInt());
779 } else if (reader.name() == QLatin1String("family")) {
780 format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toString().toInt());
781 } else if (reader.name() == QLatin1String("b")) {
782 format.setFontBold(true);
783 } else if (reader.name() == QLatin1String("i")) {
784 format.setFontItalic(true);
785 } else if (reader.name() == QLatin1String("strike")) {
786 format.setFontStrikeOut(true);
787 } else if (reader.name() == QLatin1String("outline")) {
788 format.setFontOutline(true);
789 } else if (reader.name() == QLatin1String("shadow")) {
790 format.setProperty(FormatPrivate::P_Font_Shadow, true);
791 } else if (reader.name() == QLatin1String("condense")) {
792 format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toString().toInt());
793 } else if (reader.name() == QLatin1String("extend")) {
794 format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toString().toInt());
795 } else if (reader.name() == QLatin1String("color")) {
796 XlsxColor color;
797 color.loadFromXml(reader);
798 format.setProperty(FormatPrivate::P_Font_Color, color);
799 } else if (reader.name() == QLatin1String("sz")) {
800 int sz = attributes.value(QLatin1String("val")).toString().toInt();
801 format.setFontSize(sz);
802 } else if (reader.name() == QLatin1String("u")) {
803 QString value = attributes.value(QLatin1String("val")).toString();
804 if (value == QLatin1String("double"))
805 format.setFontUnderline(Format::FontUnderlineDouble);
806 else if (value == QLatin1String("doubleAccounting"))
807 format.setFontUnderline(Format::FontUnderlineDoubleAccounting);
808 else if (value == QLatin1String("singleAccounting"))
809 format.setFontUnderline(Format::FontUnderlineSingleAccounting);
810 else
811 format.setFontUnderline(Format::FontUnderlineSingle);
812 } else if (reader.name() == QLatin1String("vertAlign")) {
813 QString value = attributes.value(QLatin1String("val")).toString();
814 if (value == QLatin1String("superscript"))
815 format.setFontScript(Format::FontScriptSuper);
816 else if (value == QLatin1String("subscript"))
817 format.setFontScript(Format::FontScriptSub);
818 } else if (reader.name() == QLatin1String("scheme")) {
819 format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString());
820 }
821 }
822 }
823 return true;
824 }
825
826 bool Styles::readFills(QXmlStreamReader &reader)
827 {
828 Q_ASSERT(reader.name() == QLatin1String("fills"));
829
830 QXmlStreamAttributes attributes = reader.attributes();
831 bool hasCount = attributes.hasAttribute(QLatin1String("count"));
832 int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
833 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
834 && reader.name() == QLatin1String("fills"))) {
835 reader.readNextStartElement();
836 if (reader.tokenType() == QXmlStreamReader::StartElement) {
837 if (reader.name() == QLatin1String("fill")) {
838 Format fill;
839 readFill(reader, fill);
840 m_fillsList.append(fill);
841 m_fillsHash.insert(fill.fillKey(), fill);
842 if (fill.isValid())
843 fill.setFillIndex(m_fillsList.size()-1);
844 }
845 }
846 }
847 if (reader.hasError())
848 qWarning()<<reader.errorString();
849
850 if (hasCount && (count != m_fillsList.size()))
851 qWarning("error read fills");
852 return true;
853 }
854
855 bool Styles::readFill(QXmlStreamReader &reader, Format &fill)
856 {
857 Q_ASSERT(reader.name() == QLatin1String("fill"));
858
859 static QMap<QString, Format::FillPattern> patternValues;
860 if (patternValues.isEmpty()) {
861 patternValues[QStringLiteral("none")] = Format::PatternNone;
862 patternValues[QStringLiteral("solid")] = Format::PatternSolid;
863 patternValues[QStringLiteral("mediumGray")] = Format::PatternMediumGray;
864 patternValues[QStringLiteral("darkGray")] = Format::PatternDarkGray;
865 patternValues[QStringLiteral("lightGray")] = Format::PatternLightGray;
866 patternValues[QStringLiteral("darkHorizontal")] = Format::PatternDarkHorizontal;
867 patternValues[QStringLiteral("darkVertical")] = Format::PatternDarkVertical;
868 patternValues[QStringLiteral("darkDown")] = Format::PatternDarkDown;
869 patternValues[QStringLiteral("darkUp")] = Format::PatternDarkUp;
870 patternValues[QStringLiteral("darkGrid")] = Format::PatternDarkGrid;
871 patternValues[QStringLiteral("darkTrellis")] = Format::PatternDarkTrellis;
872 patternValues[QStringLiteral("lightHorizontal")] = Format::PatternLightHorizontal;
873 patternValues[QStringLiteral("lightVertical")] = Format::PatternLightVertical;
874 patternValues[QStringLiteral("lightDown")] = Format::PatternLightDown;
875 patternValues[QStringLiteral("lightUp")] = Format::PatternLightUp;
876 patternValues[QStringLiteral("lightTrellis")] = Format::PatternLightTrellis;
877 patternValues[QStringLiteral("gray125")] = Format::PatternGray125;
878 patternValues[QStringLiteral("gray0625")] = Format::PatternGray0625;
879 patternValues[QStringLiteral("lightGrid")] = Format::PatternLightGrid;
880 }
881
882 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("fill"))) {
883 reader.readNextStartElement();
884 if (reader.tokenType() == QXmlStreamReader::StartElement) {
885 if (reader.name() == QLatin1String("patternFill")) {
886 QXmlStreamAttributes attributes = reader.attributes();
887 if (attributes.hasAttribute(QLatin1String("patternType"))) {
888 QString pattern = attributes.value(QLatin1String("patternType")).toString();
889 fill.setFillPattern(patternValues.contains(pattern) ? patternValues[pattern] : Format::PatternNone);
890
891 //parse foreground and background colors if they exist
892 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("patternFill"))) {
893 reader.readNextStartElement();
894 if (reader.tokenType() == QXmlStreamReader::StartElement) {
895 if (reader.name() == QLatin1String("fgColor")) {
896 XlsxColor c;
897 c.loadFromXml(reader);
898 if (fill.fillPattern() == Format::PatternSolid)
899 fill.setProperty(FormatPrivate::P_Fill_BgColor, c);
900 else
901 fill.setProperty(FormatPrivate::P_Fill_FgColor, c);
902 } else if (reader.name() == QLatin1String("bgColor")) {
903 XlsxColor c;
904 c.loadFromXml(reader);
905 if (fill.fillPattern() == Format::PatternSolid)
906 fill.setProperty(FormatPrivate::P_Fill_FgColor, c);
907 else
908 fill.setProperty(FormatPrivate::P_Fill_BgColor, c);
909 }
910 }
911 }
912 }
913 }
914 }
915 }
916
917 return true;
918 }
919
920 bool Styles::readBorders(QXmlStreamReader &reader)
921 {
922 Q_ASSERT(reader.name() == QLatin1String("borders"));
923
924 QXmlStreamAttributes attributes = reader.attributes();
925 bool hasCount = attributes.hasAttribute(QLatin1String("count"));
926 int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
927 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
928 && reader.name() == QLatin1String("borders"))) {
929 reader.readNextStartElement();
930 if (reader.tokenType() == QXmlStreamReader::StartElement) {
931 if (reader.name() == QLatin1String("border")) {
932 Format border;
933 readBorder(reader, border);
934 m_bordersList.append(border);
935 m_bordersHash.insert(border.borderKey(), border);
936 if (border.isValid())
937 border.setBorderIndex(m_bordersList.size()-1);
938 }
939 }
940 }
941
942 if (reader.hasError())
943 qWarning()<<reader.errorString();
944
945 if (hasCount && (count != m_bordersList.size()))
946 qWarning("error read borders");
947
948 return true;
949 }
950
951 bool Styles::readBorder(QXmlStreamReader &reader, Format &border)
952 {
953 Q_ASSERT(reader.name() == QLatin1String("border"));
954
955 QXmlStreamAttributes attributes = reader.attributes();
956 bool isUp = attributes.hasAttribute(QLatin1String("diagonalUp"));
957 bool isDown = attributes.hasAttribute(QLatin1String("diagonalUp"));
958 if (isUp && isDown)
959 border.setDiagonalBorderType(Format::DiagnoalBorderBoth);
960 else if (isUp)
961 border.setDiagonalBorderType(Format::DiagonalBorderUp);
962 else if (isDown)
963 border.setDiagonalBorderType(Format::DiagonalBorderDown);
964
965 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border"))) {
966 reader.readNextStartElement();
967 if (reader.tokenType() == QXmlStreamReader::StartElement) {
968 if (reader.name() == QLatin1String("left") || reader.name() == QLatin1String("right")
969 || reader.name() == QLatin1String("top") || reader.name() == QLatin1String("bottom")
970 || reader.name() == QLatin1String("diagonal") ) {
971 Format::BorderStyle style(Format::BorderNone);
972 XlsxColor color;
973 readSubBorder(reader, reader.name().toString(), style, color);
974
975 if (reader.name() == QLatin1String("left")) {
976 border.setLeftBorderStyle(style);
977 if (!color.isInvalid())
978 border.setProperty(FormatPrivate::P_Border_LeftColor, color);
979 } else if (reader.name() == QLatin1String("right")) {
980 border.setRightBorderStyle(style);
981 if (!color.isInvalid())
982 border.setProperty(FormatPrivate::P_Border_RightColor, color);
983 } else if (reader.name() == QLatin1String("top")) {
984 border.setTopBorderStyle(style);
985 if (!color.isInvalid())
986 border.setProperty(FormatPrivate::P_Border_TopColor, color);
987 } else if (reader.name() == QLatin1String("bottom")) {
988 border.setBottomBorderStyle(style);
989 if (!color.isInvalid())
990 border.setProperty(FormatPrivate::P_Border_BottomColor, color);
991 } else if (reader.name() == QLatin1String("diagonal")) {
992 border.setDiagonalBorderStyle(style);
993 if (!color.isInvalid())
994 border.setProperty(FormatPrivate::P_Border_DiagonalColor, color);
995 }
996 }
997 }
998
999 if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == QLatin1String("border"))
1000 break;
1001 }
1002
1003 return true;
1004 }
1005
1006 bool Styles::readSubBorder(QXmlStreamReader &reader, const QString &name, Format::BorderStyle &style, XlsxColor &color)
1007 {
1008 Q_ASSERT(reader.name() == name);
1009
1010 static QMap<QString, Format::BorderStyle> stylesStringsMap;
1011 if (stylesStringsMap.isEmpty()) {
1012 stylesStringsMap[QStringLiteral("none")] = Format::BorderNone;
1013 stylesStringsMap[QStringLiteral("thin")] = Format::BorderThin;
1014 stylesStringsMap[QStringLiteral("medium")] = Format::BorderMedium;
1015 stylesStringsMap[QStringLiteral("dashed")] = Format::BorderDashed;
1016 stylesStringsMap[QStringLiteral("dotted")] = Format::BorderDotted;
1017 stylesStringsMap[QStringLiteral("thick")] = Format::BorderThick;
1018 stylesStringsMap[QStringLiteral("double")] = Format::BorderDouble;
1019 stylesStringsMap[QStringLiteral("hair")] = Format::BorderHair;
1020 stylesStringsMap[QStringLiteral("mediumDashed")] = Format::BorderMediumDashed;
1021 stylesStringsMap[QStringLiteral("dashDot")] = Format::BorderDashDot;
1022 stylesStringsMap[QStringLiteral("mediumDashDot")] = Format::BorderMediumDashDot;
1023 stylesStringsMap[QStringLiteral("dashDotDot")] = Format::BorderDashDotDot;
1024 stylesStringsMap[QStringLiteral("mediumDashDotDot")] = Format::BorderMediumDashDotDot;
1025 stylesStringsMap[QStringLiteral("slantDashDot")] = Format::BorderSlantDashDot;
1026 }
1027
1028 QXmlStreamAttributes attributes = reader.attributes();
1029 if (attributes.hasAttribute(QLatin1String("style"))) {
1030 QString styleString = attributes.value(QLatin1String("style")).toString();
1031 if (stylesStringsMap.contains(styleString)) {
1032 //get style
1033 style = stylesStringsMap[styleString];
1034 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == name)) {
1035 reader.readNextStartElement();
1036 if (reader.tokenType() == QXmlStreamReader::StartElement) {
1037 if (reader.name() == QLatin1String("color"))
1038 color.loadFromXml(reader);
1039 }
1040 }
1041 }
1042 }
1043
1044 return true;
1045 }
1046
1047 bool Styles::readCellXfs(QXmlStreamReader &reader)
1048 {
1049 Q_ASSERT(reader.name() == QLatin1String("cellXfs"));
1050 QXmlStreamAttributes attributes = reader.attributes();
1051 bool hasCount = attributes.hasAttribute(QLatin1String("count"));
1052 int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
1053 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
1054 && reader.name() == QLatin1String("cellXfs"))) {
1055 reader.readNextStartElement();
1056 if (reader.tokenType() == QXmlStreamReader::StartElement) {
1057 if (reader.name() == QLatin1String("xf")) {
1058
1059 Format format;
1060 QXmlStreamAttributes xfAttrs = reader.attributes();
1061
1062 // qDebug()<<reader.name()<<reader.tokenString()<<" .........";
1063 // for (int i=0; i<xfAttrs.size(); ++i)
1064 // qDebug()<<"... "<<i<<" "<<xfAttrs[i].name()<<xfAttrs[i].value();
1065
1066 if (xfAttrs.hasAttribute(QLatin1String("numFmtId"))) {
1067 int numFmtIndex = xfAttrs.value(QLatin1String("numFmtId")).toString().toInt();
1068 bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyNumberFormat")).toString());
1069 if(apply) {
1070 if (!m_customNumFmtIdMap.contains(numFmtIndex))
1071 format.setNumberFormatIndex(numFmtIndex);
1072 else
1073 format.setNumberFormat(numFmtIndex, m_customNumFmtIdMap[numFmtIndex]->formatString);
1074 }
1075 }
1076
1077 if (xfAttrs.hasAttribute(QLatin1String("fontId"))) {
1078 int fontIndex = xfAttrs.value(QLatin1String("fontId")).toString().toInt();
1079 if (fontIndex >= m_fontsList.size()) {
1080 qDebug("Error read styles.xml, cellXfs fontId");
1081 } else {
1082 bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFont")).toString());
1083 if(apply) {
1084 Format fontFormat = m_fontsList[fontIndex];
1085 for (int i=FormatPrivate::P_Font_STARTID; i<FormatPrivate::P_Font_ENDID; ++i) {
1086 if (fontFormat.hasProperty(i))
1087 format.setProperty(i, fontFormat.property(i));
1088 }
1089 }
1090 }
1091 }
1092
1093 if (xfAttrs.hasAttribute(QLatin1String("fillId"))) {
1094 int id = xfAttrs.value(QLatin1String("fillId")).toString().toInt();
1095 if (id >= m_fillsList.size()) {
1096 qDebug("Error read styles.xml, cellXfs fillId");
1097 } else {
1098 bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyFill")).toString());
1099 if(apply) {
1100 Format fillFormat = m_fillsList[id];
1101 for (int i=FormatPrivate::P_Fill_STARTID; i<FormatPrivate::P_Fill_ENDID; ++i) {
1102 if (fillFormat.hasProperty(i))
1103 format.setProperty(i, fillFormat.property(i));
1104 }
1105 }
1106 }
1107 }
1108
1109 if (xfAttrs.hasAttribute(QLatin1String("borderId"))) {
1110 int id = xfAttrs.value(QLatin1String("borderId")).toString().toInt();
1111 if (id >= m_bordersList.size()) {
1112 qDebug("Error read styles.xml, cellXfs borderId");
1113 } else {
1114 bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyBorder")).toString());
1115 if(apply) {
1116 Format borderFormat = m_bordersList[id];
1117 for (int i=FormatPrivate::P_Border_STARTID; i<FormatPrivate::P_Border_ENDID; ++i) {
1118 if (borderFormat.hasProperty(i))
1119 format.setProperty(i, borderFormat.property(i));
1120 }
1121 }
1122 }
1123 }
1124
1125 bool apply = parseXsdBoolean(xfAttrs.value(QLatin1String("applyAlignment")).toString());
1126 if(apply) {
1127 reader.readNextStartElement();
1128 if (reader.name() == QLatin1String("alignment")) {
1129 QXmlStreamAttributes alignAttrs = reader.attributes();
1130
1131 if (alignAttrs.hasAttribute(QLatin1String("horizontal"))) {
1132 static QMap<QString, Format::HorizontalAlignment> alignStringMap;
1133 if (alignStringMap.isEmpty()) {
1134 alignStringMap.insert(QStringLiteral("left"), Format::AlignLeft);
1135 alignStringMap.insert(QStringLiteral("center"), Format::AlignHCenter);
1136 alignStringMap.insert(QStringLiteral("right"), Format::AlignRight);
1137 alignStringMap.insert(QStringLiteral("justify"), Format::AlignHJustify);
1138 alignStringMap.insert(QStringLiteral("centerContinuous"), Format::AlignHMerge);
1139 alignStringMap.insert(QStringLiteral("distributed"), Format::AlignHDistributed);
1140 }
1141 QString str = alignAttrs.value(QLatin1String("horizontal")).toString();
1142 if (alignStringMap.contains(str))
1143 format.setHorizontalAlignment(alignStringMap[str]);
1144 }
1145
1146 if (alignAttrs.hasAttribute(QLatin1String("vertical"))) {
1147 static QMap<QString, Format::VerticalAlignment> alignStringMap;
1148 if (alignStringMap.isEmpty()) {
1149 alignStringMap.insert(QStringLiteral("top"), Format::AlignTop);
1150 alignStringMap.insert(QStringLiteral("center"), Format::AlignVCenter);
1151 alignStringMap.insert(QStringLiteral("justify"), Format::AlignVJustify);
1152 alignStringMap.insert(QStringLiteral("distributed"), Format::AlignVDistributed);
1153 }
1154 QString str = alignAttrs.value(QLatin1String("vertical")).toString();
1155 if (alignStringMap.contains(str))
1156 format.setVerticalAlignment(alignStringMap[str]);
1157 }
1158
1159 if (alignAttrs.hasAttribute(QLatin1String("indent"))) {
1160 int indent = alignAttrs.value(QLatin1String("indent")).toString().toInt();
1161 format.setIndent(indent);
1162 }
1163
1164 if (alignAttrs.hasAttribute(QLatin1String("textRotation"))) {
1165 int rotation = alignAttrs.value(QLatin1String("textRotation")).toString().toInt();
1166 format.setRotation(rotation);
1167 }
1168
1169 if (alignAttrs.hasAttribute(QLatin1String("wrapText")))
1170 format.setTextWarp(true);
1171
1172 if (alignAttrs.hasAttribute(QLatin1String("shrinkToFit")))
1173 format.setShrinkToFit(true);
1174
1175 }
1176 }
1177
1178 addXfFormat(format, true);
1179 }
1180 }
1181 }
1182
1183 if (reader.hasError())
1184 qWarning()<<reader.errorString();
1185
1186 if (hasCount && (count != m_xf_formatsList.size()))
1187 qWarning("error read CellXfs");
1188
1189 return true;
1190 }
1191
1192 bool Styles::readDxfs(QXmlStreamReader &reader)
1193 {
1194 Q_ASSERT(reader.name() == QLatin1String("dxfs"));
1195 QXmlStreamAttributes attributes = reader.attributes();
1196 bool hasCount = attributes.hasAttribute(QLatin1String("count"));
1197 int count = hasCount ? attributes.value(QLatin1String("count")).toString().toInt() : -1;
1198 while (!reader.atEnd() && !(reader.tokenType() == QXmlStreamReader::EndElement
1199 && reader.name() == QLatin1String("dxfs"))) {
1200 reader.readNextStartElement();
1201 if (reader.tokenType() == QXmlStreamReader::StartElement) {
1202 if (reader.name() == QLatin1String("dxf"))
1203 readDxf(reader);
1204 }
1205 }
1206 if (reader.hasError())
1207 qWarning()<<reader.errorString();
1208
1209 if (hasCount && (count != m_dxf_formatsList.size()))
1210 qWarning("error read dxfs");
1211
1212 return true;
1213 }
1214
1215 bool Styles::readDxf(QXmlStreamReader &reader)
1216 {
1217 Q_ASSERT(reader.name() == QLatin1String("dxf"));
1218 Format format;
1219 while (!reader.atEnd() && !(reader.name() == QLatin1String("dxf") && reader.tokenType() == QXmlStreamReader::EndElement)) {
1220 reader.readNextStartElement();
1221 if (reader.tokenType() == QXmlStreamReader::StartElement) {
1222 if (reader.name() == QLatin1String("numFmt")) {
1223 QXmlStreamAttributes attributes = reader.attributes();
1224 int id = attributes.value(QLatin1String("numFmtId")).toString().toInt();
1225 QString code = attributes.value(QLatin1String("formatCode")).toString();
1226 format.setNumberFormat(id, code);
1227 } else if (reader.name() == QLatin1String("font")) {
1228 readFont(reader, format);
1229 } else if (reader.name() == QLatin1String("fill")) {
1230 readFill(reader, format);
1231 } else if (reader.name() == QLatin1String("border")) {
1232 readBorder(reader, format);
1233 }
1234 }
1235 }
1236 addDxfFormat(format, true);
1237 return true;
1238 }
1239
1240 bool Styles::readColors(QXmlStreamReader &reader)
1241 {
1242 Q_ASSERT(reader.name() == QLatin1String("colors"));
1243 while (!reader.atEnd() && !(reader.name() == QLatin1String("colors") && reader.tokenType() == QXmlStreamReader::EndElement)) {
1244 reader.readNextStartElement();
1245 if (reader.tokenType() == QXmlStreamReader::StartElement) {
1246 if (reader.name() == QLatin1String("indexedColors")) {
1247 readIndexedColors(reader);
1248 } else if (reader.name() == QLatin1String("mruColors")) {
1249
1250 }
1251 }
1252 }
1253 return true;
1254 }
1255
1256 bool Styles::readIndexedColors(QXmlStreamReader &reader)
1257 {
1258 Q_ASSERT(reader.name() == QLatin1String("indexedColors"));
1259 m_indexedColors.clear();
1260 while (!reader.atEnd() && !(reader.name() == QLatin1String("indexedColors") && reader.tokenType() == QXmlStreamReader::EndElement)) {
1261 reader.readNextStartElement();
1262 if (reader.tokenType() == QXmlStreamReader::StartElement) {
1263 if (reader.name() == QLatin1String("rgbColor")) {
1264 QString color = reader.attributes().value(QLatin1String("rgb")).toString();
1265 m_indexedColors.append(XlsxColor::fromARGBString(color));
1266 }
1267 }
1268 }
1269 if (!m_indexedColors.isEmpty())
1270 m_isIndexedColorsDefault = false;
1271 return true;
1272 }
1273
1274 bool Styles::loadFromXmlFile(QIODevice *device)
1275 {
1276 QXmlStreamReader reader(device);
1277 while (!reader.atEnd()) {
1278 QXmlStreamReader::TokenType token = reader.readNext();
1279 if (token == QXmlStreamReader::StartElement) {
1280 if (reader.name() == QLatin1String("numFmts")) {
1281 readNumFmts(reader);
1282 } else if (reader.name() == QLatin1String("fonts")) {
1283 readFonts(reader);
1284 } else if (reader.name() == QLatin1String("fills")) {
1285 readFills(reader);
1286 } else if (reader.name() == QLatin1String("borders")) {
1287 readBorders(reader);
1288 } else if (reader.name() == QLatin1String("cellStyleXfs")) {
1289
1290 } else if (reader.name() == QLatin1String("cellXfs")) {
1291 readCellXfs(reader);
1292 } else if (reader.name() == QLatin1String("cellStyles")) {
1293
1294 } else if (reader.name() == QLatin1String("dxfs")) {
1295 readDxfs(reader);
1296 } else if (reader.name() == QLatin1String("colors")) {
1297 readColors(reader);
1298 }
1299 }
1300
1301 if (reader.hasError()) {
1302 qDebug()<<"Error when read style file: "<<reader.errorString();
1303 }
1304 }
1305 return true;
1306 }
1307
1308 QColor Styles::getColorByIndex(int idx)
1309 {
1310 if (m_indexedColors.isEmpty()) {
1311 m_indexedColors<<QColor("#000000") <<QColor("#FFFFFF") <<QColor("#FF0000") <<QColor("#00FF00")
1312 <<QColor("#0000FF") <<QColor("#FFFF00") <<QColor("#FF00FF") <<QColor("#00FFFF")
1313 <<QColor("#000000") <<QColor("#FFFFFF") <<QColor("#FF0000") <<QColor("#00FF00")
1314 <<QColor("#0000FF") <<QColor("#FFFF00") <<QColor("#FF00FF") <<QColor("#00FFFF")
1315 <<QColor("#800000") <<QColor("#008000") <<QColor("#000080") <<QColor("#808000")
1316 <<QColor("#800080") <<QColor("#008080") <<QColor("#C0C0C0") <<QColor("#808080")
1317 <<QColor("#9999FF") <<QColor("#993366") <<QColor("#FFFFCC") <<QColor("#CCFFFF")
1318 <<QColor("#660066") <<QColor("#FF8080") <<QColor("#0066CC") <<QColor("#CCCCFF")
1319 <<QColor("#000080") <<QColor("#FF00FF") <<QColor("#FFFF00") <<QColor("#00FFFF")
1320 <<QColor("#800080") <<QColor("#800000") <<QColor("#008080") <<QColor("#0000FF")
1321 <<QColor("#00CCFF") <<QColor("#CCFFFF") <<QColor("#CCFFCC") <<QColor("#FFFF99")
1322 <<QColor("#99CCFF") <<QColor("#FF99CC") <<QColor("#CC99FF") <<QColor("#FFCC99")
1323 <<QColor("#3366FF") <<QColor("#33CCCC") <<QColor("#99CC00") <<QColor("#FFCC00")
1324 <<QColor("#FF9900") <<QColor("#FF6600") <<QColor("#666699") <<QColor("#969696")
1325 <<QColor("#003366") <<QColor("#339966") <<QColor("#003300") <<QColor("#333300")
1326 <<QColor("#993300") <<QColor("#993366") <<QColor("#333399") <<QColor("#333333");
1327 m_isIndexedColorsDefault = true;
1328 }
1329 if (idx < 0 || idx >= m_indexedColors.size())
1330 return QColor();
1331 return m_indexedColors[idx];
1332 }
1333
1334 } //namespace QXlsx
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)