merge the formfield patch from ooo-build
[ooovba.git] / writerperfect / source / filter / DocumentCollector.cxx
blob5baae93f1a8c8553356b6eadfc298a7d89090d6a
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
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)
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.
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.
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
23 * For further information visit http://libwpd.sourceforge.net
27 /* "This product is not manufactured, approved, or supported by
28 * Corel Corporation or Corel Corporation Limited."
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
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"
51 _WriterDocumentState::_WriterDocumentState() :
52 mbFirstElement(true),
53 mbInFakeSection(false),
54 mbListElementOpenedAtCurrentLevel(false),
55 mbTableCellOpened(false),
56 mbHeaderRow(false),
57 mbInNote(false)
61 DocumentCollector::DocumentCollector(WPSInputStream *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)
80 DocumentCollector::~DocumentCollector()
84 bool DocumentCollector::filter()
86 // The contract for DocumentCollector is that it will only be used once after it is
87 // instantiated
88 if (mbUsed)
89 return false;
91 mbUsed = true;
93 // parse & write
94 // WLACH_REFACTORING: Remove these args..
95 if (!parseSourceDocument(*mpInput))
96 return false;
97 if (!_writeTargetDocument(mpHandler))
98 return false;
100 // clean up the mess we made
101 WRITER_DEBUG_MSG(("WriterWordPerfect: Cleaning up our mess..\n"));
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;
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
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;
120 for (std::map<WPXString, SpanStyle *, ltstr>::iterator iterSpanStyle = mSpanStyleHash.begin(); iterSpanStyle != mSpanStyleHash.end(); iterSpanStyle++) {
121 delete iterSpanStyle->second;
124 for (std::map<WPXString, FontStyle *, ltstr>::iterator iterFont = mFontHash.begin(); iterFont != mFontHash.end(); iterFont++) {
125 delete iterFont->second;
128 for (std::vector<ListStyle *>::iterator iterListStyles = mListStyles.begin(); iterListStyles != mListStyles.end(); iterListStyles++) {
129 delete (*iterListStyles);
131 for (std::vector<SectionStyle *>::iterator iterSectionStyles = mSectionStyles.begin(); iterSectionStyles != mSectionStyles.end(); iterSectionStyles++) {
132 delete (*iterSectionStyles);
134 for (std::vector<TableStyle *>::iterator iterTableStyles = mTableStyles.begin(); iterTableStyles != mTableStyles.end(); iterTableStyles++) {
135 delete (*iterTableStyles);
138 for (std::vector<PageSpan *>::iterator iterPageSpans = mPageSpans.begin(); iterPageSpans != mPageSpans.end(); iterPageSpans++) {
139 delete (*iterPageSpans);
142 return true;
145 void DocumentCollector::_writeDefaultStyles(DocumentHandler *pHandler)
147 TagOpenElement stylesOpenElement("office:styles");
148 stylesOpenElement.write(pHandler);
150 TagOpenElement defaultParagraphStyleOpenElement("style:default-style");
151 defaultParagraphStyleOpenElement.addAttribute("style:family", "paragraph");
152 defaultParagraphStyleOpenElement.write(pHandler);
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);
161 TagCloseElement defaultParagraphStyleCloseElement("style:default-style");
162 defaultParagraphStyleCloseElement.write(pHandler);
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);
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);
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);
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);
199 TagCloseElement stylesCloseElement("office:styles");
200 stylesCloseElement.write(pHandler);
204 void DocumentCollector::_writeMasterPages(DocumentHandler *pHandler)
206 WPXPropertyList xBlankAttrList;
208 pHandler->startElement("office:master-styles", xBlankAttrList);
209 int pageNumber = 1;
210 for (unsigned int i=0; i<mPageSpans.size(); i++)
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();
217 pHandler->endElement("office:master-styles");
220 void DocumentCollector::_writePageMasters(DocumentHandler *pHandler)
222 for (unsigned int i=0; i<mPageSpans.size(); i++)
224 mPageSpans[i]->writePageMaster(i, pHandler);
228 bool DocumentCollector::_writeTargetDocument(DocumentHandler *pHandler)
230 WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Printing out the header stuff..\n"));
231 WPXPropertyList xBlankAttrList;
233 WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Start Document\n"));
234 mpHandler->startDocument();
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);
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);
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");
268 mpHandler->endElement("office:font-decls");
271 WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Writing out the styles..\n"));
273 // write default styles
274 _writeDefaultStyles(mpHandler);
276 mpHandler->startElement("office:automatic-styles", xBlankAttrList);
278 for (std::map<WPXString, ParagraphStyle *, ltstr>::iterator iterTextStyle = mTextStyleHash.begin();
279 iterTextStyle != mTextStyleHash.end(); iterTextStyle++)
281 // writing out the paragraph styles
282 if (strcmp((iterTextStyle->second)->getName().cstr(), "Standard"))
284 // don't write standard paragraph "no styles" style
285 (iterTextStyle->second)->write(pHandler);
289 // span styles..
290 for (std::map<WPXString, SpanStyle *, ltstr>::iterator iterSpanStyle = mSpanStyleHash.begin();
291 iterSpanStyle != mSpanStyleHash.end(); iterSpanStyle++)
293 (iterSpanStyle->second)->write(pHandler);
296 // writing out the sections styles
297 for (std::vector<SectionStyle *>::iterator iterSectionStyles = mSectionStyles.begin(); iterSectionStyles != mSectionStyles.end(); iterSectionStyles++) {
298 (*iterSectionStyles)->write(pHandler);
301 // writing out the lists styles
302 for (std::vector<ListStyle *>::iterator iterListStyles = mListStyles.begin(); iterListStyles != mListStyles.end(); iterListStyles++) {
303 (*iterListStyles)->write(pHandler);
306 // writing out the table styles
307 for (std::vector<TableStyle *>::iterator iterTableStyles = mTableStyles.begin(); iterTableStyles != mTableStyles.end(); iterTableStyles++) {
308 (*iterTableStyles)->write(pHandler);
311 // writing out the page masters
312 _writePageMasters(pHandler);
315 pHandler->endElement("office:automatic-styles");
317 _writeMasterPages(pHandler);
319 WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Writing out the document..\n"));
320 // writing out the document
321 pHandler->startElement("office:body", xBlankAttrList);
323 for (std::vector<DocumentElement *>::iterator iterBodyElements = mBodyElements.begin(); iterBodyElements != mBodyElements.end(); iterBodyElements++) {
324 (*iterBodyElements)->write(pHandler);
326 WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Finished writing all doc els..\n"));
328 pHandler->endElement("office:body");
329 pHandler->endElement("office:document-content");
331 pHandler->endDocument();
333 return true;
337 WPXString propListToStyleKey(const WPXPropertyList & xPropList)
339 WPXString sKey;
340 WPXPropertyList::Iter i(xPropList);
341 for (i.rewind(); i.next(); )
343 WPXString sProp;
344 sProp.sprintf("[%s:%s]", i.key(), i()->getStr().cstr());
345 sKey.append(sProp);
348 return sKey;
351 WPXString getParagraphStyleKey(const WPXPropertyList & xPropList, const WPXPropertyListVector & xTabStops)
353 WPXString sKey = propListToStyleKey(xPropList);
355 WPXString sTabStops;
356 sTabStops.sprintf("[num-tab-stops:%i]", xTabStops.count());
357 WPXPropertyListVector::Iter i(xTabStops);
358 for (i.rewind(); i.next();)
360 sTabStops.append(propListToStyleKey(i()));
362 sKey.append(sTabStops);
364 return sKey;
367 // _allocateFontName: add a (potentially mapped) font style to the hash if it's not already there, do nothing otherwise
368 void DocumentCollector::_allocateFontName(const WPXString & sFontName)
370 if (mFontHash.find(sFontName) == mFontHash.end())
372 FontStyle *pFontStyle = new FontStyle(sFontName.cstr(), sFontName.cstr());
373 mFontHash[sFontName] = pFontStyle;
377 void DocumentCollector::openPageSpan(const WPXPropertyList &propList)
379 PageSpan *pPageSpan = new PageSpan(propList);
380 mPageSpans.push_back(pPageSpan);
381 mpCurrentPageSpan = pPageSpan;
384 void DocumentCollector::openHeader(const WPXPropertyList &propList)
386 std::vector<DocumentElement *> * pHeaderFooterContentElements = new std::vector<DocumentElement *>;
388 if (propList["libwpd:occurence"]->getStr() == "even")
389 mpCurrentPageSpan->setHeaderLeftContent(pHeaderFooterContentElements);
390 else
391 mpCurrentPageSpan->setHeaderContent(pHeaderFooterContentElements);
393 mpCurrentContentElements = pHeaderFooterContentElements;
396 void DocumentCollector::closeHeader()
398 mpCurrentContentElements = &mBodyElements;
401 void DocumentCollector::openFooter(const WPXPropertyList &propList)
403 std::vector<DocumentElement *> * pHeaderFooterContentElements = new std::vector<DocumentElement *>;
405 if (propList["libwpd:occurence"]->getStr() == "even")
406 mpCurrentPageSpan->setFooterLeftContent(pHeaderFooterContentElements);
407 else
408 mpCurrentPageSpan->setFooterContent(pHeaderFooterContentElements);
410 mpCurrentContentElements = pHeaderFooterContentElements;
413 void DocumentCollector::closeFooter()
415 mpCurrentContentElements = &mBodyElements;
418 void DocumentCollector::openSection(const WPXPropertyList &propList, const WPXPropertyListVector &columns)
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();
428 if (iNumColumns > 1 || fSectionMarginLeft != 0 || fSectionMarginRight != 0)
430 mfSectionSpaceAfter = propList["fo:margin-bottom"]->getFloat();
431 WPXString sSectionName;
432 sSectionName.sprintf("Section%i", mSectionStyles.size());
434 SectionStyle *pSectionStyle = new SectionStyle(propList, columns, sSectionName.cstr());
435 mSectionStyles.push_back(pSectionStyle);
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));
442 else
443 mWriterDocumentState.mbInFakeSection = true;
446 void DocumentCollector::closeSection()
448 if (!mWriterDocumentState.mbInFakeSection)
449 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:section")));
450 else
451 mWriterDocumentState.mbInFakeSection = false;
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();
461 #endif
462 mfSectionSpaceAfter = 0.0f;
465 void DocumentCollector::openParagraph(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops)
467 // FIXMENOW: What happens if we open a footnote inside a table? do we then inherit the footnote's style
468 // from "Table Contents"
470 WPXPropertyList *pPersistPropList = new WPXPropertyList(propList);
471 ParagraphStyle *pStyle = NULL;
473 if (mWriterDocumentState.mbFirstElement && mpCurrentContentElements == &mBodyElements)
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");
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;
490 else
492 if (mWriterDocumentState.mbTableCellOpened)
494 if (mWriterDocumentState.mbHeaderRow)
495 pPersistPropList->insert("style:parent-style-name", "Table Heading");
496 else
497 pPersistPropList->insert("style:parent-style-name", "Table Contents");
499 else
500 pPersistPropList->insert("style:parent-style-name", "Standard");
502 WPXString sKey = getParagraphStyleKey(*pPersistPropList, tabStops);
504 if (mTextStyleHash.find(sKey) == mTextStyleHash.end()) {
505 WPXString sName;
506 sName.sprintf("S%i", mTextStyleHash.size());
508 pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
510 mTextStyleHash[sKey] = pStyle;
512 else
514 pStyle = mTextStyleHash[sKey];
515 delete pPersistPropList;
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));
524 void DocumentCollector::closeParagraph()
526 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
529 void DocumentCollector::openSpan(const WPXPropertyList &propList)
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()));
536 // Get the style
537 WPXString sName;
538 if (mSpanStyleHash.find(sSpanHashKey) == mSpanStyleHash.end())
540 // allocate a new paragraph style
541 sName.sprintf("Span%i", mSpanStyleHash.size());
542 SpanStyle *pStyle = new SpanStyle(sName.cstr(), propList);
544 mSpanStyleHash[sSpanHashKey] = pStyle;
546 else
548 sName.sprintf("%s", mSpanStyleHash.find(sSpanHashKey)->second->getName().cstr());
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));
557 void DocumentCollector::closeSpan()
559 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:span")));
562 void DocumentCollector::defineOrderedListLevel(const WPXPropertyList &propList)
564 int id = 0;
565 if (propList["libwpd:id"])
566 id = propList["libwpd:id"]->getInt();
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?!
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))))
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;
590 else
591 mbListContinueNumbering = true;
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++)
598 if ((* iterOrderedListStyles)->getListID() == propList["libwpd:id"]->getInt())
599 (* iterOrderedListStyles)->updateListLevel((propList["libwpd:level"]->getInt() - 1), propList);
603 void DocumentCollector::defineUnorderedListLevel(const WPXPropertyList &propList)
605 int id = 0;
606 if (propList["libwpd:id"])
607 id = propList["libwpd:id"]->getInt();
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?!
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);
622 // See comment in DocumentCollector::defineOrderedListLevel
623 for (std::vector<ListStyle *>::iterator iterUnorderedListStyles = mListStyles.begin(); iterUnorderedListStyles != mListStyles.end(); iterUnorderedListStyles++)
625 if ((* iterUnorderedListStyles)->getListID() == propList["libwpd:id"]->getInt())
626 (* iterUnorderedListStyles)->updateListLevel((propList["libwpd:level"]->getInt() - 1), propList);
630 void DocumentCollector::openOrderedListLevel(const WPXPropertyList & /* propList */)
632 miCurrentListLevel++;
633 TagOpenElement *pListLevelOpenElement = new TagOpenElement("text:ordered-list");
634 _openListLevel(pListLevelOpenElement);
636 if (mbListContinueNumbering) {
637 pListLevelOpenElement->addAttribute("text:continue-numbering", "true");
640 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pListLevelOpenElement));
643 void DocumentCollector::openUnorderedListLevel(const WPXPropertyList & /* propList */)
645 miCurrentListLevel++;
646 TagOpenElement *pListLevelOpenElement = new TagOpenElement("text:unordered-list");
647 _openListLevel(pListLevelOpenElement);
649 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pListLevelOpenElement));
652 void DocumentCollector::_openListLevel(TagOpenElement *pListLevelOpenElement)
654 if (!mbListElementOpened && miCurrentListLevel > 1)
656 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:list-item")));
658 else if (mbListElementParagraphOpened)
660 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
661 mbListElementParagraphOpened = false;
664 if (miCurrentListLevel==1) {
665 pListLevelOpenElement->addAttribute("text:style-name", mpCurrentListStyle->getName());
668 mbListElementOpened = false;
671 void DocumentCollector::closeOrderedListLevel()
673 _closeListLevel("ordered-list");
676 void DocumentCollector::closeUnorderedListLevel()
678 _closeListLevel("unordered-list");
681 void DocumentCollector::_closeListLevel(const char *szListType)
683 if (mbListElementOpened)
684 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
686 miCurrentListLevel--;
688 WPXString sCloseElement;
689 sCloseElement.sprintf("text:%s", szListType);
690 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement(sCloseElement.cstr())));
692 if (miCurrentListLevel > 0)
693 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
694 mbListElementOpened = false;
697 void DocumentCollector::openListElement(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops)
699 miLastListLevel = miCurrentListLevel;
700 if (miCurrentListLevel == 1)
701 miLastListNumber++;
703 if (mbListElementOpened)
704 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
706 ParagraphStyle *pStyle = NULL;
708 WPXPropertyList *pPersistPropList = new WPXPropertyList(propList);
709 pPersistPropList->insert("style:list-style-name", mpCurrentListStyle->getName());
710 pPersistPropList->insert("style:parent-style-name", "Standard");
712 WPXString sKey = getParagraphStyleKey(*pPersistPropList, tabStops);
714 if (mTextStyleHash.find(sKey) == mTextStyleHash.end())
716 WPXString sName;
717 sName.sprintf("S%i", mTextStyleHash.size());
719 pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
721 mTextStyleHash[sKey] = pStyle;
723 else
725 pStyle = mTextStyleHash[sKey];
726 delete pPersistPropList;
729 TagOpenElement *pOpenListElement = new TagOpenElement("text:list-item");
730 TagOpenElement *pOpenListElementParagraph = new TagOpenElement("text:p");
732 pOpenListElementParagraph->addAttribute("text:style-name", pStyle->getName());
734 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenListElement));
735 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenListElementParagraph));
737 mbListElementOpened = true;
738 mbListElementParagraphOpened = true;
739 mbListContinueNumbering = false;
742 void DocumentCollector::closeListElement()
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)
748 if (mbListElementParagraphOpened)
750 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
751 mbListElementParagraphOpened = false;
755 void DocumentCollector::openFootnote(const WPXPropertyList &propList)
757 TagOpenElement *pOpenFootNote = new TagOpenElement("text:footnote");
758 if (propList["libwpd:number"])
760 WPXString tmpString("ftn");
761 tmpString.append(propList["libwpd:number"]->getStr());
762 pOpenFootNote->addAttribute("text:id", tmpString);
764 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenFootNote));
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")));
771 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:footnote-body")));
773 mWriterDocumentState.mbInNote = true;
776 void DocumentCollector::closeFootnote()
778 mWriterDocumentState.mbInNote = false;
780 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote-body")));
781 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote")));
784 void DocumentCollector::openEndnote(const WPXPropertyList &propList)
786 TagOpenElement *pOpenEndNote = new TagOpenElement("text:endnote");
787 if (propList["libwpd:number"])
789 WPXString tmpString("edn");
790 tmpString.append(propList["libwpd:number"]->getStr());
791 pOpenEndNote->addAttribute("text:id", tmpString);
793 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenEndNote));
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")));
800 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:endnote-body")));
803 void DocumentCollector::closeEndnote()
805 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote-body")));
806 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote")));
809 void DocumentCollector::openTable(const WPXPropertyList &propList, const WPXPropertyListVector &columns)
811 WPXString sTableName;
812 sTableName.sprintf("Table%i", mTableStyles.size());
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());
819 if (mWriterDocumentState.mbFirstElement && mpCurrentContentElements == &mBodyElements)
821 WPXString sMasterPageName("Page Style 1");
822 pTableStyle->setMasterPageName(sMasterPageName);
823 mWriterDocumentState.mbFirstElement = false;
826 mTableStyles.push_back(pTableStyle);
828 mpCurrentTableStyle = pTableStyle;
830 TagOpenElement *pTableOpenElement = new TagOpenElement("table:table");
832 pTableOpenElement->addAttribute("table:name", sTableName.cstr());
833 pTableOpenElement->addAttribute("table:style-name", sTableName.cstr());
834 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableOpenElement));
836 for (int i=0; i<pTableStyle->getNumColumns(); i++)
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);
844 TagCloseElement *pTableColumnCloseElement = new TagCloseElement("table:table-column");
845 mpCurrentContentElements->push_back(pTableColumnCloseElement);
849 void DocumentCollector::openTableRow(const WPXPropertyList &propList)
851 if (propList["libwpd:is-header-row"] && (propList["libwpd:is-header-row"]->getInt()))
853 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("table:table-header-rows")));
854 mWriterDocumentState.mbHeaderRow = true;
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);
862 TagOpenElement *pTableRowOpenElement = new TagOpenElement("table:table-row");
863 pTableRowOpenElement->addAttribute("table:style-name", sTableRowStyleName);
864 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableRowOpenElement));
867 void DocumentCollector::closeTableRow()
869 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-row")));
870 if (mWriterDocumentState.mbHeaderRow)
872 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-header-rows")));
873 mWriterDocumentState.mbHeaderRow = false;
877 void DocumentCollector::openTableCell(const WPXPropertyList &propList)
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);
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));
895 mWriterDocumentState.mbTableCellOpened = true;
898 void DocumentCollector::closeTableCell()
900 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-cell")));
901 mWriterDocumentState.mbTableCellOpened = false;
904 void DocumentCollector::insertCoveredTableCell(const WPXPropertyList & /* propList */)
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")));
910 void DocumentCollector::closeTable()
912 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table")));
915 void DocumentCollector::insertTab()
917 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:tab-stop")));
918 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:tab-stop")));
921 void DocumentCollector::insertLineBreak()
923 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:line-break")));
924 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:line-break")));
927 void DocumentCollector::insertText(const WPXString &text)
929 DocumentElement *pText = new TextElement(text);
930 mpCurrentContentElements->push_back(pText);