00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <docbookexport.h>
00026 #include <docbookexport.moc>
00027 #include <kdebug.h>
00028 #include <kgenericfactory.h>
00029 #include <qdir.h>
00030 #include <qdom.h>
00031
00032 #include <KoFilterChain.h>
00033 #include <KWEFStructures.h>
00034 #include <KWEFUtil.h>
00035 #include <KWEFKWordLeader.h>
00036 #include <ProcessDocument.h>
00037 #include <KWEFBaseWorker.h>
00038
00039 typedef KGenericFactory<DocBookExport, KoFilter> DocBookExportFactory;
00040 K_EXPORT_COMPONENT_FACTORY( libdocbookexport, DocBookExportFactory( "kofficefilters" ) )
00041
00042 DocBookExport::DocBookExport ( KoFilter *,
00043 const char *,
00044 const QStringList & ) : KoFilter ()
00045 {
00046 }
00047
00048
00049 #define INSERT_TABLE_IN_PARA 1 // Do not change this!
00050 #define TABLES_WITH_TITLES 0
00051
00052
00053 struct DocData
00054 {
00055 bool article;
00056 bool head1;
00057 bool head2;
00058 bool head3;
00059 bool head4;
00060 bool bulletList;
00061 bool enumeratedList;
00062 bool alphabeticalList;
00063 };
00064
00065
00066 class DocBookWorker : public KWEFBaseWorker
00067 {
00068 public:
00069 DocBookWorker (void) {}
00070
00071 bool doOpenDocument ( void );
00072 bool doCloseDocument ( void );
00073
00074 bool doOpenFile ( const QString &, const QString & );
00075 bool doCloseFile ( void );
00076
00077 bool doOpenBody ( void );
00078 bool doCloseBody ( void );
00079
00080 bool doFullDocumentInfo ( const KWEFDocumentInfo & );
00081
00082 bool doFullDocument ( const QValueList<ParaData> ¶List );
00083
00084 private:
00085 void ProcessPictureData ( const Picture &picture );
00086
00087 void ProcessTableData ( const Table &table );
00088
00089 void ProcessParagraphData ( const ParaData ¶,
00090 QString tag );
00091
00092 void CloseItemizedList ( void );
00093 void CloseEnumeratedList ( void );
00094 void CloseAlphabeticalList ( void );
00095 void CloseLists ( void );
00096
00097 void CloseHead4 ( void );
00098 void CloseHead3 ( void );
00099 void CloseHead2 ( void );
00100 void CloseHead1AndArticle ( void );
00101
00102 void OpenArticleUnlessHead1 ( void );
00103
00104 QString outputText;
00105 DocData docData;
00106 QFile *fileOut;
00107 QString exportFileName;
00108 };
00109
00110
00111
00112
00113
00114
00115 void DocBookWorker::ProcessPictureData ( const Picture &picture )
00116 {
00117 QByteArray byteArray;
00118
00119 if ( loadSubFile ( picture.koStoreName,byteArray ) )
00120 {
00121 QFileInfo fileInfo (exportFileName);
00122 QDir dir ( fileInfo.dirPath () );
00123 QString subDirName = fileInfo.fileName () + ".d";
00124
00125 if ( !dir.exists (subDirName) )
00126 {
00127 dir.mkdir (subDirName);
00128 }
00129
00130 dir.cd (subDirName);
00131
00132 if ( !dir.exists ("pictures") )
00133 {
00134 dir.mkdir ("pictures");
00135 }
00136
00137 QString pictureFileName = dir.filePath (picture.koStoreName);
00138
00139 QFile pictureFile (pictureFileName);
00140
00141 if ( pictureFile.open (IO_WriteOnly) )
00142 {
00143 pictureFile.writeBlock ( byteArray, byteArray.size () );
00144
00145 QString pictureText;
00146
00147 #if TABLES_WITH_TITLES
00148 pictureText += "<FIGURE>\n";
00149
00150 #if 1
00151 pictureText += " <TITLE>" + picture.name + "</TITLE>\n";
00152 #else
00153 pictureText += " <TITLE></TITLE>\n";
00154 #endif
00155 #else
00156 pictureText += "<INFORMALFIGURE>\n";
00157 #endif
00158 pictureText += " <MEDIAOBJECT>\n";
00159 pictureText += " <IMAGEOBJECT>\n";
00160 pictureText += " <IMAGEDATA FILEREF=\"" + pictureFileName + "\">\n";
00161 pictureText += " </IMAGEOBJECT>\n";
00162 pictureText += " </MEDIAOBJECT>\n";
00163 #if TABLES_WITH_TITLES
00164 pictureText += "</FIGURE>\n";
00165 #else
00166 pictureText += "</INFORMALFIGURE>\n";
00167 #endif
00168
00169 outputText += pictureText;
00170 }
00171 else
00172 {
00173 kdError (30507) << "Unable to open picture file " << pictureFileName << "!" << endl;
00174
00175 pictureFile.close ();
00176 }
00177 }
00178 else
00179 {
00180 kdError (30507) << "Unable to open KoStore file " << picture.koStoreName << "!" << endl;
00181 }
00182 }
00183
00184
00185
00186
00187
00188 void DocBookWorker::ProcessTableData ( const Table &table )
00189 {
00190 #if 0
00191 kdError (30507) << "DEBUG: ProcessTableData ()" << endl;
00192 #endif
00193
00194 QString tableText;
00195
00196 #if TABLES_WITH_TITLES
00197 tableText += "<TABLE>\n";
00198
00199 #if 1
00200 tableText += " <TITLE>" + table.name + "</TITLE>\n";
00201 #else
00202 tableText += " <TITLE></TITLE>\n";
00203 #endif
00204 #else
00205 tableText += "<INFORMALTABLE>\n";
00206 #endif
00207
00208 tableText += " <TGROUP COLS=\"" + QString::number (table.cols) + "\">\n";
00209 tableText += " <TBODY>\n";
00210
00211 int currentRow = -1;
00212
00213 QValueList<TableCell>::ConstIterator cellIt;
00214
00215 for ( cellIt = table.cellList.begin ();
00216 cellIt != table.cellList.end ();
00217 cellIt++ )
00218 {
00219 if ( (*cellIt).row != currentRow )
00220 {
00221 if ( currentRow >= 0 )
00222 {
00223 tableText += " </ROW>\n";
00224 }
00225
00226 currentRow = (*cellIt).row;
00227
00228 tableText += " <ROW>\n";
00229 }
00230
00231 QString tmpBuf;
00232 tmpBuf = outputText;
00233 outputText = "";
00234
00235 doFullDocument ( *(*cellIt).paraList );
00236
00237 tableText += " <ENTRY>" + outputText.remove ( '\n' ) + "</ENTRY>\n";
00238
00239 outputText = tmpBuf;
00240 }
00241
00242 if ( currentRow >= 0 )
00243 {
00244 tableText += " </ROW>\n";
00245 }
00246
00247 tableText += " </TBODY>\n";
00248 tableText += " </TGROUP>\n";
00249
00250 #if TABLES_WITH_TITLES
00251 tableText += "</TABLE>\n";
00252 #else
00253 tableText += "</INFORMALTABLE>\n";
00254 #endif
00255
00256 outputText += tableText;
00257
00258 #if 0
00259 kdError (30507) << "DEBUG: ProcessTableData (): " << tableText << endl;
00260 #endif
00261 }
00262
00263
00264
00265
00266
00267
00268 void DocBookWorker::ProcessParagraphData ( const ParaData ¶,
00269 QString tag )
00270 {
00271 #if !INSERT_TABLE_IN_PARA
00272 QValueList<AnchoredInsert> tmpAnchoredInsertList;
00273 #endif
00274
00275 outputText += "<" + tag + ">";
00276
00277 if ( para.text.length () > 0 )
00278 {
00279 ValueListFormatData::ConstIterator formattingIt;
00280
00281 for ( formattingIt = para.formattingList.begin ();
00282 formattingIt != para.formattingList.end ();
00283 formattingIt++ )
00284 {
00285 switch ( (*formattingIt).id )
00286 {
00287 case 1:
00288 {
00289
00290 bool fixedFont = false;
00291
00292 if ( (*formattingIt).text.fontName == "courier" ||
00293 (*formattingIt).text.fontName == "Courier" ||
00294 (*formattingIt).text.fontName == "Courier New" )
00295 {
00296 fixedFont = true;
00297 }
00298
00299 if ( (*formattingIt).text.italic && !para.layout.formatData.text.italic )
00300 {
00301 outputText += "<EMPHASIS>";
00302 }
00303
00304 if ( (*formattingIt).text.weight > para.layout.formatData.text.weight )
00305 {
00306 outputText += "<EMPHASIS ROLE=bold>";
00307 }
00308
00309 if ( fixedFont )
00310 {
00311 outputText += "<LITERAL>";
00312 }
00313
00314 outputText += EscapeXmlText (para.text.mid ( (*formattingIt).pos, (*formattingIt).len ));
00315
00316 if ( fixedFont )
00317 {
00318 outputText += "</LITERAL>";
00319 }
00320
00321 if ( (*formattingIt).text.weight > para.layout.formatData.text.weight )
00322 {
00323 outputText += "</EMPHASIS>";
00324 }
00325
00326 if ( (*formattingIt).text.italic && !para.layout.formatData.text.italic )
00327 {
00328 outputText += "</EMPHASIS>";
00329 }
00330 }
00331 break;
00332
00333 case 4:
00334 if (9 == (*formattingIt).variable.m_type)
00335 {
00336
00337 outputText += "<ULINK URL=\"";
00338 outputText += EscapeXmlText ( (*formattingIt).variable.getHrefName(), true, true );
00339 outputText += "\">";
00340 outputText += EscapeXmlText ( (*formattingIt).variable.getLinkName() );
00341 outputText += "</ULINK>";
00342 }
00343 else
00344 {
00345 outputText += EscapeXmlText ( (*formattingIt).variable.m_text );
00346 }
00347 break;
00348
00349 case 6:
00350 #if 0
00351 kdError (30507) << "Processing anchor " << (*formattingIt).frameAnchor.name << endl;
00352 #endif
00353
00354 #if INSERT_TABLE_IN_PARA
00355 outputText += "</" + tag + ">\n";
00356
00357 #if 0
00358 anchoredInsertList.prepend ( AnchoredInsert ( (*formattingIt).frameAnchor.name,
00359 outputText.length () ) );
00360 #endif
00361
00362 switch ( (*formattingIt).frameAnchor.type )
00363 {
00364 case 2:
00365 ProcessPictureData ( (*formattingIt).frameAnchor.picture );
00366 break;
00367
00368 case 6:
00369 ProcessTableData ( (*formattingIt).frameAnchor.table );
00370 break;
00371
00372 default:
00373 kdError (30507) << "Unhandled anchor type "
00374 << (*formattingIt).frameAnchor.type << "!" << endl;
00375 }
00376 #else
00377 tmpAnchoredInsertList << AnchoredInsert ( (*formattingIt).frameAnchor.name, 0 );
00378 #endif
00379
00380 outputText += "<" + tag + ">";
00381
00382 break;
00383
00384 default:
00385 kdError (30507) << "Unhandled format id "
00386 << (*formattingIt).id << "!" << endl;
00387 }
00388 }
00389 }
00390
00391 outputText += "</" + tag + ">\n";
00392
00393 #if !INSERT_TABLE_IN_PARA
00394 QValueList<AnchoredInsert>::Iterator anchoredInsert;
00395
00396 for ( anchoredInsert = tmpAnchoredInsertList.begin ();
00397 anchoredInsert != tmpAnchoredInsertList.end ();
00398 anchoredInsert++ )
00399 {
00400 (*anchoredInsert).pos = outputText.length ();
00401 anchoredInsertList.prepend (*anchoredInsert);
00402 }
00403 #endif
00404 }
00405
00406
00407 void DocBookWorker::CloseItemizedList ( void )
00408 {
00409 if ( docData.bulletList )
00410 {
00411 outputText += "</ITEMIZEDLIST> <!-- End of Bullet List -->\n";
00412 docData.bulletList = false;
00413 }
00414 }
00415
00416
00417 void DocBookWorker::CloseEnumeratedList ( void )
00418 {
00419 if ( docData.enumeratedList )
00420 {
00421 outputText += "</ORDEREDLIST> <!-- End of Enumerated List -->\n";
00422 docData.enumeratedList = false;
00423 }
00424 }
00425
00426
00427 void DocBookWorker::CloseAlphabeticalList ( void )
00428 {
00429 if ( docData.alphabeticalList )
00430 {
00431 outputText += "</ORDEREDLIST> <!-- End of Alphabetical List -->\n";
00432 docData.alphabeticalList = false;
00433 }
00434 }
00435
00436
00437 void DocBookWorker::CloseLists ( void )
00438 {
00439 CloseItemizedList ();
00440 CloseEnumeratedList ();
00441 CloseAlphabeticalList ();
00442 }
00443
00444
00445 void DocBookWorker::CloseHead4 ( void )
00446 {
00447 CloseLists ();
00448
00449 if ( docData.head4 )
00450 {
00451 outputText += "</SECTION> <!-- End of Head 4 -->\n";
00452 docData.head4 = false;
00453 }
00454 }
00455
00456
00457 void DocBookWorker::CloseHead3 ( void )
00458 {
00459 CloseHead4 ();
00460
00461 if ( docData.head3 )
00462 {
00463 outputText += "</SECTION> <!-- End of Head 3 -->\n";
00464 docData.head3 = false;
00465 }
00466 }
00467
00468
00469 void DocBookWorker::CloseHead2 ( void )
00470 {
00471 CloseHead3 ();
00472
00473 if ( docData.head2 )
00474 {
00475 outputText += "</SECTION> <!-- End of Head 2 -->\n";
00476 docData.head2 = false;
00477 }
00478 }
00479
00480
00481 void DocBookWorker::CloseHead1AndArticle ( void )
00482 {
00483 CloseHead2 ();
00484
00485 if ( docData.article )
00486 {
00487 outputText += "</ARTICLE>\n";
00488 docData.article = false;
00489 }
00490
00491 if ( docData.head1 )
00492 {
00493 outputText += "</CHAPTER> <!-- End of Head 1 -->\n";
00494 docData.head1 = false;
00495 }
00496 }
00497
00498
00499 void DocBookWorker::OpenArticleUnlessHead1 ( void )
00500 {
00501 if ( !docData.head1 && !docData.article )
00502 {
00503 outputText += "<ARTICLE> <!-- Begin of Article -->\n";
00504 docData.article = true;
00505 }
00506 }
00507
00508
00509 bool DocBookWorker::doFullDocument ( const QValueList<ParaData> ¶List )
00510 {
00511 #if 0
00512 kdError (30507) << "doFullDocument () - Begin" << endl;
00513 #endif
00514
00515 QValueList<ParaData>::ConstIterator paraIt;
00516 QValueList<ParaData>::ConstIterator end(paraList.end ());
00517 for ( paraIt = paraList.begin (); paraIt != end ; ++paraIt )
00518 {
00519 switch ( (*paraIt).layout.counter.numbering )
00520 {
00521 case CounterData::NUM_LIST:
00522 switch ( (*paraIt).layout.counter.style )
00523 {
00524 case CounterData::STYLE_CUSTOMBULLET:
00525 case CounterData::STYLE_CIRCLEBULLET:
00526 case CounterData::STYLE_SQUAREBULLET:
00527 case CounterData::STYLE_DISCBULLET:
00528 case CounterData::STYLE_CUSTOM:
00529 case CounterData::STYLE_NONE:
00530 CloseEnumeratedList ();
00531 CloseAlphabeticalList ();
00532
00533 OpenArticleUnlessHead1 ();
00534
00535 if ( !docData.bulletList )
00536 {
00537 outputText += "<ITEMIZEDLIST> <!-- Begin of Bullet List -->\n";
00538 docData.bulletList = true;
00539 }
00540
00541 outputText += "<LISTITEM>\n";
00542 ProcessParagraphData (*paraIt, "PARA" );
00543 outputText += "</LISTITEM>\n";
00544 break;
00545
00546 case CounterData::STYLE_NUM:
00547 case CounterData::STYLE_ROM_NUM_L:
00548 case CounterData::STYLE_ROM_NUM_U:
00549 CloseItemizedList ();
00550 CloseAlphabeticalList ();
00551
00552 OpenArticleUnlessHead1 ();
00553
00554 if ( !docData.enumeratedList )
00555 {
00556 outputText += "<ORDEREDLIST NUMERATION=\"Arabic\"> <!-- Begin of Enumerated List -->\n";
00557 docData.enumeratedList = true;
00558 }
00559
00560 outputText += "<LISTITEM>\n";
00561 ProcessParagraphData (*paraIt, "PARA" );
00562 outputText += "</LISTITEM>\n";
00563 break;
00564
00565 case CounterData::STYLE_ALPHAB_L:
00566 case CounterData::STYLE_ALPHAB_U:
00567 CloseItemizedList ();
00568 CloseEnumeratedList ();
00569
00570 OpenArticleUnlessHead1 ();
00571
00572 if ( !docData.alphabeticalList )
00573 {
00574 outputText += "<ORDEREDLIST NUMERATION=\"Loweralpha\"> <!-- Begin of Alphabetical List -->\n";
00575 docData.alphabeticalList = true;
00576 }
00577
00578 outputText += "<LISTITEM>\n";
00579 ProcessParagraphData (*paraIt, "PARA" );
00580 outputText += "</LISTITEM>\n";
00581 break;
00582
00583 default:
00584 kdError (30507) << "Unknown counter style " << (*paraIt).layout.counter.style << "!" << endl;
00585 CloseLists ();
00586 OpenArticleUnlessHead1 ();
00587 ProcessParagraphData (*paraIt, "PARA" );
00588 }
00589
00590 break;
00591
00592 case CounterData::NUM_CHAPTER:
00593 switch ( (*paraIt).layout.counter.depth )
00594 {
00595 case 0:
00596 CloseHead1AndArticle ();
00597
00598 outputText += "<CHAPTER> <!-- Begin of Head 1 -->\n";
00599 docData.head1 = true;
00600
00601 ProcessParagraphData (*paraIt, "TITLE" );
00602 break;
00603
00604 case 1:
00605 CloseHead2 ();
00606
00607 outputText += "<SECTION> <!-- Begin of Head 2 -->\n";
00608 docData.head2 = true;
00609
00610 ProcessParagraphData (*paraIt, "TITLE" );
00611 break;
00612
00613 case 2:
00614 CloseHead3 ();
00615
00616 outputText += "<SECTION> <!-- Begin of Head 3 -->\n";
00617 docData.head3 = true;
00618
00619 ProcessParagraphData (*paraIt, "TITLE" );
00620 break;
00621
00622 case 3:
00623 CloseHead4 ();
00624
00625 outputText += "<SECTION> <!-- Begin of Head 4 -->\n";
00626 docData.head4 = true;
00627
00628 ProcessParagraphData (*paraIt, "TITLE" );
00629 break;
00630
00631 default:
00632 kdError (30507) << "Unexpected chapter depth " << (*paraIt).layout.counter.depth << "!" << endl;
00633 CloseLists ();
00634 OpenArticleUnlessHead1 ();
00635 ProcessParagraphData (*paraIt, "PARA" );
00636 }
00637
00638 break;
00639
00640 default:
00641 CloseLists ();
00642 OpenArticleUnlessHead1 ();
00643 ProcessParagraphData (*paraIt, "PARA" );
00644 }
00645 }
00646
00647 #if 0
00648 kdError (30507) << "doFullDocument () - End" << outputText << endl;
00649 #endif
00650 return true;
00651 }
00652
00653
00654 bool DocBookWorker::doOpenDocument ( void )
00655 {
00656 outputText += "<!DOCTYPE BOOK PUBLIC \"-//OASIS//DTD DocBook V3.1//EN\">\n";
00657 outputText += "<BOOK>\n";
00658
00659 return true;
00660 }
00661
00662
00663 bool DocBookWorker::doOpenBody ( void )
00664 {
00665 docData.article = false;
00666 docData.head1 = false;
00667 docData.head2 = false;
00668 docData.head3 = false;
00669 docData.head4 = false;
00670 docData.bulletList = false;
00671 docData.enumeratedList = false;
00672 docData.alphabeticalList = false;
00673
00674 return true;
00675 }
00676
00677
00678 bool DocBookWorker::doCloseBody ( void )
00679 {
00680 CloseHead1AndArticle ();
00681
00682 return true;
00683 }
00684
00685
00686 bool DocBookWorker::doCloseDocument ( void )
00687 {
00688 outputText += "</BOOK>\n";
00689
00690 return true;
00691 }
00692
00693
00694 bool DocBookWorker::doOpenFile ( const QString &filenameOut, const QString & )
00695 {
00696 fileOut = new QFile(filenameOut);
00697
00698 if ( !fileOut )
00699 {
00700 kdError(30507) << "No output file! Aborting!" << endl;
00701 return false;
00702 }
00703
00704 if ( !fileOut->open (IO_WriteOnly) )
00705 {
00706 kdError(30507) << "Unable to open output file!" << endl;
00707
00708 fileOut->close ();
00709 delete fileOut;
00710 fileOut = NULL;
00711
00712 return false;
00713 }
00714
00715 exportFileName=filenameOut;
00716
00717 return true;
00718 }
00719
00720
00721 bool DocBookWorker::doCloseFile ( void )
00722 {
00723 if ( !fileOut ) return true;
00724
00725
00726
00727 QCString cstr = outputText.local8Bit ();
00728 fileOut->writeBlock ( cstr, cstr.length () );
00729
00730 fileOut->close ();
00731 delete fileOut;
00732 fileOut = NULL;
00733
00734 return true;
00735 }
00736
00737
00738
00739
00740
00741
00742
00743 static void ProcessInfoData ( const QString &tagName,
00744 const QString & tagText,
00745 QString &outputText)
00746 {
00747 if ( tagText.length () )
00748 {
00749 outputText += "<" + tagName + ">" + tagText + "</" + tagName + ">\n";
00750 }
00751 }
00752
00753
00754 bool DocBookWorker::doFullDocumentInfo ( const KWEFDocumentInfo &docInfo )
00755 {
00756 QString bookInfoText;
00757 QString abstractText;
00758 QString authorText;
00759 QString affiliationText;
00760 QString addressText;
00761
00762 ProcessInfoData ( "TITLE", docInfo.title, bookInfoText );
00763 ProcessInfoData ( "PARA", docInfo.abstract, abstractText );
00764 ProcessInfoData ( "SURNAME", docInfo.fullName, authorText );
00765 ProcessInfoData ( "JOBTITLE", docInfo.jobTitle, affiliationText );
00766 ProcessInfoData ( "ORGNAME", docInfo.company, affiliationText );
00767 ProcessInfoData ( "STREET", docInfo.street, addressText );
00768 ProcessInfoData ( "CITY", docInfo.city, addressText );
00769 ProcessInfoData ( "POSTCODE", docInfo.postalCode, addressText );
00770 ProcessInfoData ( "COUNTRY", docInfo.country, addressText );
00771 ProcessInfoData ( "EMAIL", docInfo.email, addressText );
00772 ProcessInfoData ( "PHONE", docInfo.telephone, addressText );
00773 ProcessInfoData ( "FAX", docInfo.fax, addressText );
00774
00775 ProcessInfoData ( "ADDRESS", addressText, affiliationText );
00776 ProcessInfoData ( "AFFILIATION", affiliationText, authorText );
00777 ProcessInfoData ( "ABSTRACT", abstractText, bookInfoText );
00778 ProcessInfoData ( "AUTHOR", authorText, bookInfoText );
00779 ProcessInfoData ( "BOOKINFO", bookInfoText, outputText );
00780
00781 return true;
00782 }
00783
00784
00785 KoFilter::ConversionStatus DocBookExport::convert( const QCString& from, const QCString& to )
00786 {
00787 #if 0
00788 kdError (30507) << "to = " << to << ", from = " << from << endl;
00789 #endif
00790
00791 if ( to != "text/sgml" && to != "text/docbook" || from != "application/x-kword" )
00792 {
00793 return KoFilter::NotImplemented;
00794 }
00795
00796 #if 1
00797 kdError (30507) << "let's get on with it" << endl;
00798 #endif
00799
00800 DocBookWorker worker;
00801 KWEFKWordLeader leader (&worker);
00802 leader.convert (m_chain, from, to);
00803
00804 #if 1
00805 kdError (30507) << "done here" << endl;
00806 #endif
00807
00808 return KoFilter::OK;
00809 }