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 
00111 #if 0
00112     CounterData::Style m_typeList; // What is the style of the current list (undefined, if we are not in a list)
00113     bool m_inList; // Are we currently in a list?
00114     bool m_orderedList; // Is the current list ordered or not (undefined, if we are not in a list)
00115     int  m_counterList; // Counter for te lists
00116 #endif
00117 };
00118 
00119 bool ASCIIWorker::doOpenFile(const QString& filenameOut, const QString& /*to*/)
00120 {
00121     m_ioDevice = new QFile(filenameOut);
00122 
00123     if (!m_ioDevice)
00124     {
00125         kdError(30502) << "No output file! Aborting!" << endl;
00126         return false;
00127     }
00128 
00129     if (!m_ioDevice->open(IO_WriteOnly))
00130     {
00131         kdError(30502) << "Unable to open output file!" << endl;
00132         return false;
00133     }
00134 
00135     m_streamOut = new QTextStream(m_ioDevice);
00136     if (!m_streamOut)
00137     {
00138         kdError(30502) << "Could not create output stream! Aborting!" << endl;
00139         m_ioDevice->close();
00140         return false;
00141     }
00142 
00143     kdDebug(30502) << "Charset used: " << getCodec()->name() << endl;
00144 
00145     if (!getCodec())
00146     {
00147         kdError(30502) << "Could not create QTextCodec! Aborting" << endl;
00148         return false;
00149     }
00150 
00151     m_streamOut->setCodec(getCodec());
00152 
00153     return true;
00154 }
00155 
00156 bool ASCIIWorker::doCloseFile(void)
00157 {
00158     delete m_streamOut;
00159     m_streamOut=NULL;
00160     if (m_ioDevice)
00161         m_ioDevice->close();
00162     return (m_ioDevice);
00163 }
00164 
00165 bool ASCIIWorker::doOpenDocument(void)
00166 {
00167     // We have nothing to do, but to give our OK to continue
00168     return true;
00169 }
00170 
00171 bool ASCIIWorker::doCloseDocument(void)
00172 {
00173     // We have nothing to do, but to give our OK to continue
00174     return true;
00175 }
00176 
00177 bool ASCIIWorker::doFullParagraphList(const QValueList<ParaData>& paraList)
00178 {
00179     for (QValueList<ParaData>::ConstIterator it = paraList.begin();
00180          it != paraList.end();
00181          it++)
00182     {
00183         if (!doFullParagraph(*it)) return false;
00184     }
00185 
00186     return true;
00187 }
00188 
00189 bool ASCIIWorker::doFullParagraph(const ParaData& para)
00190 {
00191     return doFullParagraph(para.text, para.layout, para.formattingList);
00192 }
00193 
00194 bool ASCIIWorker::doFullParagraph(const QString& paraText, const LayoutData& layout,
00195     const ValueListFormatData& paraFormatDataList)
00196 {
00197     kdDebug(30502) << "Entering ASCIIWorker::doFullParagraph" << endl;
00198 
00199 #if 0
00200     // As KWord has only one depth of lists, we can process lists very simply.
00201     // --
00202     // Not anymore - Clarence
00203     if ( layout.counter.numbering == CounterData::NUM_LIST )
00204     {
00205         // Are we still in a list of the right type?
00206         if (!m_inList || (layout.counter.style!=m_typeList))
00207         {
00208             // We are not yet part of a list
00209             m_inList=true;
00210             m_counterList=1; // Start numbering
00211             m_typeList=layout.counter.style;
00212         }
00213 
00214         switch (m_typeList)
00215         // TODO: when we would be able to save to UTF-8,
00216         //   use correct symbols
00217         {
00218         case CounterData::STYLE_CUSTOMBULLET: // We cannot keep the custom type/style
00219         default:
00220             {
00221                 m_orderedList=false;
00222                 *m_streamOut << "- ";
00223                 break;
00224             }
00225         case CounterData::STYLE_NONE:
00226             {
00227                 m_orderedList=false;
00228                 break;
00229             }
00230         case CounterData::STYLE_CIRCLEBULLET:
00231             {
00232                 m_orderedList=false;
00233                 *m_streamOut << "o ";
00234                 break;
00235             }
00236         case CounterData::STYLE_SQUAREBULLET:
00237             {
00238                 m_orderedList=false;
00239                 *m_streamOut << "~ "; // Not much a square
00240                 break;
00241             }
00242         case CounterData::STYLE_DISCBULLET:
00243             {
00244                 m_orderedList=false;
00245                 *m_streamOut << "* "; // Not much a disc
00246                 break;
00247             }
00248         case CounterData::STYLE_NUM:
00249         case CounterData::STYLE_CUSTOM:
00250             {
00251                 m_orderedList=true;
00252                 *m_streamOut << QString::number(m_counterList,10);
00253                 break;
00254             }
00255         case CounterData::STYLE_ALPHAB_L:
00256             {
00257                 m_orderedList=true;
00258                 QString strTemp;
00259                 for (int i=m_counterList;i>0;i/=26)
00260                      strTemp=QChar(0x40+i%26)+strTemp; // Lower alpha
00261                 *m_streamOut << strTemp;
00262                 break;
00263         }
00264         case CounterData::STYLE_ALPHAB_U:
00265             {
00266                 m_orderedList=true;
00267                 QString strTemp;
00268                 for (int i=m_counterList;i>0;i/=26)
00269                      strTemp=QChar(0x40+i%26)+strTemp; // Lower alpha
00270                 *m_streamOut << strTemp;
00271                 break;
00272             }
00273         case CounterData::STYLE_ROM_NUM_L:
00274             {
00275                 // For now, we do not support lower-case Roman numbering (TODO)
00276                 m_orderedList=true;
00277                 *m_streamOut << QString::number(m_counterList,10);
00278                 break;
00279             }
00280         case CounterData::STYLE_ROM_NUM_U:
00281             {
00282                 // For now, we do not support upper-case Roman numbering (TODO)
00283                 m_orderedList=true;
00284                 *m_streamOut << QString::number(m_counterList,10);
00285                 break;
00286             }
00287         }
00288         ProcessParagraphData ( paraText, paraFormatDataList);
00289         m_counterList++; // Increment the list counter
00290     }
00291     else
00292     {
00293         m_inList=false; // Close an eventual list
00294         if ( layout.counter.numbering == CounterData::NUM_CHAPTER )
00295         {
00296             if (!layout.counter.depth)
00297             {   // HEAD 1
00298                 *m_streamOut << "###################################" << m_eol;
00299                 *m_streamOut << "# ";
00300                 ProcessParagraphData ( paraText, paraFormatDataList);
00301                 *m_streamOut << "###################################" << m_eol;
00302             }
00303             else if (layout.counter.depth==1)
00304             {   // HEAD 2
00305                 *m_streamOut << "#### ";
00306                 ProcessParagraphData ( paraText, paraFormatDataList);
00307             }
00308             else if (layout.counter.depth==2)
00309             {   // HEAD 3
00310                 *m_streamOut << "## ";
00311                 ProcessParagraphData ( paraText, paraFormatDataList);
00312             }
00313             else if (layout.counter.depth==3)
00314             {   // HEAD 4
00315                 *m_streamOut << "# ";
00316                 ProcessParagraphData ( paraText, paraFormatDataList);
00317             }
00318             else
00319             {
00320                 ProcessParagraphData ( paraText, paraFormatDataList);
00321             }
00322         }
00323         else
00324         {
00325             ProcessParagraphData ( paraText, paraFormatDataList);
00326         }
00327     }
00328 #else
00329     if (!layout.counter.text.isEmpty())
00330         *m_streamOut << layout.counter.text << " ";
00331 
00332     if (!ProcessParagraphData(paraText, paraFormatDataList)) return false;
00333 #endif
00334 
00335     kdDebug(30502) << "Exiting ASCIIWorker::doFullParagraph" << endl;
00336     return true;
00337 }
00338 
00339 
00340 bool ASCIIWorker::ProcessTable(const Table& table)
00341 {
00342     kdDebug(30502) << "processTable CALLED!" << endl;
00343 
00344     // just dump the table out (no layout for now)
00345     for (QValueList<TableCell>::ConstIterator it = table.cellList.begin();
00346          it != table.cellList.end();
00347          it++)
00348     {
00349         if (!doFullParagraphList(*(*it).paraList)) return false;
00350     }
00351 
00352     return true;
00353 }
00354 
00355 // ProcessParagraphData () mangles the pure text through the
00356 // formatting information stored in the FormatData list and prints it
00357 // out to the export file.
00358 bool ASCIIWorker::ProcessParagraphData(const QString& paraText,
00359     const ValueListFormatData& paraFormatDataList)
00360 {
00361     bool lastSegmentWasText = true;
00362 
00363     if (!paraText.isEmpty())
00364     {
00365         ValueListFormatData::ConstIterator  paraFormatDataIt;
00366 
00367         for (paraFormatDataIt = paraFormatDataList.begin ();
00368              paraFormatDataIt != paraFormatDataList.end ();
00369              paraFormatDataIt++)
00370         {
00371             lastSegmentWasText = true;
00372 
00373             switch ((*paraFormatDataIt).id)
00374             {
00375                 case 1: // Normal text
00376                 {
00377                     QString strText(paraText.mid((*paraFormatDataIt).pos,(*paraFormatDataIt).len));
00378 
00379                     // Replace line feeds by line ends
00380                     int pos;
00381                     int oldpos=0;
00382                     while ((pos=strText.find(QChar(10),oldpos))>-1)
00383                     {
00384                         strText.replace(pos,1,m_eol);
00385                         oldpos=pos+1;
00386                     }
00387 
00388                     *m_streamOut << strText;
00389                     break;
00390                 }
00391                 case 4: // Variable
00392                 {
00393                     // Just write the result of the variable
00394                     *m_streamOut << (*paraFormatDataIt).variable.m_text;
00395                     break;
00396                 }
00397                 case 6: // Frame Anchor
00398                 {
00399                     if ((*paraFormatDataIt).frameAnchor.type == 6) // Table
00400                     {
00401                         if ((*paraFormatDataIt).pos)
00402                             *m_streamOut << m_eol;
00403 
00404                         if (!ProcessTable((*paraFormatDataIt).frameAnchor.table))
00405                             return false;
00406                     }
00407                     else
00408                     {
00409                         kdWarning(30502) << "Unsupported frame anchor type: "
00410                             << (*paraFormatDataIt).frameAnchor.type << endl;
00411                     }
00412 
00413                     lastSegmentWasText = false;
00414                     break;
00415                 }
00416                 default:
00417                 {
00418                     kdWarning(30502) << "Not supported paragraph type: "
00419                         << (*paraFormatDataIt).id << endl;
00420                     break;
00421                 }
00422             }
00423         }
00424     }
00425 
00426     if (lastSegmentWasText)
00427         *m_streamOut << m_eol; // Write end of line
00428 
00429     return true;
00430 }
00431 
00432 
00433 ASCIIExport::ASCIIExport(KoFilter*, const char*, const QStringList&)
00434            : KoFilter()
00435 {
00436 }
00437 
00438 KoFilter::ConversionStatus ASCIIExport::convert(const QCString& from, const QCString& to)
00439 {
00440     if (to != "text/plain" || from != "application/x-kword")
00441     {
00442         return KoFilter::NotImplemented;
00443     }
00444     AsciiExportDialog* dialog = 0;
00445     if (!m_chain->manager()->getBatchMode())
00446     {
00447       dialog = new AsciiExportDialog();
00448       if (!dialog)
00449       {
00450     kdError(30502) << "Dialog has not been created! Aborting!" << endl;
00451     return KoFilter::StupidError;
00452       }
00453       
00454       if (!dialog->exec())
00455       {
00456     kdError(30502) << "Dialog was aborted! Aborting filter!" << endl;
00457     return KoFilter::UserCancelled;
00458       }
00459     }
00460     ASCIIWorker* worker = new ASCIIWorker();
00461 
00462     if (!worker)
00463     {
00464         kdError(30502) << "Cannot create Worker! Aborting!" << endl;
00465         delete dialog;
00466         return KoFilter::StupidError;
00467     }
00468     QTextCodec* codec;
00469     if (dialog)
00470         codec = dialog->getCodec();
00471     else
00472         codec = QTextCodec::codecForName("UTF-8");
00473     
00474     if ( !codec )
00475     {
00476         kdError(30502) << "No codec!" << endl;
00477         delete dialog;
00478         return KoFilter::StupidError;
00479     }
00480 
00481     worker->setCodec( codec );
00482     if (dialog)
00483         worker->setEndOfLine(dialog->getEndOfLine());
00484     else
00485         worker->setEndOfLine("\n");
00486 
00487     delete dialog;
00488 
00489     KWEFKWordLeader* leader = new KWEFKWordLeader(worker);
00490 
00491     if (!leader)
00492     {
00493         kdError(30502) << "Cannot create Worker! Aborting!" << endl;
00494         delete worker;
00495         return KoFilter::StupidError;
00496     }
00497 
00498     KoFilter::ConversionStatus result = leader->convert(m_chain,from,to);
00499 
00500     delete leader;
00501     delete worker;
00502 
00503     return result;
00504 }
00505 
00506 #include <asciiexport.moc>
KDE Home | KDE Accessibility Home | Description of Access Keys