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, libodf{,2}
33 #include <KoXmlNS.h>
34 #include <KoXmlStreamReader.h>
35 #include <KoXmlUtils.h>
36 
37 // Reader library
38 #include "OdfReader.h"
39 #include "OdfTextReaderBackend.h"
40 #include "OdfReaderContext.h"
41 #include "OdfDrawReader.h"
42 #include "OdfReaderDebug.h"
43 
44 
45 #if 1
46 static int debugIndent = 0;
47 #define DEBUGSTART() \
48     ++debugIndent; \
49     DEBUG_READING("entering")
50 #define DEBUGEND() \
51     DEBUG_READING("exiting"); \
52     --debugIndent
53 #define DEBUG_READING(param) \
54     debugOdfReader << QString("%1").arg(" ", debugIndent * 2) << param << ": " \
55     << (reader.isStartElement() ? "start": (reader.isEndElement() ? "end" : "other")) \
56     << reader.qualifiedName().toString()
57 #else
58 #define DEBUGSTART() \
59     // NOTHING
60 #define DEBUGEND() \
61     // NOTHING
62 #define DEBUG_READING(param) \
63     // NOTHING
64 #endif
65 
66 
OdfTextReader()67 OdfTextReader::OdfTextReader()
68     : m_parent(0)
69     , m_backend(0)
70     , m_context(0)
71 {
72 }
73 
~OdfTextReader()74 OdfTextReader::~OdfTextReader()
75 {
76 }
77 
78 
79 // ----------------------------------------------------------------
80 
81 
setParent(OdfReader * parent)82 void OdfTextReader::setParent(OdfReader *parent)
83 {
84     m_parent = parent;
85 }
86 
setBackend(OdfTextReaderBackend * backend)87 void OdfTextReader::setBackend(OdfTextReaderBackend *backend)
88 {
89     m_backend = backend;
90 }
91 
setContext(OdfReaderContext * context)92 void OdfTextReader::setContext(OdfReaderContext *context)
93 {
94     m_context = context;
95 }
96 
97 
98 // ----------------------------------------------------------------
99 
100 
101 #if 0
102 // This is a template function for the reader library.
103 // Copy this one and change the name and fill in the code.
104 void OdfTextReader::readElementNamespaceTagname(KoXmlStreamReader &reader)
105 {
106    DEBUGSTART();
107     m_backend->elementNamespaceTagname(reader, m_context);
108 
109     // <namespace:tagname> has the following children in ODF 1.2:
110     //   FILL IN THE CHILDREN LIKE THIS EXAMPLE (taken from office:document-content):
111     //          <office:automatic-styles> 3.15.3
112     //          <office:body> 3.3
113     //          <office:font-face-decls> 3.14
114     //          <office:scripts> 3.12.
115     while (reader.readNextStartElement()) {
116         QString tagName = reader.qualifiedName().toString();
117 
118         if (tagName == "office:automatic-styles") {
119             // FIXME: NYI
120             reader.skipCurrentElement();
121         }
122         else if (tagName == "office:body") {
123             readElementOfficeBody(reader);
124         }
125         ...  MORE else if () HERE
126         else {
127             reader.skipCurrentElement();
128         }
129     }
130 
131     m_backend->elementNamespaceTagname(reader, m_context);
132     DEBUGEND();
133 }
134 #endif
135 
136 
137 
138 
139 // ----------------------------------------------------------------
140 //                         Text level functions
141 
142 
143 // This function is a bit special since it doesn't handle a specific
144 // element.  Instead it handles the common child elements between a
145 // number of text-level elements.
146 //
readTextLevelElement(KoXmlStreamReader & reader)147 void OdfTextReader::readTextLevelElement(KoXmlStreamReader &reader)
148 {
149     DEBUGSTART();
150 
151     // We should not call any backend functions here.  That is already
152     // done in the functions that call this one.
153 
154     // We define the common elements on the text level as the
155     // following list.  They are the basic text level contents that
156     // can be found in a text box (<draw:text-box>) but also in many
157     // other places like <table:table-cell>, <text:section>,
158     // <office:text>, etc.
159     //
160     // The ones that are not text boxes can also have other children
161     // but these are the ones we have found to be the common ones.
162     //
163     //          <dr3d:scene> 10.5.2
164     //          <draw:a> 10.4.12
165     //          <draw:caption> 10.3.11
166     //          <draw:circle> 10.3.8
167     //          <draw:connector> 10.3.10
168     //          <draw:control> 10.3.13
169     //          <draw:custom-shape> 10.6.1
170     //          <draw:ellipse> 10.3.9
171     //          <draw:frame> 10.4.2
172     //          <draw:g> 10.3.15
173     //          <draw:line> 10.3.3
174     //          <draw:measure> 10.3.12
175     //          <draw:page-thumbnail> 10.3.14
176     //          <draw:path> 10.3.7
177     //          <draw:polygon> 10.3.5
178     //          <draw:polyline> 10.3.4
179     //          <draw:rect> 10.3.2
180     //          <draw:regular-polygon> 10.3.6
181     // All of the above are sent to the draw reader.
182     //
183     //   [done] <table:table> 9.1.2
184     //          <text:alphabetical-index> 8.8
185     //          <text:bibliography> 8.9
186     //          <text:change> 5.5.7.4
187     //          <text:change-end> 5.5.7.3
188     //          <text:change-start> 5.5.7.2
189     //   [done] <text:h> 5.1.2
190     //          <text:illustration-index> 8.4
191     //   [done] <text:list> 5.3.1
192     //          <text:numbered-paragraph> 5.3.6
193     //          <text:object-index> 8.6
194     //   [done] <text:p> 5.1.3
195     //          <text:section> 5.4
196     //   [done] <text:soft-page-break> 5.6
197     //          <text:table-index> 8.5
198     //          <text:table-of-content> 8.3
199     //          <text:user-index> 8.7
200 
201     QString tagName = reader.qualifiedName().toString();
202 
203     if (reader.prefix() == "draw" || reader.prefix() == "dr3d") {
204 	OdfDrawReader *drawReader = m_parent->drawReader();
205 	if (drawReader) {
206 	    drawReader->readCommonGraphicsElements(reader);
207 	}
208 	else {
209 	    reader.skipCurrentElement();
210 	}
211     } // draw | dr3d namespace
212     else if (tagName == "text:h") {
213         readElementTextH(reader);
214     }
215     else if (tagName == "text:p") {
216         readElementTextP(reader);
217     }
218     else if (tagName == "text:list") {
219         readElementTextList(reader);
220     }
221     else if (tagName == "table:table") {
222         readElementTableTable(reader);
223     }
224     else if (tagName == "text:soft-page-break") {
225         readElementTextSoftPageBreak(reader);
226     }
227     else {
228         readUnknownElement(reader);
229     }
230 
231     DEBUGEND();
232 }
233 
234 
readElementTextH(KoXmlStreamReader & reader)235 void OdfTextReader::readElementTextH(KoXmlStreamReader &reader)
236 {
237     DEBUGSTART();
238     m_backend->elementTextH(reader, m_context);
239 
240     // The function readParagraphContents() expects to have the reader
241     // point to the contents of the paragraph so we have to read past
242     // the text:h start tag here.
243     reader.readNext();
244     m_context->setIsInsideParagraph(true);
245     readParagraphContents(reader);
246     m_context->setIsInsideParagraph(false);
247 
248     m_backend->elementTextH(reader, m_context);
249     DEBUGEND();
250 }
251 
readElementTextP(KoXmlStreamReader & reader)252 void OdfTextReader::readElementTextP(KoXmlStreamReader &reader)
253 {
254     DEBUGSTART();
255     m_backend->elementTextP(reader, m_context);
256 
257     // The function readParagraphContents() expects to have the reader
258     // point to the contents of the paragraph so we have to read past
259     // the text:p start tag here.
260     reader.readNext();
261     m_context->setIsInsideParagraph(true);
262     readParagraphContents(reader);
263     m_context->setIsInsideParagraph(false);
264 
265     m_backend->elementTextP(reader, m_context);
266     DEBUGEND();
267 }
268 
readElementTextList(KoXmlStreamReader & reader)269 void OdfTextReader::readElementTextList(KoXmlStreamReader &reader)
270 {
271     DEBUGSTART();
272     m_backend->elementTextList(reader, m_context);
273 
274     // <text:list> has the following children in ODF 1.2:
275     //   [done] <text:list-header> 5.3.3
276     //   [done] <text:list-item> 5.3.4
277 
278     m_context->setIsInsideParagraph(true);
279     while (reader.readNextStartElement()) {
280         DEBUG_READING("loop-start");
281 
282         QString tagName = reader.qualifiedName().toString();
283         //debugOdfReader << "list child:" << tagName;
284         if (tagName == "text:list-item") {
285             readElementTextListItem(reader);
286         }
287         else if (tagName == "text:list-header") {
288             readElementTextListHeader(reader);
289         }
290         else {
291             readUnknownElement(reader);
292         }
293         DEBUG_READING("loop-end");
294     }
295     m_context->setIsInsideParagraph(false);
296 
297     m_backend->elementTextList(reader, m_context);
298     DEBUGEND();
299 }
300 
301 // ----------------------------------------------------------------
302 //                             Tables
303 
304 
readElementTableTable(KoXmlStreamReader & reader)305 void OdfTextReader::readElementTableTable(KoXmlStreamReader &reader)
306 {
307     DEBUGSTART();
308     m_backend->elementTableTable(reader, m_context);
309 
310     // <table:table> has the following children in ODF 1.2:
311     //          <office:dde-source> 14.6.5
312     //          <office:forms> 13.2
313     //   [done] <table:desc> 9.1.14
314     //          <table:named-expressions> 9.4.11
315     //          <table:scenario> 9.2.7
316     //          <table:shapes> 9.2.8
317     //   [done] <table:table-column> 9.1.6
318     //   [done] <table:table-column-group> 9.1.10
319     //   [done] <table:table-columns> 9.1.12
320     //   [done] <table:table-header-columns> 9.1.11
321     //   [done] <table:table-header-rows> 9.1.7
322     //   [done] <table:table-row> 9.1.3
323     //   [done] <table:table-row-group> 9.1.9
324     //   [done] <table:table-rows> 9.1.8
325     //          <table:table-source> 9.2.6
326     //   [done] <table:title> 9.1.13
327     //   [done] <text:soft-page-break> 5.6
328     while (reader.readNextStartElement()) {
329         QString tagName = reader.qualifiedName().toString();
330 
331         if (tagName == "table:table-column") {
332             readElementTableTableColumn(reader);
333         }
334         else if (tagName == "table:table-column-group") {
335             readElementTableTableColumnGroup(reader);
336         }
337         else if (tagName == "table:table-columns") {
338             readElementTableTableColumns(reader);
339         }
340         else if (tagName == "table:table-header-columns") {
341             readElementTableTableHeaderColumns(reader);
342         }
343         else if (tagName == "table:table-header-rows") {
344             readElementTableTableHeaderRows(reader);
345         }
346         else if (tagName == "table:table-row") {
347             readElementTableTableRow(reader);
348         }
349         else if (tagName == "table:table-row-group") {
350             readElementTableTableRowGroup(reader);
351         }
352         else if (tagName == "table:table-rows") {
353             readElementTableTableRows(reader);
354         }
355         else if (tagName == "table:title") {
356 	    QString value;
357 	    readCharacterData(reader, value);
358 	    m_backend->textVariable(tagName, value);
359         }
360         else if (tagName == "table:desc") {
361 	    QString value;
362 	    readCharacterData(reader, value);
363 	    m_backend->textVariable(tagName, value);
364         }
365         else if (tagName == "text:soft-page-break") {
366             readElementTextSoftPageBreak(reader);
367         }
368         else {
369             reader.skipCurrentElement();
370         }
371     }
372 
373     m_backend->elementTableTable(reader, m_context);
374     DEBUGEND();
375 }
376 
readElementTableTableColumnGroup(KoXmlStreamReader & reader)377 void OdfTextReader::readElementTableTableColumnGroup(KoXmlStreamReader &reader)
378 {
379    DEBUGSTART();
380     m_backend->elementTableTableColumnGroup(reader, m_context);
381 
382     // <table:table-column-group> has the following children in ODF 1.2:
383     //          <table:table-header-columns> 9.1.11
384     //          <table:table-column> 9.1.6
385     //          <table:table-column-group> 9.1.10
386     //          <table:table-columns> 9.1.12
387     //
388     while (reader.readNextStartElement()) {
389         QString tagName = reader.qualifiedName().toString();
390 
391 	if (tagName == "table:table-header-columns") {
392             readElementTableTableHeaderColumns(reader);
393         }
394         else if (tagName == "table:table-column") {
395             readElementTableTableColumn(reader);
396         }
397         else if (tagName == "table:table-column-group") {
398             readElementTableTableColumnGroup(reader);
399         }
400         else if (tagName == "table:table-columns") {
401             readElementTableTableColumns(reader);
402         }
403         else {
404             reader.skipCurrentElement();
405         }
406     }
407 
408     m_backend->elementTableTableColumnGroup(reader, m_context);
409     DEBUGEND();
410 }
411 
readElementTableTableColumns(KoXmlStreamReader & reader)412 void OdfTextReader::readElementTableTableColumns(KoXmlStreamReader &reader)
413 {
414     DEBUGSTART();
415     m_backend->elementTableTableColumns(reader, m_context);
416 
417     // <table:table-columns> has the following children in ODF 1.2:
418     //   [done] <table:table-column> 9.1.6
419     while (reader.readNextStartElement()) {
420         QString tagName = reader.qualifiedName().toString();
421 
422         if (tagName == "table:table-column") {
423             readElementTableTableColumn(reader);
424         }
425         else {
426             reader.skipCurrentElement();
427         }
428     }
429 
430     m_backend->elementTableTableColumns(reader, m_context);
431     DEBUGEND();
432 }
433 
readElementTableTableHeaderColumns(KoXmlStreamReader & reader)434 void OdfTextReader::readElementTableTableHeaderColumns(KoXmlStreamReader &reader)
435 {
436     DEBUGSTART();
437     m_backend->elementTableTableHeaderColumns(reader, m_context);
438 
439     // <table:table-header-columns> has the following children in ODF 1.2:
440     //   [done] <table:table-column> 9.1.6
441     while (reader.readNextStartElement()) {
442         QString tagName = reader.qualifiedName().toString();
443 
444         if (tagName == "table:table-column") {
445             readElementTableTableColumn(reader);
446         }
447         else {
448             reader.skipCurrentElement();
449         }
450     }
451 
452     m_backend->elementTableTableHeaderColumns(reader, m_context);
453     DEBUGEND();
454 }
455 
readElementTableTableHeaderRows(KoXmlStreamReader & reader)456 void OdfTextReader::readElementTableTableHeaderRows(KoXmlStreamReader &reader)
457 {
458     DEBUGSTART();
459     m_backend->elementTableTableHeaderRows(reader, m_context);
460 
461     // <table:table-header-rows> has the following children in ODF 1.2:
462     //   [done] <table:table-row> 9.1.3
463     //   [done] <text:soft-page-break> 5.6.
464     while (reader.readNextStartElement()) {
465         QString tagName = reader.qualifiedName().toString();
466 
467         if (tagName == "table:table-row") {
468             readElementTableTableRow(reader);
469         }
470         else if (tagName == "text:soft-page-break") {
471             readElementTextSoftPageBreak(reader);
472         }
473         else {
474             reader.skipCurrentElement();
475         }
476     }
477 
478     m_backend->elementTableTableHeaderRows(reader, m_context);
479     DEBUGEND();
480 }
481 
readElementTableTableColumn(KoXmlStreamReader & reader)482 void OdfTextReader::readElementTableTableColumn(KoXmlStreamReader &reader)
483 {
484     DEBUGSTART();
485     m_backend->elementTableTableColumn(reader, m_context);
486 
487     // <table:table-column> has no children in ODF 1.2
488     reader.skipCurrentElement();
489 
490     m_backend->elementTableTableColumn(reader, m_context);
491     DEBUGEND();
492 }
493 
readElementTableTableRowGroup(KoXmlStreamReader & reader)494 void OdfTextReader::readElementTableTableRowGroup(KoXmlStreamReader &reader)
495 {
496    DEBUGSTART();
497     m_backend->elementTableTableRowGroup(reader, m_context);
498 
499     // <table:table-row-group> has the following children in ODF 1.2:
500     //          <table:table-header-rows> 9.1.7
501     //          <table:table-row> 9.1.3
502     //          <table:table-row-group> 9.1.9
503     //          <table:table-rows> 9.1.8
504     //          <text:soft-page-break> 5.6
505    //
506     while (reader.readNextStartElement()) {
507         QString tagName = reader.qualifiedName().toString();
508 
509 	if (tagName == "table:table-header-rows") {
510             readElementTableTableHeaderRows(reader);
511         }
512         else if (tagName == "table:table-row") {
513             readElementTableTableRow(reader);
514         }
515         else if (tagName == "table:table-row-group") {
516             readElementTableTableRowGroup(reader);
517         }
518         else if (tagName == "table:table-rows") {
519             readElementTableTableRows(reader);
520         }
521         else if (tagName == "text:soft-page-break") {
522             readElementTextSoftPageBreak(reader);
523         }
524         else {
525             reader.skipCurrentElement();
526         }
527     }
528 
529     m_backend->elementTableTableRowGroup(reader, m_context);
530     DEBUGEND();
531 }
532 
readElementTableTableRow(KoXmlStreamReader & reader)533 void OdfTextReader::readElementTableTableRow(KoXmlStreamReader &reader)
534 {
535     DEBUGSTART();
536     m_backend->elementTableTableRow(reader, m_context);
537 
538     // <table:table-row> has the following children in ODF 1.2:
539     //   [done] <table:covered-table-cell> 9.1.5
540     //   [done] <table:table-cell> 9.1.4.
541     while (reader.readNextStartElement()) {
542         QString tagName = reader.qualifiedName().toString();
543 
544         if (tagName == "table:covered-table-cell") {
545             readElementTableCoveredTableCell(reader);
546         }
547         else if (tagName == "table:table-cell") {
548             readElementTableTableCell(reader);
549         }
550         else {
551             reader.skipCurrentElement();
552         }
553     }
554 
555     m_backend->elementTableTableRow(reader, m_context);
556     DEBUGEND();
557 }
558 
readElementTableTableRows(KoXmlStreamReader & reader)559 void OdfTextReader::readElementTableTableRows(KoXmlStreamReader &reader)
560 {
561     DEBUGSTART();
562     m_backend->elementTableTableRows(reader, m_context);
563 
564     // <table:table-header-rows> has the following children in ODF 1.2:
565     //   [done] <table:table-row> 9.1.3
566     //   [done] <text:soft-page-break> 5.6.
567     while (reader.readNextStartElement()) {
568         QString tagName = reader.qualifiedName().toString();
569 
570         if (tagName == "table:table-row") {
571             readElementTableTableRow(reader);
572         }
573         else if (tagName == "text:soft-page-break") {
574             readElementTextSoftPageBreak(reader);
575         }
576         else {
577             reader.skipCurrentElement();
578         }
579     }
580 
581     m_backend->elementTableTableRows(reader, m_context);
582     DEBUGEND();
583 }
584 
readElementTableTableCell(KoXmlStreamReader & reader)585 void OdfTextReader::readElementTableTableCell(KoXmlStreamReader &reader)
586 {
587     DEBUGSTART();
588     m_backend->elementTableTableCell(reader, m_context);
589 
590     // <table:table-cell> has the following children in ODF 1.2:
591     //
592     // In addition to the text level tags like <text:p> etc that can
593     // be found in any textbox, table cell or similar, it has the
594     // following text document children:
595     //
596     //   [done] <office:annotation> 14.1
597     //          <table:cell-range-source> 9.3.1
598     //          <table:detective> 9.3.2
599 
600     while (reader.readNextStartElement()) {
601         DEBUG_READING("loop-start");
602 
603         QString tagName = reader.qualifiedName().toString();
604         if (tagName == "office:annotation") {
605 	    readElementOfficeAnnotation(reader);
606         }
607         else if (tagName == "table:cell-range-source") {
608             // FIXME: NYI
609             reader.skipCurrentElement();
610         }
611         else if (tagName == "table:detective") {
612             // FIXME: NYI
613             reader.skipCurrentElement();
614         }
615         else {
616             readTextLevelElement(reader);
617         }
618         DEBUG_READING("loop-end");
619     }
620 
621     m_backend->elementTableTableCell(reader, m_context);
622     DEBUGEND();
623 }
624 
readElementTableCoveredTableCell(KoXmlStreamReader & reader)625 void OdfTextReader::readElementTableCoveredTableCell(KoXmlStreamReader &reader)
626 {
627     DEBUGSTART();
628     m_backend->elementTableCoveredTableCell(reader, m_context);
629 
630     // <table:covered-table-cell> has the following children in ODF 1.2:
631     //
632     // In addition to the text level tags like <text:p> etc that can
633     // be found in any textbox, table cell or similar, it has the
634     // following text document children:
635     //
636     //   [done] <office:annotation> 14.1
637     //          <table:cell-range-source> 9.3.1
638     //          <table:detective> 9.3.2
639 
640     while (reader.readNextStartElement()) {
641         DEBUG_READING("loop-start");
642 
643         QString tagName = reader.qualifiedName().toString();
644         if (tagName == "office:annotation") {
645 	    readElementOfficeAnnotation(reader);
646 	}
647         else if (tagName == "table:cell-range-source") {
648             // FIXME: NYI
649             reader.skipCurrentElement();
650         }
651         else if (tagName == "table:detective") {
652             // FIXME: NYI
653             reader.skipCurrentElement();
654         }
655         else {
656             readTextLevelElement(reader);
657         }
658         DEBUG_READING("loop-end");
659     }
660 
661     m_backend->elementTableCoveredTableCell(reader, m_context);
662     DEBUGEND();
663 }
664 
665 
666 // ----------------------------------------------------------------
667 //                     Paragraph level functions
668 
669 
670 // This function is a bit special since it doesn't handle a specific
671 // element.  Instead it handles the common child elements between a
672 // number of paragraph-level elements.
673 //
readParagraphContents(KoXmlStreamReader & reader)674 void OdfTextReader::readParagraphContents(KoXmlStreamReader &reader)
675 {
676     DEBUGSTART();
677 
678     // We enter this function with the reader pointing to the first
679     // element *inside* the paragraph.
680     //
681     // We should not call any backend functions here.  That is already
682     // done in the functions that call this one.
683 
684     while (!reader.atEnd() && !reader.isEndElement()) {
685         DEBUG_READING("loop-start");
686 
687         if (reader.isCharacters()) {
688             //debugOdfReader << "Found character data";
689             m_backend->characterData(reader, m_context);
690             reader.readNext();
691             continue;
692         }
693 
694         if (!reader.isStartElement())
695             continue;
696 
697         // We define the common elements on the paragraph level as the
698         // following list.  They are the basic paragraph level contents that
699         // can be found in a paragraph (text:p), heading (text:h), etc
700         //
701         // The common paragraph level elements are the following in ODF 1.2:
702         //
703         //          <dr3d:scene> 10.5.2
704         //          <draw:a> 10.4.12
705         //          <draw:caption> 10.3.11
706         //          <draw:circle> 10.3.8
707         //          <draw:connector> 10.3.10
708         //          <draw:control> 10.3.13
709         //          <draw:custom-shape> 10.6.1
710         //          <draw:ellipse> 10.3.9
711         //   [done] <draw:frame> 10.4.2
712         //          <draw:g> 10.3.15
713         //          <draw:line> 10.3.3
714         //          <draw:measure> 10.3.12
715         //          <draw:page-thumbnail> 10.3.14
716         //          <draw:path> 10.3.7
717         //          <draw:polygon> 10.3.5
718         //          <draw:polyline> 10.3.4
719         //          <draw:rect> 10.3.2
720         //          <draw:regular-polygon> 10.3.6
721 	// All of the above are sent to the draw reader.
722 	//
723         //   [done] <office:annotation> 14.1
724         //   [done] <office:annotation-end> 14.2
725         //          <presentation:date-time> 10.9.3.5
726         //          <presentation:footer> 10.9.3.3
727         //          <presentation:header> 10.9.3.1
728         //   [done] <text:a> 6.1.8
729         //          <text:alphabetical-index-mark> 8.1.10
730         //          <text:alphabetical-index-mark-end> 8.1.9
731         //          <text:alphabetical-index-mark-start> 8.1.8
732         //          <text:author-initials> 7.3.7.2
733         //          <text:author-name> 7.3.7.1
734         //          <text:bibliography-mark> 8.1.11
735         //          <text:bookmark> 6.2.1.2
736         //          <text:bookmark-end> 6.2.1.4
737         //          <text:bookmark-ref> 7.7.6
738         //          <text:bookmark-start> 6.2.1.3
739         //          <text:change> 5.5.7.4
740         //          <text:change-end> 5.5.7.3
741         //          <text:change-start> 5.5.7.2
742         //          <text:chapter> 7.3.8
743         //          <text:character-count> 7.5.18.5
744         //          <text:conditional-text> 7.7.3
745         //          <text:creation-date> 7.5.3
746         //          <text:creation-time> 7.5.4
747         //          <text:creator> 7.5.17
748         //          <text:database-display> 7.6.3
749         //          <text:database-name> 7.6.7
750         //          <text:database-next> 7.6.4
751         //          <text:database-row-number> 7.6.6
752         //          <text:database-row-select> 7.6.5
753         //          <text:date> 7.3.2
754         //          <text:dde-connection> 7.7.12
755         //          <text:description> 7.5.5
756         //          <text:editing-cycles> 7.5.13
757         //          <text:editing-duration> 7.5.14
758         //          <text:execute-macro> 7.7.10
759         //          <text:expression> 7.4.14
760         //          <text:file-name> 7.3.9
761         //          <text:hidden-paragraph> 7.7.11
762         //          <text:hidden-text> 7.7.4
763         //          <text:image-count> 7.5.18.7
764         //          <text:initial-creator> 7.5.2
765         //          <text:keywords> 7.5.12
766         //   [done] <text:line-break> 6.1.5
767         //          <text:measure> 7.7.13
768         //          <text:meta> 6.1.9
769         //          <text:meta-field> 7.5.19
770         //          <text:modification-date> 7.5.16
771         //          <text:modification-time> 7.5.15
772         //          <text:note> 6.3.2
773         //          <text:note-ref> 7.7.7
774         //          <text:object-count> 7.5.18.8
775         //          <text:page-continuation> 7.3.5
776         //          <text:page-count> 7.5.18.2
777         //          <text:page-number> 7.3.4
778         //          <text:page-variable-get> 7.7.1.3
779         //          <text:page-variable-set> 7.7.1.2
780         //          <text:paragraph-count> 7.5.18.3
781         //          <text:placeholder> 7.7.2
782         //          <text:print-date> 7.5.8
783         //          <text:printed-by> 7.5.9
784         //          <text:print-time> 7.5.7
785         //          <text:reference-mark> 6.2.2.2
786         //          <text:reference-mark-end> 6.2.2.4
787         //          <text:reference-mark-start> 6.2.2.3
788         //          <text:reference-ref> 7.7.5
789         //          <text:ruby> 6.4
790         //   [done] <text:s> 6.1.3
791         //          <text:script> 7.7.9
792         //          <text:sender-city> 7.3.6.13
793         //          <text:sender-company> 7.3.6.10
794         //          <text:sender-country> 7.3.6.15
795         //          <text:sender-email> 7.3.6.7
796         //          <text:sender-fax> 7.3.6.9
797         //          <text:sender-firstname> 7.3.6.2
798         //          <text:sender-initials> 7.3.6.4
799         //          <text:sender-lastname> 7.3.6.3
800         //          <text:sender-phone-private> 7.3.6.8
801         //          <text:sender-phone-work> 7.3.6.11
802         //          <text:sender-position> 7.3.6.6
803         //          <text:sender-postal-code> 7.3.6.14
804         //          <text:sender-state-or-province> 7.3.6.16
805         //          <text:sender-street> 7.3.6.12
806         //          <text:sender-title> 7.3.6.5
807         //          <text:sequence> 7.4.13
808         //          <text:sequence-ref> 7.7.8
809         //          <text:sheet-name> 7.3.11
810         //   [done] <text:soft-page-break> 5.6
811         //   [done] <text:span> 6.1.7
812         //          <text:subject> 7.5.11
813         //          <text:tab> 6.1.4
814         //          <text:table-count> 7.5.18.6
815         //          <text:table-formula> 7.7.14
816         //          <text:template-name> 7.3.10
817         //          <text:text-input> 7.4.15
818         //          <text:time> 7.3.3
819         //          <text:title> 7.5.10
820         //          <text:toc-mark> 8.1.4
821         //          <text:toc-mark-end> 8.1.3
822         //          <text:toc-mark-start> 8.1.2
823         //          <text:user-defined> 7.5.6
824         //          <text:user-field-get> 7.4.9
825         //          <text:user-field-input> 7.4.10
826         //          <text:user-index-mark> 8.1.7
827         //          <text:user-index-mark-end> 8.1.6
828         //          <text:user-index-mark-start> 8.1.5
829         //          <text:variable-get> 7.4.5
830         //          <text:variable-input> 7.4.6
831         //          <text:variable-set> 7.4.4
832         //          <text:word-count> 7.5.18.4.
833         //
834         // FIXME: Only very few tags are handled right now.
835 
836         QString tagName = reader.qualifiedName().toString();
837 
838 	if (reader.prefix() == "draw" || reader.prefix() == "dr3d") {
839 	    OdfDrawReader *drawReader = m_parent->drawReader();
840 	    if (drawReader) {
841 		drawReader->readCommonGraphicsElements(reader);
842 	    }
843 	    else {
844 		reader.skipCurrentElement();
845 	    }
846         } // draw | dr3d namespace
847         else if (reader.prefix() == "office") {
848             if (tagName == "office:annotation") {
849                 readElementOfficeAnnotation(reader);
850             }
851             else if (tagName == "office:annotation-end") {
852                 readElementOfficeAnnotationEnd(reader);
853             }
854             else {
855                 // Unknown office: element
856                 readUnknownElement(reader);
857             }
858         } // office namespace
859         else if (reader.prefix() == "text") {
860 
861             if (tagName == "text:a") {
862                 readElementTextA(reader);
863             }
864             else if (tagName == "text:line-break") {
865                 readElementTextLineBreak(reader);
866             }
867             else if (tagName == "text:span") {
868                 readElementTextSpan(reader);
869             }
870             else if (tagName == "text:s") {
871                 readElementTextS(reader);
872             }
873             else if (tagName == "text:soft-page-break") {
874                 readElementTextSoftPageBreak(reader);
875             }
876             else {
877                 // Unknown text: element
878                 readUnknownElement(reader);
879             }
880         } // text namespace
881         else {
882             // Unknown namespace
883             readUnknownElement(reader);
884         }
885 
886         // Read past the end tag of the just parsed element.
887         reader.readNext();
888         DEBUG_READING("loop-end");
889     }
890 
891     DEBUGEND();
892 }
893 
readElementOfficeAnnotation(KoXmlStreamReader & reader)894 void OdfTextReader::readElementOfficeAnnotation(KoXmlStreamReader &reader)
895 {
896     DEBUGSTART();
897     m_backend->elementOfficeAnnotation(reader, m_context);
898 
899     // <office:annotation> has the following children in ODF 1.2:
900     //   [done] <dc:creator> 4.3.2.7
901     //   [done] <dc:date> 4.3.2.10
902     //   [done] <meta:date-string> 14.3
903     //   [done] <text:list> 5.3.1
904     //   [done] <text:p> 5.1.3
905     while (reader.readNextStartElement()) {
906         QString tagName = reader.qualifiedName().toString();
907 
908         if (tagName == "dc:creator") {
909             readElementDcCreator(reader);
910         }
911         else if (tagName == "dc:date") {
912             readElementDcDate(reader);
913         }
914         else if (tagName == "meta:date-string") {
915 	    QString value;
916 	    readCharacterData(reader, value);
917 	    m_backend->textVariable(tagName, value);
918         }
919         else if (tagName == "text:list") {
920             readElementTextList(reader);
921         }
922         else if (tagName == "text:p") {
923             readElementTextP(reader);
924         }
925         else {
926             reader.skipCurrentElement();
927         }
928     }
929 
930     m_backend->elementOfficeAnnotation(reader, m_context);
931     DEBUGEND();
932 }
933 
readElementOfficeAnnotationEnd(KoXmlStreamReader & reader)934 void OdfTextReader::readElementOfficeAnnotationEnd(KoXmlStreamReader &reader)
935 {
936     DEBUGSTART();
937     m_backend->elementOfficeAnnotationEnd(reader, m_context);
938 
939     // <office:annotation-end> has no children in ODF 1.2:
940     // FIXME: Skip current element or call parseUnknownElement?
941     reader.skipCurrentElement();
942 
943     m_backend->elementOfficeAnnotationEnd(reader, m_context);
944     DEBUGEND();
945 }
946 
readElementDcCreator(KoXmlStreamReader & reader)947 void OdfTextReader::readElementDcCreator(KoXmlStreamReader &reader)
948 {
949     DEBUGSTART();
950     m_backend->elementDcCreator(reader, m_context);
951 
952     reader.readNext();
953     readParagraphContents(reader);
954 
955     m_backend->elementDcCreator(reader, m_context);
956     DEBUGEND();
957 }
958 
readElementDcDate(KoXmlStreamReader & reader)959 void OdfTextReader::readElementDcDate(KoXmlStreamReader &reader)
960 {
961     DEBUGSTART();
962     m_backend->elementDcDate(reader, m_context);
963 
964     reader.readNext();
965     readParagraphContents(reader);
966 
967     m_backend->elementDcDate(reader, m_context);
968     DEBUGEND();
969 }
970 
readElementTextA(KoXmlStreamReader & reader)971 void OdfTextReader::readElementTextA(KoXmlStreamReader &reader)
972 {
973     DEBUGSTART();
974     m_backend->elementTextA(reader, m_context);
975 
976     // readParagraphContents expect to have the reader point to the
977     // contents of the paragraph so we have to read past the text:a
978     // start tag here.
979     reader.readNext();
980     readParagraphContents(reader);
981 
982     m_backend->elementTextA(reader, m_context);
983     DEBUGEND();
984 }
985 
readElementTextLineBreak(KoXmlStreamReader & reader)986 void OdfTextReader::readElementTextLineBreak(KoXmlStreamReader &reader)
987 {
988     DEBUGSTART();
989     m_backend->elementTextLineBreak(reader, m_context);
990 
991     // This element has no child elements in ODF 1.2.
992     reader.skipCurrentElement();
993 
994     m_backend->elementTextLineBreak(reader, m_context);
995     DEBUGEND();
996 }
997 
readElementTextS(KoXmlStreamReader & reader)998 void OdfTextReader::readElementTextS(KoXmlStreamReader &reader)
999 {
1000     DEBUGSTART();
1001     m_backend->elementTextS(reader, m_context);
1002 
1003     // This element has no child elements in ODF 1.2.
1004     reader.skipCurrentElement();
1005 
1006     m_backend->elementTextS(reader, m_context);
1007     DEBUGEND();
1008 }
1009 
readElementTextSpan(KoXmlStreamReader & reader)1010 void OdfTextReader::readElementTextSpan(KoXmlStreamReader &reader)
1011 {
1012     DEBUGSTART();
1013     m_backend->elementTextSpan(reader, m_context);
1014 
1015     reader.readNext();
1016     readParagraphContents(reader);
1017 
1018     m_backend->elementTextSpan(reader, m_context);
1019     DEBUGEND();
1020 }
1021 
1022 
1023 // ----------------------------------------------------------------
1024 //                        List level functions
1025 
1026 
readElementTextListHeader(KoXmlStreamReader & reader)1027 void OdfTextReader::readElementTextListHeader(KoXmlStreamReader &reader)
1028 {
1029     DEBUGSTART();
1030     m_backend->elementTextListHeader(reader, m_context);
1031 
1032     // <text:list-header> has the following children in ODF 1.2:
1033     //   [done] <text:h> 5.1.2
1034     //   [done] <text:p> 5.1.3
1035     //   [done] <text:list> 5.3.1
1036     //   [done] <text:soft-page-break> 5.6
1037     //          <text:number> 6.1.10
1038     while(reader.readNextStartElement()) {
1039 	DEBUG_READING("loop-start");
1040 
1041 	QString tagName = reader.qualifiedName().toString();
1042 	if (tagName == "text:h") {
1043 	    readElementTextH(reader);
1044 	}
1045 	else if (tagName == "text:p") {
1046 	    readElementTextP(reader);
1047 	}
1048 	else if (tagName == "text:list") {
1049 	    readElementTextList(reader);
1050 	}
1051         else if (tagName == "text:soft-page-break") {
1052 	    readElementTextSoftPageBreak(reader);
1053         }
1054         else if (tagName == "text:number") {
1055             // FIXME: NYI
1056             reader.skipCurrentElement();
1057         }
1058 	else {
1059 	    readUnknownElement(reader);
1060 	}
1061 
1062 	DEBUG_READING("loop-end");
1063     }
1064 
1065     m_backend->elementTextListHeader(reader, m_context);
1066     DEBUGEND();
1067 }
1068 
readElementTextListItem(KoXmlStreamReader & reader)1069 void OdfTextReader::readElementTextListItem(KoXmlStreamReader &reader)
1070 {
1071     DEBUGSTART();
1072     m_backend->elementTextListItem(reader, m_context);
1073 
1074     // <text:list-item> has the following children in ODF 1.2:
1075     //   [done] <text:h> 5.1.2
1076     //   [done] <text:p> 5.1.3
1077     //   [done] <text:list> 5.3.1
1078     //   [done] <text:soft-page-break> 5.6
1079     //          <text:number> 6.1.10
1080     while(reader.readNextStartElement()) {
1081         DEBUG_READING("loop-start");
1082 
1083         QString tagName = reader.qualifiedName().toString();
1084         debugOdfReader <<tagName;
1085 	if (tagName == "text:h") {
1086 	    readElementTextH(reader);
1087 	}
1088 	else if (tagName == "text:p") {
1089 	    readElementTextP(reader);
1090 	}
1091         else if (tagName == "text:list") {
1092             readElementTextList(reader);
1093         }
1094         else if (tagName == "text:soft-page-break") {
1095 	    readElementTextSoftPageBreak(reader);
1096         }
1097         else if (tagName == "text:number") {
1098             //FIXME
1099             reader.skipCurrentElement();
1100         }
1101         else {
1102             readUnknownElement(reader);
1103         }
1104 
1105 	DEBUG_READING("loop-end");
1106     }
1107 
1108     m_backend->elementTextListItem(reader, m_context);
1109     DEBUGEND();
1110 }
1111 
1112 // ----------------------------------------------------------------
1113 //                             Other functions
1114 
1115 
readElementTextSoftPageBreak(KoXmlStreamReader & reader)1116 void OdfTextReader::readElementTextSoftPageBreak(KoXmlStreamReader &reader)
1117 {
1118     DEBUGSTART();
1119     m_backend->elementTextSoftPageBreak(reader, m_context);
1120 
1121     // <text:soft-page-break> has no children in ODF 1.2
1122     reader.skipCurrentElement();
1123 
1124     m_backend->elementTextSoftPageBreak(reader, m_context);
1125     DEBUGEND();
1126 }
1127 
1128 
readUnknownElement(KoXmlStreamReader & reader)1129 void OdfTextReader::readUnknownElement(KoXmlStreamReader &reader)
1130 {
1131     DEBUGSTART();
1132 
1133     if (m_context->isInsideParagraph()) {
1134         // readParagraphContents expect to have the reader point to the
1135         // contents of the paragraph so we have to read past the text:p
1136         // start tag here.
1137         reader.readNext();
1138         readParagraphContents(reader);
1139     }
1140     else {
1141         while (reader.readNextStartElement()) {
1142             readTextLevelElement(reader);
1143         }
1144     }
1145 
1146     DEBUGEND();
1147 }
1148 
1149