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."
32 #pragma warning( push, 1 )
34 #include <libwpd/libwpd.h>
36 #pragma warning( pop )
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() :
53 mbInFakeSection(false),
54 mbListElementOpenedAtCurrentLevel(false),
55 mbTableCellOpened(false),
61 DocumentCollector::DocumentCollector(WPSInputStream
*pInput
, DocumentHandler
*pHandler
) :
65 mfSectionSpaceAfter(0.0f
),
67 mpCurrentContentElements(&mBodyElements
),
68 mpCurrentPageSpan(NULL
),
70 mpCurrentListStyle(NULL
),
71 miCurrentListLevel(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
94 // WLACH_REFACTORING: Remove these args..
95 if (!parseSourceDocument(*mpInput
))
97 if (!_writeTargetDocument(mpHandler
))
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
++) {
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
);
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
);
210 for (unsigned int i
=0; i
<mPageSpans
.size(); i
++)
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
);
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();
337 WPXString
propListToStyleKey(const WPXPropertyList
& xPropList
)
340 WPXPropertyList::Iter
i(xPropList
);
341 for (i
.rewind(); i
.next(); )
344 sProp
.sprintf("[%s:%s]", i
.key(), i()->getStr().cstr());
351 WPXString
getParagraphStyleKey(const WPXPropertyList
& xPropList
, const WPXPropertyListVector
& xTabStops
)
353 WPXString sKey
= propListToStyleKey(xPropList
);
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
);
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
);
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
);
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
));
443 mWriterDocumentState
.mbInFakeSection
= true;
446 void DocumentCollector::closeSection()
448 if (!mWriterDocumentState
.mbInFakeSection
)
449 mpCurrentContentElements
->push_back(static_cast<DocumentElement
*>(new TagCloseElement("text:section")));
451 mWriterDocumentState
.mbInFakeSection
= false;
453 // open as many paragraphs as needed to simulate section space after
454 // WLACH_REFACTORING: disable this for now..
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);
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
480 pPersistPropList
->insert("style:parent-style-name", "Standard");
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;
492 if (mWriterDocumentState
.mbTableCellOpened
)
494 if (mWriterDocumentState
.mbHeaderRow
)
495 pPersistPropList
->insert("style:parent-style-name", "Table Heading");
497 pPersistPropList
->insert("style:parent-style-name", "Table Contents");
500 pPersistPropList
->insert("style:parent-style-name", "Standard");
502 WPXString sKey
= getParagraphStyleKey(*pPersistPropList
, tabStops
);
504 if (mTextStyleHash
.find(sKey
) == mTextStyleHash
.end()) {
506 sName
.sprintf("S%i", mTextStyleHash
.size());
508 pStyle
= new ParagraphStyle(pPersistPropList
, tabStops
, sName
);
510 mTextStyleHash
[sKey
] = pStyle
;
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()));
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
;
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
)
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
));
582 sName
.sprintf("OL%i", 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;
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
)
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
));
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)
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())
717 sName
.sprintf("S%i", mTextStyleHash
.size());
719 pStyle
= new ParagraphStyle(pPersistPropList
, tabStops
, sName
);
721 mTextStyleHash
[sKey
] = pStyle
;
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
);