/* This file is part of the KDE project Copyright (C) 1998, 1999 Reginald Stadlbauer Copyright (c) 2000 ID-PRO Deutschland GmbH. All rights reserved. Contact: Wolf-Michael Bolle Copyright (C) 2001, 2002 Nicolas GOUTTE Copyright (c) 2001 IABG mbH. All rights reserved. Contact: Wolf-Michael Bolle This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include typedef KGenericFactory DocBookExportFactory; K_EXPORT_COMPONENT_FACTORY( libdocbookexport, DocBookExportFactory( "kofficefilters" ) ) DocBookExport::DocBookExport ( KoFilter *, const char *, const TQStringList & ) : KoFilter () { } #define INSERT_TABLE_IN_PARA 1 // Do not change this! #define TABLES_WITH_TITLES 0 struct DocData { bool article; bool head1; bool head2; bool head3; bool head4; bool bulletList; bool enumeratedList; bool alphabeticalList; }; class DocBookWorker : public KWEFBaseWorker { public: DocBookWorker (void) {} bool doOpenDocument ( void ); bool doCloseDocument ( void ); bool doOpenFile ( const TQString &, const TQString & ); bool doCloseFile ( void ); bool doOpenBody ( void ); bool doCloseBody ( void ); bool doFullDocumentInfo ( const KWEFDocumentInfo & ); bool doFullDocument ( const TQValueList ¶List ); private: void ProcessPictureData ( const Picture &picture ); void ProcessTableData ( const Table &table ); void ProcessParagraphData ( const ParaData ¶, TQString tag ); void CloseItemizedList ( void ); void CloseEnumeratedList ( void ); void CloseAlphabeticalList ( void ); void CloseLists ( void ); void CloseHead4 ( void ); void CloseHead3 ( void ); void CloseHead2 ( void ); void CloseHead1AndArticle ( void ); void OpenArticleUnlessHead1 ( void ); TQString outputText; DocData docData; TQFile *fileOut; TQString exportFileName; }; // ProcessPictureData () takes the available picture data, makes a // copy of the image file into *.sgml.d/pictures/*.* from KoStore // pictures/*.*, and creates the necessary DocBook tags for it. void DocBookWorker::ProcessPictureData ( const Picture &picture ) { TQByteArray byteArray; if ( loadSubFile ( picture.koStoreName,byteArray ) ) { TQFileInfo fileInfo (exportFileName); TQDir dir ( fileInfo.dirPath () ); TQString subDirName = fileInfo.fileName () + ".d"; if ( !dir.exists (subDirName) ) { dir.mkdir (subDirName); } dir.cd (subDirName); if ( !dir.exists ("pictures") ) { dir.mkdir ("pictures"); } TQString pictureFileName = dir.filePath (picture.koStoreName); TQFile pictureFile (pictureFileName); if ( pictureFile.open (IO_WriteOnly) ) { pictureFile.writeBlock ( byteArray, byteArray.size () ); TQString pictureText; #if TABLES_WITH_TITLES pictureText += "
\n"; #if 1 pictureText += " " + picture.name + "\n"; #else pictureText += " \n"; #endif #else pictureText += "\n"; #endif pictureText += " \n"; pictureText += " \n"; pictureText += " \n"; pictureText += " \n"; pictureText += " \n"; #if TABLES_WITH_TITLES pictureText += "
\n"; #else pictureText += "\n"; #endif outputText += pictureText; } else { kdError (30507) << "Unable to open picture file " << pictureFileName << "!" << endl; pictureFile.close (); } } else { kdError (30507) << "Unable to open KoStore file " << picture.koStoreName << "!" << endl; } } // ProcessTableData () takes the table data and creates the necessary // DocBook tags for it. void DocBookWorker::ProcessTableData ( const Table &table ) { #if 0 kdError (30507) << "DEBUG: ProcessTableData ()" << endl; #endif TQString tableText; #if TABLES_WITH_TITLES tableText += "\n"; #if 1 tableText += " " + table.name + "\n"; #else tableText += " \n"; #endif #else tableText += "\n"; #endif tableText += " \n"; tableText += " \n"; int currentRow = -1; TQValueList::ConstIterator cellIt; for ( cellIt = table.cellList.begin (); cellIt != table.cellList.end (); cellIt++ ) { if ( (*cellIt).row != currentRow ) { if ( currentRow >= 0 ) { tableText += " \n"; } currentRow = (*cellIt).row; tableText += " \n"; } TQString tmpBuf; tmpBuf = outputText; outputText = ""; doFullDocument ( *(*cellIt).paraList ); tableText += " " + outputText.remove ( '\n' ) + "\n"; outputText = tmpBuf; } if ( currentRow >= 0 ) { tableText += " \n"; } tableText += " \n"; tableText += " \n"; #if TABLES_WITH_TITLES tableText += "
\n"; #else tableText += "\n"; #endif outputText += tableText; #if 0 kdError (30507) << "DEBUG: ProcessTableData (): " << tableText << endl; #endif } // ProcessParagraphData () mangles the pure text through the // formatting information stored in the FormatData list and prints it // out to the export file. void DocBookWorker::ProcessParagraphData ( const ParaData ¶, TQString tag ) { #if !INSERT_TABLE_IN_PARA TQValueList tmpAnchoredInsertList; #endif outputText += "<" + tag + ">"; if ( para.text.length () > 0 ) { ValueListFormatData::ConstIterator formattingIt; for ( formattingIt = para.formattingList.begin (); formattingIt != para.formattingList.end (); formattingIt++ ) { switch ( (*formattingIt).id ) { case 1: // texts { bool fixedFont = false; if ( (*formattingIt).text.fontName == "courier" || (*formattingIt).text.fontName == "Courier" || (*formattingIt).text.fontName == "Courier New" ) { fixedFont = true; } if ( (*formattingIt).text.italic && !para.layout.formatData.text.italic ) { outputText += ""; } if ( (*formattingIt).text.weight > para.layout.formatData.text.weight ) { outputText += ""; } if ( fixedFont ) { outputText += ""; } outputText += EscapeXmlText (para.text.mid ( (*formattingIt).pos, (*formattingIt).len )); if ( fixedFont ) { outputText += ""; } if ( (*formattingIt).text.weight > para.layout.formatData.text.weight ) { outputText += ""; } if ( (*formattingIt).text.italic && !para.layout.formatData.text.italic ) { outputText += ""; } } break; case 4: // variables if (9 == (*formattingIt).variable.m_type) { // A link (TODO: verify the code, as the tags were copied from a XML DocBook file) outputText += ""; outputText += EscapeXmlText ( (*formattingIt).variable.getLinkName() ); outputText += ""; } else { outputText += EscapeXmlText ( (*formattingIt).variable.m_text ); } break; case 6: // anchors #if 0 kdError (30507) << "Processing anchor " << (*formattingIt).frameAnchor.name << endl; #endif #if INSERT_TABLE_IN_PARA outputText += "\n"; #if 0 anchoredInsertList.prepend ( AnchoredInsert ( (*formattingIt).frameAnchor.name, outputText.length () ) ); #endif switch ( (*formattingIt).frameAnchor.type ) { case 2: ProcessPictureData ( (*formattingIt).frameAnchor.picture ); break; case 6: ProcessTableData ( (*formattingIt).frameAnchor.table ); break; default: kdError (30507) << "Unhandled anchor type " << (*formattingIt).frameAnchor.type << "!" << endl; } #else tmpAnchoredInsertList << AnchoredInsert ( (*formattingIt).frameAnchor.name, 0 ); #endif outputText += "<" + tag + ">"; break; default: kdError (30507) << "Unhandled format id " << (*formattingIt).id << "!" << endl; } } } outputText += "\n"; #if !INSERT_TABLE_IN_PARA TQValueList::Iterator anchoredInsert; for ( anchoredInsert = tmpAnchoredInsertList.begin (); anchoredInsert != tmpAnchoredInsertList.end (); anchoredInsert++ ) { (*anchoredInsert).pos = outputText.length (); anchoredInsertList.prepend (*anchoredInsert); } #endif } void DocBookWorker::CloseItemizedList ( void ) { if ( docData.bulletList ) { outputText += " \n"; docData.bulletList = false; } } void DocBookWorker::CloseEnumeratedList ( void ) { if ( docData.enumeratedList ) { outputText += " \n"; docData.enumeratedList = false; } } void DocBookWorker::CloseAlphabeticalList ( void ) { if ( docData.alphabeticalList ) { outputText += " \n"; docData.alphabeticalList = false; } } void DocBookWorker::CloseLists ( void ) { CloseItemizedList (); CloseEnumeratedList (); CloseAlphabeticalList (); } void DocBookWorker::CloseHead4 ( void ) { CloseLists (); if ( docData.head4 ) { outputText += " \n"; docData.head4 = false; } } void DocBookWorker::CloseHead3 ( void ) { CloseHead4 (); if ( docData.head3 ) { outputText += " \n"; docData.head3 = false; } } void DocBookWorker::CloseHead2 ( void ) { CloseHead3 (); if ( docData.head2 ) { outputText += " \n"; docData.head2 = false; } } void DocBookWorker::CloseHead1AndArticle ( void ) { CloseHead2 (); if ( docData.article ) { outputText += "\n"; docData.article = false; } if ( docData.head1 ) { outputText += " \n"; docData.head1 = false; } } void DocBookWorker::OpenArticleUnlessHead1 ( void ) { if ( !docData.head1 && !docData.article ) { outputText += "
\n"; docData.article = true; } } bool DocBookWorker::doFullDocument ( const TQValueList ¶List ) { #if 0 kdError (30507) << "doFullDocument () - Begin" << endl; #endif TQValueList::ConstIterator paraIt; TQValueList::ConstIterator end(paraList.end ()); for ( paraIt = paraList.begin (); paraIt != end ; ++paraIt ) { switch ( (*paraIt).layout.counter.numbering ) { case CounterData::NUM_LIST: switch ( (*paraIt).layout.counter.style ) { case CounterData::STYLE_CUSTOMBULLET: case CounterData::STYLE_CIRCLEBULLET: case CounterData::STYLE_SQUAREBULLET: case CounterData::STYLE_DISCBULLET: case CounterData::STYLE_CUSTOM: case CounterData::STYLE_NONE: CloseEnumeratedList (); CloseAlphabeticalList (); OpenArticleUnlessHead1 (); if ( !docData.bulletList ) { outputText += " \n"; docData.bulletList = true; } outputText += "\n"; ProcessParagraphData (*paraIt, "PARA" ); outputText += "\n"; break; case CounterData::STYLE_NUM: case CounterData::STYLE_ROM_NUM_L: case CounterData::STYLE_ROM_NUM_U: CloseItemizedList (); CloseAlphabeticalList (); OpenArticleUnlessHead1 (); if ( !docData.enumeratedList ) { outputText += " \n"; docData.enumeratedList = true; } outputText += "\n"; ProcessParagraphData (*paraIt, "PARA" ); outputText += "\n"; break; case CounterData::STYLE_ALPHAB_L: case CounterData::STYLE_ALPHAB_U: CloseItemizedList (); CloseEnumeratedList (); OpenArticleUnlessHead1 (); if ( !docData.alphabeticalList ) { outputText += " \n"; docData.alphabeticalList = true; } outputText += "\n"; ProcessParagraphData (*paraIt, "PARA" ); outputText += "\n"; break; default: kdError (30507) << "Unknown counter style " << (*paraIt).layout.counter.style << "!" << endl; CloseLists (); OpenArticleUnlessHead1 (); ProcessParagraphData (*paraIt, "PARA" ); } break; case CounterData::NUM_CHAPTER: switch ( (*paraIt).layout.counter.depth ) { case 0: CloseHead1AndArticle (); outputText += " \n"; docData.head1 = true; ProcessParagraphData (*paraIt, "TITLE" ); break; case 1: CloseHead2 (); outputText += "
\n"; docData.head2 = true; ProcessParagraphData (*paraIt, "TITLE" ); break; case 2: CloseHead3 (); outputText += "
\n"; docData.head3 = true; ProcessParagraphData (*paraIt, "TITLE" ); break; case 3: CloseHead4 (); outputText += "
\n"; docData.head4 = true; ProcessParagraphData (*paraIt, "TITLE" ); break; default: kdError (30507) << "Unexpected chapter depth " << (*paraIt).layout.counter.depth << "!" << endl; CloseLists (); OpenArticleUnlessHead1 (); ProcessParagraphData (*paraIt, "PARA" ); } break; default: CloseLists (); OpenArticleUnlessHead1 (); ProcessParagraphData (*paraIt, "PARA" ); } } #if 0 kdError (30507) << "doFullDocument () - End" << outputText << endl; #endif return true; } bool DocBookWorker::doOpenDocument ( void ) { outputText += "\n"; outputText += "\n"; return true; } bool DocBookWorker::doOpenBody ( void ) { docData.article = false; docData.head1 = false; docData.head2 = false; docData.head3 = false; docData.head4 = false; docData.bulletList = false; docData.enumeratedList = false; docData.alphabeticalList = false; return true; } bool DocBookWorker::doCloseBody ( void ) { CloseHead1AndArticle (); return true; } bool DocBookWorker::doCloseDocument ( void ) { outputText += "\n"; return true; } bool DocBookWorker::doOpenFile ( const TQString &filenameOut, const TQString & /*to*/ ) { fileOut = new TQFile(filenameOut); if ( !fileOut ) { kdError(30507) << "No output file! Aborting!" << endl; return false; } if ( !fileOut->open (IO_WriteOnly) ) { kdError(30507) << "Unable to open output file!" << endl; fileOut->close (); delete fileOut; fileOut = NULL; return false; } exportFileName=filenameOut; return true; } bool DocBookWorker::doCloseFile ( void ) { if ( !fileOut ) return true; // As a TQChar can be transformed into many bytes, // we need to use TQCString::length instead of TQString::length TQCString cstr = outputText.local8Bit (); fileOut->writeBlock ( cstr, cstr.length () ); fileOut->close (); delete fileOut; fileOut = NULL; return true; } // ProcessInfoData () creates a subtag to the current tag level with // text that was created earlier by ProcessInfoData () and adds it to // the current tag level. It is used by ProcessDocumentIntoTag () to // assemble the diverse levels of information of the BOOKINFO tag. static void ProcessInfoData ( const TQString &tagName, const TQString & tagText, TQString &outputText) { if ( tagText.length () ) { outputText += "<" + tagName + ">" + tagText + "\n"; } } bool DocBookWorker::doFullDocumentInfo ( const KWEFDocumentInfo &docInfo ) { TQString bookInfoText; TQString abstractText; TQString authorText; TQString affiliationText; TQString addressText; ProcessInfoData ( "TITLE", docInfo.title, bookInfoText ); ProcessInfoData ( "PARA", docInfo.abstract, abstractText ); ProcessInfoData ( "SURNAME", docInfo.fullName, authorText ); ProcessInfoData ( "JOBTITLE", docInfo.jobTitle, affiliationText ); ProcessInfoData ( "ORGNAME", docInfo.company, affiliationText ); ProcessInfoData ( "STREET", docInfo.street, addressText ); ProcessInfoData ( "CITY", docInfo.city, addressText ); ProcessInfoData ( "POSTCODE", docInfo.postalCode, addressText ); ProcessInfoData ( "COUNTRY", docInfo.country, addressText ); ProcessInfoData ( "EMAIL", docInfo.email, addressText ); ProcessInfoData ( "PHONE", docInfo.telephone, addressText ); ProcessInfoData ( "FAX", docInfo.fax, addressText ); ProcessInfoData ( "ADDRESS", addressText, affiliationText ); ProcessInfoData ( "AFFILIATION", affiliationText, authorText ); ProcessInfoData ( "ABSTRACT", abstractText, bookInfoText ); ProcessInfoData ( "AUTHOR", authorText, bookInfoText ); ProcessInfoData ( "BOOKINFO", bookInfoText, outputText ); return true; } KoFilter::ConversionStatus DocBookExport::convert( const TQCString& from, const TQCString& to ) { #if 0 kdError (30507) << "to = " << to << ", from = " << from << endl; #endif if ( to != "text/sgml" && to != "text/docbook" || from != "application/x-kword" ) { return KoFilter::NotImplemented; } #if 1 kdError (30507) << "let's get on with it" << endl; #endif DocBookWorker worker; KWEFKWordLeader leader (&worker); leader.convert (m_chain, from, to); #if 1 kdError (30507) << "done here" << endl; #endif return KoFilter::OK; }