filters

asciiexport.cpp
1/* This file is part of the KDE project
2 Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
3 Copyright (c) 2000 ID-PRO Deutschland GmbH. All rights reserved.
4 Contact: Wolf-Michael Bolle <Bolle@ID-PRO.de>
5 Copyright (C) 2001, 2002, 2004 Nicolas GOUTTE <goutte@kde.org>
6 Copyright (C) 2003 Clarence Dang <dang@kde.org>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24
25#include <limits.h>
26
27#include <tqcstring.h>
28#include <tqfile.h>
29#include <tqiodevice.h>
30#include <tqstring.h>
31#include <tqtextcodec.h>
32#include <tqtextstream.h>
33
34#include <kdebug.h>
35#include <kgenericfactory.h>
36
37#include <KoFilterChain.h>
38#include <KoFilterManager.h>
39#include <KoStore.h>
40
41#include <KWEFStructures.h>
42#include <KWEFBaseWorker.h>
43#include <KWEFKWordLeader.h>
44
45#include <ExportDialog.h>
46#include <asciiexport.h>
47
48
49class ASCIIExportFactory : KGenericFactory<ASCIIExport, KoFilter>
50{
51public:
52 ASCIIExportFactory() : KGenericFactory<ASCIIExport, KoFilter>("kwordasciiexport")
53 {
54 }
55
56protected:
57 virtual void setupTranslations(void)
58 {
59 TDEGlobal::locale()->insertCatalogue("kofficefilters");
60 }
61};
62
63K_EXPORT_COMPONENT_FACTORY(libasciiexport, ASCIIExportFactory())
64
65
66class ASCIIWorker : public KWEFBaseWorker
67{
68public:
69 ASCIIWorker() : m_ioDevice(NULL), m_streamOut(NULL), m_eol("\n")/*,
70 m_inList(false)*/
71 {
72 }
73
74 virtual ~ASCIIWorker()
75 {
76 delete m_streamOut; delete m_ioDevice;
77 }
78
79public:
80 virtual bool doOpenFile(const TQString& filenameOut, const TQString& to);
81 virtual bool doCloseFile(void); // Close file in normal conditions
82
83 virtual bool doOpenDocument(void);
84 virtual bool doCloseDocument(void);
85
86 virtual bool doFullParagraphList(const TQValueList<ParaData>& paraList);
87 virtual bool doFullParagraph(const ParaData& para);
88 virtual bool doFullParagraph(const TQString& paraText,
89 const LayoutData& layout,
90 const ValueListFormatData& paraFormatDataList);
91
92public:
93 TQString getEndOfLine(void) const { return m_eol; }
94 void setEndOfLine(const TQString& str) { m_eol = str; }
95
96 TQTextCodec* getCodec(void) const { return m_codec; }
97 void setCodec(TQTextCodec* codec) { m_codec = codec; }
98
99private:
100 virtual bool ProcessTable(const Table& table);
101 virtual bool ProcessParagraphData (const TQString& paraText,
102 const ValueListFormatData& paraFormatDataList);
103
104private:
105 TQIODevice* m_ioDevice;
106 TQTextStream* m_streamOut;
107
108 TQTextCodec* m_codec; // TQTextCodec in which the file will be written
109 TQString m_eol; // End of line character(s)
110 TQStringList m_automaticNotes; // Automatic foot-/endnotes
111 TQString m_manualNotes; // Manual foot-/endnotes
112
113#if 0
114 CounterData::Style m_typeList; // What is the style of the current list (undefined, if we are not in a list)
115 bool m_inList; // Are we currently in a list?
116 bool m_orderedList; // Is the current list ordered or not (undefined, if we are not in a list)
117 int m_counterList; // Counter for te lists
118#endif
119};
120
121bool ASCIIWorker::doOpenFile(const TQString& filenameOut, const TQString& /*to*/)
122{
123 m_ioDevice = new TQFile(filenameOut);
124
125 if (!m_ioDevice)
126 {
127 kdError(30502) << "No output file! Aborting!" << endl;
128 return false;
129 }
130
131 if (!m_ioDevice->open(IO_WriteOnly))
132 {
133 kdError(30502) << "Unable to open output file!" << endl;
134 return false;
135 }
136
137 m_streamOut = new TQTextStream(m_ioDevice);
138 if (!m_streamOut)
139 {
140 kdError(30502) << "Could not create output stream! Aborting!" << endl;
141 m_ioDevice->close();
142 return false;
143 }
144
145 kdDebug(30502) << "Charset used: " << getCodec()->name() << endl;
146
147 if (!getCodec())
148 {
149 kdError(30502) << "Could not create TQTextCodec! Aborting" << endl;
150 return false;
151 }
152
153 m_streamOut->setCodec(getCodec());
154
155 return true;
156}
157
158bool ASCIIWorker::doCloseFile(void)
159{
160 delete m_streamOut;
161 m_streamOut=NULL;
162 if (m_ioDevice)
163 m_ioDevice->close();
164 return (m_ioDevice);
165}
166
167bool ASCIIWorker::doOpenDocument(void)
168{
169 // We have nothing to do, but to give our OK to continue
170 return true;
171}
172
173bool ASCIIWorker::doCloseDocument(void)
174{
175 // Add foot-/endnotes
176 if (!m_automaticNotes.empty())
177 {
178 *m_streamOut << m_eol;
179 int noteNumber = 1;
180 for (TQStringList::Iterator it = m_automaticNotes.begin(); it != m_automaticNotes.end(); ++it)
181 {
182 *m_streamOut << "[" << noteNumber << "] " << *it;
183 noteNumber++;
184 }
185 }
186
187 if (!m_manualNotes.isEmpty())
188 *m_streamOut << m_eol << m_manualNotes;
189
190 return true;
191}
192
193bool ASCIIWorker::doFullParagraphList(const TQValueList<ParaData>& paraList)
194{
195 for (TQValueList<ParaData>::ConstIterator it = paraList.begin();
196 it != paraList.end();
197 it++)
198 {
199 if (!doFullParagraph(*it)) return false;
200 }
201
202 return true;
203}
204
205bool ASCIIWorker::doFullParagraph(const ParaData& para)
206{
207 return doFullParagraph(para.text, para.layout, para.formattingList);
208}
209
210bool ASCIIWorker::doFullParagraph(const TQString& paraText, const LayoutData& layout,
211 const ValueListFormatData& paraFormatDataList)
212{
213 kdDebug(30502) << "Entering ASCIIWorker::doFullParagraph" << endl;
214
215#if 0
216 // As KWord has only one depth of lists, we can process lists very simply.
217 // --
218 // Not anymore - Clarence
219 if ( layout.counter.numbering == CounterData::NUM_LIST )
220 {
221 // Are we still in a list of the right type?
222 if (!m_inList || (layout.counter.style!=m_typeList))
223 {
224 // We are not yet part of a list
225 m_inList=true;
226 m_counterList=1; // Start numbering
227 m_typeList=layout.counter.style;
228 }
229
230 switch (m_typeList)
231 // TODO: when we would be able to save to UTF-8,
232 // use correct symbols
233 {
234 case CounterData::STYLE_CUSTOMBULLET: // We cannot keep the custom type/style
235 default:
236 {
237 m_orderedList=false;
238 *m_streamOut << "- ";
239 break;
240 }
241 case CounterData::STYLE_NONE:
242 {
243 m_orderedList=false;
244 break;
245 }
246 case CounterData::STYLE_CIRCLEBULLET:
247 {
248 m_orderedList=false;
249 *m_streamOut << "o ";
250 break;
251 }
252 case CounterData::STYLE_SQUAREBULLET:
253 {
254 m_orderedList=false;
255 *m_streamOut << "~ "; // Not much a square
256 break;
257 }
258 case CounterData::STYLE_DISCBULLET:
259 {
260 m_orderedList=false;
261 *m_streamOut << "* "; // Not much a disc
262 break;
263 }
264 case CounterData::STYLE_NUM:
265 case CounterData::STYLE_CUSTOM:
266 {
267 m_orderedList=true;
268 *m_streamOut << TQString::number(m_counterList,10);
269 break;
270 }
271 case CounterData::STYLE_ALPHAB_L:
272 {
273 m_orderedList=true;
274 TQString strTemp;
275 for (int i=m_counterList;i>0;i/=26)
276 strTemp=TQChar(0x40+i%26)+strTemp; // Lower alpha
277 *m_streamOut << strTemp;
278 break;
279 }
280 case CounterData::STYLE_ALPHAB_U:
281 {
282 m_orderedList=true;
283 TQString strTemp;
284 for (int i=m_counterList;i>0;i/=26)
285 strTemp=TQChar(0x40+i%26)+strTemp; // Lower alpha
286 *m_streamOut << strTemp;
287 break;
288 }
289 case CounterData::STYLE_ROM_NUM_L:
290 {
291 // For now, we do not support lower-case Roman numbering (TODO)
292 m_orderedList=true;
293 *m_streamOut << TQString::number(m_counterList,10);
294 break;
295 }
296 case CounterData::STYLE_ROM_NUM_U:
297 {
298 // For now, we do not support upper-case Roman numbering (TODO)
299 m_orderedList=true;
300 *m_streamOut << TQString::number(m_counterList,10);
301 break;
302 }
303 }
304 ProcessParagraphData ( paraText, paraFormatDataList);
305 m_counterList++; // Increment the list counter
306 }
307 else
308 {
309 m_inList=false; // Close an eventual list
310 if ( layout.counter.numbering == CounterData::NUM_CHAPTER )
311 {
312 if (!layout.counter.depth)
313 { // HEAD 1
314 *m_streamOut << "###################################" << m_eol;
315 *m_streamOut << "# ";
316 ProcessParagraphData ( paraText, paraFormatDataList);
317 *m_streamOut << "###################################" << m_eol;
318 }
319 else if (layout.counter.depth==1)
320 { // HEAD 2
321 *m_streamOut << "#### ";
322 ProcessParagraphData ( paraText, paraFormatDataList);
323 }
324 else if (layout.counter.depth==2)
325 { // HEAD 3
326 *m_streamOut << "## ";
327 ProcessParagraphData ( paraText, paraFormatDataList);
328 }
329 else if (layout.counter.depth==3)
330 { // HEAD 4
331 *m_streamOut << "# ";
332 ProcessParagraphData ( paraText, paraFormatDataList);
333 }
334 else
335 {
336 ProcessParagraphData ( paraText, paraFormatDataList);
337 }
338 }
339 else
340 {
341 ProcessParagraphData ( paraText, paraFormatDataList);
342 }
343 }
344#else
345 if (!layout.counter.text.isEmpty())
346 *m_streamOut << layout.counter.text << " ";
347
348 if (!ProcessParagraphData(paraText, paraFormatDataList)) return false;
349#endif
350
351 kdDebug(30502) << "Exiting ASCIIWorker::doFullParagraph" << endl;
352 return true;
353}
354
355
356bool ASCIIWorker::ProcessTable(const Table& table)
357{
358 kdDebug(30502) << "processTable CALLED!" << endl;
359
360 // just dump the table out (no layout for now)
361 for (TQValueList<TableCell>::ConstIterator it = table.cellList.begin();
362 it != table.cellList.end();
363 it++)
364 {
365 if (!doFullParagraphList(*(*it).paraList)) return false;
366 }
367
368 return true;
369}
370
371// ProcessParagraphData () mangles the pure text through the
372// formatting information stored in the FormatData list and prints it
373// out to the export file.
374bool ASCIIWorker::ProcessParagraphData(const TQString& paraText,
375 const ValueListFormatData& paraFormatDataList)
376{
377 bool lastSegmentWasText = true;
378
379 if (!paraText.isEmpty())
380 {
381 ValueListFormatData::ConstIterator paraFormatDataIt;
382
383 for (paraFormatDataIt = paraFormatDataList.begin ();
384 paraFormatDataIt != paraFormatDataList.end ();
385 paraFormatDataIt++)
386 {
387 lastSegmentWasText = true;
388
389 switch ((*paraFormatDataIt).id)
390 {
391 case 1: // Normal text
392 {
393 TQString strText(paraText.mid((*paraFormatDataIt).pos,(*paraFormatDataIt).len));
394 strText = strText.replace(TQChar(10), m_eol, true);
395 *m_streamOut << strText;
396 break;
397 }
398 case 4: // Variable
399 {
400 if (11==(*paraFormatDataIt).variable.m_type)
401 {
402 // Footnote
403 TQString value = (*paraFormatDataIt).variable.getFootnoteValue();
404 bool automatic = (*paraFormatDataIt).variable.getFootnoteAuto();
405 TQValueList<ParaData> *paraList = (*paraFormatDataIt).variable.getFootnotePara();
406 if (paraList)
407 {
408 TQString notestr;
409 TQValueList<ParaData>::ConstIterator it;
410 TQValueList<ParaData>::ConstIterator end(paraList->end());
411 for (it=paraList->begin();it!=end;++it)
412 notestr += (*it).text.stripWhiteSpace().replace(TQChar(10), m_eol, true) + m_eol;
413
414 *m_streamOut << "[";
415 if (automatic) {
416 // Automatic footnote
417 *m_streamOut << m_automaticNotes.count() + 1;
418 m_automaticNotes.append(notestr);
419 }
420 else
421 {
422 // Manual footnote
423 *m_streamOut << value;
424 m_manualNotes += "[" + value + "] " + notestr;
425 }
426 *m_streamOut << "]";
427 }
428 }
429 else
430 {
431 // Generic variable
432 *m_streamOut << (*paraFormatDataIt).variable.m_text;
433 }
434 break;
435 }
436 case 6: // Frame Anchor
437 {
438 if ((*paraFormatDataIt).frameAnchor.type == 6) // Table
439 {
440 if ((*paraFormatDataIt).pos)
441 *m_streamOut << m_eol;
442
443 if (!ProcessTable((*paraFormatDataIt).frameAnchor.table))
444 return false;
445 }
446 else
447 {
448 kdWarning(30502) << "Unsupported frame anchor type: "
449 << (*paraFormatDataIt).frameAnchor.type << endl;
450 }
451
452 lastSegmentWasText = false;
453 break;
454 }
455 default:
456 {
457 kdWarning(30502) << "Not supported paragraph type: "
458 << (*paraFormatDataIt).id << endl;
459 break;
460 }
461 }
462 }
463 }
464
465 if (lastSegmentWasText)
466 *m_streamOut << m_eol; // Write end of line
467
468 return true;
469}
470
471
472ASCIIExport::ASCIIExport(KoFilter*, const char*, const TQStringList&)
473 : KoFilter()
474{
475}
476
477KoFilter::ConversionStatus ASCIIExport::convert(const TQCString& from, const TQCString& to)
478{
479 if (to != "text/plain" || from != "application/x-kword")
480 {
481 return KoFilter::NotImplemented;
482 }
483 AsciiExportDialog* dialog = 0;
484 if (!m_chain->manager()->getBatchMode())
485 {
486 dialog = new AsciiExportDialog();
487 if (!dialog)
488 {
489 kdError(30502) << "Dialog has not been created! Aborting!" << endl;
490 return KoFilter::StupidError;
491 }
492
493 if (!dialog->exec())
494 {
495 kdError(30502) << "Dialog was aborted! Aborting filter!" << endl;
496 return KoFilter::UserCancelled;
497 }
498 }
499 ASCIIWorker* worker = new ASCIIWorker();
500
501 if (!worker)
502 {
503 kdError(30502) << "Cannot create Worker! Aborting!" << endl;
504 delete dialog;
505 return KoFilter::StupidError;
506 }
507 TQTextCodec* codec;
508 if (dialog)
509 codec = dialog->getCodec();
510 else
511 codec = TQTextCodec::codecForName("UTF-8");
512
513 if ( !codec )
514 {
515 kdError(30502) << "No codec!" << endl;
516 delete dialog;
517 return KoFilter::StupidError;
518 }
519
520 worker->setCodec( codec );
521 if (dialog)
522 worker->setEndOfLine(dialog->getEndOfLine());
523 else
524 worker->setEndOfLine("\n");
525
526 delete dialog;
527
528 KWEFKWordLeader* leader = new KWEFKWordLeader(worker);
529
530 if (!leader)
531 {
532 kdError(30502) << "Cannot create Worker! Aborting!" << endl;
533 delete worker;
534 return KoFilter::StupidError;
535 }
536
537 KoFilter::ConversionStatus result = leader->convert(m_chain,from,to);
538
539 delete leader;
540 delete worker;
541
542 return result;
543}
544
545#include <asciiexport.moc>
TQString text
text at the time of saving (no formatting info though)
@ NUM_LIST
Numbered as a list item.
@ NUM_CHAPTER
Numbered as a heading.
Base worker of the libexport system.
Paragraph layout.
This class hold a table.