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()&gt;=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()&gt;=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()&gt;=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()&gt;=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()&gt;=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()&gt;=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()&gt;=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()&gt;=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()&gt;=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()&gt;0\" style:apply-style-name=\"N5133P0\"/>"
336         "\n      <style:map style:condition=\"value()&lt;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()&gt;0\" style:apply-style-name=\"N5134P0\"/>"
362         "\n      <style:map style:condition=\"value()&lt;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()&gt;0\" style:apply-style-name=\"N5135P0\"/>"
385         "\n      <style:map style:condition=\"value()&lt;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()&gt;0\" style:apply-style-name=\"N5136P0\"/>"
413         "\n      <style:map style:condition=\"value()&lt;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