1 /*
2 * This file is part of Office 2007 Filters for Calligra
3 *
4 * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
5 *
6 * Contact: Suresh Chande suresh.chande@nokia.com
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * version 2.1 as published by the Free Software Foundation.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24 #include "PptxXmlDocumentReader.h"
25
26 #include "PptxXmlCommentAuthorsReader.h"
27 #include "PptxImport.h"
28 #include "PptxDebug.h"
29
30 #include <VmlDrawingReader.h>
31 #include <MsooXmlRelationships.h>
32 #include <MsooXmlSchemas.h>
33 #include <MsooXmlUtils.h>
34 #include <MsooXmlUnits.h>
35 #include <MsooXmlDrawingTableStyleReader.h>
36
37 #include <KoXmlWriter.h>
38 #include <KoGenStyles.h>
39 #include <KoPageLayout.h>
40 #include <KoOdfGraphicStyles.h>
41
42 #include <KoTable.h>
43 #include <KoRow.h>
44 #include <KoColumn.h>
45 #include <KoCell.h>
46 #include <KoCellStyle.h>
47
48 #define MSOOXML_CURRENT_NS "p"
49 #define MSOOXML_CURRENT_CLASS PptxXmlDocumentReader
50 #define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
51 #define PPTXXMLDOCUMENTREADER_CPP
52
53 #include <MsooXmlReader_p.h>
54
55
PptxXmlDocumentReaderContext(PptxImport & _import,const QString & _path,const QString & _file,MSOOXML::MsooXmlRelationships & _relationships)56 PptxXmlDocumentReaderContext::PptxXmlDocumentReaderContext(
57 PptxImport& _import, const QString& _path, const QString& _file,
58 MSOOXML::MsooXmlRelationships& _relationships)
59 : import(&_import),
60 path(_path), file(_file), relationships(&_relationships)
61 {
62 firstReadRound = true;
63 numberOfItems = 0;
64 }
65
66 class PptxXmlDocumentReader::Private
67 {
68 public:
Private()69 Private()
70 {
71 }
~Private()72 ~Private() {
73 qDeleteAll(slideLayoutPropertiesMap);
74 }
75 QMap<QString, PptxSlideProperties*> slideLayoutPropertiesMap;
76 uint slideNumber; //!< temp., see todo in PptxXmlDocumentReader::read_sldId()
77 bool sldSzRead, noteSzRead;
78 KoPageLayout pageLayout, notePageLayout;
79
80 // Several because there are several masterpages
81 QVector<QString> masterPageDrawStyleNames;
82 QVector<KoGenStyle> masterPageStyles;
83 QVector<QString> masterPageFrames;
84
85 QMap<QString, PptxSlideProperties> slideMasterPageProperties;
86 QMap<QString, PptxSlideProperties> notesMasterPageProperties;
87
88 QMap<int, QString> commentAuthors;
89 private:
90 };
91
PptxXmlDocumentReader(KoOdfWriters * writers)92 PptxXmlDocumentReader::PptxXmlDocumentReader(KoOdfWriters *writers)
93 : MSOOXML::MsooXmlCommonReader(writers)
94 , m_writers(writers)
95 , m_context(0)
96 , d(new Private)
97 {
98 init();
99 }
100
~PptxXmlDocumentReader()101 PptxXmlDocumentReader::~PptxXmlDocumentReader()
102 {
103 delete d;
104 }
105
init()106 void PptxXmlDocumentReader::init()
107 {
108 m_defaultNamespace = QLatin1String(MSOOXML_CURRENT_NS ":");
109 }
110
read(MSOOXML::MsooXmlReaderContext * context)111 KoFilter::ConversionStatus PptxXmlDocumentReader::read(MSOOXML::MsooXmlReaderContext* context)
112 {
113 m_context = dynamic_cast<PptxXmlDocumentReaderContext*>(context);
114 Q_ASSERT(m_context);
115 d->slideNumber = 0;
116 d->sldSzRead = false;
117 d->noteSzRead = false;
118 d->pageLayout = KoPageLayout();
119 d->notePageLayout = KoPageLayout();
120
121 const KoFilter::ConversionStatus result = readInternal();
122
123 m_context = 0;
124 return result;
125 }
126
readInternal()127 KoFilter::ConversionStatus PptxXmlDocumentReader::readInternal()
128 {
129 debugPptx << "=============================";
130 readNext();
131 if (!isStartDocument()) {
132 return KoFilter::WrongFormat;
133 }
134
135 // p:presentation
136 readNext();
137 debugPptx << *this << namespaceUri();
138
139 if (!expectEl("p:presentation")) {
140 return KoFilter::WrongFormat;
141 }
142 if (!expectNS(MSOOXML::Schemas::presentationml)) {
143 return KoFilter::WrongFormat;
144 }
145 // const QXmlStreamAttributes attrs( attributes() );
146 // for (int i=0; i<attrs.count(); i++) {
147 // debugPptx << "1 NS prefix:" << attrs[i].name() << "uri:" << attrs[i].namespaceUri();
148
149 QXmlStreamNamespaceDeclarations namespaces(namespaceDeclarations());
150 for (int i = 0; i < namespaces.count(); i++) {
151 debugPptx << "NS prefix:" << namespaces[i].prefix() << "uri:" << namespaces[i].namespaceUri();
152 }
153 //! @todo find out whether the namespace returned by namespaceUri()
154 //! is exactly the same ref as the element of namespaceDeclarations()
155 if (!namespaces.contains(QXmlStreamNamespaceDeclaration("p", MSOOXML::Schemas::presentationml))) {
156 raiseError(i18n("Namespace \"%1\" not found", QLatin1String(MSOOXML::Schemas::presentationml)));
157 return KoFilter::WrongFormat;
158 }
159 //! @todo expect other namespaces too...
160
161 {
162 PptxXmlCommentAuthorsReader autorsReader(this);
163 const QString autorsFilePath = m_context->relationships->targetForType(m_context->path, m_context->file, MSOOXML::Relationships::commentAuthors);
164 PptxXmlCommentAuthorsReaderContext autorsContext;
165 m_context->import->loadAndParseDocument(&autorsReader, autorsFilePath, &autorsContext);
166 d->commentAuthors = autorsContext.authors;
167 }
168
169 TRY_READ(presentation)
170 debugPptx << "===========finished============";
171 return KoFilter::OK;
172 }
173
slideLayoutProperties(const QString & slidePath,const QString & slideFile)174 PptxSlideProperties* PptxXmlDocumentReader::slideLayoutProperties(const QString& slidePath, const QString& slideFile)
175 {
176 const QString slideLayoutPathAndFile(m_context->relationships->targetForType(
177 slidePath, slideFile,
178 QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout"));
179 debugPptx << QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout";
180 debugPptx << "slideLayoutPathAndFile:" << slideLayoutPathAndFile;
181 if (slideLayoutPathAndFile.isEmpty())
182 return 0;
183
184 QString slideLayoutPath, slideLayoutFile;
185 MSOOXML::Utils::splitPathAndFile(slideLayoutPathAndFile, &slideLayoutPath, &slideLayoutFile);
186
187 // load layout or find in cache
188 PptxSlideProperties *result = d->slideLayoutPropertiesMap.value(slideLayoutPathAndFile);
189 if (result)
190 return result;
191
192 QString slideMasterPath, slideMasterFile;
193 MSOOXML::Utils::splitPathAndFile(m_context->relationships->targetForType(slidePath, slideFile,
194 QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout"), &slideMasterPath, &slideMasterFile);
195 const QString slideMasterPathAndFile = m_context->relationships->targetForType(slideMasterPath, slideMasterFile,
196 QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideMaster");
197
198 result = new PptxSlideProperties();
199 result->m_slideMasterName = slideMasterPathAndFile;
200
201 VmlDrawingReader vmlreader(this);
202 QString vmlTarget = m_context->relationships->targetForType(slideLayoutPath, slideLayoutFile,
203 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
204
205 if (!vmlTarget.isEmpty()) {
206 QString errorMessage, vmlPath, vmlFile;
207
208 QString fileName = vmlTarget;
209 fileName.remove(0, m_context->path.length());
210 MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
211
212 VmlDrawingReaderContext vmlContext(*m_context->import,
213 vmlPath, vmlFile, *m_context->relationships);
214
215 const KoFilter::ConversionStatus status =
216 m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
217 if (status != KoFilter::OK) {
218 vmlreader.raiseError(errorMessage);
219 }
220 }
221
222 MSOOXML::Utils::AutoPtrSetter<PptxSlideProperties> slideLayoutPropertiesSetter(result);
223 PptxXmlSlideReaderContext context(
224 *m_context->import,
225 slideLayoutPath, slideLayoutFile,
226 0/*unused*/, &d->slideMasterPageProperties[slideMasterPathAndFile].theme,
227 PptxXmlSlideReader::SlideLayout,
228 result,
229 &d->slideMasterPageProperties[slideMasterPathAndFile], //PptxSlideMasterPageProperties
230 0,
231 *m_context->relationships,
232 d->commentAuthors,
233 d->slideMasterPageProperties[slideMasterPathAndFile].colorMap,
234 vmlreader
235 );
236
237 PptxXmlSlideReader slideLayoutReader(this);
238 context.firstReadingRound = true;
239
240 KoFilter::ConversionStatus status = m_context->import->loadAndParseDocument(
241 &slideLayoutReader, slideLayoutPath + '/' + slideLayoutFile, &context);
242 if (status != KoFilter::OK) {
243 debugPptx << slideLayoutReader.errorString();
244 return 0;
245 }
246
247 context.initializeContext(d->slideMasterPageProperties[slideMasterPathAndFile].theme, defaultParagraphStyles,
248 defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
249
250 context.firstReadingRound = false;
251 status = m_context->import->loadAndParseDocument(
252 &slideLayoutReader, slideLayoutPath + '/' + slideLayoutFile, &context);
253 if (status != KoFilter::OK) {
254 debugPptx << slideLayoutReader.errorString();
255 return 0;
256 }
257
258 slideLayoutPropertiesSetter.release();
259 d->slideLayoutPropertiesMap.insert(slideLayoutPathAndFile, result);
260 return result;
261 }
262
263 #undef CURRENT_EL
264 #define CURRENT_EL sldId
265 //! p:sldId handler (Slide ID)
266 /*! ECMA-376, 19.2.1.33, p. 2797.
267
268 This element specifies a presentation slide that is available within the
269 corresponding presentation.
270
271 Parent elements:
272 - [done] sldIdLst (§19.2.1.34)
273
274 Child elements:
275 - extLst (Extension List)
276 */
read_sldId()277 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldId()
278 {
279 READ_PROLOGUE
280 const QXmlStreamAttributes attrs(attributes());
281 TRY_READ_ATTR_WITHOUT_NS(id)
282 READ_ATTR_WITH_NS(r, id)
283 debugPptx << "id:" << id << "r:id:" << r_id;
284
285 // locate this slide
286 const QString slidePathAndFile(m_context->relationships->target(m_context->path, m_context->file, r_id));
287 debugPptx << "slidePathAndFile:" << slidePathAndFile;
288
289 QString slidePath, slideFile;
290 MSOOXML::Utils::splitPathAndFile(slidePathAndFile, &slidePath, &slideFile);
291
292 PptxSlideProperties *slideLayoutProperties = this->slideLayoutProperties(slidePath, slideFile);
293 if (!slideLayoutProperties) {
294 raiseError(i18n("Slide layout \"%1\" not found", slidePath + '/' + slideFile));
295 return KoFilter::WrongFormat;
296 }
297
298 VmlDrawingReader vmlreader(this);
299 QString vmlTarget = m_context->relationships->targetForType(slidePath, slideFile,
300 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
301
302 if (!vmlTarget.isEmpty()) {
303 QString errorMessage, vmlPath, vmlFile;
304
305 QString fileName = vmlTarget;
306 fileName.remove(0, m_context->path.length());
307 MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
308
309 VmlDrawingReaderContext vmlContext(*m_context->import,
310 vmlPath, vmlFile, *m_context->relationships);
311
312 const KoFilter::ConversionStatus status =
313 m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
314 if (status != KoFilter::OK) {
315 vmlreader.raiseError(errorMessage);
316 }
317 }
318
319 QString slideMasterPath, slideMasterFile;
320 MSOOXML::Utils::splitPathAndFile(m_context->relationships->targetForType(slidePath, slideFile, QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideLayout"), &slideMasterPath, &slideMasterFile);
321 const QString slideMasterPathAndFile = m_context->relationships->targetForType(slideMasterPath, slideMasterFile, QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/slideMaster");
322
323 // Delay the reading of a tableStyle until we find a table as we need the
324 // clrMap from the master slide
325 const QString tableStylesFilePath = m_context->relationships->targetForType(m_context->path, m_context->file, MSOOXML::Relationships::tableStyles);
326
327 PptxSlideProperties *notes = 0;
328 const QString notesTarget(m_context->relationships->targetForType(m_context->path, m_context->file,
329 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster"));
330 if (!notesTarget.isEmpty()) {
331 notes = &d->notesMasterPageProperties[notesTarget];
332 }
333
334 PptxXmlSlideReaderContext context(
335 *m_context->import,
336 slidePath, slideFile,
337 d->slideNumber,
338 &d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName].theme,
339 PptxXmlSlideReader::Slide,
340 slideLayoutProperties,
341 &d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName],
342 notes,
343 *m_context->relationships,
344 d->commentAuthors,
345 d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName].colorMap,
346 vmlreader,
347 tableStylesFilePath
348 );
349
350 // 1st reading round - read possible colorMap override
351 PptxXmlSlideReader slideReader(this);
352 context.firstReadingRound = true;
353
354 KoFilter::ConversionStatus status = m_context->import->loadAndParseDocument(
355 &slideReader, slidePath + '/' + slideFile, &context);
356 if (status != KoFilter::OK) {
357 debugPptx << slideReader.errorString();
358 return status;
359 }
360
361 context.initializeContext(d->slideMasterPageProperties[slideLayoutProperties->m_slideMasterName].theme, defaultParagraphStyles,
362 defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
363
364 // 2nd reading round
365 context.firstReadingRound = false;
366 status = m_context->import->loadAndParseDocument(&slideReader, slidePath + '/' + slideFile, &context);
367 if (status != KoFilter::OK) {
368 debugPptx << slideReader.errorString();
369 return status;
370 }
371
372 ++d->slideNumber;
373
374 SKIP_EVERYTHING
375 READ_EPILOGUE
376 }
377
378 #undef CURRENT_EL
379 #define CURRENT_EL notesMasterId
380 //! p:noteMasterId (Note Master ID)
381 /*!
382 Parent elements:
383 - [done] noteMasterIdLst (§19.2.1.37)
384
385 Child elements:
386 - extLst (Extension List) §19.2.1.12
387 */
read_notesMasterId()388 KoFilter::ConversionStatus PptxXmlDocumentReader::read_notesMasterId()
389 {
390 READ_PROLOGUE
391 const QXmlStreamAttributes attrs(attributes());
392 READ_ATTR_WITH_NS(r, id)
393
394 const QString notesMasterPathAndFile(m_context->relationships->target(m_context->path, m_context->file, r_id));
395 debugPptx << "notesMasterPathAndFile:" << notesMasterPathAndFile;
396
397 QString notesMasterPath, notesMasterFile;
398 MSOOXML::Utils::splitPathAndFile(notesMasterPathAndFile, ¬esMasterPath, ¬esMasterFile);
399
400 // Reading the notesmaster theme
401 PptxSlideProperties notesPageProperties;
402
403 const QString notesThemePathAndFile(m_context->relationships->targetForType(
404 notesMasterPath, notesMasterFile,
405 QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme"));
406 debugPptx << QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme";
407 debugPptx << "notesThemePathAndFile:" << notesThemePathAndFile;
408
409 QString notesThemePath, notesThemeFile;
410 MSOOXML::Utils::splitPathAndFile(notesThemePathAndFile, ¬esThemePath, ¬esThemeFile);
411
412 MSOOXML::MsooXmlThemesReader themesReader(m_writers);
413 MSOOXML::MsooXmlThemesReaderContext themecontext(notesPageProperties.theme, m_context->relationships, m_context->import,
414 notesThemePath, notesThemeFile);
415
416 QString errorMessage;
417
418 KoFilter::ConversionStatus status
419 = m_context->import->loadAndParseDocument(&themesReader, notesThemePathAndFile, errorMessage, &themecontext);
420
421 //empty map used here as slideMaster is the place where the map is created
422 QMap<QString, QString> dummyMap;
423
424 VmlDrawingReader vmlreader(this);
425 QString vmlTarget = m_context->relationships->targetForType(notesMasterPath, notesMasterFile,
426 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
427
428 if (!vmlTarget.isEmpty()) {
429 QString errorMessage, vmlPath, vmlFile;
430
431 QString fileName = vmlTarget;
432 fileName.remove(0, m_context->path.length());
433 MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
434
435 VmlDrawingReaderContext vmlContext(*m_context->import,
436 vmlPath, vmlFile, *m_context->relationships);
437
438 const KoFilter::ConversionStatus status =
439 m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
440 if (status != KoFilter::OK) {
441 vmlreader.raiseError(errorMessage);
442 }
443 }
444
445 PptxXmlSlideReaderContext context(
446 *m_context->import,
447 notesMasterPath, notesMasterFile,
448 0, ¬esPageProperties.theme,
449 PptxXmlSlideReader::NotesMaster,
450 0,
451 0,
452 ¬esPageProperties,
453 *m_context->relationships,
454 d->commentAuthors,
455 dummyMap,
456 vmlreader,
457 QString()
458 );
459
460 PptxXmlSlideReader notesMasterReader(this);
461 context.firstReadingRound = true;
462 status = m_context->import->loadAndParseDocument(
463 ¬esMasterReader, notesMasterPath + '/' + notesMasterFile, &context);
464 if (status != KoFilter::OK) {
465 debugPptx << notesMasterReader.errorString();
466 return status;
467 }
468
469 context.initializeContext(notesPageProperties.theme, defaultParagraphStyles,
470 defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
471
472 // In this context we already have the real colorMap
473 context.firstReadingRound = false;
474
475 status = m_context->import->loadAndParseDocument(
476 ¬esMasterReader, notesMasterPath + '/' + notesMasterFile, &context);
477 if (status != KoFilter::OK) {
478 debugPptx << notesMasterReader.errorString();
479 return status;
480 }
481
482 d->notesMasterPageProperties.insert(notesMasterPathAndFile, notesPageProperties);
483
484 SKIP_EVERYTHING
485 READ_EPILOGUE
486 }
487
488 #undef CURRENT_EL
489 #define CURRENT_EL sldMasterId
490 //! p:sldMasterId (Slide Master ID)
491 /*! This element specifies a slide master that is available within the corresponding presentation.
492 A slide master is a slide that is specifically designed to be a template for all related child layout slides.
493
494 ECMA-376, 19.2.1.33, p. 2797.
495 Parent elements:
496 - [done] sldMasterIdLst (§19.2.1.37)
497 Child elements:
498 - extLst (Extension List) §19.2.1.12
499 */
read_sldMasterId()500 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldMasterId()
501 {
502 READ_PROLOGUE
503 const QXmlStreamAttributes attrs(attributes());
504 TRY_READ_ATTR_WITHOUT_NS(id)
505 READ_ATTR_WITH_NS(r, id)
506 debugPptx << "id:" << id << "r:id:" << r_id;
507
508 const QString slideMasterPathAndFile(m_context->relationships->target(m_context->path, m_context->file, r_id));
509 debugPptx << "slideMasterPathAndFile:" << slideMasterPathAndFile;
510
511 QString slideMasterPath, slideMasterFile;
512 MSOOXML::Utils::splitPathAndFile(slideMasterPathAndFile, &slideMasterPath, &slideMasterFile);
513
514 // Reading the slidemaster theme
515
516 PptxSlideProperties masterPageProperties;
517
518 const QString slideThemePathAndFile(m_context->relationships->targetForType(
519 slideMasterPath, slideMasterFile,
520 QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme"));
521 debugPptx << QLatin1String(MSOOXML::Schemas::officeDocument::relationships) + "/theme";
522 debugPptx << "slideThemePathAndFile:" << slideThemePathAndFile;
523
524 QString slideThemePath, slideThemeFile;
525 MSOOXML::Utils::splitPathAndFile(slideThemePathAndFile, &slideThemePath, &slideThemeFile);
526
527 MSOOXML::MsooXmlThemesReader themesReader(m_writers);
528 MSOOXML::MsooXmlThemesReaderContext themecontext(masterPageProperties.theme, m_context->relationships, m_context->import,
529 slideThemePath, slideThemeFile);
530
531 QString errorMessage;
532
533 KoFilter::ConversionStatus status
534 = m_context->import->loadAndParseDocument(&themesReader, slideThemePathAndFile, errorMessage, &themecontext);
535
536 //empty map used here as slideMaster is the place where the map is created
537 QMap<QString, QString> dummyMap;
538
539 VmlDrawingReader vmlreader(this);
540 QString vmlTarget = m_context->relationships->targetForType(slideMasterPath, slideMasterFile,
541 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing");
542
543 if (!vmlTarget.isEmpty()) {
544 QString errorMessage, vmlPath, vmlFile;
545
546 QString fileName = vmlTarget;
547 fileName.remove(0, m_context->path.length());
548 MSOOXML::Utils::splitPathAndFile(vmlTarget, &vmlPath, &vmlFile);
549
550 VmlDrawingReaderContext vmlContext(*m_context->import,
551 vmlPath, vmlFile, *m_context->relationships);
552
553 const KoFilter::ConversionStatus status =
554 m_context->import->loadAndParseDocument(&vmlreader, vmlTarget, errorMessage, &vmlContext);
555 if (status != KoFilter::OK) {
556 vmlreader.raiseError(errorMessage);
557 }
558 }
559
560 PptxXmlSlideReaderContext context(
561 *m_context->import,
562 slideMasterPath, slideMasterFile,
563 0/*unused*/, &masterPageProperties.theme,
564 PptxXmlSlideReader::SlideMaster,
565 0,
566 &masterPageProperties,
567 0,
568 *m_context->relationships,
569 d->commentAuthors,
570 dummyMap,
571 vmlreader,
572 QString()
573 );
574
575 PptxXmlSlideReader slideMasterReader(this);
576 context.firstReadingRound = true;
577 status = m_context->import->loadAndParseDocument(
578 &slideMasterReader, slideMasterPath + '/' + slideMasterFile, &context);
579 if (status != KoFilter::OK) {
580 debugPptx << slideMasterReader.errorString();
581 return status;
582 }
583
584 context.initializeContext(masterPageProperties.theme, defaultParagraphStyles,
585 defaultTextStyles, defaultListStyles, defaultBulletColors, defaultTextColors, defaultLatinFonts);
586
587 // In this context we already have the real colorMap
588 context.firstReadingRound = false;
589
590 status = m_context->import->loadAndParseDocument(
591 &slideMasterReader, slideMasterPath + '/' + slideMasterFile, &context);
592 if (status != KoFilter::OK) {
593 debugPptx << slideMasterReader.errorString();
594 return status;
595 }
596
597 d->slideMasterPageProperties.insert(slideMasterPathAndFile, masterPageProperties);
598 d->masterPageDrawStyleNames.push_back(context.pageDrawStyleName);
599 d->masterPageFrames += context.pageFrames;
600 debugPptx << "d->masterPageDrawStyleName:" << d->masterPageDrawStyleNames.back();
601 SKIP_EVERYTHING
602 READ_EPILOGUE
603 }
604
605 #undef CURRENT_EL
606 #define CURRENT_EL sldIdLst
607 //! p:sldIdLst handler (List of Slide IDs)
608 /*! ECMA-376, 19.2.1.34, p. 2798.
609 Parent elements:
610 - [done] presentation (§19.2.1.26)
611 Child elements:
612 - [done] sldId (Slide ID)
613 */
read_sldIdLst()614 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldIdLst()
615 {
616 READ_PROLOGUE
617 while (!atEnd()) {
618 readNext();
619 debugPptx << *this;
620 BREAK_IF_END_OF(CURRENT_EL)
621 if (isStartElement()) {
622 if (name() == "sldId") {
623 TRY_READ(sldId)
624 if (m_context->numberOfItems > 0) {
625 m_context->import->reportProgress(100 / m_context->numberOfItems);
626 m_context->numberOfItems = m_context->numberOfItems - 1;
627 }
628 }
629 ELSE_WRONG_FORMAT
630 }
631 }
632 READ_EPILOGUE
633 }
634
635 #undef CURRENT_EL
636 #define CURRENT_EL notesMasterIdLst
637 //! p:noteMasterIdLst handler (List of Note Master IDs)
638 /*!
639
640 Parent elements:
641 - [done] presentation (§19.2.1.26)
642
643 Child elements:
644 - [done] noteMasterId (Note Master ID) §19.2.1.36
645 */
read_notesMasterIdLst()646 KoFilter::ConversionStatus PptxXmlDocumentReader::read_notesMasterIdLst()
647 {
648 READ_PROLOGUE
649 while (!atEnd()) {
650 readNext();
651 BREAK_IF_END_OF(CURRENT_EL)
652 if (isStartElement()) {
653 if (name() == "notesMasterId") {
654 TRY_READ(notesMasterId)
655 if (m_context->numberOfItems > 0) {
656 m_context->import->reportProgress(100 / m_context->numberOfItems);
657 m_context->numberOfItems = m_context->numberOfItems - 1;
658 }
659 }
660 ELSE_WRONG_FORMAT
661 }
662 }
663
664 READ_EPILOGUE
665 }
666
667 #undef CURRENT_EL
668 #define CURRENT_EL sldMasterIdLst
669 //! p:sldMasterIdLst handler (List of Slide Master IDs)
670 /*! ECMA-376, 19.2.1.37, p. 2800
671 This element specifies a list of identification information for the slide master slides that
672 are available within the corresponding presentation. A slide master is a slide that
673 is specifically designed to be a template for all related child layout slides.
674
675 Parent elements:
676 - [done] presentation (§19.2.1.26)
677 Child elements:
678 - [done] sldMasterId (Slide Master ID) §19.2.1.36
679 */
read_sldMasterIdLst()680 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldMasterIdLst()
681 {
682 READ_PROLOGUE
683 while (!atEnd()) {
684 readNext();
685 BREAK_IF_END_OF(CURRENT_EL)
686 if (isStartElement()) {
687 if (name() == "sldMasterId") {
688 TRY_READ(sldMasterId)
689 if (m_context->numberOfItems > 0) {
690 m_context->import->reportProgress(100 / m_context->numberOfItems);
691 m_context->numberOfItems = m_context->numberOfItems - 1;
692 }
693 }
694 ELSE_WRONG_FORMAT
695 }
696 }
697
698 READ_EPILOGUE
699 }
700
701 #undef CURRENT_EL
702 #define CURRENT_EL notesSz
703 //! p:noteSz handler
704 /*!
705
706 Parent elements:
707 - [done] presentation (§19.2.1.26)
708
709 No child elements.
710 */
read_notesSz()711 KoFilter::ConversionStatus PptxXmlDocumentReader::read_notesSz()
712 {
713 READ_PROLOGUE
714 const QXmlStreamAttributes attrs(attributes());
715 READ_ATTR_WITHOUT_NS(cx)
716 READ_ATTR_WITHOUT_NS(cy)
717 int intCx = 0;
718 int intCy = 0;
719 STRING_TO_INT(cx, intCx, "notesSz@cx")
720 STRING_TO_INT(cy, intCy, "notesSz@cy")
721 //! @todo check "type" attr, e.g. 4x3
722
723 d->notePageLayout.width = EMU_TO_POINT(qreal(intCx));
724 d->notePageLayout.height = EMU_TO_POINT(qreal(intCy));
725 d->notePageLayout.leftMargin = 0.0;
726 d->notePageLayout.rightMargin = 0.0;
727 d->notePageLayout.topMargin = 0.0;
728 d->notePageLayout.bottomMargin = 0.0;
729
730 d->notePageLayout.orientation = d->notePageLayout.width > d->notePageLayout.height
731 ? KoPageFormat::Landscape : KoPageFormat::Portrait;
732
733 readNext();
734
735 d->noteSzRead = true;
736 READ_EPILOGUE
737 }
738
739 #undef CURRENT_EL
740 #define CURRENT_EL sldSz
741 //! p:sldSz handler (Presentation)
742 /*! ECMA-376, 19.2.1.39, p. 2801.
743 This element specifies the size of the presentation slide surface.
744
745 Parent elements:
746 - [done] presentation (§19.2.1.26)
747
748 No child elements.
749 */
read_sldSz()750 KoFilter::ConversionStatus PptxXmlDocumentReader::read_sldSz()
751 {
752 READ_PROLOGUE
753 const QXmlStreamAttributes attrs(attributes());
754 READ_ATTR_WITHOUT_NS(cx)
755 READ_ATTR_WITHOUT_NS(cy)
756 int intCx = 0;
757 int intCy = 0;
758 STRING_TO_INT(cx, intCx, "sldSz@cx")
759 STRING_TO_INT(cy, intCy, "sldSz@cy")
760 //! @todo check "type" attr, e.g. 4x3
761
762 d->pageLayout.width = EMU_TO_POINT(qreal(intCx));
763 d->pageLayout.height = EMU_TO_POINT(qreal(intCy));
764 d->pageLayout.leftMargin = 0.0;
765 d->pageLayout.rightMargin = 0.0;
766 d->pageLayout.topMargin = 0.0;
767 d->pageLayout.bottomMargin = 0.0;
768 //! @todo orientation heuristics - OK?
769 d->pageLayout.orientation = d->pageLayout.width > d->pageLayout.height
770 ? KoPageFormat::Landscape : KoPageFormat::Portrait;
771
772 readNext();
773
774 d->sldSzRead = true;
775 READ_EPILOGUE
776 }
777
778 //! defaultTextStyle (Presentation Default Text Style)
779 /*! ECMA-376, 19.2.1.8, p. 2773.
780
781 This element specifies the default text styles that are to be used within the
782 presentation. The text style defined here can be referenced when inserting a
783 new slide if that slide is not associated with a master slide or if no styling
784 information has been otherwise specified for the text within the presentation
785 slide.
786
787 Parent element:
788 - [done] presentation (§19.2.1.26)
789
790 Child elements:
791 - defPPr (§21.1.2.2.2)
792 - extLst (§20.1.2.2.15)
793 - [done] lvl1pPr (§21.1.2.4.13)
794 - [done] lvl2pPr (§21.1.2.4.14)
795 - [done] lvl3pPr (§21.1.2.4.15)
796 - [done] lvl4pPr (§21.1.2.4.16)
797 - [done] lvl5pPr (§21.1.2.4.17)
798 - [done] lvl6pPr (§21.1.2.4.18)
799 - [done] lvl7pPr (§21.1.2.4.19)
800 - [done] lvl8pPr (§21.1.2.4.20)
801 - [done] lvl9pPr (§21.1.2.4.21)
802 */
803 #undef CURRENT_EL
804 #define CURRENT_EL defaultTextStyle
read_defaultTextStyle()805 KoFilter::ConversionStatus PptxXmlDocumentReader::read_defaultTextStyle()
806 {
807 READ_PROLOGUE
808 m_currentListStyle = KoGenStyle(KoGenStyle::ListStyle);
809
810 while (!atEnd()) {
811 readNext();
812 debugPptx << *this;
813 BREAK_IF_END_OF(CURRENT_EL)
814 if (isStartElement()) {
815 // Initializing the default style for the level. At the end, there
816 // should be 9 levels
817 if (qualifiedName().toString().startsWith(QLatin1String("a:lvl"))) {
818 defaultTextColors.push_back(QString());
819 defaultLatinFonts.push_back(QString());
820 defaultBulletColors.push_back(QString());
821 }
822 }
823 if (isStartElement()) {
824 TRY_READ_IF_NS(a, lvl1pPr)
825 ELSE_TRY_READ_IF_NS(a, lvl2pPr)
826 ELSE_TRY_READ_IF_NS(a, lvl3pPr)
827 ELSE_TRY_READ_IF_NS(a, lvl4pPr)
828 ELSE_TRY_READ_IF_NS(a, lvl5pPr)
829 ELSE_TRY_READ_IF_NS(a, lvl6pPr)
830 ELSE_TRY_READ_IF_NS(a, lvl7pPr)
831 ELSE_TRY_READ_IF_NS(a, lvl8pPr)
832 ELSE_TRY_READ_IF_NS(a, lvl9pPr)
833 //! @todo add ELSE_WRONG_FORMAT
834 }
835 if (isEndElement()) {
836 if (qualifiedName().toString().startsWith(QLatin1String("a:lvl"))) {
837 defaultParagraphStyles.push_back(m_currentParagraphStyle);
838 defaultTextStyles.push_back(m_currentTextStyle);
839 defaultListStyles.push_back(m_currentBulletProperties);
840 }
841 }
842 }
843
844 READ_EPILOGUE
845 }
846
847 #undef CURRENT_EL
848 #define CURRENT_EL presentation
849 //! p:presentation handler (Presentation)
850 /*! ECMA-376, 19.2.1.26, p. 2790.
851 Root element.
852 Child elements:
853 - ustDataLst (Customer Data List) §19.3.1.18
854 - custShowLst (List of Custom Shows) §19.2.1.7
855 - [done] defaultTextStyle (Presentation Default Text Style) §19.2.1.8
856 - embeddedFontLst (Embedded Font List) §19.2.1.10
857 - extLst (Extension List) §19.2.1.12
858 - handoutMasterIdLst (List of Handout Master IDs) §19.2.1.15
859 - kinsoku (Kinsoku Settings) §19.2.1.17
860 - modifyVerifier (Modification Verifier) §19.2.1.19
861 - [done] notesMasterIdLst (List of Notes Master IDs) §19.2.1.21
862 - [done] notesSz (Notes Slide Size) §19.2.1.22
863 - photoAlbum (Photo Album Information) §19.2.1.24
864 - [done] sldIdLst (List of Slide IDs) §19.2.1.34
865 - [done] sldMasterIdLst (List of Slide Master IDs) §19.2.1.37
866 - [done] sldSz (Presentation Slide Size) §19.2.1.39
867 - smartTags (Smart Tags) §19.2.1.40
868 */
869 //! @todo support all child elements
read_presentation()870 KoFilter::ConversionStatus PptxXmlDocumentReader::read_presentation()
871 {
872 READ_PROLOGUE
873
874 QXmlStreamNamespaceDeclarations namespaces = namespaceDeclarations();
875 for (int i = 0; i < namespaces.count(); i++) {
876 debugPptx << "NS prefix:" << namespaces[i].prefix() << "uri:" << namespaces[i].namespaceUri();
877 }
878
879 if (!m_context->firstReadRound) {
880 debugPptx << "======> Second reading round <======";
881 while (!atEnd()) {
882 readNext();
883 debugPptx << *this;
884 BREAK_IF_END_OF(CURRENT_EL)
885 if (isStartElement()) {
886 TRY_READ_IF(sldMasterIdLst)
887 ELSE_TRY_READ_IF(sldIdLst)
888 ELSE_TRY_READ_IF(sldSz)
889 ELSE_TRY_READ_IF(notesMasterIdLst)
890 ELSE_TRY_READ_IF(notesSz)
891 SKIP_UNKNOWN
892 //! @todo add ELSE_WRONG_FORMAT
893 }
894 }
895 }
896 else {
897 while (!atEnd()) {
898 readNext();
899 BREAK_IF_END_OF(CURRENT_EL)
900 if (isStartElement()) {
901 TRY_READ_IF(defaultTextStyle)
902 SKIP_UNKNOWN
903 }
904 }
905 // TODO: Discuss the font-size logic in case it's not provided in the
906 // presentation at the Office Open XML File Format Implementation
907 // forum. The 18pt value is a result of test files analysis.
908 KoGenStyle style(KoGenStyle::ParagraphStyle, "paragraph");
909 style.setDefaultStyle(true);
910 style.addPropertyPt("fo:font-size", 18, KoGenStyle::TextType);
911
912 // TODO: Add all defaults defined by the spec. Values defined by
913 // defaultTextStyle/defPPr come on top.
914 style.addPropertyPt("fo:margin-left", EMU_TO_POINT(347663));
915 style.addPropertyPt("fo:margin-top", 0);
916 style.addPropertyPt("fo:margin-right", 0);
917 style.addPropertyPt("fo:margin-bottom", 0);
918 style.addPropertyPt("fo:text-indent", EMU_TO_POINT(-342900));
919
920 mainStyles->insert(style);
921
922 style = KoGenStyle(KoGenStyle::TextStyle, "text");
923 style.setDefaultStyle(true);
924 style.addPropertyPt("fo:font-size", 18, KoGenStyle::TextType);
925 mainStyles->insert(style);
926 }
927
928 if (!m_context->firstReadRound) {
929 // There are double the amount of masterPage frames because we read slideMaster always twice
930 // This means that first frame of the set is always empty and is skipped in the loop
931 unsigned frameCount = d->masterPageFrames.size() / 2;
932 unsigned index = 0;
933 while (index < frameCount) {
934 d->masterPageStyles.push_back(KoGenStyle(KoGenStyle::MasterPageStyle));
935 if (d->sldSzRead) {
936 KoGenStyle pageLayoutStyle(d->pageLayout.saveOdf());
937 pageLayoutStyle.setAutoStyleInStylesDotXml(true);
938 const QString pageLayoutStyleName(mainStyles->insert(pageLayoutStyle, "PM"));
939 debugPptx << "pageLayoutStyleName:" << pageLayoutStyleName;
940
941 d->masterPageStyles[index].addAttribute("style:page-layout-name", pageLayoutStyleName);
942 }
943 if (!d->masterPageDrawStyleNames.at(index).isEmpty()) {
944 d->masterPageStyles[index].addAttribute("draw:style-name", d->masterPageDrawStyleNames.at(index));
945 }
946 d->masterPageStyles[index].addChildElement(QString("frame-2-%1").arg(index), d->masterPageFrames.at((1+index)*2-1));
947 const QString masterPageStyleName(mainStyles->insert(d->masterPageStyles.at(index), "slideMaster"));
948 ++index;
949 }
950 } else {
951 m_context->numberOfItems = m_context->relationships->targetCountWithWord("slideMasters") +
952 m_context->relationships->targetCountWithWord("notesMasters") +
953 m_context->relationships->targetCountWithWord("slides");
954 }
955
956 READ_EPILOGUE
957 }
958
959 #define blipFill_NS "a"
960
961 // END NAMESPACE p
962
963 // BEGIN NAMESPACE a
964
965 #undef MSOOXML_CURRENT_NS
966 #define MSOOXML_CURRENT_NS "a"
967
968 #include <MsooXmlCommonReaderImpl.h> // this adds a:p, a:pPr, a:t, a:r, etc.
969
970 #define DRAWINGML_NS "a"
971 #define DRAWINGML_PIC_NS "p" // DrawingML/Picture
972
973 #include <MsooXmlCommonReaderDrawingMLImpl.h> // this adds p:pic, etc.
974