1 /*
2 * This file is part of Office 2007 Filters for Calligra
3 * Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
4 * Copyright (C) 2003 David Faure <faure@kde.org>
5 * Copyright (C) 2002, 2003, 2004 Nicolas GOUTTE <goutte@kde.org>
6 * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
7 *
8 * Contact: Suresh Chande suresh.chande@nokia.com
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * version 2.1 as published by the Free Software Foundation.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26 #include "XlsxUtils.h"
27 #include "XlsxImport.h"
28 #include "XlsxXmlDocumentReader.h"
29 #include "XlsxXmlSharedStringsReader.h"
30 #include "XlsxXmlStylesReader.h"
31 #include "XlsxXmlCommentsReader.h"
32
33 #include <MsooXmlUtils.h>
34 #include <MsooXmlSchemas.h>
35 #include <MsooXmlContentTypes.h>
36 #include <MsooXmlRelationships.h>
37 #include "MsooXmlThemesReader.h"
38
39 #include <memory>
40
41 #include <QColor>
42 #include <QFile>
43 #include <QFont>
44 #include <QPen>
45 #include <QRegExp>
46 #include <QImage>
47
48 #include <kpluginfactory.h>
49
50 #include <KoEmbeddedDocumentSaver.h>
51 #include <KoDocumentInfo.h>
52 #include <KoDocument.h>
53 #include <KoFilterChain.h>
54 #include <KoPageLayout.h>
55 #include <KoXmlWriter.h>
56
57 K_PLUGIN_FACTORY_WITH_JSON(XlsxImportFactory, "calligra_filter_xlsx2ods.json", registerPlugin<XlsxImport>();)
58
59 Q_LOGGING_CATEGORY(lcXlsxImport, "calligra.filter.xlsx2ods")
60
61 enum XlsxDocumentType {
62 XlsxDocument,
63 XlsxTemplate,
64 XlsxMacroDocument
65 };
66
67 class XlsxImport::Private
68 {
69 public:
Private()70 Private() : type(XlsxDocument), macrosEnabled(false) {
71 }
72
mainDocumentContentType() const73 const char* mainDocumentContentType() const
74 {
75 if (type == XlsxMacroDocument)
76 return MSOOXML::ContentTypes::spreadsheetMacroDocument;
77 if (type == XlsxTemplate)
78 return MSOOXML::ContentTypes::spreadsheetTemplate;
79 return MSOOXML::ContentTypes::spreadsheetDocument;
80 }
81
82 XlsxDocumentType type;
83 bool macrosEnabled;
84 };
85
XlsxImport(QObject * parent,const QVariantList &)86 XlsxImport::XlsxImport(QObject* parent, const QVariantList &)
87 : MSOOXML::MsooXmlImport(QLatin1String("spreadsheet"), parent), d(new Private)
88 {
89 }
90
~XlsxImport()91 XlsxImport::~XlsxImport()
92 {
93 delete d;
94 }
95
acceptsSourceMimeType(const QByteArray & mime) const96 bool XlsxImport::acceptsSourceMimeType(const QByteArray& mime) const
97 {
98 qCDebug(lcXlsxImport) << "Entering XLSX Import filter: from " << mime;
99 if (mime == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
100 d->type = XlsxDocument;
101 d->macrosEnabled = false;
102 }
103 else if (mime == "application/vnd.openxmlformats-officedocument.spreadsheetml.template") {
104 d->type = XlsxTemplate;
105 d->macrosEnabled = false;
106 }
107 else if (mime == "application/vnd.ms-excel.sheet.macroEnabled") {
108 d->type = XlsxMacroDocument;
109 d->macrosEnabled = true;
110 }
111 else if (mime == "application/vnd.ms-excel.sheet.macroEnabled.12") {
112 d->type = XlsxDocument;
113 d->macrosEnabled = true;
114 }
115 else if (mime == "application/vnd.ms-excel.template.macroEnabled.12") {
116 d->type = XlsxTemplate;
117 d->macrosEnabled = true;
118 }
119 else {
120 return false;
121 }
122 return true;
123 }
124
acceptsDestinationMimeType(const QByteArray & mime) const125 bool XlsxImport::acceptsDestinationMimeType(const QByteArray& mime) const
126 {
127 qCDebug(lcXlsxImport) << "Entering XLSX Import filter: to " << mime;
128 return mime == "application/vnd.oasis.opendocument.spreadsheet";
129 }
130
parseParts(KoOdfWriters * writers,MSOOXML::MsooXmlRelationships * relationships,QString & errorMessage)131 KoFilter::ConversionStatus XlsxImport::parseParts(KoOdfWriters *writers,
132 MSOOXML::MsooXmlRelationships *relationships, QString& errorMessage)
133 {
134 // more here...
135 // 0. temporary styles
136 //! @todo create styles in XlsxXmlDocumentReader (XLSX defines styles in workbook.xml)
137
138 writers->mainStyles->insertRawOdfStyles(
139 KoGenStyles::DocumentStyles,
140 " <!-- COPIED -->"
141 "\n <style:default-style style:family=\"table-cell\">"
142 "\n <style:table-cell-properties />"
143 "\n <style:paragraph-properties style:tab-stop-distance=\"1.27cm\"/>"
144 "\n <style:text-properties style:font-name=\"Albany AMT\" fo:language=\"en\" fo:country=\"US\" style:font-name-asian=\"Arial\" style:language-asian=\"zxx\" style:country-asian=\"none\" style:font-name-complex=\"Tahoma\" style:language-complex=\"zxx\" style:country-complex=\"none\"/>"
145 "\n </style:default-style>"
146 "\n <number:number-style style:name=\"N0\">"
147 "\n <number:number number:min-integer-digits=\"1\"/>"
148 "\n </number:number-style>"
149 "\n <number:currency-style style:name=\"N104P0\" style:volatile=\"true\">"
150 "\n <number:currency-symbol number:language=\"en\" number:country=\"US\">$</number:currency-symbol>"
151 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
152 "\n </number:currency-style>"
153 "\n <number:currency-style style:name=\"N104\">"
154 "\n <style:text-properties fo:color=\"#ff0000\"/>"
155 "\n <number:text>-</number:text>"
156 "\n <number:currency-symbol number:language=\"en\" number:country=\"US\">$</number:currency-symbol>"
157 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
158 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N104P0\"/>"
159 "\n </number:currency-style>"
160 "\n <number:number-style style:name=\"N5000\" number:language=\"en\" number:country=\"US\">"
161 "\n <number:number number:min-integer-digits=\"1\"/>"
162 "\n </number:number-style>"
163 "\n <number:currency-style style:name=\"N5116P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
164 "\n <number:currency-symbol/>"
165 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
166 "\n <number:text> </number:text>"
167 "\n </number:currency-style>"
168 "\n <number:currency-style style:name=\"N5116\" number:language=\"en\" number:country=\"US\">"
169 "\n <number:text>(</number:text>"
170 "\n <number:currency-symbol/>"
171 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
172 "\n <number:text>)</number:text>"
173 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5116P0\"/>"
174 "\n </number:currency-style>"
175 "\n <number:currency-style style:name=\"N5117P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
176 "\n <number:currency-symbol/>"
177 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
178 "\n <number:text> </number:text>"
179 "\n </number:currency-style>"
180 "\n <number:currency-style style:name=\"N5117\" number:language=\"en\" number:country=\"US\">"
181 "\n <style:text-properties fo:color=\"#ff0000\"/>"
182 "\n <number:text>(</number:text>"
183 "\n <number:currency-symbol/>"
184 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
185 "\n <number:text>)</number:text>"
186 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5117P0\"/>"
187 "\n </number:currency-style>"
188 "\n <number:currency-style style:name=\"N5118P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
189 "\n <number:currency-symbol/>"
190 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
191 "\n <number:text> </number:text>"
192 "\n </number:currency-style>"
193 "\n <number:currency-style style:name=\"N5118\" number:language=\"en\" number:country=\"US\">"
194 "\n <number:text>(</number:text>"
195 "\n <number:currency-symbol/>"
196 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
197 "\n <number:text>)</number:text>"
198 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5118P0\"/>"
199 "\n </number:currency-style>"
200 "\n <number:currency-style style:name=\"N5119P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
201 "\n <number:currency-symbol/>"
202 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
203 "\n <number:text> </number:text>"
204 "\n </number:currency-style>"
205 "\n <number:currency-style style:name=\"N5119\" number:language=\"en\" number:country=\"US\">"
206 "\n <style:text-properties fo:color=\"#ff0000\"/>"
207 "\n <number:text>(</number:text>"
208 "\n <number:currency-symbol/>"
209 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
210 "\n <number:text>)</number:text>"
211 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5119P0\"/>"
212 "\n </number:currency-style>"
213 "\n <number:date-style style:name=\"N5120\" number:language=\"en\" number:country=\"US\">"
214 "\n <number:month/>"
215 "\n <number:text>/</number:text>"
216 "\n <number:day/>"
217 "\n <number:text>/</number:text>"
218 "\n <number:year number:style=\"long\"/>"
219 "\n </number:date-style>"
220 "\n <number:date-style style:name=\"N5121\" number:language=\"en\" number:country=\"US\">"
221 "\n <number:day/>"
222 "\n <number:text>-</number:text>"
223 "\n <number:month number:textual=\"true\"/>"
224 "\n <number:text>-</number:text>"
225 "\n <number:year/>"
226 "\n </number:date-style>"
227 "\n <number:date-style style:name=\"N5122\" number:language=\"en\" number:country=\"US\">"
228 "\n <number:day/>"
229 "\n <number:text>-</number:text>"
230 "\n <number:month number:textual=\"true\"/>"
231 "\n </number:date-style>"
232 "\n <number:date-style style:name=\"N5123\" number:language=\"en\" number:country=\"US\">"
233 "\n <number:month number:textual=\"true\"/>"
234 "\n <number:text>-</number:text>"
235 "\n <number:year/>"
236 "\n </number:date-style>"
237 "\n <number:time-style style:name=\"N5124\" number:language=\"en\" number:country=\"US\">"
238 "\n <number:hours/>"
239 "\n <number:text>:</number:text>"
240 "\n <number:minutes number:style=\"long\"/>"
241 "\n <number:text> </number:text>"
242 "\n <number:am-pm/>"
243 "\n </number:time-style>"
244 "\n <number:time-style style:name=\"N5125\" number:language=\"en\" number:country=\"US\">"
245 "\n <number:hours/>"
246 "\n <number:text>:</number:text>"
247 "\n <number:minutes number:style=\"long\"/>"
248 "\n <number:text>:</number:text>"
249 "\n <number:seconds number:style=\"long\"/>"
250 "\n <number:text> </number:text>"
251 "\n <number:am-pm/>"
252 "\n </number:time-style>"
253 "\n <number:time-style style:name=\"N5126\" number:language=\"en\" number:country=\"US\">"
254 "\n <number:hours/>"
255 "\n <number:text>:</number:text>"
256 "\n <number:minutes number:style=\"long\"/>"
257 "\n </number:time-style>"
258 "\n <number:time-style style:name=\"N5127\" number:language=\"en\" number:country=\"US\">"
259 "\n <number:hours/>"
260 "\n <number:text>:</number:text>"
261 "\n <number:minutes number:style=\"long\"/>"
262 "\n <number:text>:</number:text>"
263 "\n <number:seconds number:style=\"long\"/>"
264 "\n </number:time-style>"
265 "\n <number:date-style style:name=\"N5128\" number:language=\"en\" number:country=\"US\">"
266 "\n <number:month/>"
267 "\n <number:text>/</number:text>"
268 "\n <number:day/>"
269 "\n <number:text>/</number:text>"
270 "\n <number:year number:style=\"long\"/>"
271 "\n <number:text> </number:text>"
272 "\n <number:hours/>"
273 "\n <number:text>:</number:text>"
274 "\n <number:minutes number:style=\"long\"/>"
275 "\n </number:date-style>"
276 "\n <number:number-style style:name=\"N5129P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
277 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
278 "\n <number:text> </number:text>"
279 "\n </number:number-style>"
280 "\n <number:number-style style:name=\"N5129\" number:language=\"en\" number:country=\"US\">"
281 "\n <number:text>(</number:text>"
282 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
283 "\n <number:text>)</number:text>"
284 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5129P0\"/>"
285 "\n </number:number-style>"
286 "\n <number:number-style style:name=\"N5130P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
287 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
288 "\n <number:text> </number:text>"
289 "\n </number:number-style>"
290 "\n <number:number-style style:name=\"N5130\" number:language=\"en\" number:country=\"US\">"
291 "\n <style:text-properties fo:color=\"#ff0000\"/>"
292 "\n <number:text>(</number:text>"
293 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
294 "\n <number:text>)</number:text>"
295 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5130P0\"/>"
296 "\n </number:number-style>"
297 "\n <number:number-style style:name=\"N5131P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
298 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
299 "\n <number:text> </number:text>"
300 "\n </number:number-style>"
301 "\n <number:number-style style:name=\"N5131\" number:language=\"en\" number:country=\"US\">"
302 "\n <number:text>(</number:text>"
303 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
304 "\n <number:text>)</number:text>"
305 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5131P0\"/>"
306 "\n </number:number-style>"
307 "\n <number:number-style style:name=\"N5132P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
308 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
309 "\n <number:text> </number:text>"
310 "\n </number:number-style>"
311 "\n <number:number-style style:name=\"N5132\" number:language=\"en\" number:country=\"US\">"
312 "\n <style:text-properties fo:color=\"#ff0000\"/>"
313 "\n <number:text>(</number:text>"
314 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
315 "\n <number:text>)</number:text>"
316 "\n <style:map style:condition=\"value()>=0\" style:apply-style-name=\"N5132P0\"/>"
317 "\n </number:number-style>"
318 "\n <number:number-style style:name=\"N5133P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
319 "\n <number:text> </number:text>"
320 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
321 "\n <number:text> </number:text>"
322 "\n </number:number-style>"
323 "\n <number:number-style style:name=\"N5133P1\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
324 "\n <number:text> (</number:text>"
325 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
326 "\n <number:text>)</number:text>"
327 "\n </number:number-style>"
328 "\n <number:number-style style:name=\"N5133P2\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
329 "\n <number:text> - </number:text>"
330 "\n </number:number-style>"
331 "\n <number:text-style style:name=\"N5133\" number:language=\"en\" number:country=\"US\">"
332 "\n <number:text> </number:text>"
333 "\n <number:text-content/>"
334 "\n <number:text> </number:text>"
335 "\n <style:map style:condition=\"value()>0\" style:apply-style-name=\"N5133P0\"/>"
336 "\n <style:map style:condition=\"value()<0\" style:apply-style-name=\"N5133P1\"/>"
337 "\n <style:map style:condition=\"value()=0\" style:apply-style-name=\"N5133P2\"/>"
338 "\n </number:text-style>"
339 "\n <number:currency-style style:name=\"N5134P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
340 "\n <number:text> </number:text>"
341 "\n <number:currency-symbol/>"
342 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
343 "\n <number:text> </number:text>"
344 "\n </number:currency-style>"
345 "\n <number:currency-style style:name=\"N5134P1\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
346 "\n <number:text> </number:text>"
347 "\n <number:currency-symbol/>"
348 "\n <number:text>(</number:text>"
349 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
350 "\n <number:text>)</number:text>"
351 "\n </number:currency-style>"
352 "\n <number:currency-style style:name=\"N5134P2\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
353 "\n <number:text> </number:text>"
354 "\n <number:currency-symbol/>"
355 "\n <number:text>- </number:text>"
356 "\n </number:currency-style>"
357 "\n <number:text-style style:name=\"N5134\" number:language=\"en\" number:country=\"US\">"
358 "\n <number:text> </number:text>"
359 "\n <number:text-content/>"
360 "\n <number:text> </number:text>"
361 "\n <style:map style:condition=\"value()>0\" style:apply-style-name=\"N5134P0\"/>"
362 "\n <style:map style:condition=\"value()<0\" style:apply-style-name=\"N5134P1\"/>"
363 "\n <style:map style:condition=\"value()=0\" style:apply-style-name=\"N5134P2\"/>"
364 "\n </number:text-style>"
365 "\n <number:number-style style:name=\"N5135P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
366 "\n <number:text> </number:text>"
367 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
368 "\n <number:text> </number:text>"
369 "\n </number:number-style>"
370 "\n <number:number-style style:name=\"N5135P1\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
371 "\n <number:text> (</number:text>"
372 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
373 "\n <number:text>)</number:text>"
374 "\n </number:number-style>"
375 "\n <number:number-style style:name=\"N5135P2\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
376 "\n <number:text> -</number:text>"
377 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"0\"/>"
378 "\n <number:text> </number:text>"
379 "\n </number:number-style>"
380 "\n <number:text-style style:name=\"N5135\" number:language=\"en\" number:country=\"US\">"
381 "\n <number:text> </number:text>"
382 "\n <number:text-content/>"
383 "\n <number:text> </number:text>"
384 "\n <style:map style:condition=\"value()>0\" style:apply-style-name=\"N5135P0\"/>"
385 "\n <style:map style:condition=\"value()<0\" style:apply-style-name=\"N5135P1\"/>"
386 "\n <style:map style:condition=\"value()=0\" style:apply-style-name=\"N5135P2\"/>"
387 "\n </number:text-style>"
388 "\n <number:currency-style style:name=\"N5136P0\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
389 "\n <number:text> </number:text>"
390 "\n <number:currency-symbol/>"
391 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
392 "\n <number:text> </number:text>"
393 "\n </number:currency-style>"
394 "\n <number:currency-style style:name=\"N5136P1\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
395 "\n <number:text> </number:text>"
396 "\n <number:currency-symbol/>"
397 "\n <number:text>(</number:text>"
398 "\n <number:number number:decimal-places=\"2\" number:min-integer-digits=\"1\" number:grouping=\"true\"/>"
399 "\n <number:text>)</number:text>"
400 "\n </number:currency-style>"
401 "\n <number:currency-style style:name=\"N5136P2\" style:volatile=\"true\" number:language=\"en\" number:country=\"US\">"
402 "\n <number:text> </number:text>"
403 "\n <number:currency-symbol/>"
404 "\n <number:text>-</number:text>"
405 "\n <number:number number:decimal-places=\"0\" number:min-integer-digits=\"0\"/>"
406 "\n <number:text> </number:text>"
407 "\n </number:currency-style>"
408 "\n <number:text-style style:name=\"N5136\" number:language=\"en\" number:country=\"US\">"
409 "\n <number:text> </number:text>"
410 "\n <number:text-content/>"
411 "\n <number:text> </number:text>"
412 "\n <style:map style:condition=\"value()>0\" style:apply-style-name=\"N5136P0\"/>"
413 "\n <style:map style:condition=\"value()<0\" style:apply-style-name=\"N5136P1\"/>"
414 "\n <style:map style:condition=\"value()=0\" style:apply-style-name=\"N5136P2\"/>"
415 "\n </number:text-style>"
416 "\n <number:time-style style:name=\"N5137\" number:language=\"en\" number:country=\"US\">"
417 "\n <number:minutes number:style=\"long\"/>"
418 "\n <number:text>:</number:text>"
419 "\n <number:seconds number:style=\"long\"/>"
420 "\n </number:time-style>"
421 "\n <number:time-style style:name=\"N5138\" number:language=\"en\" number:country=\"US\" number:truncate-on-overflow=\"false\">"
422 "\n <number:hours/>"
423 "\n <number:text>:</number:text>"
424 "\n <number:minutes number:style=\"long\"/>"
425 "\n <number:text>:</number:text>"
426 "\n <number:seconds number:style=\"long\"/>"
427 "\n </number:time-style>"
428 "\n <number:time-style style:name=\"N5139\" number:language=\"en\" number:country=\"US\">"
429 "\n <number:minutes number:style=\"long\"/>"
430 "\n <number:text>:</number:text>"
431 "\n <number:seconds number:style=\"long\" number:decimal-places=\"1\"/>"
432 "\n </number:time-style>"
433 "\n <number:number-style style:name=\"N5140\" number:language=\"en\" number:country=\"US\">"
434 "\n <number:scientific-number number:decimal-places=\"1\" number:min-integer-digits=\"3\" number:min-exponent-digits=\"1\"/>"
435 "\n </number:number-style>"
436 "\n <style:style style:name=\"Default\" style:family=\"table-cell\"/>"
437 "\n <style:style style:name=\"Result\" style:family=\"table-cell\" style:parent-style-name=\"Default\">"
438 "\n <style:text-properties fo:font-style=\"italic\" style:text-underline-style=\"solid\" style:text-underline-width=\"auto\" style:text-underline-color=\"font-color\" fo:font-weight=\"bold\"/>"
439 "\n </style:style>"
440 "\n <style:style style:name=\"Result2\" style:family=\"table-cell\" style:parent-style-name=\"Result\" style:data-style-name=\"N104\"/>"
441 "\n <style:style style:name=\"Heading\" style:family=\"table-cell\" style:parent-style-name=\"Default\">"
442 "\n <style:table-cell-properties style:text-align-source=\"fix\" style:repeat-content=\"false\"/>"
443 "\n <style:paragraph-properties fo:text-align=\"center\"/>"
444 "\n <style:text-properties fo:font-size=\"16pt\" fo:font-style=\"italic\" fo:font-weight=\"bold\"/>"
445 "\n </style:style>"
446 "\n <style:style style:name=\"Heading1\" style:family=\"table-cell\" style:parent-style-name=\"Heading\">"
447 "\n <style:table-cell-properties style:rotation-angle=\"90\"/>"
448 "\n </style:style>"
449 "\n <style:style style:name=\"Excel_20_Built-in_20_Normal\" style:display-name=\"Excel Built-in Normal\" style:family=\"table-cell\" style:parent-style-name=\"Default\" style:data-style-name=\"N5000\">"
450 "\n <style:table-cell-properties style:cell-protect=\"protected\" style:print-content=\"true\" style:diagonal-bl-tr=\"none\" style:diagonal-tl-br=\"none\" style:text-align-source=\"value-type\" style:repeat-content=\"false\" fo:background-color=\"transparent\" fo:wrap-option=\"no-wrap\" fo:border=\"none\" style:direction=\"ltr\" style:rotation-angle=\"0\" style:rotation-align=\"none\" style:shrink-to-fit=\"false\" style:vertical-align=\"bottom\"/>"
451 "\n <style:paragraph-properties fo:margin-left=\"0cm\" style:writing-mode=\"page\"/>"
452 "\n <style:text-properties fo:color=\"#000000\" style:text-outline=\"false\" style:text-line-through-style=\"none\" style:font-name=\"Calibri\" fo:font-size=\"11pt\" fo:font-style=\"normal\" fo:text-shadow=\"none\" style:text-underline-style=\"none\" fo:font-weight=\"normal\" style:font-size-asian=\"11pt\" style:font-style-asian=\"normal\" style:font-weight-asian=\"normal\" style:font-size-complex=\"11pt\" style:font-style-complex=\"normal\" style:font-weight-complex=\"normal\"/>"
453 "\n </style:style>"
454 "\n <!-- /COPIED -->"
455 );
456
457 writers->mainStyles->insertRawOdfStyles(
458 KoGenStyles::MasterStyles,
459 " <!-- COPIED -->"
460 "\n <style:master-page style:name=\"Default\" style:page-layout-name=\"pm1\">"
461 "\n <style:header>"
462 "\n <text:p>"
463 "\n <text:sheet-name>" "???" "</text:sheet-name>"
464 "\n </text:p>"
465 "\n </style:header>"
466 "\n <style:header-left style:display=\"false\"/>"
467 "\n <style:footer>"
468 "\n <text:p>Page <text:page-number>1</text:page-number></text:p>"
469 "\n </style:footer>"
470 "\n <style:footer-left style:display=\"false\"/>"
471 "\n </style:master-page>"
472 "\n <style:master-page style:name=\"Report\" style:page-layout-name=\"pm2\">"
473 "\n <style:header>"
474 "\n <style:region-left>"
475 "\n <text:p><text:sheet-name>" "???" "</text:sheet-name> (<text:title>" "???" "</text:title>)</text:p>"
476 "\n </style:region-left>"
477 "\n <style:region-right>"
478 "\n <text:p><text:date style:data-style-name=\"N2\" text:date-value=\"2009-07-18\">07/18/2009</text:date>, <text:time>21:48:12</text:time></text:p>"
479 "\n </style:region-right>"
480 "\n </style:header>"
481 "\n <style:header-left style:display=\"false\"/>"
482 "\n <style:footer>"
483 "\n <text:p>Page <text:page-number>1</text:page-number> / <text:page-count>99</text:page-count></text:p>"
484 "\n </style:footer>"
485 "\n <style:footer-left style:display=\"false\"/>"
486 "\n </style:master-page>"
487 "\n <style:master-page style:name=\"PageStyle_5f_Test_20_sheet_20__5f_1\" style:display-name=\"PageStyle_Test sheet _1\" style:page-layout-name=\"pm3\">"
488 "\n <style:header style:display=\"false\"/>"
489 "\n <style:header-left style:display=\"false\"/>"
490 "\n <style:footer style:display=\"false\"/>"
491 "\n <style:footer-left style:display=\"false\"/>"
492 "\n </style:master-page>"
493 "\n <style:master-page style:name=\"PageStyle_5f_Test_20_sheet_20__5f_2\" style:display-name=\"PageStyle_Test sheet _2\" style:page-layout-name=\"pm4\">"
494 "\n <style:header style:display=\"false\"/>"
495 "\n <style:header-left style:display=\"false\"/>"
496 "\n <style:footer style:display=\"false\"/>"
497 "\n <style:footer-left style:display=\"false\"/>"
498 "\n </style:master-page>"
499 "\n <!-- COPIED -->"
500 );
501
502 writers->mainStyles->insertRawOdfStyles(
503 KoGenStyles::StylesXmlAutomaticStyles,
504 " <!-- COPIED -->"
505 "\n <style:page-layout style:name=\"pm1\">"
506 "\n <style:page-layout-properties style:first-page-number=\"continue\" style:writing-mode=\"lr-tb\"/>"
507 "\n <style:header-style>"
508 "\n <style:header-footer-properties fo:min-height=\"0.751cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-bottom=\"0.25cm\"/>"
509 "\n </style:header-style>"
510 "\n <style:footer-style>"
511 "\n <style:header-footer-properties fo:min-height=\"0.751cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-top=\"0.25cm\"/>"
512 "\n </style:footer-style>"
513 "\n </style:page-layout>"
514 "\n <style:page-layout style:name=\"pm2\">"
515 "\n <style:page-layout-properties style:writing-mode=\"lr-tb\"/>"
516 "\n <style:header-style>"
517 "\n <style:header-footer-properties fo:min-height=\"0.751cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-bottom=\"0.25cm\" fo:border=\"0.088cm solid #000000\" fo:padding=\"0.018cm\" fo:background-color=\"#c0c0c0\">"
518 "\n <style:background-image/>"
519 "\n </style:header-footer-properties>"
520 "\n </style:header-style>"
521 "\n <style:footer-style>"
522 "\n <style:header-footer-properties fo:min-height=\"0.751cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-top=\"0.25cm\" fo:border=\"0.088cm solid #000000\" fo:padding=\"0.018cm\" fo:background-color=\"#c0c0c0\">"
523 "\n <style:background-image/>"
524 "\n </style:header-footer-properties>"
525 "\n </style:footer-style>"
526 "\n </style:page-layout>"
527 "\n <style:page-layout style:name=\"pm3\">"
528 "\n <style:page-layout-properties fo:page-width=\"21.001cm\" fo:page-height=\"29.7cm\" style:num-format=\"1\" style:print-orientation=\"portrait\" fo:margin-top=\"1.905cm\" fo:margin-bottom=\"1.905cm\" fo:margin-left=\"1.778cm\" fo:margin-right=\"1.778cm\" style:print-page-order=\"ttb\" style:first-page-number=\"continue\" style:scale-to=\"100%\" style:writing-mode=\"lr-tb\" style:print=\"charts drawings objects zero-values\"/>"
529 "\n <style:header-style>"
530 "\n <style:header-footer-properties fo:min-height=\"0.75cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-bottom=\"0.25cm\"/>"
531 "\n </style:header-style>"
532 "\n <style:footer-style>"
533 "\n <style:header-footer-properties fo:min-height=\"0.75cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-top=\"0.25cm\"/>"
534 "\n </style:footer-style>"
535 "\n </style:page-layout>"
536 "\n <style:page-layout style:name=\"pm4\">"
537 "\n <style:page-layout-properties fo:page-width=\"21.59cm\" fo:page-height=\"27.94cm\" style:num-format=\"1\" style:print-orientation=\"portrait\" fo:margin-top=\"1.905cm\" fo:margin-bottom=\"1.905cm\" fo:margin-left=\"1.778cm\" fo:margin-right=\"1.778cm\" style:print-page-order=\"ttb\" style:first-page-number=\"continue\" style:scale-to=\"100%\" style:writing-mode=\"lr-tb\" style:print=\"charts drawings objects zero-values\"/>"
538 "\n <style:header-style>"
539 "\n <style:header-footer-properties fo:min-height=\"0.75cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-bottom=\"0.25cm\"/>"
540 "\n </style:header-style>"
541 "\n <style:footer-style>"
542 "\n <style:header-footer-properties fo:min-height=\"0.75cm\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\" fo:margin-top=\"0.25cm\"/>"
543 "\n </style:footer-style>"
544 "\n </style:page-layout>"
545 "\n <!-- /COPIED -->"
546 );
547
548 // Todo, find out whether these are defaults for xlsx or whether they can be read somewhere
549 writers->body->startElement("table:calculation-settings");
550 writers->body->addAttribute("table:case-sensitive", "false");
551 writers->body->addAttribute("table:automatic-find-labels", "false");
552 writers->body->addAttribute("table:use-regular-expressions", "false");
553 writers->body->addAttribute("table:use-wildcards", "true");
554 writers->body->endElement(); // table:calculation-settings
555
556 // 1. parse themes
557 QList<QByteArray> partNames = this->partNames(d->mainDocumentContentType());
558
559 // following is a workaround till the patch at https://bugs.freedesktop.org/show_bug.cgi?id=30417 is applied
560 // so we are able to proper handle this case already before using the mimetype.
561 if (partNames.isEmpty() && d->type != XlsxMacroDocument) {
562 QList<QByteArray> macroPartNames = this->partNames(MSOOXML::ContentTypes::spreadsheetMacroDocument);
563 if (macroPartNames.count() == 1 && acceptsSourceMimeType("application/vnd.ms-excel.sheet.macroEnabled")) {
564 partNames = macroPartNames;
565 }
566 }
567
568 if (partNames.count() != 1) {
569 errorMessage = i18n("Unable to find part for type %1", d->mainDocumentContentType());
570 return KoFilter::WrongFormat;
571 }
572 const QString spreadPathAndFile(partNames.first());
573 QString spreadPath, spreadFile;
574 MSOOXML::Utils::splitPathAndFile(spreadPathAndFile, &spreadPath, &spreadFile);
575
576 MSOOXML::DrawingMLTheme themes;
577 const QString spreadThemePathAndFile(relationships->targetForType(
578 spreadPath, spreadFile,
579 QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme"));
580 qCDebug(lcXlsxImport) << QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme";
581
582 QString spreadThemePath, spreadThemeFile;
583 MSOOXML::Utils::splitPathAndFile(spreadThemePathAndFile, &spreadThemePath, &spreadThemeFile);
584
585 MSOOXML::MsooXmlThemesReader themesReader(writers);
586 MSOOXML::MsooXmlThemesReaderContext themecontext(themes, relationships, (MSOOXML::MsooXmlImport*)this,
587 spreadThemePath, spreadThemeFile);
588
589 KoFilter::ConversionStatus status
590 = loadAndParseDocument(&themesReader, spreadThemePathAndFile, errorMessage, &themecontext);
591 Q_UNUSED(status);
592 reportProgress(5);
593
594 // 2. parse styles
595 XlsxStyles styles;
596 XlsxXmlStylesReaderContext colorContext(styles, true, this, &themes);
597 {
598 // In first round we read color overrides, in 2nd round we can actually use them.
599 XlsxXmlStylesReader stylesReader(writers);
600 RETURN_IF_ERROR(loadAndParseDocumentIfExists(
601 MSOOXML::ContentTypes::spreadsheetStyles, &stylesReader, writers, errorMessage, &colorContext))
602 reportProgress(15);
603 XlsxXmlStylesReaderContext context2(styles, false, this, &themes);
604 context2.colorIndices = colorContext.colorIndices; // Overriding default colors potentially
605 RETURN_IF_ERROR(loadAndParseDocumentIfExists(
606 MSOOXML::ContentTypes::spreadsheetStyles, &stylesReader, writers, errorMessage, &context2))
607 }
608
609 reportProgress(30);
610
611 // 3. parse shared strings
612 QVector<QString> sharedStrings;
613 {
614 XlsxXmlSharedStringsReader sharedStringsReader(writers);
615 XlsxXmlSharedStringsReaderContext context(sharedStrings, &themes, colorContext.colorIndices);
616 RETURN_IF_ERROR(loadAndParseDocumentIfExists(
617 MSOOXML::ContentTypes::spreadsheetSharedStrings, &sharedStringsReader, writers, errorMessage, &context))
618 }
619
620 reportProgress(35);
621
622 // 4. parse comments
623 XlsxComments comments;
624 {
625 XlsxXmlCommentsReader commentsReader(writers);
626 XlsxXmlCommentsReaderContext context(comments, &themes, colorContext.colorIndices);
627 RETURN_IF_ERROR( loadAndParseDocumentFromFileIfExists(
628 //! @todo only support "xl/comments1.xml" filename for comments?
629 "xl/comments1.xml", &commentsReader, writers, errorMessage, &context) )
630 }
631
632 reportProgress(40);
633
634 // 5. parse document
635 {
636 XlsxXmlDocumentReaderContext context(*this, &themes, sharedStrings, comments, styles, *relationships, "workbook.xml", "xl");
637 XlsxXmlDocumentReader documentReader(writers);
638 RETURN_IF_ERROR(loadAndParseDocument(d->mainDocumentContentType(), &documentReader, writers, errorMessage, &context))
639 }
640
641 reportProgress(100);
642
643 // more here...
644 return KoFilter::OK;
645 }
646
647 #include "XlsxImport.moc"
648