filters

WordPerfectCollector.cxx

00001 /* WordPerfectCollector: Collects sections and runs of text from a
00002  * wordperfect file (and styles to go along with them) and writes them
00003  * to a Writer target document
00004  *
00005  * Copyright (C) 2002-2004 William Lachance (william.lachance@sympatico.ca)
00006  * Copyright (C) 2003-2004 Net Integration Technologies (http://www.net-itech.com)
00007  * Copyright (C) 2004 Fridrich Strba (fridrich.strba@bluewin.ch)
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2 of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Library General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Library General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
00022  * Boston, MA 02110-1301, USA.
00023  *
00024  * For further information visit http://libwpd.sourceforge.net
00025  *
00026  */
00027 
00028 /* "This product is not manufactured, approved, or supported by
00029  * Corel Corporation or Corel Corporation Limited."
00030  */
00031 
00032 #include <libwpd/libwpd.h>
00033 #include <string.h> // for strcmp
00034 
00035 #include "WordPerfectCollector.hxx"
00036 #include "DocumentElement.hxx"
00037 #include "TextRunStyle.hxx"
00038 #include "FontStyle.hxx"
00039 #include "ListStyle.hxx"
00040 #include "PageSpan.hxx"
00041 #include "SectionStyle.hxx"
00042 #include "TableStyle.hxx"
00043 #include "FilterInternal.hxx"
00044 #include "WriterProperties.hxx"
00045 
00046 _WriterDocumentState::_WriterDocumentState() :
00047     mbFirstElement(true),
00048     mbInFakeSection(false),
00049     mbListElementOpenedAtCurrentLevel(false),
00050     mbTableCellOpened(false),
00051     mbHeaderRow(false),
00052     mbInNote(false)
00053 {
00054 }
00055 
00056 WordPerfectCollector::WordPerfectCollector(WPXInputStream *pInput, DocumentHandler *pHandler) :
00057         mpInput(pInput),
00058         mpHandler(pHandler),
00059     mbUsed(false),
00060     mfSectionSpaceAfter(0.0f),
00061     miNumListStyles(0),
00062     mpCurrentContentElements(&mBodyElements),
00063     mpCurrentPageSpan(NULL),
00064     miNumPageStyles(0),
00065     mpCurrentListStyle(NULL),
00066     miCurrentListLevel(0),
00067     miLastListLevel(0),
00068     miLastListNumber(0),
00069     mbListContinueNumbering(false),
00070     mbListElementParagraphOpened(false),
00071     mbListElementOpened(false)
00072 {
00073 }
00074 
00075 WordPerfectCollector::~WordPerfectCollector()
00076 {
00077 }
00078 
00079 bool WordPerfectCollector::filter()
00080 {
00081     // The contract for WordPerfectCollector is that it will only be used once after it is
00082     // instantiated
00083     if (mbUsed)
00084         return false;
00085 
00086     mbUsed = true;
00087 
00088     // parse & write
00089         // WLACH_REFACTORING: Remove these args..
00090     if (!_parseSourceDocument(*mpInput))
00091         return false;
00092     if (!_writeTargetDocument(*mpHandler))
00093         return false;
00094 
00095     // clean up the mess we made
00096     WRITER_DEBUG_MSG(("WriterWordPerfect: Cleaning up our mess..\n"));
00097 
00098     WRITER_DEBUG_MSG(("Destroying the body elements\n"));
00099     for (std::vector<DocumentElement *>::iterator iterBody = mBodyElements.begin(); iterBody != mBodyElements.end(); iterBody++) {
00100         delete((*iterBody));
00101         (*iterBody) = NULL;
00102     }
00103 
00104     WRITER_DEBUG_MSG(("Destroying the styles elements\n"));
00105     for (std::vector<DocumentElement *>::iterator iterStyles = mStylesElements.begin(); iterStyles != mStylesElements.end(); iterStyles++) {
00106         delete (*iterStyles);
00107         (*iterStyles) = NULL; // we may pass over the same element again (in the case of headers/footers spanning multiple pages)
00108                       // so make sure we don't do a double del
00109     }
00110 
00111     WRITER_DEBUG_MSG(("Destroying the rest of the styles elements\n"));
00112     for (std::map<WPXString, ParagraphStyle *, ltstr>::iterator iterTextStyle = mTextStyleHash.begin(); iterTextStyle != mTextStyleHash.end(); iterTextStyle++) {
00113         delete(iterTextStyle->second);
00114     }
00115     for (std::map<WPXString, FontStyle *, ltstr>::iterator iterFont = mFontHash.begin(); iterFont != mFontHash.end(); iterFont++) {
00116         delete(iterFont->second);
00117     }
00118 
00119     for (std::vector<ListStyle *>::iterator iterListStyles = mListStyles.begin(); iterListStyles != mListStyles.end(); iterListStyles++) {
00120         delete((*iterListStyles));
00121     }
00122     for (std::vector<SectionStyle *>::iterator iterSectionStyles = mSectionStyles.begin(); iterSectionStyles != mSectionStyles.end(); iterSectionStyles++) {
00123         delete((*iterSectionStyles));
00124     }
00125     for (std::vector<TableStyle *>::iterator iterTableStyles = mTableStyles.begin(); iterTableStyles != mTableStyles.end(); iterTableStyles++) {
00126         delete((*iterTableStyles));
00127     }
00128 
00129     for (std::vector<PageSpan *>::iterator iterPageSpans = mPageSpans.begin(); iterPageSpans != mPageSpans.end(); iterPageSpans++) {
00130         delete((*iterPageSpans));
00131     }
00132 
00133     return true;
00134 }
00135 
00136 bool WordPerfectCollector::_parseSourceDocument(WPXInputStream &input)
00137 {
00138         WPDResult result = WPDocument::parse(&input, static_cast<WPXHLListenerImpl *>(this));
00139         if (result != WPD_OK)
00140                 return false;
00141 
00142     return true;
00143 }
00144 
00145 void WordPerfectCollector::_writeDefaultStyles(DocumentHandler &xHandler)
00146 {
00147     TagOpenElement stylesOpenElement("office:styles");
00148     stylesOpenElement.write(xHandler);
00149 
00150     TagOpenElement defaultParagraphStyleOpenElement("style:default-style");
00151     defaultParagraphStyleOpenElement.addAttribute("style:family", "paragraph");
00152     defaultParagraphStyleOpenElement.write(xHandler);
00153 
00154     TagOpenElement defaultParagraphStylePropertiesOpenElement("style:properties");
00155     defaultParagraphStylePropertiesOpenElement.addAttribute("style:family", "paragraph");
00156     defaultParagraphStylePropertiesOpenElement.addAttribute("style:tab-stop-distance", "0.5inch");
00157     defaultParagraphStylePropertiesOpenElement.write(xHandler);
00158     TagCloseElement defaultParagraphStylePropertiesCloseElement("style:properties");
00159     defaultParagraphStylePropertiesCloseElement.write(xHandler);
00160 
00161     TagCloseElement defaultParagraphStyleCloseElement("style:default-style");
00162     defaultParagraphStyleCloseElement.write(xHandler);
00163     
00164     TagOpenElement standardStyleOpenElement("style:style");
00165         standardStyleOpenElement.addAttribute("style:name", "Standard");
00166         standardStyleOpenElement.addAttribute("style:family", "paragraph");
00167         standardStyleOpenElement.addAttribute("style:class", "text");
00168         standardStyleOpenElement.write(xHandler);
00169         TagCloseElement standardStyleCloseElement("style:style");
00170         standardStyleCloseElement.write(xHandler);
00171 
00172         TagOpenElement textBodyStyleOpenElement("style:style");
00173         textBodyStyleOpenElement.addAttribute("style:name", "Text Body");
00174         textBodyStyleOpenElement.addAttribute("style:family", "paragraph");
00175         textBodyStyleOpenElement.addAttribute("style:parent-style-name", "Standard");
00176         textBodyStyleOpenElement.addAttribute("style:class", "text");
00177         textBodyStyleOpenElement.write(xHandler);
00178         TagCloseElement textBodyStyleCloseElement("style:style");
00179         textBodyStyleCloseElement.write(xHandler);
00180 
00181         TagOpenElement tableContentsStyleOpenElement("style:style");
00182         tableContentsStyleOpenElement.addAttribute("style:name", "Table Contents");
00183         tableContentsStyleOpenElement.addAttribute("style:family", "paragraph");
00184         tableContentsStyleOpenElement.addAttribute("style:parent-style-name", "Text Body");
00185         tableContentsStyleOpenElement.addAttribute("style:class", "extra");
00186         tableContentsStyleOpenElement.write(xHandler);
00187         TagCloseElement tableContentsStyleCloseElement("style:style");
00188         tableContentsStyleCloseElement.write(xHandler);
00189 
00190         TagOpenElement tableHeadingStyleOpenElement("style:style");
00191         tableHeadingStyleOpenElement.addAttribute("style:name", "Table Heading");
00192         tableHeadingStyleOpenElement.addAttribute("style:family", "paragraph");
00193         tableHeadingStyleOpenElement.addAttribute("style:parent-style-name", "Table Contents");
00194         tableHeadingStyleOpenElement.addAttribute("style:class", "extra");
00195         tableHeadingStyleOpenElement.write(xHandler);
00196         TagCloseElement tableHeadingStyleCloseElement("style:style");
00197         tableHeadingStyleCloseElement.write(xHandler);
00198 
00199     TagCloseElement stylesCloseElement("office:styles");
00200     stylesCloseElement.write(xHandler);
00201 
00202 }
00203 
00204 // writes everything up to the automatic styles declarations..
00205 void WordPerfectCollector::_writeBegin()
00206 {
00207 }
00208 
00209 void WordPerfectCollector::_writeMasterPages(DocumentHandler &xHandler)
00210 {
00211         WPXPropertyList xBlankAttrList;
00212 
00213     xHandler.startElement("office:master-styles", xBlankAttrList);
00214     int pageNumber = 1;
00215     for (int i=0; i<mPageSpans.size(); i++)
00216     {
00217         bool bLastPage;
00218         (i == (mPageSpans.size() - 1)) ? bLastPage = true : bLastPage = false;
00219         mPageSpans[i]->writeMasterPages(pageNumber, i, bLastPage, xHandler);
00220         pageNumber += mPageSpans[i]->getSpan();
00221     }
00222     xHandler.endElement("office:master-styles");
00223 }
00224 
00225 void WordPerfectCollector::_writePageMasters(DocumentHandler &xHandler)
00226 {
00227     int pageNumber = 1;
00228     for (int i=0; i<mPageSpans.size(); i++)
00229     {
00230         mPageSpans[i]->writePageMaster(i, xHandler);
00231     }
00232 }
00233 
00234 bool WordPerfectCollector::_writeTargetDocument(DocumentHandler &xHandler)
00235 {        
00236     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Printing out the header stuff..\n"));
00237     WPXPropertyList xBlankAttrList;
00238 
00239     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Start Document\n"));
00240     mpHandler->startDocument();
00241 
00242     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: preamble\n"));
00243         WPXPropertyList docContentPropList;
00244     docContentPropList.insert("xmlns:office", "http://openoffice.org/2000/office");
00245     docContentPropList.insert("xmlns:style", "http://openoffice.org/2000/style");
00246     docContentPropList.insert("xmlns:text", "http://openoffice.org/2000/text");
00247     docContentPropList.insert("xmlns:table", "http://openoffice.org/2000/table");
00248     docContentPropList.insert("xmlns:draw", "http://openoffice.org/2000/draw");
00249     docContentPropList.insert("xmlns:fo", "http://www.w3.org/1999/XSL/Format");
00250     docContentPropList.insert("xmlns:xlink", "http://www.w3.org/1999/xlink");
00251     docContentPropList.insert("xmlns:number", "http://openoffice.org/2000/datastyle");
00252     docContentPropList.insert("xmlns:svg", "http://www.w3.org/2000/svg");
00253     docContentPropList.insert("xmlns:chart", "http://openoffice.org/2000/chart");
00254     docContentPropList.insert("xmlns:dr3d", "http://openoffice.org/2000/dr3d");
00255     docContentPropList.insert("xmlns:math", "http://www.w3.org/1998/Math/MathML");
00256     docContentPropList.insert("xmlns:form", "http://openoffice.org/2000/form");
00257     docContentPropList.insert("xmlns:script", "http://openoffice.org/2000/script");
00258     docContentPropList.insert("office:class", "text");
00259     docContentPropList.insert("office:version", "1.0");
00260         mpHandler->startElement("office:document-content", docContentPropList);
00261 
00262     // write out the font styles
00263     mpHandler->startElement("office:font-decls", xBlankAttrList);
00264     for (std::map<WPXString, FontStyle *, ltstr>::iterator iterFont = mFontHash.begin(); iterFont != mFontHash.end(); iterFont++) {
00265         iterFont->second->write(*mpHandler);
00266     }
00267     TagOpenElement symbolFontOpen("style:font-decl");
00268     symbolFontOpen.addAttribute("style:name", "StarSymbol");
00269     symbolFontOpen.addAttribute("fo:font-family", "StarSymbol");
00270     symbolFontOpen.addAttribute("style:font-charset", "x-symbol");
00271     symbolFontOpen.write(*mpHandler);
00272         mpHandler->endElement("style:font-decl");
00273 
00274     mpHandler->endElement("office:font-decls");
00275 
00276 
00277     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Writing out the styles..\n"));
00278 
00279     // write default styles
00280     _writeDefaultStyles(*mpHandler);
00281 
00282     mpHandler->startElement("office:automatic-styles", xBlankAttrList);
00283 
00284     for (std::map<WPXString, ParagraphStyle *, ltstr>::iterator iterTextStyle = mTextStyleHash.begin(); 
00285              iterTextStyle != mTextStyleHash.end(); iterTextStyle++) 
00286         {
00287         // writing out the paragraph styles
00288         if (strcmp((iterTextStyle->second)->getName().cstr(), "Standard")) 
00289                 {
00290             // don't write standard paragraph "no styles" style
00291             (iterTextStyle->second)->write(xHandler);
00292         }
00293     }
00294 
00295         // span styles..
00296     for (std::map<WPXString, SpanStyle *, ltstr>::iterator iterSpanStyle = mSpanStyleHash.begin(); 
00297              iterSpanStyle != mSpanStyleHash.end(); iterSpanStyle++) 
00298         {
00299                 (iterSpanStyle->second)->write(xHandler);
00300     }
00301 
00302     // writing out the sections styles
00303     for (std::vector<SectionStyle *>::iterator iterSectionStyles = mSectionStyles.begin(); iterSectionStyles != mSectionStyles.end(); iterSectionStyles++) {
00304         (*iterSectionStyles)->write(xHandler);
00305     }
00306 
00307     // writing out the lists styles
00308     for (std::vector<ListStyle *>::iterator iterListStyles = mListStyles.begin(); iterListStyles != mListStyles.end(); iterListStyles++) {
00309         (*iterListStyles)->write(xHandler);
00310     }
00311 
00312     // writing out the table styles
00313     for (std::vector<TableStyle *>::iterator iterTableStyles = mTableStyles.begin(); iterTableStyles != mTableStyles.end(); iterTableStyles++) {
00314         (*iterTableStyles)->write(xHandler);
00315     }
00316 
00317     // writing out the page masters
00318     _writePageMasters(xHandler);
00319 
00320 
00321     xHandler.endElement("office:automatic-styles");
00322 
00323     _writeMasterPages(xHandler);
00324 
00325     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Writing out the document..\n"));
00326     // writing out the document
00327     xHandler.startElement("office:body", xBlankAttrList);
00328 
00329     for (std::vector<DocumentElement *>::iterator iterBodyElements = mBodyElements.begin(); iterBodyElements != mBodyElements.end(); iterBodyElements++) {
00330         (*iterBodyElements)->write(xHandler);
00331     }
00332     WRITER_DEBUG_MSG(("WriterWordPerfect: Document Body: Finished writing all doc els..\n"));
00333 
00334     xHandler.endElement("office:body");
00335     xHandler.endElement("office:document-content");
00336 
00337     xHandler.endDocument();
00338 
00339     return true;
00340 }
00341 
00342 
00343 WPXString propListToStyleKey(const WPXPropertyList & xPropList)
00344 {
00345         WPXString sKey;
00346         WPXPropertyList::Iter i(xPropList);
00347         for (i.rewind(); i.next(); )
00348         {
00349                 WPXString sProp;
00350                 sProp.sprintf("[%s:%s]", i.key(), i()->getStr().cstr());
00351                 sKey.append(sProp);
00352         }
00353 
00354         return sKey;
00355 }
00356 
00357 WPXString getParagraphStyleKey(const WPXPropertyList & xPropList, const WPXPropertyListVector & xTabStops)
00358 {
00359         WPXString sKey = propListToStyleKey(xPropList);
00360         
00361         WPXString sTabStops;
00362         sTabStops.sprintf("[num-tab-stops:%i]", xTabStops.count());
00363         WPXPropertyListVector::Iter i(xTabStops);
00364         for (i.rewind(); i.next();)
00365         {
00366                 sTabStops.append(propListToStyleKey(i()));
00367         }
00368         sKey.append(sTabStops);
00369 
00370         return sKey;
00371 }
00372 
00373 // _allocateFontName: add a (potentially mapped) font style to the hash if it's not already there, do nothing otherwise
00374 void WordPerfectCollector::_allocateFontName(const WPXString & sFontName)
00375 {
00376     if (mFontHash.find(sFontName) == mFontHash.end())
00377     {
00378         FontStyle *pFontStyle = new FontStyle(sFontName.cstr(), sFontName.cstr());
00379         mFontHash[sFontName] = pFontStyle;
00380     }
00381 }
00382 
00383 void WordPerfectCollector::openPageSpan(const WPXPropertyList &propList)
00384 {
00385     PageSpan *pPageSpan = new PageSpan(propList);
00386     mPageSpans.push_back(pPageSpan);
00387     mpCurrentPageSpan = pPageSpan;
00388 }
00389 
00390 void WordPerfectCollector::openHeader(const WPXPropertyList &propList)
00391 {
00392     std::vector<DocumentElement *> * pHeaderFooterContentElements = new std::vector<DocumentElement *>;
00393 
00394     if (propList["libwpd:occurence"]->getStr() == "even")
00395                 mpCurrentPageSpan->setHeaderLeftContent(pHeaderFooterContentElements);
00396         else
00397                 mpCurrentPageSpan->setHeaderContent(pHeaderFooterContentElements);
00398 
00399     mpCurrentContentElements = pHeaderFooterContentElements;
00400 }
00401 
00402 void WordPerfectCollector::closeHeader()
00403 {
00404     mpCurrentContentElements = &mBodyElements;
00405 }
00406 
00407 void WordPerfectCollector::openFooter(const WPXPropertyList &propList)
00408 {
00409     std::vector<DocumentElement *> * pHeaderFooterContentElements = new std::vector<DocumentElement *>;
00410 
00411     if (propList["libwpd:occurence"]->getStr() == "even")
00412                 mpCurrentPageSpan->setFooterLeftContent(pHeaderFooterContentElements);
00413         else
00414                 mpCurrentPageSpan->setFooterContent(pHeaderFooterContentElements);
00415 
00416     mpCurrentContentElements = pHeaderFooterContentElements;
00417 }
00418 
00419 void WordPerfectCollector::closeFooter()
00420 {
00421     mpCurrentContentElements = &mBodyElements;
00422 }
00423 
00424 void WordPerfectCollector::openSection(const WPXPropertyList &propList, const WPXPropertyListVector &columns)
00425 {
00426         int iNumColumns = columns.count();
00427 
00428     if (iNumColumns > 1)
00429     {
00430         mfSectionSpaceAfter = propList["fo:margin-bottom"]->getFloat();
00431         WPXString sSectionName;
00432         sSectionName.sprintf("Section%i", mSectionStyles.size());
00433         
00434         SectionStyle *pSectionStyle = new SectionStyle(propList, columns, sSectionName.cstr());
00435         mSectionStyles.push_back(pSectionStyle);
00436         
00437         TagOpenElement *pSectionOpenElement = new TagOpenElement("text:section");
00438         pSectionOpenElement->addAttribute("text:style-name", pSectionStyle->getName());
00439         pSectionOpenElement->addAttribute("text:name", pSectionStyle->getName());
00440         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pSectionOpenElement));
00441     }
00442     else
00443         mWriterDocumentState.mbInFakeSection = true;
00444 }
00445 
00446 void WordPerfectCollector::closeSection()
00447 {
00448     if (!mWriterDocumentState.mbInFakeSection)
00449         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:section")));
00450     else
00451         mWriterDocumentState.mbInFakeSection = false;
00452 
00453     // open as many paragraphs as needed to simulate section space after
00454     // WLACH_REFACTORING: disable this for now..
00455     #if 0
00456     for (float f=0.0f; f<mfSectionSpaceAfter; f+=1.0f) {
00457         vector<WPXTabStop> dummyTabStops;
00458         openParagraph(WPX_PARAGRAPH_JUSTIFICATION_LEFT, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, dummyTabStops, false, false);
00459         closeParagraph();
00460     }
00461     #endif
00462     mfSectionSpaceAfter = 0.0f;
00463 }
00464 
00465 void WordPerfectCollector::openParagraph(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops)
00466 {
00467     // FIXMENOW: What happens if we open a footnote inside a table? do we then inherit the footnote's style
00468     // from "Table Contents"
00469     
00470     WPXPropertyList *pPersistPropList = new WPXPropertyList(propList);
00471     ParagraphStyle *pStyle = NULL;
00472 
00473     if (mWriterDocumentState.mbFirstElement && mpCurrentContentElements == &mBodyElements)
00474     {
00475         // we don't have to go through the fuss of determining if the paragraph style is 
00476         // unique in this case, because if we are the first document element, then we
00477         // are singular. Neither do we have to determine what our parent style is-- we can't
00478         // be inside a table in this case (the table would be the first document element 
00479         //in that case)
00480         pPersistPropList->insert("style:parent-style-name", "Standard");
00481         WPXString sName;
00482         sName.sprintf("FS");
00483 
00484         WPXString sParagraphHashKey("P|FS");
00485         pPersistPropList->insert("style:master-page-name", "Page Style 1");
00486                 pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
00487         mTextStyleHash[sParagraphHashKey] = pStyle;
00488         mWriterDocumentState.mbFirstElement = false;
00489     }
00490     else
00491     {
00492         if (mWriterDocumentState.mbTableCellOpened)
00493         {
00494             if (mWriterDocumentState.mbHeaderRow)
00495                 pPersistPropList->insert("style:parent-style-name", "Table Heading");
00496             else
00497                 pPersistPropList->insert("style:parent-style-name", "Table Contents");
00498         }
00499         else
00500             pPersistPropList->insert("style:parent-style-name", "Standard");
00501 
00502                 WPXString sKey = getParagraphStyleKey(*pPersistPropList, tabStops);
00503 
00504         if (mTextStyleHash.find(sKey) == mTextStyleHash.end()) {
00505             WPXString sName;
00506             sName.sprintf("S%i", mTextStyleHash.size()); 
00507             
00508             pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
00509     
00510             mTextStyleHash[sKey] = pStyle;
00511         }
00512         else
00513         {
00514             pStyle = mTextStyleHash[sKey];
00515             delete pPersistPropList;
00516         }
00517     }
00518     // create a document element corresponding to the paragraph, and append it to our list of document elements
00519     TagOpenElement *pParagraphOpenElement = new TagOpenElement("text:p");
00520     pParagraphOpenElement->addAttribute("text:style-name", pStyle->getName());
00521     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pParagraphOpenElement));
00522 }
00523 
00524 void WordPerfectCollector::closeParagraph()
00525 {
00526     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
00527 }
00528 
00529 void WordPerfectCollector::openSpan(const WPXPropertyList &propList)
00530 {
00531         if (propList["style:font-name"])
00532                 _allocateFontName(propList["style:font-name"]->getStr());
00533     WPXString sSpanHashKey = propListToStyleKey(propList);
00534     WRITER_DEBUG_MSG(("WriterWordPerfect: Span Hash Key: %s\n", sSpanHashKey.cstr()));
00535 
00536     // Get the style
00537         WPXString sName;
00538     if (mSpanStyleHash.find(sSpanHashKey) == mSpanStyleHash.end())
00539         {
00540         // allocate a new paragraph style
00541         sName.sprintf("Span%i", mSpanStyleHash.size());
00542         SpanStyle *pStyle = new SpanStyle(sName.cstr(), propList);                
00543 
00544         mSpanStyleHash[sSpanHashKey] = pStyle;
00545     }
00546     else 
00547         {
00548         sName.sprintf("%s", mSpanStyleHash.find(sSpanHashKey)->second->getName().cstr());
00549     }
00550 
00551     // create a document element corresponding to the paragraph, and append it to our list of document elements
00552     TagOpenElement *pSpanOpenElement = new TagOpenElement("text:span");
00553     pSpanOpenElement->addAttribute("text:style-name", sName.cstr());
00554     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pSpanOpenElement));
00555 }
00556 
00557 void WordPerfectCollector::closeSpan()
00558 {
00559     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:span")));
00560 }
00561 
00562 void WordPerfectCollector::defineOrderedListLevel(const WPXPropertyList &propList)
00563 {
00564         int id = 0;
00565         if (propList["libwpd:id"])
00566                 id = propList["libwpd:id"]->getInt();
00567 
00568     OrderedListStyle *pOrderedListStyle = NULL;
00569     if (mpCurrentListStyle && mpCurrentListStyle->getListID() == id)
00570         pOrderedListStyle = static_cast<OrderedListStyle *>(mpCurrentListStyle); // FIXME: using a dynamic cast here causes oo to crash?!
00571 
00572     // this rather appalling conditional makes sure we only start a new list (rather than continue an old
00573     // one) if: (1) we have no prior list OR (2) the prior list is actually definitively different
00574     // from the list that is just being defined (listIDs differ) OR (3) we can tell that the user actually
00575     // is starting a new list at level 1 (and only level 1)
00576     if (pOrderedListStyle == NULL || pOrderedListStyle->getListID() != id  ||
00577         (propList["libwpd:level"] && propList["libwpd:level"]->getInt()==1 && 
00578              (propList["text:start-value"] && propList["text:start-value"]->getInt() != (miLastListNumber+1))))
00579     {
00580         WRITER_DEBUG_MSG(("Attempting to create a new ordered list style (listid: %i)\n", id));
00581         WPXString sName;
00582         sName.sprintf("OL%i", miNumListStyles);
00583         miNumListStyles++;
00584         pOrderedListStyle = new OrderedListStyle(sName.cstr(), propList["libwpd:id"]->getInt());
00585         mListStyles.push_back(static_cast<ListStyle *>(pOrderedListStyle));
00586         mpCurrentListStyle = static_cast<ListStyle *>(pOrderedListStyle);
00587         mbListContinueNumbering = false;
00588         miLastListNumber = 0;
00589     }
00590     else
00591         mbListContinueNumbering = true;
00592 
00593     // Iterate through ALL list styles with the same WordPerfect list id and define a level if it is not already defined
00594     // This solves certain problems with lists that start and finish without reaching certain levels and then begin again
00595     // and reach those levels. See gradguide0405_PC.wpd in the regression suite
00596     for (std::vector<ListStyle *>::iterator iterOrderedListStyles = mListStyles.begin(); iterOrderedListStyles != mListStyles.end(); iterOrderedListStyles++)
00597     {
00598         if ((* iterOrderedListStyles)->getListID() == propList["libwpd:id"]->getInt())
00599             (* iterOrderedListStyles)->updateListLevel((propList["libwpd:level"]->getInt() - 1), propList);
00600     }
00601 }
00602 
00603 void WordPerfectCollector::defineUnorderedListLevel(const WPXPropertyList &propList)
00604 {
00605         int id = 0;
00606         if (propList["libwpd:id"])
00607                 id = propList["libwpd:id"]->getInt();
00608 
00609     UnorderedListStyle *pUnorderedListStyle = NULL;
00610     if (mpCurrentListStyle && mpCurrentListStyle->getListID() == id)
00611         pUnorderedListStyle = static_cast<UnorderedListStyle *>(mpCurrentListStyle); // FIXME: using a dynamic cast here causes oo to crash?!
00612 
00613     if (pUnorderedListStyle == NULL) {
00614         WRITER_DEBUG_MSG(("Attempting to create a new unordered list style (listid: %i)\n", id));
00615         WPXString sName;
00616         sName.sprintf("UL%i", miNumListStyles);
00617         pUnorderedListStyle = new UnorderedListStyle(sName.cstr(), id);
00618         mListStyles.push_back(static_cast<ListStyle *>(pUnorderedListStyle));
00619         mpCurrentListStyle = static_cast<ListStyle *>(pUnorderedListStyle);
00620     }
00621 
00622     // See comment in WordPerfectCollector::defineOrderedListLevel
00623     for (std::vector<ListStyle *>::iterator iterUnorderedListStyles = mListStyles.begin(); iterUnorderedListStyles != mListStyles.end(); iterUnorderedListStyles++)
00624     {
00625         if ((* iterUnorderedListStyles)->getListID() == propList["libwpd:id"]->getInt())
00626             (* iterUnorderedListStyles)->updateListLevel((propList["libwpd:level"]->getInt() - 1), propList);
00627     }
00628 }
00629 
00630 void WordPerfectCollector::openOrderedListLevel(const WPXPropertyList &propList)
00631 {
00632     miCurrentListLevel++;
00633     TagOpenElement *pListLevelOpenElement = new TagOpenElement("text:ordered-list");
00634     _openListLevel(pListLevelOpenElement);
00635 
00636     if (mbListContinueNumbering) {
00637         pListLevelOpenElement->addAttribute("text:continue-numbering", "true");
00638     }
00639 
00640     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pListLevelOpenElement));
00641 }
00642 
00643 void WordPerfectCollector::openUnorderedListLevel(const WPXPropertyList &propList)
00644 {
00645     miCurrentListLevel++;
00646     TagOpenElement *pListLevelOpenElement = new TagOpenElement("text:unordered-list");
00647     _openListLevel(pListLevelOpenElement);
00648 
00649     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pListLevelOpenElement));
00650 }
00651 
00652 void WordPerfectCollector::_openListLevel(TagOpenElement *pListLevelOpenElement)
00653 {
00654     if (!mbListElementOpened && miCurrentListLevel > 1)
00655     {
00656         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:list-item")));
00657     }
00658     else if (mbListElementParagraphOpened)
00659     {
00660         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
00661         mbListElementParagraphOpened = false;
00662     }
00663 
00664     if (miCurrentListLevel==1) {
00665         pListLevelOpenElement->addAttribute("text:style-name", mpCurrentListStyle->getName());
00666     }
00667 
00668     mbListElementOpened = false;
00669 }
00670 
00671 void WordPerfectCollector::closeOrderedListLevel()
00672 {
00673     _closeListLevel("ordered-list");
00674 }
00675 
00676 void WordPerfectCollector::closeUnorderedListLevel()
00677 {
00678     _closeListLevel("unordered-list");
00679 }
00680 
00681 void WordPerfectCollector::_closeListLevel(const char *szListType)
00682 {
00683     if (mbListElementOpened)
00684         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
00685 
00686     miCurrentListLevel--;
00687 
00688     WPXString sCloseElement;
00689     sCloseElement.sprintf("text:%s", szListType);
00690     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement(sCloseElement.cstr())));
00691 
00692     if (miCurrentListLevel > 0)
00693         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
00694     mbListElementOpened = false;
00695 }
00696 
00697 void WordPerfectCollector::openListElement(const WPXPropertyList &propList, const WPXPropertyListVector &tabStops)
00698 {
00699     miLastListLevel = miCurrentListLevel;
00700     if (miCurrentListLevel == 1)
00701         miLastListNumber++;
00702 
00703     if (mbListElementOpened)
00704         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:list-item")));
00705 
00706     ParagraphStyle *pStyle = NULL;
00707 
00708     WPXPropertyList *pPersistPropList = new WPXPropertyList(propList);
00709     pPersistPropList->insert("style:list-style-name", mpCurrentListStyle->getName());
00710     pPersistPropList->insert("style:parent-style-name", "Standard");
00711 
00712         WPXString sKey = getParagraphStyleKey(*pPersistPropList, tabStops);
00713 
00714         if (mTextStyleHash.find(sKey) == mTextStyleHash.end()) 
00715         {
00716                 WPXString sName;
00717                 sName.sprintf("S%i", mTextStyleHash.size()); 
00718         
00719                 pStyle = new ParagraphStyle(pPersistPropList, tabStops, sName);
00720                 
00721                 mTextStyleHash[sKey] = pStyle;
00722         }
00723         else
00724         {
00725                 pStyle = mTextStyleHash[sKey];
00726                 delete pPersistPropList;
00727         }
00728 
00729     TagOpenElement *pOpenListElement = new TagOpenElement("text:list-item");
00730     TagOpenElement *pOpenListElementParagraph = new TagOpenElement("text:p");
00731 
00732     pOpenListElementParagraph->addAttribute("text:style-name", pStyle->getName());
00733 
00734     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenListElement));
00735     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenListElementParagraph));
00736         
00737     mbListElementOpened = true;
00738     mbListElementParagraphOpened = true;
00739     mbListContinueNumbering = false;
00740 }
00741 
00742 void WordPerfectCollector::closeListElement()
00743 {
00744     // this code is kind of tricky, because we don't actually close the list element (because this list element
00745     // could contain another list level in OOo's implementation of lists). that is done in the closeListLevel
00746     // code (or when we open another list element)
00747 
00748     if (mbListElementParagraphOpened)
00749     {
00750         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:p")));
00751         mbListElementParagraphOpened = false;
00752     }
00753 }
00754 
00755 void WordPerfectCollector::openFootnote(const WPXPropertyList &propList)
00756 {
00757     TagOpenElement *pOpenFootNote = new TagOpenElement("text:footnote");
00758     if (propList["libwpd:number"])
00759     {
00760         WPXString tmpString("ftn");
00761         tmpString.append(propList["libwpd:number"]->getStr());
00762         pOpenFootNote->addAttribute("text:id", tmpString);
00763     }
00764     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenFootNote));
00765 
00766     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:footnote-citation")));
00767         if (propList["libwpd:number"])
00768                 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new CharDataElement(propList["libwpd:number"]->getStr().cstr())));
00769     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote-citation")));
00770 
00771     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:footnote-body")));
00772     
00773     mWriterDocumentState.mbInNote = true;
00774 }
00775 
00776 void WordPerfectCollector::closeFootnote()
00777 {
00778     mWriterDocumentState.mbInNote = false;
00779 
00780     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote-body")));
00781     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:footnote")));
00782 }
00783 
00784 void WordPerfectCollector::openEndnote(const WPXPropertyList &propList)
00785 {
00786     TagOpenElement *pOpenEndNote = new TagOpenElement("text:endnote");
00787     if (propList["libwpd:number"])
00788     {
00789         WPXString tmpString("edn");
00790         tmpString.append(propList["libwpd:number"]->getStr());
00791         pOpenEndNote->addAttribute("text:id", tmpString);
00792     }
00793     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pOpenEndNote));
00794 
00795     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:endnote-citation")));
00796         if (propList["libwpd:number"])
00797                 mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new CharDataElement(propList["libwpd:number"]->getStr().cstr())));
00798     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote-citation")));
00799 
00800     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:endnote-body")));
00801     
00802     mWriterDocumentState.mbInNote = true;
00803 }
00804 
00805 void WordPerfectCollector::closeEndnote()
00806 {
00807     mWriterDocumentState.mbInNote = false;
00808 
00809     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote-body")));
00810     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:endnote")));
00811 }
00812 
00813 void WordPerfectCollector::openTable(const WPXPropertyList &propList, const WPXPropertyListVector &columns)
00814 {
00815     if (!mWriterDocumentState.mbInNote)
00816     {
00817         WPXString sTableName;
00818         sTableName.sprintf("Table%i", mTableStyles.size());
00819 
00820         // FIXME: we base the table style off of the page's margin left, ignoring (potential) wordperfect margin
00821         // state which is transmitted inside the page. could this lead to unacceptable behaviour?
00822             // WLACH_REFACTORING: characterize this behaviour, probably should nip it at the bud within libwpd
00823         TableStyle *pTableStyle = new TableStyle(propList, columns, sTableName.cstr());
00824 
00825         if (mWriterDocumentState.mbFirstElement && mpCurrentContentElements == &mBodyElements)
00826         {
00827             WPXString sMasterPageName("Page Style 1");
00828             pTableStyle->setMasterPageName(sMasterPageName);
00829             mWriterDocumentState.mbFirstElement = false;
00830         }
00831 
00832         mTableStyles.push_back(pTableStyle);
00833 
00834         mpCurrentTableStyle = pTableStyle;
00835 
00836         TagOpenElement *pTableOpenElement = new TagOpenElement("table:table");
00837 
00838         pTableOpenElement->addAttribute("table:name", sTableName.cstr());
00839         pTableOpenElement->addAttribute("table:style-name", sTableName.cstr());
00840         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableOpenElement));
00841 
00842         for (int i=0; i<pTableStyle->getNumColumns(); i++) 
00843             {
00844             TagOpenElement *pTableColumnOpenElement = new TagOpenElement("table:table-column");
00845             WPXString sColumnStyleName;
00846             sColumnStyleName.sprintf("%s.Column%i", sTableName.cstr(), (i+1));
00847             pTableColumnOpenElement->addAttribute("table:style-name", sColumnStyleName.cstr());
00848             mpCurrentContentElements->push_back(pTableColumnOpenElement);
00849 
00850             TagCloseElement *pTableColumnCloseElement = new TagCloseElement("table:table-column");
00851             mpCurrentContentElements->push_back(pTableColumnCloseElement);
00852         }
00853     }
00854 }
00855 
00856 void WordPerfectCollector::openTableRow(const WPXPropertyList &propList)
00857 {
00858     if (!mWriterDocumentState.mbInNote)
00859     {
00860         if (propList["libwpd:is-header-row"] && (propList["libwpd:is-header-row"]->getInt()))
00861         {
00862             mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("table:table-header-rows")));
00863             mWriterDocumentState.mbHeaderRow = true;
00864         }
00865 
00866         WPXString sTableRowStyleName;
00867         sTableRowStyleName.sprintf("%s.Row%i", mpCurrentTableStyle->getName().cstr(), mpCurrentTableStyle->getNumTableRowStyles());
00868         TableRowStyle *pTableRowStyle = new TableRowStyle(propList, sTableRowStyleName.cstr());
00869         mpCurrentTableStyle->addTableRowStyle(pTableRowStyle);
00870 
00871         TagOpenElement *pTableRowOpenElement = new TagOpenElement("table:table-row");
00872         pTableRowOpenElement->addAttribute("table:style-name", sTableRowStyleName);
00873         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableRowOpenElement));
00874     }
00875 }
00876 
00877 void WordPerfectCollector::closeTableRow()
00878 {
00879     if (!mWriterDocumentState.mbInNote)
00880     {
00881         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-row")));
00882         if (mWriterDocumentState.mbHeaderRow)
00883         {
00884             mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-header-rows")));
00885             mWriterDocumentState.mbHeaderRow = false;
00886         }
00887     }
00888 }
00889 
00890 void WordPerfectCollector::openTableCell(const WPXPropertyList &propList)
00891 {
00892     if (!mWriterDocumentState.mbInNote)
00893     {
00894         WPXString sTableCellStyleName;
00895         sTableCellStyleName.sprintf( "%s.Cell%i", mpCurrentTableStyle->getName().cstr(), mpCurrentTableStyle->getNumTableCellStyles());
00896         TableCellStyle *pTableCellStyle = new TableCellStyle(propList, sTableCellStyleName.cstr());
00897         mpCurrentTableStyle->addTableCellStyle(pTableCellStyle);
00898 
00899         TagOpenElement *pTableCellOpenElement = new TagOpenElement("table:table-cell");
00900         pTableCellOpenElement->addAttribute("table:style-name", sTableCellStyleName);
00901         if (propList["table:number-columns-spanned"])
00902                     pTableCellOpenElement->addAttribute("table:number-columns-spanned", 
00903                                                         propList["table:number-columns-spanned"]->getStr().cstr());
00904             if (propList["table:number-rows-spanned"])
00905                     pTableCellOpenElement->addAttribute("table:number-rows-spanned",
00906                                                         propList["table:number-rows-spanned"]->getStr().cstr());
00907         pTableCellOpenElement->addAttribute("table:value-type", "string");
00908         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(pTableCellOpenElement));
00909 
00910         mWriterDocumentState.mbTableCellOpened = true;
00911     }
00912 }
00913 
00914 void WordPerfectCollector::closeTableCell()
00915 {
00916     if (!mWriterDocumentState.mbInNote)
00917     {
00918         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table-cell")));
00919         mWriterDocumentState.mbTableCellOpened = false;
00920     }
00921 }
00922 
00923 void WordPerfectCollector::insertCoveredTableCell(const WPXPropertyList &propList)
00924 {
00925     if (!mWriterDocumentState.mbInNote)
00926     {
00927         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("table:covered-table-cell")));
00928         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:covered-table-cell")));
00929     }
00930 }
00931 
00932 void WordPerfectCollector::closeTable()
00933 {
00934     if (!mWriterDocumentState.mbInNote)
00935     {
00936         mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("table:table")));
00937     }
00938 }
00939 
00940 
00941 void WordPerfectCollector::insertTab()
00942 {
00943     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:tab-stop")));
00944     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:tab-stop")));
00945 }
00946 
00947 void WordPerfectCollector::insertLineBreak()
00948 {
00949     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagOpenElement("text:line-break")));
00950     mpCurrentContentElements->push_back(static_cast<DocumentElement *>(new TagCloseElement("text:line-break")));
00951 }
00952 
00953 void WordPerfectCollector::insertText(const WPXString &text)
00954 {
00955     DocumentElement *pText = new TextElement(text);
00956     mpCurrentContentElements->push_back(pText);
00957 }
KDE Home | KDE Accessibility Home | Description of Access Keys