xref: /AOO41X/main/writerperfect/source/filter/DocumentCollector.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /* DocumentCollector: Collects sections and runs of text from a
2  * file (and styles to go along with them) and writes them
3  * to a Writer target document
4  *
5  * Copyright (C) 2002-2004 William Lachance (william.lachance@sympatico.ca)
6  * Copyright (C) 2003-2004 Net Integration Technologies (http://www.net-itech.com)
7  * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22  *
23  * For further information visit http://libwpd.sourceforge.net
24  *
25  */
26 
27 /* "This product is not manufactured, approved, or supported by
28  * Corel Corporation or Corel Corporation Limited."
29  */
30 
31 #if defined _MSC_VER
32 #pragma warning( push, 1 )
33 #endif
34 #include <libwpd/libwpd.h>
35 #if defined _MSC_VER
36 #pragma warning( pop )
37 #endif
38 #include <string.h> // for strcmp
39 
40 #include "DocumentCollector.hxx"
41 #include "DocumentElement.hxx"
42 #include "TextRunStyle.hxx"
43 #include "FontStyle.hxx"
44 #include "ListStyle.hxx"
45 #include "PageSpan.hxx"
46 #include "SectionStyle.hxx"
47 #include "TableStyle.hxx"
48 #include "FilterInternal.hxx"
49 #include "WriterProperties.hxx"
50 
_WriterDocumentState()51 _WriterDocumentState::_WriterDocumentState() :
52     mbFirstElement(true),
53     mbInFakeSection(false),
54     mbListElementOpenedAtCurrentLevel(false),
55     mbTableCellOpened(false),
56     mbHeaderRow(false),
57     mbInNote(false)
58 {
59 }
60 
DocumentCollector(WPXInputStream * pInput,DocumentHandler * pHandler)61 DocumentCollector::DocumentCollector(WPXInputStream *pInput, DocumentHandler *pHandler) :
62         mpInput(pInput),
63         mpHandler(pHandler),
64     mbUsed(false),
65     mfSectionSpaceAfter(0.0f),
66     miNumListStyles(0),
67     mpCurrentContentElements(&mBodyElements),
68     mpCurrentPageSpan(NULL),
69     miNumPageStyles(0),
70     mpCurrentListStyle(NULL),
71     miCurrentListLevel(0),
72     miLastListLevel(0),
73     miLastListNumber(0),
74     mbListContinueNumbering(false),
75     mbListElementOpened(false),
76     mbListElementParagraphOpened(false)
77 {
78 }
79 
~DocumentCollector()80 DocumentCollector::~DocumentCollector()
81 {
82 }
83 
filter()84 bool DocumentCollector::filter()
85 {
86     // The contract for DocumentCollector is that it will only be used once after it is
87     // instantiated
88     if (mbUsed)
89         return false;
90 
91     mbUsed = true;
92 
93     // parse & write
94         // WLACH_REFACTORING: Remove these args..
95     if (!parseSourceDocument(*mpInput))
96         return false;
97     if (!_writeTargetDocument(mpHandler))
98         return false;
99 
100     // clean up the mess we made
101     WRITER_DEBUG_MSG(("WriterWordPerfect: Cleaning up our mess..\n"));
102 
103     WRITER_DEBUG_MSG(("Destroying the body elements\n"));
104     for (std::vector<DocumentElement *>::iterator iterBody = mBodyElements.begin(); iterBody != mBodyElements.end(); iterBody++) {
105         delete((*iterBody));
106         (*iterBody) = NULL;
107     }
108 
109     WRITER_DEBUG_MSG(("Destroying the styles elements\n"));
110     for (std::vector<DocumentElement *>::iterator iterStyles = mStylesElements.begin(); iterStyles != mStylesElements.end(); iterStyles++) {
111         delete (*iterStyles);
112         (*iterStyles) = NULL; // we may pass over the same element again (in the case of headers/footers spanning multiple pages)
113                       // so make sure we don't do a double del
114     }
115 
116     WRITER_DEBUG_MSG(("Destroying the rest of the styles elements\n"));
117     for (std::map<WPXString, ParagraphStyle *, ltstr>::iterator iterTextStyle = mTextStyleHash.begin(); iterTextStyle != mTextStyleHash.end(); iterTextStyle++) {
118         delete iterTextStyle->second;
119     }
120     for (std::map<WPXString, SpanStyle *, ltstr>::iterator iterSpanStyle = mSpanStyleHash.begin(); iterSpanStyle != mSpanStyleHash.end(); iterSpanStyle++) {
121         delete iterSpanStyle->second;
122     }
123 
124     for (std::map<WPXString, FontStyle *, ltstr>::iterator iterFont = mFontHash.begin(); iterFont != mFontHash.end(); iterFont++) {
125         delete iterFont->second;
126     }
127 
128     for (std::vector<ListStyle *>::iterator iterListStyles = mListStyles.begin(); iterListStyles != mListStyles.end(); iterListStyles++) {
129         delete (*iterListStyles);
130     }
131     for (std::vector<SectionStyle *>::iterator iterSectionStyles = mSectionStyles.begin(); iterSectionStyles != mSectionStyles.end(); iterSectionStyles++) {
132         delete (*iterSectionStyles);
133     }
134     for (std::vector<TableStyle *>::iterator iterTableStyles = mTableStyles.begin(); iterTableStyles != mTableStyles.end(); iterTableStyles++) {
135         delete (*iterTableStyles);
136     }
137 
138     for (std::vector<PageSpan *>::iterator iterPageSpans = mPageSpans.begin(); iterPageSpans != mPageSpans.end(); iterPageSpans++) {
139         delete (*iterPageSpans);
140     }
141 
142     return true;
143 }
144 
_writeDefaultStyles(DocumentHandler * pHandler)145 void DocumentCollector::_writeDefaultStyles(DocumentHandler *pHandler)
146 {
147     TagOpenElement stylesOpenElement("office:styles");
148     stylesOpenElement.write(pHandler);
149 
150     TagOpenElement defaultParagraphStyleOpenElement("style:default-style");
151     defaultParagraphStyleOpenElement.addAttribute("style:family", "paragraph");
152     defaultParagraphStyleOpenElement.write(pHandler);
153 
154     TagOpenElement defaultParagraphStylePropertiesOpenElement("style:properties");
155     defaultParagraphStylePropertiesOpenElement.addAttribute("style:family", "paragraph");
156     defaultParagraphStylePropertiesOpenElement.addAttribute("style:tab-stop-distance", "0.5inch");
157     defaultParagraphStylePropertiesOpenElement.write(pHandler);
158     TagCloseElement defaultParagraphStylePropertiesCloseElement("style:properties");
159     defaultParagraphStylePropertiesCloseElement.write(pHandler);
160 
161     TagCloseElement defaultParagraphStyleCloseElement("style:default-style");
162     defaultParagraphStyleCloseElement.write(pHandler);
163 
164     TagOpenElement standardStyleOpenElement("style:style");
165         standardStyleOpenElement.addAttribute("style:name", "Standard");
166         standardStyleOpenElement.addAttribute("style:family", "paragraph");
167         standardStyleOpenElement.addAttribute("style:class", "text");
168         standardStyleOpenElement.write(pHandler);
169         TagCloseElement standardStyleCloseElement("style:style");
170         standardStyleCloseElement.write(pHandler);
171 
172         TagOpenElement textBodyStyleOpenElement("style:style");
173         textBodyStyleOpenElement.addAttribute("style:name", "Text Body");
174         textBodyStyleOpenElement.addAttribute("style:family", "paragraph");
175         textBodyStyleOpenElement.addAttribute("style:parent-style-name", "Standard");
176         textBodyStyleOpenElement.addAttribute("style:class", "text");
177         textBodyStyleOpenElement.write(pHandler);
178         TagCloseElement textBodyStyleCloseElement("style:style");
179         textBodyStyleCloseElement.write(pHandler);
180 
181         TagOpenElement tableContentsStyleOpenElement("style:style");
182         tableContentsStyleOpenElement.addAttribute("style:name", "Table Contents");
183         tableContentsStyleOpenElement.addAttribute("style:family", "paragraph");
184         tableContentsStyleOpenElement.addAttribute("style:parent-style-name", "Text Body");
185         tableContentsStyleOpenElement.addAttribute("style:class", "extra");
186         tableContentsStyleOpenElement.write(pHandler);
187         TagCloseElement tableContentsStyleCloseElement("style:style");
188         tableContentsStyleCloseElement.write(pHandler);
189 
190         TagOpenElement tableHeadingStyleOpenElement("style:style");
191         tableHeadingStyleOpenElement.addAttribute("style:name", "Table Heading");
192         tableHeadingStyleOpenElement.addAttribute("style:family", "paragraph");
193         tableHeadingStyleOpenElement.addAttribute("style:parent-style-name", "Table Contents");
194         tableHeadingStyleOpenElement.addAttribute("style:class", "extra");
195         tableHeadingStyleOpenElement.write(pHandler);
196         TagCloseElement tableHeadingStyleCloseElement("style:style");
197         tableHeadingStyleCloseElement.write(pHandler);
198 
199     TagCloseElement stylesCloseElement("office:styles");
200     stylesCloseElement.write(pHandler);
201 
202 }
203 
_writeMasterPages(DocumentHandler * pHandler)204 void DocumentCollector::_writeMasterPages(DocumentHandler *pHandler)
205 {
206         WPXPropertyList xBlankAttrList;
207 
208     pHandler->startElement("office:master-styles", xBlankAttrList);
209     int pageNumber = 1;
210     for (unsigned int i=0; i<mPageSpans.size(); i++)
211     {
212         bool bLastPage;
213         (i == (mPageSpans.size() - 1)) ? bLastPage = true : bLastPage = false;
214         mPageSpans[i]->writeMasterPages(pageNumber, i, bLastPage, pHandler);
215         pageNumber += mPageSpans[i]->getSpan();
216     }
217     pHandler->endElement("office:master-styles");
218 }
219 
_writePageMasters(DocumentHandler * pHandler)220 void DocumentCollector::_writePageMasters(DocumentHandler *pHandler)
221 {
222     for (unsigned int i=0; i<mPageSpans.size(); i++)
223     {
224         mPageSpans[i]->writePageMaster(i, pHandler);
225     }
226 }
227 
_writeTargetDocument(DocumentHandler * pHandler)228 bool DocumentCollector::_writeTargetDocument(DocumentHandler *pHandler)
229 {
230     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Printing out the header stuff..\n"));
231     WPXPropertyList xBlankAttrList;
232 
233     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Start Document\n"));
234     mpHandler->startDocument();
235 
236     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: preamble\n"));
237         WPXPropertyList docContentPropList;
238     docContentPropList.insert("xmlns:office", "http://openoffice.org/2000/office");
239     docContentPropList.insert("xmlns:style", "http://openoffice.org/2000/style");
240     docContentPropList.insert("xmlns:text", "http://openoffice.org/2000/text");
241     docContentPropList.insert("xmlns:table", "http://openoffice.org/2000/table");
242     docContentPropList.insert("xmlns:draw", "http://openoffice.org/2000/draw");
243     docContentPropList.insert("xmlns:fo", "http://www.w3.org/1999/XSL/Format");
244     docContentPropList.insert("xmlns:xlink", "http://www.w3.org/1999/xlink");
245     docContentPropList.insert("xmlns:number", "http://openoffice.org/2000/datastyle");
246     docContentPropList.insert("xmlns:svg", "http://www.w3.org/2000/svg");
247     docContentPropList.insert("xmlns:chart", "http://openoffice.org/2000/chart");
248     docContentPropList.insert("xmlns:dr3d", "http://openoffice.org/2000/dr3d");
249     docContentPropList.insert("xmlns:math", "http://www.w3.org/1998/Math/MathML");
250     docContentPropList.insert("xmlns:form", "http://openoffice.org/2000/form");
251     docContentPropList.insert("xmlns:script", "http://openoffice.org/2000/script");
252     docContentPropList.insert("office:class", "text");
253     docContentPropList.insert("office:version", "1.0");
254         mpHandler->startElement("office:document-content", docContentPropList);
255 
256     // write out the font styles
257     mpHandler->startElement("office:font-decls", xBlankAttrList);
258     for (std::map<WPXString, FontStyle *, ltstr>::iterator iterFont = mFontHash.begin(); iterFont != mFontHash.end(); iterFont++) {
259         iterFont->second->write(mpHandler);
260     }
261     TagOpenElement symbolFontOpen("style:font-decl");
262     symbolFontOpen.addAttribute("style:name", "StarSymbol");
263     symbolFontOpen.addAttribute("fo:font-family", "StarSymbol");
264     symbolFontOpen.addAttribute("style:font-charset", "x-symbol");
265     symbolFontOpen.write(mpHandler);
266         mpHandler->endElement("style:font-decl");
267 
268     mpHandler->endElement("office:font-decls");
269 
270 
271     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Writing out the styles..\n"));
272 
273     // write default styles
274     _writeDefaultStyles(mpHandler);
275 
276     mpHandler->startElement("office:automatic-styles", xBlankAttrList);
277 
278     for (std::map<WPXString, ParagraphStyle *, ltstr>::iterator iterTextStyle = mTextStyleHash.begin();
279              iterTextStyle != mTextStyleHash.end(); iterTextStyle++)
280         {
281         // writing out the paragraph styles
282         if (strcmp((iterTextStyle->second)->getName().cstr(), "Standard"))
283                 {
284             // don't write standard paragraph "no styles" style
285             (iterTextStyle->second)->write(pHandler);
286         }
287     }
288 
289         // span styles..
290     for (std::map<WPXString, SpanStyle *, ltstr>::iterator iterSpanStyle = mSpanStyleHash.begin();
291              iterSpanStyle != mSpanStyleHash.end(); iterSpanStyle++)
292         {
293                 (iterSpanStyle->second)->write(pHandler);
294     }
295 
296     // writing out the sections styles
297     for (std::vector<SectionStyle *>::iterator iterSectionStyles = mSectionStyles.begin(); iterSectionStyles != mSectionStyles.end(); iterSectionStyles++) {
298         (*iterSectionStyles)->write(pHandler);
299     }
300 
301     // writing out the lists styles
302     for (std::vector<ListStyle *>::iterator iterListStyles = mListStyles.begin(); iterListStyles != mListStyles.end(); iterListStyles++) {
303         (*iterListStyles)->write(pHandler);
304     }
305 
306     // writing out the table styles
307     for (std::vector<TableStyle *>::iterator iterTableStyles = mTableStyles.begin(); iterTableStyles != mTableStyles.end(); iterTableStyles++) {
308         (*iterTableStyles)->write(pHandler);
309     }
310 
311     // writing out the page masters
312     _writePageMasters(pHandler);
313 
314 
315     pHandler->endElement("office:automatic-styles");
316 
317     _writeMasterPages(pHandler);
318 
319     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Writing out the document..\n"));
320     // writing out the document
321     pHandler->startElement("office:body", xBlankAttrList);
322 
323     for (std::vector<DocumentElement *>::iterator iterBodyElements = mBodyElements.begin(); iterBodyElements != mBodyElements.end(); iterBodyElements++) {
324         (*iterBodyElements)->write(pHandler);
325     }
326     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Finished writing all doc els..\n"));
327 
328     pHandler->endElement("office:body");
329     pHandler->endElement("office:document-content");
330 
331     pHandler->endDocument();
332 
333     return true;
334 }
335 
336 
propListToStyleKey(const WPXPropertyList & xPropList)337 WPXString propListToStyleKey(const WPXPropertyList & xPropList)
338 {
339         WPXString sKey;
340         WPXPropertyList::Iter i(xPropList);
341         for (i.rewind(); i.next(); )
342         {
343                 WPXString sProp;
344                 sProp.sprintf("[%s:%s]", i.key(), i()->getStr().cstr());
345                 sKey.append(sProp);
346         }
347 
348         return sKey;
349 }
350 
getParagraphStyleKey(const WPXPropertyList & xPropList,const WPXPropertyListVector & xTabStops)351 WPXString getParagraphStyleKey(const WPXPropertyList & xPropList, const WPXPropertyListVector & xTabStops)
352 {
353         WPXString sKey = propListToStyleKey(xPropList);
354 
355         WPXString sTabStops;
356         sTabStops.sprintf("[num-tab-stops:%i]", xTabStops.count());
357         WPXPropertyListVector::Iter i(xTabStops);
358         for (i.rewind(); i.next();)
359         {
360                 sTabStops.append(propListToStyleKey(i()));
361         }
362         sKey.append(sTabStops);
363 
364         return sKey;
365 }
366 
367 // _allocateFontName: add a (potentially mapped) font style to the hash if it's not already there, do nothing otherwise
_allocateFontName(const WPXString & sFontName)368 void DocumentCollector::_allocateFontName(const WPXString & sFontName)
369 {
370     if (mFontHash.find(sFontName) == mFontHash.end())
371     {
372         FontStyle *pFontStyle = new FontStyle(sFontName.cstr(), sFontName.cstr());
373         mFontHash[sFontName] = pFontStyle;
374     }
375 }
376 
openPageSpan(const WPXPropertyList & propList)377 void DocumentCollector::openPageSpan(const WPXPropertyList &propList)
378 {
379     PageSpan *pPageSpan = new PageSpan(propList);
380     mPageSpans.push_back(pPageSpan);
381     mpCurrentPageSpan = pPageSpan;
382 }
383 
openHeader(const WPXPropertyList & propList)384 void DocumentCollector::openHeader(const WPXPropertyList &propList)
385 {
386     std::vector<DocumentElement *> * pHeaderFooterContentElements = new std::vector<DocumentElement *>;
387 
388     if (propList["libwpd:occurence"]->getStr() == "even")
389                 mpCurrentPageSpan->setHeaderLeftContent(pHeaderFooterContentElements);
390         else
391                 mpCurrentPageSpan->setHeaderContent(pHeaderFooterContentElements);
392 
393     mpCurrentContentElements = pHeaderFooterContentElements;
394 }
395 
closeHeader()396 void DocumentCollector::closeHeader()
397 {
398     mpCurrentContentElements = &mBodyElements;
399 }
400 
openFooter(const WPXPropertyList & propList)401 void DocumentCollector::openFooter(const WPXPropertyList &propList)
402 {
403     std::vector<DocumentElement *> * pHeaderFooterContentElements = new std::vector<DocumentElement *>;
404 
405     if (propList["libwpd:occurence"]->getStr() == "even")
406                 mpCurrentPageSpan->setFooterLeftContent(pHeaderFooterContentElements);
407         else
408                 mpCurrentPageSpan->setFooterContent(pHeaderFooterContentElements);
409 
410     mpCurrentContentElements = pHeaderFooterContentElements;
411 }
412 
closeFooter()413 void DocumentCollector::closeFooter()
414 {
415     mpCurrentContentElements = &mBodyElements;
416 }
417 
openSection(const WPXPropertyList & propList,const WPXPropertyListVector & columns)418 void DocumentCollector::openSection(const WPXPropertyList &propList, const WPXPropertyListVector &columns)
419 {
420         int iNumColumns = columns.count();
421     float fSectionMarginLeft = 0.0f;
422     float fSectionMarginRight = 0.0f;
423     if (propList["fo:margin-left"])
424         fSectionMarginLeft = propList["fo:margin-left"]->getFloat();
425     if (propList["fo:margin-right"])
426         fSectionMarginRight = propList["fo:margin-right"]->getFloat();
427 
428     if (iNumColumns > 1 || fSectionMarginLeft != 0 || fSectionMarginRight != 0)
429     {
430         mfSectionSpaceAfter = propList["fo:margin-bottom"]->getFloat();
431         WPXString sSectionName;
432         sSectionName.sprintf("Section%i", mSectionStyles.size());
433 
434         SectionStyle *pSectionStyle = new SectionStyle(propList, columns, sSectionName.cstr());
435         mSectionStyles.push_back(pSectionStyle);
436 
437         TagOpenElement *pSectionOpenElement = new TagOpenElement("text:section");
438         pSectionOpenElement->addAttribute("text:style-name", pSectionStyle->getName());
439         pSectionOpenElement->addAttribute("text:name", pSectionStyle->getName());
440         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pSectionOpenElement));
441     }
442     else
443         mWriterDocumentState.mbInFakeSection = true;
444 }
445 
closeSection()446 void DocumentCollector::closeSection()
447 {
448     if (!mWriterDocumentState.mbInFakeSection)
449         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:section")));
450     else
451         mWriterDocumentState.mbInFakeSection = false;
452 
453     // open as many paragraphs as needed to simulate section space after
454     // WLACH_REFACTORING: disable this for now..
455     #if 0
456     for (float f=0.0f; f<mfSectionSpaceAfter; f+=1.0f) {
457         vector<WPXTabStop> dummyTabStops;
458         openParagraph(WPX_PARAGRAPH_JUSTIFICATION_LEFT, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, dummyTabStops, false, false);
459         closeParagraph();
460     }
461     #endif
462     mfSectionSpaceAfter = 0.0f;
463 }
464 
openParagraph(const WPXPropertyList & propList,const WPXPropertyListVector & tabStops)465 void DocumentCollector::openParagraph(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops)
466 {
467     // FIXMENOW: What happens if we open a footnote inside a table? do we then inherit the footnote's style
468     // from "Table Contents"
469 
470     WPXPropertyList *pPersistPropList = new WPXPropertyList(propList);
471     ParagraphStyle *pStyle = NULL;
472 
473     if (mWriterDocumentState.mbFirstElement && mpCurrentContentElements == &mBodyElements)
474     {
475         // we don't have to go through the fuss of determining if the paragraph style is
476         // unique in this case, because if we are the first document element, then we
477         // are singular. Neither do we have to determine what our parent style is-- we can't
478         // be inside a table in this case (the table would be the first document element
479         //in that case)
480         pPersistPropList->insert("style:parent-style-name", "Standard");
481         WPXString sName;
482         sName.sprintf("FS");
483 
484         WPXString sParagraphHashKey("P|FS");
485         pPersistPropList->insert("style:master-page-name", "Page Style 1");
486                 pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
487         mTextStyleHash[sParagraphHashKey] = pStyle;
488         mWriterDocumentState.mbFirstElement = false;
489     }
490     else
491     {
492         if (mWriterDocumentState.mbTableCellOpened)
493         {
494             if (mWriterDocumentState.mbHeaderRow)
495                 pPersistPropList->insert("style:parent-style-name", "Table Heading");
496             else
497                 pPersistPropList->insert("style:parent-style-name", "Table Contents");
498         }
499         else
500             pPersistPropList->insert("style:parent-style-name", "Standard");
501 
502                 WPXString sKey = getParagraphStyleKey(*pPersistPropList, tabStops);
503 
504         if (mTextStyleHash.find(sKey) == mTextStyleHash.end()) {
505             WPXString sName;
506             sName.sprintf("S%i", mTextStyleHash.size());
507 
508             pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
509 
510             mTextStyleHash[sKey] = pStyle;
511         }
512         else
513         {
514             pStyle = mTextStyleHash[sKey];
515             delete pPersistPropList;
516         }
517     }
518     // create a document element corresponding to the paragraph, and append it to our list of document elements
519     TagOpenElement *pParagraphOpenElement = new TagOpenElement("text:p");
520     pParagraphOpenElement->addAttribute("text:style-name", pStyle->getName());
521     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pParagraphOpenElement));
522 }
523 
closeParagraph()524 void DocumentCollector::closeParagraph()
525 {
526     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
527 }
528 
openSpan(const WPXPropertyList & propList)529 void DocumentCollector::openSpan(const WPXPropertyList &propList)
530 {
531         if (propList["style:font-name"])
532                 _allocateFontName(propList["style:font-name"]->getStr());
533     WPXString sSpanHashKey = propListToStyleKey(propList);
534     WRITER_DEBUG_MSG(("WriterWordPerfect: Span Hash Key: %s\n", sSpanHashKey.cstr()));
535 
536     // Get the style
537         WPXString sName;
538     if (mSpanStyleHash.find(sSpanHashKey) == mSpanStyleHash.end())
539         {
540         // allocate a new paragraph style
541         sName.sprintf("Span%i", mSpanStyleHash.size());
542         SpanStyle *pStyle = new SpanStyle(sName.cstr(), propList);
543 
544         mSpanStyleHash[sSpanHashKey] = pStyle;
545     }
546     else
547         {
548         sName.sprintf("%s", mSpanStyleHash.find(sSpanHashKey)->second->getName().cstr());
549     }
550 
551     // create a document element corresponding to the paragraph, and append it to our list of document elements
552     TagOpenElement *pSpanOpenElement = new TagOpenElement("text:span");
553     pSpanOpenElement->addAttribute("text:style-name", sName.cstr());
554     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pSpanOpenElement));
555 }
556 
closeSpan()557 void DocumentCollector::closeSpan()
558 {
559     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:span")));
560 }
561 
defineOrderedListLevel(const WPXPropertyList & propList)562 void DocumentCollector::defineOrderedListLevel(const WPXPropertyList &propList)
563 {
564         int id = 0;
565         if (propList["libwpd:id"])
566                 id = propList["libwpd:id"]->getInt();
567 
568     OrderedListStyle *pOrderedListStyle = NULL;
569     if (mpCurrentListStyle && mpCurrentListStyle->getListID() == id)
570         pOrderedListStyle = static_cast<OrderedListStyle *>(mpCurrentListStyle); // FIXME: using a dynamic cast here causes oo to crash?!
571 
572     // this rather appalling conditional makes sure we only start a new list (rather than continue an old
573     // one) if: (1) we have no prior list OR (2) the prior list is actually definitively different
574     // from the list that is just being defined (listIDs differ) OR (3) we can tell that the user actually
575     // is starting a new list at level 1 (and only level 1)
576     if (pOrderedListStyle == NULL || pOrderedListStyle->getListID() != id  ||
577         (propList["libwpd:level"] && propList["libwpd:level"]->getInt()==1 &&
578              (propList["text:start-value"] && (unsigned int)(propList["text:start-value"]->getInt()) != (miLastListNumber+1))))
579     {
580         WRITER_DEBUG_MSG(("Attempting to create a new ordered list style (listid: %i)\n", id));
581         WPXString sName;
582         sName.sprintf("OL%i", miNumListStyles);
583         miNumListStyles++;
584         pOrderedListStyle = new OrderedListStyle(sName.cstr(), propList["libwpd:id"]->getInt());
585         mListStyles.push_back(static_cast<ListStyle *>(pOrderedListStyle));
586         mpCurrentListStyle = static_cast<ListStyle *>(pOrderedListStyle);
587         mbListContinueNumbering = false;
588         miLastListNumber = 0;
589     }
590     else
591         mbListContinueNumbering = true;
592 
593     // Iterate through ALL list styles with the same WordPerfect list id and define a level if it is not already defined
594     // This solves certain problems with lists that start and finish without reaching certain levels and then begin again
595     // and reach those levels. See gradguide0405_PC.wpd in the regression suite
596     for (std::vector<ListStyle *>::iterator iterOrderedListStyles = mListStyles.begin(); iterOrderedListStyles != mListStyles.end(); iterOrderedListStyles++)
597     {
598         if ((* iterOrderedListStyles)->getListID() == propList["libwpd:id"]->getInt())
599             (* iterOrderedListStyles)->updateListLevel((propList["libwpd:level"]->getInt() - 1), propList);
600     }
601 }
602 
defineUnorderedListLevel(const WPXPropertyList & propList)603 void DocumentCollector::defineUnorderedListLevel(const WPXPropertyList &propList)
604 {
605         int id = 0;
606         if (propList["libwpd:id"])
607                 id = propList["libwpd:id"]->getInt();
608 
609     UnorderedListStyle *pUnorderedListStyle = NULL;
610     if (mpCurrentListStyle && mpCurrentListStyle->getListID() == id)
611         pUnorderedListStyle = static_cast<UnorderedListStyle *>(mpCurrentListStyle); // FIXME: using a dynamic cast here causes oo to crash?!
612 
613     if (pUnorderedListStyle == NULL) {
614         WRITER_DEBUG_MSG(("Attempting to create a new unordered list style (listid: %i)\n", id));
615         WPXString sName;
616         sName.sprintf("UL%i", miNumListStyles);
617         pUnorderedListStyle = new UnorderedListStyle(sName.cstr(), id);
618         mListStyles.push_back(static_cast<ListStyle *>(pUnorderedListStyle));
619         mpCurrentListStyle = static_cast<ListStyle *>(pUnorderedListStyle);
620     }
621 
622     // See comment in DocumentCollector::defineOrderedListLevel
623     for (std::vector<ListStyle *>::iterator iterUnorderedListStyles = mListStyles.begin(); iterUnorderedListStyles != mListStyles.end(); iterUnorderedListStyles++)
624     {
625         if ((* iterUnorderedListStyles)->getListID() == propList["libwpd:id"]->getInt())
626             (* iterUnorderedListStyles)->updateListLevel((propList["libwpd:level"]->getInt() - 1), propList);
627     }
628 }
629 
openOrderedListLevel(const WPXPropertyList &)630 void DocumentCollector::openOrderedListLevel(const WPXPropertyList & /* propList */)
631 {
632     miCurrentListLevel++;
633     TagOpenElement *pListLevelOpenElement = new TagOpenElement("text:ordered-list");
634     _openListLevel(pListLevelOpenElement);
635 
636     if (mbListContinueNumbering) {
637         pListLevelOpenElement->addAttribute("text:continue-numbering", "true");
638     }
639 
640     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pListLevelOpenElement));
641 }
642 
openUnorderedListLevel(const WPXPropertyList &)643 void DocumentCollector::openUnorderedListLevel(const WPXPropertyList & /* propList */)
644 {
645     miCurrentListLevel++;
646     TagOpenElement *pListLevelOpenElement = new TagOpenElement("text:unordered-list");
647     _openListLevel(pListLevelOpenElement);
648 
649     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pListLevelOpenElement));
650 }
651 
_openListLevel(TagOpenElement * pListLevelOpenElement)652 void DocumentCollector::_openListLevel(TagOpenElement *pListLevelOpenElement)
653 {
654     if (!mbListElementOpened && miCurrentListLevel > 1)
655     {
656         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:list-item")));
657     }
658     else if (mbListElementParagraphOpened)
659     {
660         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
661         mbListElementParagraphOpened = false;
662     }
663 
664     if (miCurrentListLevel==1) {
665         pListLevelOpenElement->addAttribute("text:style-name", mpCurrentListStyle->getName());
666     }
667 
668     mbListElementOpened = false;
669 }
670 
closeOrderedListLevel()671 void DocumentCollector::closeOrderedListLevel()
672 {
673     _closeListLevel("ordered-list");
674 }
675 
closeUnorderedListLevel()676 void DocumentCollector::closeUnorderedListLevel()
677 {
678     _closeListLevel("unordered-list");
679 }
680 
_closeListLevel(const char * szListType)681 void DocumentCollector::_closeListLevel(const char *szListType)
682 {
683     if (mbListElementOpened)
684         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
685 
686     miCurrentListLevel--;
687 
688     WPXString sCloseElement;
689     sCloseElement.sprintf("text:%s", szListType);
690     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement(sCloseElement.cstr())));
691 
692     if (miCurrentListLevel > 0)
693         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
694     mbListElementOpened = false;
695 }
696 
openListElement(const WPXPropertyList & propList,const WPXPropertyListVector & tabStops)697 void DocumentCollector::openListElement(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops)
698 {
699     miLastListLevel = miCurrentListLevel;
700     if (miCurrentListLevel == 1)
701         miLastListNumber++;
702 
703     if (mbListElementOpened)
704         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
705 
706     ParagraphStyle *pStyle = NULL;
707 
708     WPXPropertyList *pPersistPropList = new WPXPropertyList(propList);
709     pPersistPropList->insert("style:list-style-name", mpCurrentListStyle->getName());
710     pPersistPropList->insert("style:parent-style-name", "Standard");
711 
712         WPXString sKey = getParagraphStyleKey(*pPersistPropList, tabStops);
713 
714         if (mTextStyleHash.find(sKey) == mTextStyleHash.end())
715         {
716                 WPXString sName;
717                 sName.sprintf("S%i", mTextStyleHash.size());
718 
719                 pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
720 
721                 mTextStyleHash[sKey] = pStyle;
722         }
723         else
724         {
725                 pStyle = mTextStyleHash[sKey];
726                 delete pPersistPropList;
727         }
728 
729     TagOpenElement *pOpenListElement = new TagOpenElement("text:list-item");
730     TagOpenElement *pOpenListElementParagraph = new TagOpenElement("text:p");
731 
732     pOpenListElementParagraph->addAttribute("text:style-name", pStyle->getName());
733 
734     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenListElement));
735     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenListElementParagraph));
736 
737     mbListElementOpened = true;
738     mbListElementParagraphOpened = true;
739     mbListContinueNumbering = false;
740 }
741 
closeListElement()742 void DocumentCollector::closeListElement()
743 {
744     // this code is kind of tricky, because we don't actually close the list element (because this list element
745     // could contain another list level in OOo's implementation of lists). that is done in the closeListLevel
746     // code (or when we open another list element)
747 
748     if (mbListElementParagraphOpened)
749     {
750         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
751         mbListElementParagraphOpened = false;
752     }
753 }
754 
openFootnote(const WPXPropertyList & propList)755 void DocumentCollector::openFootnote(const WPXPropertyList &propList)
756 {
757     TagOpenElement *pOpenFootNote = new TagOpenElement("text:footnote");
758     if (propList["libwpd:number"])
759     {
760         WPXString tmpString("ftn");
761         tmpString.append(propList["libwpd:number"]->getStr());
762         pOpenFootNote->addAttribute("text:id", tmpString);
763     }
764     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenFootNote));
765 
766     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:footnote-citation")));
767         if (propList["libwpd:number"])
768                 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new CharDataElement(propList["libwpd:number"]->getStr().cstr())));
769     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote-citation")));
770 
771     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:footnote-body")));
772 
773     mWriterDocumentState.mbInNote = true;
774 }
775 
closeFootnote()776 void DocumentCollector::closeFootnote()
777 {
778     mWriterDocumentState.mbInNote = false;
779 
780     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote-body")));
781     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote")));
782 }
783 
openEndnote(const WPXPropertyList & propList)784 void DocumentCollector::openEndnote(const WPXPropertyList &propList)
785 {
786     TagOpenElement *pOpenEndNote = new TagOpenElement("text:endnote");
787     if (propList["libwpd:number"])
788     {
789         WPXString tmpString("edn");
790         tmpString.append(propList["libwpd:number"]->getStr());
791         pOpenEndNote->addAttribute("text:id", tmpString);
792     }
793     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenEndNote));
794 
795     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:endnote-citation")));
796         if (propList["libwpd:number"])
797                 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new CharDataElement(propList["libwpd:number"]->getStr().cstr())));
798     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote-citation")));
799 
800     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:endnote-body")));
801 
802 }
closeEndnote()803 void DocumentCollector::closeEndnote()
804 {
805     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote-body")));
806     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote")));
807 }
808 
openTable(const WPXPropertyList & propList,const WPXPropertyListVector & columns)809 void DocumentCollector::openTable(const WPXPropertyList &propList, const WPXPropertyListVector &columns)
810 {
811     WPXString sTableName;
812     sTableName.sprintf("Table%i", mTableStyles.size());
813 
814     // FIXME: we base the table style off of the page's margin left, ignoring (potential) wordperfect margin
815     // state which is transmitted inside the page. could this lead to unacceptable behaviour?
816         // WLACH_REFACTORING: characterize this behaviour, probably should nip it at the bud within libwpd
817     TableStyle *pTableStyle = new TableStyle(propList, columns, sTableName.cstr());
818 
819     if (mWriterDocumentState.mbFirstElement && mpCurrentContentElements == &mBodyElements)
820     {
821         WPXString sMasterPageName("Page Style 1");
822         pTableStyle->setMasterPageName(sMasterPageName);
823         mWriterDocumentState.mbFirstElement = false;
824     }
825 
826     mTableStyles.push_back(pTableStyle);
827 
828     mpCurrentTableStyle = pTableStyle;
829 
830     TagOpenElement *pTableOpenElement = new TagOpenElement("table:table");
831 
832     pTableOpenElement->addAttribute("table:name", sTableName.cstr());
833     pTableOpenElement->addAttribute("table:style-name", sTableName.cstr());
834     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableOpenElement));
835 
836     for (int i=0; i<pTableStyle->getNumColumns(); i++)
837         {
838         TagOpenElement *pTableColumnOpenElement = new TagOpenElement("table:table-column");
839         WPXString sColumnStyleName;
840         sColumnStyleName.sprintf("%s.Column%i", sTableName.cstr(), (i+1));
841         pTableColumnOpenElement->addAttribute("table:style-name", sColumnStyleName.cstr());
842         mpCurrentContentElements->push_back(pTableColumnOpenElement);
843 
844         TagCloseElement *pTableColumnCloseElement = new TagCloseElement("table:table-column");
845         mpCurrentContentElements->push_back(pTableColumnCloseElement);
846     }
847 }
848 
openTableRow(const WPXPropertyList & propList)849 void DocumentCollector::openTableRow(const WPXPropertyList &propList)
850 {
851     if (propList["libwpd:is-header-row"] && (propList["libwpd:is-header-row"]->getInt()))
852     {
853         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("table:table-header-rows")));
854         mWriterDocumentState.mbHeaderRow = true;
855     }
856 
857     WPXString sTableRowStyleName;
858     sTableRowStyleName.sprintf("%s.Row%i", mpCurrentTableStyle->getName().cstr(), mpCurrentTableStyle->getNumTableRowStyles());
859     TableRowStyle *pTableRowStyle = new TableRowStyle(propList, sTableRowStyleName.cstr());
860     mpCurrentTableStyle->addTableRowStyle(pTableRowStyle);
861 
862     TagOpenElement *pTableRowOpenElement = new TagOpenElement("table:table-row");
863     pTableRowOpenElement->addAttribute("table:style-name", sTableRowStyleName);
864     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableRowOpenElement));
865 }
866 
closeTableRow()867 void DocumentCollector::closeTableRow()
868 {
869     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-row")));
870     if (mWriterDocumentState.mbHeaderRow)
871     {
872         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-header-rows")));
873         mWriterDocumentState.mbHeaderRow = false;
874     }
875 }
876 
openTableCell(const WPXPropertyList & propList)877 void DocumentCollector::openTableCell(const WPXPropertyList &propList)
878 {
879     WPXString sTableCellStyleName;
880     sTableCellStyleName.sprintf( "%s.Cell%i", mpCurrentTableStyle->getName().cstr(), mpCurrentTableStyle->getNumTableCellStyles());
881     TableCellStyle *pTableCellStyle = new TableCellStyle(propList, sTableCellStyleName.cstr());
882     mpCurrentTableStyle->addTableCellStyle(pTableCellStyle);
883 
884     TagOpenElement *pTableCellOpenElement = new TagOpenElement("table:table-cell");
885     pTableCellOpenElement->addAttribute("table:style-name", sTableCellStyleName);
886     if (propList["table:number-columns-spanned"])
887                 pTableCellOpenElement->addAttribute("table:number-columns-spanned",
888                                                     propList["table:number-columns-spanned"]->getStr().cstr());
889         if (propList["table:number-rows-spanned"])
890                 pTableCellOpenElement->addAttribute("table:number-rows-spanned",
891                                                     propList["table:number-rows-spanned"]->getStr().cstr());
892     pTableCellOpenElement->addAttribute("table:value-type", "string");
893     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableCellOpenElement));
894 
895     mWriterDocumentState.mbTableCellOpened = true;
896 }
897 
closeTableCell()898 void DocumentCollector::closeTableCell()
899 {
900     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-cell")));
901     mWriterDocumentState.mbTableCellOpened = false;
902 }
903 
insertCoveredTableCell(const WPXPropertyList &)904 void DocumentCollector::insertCoveredTableCell(const WPXPropertyList & /* propList */)
905 {
906     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("table:covered-table-cell")));
907     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:covered-table-cell")));
908 }
909 
closeTable()910 void DocumentCollector::closeTable()
911 {
912     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table")));
913 }
914 
insertTab()915 void DocumentCollector::insertTab()
916 {
917     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:tab-stop")));
918     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:tab-stop")));
919 }
920 
insertLineBreak()921 void DocumentCollector::insertLineBreak()
922 {
923     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:line-break")));
924     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:line-break")));
925 }
926 
insertText(const WPXString & text)927 void DocumentCollector::insertText(const WPXString &text)
928 {
929     DocumentElement *pText = new TextElement(text);
930     mpCurrentContentElements->push_back(pText);
931 }
932