filters

asciiexport.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
00003    Copyright (c) 2000 ID-PRO Deutschland GmbH. All rights reserved.
00004                       Contact: Wolf-Michael Bolle <Bolle@ID-PRO.de>
00005    Copyright (C) 2001, 2002, 2004 Nicolas GOUTTE <goutte@kde.org>
00006    Copyright (C) 2003 Clarence Dang <dang@kde.org>
00007 
00008    This library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Library General Public
00010    License as published by the Free Software Foundation; either
00011    version 2 of the License, or (at your option) any later version.
00012 
00013    This library is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016    Library General Public License for more details.
00017 
00018    You should have received a copy of the GNU Library General Public License
00019    along with this library; see the file COPYING.LIB.  If not, write to
00020    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021  * Boston, MA 02110-1301, USA.
00022 */
00023 
00024 
00025 #include <limits.h>
00026 
00027 #include <qcstring.h>
00028 #include <qfile.h>
00029 #include <qiodevice.h>
00030 #include <qstring.h>
00031 #include <qtextcodec.h>
00032 #include <qtextstream.h>
00033 
00034 #include <kdebug.h>
00035 #include <kgenericfactory.h>
00036 
00037 #include <KoFilterChain.h>
00038 #include <KoFilterManager.h>
00039 #include <KoStore.h>
00040 
00041 #include <KWEFStructures.h>
00042 #include <KWEFBaseWorker.h>
00043 #include <KWEFKWordLeader.h>
00044 
00045 #include <ExportDialog.h>
00046 #include <asciiexport.h>
00047 
00048 
00049 class ASCIIExportFactory : KGenericFactory<ASCIIExport, KoFilter>
00050 {
00051 public:
00052     ASCIIExportFactory() : KGenericFactory<ASCIIExport, KoFilter>("kwordasciiexport")
00053     {
00054     }
00055 
00056 protected:
00057     virtual void setupTranslations(void)
00058     {
00059         KGlobal::locale()->insertCatalogue("kofficefilters");
00060     }
00061 };
00062 
00063 K_EXPORT_COMPONENT_FACTORY(libasciiexport, ASCIIExportFactory())
00064 
00065 
00066 class ASCIIWorker : public KWEFBaseWorker
00067 {
00068 public:
00069     ASCIIWorker() : m_ioDevice(NULL), m_streamOut(NULL), m_eol("\n")/*,
00070         m_inList(false)*/
00071     {
00072     }
00073 
00074     virtual ~ASCIIWorker()
00075     {
00076         delete m_streamOut; delete m_ioDevice;
00077     }
00078 
00079 public:
00080     virtual bool doOpenFile(const QString& filenameOut, const QString& to);
00081     virtual bool doCloseFile(void); // Close file in normal conditions
00082 
00083     virtual bool doOpenDocument(void);
00084     virtual bool doCloseDocument(void);
00085 
00086     virtual bool doFullParagraphList(const QValueList<ParaData>& paraList);
00087     virtual bool doFullParagraph(const ParaData& para);
00088     virtual bool doFullParagraph(const QString& paraText,
00089         const LayoutData& layout,
00090         const ValueListFormatData& paraFormatDataList);
00091 
00092 public:
00093     QString getEndOfLine(void) const { return m_eol; }
00094     void setEndOfLine(const QString& str) { m_eol = str; }
00095 
00096     QTextCodec* getCodec(void) const { return m_codec; }
00097     void setCodec(QTextCodec* codec) { m_codec = codec; }
00098 
00099 private:
00100     virtual bool ProcessTable(const Table& table);
00101     virtual bool ProcessParagraphData (const QString& paraText,
00102         const ValueListFormatData& paraFormatDataList);
00103 
00104 private:
00105     QIODevice* m_ioDevice;
00106     QTextStream* m_streamOut;
00107 
00108     QTextCodec* m_codec; // QTextCodec in which the file will be written
00109     QString m_eol; // End of line character(s)
00110     QStringList m_automaticNotes; // Automatic foot-/endnotes
00111     QString m_manualNotes; // Manual foot-/endnotes
00112 
00113 #if 0
00114     CounterData::Style m_typeList; // What is the style of the current list (undefined, if we are not in a list)
00115     bool m_inList; // Are we currently in a list?
00116     bool m_orderedList; // Is the current list ordered or not (undefined, if we are not in a list)
00117     int  m_counterList; // Counter for te lists
00118 #endif
00119 };
00120 
00121 bool ASCIIWorker::doOpenFile(const QString& filenameOut, const QString& /*to*/)
00122 {
00123     m_ioDevice = new QFile(filenameOut);
00124 
00125     if (!m_ioDevice)
00126     {
00127         kdError(30502) << "No output file! Aborting!" << endl;
00128         return false;
00129     }
00130 
00131     if (!m_ioDevice->open(IO_WriteOnly))
00132     {
00133         kdError(30502) << "Unable to open output file!" << endl;
00134         return false;
00135     }
00136 
00137     m_streamOut = new QTextStream(m_ioDevice);
00138     if (!m_streamOut)
00139     {
00140         kdError(30502) << "Could not create output stream! Aborting!" << endl;
00141         m_ioDevice->close();
00142         return false;
00143     }
00144 
00145     kdDebug(30502) << "Charset used: " << getCodec()->name() << endl;
00146 
00147     if (!getCodec())
00148     {
00149         kdError(30502) << "Could not create QTextCodec! Aborting" << endl;
00150         return false;
00151     }
00152 
00153     m_streamOut->setCodec(getCodec());
00154 
00155     return true;
00156 }
00157 
00158 bool ASCIIWorker::doCloseFile(void)
00159 {
00160     delete m_streamOut;
00161     m_streamOut=NULL;
00162     if (m_ioDevice)
00163         m_ioDevice->close();
00164     return (m_ioDevice);
00165 }
00166 
00167 bool ASCIIWorker::doOpenDocument(void)
00168 {
00169     // We have nothing to do, but to give our OK to continue
00170     return true;
00171 }
00172 
00173 bool ASCIIWorker::doCloseDocument(void)
00174 {
00175     // Add foot-/endnotes
00176     if (!m_automaticNotes.empty())
00177     {
00178         *m_streamOut << m_eol;
00179         int noteNumber = 1;
00180         for (QStringList::Iterator it = m_automaticNotes.begin(); it != m_automaticNotes.end(); ++it)
00181         {
00182             *m_streamOut << "[" << noteNumber << "] " << *it;
00183             noteNumber++;
00184         }
00185     }
00186 
00187     if (!m_manualNotes.isEmpty())
00188         *m_streamOut << m_eol << m_manualNotes;
00189 
00190     return true;
00191 }
00192 
00193 bool ASCIIWorker::doFullParagraphList(const QValueList<ParaData>& paraList)
00194 {
00195     for (QValueList<ParaData>::ConstIterator it = paraList.begin();
00196          it != paraList.end();
00197          it++)
00198     {
00199         if (!doFullParagraph(*it)) return false;
00200     }
00201 
00202     return true;
00203 }
00204 
00205 bool ASCIIWorker::doFullParagraph(const ParaData& para)
00206 {
00207     return doFullParagraph(para.text, para.layout, para.formattingList);
00208 }
00209 
00210 bool ASCIIWorker::doFullParagraph(const QString& paraText, const LayoutData& layout,
00211     const ValueListFormatData& paraFormatDataList)
00212 {
00213     kdDebug(30502) << "Entering ASCIIWorker::doFullParagraph" << endl;
00214 
00215 #if 0
00216     // As KWord has only one depth of lists, we can process lists very simply.
00217     // --
00218     // Not anymore - Clarence
00219     if ( layout.counter.numbering == CounterData::NUM_LIST )
00220     {
00221         // Are we still in a list of the right type?
00222         if (!m_inList || (layout.counter.style!=m_typeList))
00223         {
00224             // We are not yet part of a list
00225             m_inList=true;
00226             m_counterList=1; // Start numbering
00227             m_typeList=layout.counter.style;
00228         }
00229 
00230         switch (m_typeList)
00231         // TODO: when we would be able to save to UTF-8,
00232         //   use correct symbols
00233         {
00234         case CounterData::STYLE_CUSTOMBULLET: // We cannot keep the custom type/style
00235         default:
00236             {
00237                 m_orderedList=false;
00238                 *m_streamOut << "- ";
00239                 break;
00240             }
00241         case CounterData::STYLE_NONE:
00242             {
00243                 m_orderedList=false;
00244                 break;
00245             }
00246         case CounterData::STYLE_CIRCLEBULLET:
00247             {
00248                 m_orderedList=false;
00249                 *m_streamOut << "o ";
00250                 break;
00251             }
00252         case CounterData::STYLE_SQUAREBULLET:
00253             {
00254                 m_orderedList=false;
00255                 *m_streamOut << "~ "; // Not much a square
00256                 break;
00257             }
00258         case CounterData::STYLE_DISCBULLET:
00259             {
00260                 m_orderedList=false;
00261                 *m_streamOut << "* "; // Not much a disc
00262                 break;
00263             }
00264         case CounterData::STYLE_NUM:
00265         case CounterData::STYLE_CUSTOM:
00266             {
00267                 m_orderedList=true;
00268                 *m_streamOut << QString::number(m_counterList,10);
00269                 break;
00270             }
00271         case CounterData::STYLE_ALPHAB_L:
00272             {
00273                 m_orderedList=true;
00274                 QString strTemp;
00275                 for (int i=m_counterList;i>0;i/=26)
00276                      strTemp=QChar(0x40+i%26)+strTemp; // Lower alpha
00277                 *m_streamOut << strTemp;
00278                 break;
00279         }
00280         case CounterData::STYLE_ALPHAB_U:
00281             {
00282                 m_orderedList=true;
00283                 QString strTemp;
00284                 for (int i=m_counterList;i>0;i/=26)
00285                      strTemp=QChar(0x40+i%26)+strTemp; // Lower alpha
00286                 *m_streamOut << strTemp;
00287                 break;
00288             }
00289         case CounterData::STYLE_ROM_NUM_L:
00290             {
00291                 // For now, we do not support lower-case Roman numbering (TODO)
00292                 m_orderedList=true;
00293                 *m_streamOut << QString::number(m_counterList,10);
00294                 break;
00295             }
00296         case CounterData::STYLE_ROM_NUM_U:
00297             {
00298                 // For now, we do not support upper-case Roman numbering (TODO)
00299                 m_orderedList=true;
00300                 *m_streamOut << QString::number(m_counterList,10);
00301                 break;
00302             }
00303         }
00304         ProcessParagraphData ( paraText, paraFormatDataList);
00305         m_counterList++; // Increment the list counter
00306     }
00307     else
00308     {
00309         m_inList=false; // Close an eventual list
00310         if ( layout.counter.numbering == CounterData::NUM_CHAPTER )
00311         {
00312             if (!layout.counter.depth)
00313             {   // HEAD 1
00314                 *m_streamOut << "###################################" << m_eol;
00315                 *m_streamOut << "# ";
00316                 ProcessParagraphData ( paraText, paraFormatDataList);
00317                 *m_streamOut << "###################################" << m_eol;
00318             }
00319             else if (layout.counter.depth==1)
00320             {   // HEAD 2
00321                 *m_streamOut << "#### ";
00322                 ProcessParagraphData ( paraText, paraFormatDataList);
00323             }
00324             else if (layout.counter.depth==2)
00325             {   // HEAD 3
00326                 *m_streamOut << "## ";
00327                 ProcessParagraphData ( paraText, paraFormatDataList);
00328             }
00329             else if (layout.counter.depth==3)
00330             {   // HEAD 4
00331                 *m_streamOut << "# ";
00332                 ProcessParagraphData ( paraText, paraFormatDataList);
00333             }
00334             else
00335             {
00336                 ProcessParagraphData ( paraText, paraFormatDataList);
00337             }
00338         }
00339         else
00340         {
00341             ProcessParagraphData ( paraText, paraFormatDataList);
00342         }
00343     }
00344 #else
00345     if (!layout.counter.text.isEmpty())
00346         *m_streamOut << layout.counter.text << " ";
00347 
00348     if (!ProcessParagraphData(paraText, paraFormatDataList)) return false;
00349 #endif
00350 
00351     kdDebug(30502) << "Exiting ASCIIWorker::doFullParagraph" << endl;
00352     return true;
00353 }
00354 
00355 
00356 bool ASCIIWorker::ProcessTable(const Table& table)
00357 {
00358     kdDebug(30502) << "processTable CALLED!" << endl;
00359 
00360     // just dump the table out (no layout for now)
00361     for (QValueList<TableCell>::ConstIterator it = table.cellList.begin();
00362          it != table.cellList.end();
00363          it++)
00364     {
00365         if (!doFullParagraphList(*(*it).paraList)) return false;
00366     }
00367 
00368     return true;
00369 }
00370 
00371 // ProcessParagraphData () mangles the pure text through the
00372 // formatting information stored in the FormatData list and prints it
00373 // out to the export file.
00374 bool ASCIIWorker::ProcessParagraphData(const QString& paraText,
00375     const ValueListFormatData& paraFormatDataList)
00376 {
00377     bool lastSegmentWasText = true;
00378 
00379     if (!paraText.isEmpty())
00380     {
00381         ValueListFormatData::ConstIterator  paraFormatDataIt;
00382 
00383         for (paraFormatDataIt = paraFormatDataList.begin ();
00384              paraFormatDataIt != paraFormatDataList.end ();
00385              paraFormatDataIt++)
00386         {
00387             lastSegmentWasText = true;
00388 
00389             switch ((*paraFormatDataIt).id)
00390             {
00391                 case 1: // Normal text
00392                 {
00393                     QString strText(paraText.mid((*paraFormatDataIt).pos,(*paraFormatDataIt).len));
00394                     strText = strText.replace(QChar(10), m_eol, true);
00395                     *m_streamOut << strText;
00396                     break;
00397                 }
00398                 case 4: // Variable
00399                 {
00400                     if (11==(*paraFormatDataIt).variable.m_type)
00401                     {
00402                         // Footnote
00403                         QString value = (*paraFormatDataIt).variable.getFootnoteValue();
00404                         bool automatic = (*paraFormatDataIt).variable.getFootnoteAuto();
00405                         QValueList<ParaData> *paraList = (*paraFormatDataIt).variable.getFootnotePara();
00406                         if (paraList)
00407                         {
00408                             QString notestr;
00409                             QValueList<ParaData>::ConstIterator it;
00410                             QValueList<ParaData>::ConstIterator end(paraList->end());
00411                             for (it=paraList->begin();it!=end;++it)
00412                                 notestr += (*it).text.stripWhiteSpace().replace(QChar(10), m_eol, true) + m_eol;
00413 
00414                             *m_streamOut << "[";
00415                             if (automatic) {
00416                                 // Automatic footnote
00417                                 *m_streamOut << m_automaticNotes.count() + 1;
00418                                 m_automaticNotes.append(notestr);
00419                             }
00420                             else
00421                             {
00422                                 // Manual footnote
00423                                 *m_streamOut << value;
00424                                 m_manualNotes += "[" + value + "] " + notestr;
00425                             }
00426                             *m_streamOut << "]";
00427                         }
00428                     }
00429                     else
00430                     {
00431                         // Generic variable
00432                         *m_streamOut << (*paraFormatDataIt).variable.m_text;
00433                     }
00434                     break;
00435                 }
00436                 case 6: // Frame Anchor
00437                 {
00438                     if ((*paraFormatDataIt).frameAnchor.type == 6) // Table
00439                     {
00440                         if ((*paraFormatDataIt).pos)
00441                             *m_streamOut << m_eol;
00442 
00443                         if (!ProcessTable((*paraFormatDataIt).frameAnchor.table))
00444                             return false;
00445                     }
00446                     else
00447                     {
00448                         kdWarning(30502) << "Unsupported frame anchor type: "
00449                             << (*paraFormatDataIt).frameAnchor.type << endl;
00450                     }
00451 
00452                     lastSegmentWasText = false;
00453                     break;
00454                 }
00455                 default:
00456                 {
00457                     kdWarning(30502) << "Not supported paragraph type: "
00458                         << (*paraFormatDataIt).id << endl;
00459                     break;
00460                 }
00461             }
00462         }
00463     }
00464 
00465     if (lastSegmentWasText)
00466         *m_streamOut << m_eol; // Write end of line
00467 
00468     return true;
00469 }
00470 
00471 
00472 ASCIIExport::ASCIIExport(KoFilter*, const char*, const QStringList&)
00473            : KoFilter()
00474 {
00475 }
00476 
00477 KoFilter::ConversionStatus ASCIIExport::convert(const QCString& from, const QCString& to)
00478 {
00479     if (to != "text/plain" || from != "application/x-kword")
00480     {
00481         return KoFilter::NotImplemented;
00482     }
00483     AsciiExportDialog* dialog = 0;
00484     if (!m_chain->manager()->getBatchMode())
00485     {
00486       dialog = new AsciiExportDialog();
00487       if (!dialog)
00488       {
00489     kdError(30502) << "Dialog has not been created! Aborting!" << endl;
00490     return KoFilter::StupidError;
00491       }
00492       
00493       if (!dialog->exec())
00494       {
00495     kdError(30502) << "Dialog was aborted! Aborting filter!" << endl;
00496     return KoFilter::UserCancelled;
00497       }
00498     }
00499     ASCIIWorker* worker = new ASCIIWorker();
00500 
00501     if (!worker)
00502     {
00503         kdError(30502) << "Cannot create Worker! Aborting!" << endl;
00504         delete dialog;
00505         return KoFilter::StupidError;
00506     }
00507     QTextCodec* codec;
00508     if (dialog)
00509         codec = dialog->getCodec();
00510     else
00511         codec = QTextCodec::codecForName("UTF-8");
00512     
00513     if ( !codec )
00514     {
00515         kdError(30502) << "No codec!" << endl;
00516         delete dialog;
00517         return KoFilter::StupidError;
00518     }
00519 
00520     worker->setCodec( codec );
00521     if (dialog)
00522         worker->setEndOfLine(dialog->getEndOfLine());
00523     else
00524         worker->setEndOfLine("\n");
00525 
00526     delete dialog;
00527 
00528     KWEFKWordLeader* leader = new KWEFKWordLeader(worker);
00529 
00530     if (!leader)
00531     {
00532         kdError(30502) << "Cannot create Worker! Aborting!" << endl;
00533         delete worker;
00534         return KoFilter::StupidError;
00535     }
00536 
00537     KoFilter::ConversionStatus result = leader->convert(m_chain,from,to);
00538 
00539     delete leader;
00540     delete worker;
00541 
00542     return result;
00543 }
00544 
00545 #include <asciiexport.moc>
KDE Home | KDE Accessibility Home | Description of Access Keys