1 /* This file is part of the KDE project
2 
3    Copyright (C) 2012-2013 Inge Wallin            <inge@lysator.liu.se>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19 */
20 
21 
22 // Own
23 #include "OdfTextReader.h"
24 
25 // Qt
26 #include <QStringList>
27 #include <QBuffer>
28 
29 // KF5
30 #include <klocalizedstring.h>
31 
32 // Calligra
33 #include <KoStore.h>
34 #include <KoXmlStreamReader.h>
35 #include <KoXmlNS.h>
36 #include <KoXmlWriter.h>  // For copyXmlElement
37 #include <KoOdfReadStore.h>
38 
39 // Reader library
40 #include "OdfReader.h"
41 #include "OdfDrawReaderBackend.h"
42 #include "OdfReaderContext.h"
43 #include "OdfReaderDebug.h"
44 
45 
46 #if 1
47 static int debugIndent = 0;
48 #define DEBUGSTART() \
49     ++debugIndent; \
50     DEBUG_READING("entering")
51 #define DEBUGEND() \
52     DEBUG_READING("exiting"); \
53     --debugIndent
54 #define DEBUG_READING(param) \
55     debugOdfReader << QString("%1").arg(" ", debugIndent * 2) << param << ": " \
56     << (reader.isStartElement() ? "start": (reader.isEndElement() ? "end" : "other")) \
57     << reader.qualifiedName().toString()
58 #else
59 #define DEBUGSTART() \
60     // NOTHING
61 #define DEBUGEND() \
62     // NOTHING
63 #define DEBUG_READING(param) \
64     // NOTHING
65 #endif
66 
67 
OdfDrawReader()68 OdfDrawReader::OdfDrawReader()
69     : m_parent(0)
70     , m_backend(0)
71     , m_context(0)
72 {
73 }
74 
~OdfDrawReader()75 OdfDrawReader::~OdfDrawReader()
76 {
77 }
78 
79 
80 // ----------------------------------------------------------------
81 //                             setters
82 
83 
setParent(OdfReader * parent)84 void OdfDrawReader::setParent(OdfReader *parent)
85 {
86     m_parent = parent;
87 }
88 
setBackend(OdfDrawReaderBackend * backend)89 void OdfDrawReader::setBackend(OdfDrawReaderBackend *backend)
90 {
91     m_backend = backend;
92 }
93 
setContext(OdfReaderContext * context)94 void OdfDrawReader::setContext(OdfReaderContext *context)
95 {
96     m_context = context;
97 }
98 
99 
100 // ----------------------------------------------------------------
101 //                         namespace dr3d
102 
103 
readElementDr3dScene(KoXmlStreamReader & reader)104 void OdfDrawReader::readElementDr3dScene(KoXmlStreamReader &reader)
105 {
106    DEBUGSTART();
107     m_backend->elementDr3dScene(reader, m_context);
108 
109     // <dr3d:scene> has the following children in ODF 1.2:
110     //   [done] <dr3d:cube> 10.5.4
111     //   [done] <dr3d:extrude> 10.5.6
112     //   [done] <dr3d:light> 10.5.3
113     //   [done] <dr3d:rotate> 10.5.7
114     //   [done] <dr3d:scene> 10.5.2
115     //   [done] <dr3d:sphere> 10.5.5
116 
117     //          <draw:glue-point> 10.3.16
118     //          <svg:desc> 10.3.18
119     //          <svg:title> 10.3.17.
120     //
121     while (reader.readNextStartElement()) {
122         QString tagName = reader.qualifiedName().toString();
123 
124         if (tagName == "dr3d:cube") {
125 	    readElementDr3dCube(reader);
126         }
127         else if (tagName == "dr3d:extrude") {
128 	    readElementDr3dExtrude(reader);
129         }
130         else if (tagName == "dr3d:light") {
131 	    readElementDr3dLight(reader);
132         }
133         else if (tagName == "dr3d:rotate") {
134 	    readElementDr3dRotate(reader);
135         }
136         else if (tagName == "dr3d:scene") {
137 	    readElementDr3dScene(reader);
138         }
139         else if (tagName == "dr3d:sphere") {
140 	    readElementDr3dSphere(reader);
141         }
142         //...  MORE else if () HERE
143         else {
144             reader.skipCurrentElement();
145         }
146     }
147 
148     m_backend->elementDr3dScene(reader, m_context);
149     DEBUGEND();
150 }
151 
IMPLEMENT_READER_FUNCTION_NO_CHILDREN(OdfDrawReader,Dr3dLight)152 IMPLEMENT_READER_FUNCTION_NO_CHILDREN(OdfDrawReader, Dr3dLight)   // ODF 1.2  10.5.3
153 IMPLEMENT_READER_FUNCTION_NO_CHILDREN(OdfDrawReader, Dr3dCube)    // ODF 1.2  10.5.4
154 IMPLEMENT_READER_FUNCTION_NO_CHILDREN(OdfDrawReader, Dr3dSphere)  // ODF 1.2  10.5.5
155 IMPLEMENT_READER_FUNCTION_NO_CHILDREN(OdfDrawReader, Dr3dExtrude) // ODF 1.2  10.5.6
156 IMPLEMENT_READER_FUNCTION_NO_CHILDREN(OdfDrawReader, Dr3dRotate)  // ODF 1.2  10.5.7
157 
158 
159 // ================================================================
160 //                         namespace draw
161 
162 
163 // ----------------------------------------------------------------
164 
165 
166 #if 0
167 // This is a template function for the reader library.
168 // Copy this one and change the name and fill in the code.
169 void OdfDrawReader::readElementNamespaceTagname(KoXmlStreamReader &reader)
170 {
171    DEBUGSTART();
172     m_backend->elementNamespaceTagname(reader, m_context);
173 
174     // <namespace:tagname> has the following children in ODF 1.2:
175     //   FILL IN THE CHILDREN LIKE THIS EXAMPLE (taken from office:document-content):
176     //          <office:automatic-styles> 3.15.3
177     //          <office:body> 3.3
178     //          <office:font-face-decls> 3.14
179     //          <office:scripts> 3.12.
180     while (reader.readNextStartElement()) {
181         QString tagName = reader.qualifiedName().toString();
182 
183         if (tagName == "office:automatic-styles") {
184             // FIXME: NYI
185             reader.skipCurrentElement();
186         }
187         else if (tagName == "office:body") {
188             readElementOfficeBody(reader);
189         }
190         ...  MORE else if () HERE
191         else {
192             reader.skipCurrentElement();
193         }
194     }
195 
196     m_backend->elementNamespaceTagname(reader, m_context);
197     DEBUGEND();
198 }
199 #endif
200 
201 
202 void OdfDrawReader::readCommonGraphicsElements(KoXmlStreamReader &reader)
203 {
204     DEBUGSTART();
205 
206     // This is a function common to all draw elements so no backend function
207     // should be called here.
208 
209     // The common graphics elements are:
210     //   [done] <dr3d:scene> 10.5.2
211     //   [done] <draw:a> 10.4.12
212     //   [done] <draw:caption> 10.3.11
213     //   [done] <draw:circle> 10.3.8
214     //   [done] <draw:connector> 10.3.10
215     //          <draw:control> 10.3.13
216     //          <draw:custom-shape> 10.6.1
217     //   [done] <draw:ellipse> 10.3.9
218     //   [done] <draw:frame> 10.4.2
219     //          <draw:g> 10.3.15
220     //   [done] <draw:line> 10.3.3
221     //   [done] <draw:measure> 10.3.12
222     //          <draw:page-thumbnail> 10.3.14
223     //   [path] <draw:path> 10.3.7
224     //   [done] <draw:polygon> 10.3.5
225     //   [done] <draw:polyline> 10.3.4
226     //   [done] <draw:rect> 10.3.2
227     //   [done] <draw:regular-polygon> 10.3.6
228 
229     QString tagName = reader.qualifiedName().toString();
230     //debugOdfReader << "list child:" << tagName;
231     if (tagName == "dr3d:scene") {
232 	readElementDr3dScene(reader);
233     }
234     else if (tagName == "draw:a") {
235 	readElementDrawA(reader);
236     }
237     else if (tagName == "draw:caption") {
238 	readElementDrawCaption(reader);
239     }
240     else if (tagName == "draw:circle") {
241 	readElementDrawCircle(reader);
242     }
243     else if (tagName == "draw:connector") {
244 	readElementDrawConnector(reader);
245     }
246     else if (tagName == "draw:ellipse") {
247 	readElementDrawEllipse(reader);
248     }
249     else if (tagName == "draw:frame") {
250 	readElementDrawFrame(reader);
251     }
252     else if (tagName == "draw:line") {
253 	readElementDrawLine(reader);
254     }
255     else if (tagName == "draw:measure") {
256 	readElementDrawMeasure(reader);
257     }
258     else if (tagName == "draw:path") {
259 	readElementDrawPath(reader);
260     }
261     else if (tagName == "draw:polygon") {
262 	readElementDrawPolygon(reader);
263     }
264     else if (tagName == "draw:polyline") {
265 	readElementDrawPolyline(reader);
266     }
267     else if (tagName == "draw:rect") {
268 	readElementDrawRect(reader);
269     }
270     else if (tagName == "draw:regular-polygon") {
271 	readElementDrawRegularPolygon(reader);
272     }
273     else {
274 	// FIXME: Should this perhaps be skipCurrentElement()?
275 	readUnknownElement(reader);
276     }
277 
278     DEBUGEND();
279 }
280 
readElementDrawA(KoXmlStreamReader & reader)281 void OdfDrawReader::readElementDrawA(KoXmlStreamReader &reader)
282 {
283     DEBUGSTART();
284     m_backend->elementDrawA(reader, m_context);
285 
286     // <draw:a> has all the normal drawing children.
287     readCommonGraphicsElements(reader);
288 
289     m_backend->elementDrawA(reader, m_context);
290     DEBUGEND();
291 }
292 
293 
294 #define IMPLEMENT_GRAPHIC_OBJECT(object)                                \
295 void OdfDrawReader::readElementDraw##object(KoXmlStreamReader &reader)  \
296 {                                                                       \
297     DEBUGSTART();                                                       \
298     m_backend->elementDraw##object(reader, m_context);                  \
299                                                                         \
300     readGraphicsObjectChildren(reader);                                 \
301                                                                         \
302     m_backend->elementDraw##object(reader, m_context);                  \
303     DEBUGEND();                                                         \
304 }
305 
306 IMPLEMENT_GRAPHIC_OBJECT(Rect)            // ODF 1.2  10.3.2
IMPLEMENT_GRAPHIC_OBJECT(Line)307 IMPLEMENT_GRAPHIC_OBJECT(Line)		  // ODF 1.2  10.3.3
308 IMPLEMENT_GRAPHIC_OBJECT(Polyline)	  // ODF 1.2  10.3.4
309 IMPLEMENT_GRAPHIC_OBJECT(Polygon)	  // ODF 1.2  10.3.5
310 IMPLEMENT_GRAPHIC_OBJECT(RegularPolygon)  // ODF 1.2  10.3.6
311 IMPLEMENT_GRAPHIC_OBJECT(Path)		  // ODF 1.2  10.3.7
312 IMPLEMENT_GRAPHIC_OBJECT(Circle)	  // ODF 1.2  10.3.8
313 IMPLEMENT_GRAPHIC_OBJECT(Ellipse)	  // ODF 1.2  10.3.9
314 IMPLEMENT_GRAPHIC_OBJECT(Connector)	  // ODF 1.2  10.3.10
315 IMPLEMENT_GRAPHIC_OBJECT(Caption)	  // ODF 1.2  10.3.11
316 IMPLEMENT_GRAPHIC_OBJECT(Measure)	  // ODF 1.2  10.3.12
317 
318 
319 void OdfDrawReader::readGraphicsObjectChildren(KoXmlStreamReader &reader)
320 {
321     // No backend calls in this function
322 
323     // <draw:circle>, <draw:rect>, etc have the following children in ODF 1.2:
324     //          <draw:glue-point> 10.3.16
325     //          <office:event-listeners> 10.3.19
326     //          <svg:desc> 10.3.18
327     //          <svg:title> 10.3.17
328     //   [done] <text:list> 5.3.1
329     //   [done] <text:p> 5.1.3.
330     while (reader.readNextStartElement()) {
331         QString tagName = reader.qualifiedName().toString();
332 
333         if (tagName == "draw:glue-point") {
334             // FIXME: NYI
335             reader.skipCurrentElement();
336             //readElementOfficeDrawGluePoint(reader);
337         }
338         else if (tagName == "office:event-listeners") {
339             // FIXME: NYI
340             reader.skipCurrentElement();
341             //readElementOfficeEventListeners(reader);
342         }
343         else if (reader.prefix() == "svg") {
344 	    if (tagName == "svg:desc") {
345 		// FIXME: NYI
346 		reader.skipCurrentElement();
347 		//readElementSvgDesc(reader);
348 	    }
349 	    else if (tagName == "svg:title") {
350 		// FIXME: NYI
351 		reader.skipCurrentElement();
352 		//readElementSvgTitle(reader);
353 	    }
354 	    else {
355 		reader.skipCurrentElement();
356 	    }
357         } // namespace svg
358         else if (reader.prefix() == "text") {
359 	    OdfTextReader *textReader = m_parent->textReader();
360 	    if (!textReader) {
361 		reader.skipCurrentElement();
362 	    }
363 	    else if (tagName == "text:list") {
364 		textReader->readElementTextList(reader);
365 	    }
366 	    else if (tagName == "text:p") {
367 		textReader->readElementTextP(reader);
368 	    }
369 	    else {
370 		reader.skipCurrentElement();
371 	    }
372         } // namespace text
373         else {
374             reader.skipCurrentElement();
375         }
376     }
377 }
378 
379 
380 // ----------------------------------------------------------------
381 //                                 Frames
382 
383 
readElementDrawFrame(KoXmlStreamReader & reader)384 void OdfDrawReader::readElementDrawFrame(KoXmlStreamReader &reader)
385 {
386     DEBUGSTART();
387     m_backend->elementDrawFrame(reader, m_context);
388 
389     // <draw:frame> has the following children in ODF 1.2:
390     //          <draw:applet> 10.4.7
391     //          <draw:contour-path> 10.4.11.3
392     //          <draw:contour-polygon> 10.4.11.2
393     //          <draw:floating-frame> 10.4.10
394     //          <draw:glue-point> 10.3.16
395     //          <draw:image> 10.4.4
396     //          <draw:image-map> 10.4.13.2
397     //   [done] <draw:object> 10.4.6.2
398     //   [done] <draw:object-ole> 10.4.6.3
399     //          <draw:plugin> 10.4.8
400     //          <draw:text-box> 10.4.3
401     //          <office:event-listeners> 10.3.19
402     //          <svg:desc> 10.3.18
403     //          <svg:title> 10.3.17
404     //   [done] <table:table> 9.1.2
405     //
406     while (reader.readNextStartElement()) {
407         QString tagName = reader.qualifiedName().toString();
408 
409         if (tagName == "draw:image") {
410             // FIXME: NYI
411             reader.skipCurrentElement();
412         }
413         else if (tagName == "draw:object") {
414 	    readElementDrawObject(reader);
415         }
416         else if (tagName == "draw:object-ole") {
417 	    readElementDrawObjectOle(reader);
418         }
419         //...  MORE else if () HERE
420         else if (tagName == "table:table") {
421 	    OdfTextReader *textReader = m_parent->textReader();
422 	    if (textReader) {
423 		textReader->readElementTableTable(reader);
424 	    }
425 	    else {
426 		reader.skipCurrentElement();
427 	    }
428         }
429         else {
430             reader.skipCurrentElement();
431         }
432     }
433 
434     m_backend->elementDrawFrame(reader, m_context);
435     DEBUGEND();
436 }
437 
readElementDrawObject(KoXmlStreamReader & reader)438 void OdfDrawReader::readElementDrawObject(KoXmlStreamReader &reader)
439 {
440    DEBUGSTART();
441     m_backend->elementDrawObject(reader, m_context);
442 
443     // <draw:object> has the following children in ODF 1.2:
444     //          <math:math> 14.5
445     //          <office:document> 3.1.2
446     while (reader.readNextStartElement()) {
447         QString tagName = reader.qualifiedName().toString();
448 
449         if (tagName == "math:math") {
450             // FIXME: NYI
451             reader.skipCurrentElement();
452         }
453         else if (tagName == "office:document") {
454             // FIXME: NYI
455             reader.skipCurrentElement();
456         }
457         else {
458 	    // Shouldn't happen.
459             reader.skipCurrentElement();
460         }
461     }
462 
463     m_backend->elementDrawObject(reader, m_context);
464     DEBUGEND();
465 }
466 
readElementDrawObjectOle(KoXmlStreamReader & reader)467 void OdfDrawReader::readElementDrawObjectOle(KoXmlStreamReader &reader)
468 {
469    DEBUGSTART();
470     m_backend->elementDrawObjectOle(reader, m_context);
471 
472     // <draw:object-ole> has the following children in ODF 1.2:
473     //          <office:binary-data> 10.4.5
474     while (reader.readNextStartElement()) {
475         QString tagName = reader.qualifiedName().toString();
476 
477 	if (tagName == "office:binary-data") {
478             // FIXME: NYI
479             reader.skipCurrentElement();
480         }
481         else {
482 	    // Shouldn't happen.
483             reader.skipCurrentElement();
484         }
485     }
486 
487     m_backend->elementDrawObjectOle(reader, m_context);
488     DEBUGEND();
489 }
490 
491 
492 // ----------------------------------------------------------------
493 //                             Other functions
494 
495 
readUnknownElement(KoXmlStreamReader & reader)496 void OdfDrawReader::readUnknownElement(KoXmlStreamReader &reader)
497 {
498     DEBUGSTART();
499 
500 #if 0  // FIXME: Fix this
501     if (m_context->isInsideParagraph()) {
502         // readParagraphContents expect to have the reader point to the
503         // contents of the paragraph so we have to read past the draw:p
504         // start tag here.
505         reader.readNext();
506         readParagraphContents(reader);
507     }
508     else {
509         while (reader.readNextStartElement()) {
510             readTextLevelElement(reader);
511         }
512     }
513 #else
514     reader.skipCurrentElement();
515 #endif
516 
517     DEBUGEND();
518 }
519