~ubuntu-branches/ubuntu/breezy/koffice/breezy

« back to all changes in this revision

Viewing changes to filters/kword/mswrite/mswriteimport.cc

  • Committer: Bazaar Package Importer
  • Author(s): Ben Burton
  • Date: 2004-05-09 11:33:00 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040509113300-vfrdadqsvjfuhn3b
Tags: 1:1.3.1-1
* New upstream bugfix release.
* Built against newer imagemagick (closes: #246623).
* Made koffice-libs/kformula recommend/depend on latex-xft-fonts, which
  provides mathematical fonts that the formula editor can use.  Also
  patched the kformula part to make these fonts the default.
* Changed kword menu hint from "WordProcessors" to "Word processors"
  (closes: #246209).
* Spellchecker configuration is now fixed (closes: #221256, #227568).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
   Copyright (C) 2001-2003 Clarence Dang <dang@kde.org>
 
3
 
 
4
   This library is free software; you can redistribute it and/or
 
5
   modify it under the terms of the GNU Library General Public
 
6
   License Version 2 as published by the Free Software Foundation.
 
7
 
 
8
   This library is distributed in the hope that it will be useful,
 
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
   Library General Public License Version 2 for more details.
 
12
 
 
13
   You should have received a copy of the GNU Library General Public License
 
14
   Version 2 along with this library; see the file COPYING.LIB.  If not,
 
15
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
16
   Boston, MA 02111-1307, USA.
 
17
*/
 
18
 
 
19
#ifndef NDEBUG
 
20
        //#define DEBUG_XML_OUTPUT
 
21
#endif
 
22
 
 
23
#include <stdio.h>
 
24
#include <string.h>
 
25
#include <stdarg.h>
 
26
 
 
27
#include <qfile.h>
 
28
#include <qobject.h>
 
29
#include <qstring.h>
 
30
#include <qtextcodec.h>
 
31
#include <qtextstream.h>
 
32
 
 
33
#include <kdebug.h>
 
34
#include <kgenericfactory.h>
 
35
 
 
36
#include <koFilterChain.h>
 
37
#include <koStore.h>
 
38
 
 
39
#include "list.h"
 
40
#include "libmswrite.h"
 
41
 
 
42
#include "ImportDialog.h"
 
43
#include "mswriteimport.h"
 
44
 
 
45
 
 
46
class MSWriteImportFactory : KGenericFactory <MSWriteImport, KoFilter>
 
47
{
 
48
public:
 
49
        MSWriteImportFactory () : KGenericFactory <MSWriteImport, KoFilter> ("kwordmswriteimport")
 
50
        {
 
51
        }
 
52
 
 
53
protected:
 
54
        virtual void setupTranslations (void)
 
55
        {
 
56
                KGlobal::locale()->insertCatalogue ("kwordmswritefilter");
 
57
        }
 
58
};
 
59
 
 
60
K_EXPORT_COMPONENT_FACTORY (libmswriteimport, MSWriteImportFactory ())
 
61
 
 
62
 
 
63
//
 
64
// Device that reads from .WRI file
 
65
//
 
66
 
 
67
class WRIDevice : public MSWrite::Device
 
68
{
 
69
private:
 
70
        FILE *m_infp;
 
71
 
 
72
public:
 
73
        WRIDevice () : m_infp (NULL)
 
74
        {
 
75
        }
 
76
 
 
77
        virtual ~WRIDevice ()
 
78
        {
 
79
                closeFile ();
 
80
        }
 
81
 
 
82
        bool openFile (const char *fileName)
 
83
        {
 
84
                m_infp = fopen (fileName, "rb");
 
85
                if (!m_infp)
 
86
                {
 
87
                        error (MSWrite::Error::FileError, "could not open file for reading\n");
 
88
                        return false;
 
89
                }
 
90
 
 
91
                return true;
 
92
        }
 
93
 
 
94
        bool closeFile (void)
 
95
        {
 
96
                if (m_infp)
 
97
                {
 
98
                        if (fclose (m_infp))
 
99
                        {
 
100
                                error (MSWrite::Error::FileError, "could not close input file\n");
 
101
                                return false;
 
102
                        }
 
103
 
 
104
                        m_infp = NULL;
 
105
                }
 
106
 
 
107
                return true;
 
108
        }
 
109
 
 
110
        bool read (MSWrite::Byte *buf, const MSWrite::DWord numBytes)
 
111
        {
 
112
                if (fread (buf, 1, (size_t) numBytes, m_infp) != (size_t) numBytes)
 
113
                {
 
114
                        error (MSWrite::Error::FileError, "could not read from input file\n");
 
115
                        return false;
 
116
                }
 
117
 
 
118
                return true;
 
119
        }
 
120
 
 
121
        bool write (const MSWrite::Byte *, const MSWrite::DWord)
 
122
        {
 
123
                error (MSWrite::Error::InternalError, "writing to an input file?\n");
 
124
                return false;
 
125
        }
 
126
 
 
127
        bool seek (const long offset, const int whence)
 
128
        {
 
129
                if (fseek (m_infp, offset, whence))
 
130
                {
 
131
                        error (MSWrite::Error::InternalError, "could not seek input file\n");
 
132
                        return false;
 
133
                }
 
134
 
 
135
                return true;
 
136
        }
 
137
 
 
138
        long tell (void)
 
139
        {
 
140
                return ftell (m_infp);
 
141
        }
 
142
 
 
143
        void debug (const char *s)
 
144
        {
 
145
                kdDebug (30509) << s;
 
146
        }
 
147
 
 
148
        void debug (const int i)
 
149
        {
 
150
                kdDebug (30509) << i;
 
151
        }
 
152
 
 
153
        void error (const int errorCode, const char *message,
 
154
                                        const char * /*file*/ = "", const int /*lineno*/ = 0,
 
155
                                        MSWrite::DWord /*tokenValue*/ = NoToken)
 
156
        {
 
157
                if (errorCode == MSWrite::Error::Warn)
 
158
                        kdWarning (30509) << message;
 
159
                else
 
160
                {
 
161
                        m_error = errorCode;
 
162
                        kdError (30509) << message;
 
163
                }
 
164
        }
 
165
};
 
166
 
 
167
 
 
168
//
 
169
// Generator that creates the KWord file
 
170
//
 
171
 
 
172
class KWordGenerator : public MSWrite::Generator, public MSWrite::NeedsDevice
 
173
{
 
174
private:
 
175
        // KoStore can only have 1 file open at a time
 
176
        // so we store objects in this structure temporarily
 
177
        class WRIObject
 
178
        {
 
179
        private:
 
180
                WRIObject (const WRIObject &rhs);
 
181
 
 
182
        public:
 
183
                MSWrite::Byte *m_data;
 
184
                MSWrite::DWord m_dataLength;
 
185
                MSWrite::DWord m_dataUpto;
 
186
                QString m_nameInStore;
 
187
 
 
188
                WRIObject () : m_data (NULL), m_dataLength (0), m_dataUpto (0)
 
189
                {
 
190
                }
 
191
 
 
192
                ~WRIObject ()
 
193
                {
 
194
                        delete [] m_data;
 
195
                }
 
196
 
 
197
                WRIObject operator= (const WRIObject &rhs)
 
198
                {
 
199
                        delete [] m_data;
 
200
 
 
201
                        m_dataLength = rhs.m_dataLength;
 
202
                        m_dataUpto = rhs.m_dataUpto;
 
203
                        m_nameInStore = rhs.m_nameInStore;
 
204
 
 
205
                        if (rhs.m_data)
 
206
                        {
 
207
                                m_data = new MSWrite::Byte [m_dataLength];
 
208
                                if (m_data)
 
209
                                        memcpy (m_data, rhs.m_data, m_dataLength);
 
210
                                // remember to check m_data before use
 
211
                        }
 
212
                        else
 
213
                                m_data = NULL;
 
214
 
 
215
                        return *this;
 
216
                }
 
217
        };
 
218
 
 
219
        // page/margin dimensions
 
220
        int m_pageWidth, m_pageHeight;
 
221
        int m_left, m_right, m_top, m_bottom;           // describing border of Text Frameset (position, not magnitude)
 
222
        int m_leftMargin, m_rightMargin, m_topMargin, m_bottomMargin;
 
223
        int m_headerFromTop, m_footerFromTop;
 
224
        bool m_hasHeader, m_isHeaderOnFirstPage;
 
225
        bool m_hasFooter, m_isFooterOnFirstPage;
 
226
        bool m_writeHeaderFirstTime, m_writeFooterFirstTime;
 
227
 
 
228
        int inWhat;
 
229
 
 
230
        enum inWhatPossiblities
 
231
        {
 
232
                Nothing,
 
233
                Header,
 
234
                Footer,
 
235
                Body
 
236
        };
 
237
 
 
238
        int m_startingPageNumber;
 
239
 
 
240
        KoFilterChain *m_chain;
 
241
        KoStoreDevice *m_outfile;
 
242
 
 
243
        // for charset conversion
 
244
        QTextCodec *m_codec;
 
245
        QTextDecoder *m_decoder;
 
246
 
 
247
        // import options (compensate for differences between KWord and MS Write)
 
248
        bool m_simulateLineSpacing;
 
249
        bool m_simulateImageOffset;
 
250
 
 
251
        // formatting
 
252
        QString m_formatOutput;
 
253
        int m_charInfoCountStart, m_charInfoCountLen;
 
254
        bool m_pageBreak, m_needAnotherParagraph;
 
255
        int m_pageBreakOffset;
 
256
        int m_lineSpacingFromAbove;
 
257
 
 
258
        // picture counters
 
259
        int m_numPictures;
 
260
        QString m_pictures;
 
261
 
 
262
        QString m_objectFrameset;
 
263
 
 
264
        MSWrite::List <WRIObject> m_objectList;
 
265
 
 
266
        double m_objectHorizOffset;
 
267
        bool m_paraIsImage;
 
268
 
 
269
        MSWriteImport *m_koLink;
 
270
 
 
271
        // XML output that is held back until after "Text Frameset 1" is output
 
272
        // (i.e. header & footer must come after the Body in KWord)
 
273
        bool m_delayOutput;
 
274
        QString m_heldOutput;
 
275
 
 
276
        void delayOutput (const bool yes)
 
277
        {
 
278
                m_delayOutput = yes;
 
279
        }
 
280
 
 
281
        bool delayOutputFlush (void)
 
282
        {
 
283
                QCString strUtf8 = m_heldOutput.utf8 ();
 
284
                int strLength = strUtf8.length ();
 
285
 
 
286
                if (m_outfile->writeBlock (strUtf8, strLength) != strLength)
 
287
                        ErrorAndQuit (MSWrite::Error::FileError, "could not write delayed output\n");
 
288
 
 
289
                m_heldOutput = "";
 
290
                return true;
 
291
        }
 
292
 
 
293
public:
 
294
        KWordGenerator () : m_hasHeader (false), m_isHeaderOnFirstPage (false),
 
295
                                                                m_hasFooter (false), m_isFooterOnFirstPage (false),
 
296
                                                                m_writeHeaderFirstTime (true), m_writeFooterFirstTime (true),
 
297
                                                                inWhat (Nothing),
 
298
                                                                m_decoder (NULL),
 
299
                                                                m_simulateLineSpacing (false),
 
300
                                                                m_simulateImageOffset (true),
 
301
                                                                m_pageBreak (false), m_needAnotherParagraph (false),
 
302
                                                                m_lineSpacingFromAbove (0),
 
303
                                                                m_numPictures (0)
 
304
        {
 
305
                delayOutput (false);
 
306
 
 
307
                // just select windows-1252 until the "Select Encoding" dialog works
 
308
                m_codec = QTextCodec::codecForName ("CP 1252");
 
309
 
 
310
                if (m_codec)
 
311
                        m_decoder = m_codec->makeDecoder();
 
312
                else
 
313
                        kdWarning (30509) << "Cannot convert from Win Charset!" << endl;
 
314
        }
 
315
 
 
316
        virtual ~KWordGenerator ()
 
317
        {
 
318
                delete m_decoder;
 
319
        }
 
320
 
 
321
        void setFilterChain (KoFilterChain *chain)
 
322
        {
 
323
                m_chain = chain;
 
324
        }
 
325
 
 
326
        bool writeDocumentBegin (const MSWrite::Word,
 
327
                                                                                const MSWrite::PageLayout *pageLayout)
 
328
        {
 
329
                kdDebug (30509) << "writeDocumentBegin()" << endl;
 
330
 
 
331
                // open maindoc.xml
 
332
                m_outfile = m_chain->storageFile ("root", KoStore::Write);
 
333
                if (!m_outfile)
 
334
                        ErrorAndQuit (MSWrite::Error::FileError, "could not open root in store\n");
 
335
 
 
336
 
 
337
                //
 
338
                // store page dimensions for now
 
339
                //
 
340
 
 
341
                // page width & height
 
342
                m_pageWidth = Twip2Point (pageLayout->getPageWidth ());
 
343
                m_pageHeight = Twip2Point (pageLayout->getPageHeight ());
 
344
 
 
345
                // offset of margins
 
346
                m_left = Twip2Point (pageLayout->getLeftMargin ());
 
347
                m_right = m_left + Twip2Point (pageLayout->getTextWidth ()) - 1;
 
348
                m_top = Twip2Point (pageLayout->getTopMargin ());
 
349
                m_bottom = m_top + Twip2Point (pageLayout->getTextHeight ()) - 1;
 
350
 
 
351
                // size of margins
 
352
                m_leftMargin = m_left;
 
353
                m_rightMargin = Twip2Point (pageLayout->getRightMargin ());
 
354
                m_topMargin = m_top;
 
355
                m_bottomMargin = Twip2Point (pageLayout->getBottomMargin ());
 
356
 
 
357
                kdDebug (30509) << "leftMargin: " << m_leftMargin << endl;
 
358
                kdDebug (30509) << "rightMargin: " << m_rightMargin << endl;
 
359
                kdDebug (30509) << "topMargin: " << m_topMargin << endl;
 
360
                kdDebug (30509) << "bottomMargin: " << m_bottomMargin << endl;
 
361
 
 
362
                // offset of header & footer
 
363
                m_headerFromTop = Twip2Point (pageLayout->getHeaderFromTop ());
 
364
                m_footerFromTop = Twip2Point (pageLayout->getFooterFromTop ());
 
365
 
 
366
                kdDebug (30509) << "headerFromTop: " << m_headerFromTop
 
367
                                                                << " footerFromTop: " << m_footerFromTop << endl;
 
368
 
 
369
                m_startingPageNumber = pageLayout->getPageNumberStart ();
 
370
 
 
371
                return true;
 
372
        }
 
373
 
 
374
        bool writeDocumentBeginForReal (void)
 
375
        {
 
376
                kdDebug (30509) << "writeDocumentBeginForReal()" << endl;
 
377
 
 
378
                // adjust margins/PAPERBORDERS to ensure that the header & footer are
 
379
                // within them
 
380
                // TODO: stop header & footer from changing body's location
 
381
                // TODO: recompute offset of margins after recomputing margins
 
382
                if (m_hasHeader)
 
383
                        if (m_headerFromTop < m_topMargin)
 
384
                                m_topMargin = m_headerFromTop;
 
385
 
 
386
                if (m_hasFooter)
 
387
                        if (m_pageHeight - m_footerFromTop < m_bottomMargin)
 
388
                                m_bottomMargin = m_pageHeight - m_footerFromTop;
 
389
 
 
390
                kdDebug (30509) << "adjusted::: leftMargin: " << m_leftMargin
 
391
                                                                << "  rightMargin: " << m_rightMargin
 
392
                                                                << "  topMargin: " << m_topMargin
 
393
                                                                << "  bottomMargin: " << m_bottomMargin
 
394
                                                                << endl;
 
395
 
 
396
                // start document
 
397
                // TODO: error checking
 
398
                writeTextInternal ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 
399
                writeTextInternal ("<!DOCTYPE DOC PUBLIC \"-//KDE//DTD kword 1.3//EN\" "
 
400
                                                                        "\"http://www.koffice.org/DTD/kword-1.3.dtd\">");
 
401
                writeTextInternal ("<DOC xmlns=\"http://www.koffice.org/DTD/kword\" "
 
402
                                                                        "mime=\"application/x-kword\" "
 
403
                                                                        "syntaxVersion=\"3\" editor=\"KWord\">");
 
404
 
 
405
                writeTextInternal ("<PAPER format=\"1\" "
 
406
                                                                        "width=\"%i\" height=\"%i\" "
 
407
                                                                        "orientation=\"0\" columns=\"1\" "
 
408
                                                                        "hType=\"%i\" fType=\"%i\">",
 
409
                                                                        m_pageWidth, m_pageHeight,
 
410
                                                                        m_isHeaderOnFirstPage ? 0 : 2,
 
411
                                                                        m_isFooterOnFirstPage ? 0 : 2);
 
412
 
 
413
                writeTextInternal ("<PAPERBORDERS left=\"%i\" right=\"%i\" "
 
414
                                                                        "top=\"%i\" bottom=\"%i\"/>",
 
415
                                                                        m_leftMargin, m_rightMargin,
 
416
                                                                        m_topMargin, m_bottomMargin);
 
417
 
 
418
                writeTextInternal ("</PAPER>");
 
419
 
 
420
                writeTextInternal ("<ATTRIBUTES processing=\"0\" "
 
421
                                                                        "tabStopValue=\"%lf\" "
 
422
                                                                        "hasHeader=\"%i\" hasFooter=\"%i\"/>",
 
423
                                                                        Inch2Point (0.5),
 
424
                                                                        m_hasHeader ? 1 : 0, m_hasFooter ? 1 : 0);
 
425
 
 
426
                // handle page numbering not starting from 1
 
427
                if (m_startingPageNumber != 1)
 
428
                        writeTextInternal ("<VARIABLESETTINGS startingPageNumber=\"%i\"/>",
 
429
                                                                                m_startingPageNumber);
 
430
 
 
431
                writeTextInternal ("<FRAMESETS>");
 
432
 
 
433
                return true;
 
434
        }
 
435
 
 
436
        bool writeDocumentEnd (const MSWrite::Word, const MSWrite::PageLayout *)
 
437
        {
 
438
                kdDebug (30509) << "writeDocumentEnd()" << endl;
 
439
 
 
440
                // write framesets for the objects
 
441
                writeTextInternal (m_objectFrameset);
 
442
 
 
443
                writeTextInternal ("</FRAMESETS>");
 
444
                writeTextInternal ("<STYLES>");
 
445
                writeTextInternal ("<STYLE>");
 
446
                        writeTextInternal ("<NAME value=\"Standard\"/>");
 
447
                        writeTextInternal ("<FLOW align=\"left\"/>");
 
448
                        writeTextInternal ("<INDENTS first=\"0\" left=\"0\" right=\"0\"/>");
 
449
                        writeTextInternal ("<OFFSETS before=\"0\" after=\"0\"/>");
 
450
 
 
451
                        writeTextInternal ("<FORMAT id=\"1\">");
 
452
                                writeTextInternal ("<COLOR blue=\"0\" red=\"0\" green=\"0\"/>");
 
453
                                writeTextInternal ("<FONT name=\"helvetica\"/>");
 
454
                                writeTextInternal ("<SIZE value=\"12\"/>");
 
455
                                writeTextInternal ("<WEIGHT value=\"50\"/>");
 
456
                                writeTextInternal ("<ITALIC value=\"0\"/>");
 
457
                                writeTextInternal ("<UNDERLINE value=\"0\"/>");
 
458
                                writeTextInternal ("<STRIKEOUT value=\"0\"/>");
 
459
                                writeTextInternal ("<VERTALIGN value=\"0\"/>");
 
460
                        writeTextInternal ("</FORMAT>");
 
461
 
 
462
                        writeTextInternal ("<FOLLOWING name=\"Standard\"/>");
 
463
                writeTextInternal ("</STYLE>");
 
464
                writeTextInternal ("</STYLES>");
 
465
 
 
466
                // write out image keys
 
467
                writeTextInternal ("<PICTURES>");
 
468
                        writeTextInternal (m_pictures);
 
469
                writeTextInternal ("</PICTURES>");
 
470
 
 
471
                // end document
 
472
                writeTextInternal ("</DOC>");
 
473
 
 
474
                // close maindoc.xml
 
475
                m_outfile->close ();
 
476
                m_outfile = (KoStoreDevice *) NULL;
 
477
 
 
478
                //
 
479
                // output object data
 
480
 
 
481
                /*if (m_objectUpto != getNumObjects ())
 
482
                        warning ("m_objectUpto (%i) != getNumObjects() (%i) -- this is probably because OLE is unimplemented\n",
 
483
                                                m_objectUpto, getNumObjects ());*/
 
484
 
 
485
                MSWrite::List <WRIObject>::Iterator it;
 
486
                for (it = m_objectList.begin (); it != m_objectList.end (); it++)
 
487
                {
 
488
                        kdDebug (30509) << "outputting object \'" << (*it).m_nameInStore
 
489
                                                                        << "\'   (length: " << (*it).m_dataLength << ")"
 
490
                                                                        << endl;
 
491
 
 
492
                        if (!(*it).m_data)
 
493
                                ErrorAndQuit (MSWrite::Error::InternalError, "image data not initialised\n");
 
494
 
 
495
                        // open file for object in store
 
496
                        m_outfile = m_chain->storageFile ((*it).m_nameInStore, KoStore::Write);
 
497
                        if (!m_outfile)
 
498
                                ErrorAndQuit (MSWrite::Error::FileError, "could not open image in store\n");
 
499
 
 
500
                        if (m_outfile->writeBlock ((const char *) (*it).m_data, (*it).m_dataLength)
 
501
                                != (Q_LONG) (*it).m_dataLength)
 
502
                                ErrorAndQuit (MSWrite::Error::FileError, "could not write image to store\n");
 
503
 
 
504
                        // close object in store
 
505
                        m_outfile->close ();
 
506
                        m_outfile = NULL;
 
507
                }
 
508
 
 
509
                return true;
 
510
        }
 
511
 
 
512
 
 
513
        bool writeFooterBegin (void)
 
514
        {
 
515
                kdDebug (30509) << "writeFooterBegin()" << endl;
 
516
 
 
517
                inWhat = Footer;
 
518
                m_hasFooter = true;
 
519
 
 
520
                // footers must go after body in KWord
 
521
                delayOutput (true);
 
522
 
 
523
                // footer frameset will be written in writeParaInfoBegin()
 
524
 
 
525
                return true;
 
526
        }
 
527
 
 
528
        bool writeFooterEnd (void)
 
529
        {
 
530
                kdDebug (30509) << "writeFooterEnd()" << endl;
 
531
 
 
532
                inWhat = Nothing;
 
533
 
 
534
                if (!m_writeFooterFirstTime)
 
535
                        writeTextInternal ("</FRAMESET>");
 
536
                delayOutput (false);
 
537
 
 
538
                return true;
 
539
        }
 
540
 
 
541
        bool writeHeaderBegin (void)
 
542
        {
 
543
                kdDebug (30509) << "writeHeaderBegin()" << endl;
 
544
 
 
545
                inWhat = Header;
 
546
                m_hasHeader = true;
 
547
 
 
548
                // headers must go after body in KWord
 
549
                delayOutput (true);
 
550
 
 
551
                // header frameset will be written in writeParaInfoBegin()
 
552
 
 
553
                return true;
 
554
        }
 
555
 
 
556
        bool writeHeaderEnd (void)
 
557
        {
 
558
                kdDebug (30509) << "writeHeaderEnd()" << endl;
 
559
 
 
560
                inWhat = Nothing;
 
561
 
 
562
                if (!m_writeHeaderFirstTime)
 
563
                        writeTextInternal ("</FRAMESET>");
 
564
                delayOutput (false);
 
565
 
 
566
                return true;
 
567
        }
 
568
 
 
569
        bool writeBodyBegin (void)
 
570
        {
 
571
                kdDebug (30509) << "writeBodyBegin()" << endl;
 
572
 
 
573
                inWhat = Body;
 
574
 
 
575
                // writeFooterBegin() and writeHeaderBegin() have been called by now
 
576
                // so we have enough information to actually write about them
 
577
                writeDocumentBeginForReal ();
 
578
 
 
579
                writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"0\" name=\"Text Frameset 1\" visible=\"1\">");
 
580
                // TODO: runaround?
 
581
                writeTextInternal ("<FRAME runaround=\"1\" autoCreateNewFrame=\"1\" newFrameBehavior=\"0\" copy=\"0\""
 
582
                                                                        " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
 
583
                                                                        m_top, m_bottom, m_left, m_right);
 
584
 
 
585
                return true;
 
586
        }
 
587
 
 
588
        bool writeBodyEnd (void)
 
589
        {
 
590
                kdDebug (30509) << "writeBodyEnd()" << endl;
 
591
 
 
592
                inWhat = Nothing;
 
593
 
 
594
                // <PAGEBREAKING hardFrameBreakAfter=\"true\"/>" may have been in the last paragraph
 
595
                // and for "hardFrameBreakAfter" to do its work, we need one more final paragraph!
 
596
                if (m_needAnotherParagraph)
 
597
                {
 
598
                        kdDebug (30509) << "needAnotherParagraph in bodyEndWrite()" << endl;
 
599
                        writeTextInternal ("<PARAGRAPH><TEXT></TEXT><LAYOUT></LAYOUT></PARAGRAPH>");
 
600
                        m_needAnotherParagraph = false;
 
601
                }
 
602
 
 
603
                writeTextInternal ("</FRAMESET>");
 
604
 
 
605
                // since "Text Frameset 1" has ended, we can output the header & footer, now
 
606
                delayOutputFlush ();
 
607
 
 
608
                return true;
 
609
        }
 
610
 
 
611
        bool writeParaInfoBegin (const MSWrite::FormatParaProperty *paraProperty,
 
612
                                                                                const MSWrite::OLE *ole,
 
613
                                                                                const MSWrite::Image *image)
 
614
        {
 
615
                //kdDebug (30509) << "writeParaInfoBegin()" << endl;
 
616
 
 
617
                // reset charInfo counters
 
618
                m_charInfoCountStart = 0;
 
619
                m_charInfoCountLen = 0;
 
620
 
 
621
                if (inWhat == Header)
 
622
                {
 
623
                        m_isHeaderOnFirstPage = paraProperty->getIsOnFirstPage ();
 
624
 
 
625
                        if (m_writeHeaderFirstTime)
 
626
                        {
 
627
                                // dummy header frames
 
628
                                //
 
629
 
 
630
                                // except, if the header is NOT on the first page, then make an empty "First Page Header"
 
631
                                // by setting "visible=1"
 
632
                                writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"1\" name=\"First Page Header\" visible=\"%i\">",
 
633
                                                                                        m_isHeaderOnFirstPage ? 1 : 0);
 
634
                                writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
 
635
                                                                                        " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
 
636
                                                                                        m_headerFromTop, m_headerFromTop, m_left, m_right);
 
637
                                writeTextInternal ("</FRAMESET>");
 
638
 
 
639
                                writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"2\" name=\"Even Pages Header\" visible=\"0\">");
 
640
                                writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
 
641
                                                                                        " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
 
642
                                                                                        m_headerFromTop, m_headerFromTop, m_left, m_right);
 
643
                                writeTextInternal ("</FRAMESET>");
 
644
 
 
645
                                // real header frame
 
646
                                writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"3\" name=\"Odd Pages Header\" visible=\"1\">");
 
647
                                writeTextInternal ("<FRAME runaround=\"1\" copy=\"1\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
 
648
                                                                                        " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
 
649
                                                                                        m_headerFromTop, m_headerFromTop, m_left, m_right);
 
650
 
 
651
                                m_writeHeaderFirstTime = false;
 
652
                        }
 
653
                }
 
654
                else if (inWhat == Footer)
 
655
                {
 
656
                        m_isFooterOnFirstPage = paraProperty->getIsOnFirstPage ();
 
657
 
 
658
                        if (m_writeFooterFirstTime)
 
659
                        {
 
660
                                // dummy footer frames
 
661
                                //
 
662
 
 
663
                                // except, if the footer is NOT on the first page, then make an empty "First Page Footer"
 
664
                                // by setting "visible=1"
 
665
                                writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"4\" name=\"First Page Footer\" visible=\"%i\">",
 
666
                                                                                        m_isFooterOnFirstPage ? 1 : 0);
 
667
                                writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
 
668
                                                                                        " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
 
669
                                                                                        m_footerFromTop, m_footerFromTop, m_left, m_right);
 
670
                                writeTextInternal ("</FRAMESET>");
 
671
 
 
672
                                writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"5\" name=\"Even Pages Footer\" visible=\"0\">");
 
673
                                writeTextInternal ("<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
 
674
                                                                                        " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
 
675
                                                                                        m_footerFromTop, m_footerFromTop, m_left, m_right);
 
676
                                writeTextInternal ("</FRAMESET>");
 
677
 
 
678
                                // real footer frame
 
679
                                writeTextInternal ("<FRAMESET frameType=\"1\" frameInfo=\"6\" name=\"Odd Pages Footer\" visible=\"1\">");
 
680
                                writeTextInternal ("<FRAME runaround=\"1\" copy=\"1\" newFrameBehavior=\"2\" autoCreateNewFrame=\"0\""
 
681
                                                                                        " top=\"%i\" bottom=\"%i\" left=\"%i\" right=\"%i\"/>",
 
682
                                                                                        m_footerFromTop, m_footerFromTop, m_left, m_right);
 
683
 
 
684
                                m_writeFooterFirstTime = false;
 
685
                        }
 
686
                }
 
687
 
 
688
                if (!writeTextInternal ("<PARAGRAPH><TEXT>")) return false;
 
689
 
 
690
                if (image)
 
691
                {
 
692
                        kdDebug (30509) << "Paragraph is an image!" << endl;
 
693
 
 
694
                        QString imageName;
 
695
                        QString fileInStore;
 
696
 
 
697
 
 
698
                        // give picture a name
 
699
                        //
 
700
 
 
701
                        imageName = "Picture ";
 
702
                        imageName += QString::number (m_numPictures + 1);       // image numbers start at 1...
 
703
 
 
704
 
 
705
                        // give picture a filename
 
706
                        //
 
707
 
 
708
                        fileInStore = "pictures/picture" + QString::number (m_numPictures + 1);
 
709
 
 
710
                        kdDebug (30509) << "\tGetting type..." << endl;
 
711
 
 
712
                        // append extension
 
713
                        if (image->getIsBMP ())
 
714
                                fileInStore += ".bmp";
 
715
                        else if (image->getIsWMF () )
 
716
                                fileInStore += ".wmf";
 
717
                        else
 
718
                                ErrorAndQuit (MSWrite::Error::InternalError, "unsupported picture type\n");
 
719
 
 
720
 
 
721
                        // indicate anchored image in formatting
 
722
                        //
 
723
                        kdDebug (30509) << "\tIndicating anchored image in formatting" << endl;
 
724
                        if (!writeTextInternal ("#")) return false;
 
725
 
 
726
                        m_formatOutput += "<FORMAT id=\"6\" pos=\"0\" len=\"1\">";
 
727
                                m_formatOutput += "<ANCHOR type=\"frameset\" instance=\"";
 
728
                                        m_formatOutput += imageName;
 
729
                                m_formatOutput += "\"/>";
 
730
                        m_formatOutput += "</FORMAT>";
 
731
 
 
732
 
 
733
                        // write framesets (truly written in documentEndWrite())
 
734
                        //
 
735
                        kdDebug (30509) << "\tWriting framesets!" << endl;
 
736
 
 
737
                        m_objectFrameset += "<FRAMESET frameType=\"2\" frameInfo=\"0\" name=\"";
 
738
                        m_objectFrameset += imageName;
 
739
                        m_objectFrameset += "\" visible=\"1\">";
 
740
 
 
741
                                m_objectFrameset += "<FRAME runaround=\"1\" copy=\"0\" newFrameBehavior=\"1\"";
 
742
 
 
743
                                const double imageLeft = double (m_left) + Twip2Point (double (image->getIndent ()));
 
744
                                m_objectFrameset += " left=\"";
 
745
                                        m_objectFrameset += QString::number (imageLeft);
 
746
                                        m_objectFrameset += "\"";
 
747
 
 
748
                                const double imageWidth = Twip2Point (double (image->getDisplayedWidth ()));
 
749
                                m_objectFrameset += " right=\"";
 
750
                                        m_objectFrameset += QString::number (imageLeft + imageWidth - 1);
 
751
                                        m_objectFrameset += "\"";
 
752
 
 
753
                                m_objectFrameset += " top=\"";
 
754
                                        m_objectFrameset += QString::number (m_top);
 
755
                                        m_objectFrameset += "\"";
 
756
 
 
757
                                const double imageHeight = Twip2Point (double (image->getDisplayedHeight ()));
 
758
                                m_objectFrameset += " bottom=\"";
 
759
                                        m_objectFrameset += QString::number (double (m_top) + imageHeight - 1);
 
760
                                        m_objectFrameset += "\"/>";
 
761
 
 
762
                                m_objectFrameset += "<PICTURE keepAspectRatio=\"false\">";
 
763
                                m_objectFrameset += "<KEY msec=\"0\" hour=\"0\" second=\"0\" minute=\"0\" day=\"1\" month=\"1\" year=\"1970\"";
 
764
                                m_objectFrameset += " filename=\"";
 
765
                                m_objectFrameset += fileInStore;
 
766
                                m_objectFrameset += "\"/>";
 
767
                                m_objectFrameset += "</PICTURE>";
 
768
 
 
769
                        m_objectFrameset += "</FRAMESET>";
 
770
                #ifdef DEBUG_XML_OUTPUT
 
771
                        m_objectFrameset += "\n";
 
772
                #endif
 
773
 
 
774
                        m_pictures += "<KEY msec=\"0\" hour=\"0\" second=\"0\" minute=\"0\" day=\"1\" month=\"1\" year=\"1970\"";
 
775
                        m_pictures += " name=\"";
 
776
                        m_pictures += fileInStore;
 
777
                        m_pictures += "\"";
 
778
                        m_pictures += " filename=\"";
 
779
                        m_pictures += fileInStore;
 
780
                        m_pictures += "\"/>";
 
781
 
 
782
                        m_numPictures++;
 
783
 
 
784
 
 
785
                        // store object properties
 
786
                        //
 
787
                        kdDebug (30509) << "\tStoring object" << endl;
 
788
 
 
789
                        if (!m_objectList.addToBack ())
 
790
                                ErrorAndQuit (MSWrite::Error::OutOfMemory, "could not allocate memory for object\n");
 
791
 
 
792
                        WRIObject &obj = *m_objectList.begin (false);
 
793
                        obj.m_nameInStore = fileInStore;
 
794
                        obj.m_dataLength = image->getExternalImageSize ();
 
795
                        obj.m_data = new MSWrite::Byte [obj.m_dataLength];
 
796
                        if (!obj.m_data)
 
797
                                ErrorAndQuit (MSWrite::Error::OutOfMemory, "could not allocate memory for object data\n");
 
798
 
 
799
                        // if anchored images could be positioned properly, this wouldn't be needed
 
800
                        m_objectHorizOffset = double (Twip2Point (image->getIndent ()));
 
801
                        m_paraIsImage = true;
 
802
                }
 
803
                else
 
804
                {
 
805
                        if (ole)
 
806
                        {
 
807
                                if (!writeTextInternal ("[OLE unsupported]")) return false;
 
808
                        }
 
809
 
 
810
                        m_paraIsImage = false;
 
811
                }
 
812
 
 
813
 
 
814
                return true;
 
815
        }
 
816
 
 
817
        bool writeParaInfoEnd (const MSWrite::FormatParaProperty *paraProperty,
 
818
                                                                        const MSWrite::OLE * /*ole*/,
 
819
                                                                        const MSWrite::Image *image)
 
820
 
 
821
        {
 
822
                //kdDebug (30509) << "writeParaInfoEnd()" << endl;
 
823
 
 
824
                if (image)
 
825
                {
 
826
                        WRIObject &obj = *m_objectList.begin (false);
 
827
 
 
828
                        // consistency check: wrote exactly the right amount of data?
 
829
                        if (obj.m_dataUpto != obj.m_dataLength)
 
830
                                kdWarning (30509) << "obj.dataUpto (" << obj.m_dataUpto
 
831
                                                                                << ") != obj.dataLength (" << obj.m_dataLength
 
832
                                                                                << ")" << endl;
 
833
                }
 
834
 
 
835
                QString output;
 
836
                output += "</TEXT>";
 
837
 
 
838
                output += "<LAYOUT>";
 
839
                        output += "<NAME value=\"Standard\"/>";
 
840
 
 
841
                        int align = paraProperty->getAlignment ();
 
842
 
 
843
                        if (align != MSWrite::Alignment::Left)
 
844
                        {
 
845
                                output += "<FLOW align=\"";
 
846
                                switch (align)
 
847
                                {
 
848
                                        /*case MSWrite::Alignment::Left:
 
849
                                                output += "left";
 
850
                                                break;*/
 
851
                                        case MSWrite::Alignment::Centre:
 
852
                                                output += "center";
 
853
                                                break;
 
854
                                        case MSWrite::Alignment::Right:
 
855
                                                output += "right";
 
856
                                                break;
 
857
                                        case MSWrite::Alignment::Justify:
 
858
                                                output += "justify";
 
859
                                                break;
 
860
                                }
 
861
                                output += "\"/>";
 
862
                        }
 
863
 
 
864
                        double indentFirst = Twip2Point (double (paraProperty->getLeftIndentFirstLine ()));
 
865
                        double indentLeft = Twip2Point (double (paraProperty->getLeftIndent ()));
 
866
                        double indentRight = Twip2Point (double (paraProperty->getRightIndent ()));
 
867
 
 
868
        #if 0
 
869
                        debug ("raw indent:  first: %i  left: %i  right: %i\n",
 
870
                                                indentFirst, indentLeft, indentRight);
 
871
        #endif
 
872
 
 
873
                        if (m_paraIsImage /*paraProperty->isObject ()*/ && m_objectHorizOffset)
 
874
                        {
 
875
                                if (align == MSWrite::Align::Center)
 
876
                                {
 
877
                                        // TODO: I don't know what m_objectHorizOffset is relative to!
 
878
                                        kdDebug (30509) <<  "ignoring image offset with centred image" << endl;
 
879
                                        m_objectHorizOffset = 0;
 
880
                                }
 
881
                                else
 
882
                                {
 
883
                                        // MSWrite does not add the horizontal offset of the image from the left margin to the Left Indent
 
884
                                        // -- instead, it selects the bigger one
 
885
                                        // TODO: proper image positioning (see doc IMPERFECT)
 
886
                                        if (m_simulateImageOffset && m_objectHorizOffset > indentLeft)
 
887
                                        {
 
888
                                                kdDebug (30509) << "image is further away from left margin by itself, rather than using indentLeft ("
 
889
                                                                                                << m_objectHorizOffset << " > " << indentLeft << ")" << endl;
 
890
                                                indentLeft = m_objectHorizOffset;
 
891
                                        }
 
892
                                }
 
893
                        }
 
894
 
 
895
                        // hopefully these test operations will be cheaper than the XML ones :)
 
896
                        if (indentFirst || indentLeft || indentRight)
 
897
                        {
 
898
                                output += "<INDENTS";
 
899
                                if (indentFirst) output += " first=\"" + QString::number (indentFirst) + "\"";
 
900
                                if (indentLeft) output += " left=\"" + QString::number (indentLeft) + "\"";
 
901
                                if (indentRight) output += " right=\"" + QString::number (indentRight) + "\"";
 
902
                                output += "/>";
 
903
                        }
 
904
 
 
905
                        MSWrite::Word lineSpacing = paraProperty->getLineSpacing ();
 
906
 
 
907
                        if (lineSpacing != MSWrite::LineSpacing::Single)
 
908
                        {
 
909
                        #if 1
 
910
                                output += "<LINESPACING type=\"atleast\" spacingvalue=\"" + QString::number (Twip2Point (lineSpacing)) + "\"/>";
 
911
                        #else   // old way
 
912
                                output += "<LINESPACING type=\"";
 
913
                                switch (lineSpacing)
 
914
                                {
 
915
                                        //case MSWrite:;LineSpacing::Single:
 
916
                                        //      break;
 
917
                                        case MSWrite::LineSpacing::OneAndAHalf:
 
918
                                                output += "oneandhalf";
 
919
                                                break;
 
920
                                        case MSWrite::LineSpacing::Double:
 
921
                                                output += "double";
 
922
                                                break;
 
923
                                        default:
 
924
                                                kdWarning (30509) << "non-\"standard\" linespacing value: " <<  lineSpacing << endl;
 
925
                                                output += "atleast\" ";
 
926
                                                output += "spacingvalue=\"";
 
927
                                                        output += QString::number (Twip2Point (lineSpacing));
 
928
                                                break;
 
929
                                }
 
930
                                output += "\"/>";
 
931
                        #endif
 
932
                        }
 
933
 
 
934
                        // Do we want the linespacing to _look_ like it does in Write?
 
935
                        // (this adds extra space before each paragraph)
 
936
                        if (m_simulateLineSpacing)
 
937
                        {
 
938
                                // emulate Write's linespacing (aligned to bottom)
 
939
                                // by using varying amounts of space before the paragraph
 
940
                                // TODO: test if it works nicely enough (what if you have several different sized fonts in paragraph?)
 
941
                                if (lineSpacing != MSWrite::LineSpacing::Single)                // if not normal linespacing...
 
942
                                {
 
943
                                        output += "<OFFSETS before=\"";
 
944
 
 
945
                                        int amount = 0;
 
946
                                        switch (lineSpacing)
 
947
                                        {
 
948
                                        /*case MSWrite::LineSpacing::Single:
 
949
                                                break;*/
 
950
                                        case MSWrite::LineSpacing::OneAndAHalf:
 
951
                                                amount = 7;
 
952
                                                break;
 
953
                                        case MSWrite::LineSpacing::Double:
 
954
                                                amount = 14;
 
955
                                                break;
 
956
                                        default:
 
957
                                                kdWarning (30509) << "unknown linespacing value: " << lineSpacing << endl;
 
958
                                                break;
 
959
                                        }
 
960
 
 
961
                                        // subtract the amount of trailing linespace from last paragraph
 
962
                                        amount -= m_lineSpacingFromAbove;
 
963
                                        if (amount <= 0) amount = 0;            // no emulation can be perfect...
 
964
 
 
965
                                        output += QString::number (amount);
 
966
                                        output += "\" />";
 
967
                                }
 
968
 
 
969
                                // GUESS (TODO: fix) the amount of trailing linespace
 
970
                                switch (lineSpacing)
 
971
                                {
 
972
                                case MSWrite::LineSpacing::Single:
 
973
                                        m_lineSpacingFromAbove = 0;
 
974
                                        break;
 
975
                                case MSWrite::LineSpacing::OneAndAHalf:
 
976
                                        m_lineSpacingFromAbove = 7;
 
977
                                        break;
 
978
                                case MSWrite::LineSpacing::Double:
 
979
                                        m_lineSpacingFromAbove = 14;
 
980
                                        break;
 
981
                                default:                // unknown
 
982
                                        m_lineSpacingFromAbove = 0;
 
983
                                        break;
 
984
                                }
 
985
                        }       // if (m_simulateLineSpacing)   {
 
986
 
 
987
                        if (m_pageBreak)
 
988
                        {
 
989
        #if 0
 
990
                                debug ("\tpagebrk: output: offset: %i chars in paragraph: %i\n",
 
991
                                        m_pageBreakOffset, m_charInfoCountStart + m_charInfoCountLen);
 
992
        #endif
 
993
 
 
994
                                // page break before all the text
 
995
                                if (m_pageBreakOffset == 0 && m_charInfoCountStart + m_charInfoCountLen > 0)
 
996
                                {
 
997
                                        output += "<PAGEBREAKING hardFrameBreak=\"true\"/>";
 
998
                                        m_needAnotherParagraph = false; // this paragraph is on first page so we don't need another one
 
999
                                }
 
1000
                                // we assume that the pageBreak was after all the text (TODO: don't assume this)
 
1001
                                else
 
1002
                                {
 
1003
                                        output += "<PAGEBREAKING hardFrameBreakAfter=\"true\"/>";
 
1004
                                        m_needAnotherParagraph = true;  // need another paragraph for hardFrameBreakAfter to work
 
1005
                                }
 
1006
 
 
1007
                                m_pageBreak = false;            // reset flag
 
1008
                        }
 
1009
                        else
 
1010
                                m_needAnotherParagraph = false;
 
1011
 
 
1012
                        // Tabulators
 
1013
                        for (int i = 0; i < paraProperty->getNumTabulator (); i++)
 
1014
                        {
 
1015
                                const MSWrite::FormatParaPropertyTabulator *tab = paraProperty->getTabulator (i);
 
1016
                                if (tab->getIsDummy ()) break;
 
1017
 
 
1018
                                output += "<TABULATOR";
 
1019
 
 
1020
                                if (tab->getIsDecimal ())
 
1021
                                        output += " type=\"3\" alignchar=\".\"";
 
1022
                                else
 
1023
                                        output += " type=\"0\"";
 
1024
 
 
1025
                                output += " ptpos=\"" + QString::number (Twip2Point (double (tab->getIndent ()))) + "\"/>";
 
1026
 
 
1027
                                //debug ("Tab: isNormal: %i  ptPos: %i\n",
 
1028
                                //                      paraProperty->tbd [i].isTabNormal (), paraProperty->tbd [i].getTabNumPoints ());
 
1029
                        }
 
1030
 
 
1031
                output += "</LAYOUT>";
 
1032
        #ifdef DEBUG_XML_OUTPUT
 
1033
                output += "\n";
 
1034
        #endif
 
1035
 
 
1036
                output += "<FORMATS>";
 
1037
        #ifdef DEBUG_XML_OUTPUT
 
1038
                output += "\n";
 
1039
        #endif
 
1040
                        // output all the charInfo for this paragraph
 
1041
                        output += m_formatOutput; m_formatOutput = "";
 
1042
                output += "</FORMATS>";
 
1043
        #ifdef DEBUG_XML_OUTPUT
 
1044
                output += "\n";
 
1045
        #endif
 
1046
 
 
1047
                output += "</PARAGRAPH>";
 
1048
        #ifdef DEBUG_XML_OUTPUT
 
1049
                output += "\n";
 
1050
        #endif
 
1051
 
 
1052
                if (!writeTextInternal (output)) return false;
 
1053
 
 
1054
                return true;
 
1055
        }
 
1056
 
 
1057
        bool writeCharInfoBegin (const MSWrite::FormatCharProperty * /*charProperty*/)
 
1058
        {
 
1059
                //kdDebug (30509) << "writeCharInfoBegin()" << endl;
 
1060
 
 
1061
                return true;
 
1062
        }
 
1063
 
 
1064
        // outputs character formatting tags
 
1065
        bool writeCharInfoEnd (const MSWrite::FormatCharProperty *charProperty,
 
1066
                                                                        const bool = false)
 
1067
        {
 
1068
                //kdDebug (30509) << "writeCharInfoEnd()" << endl;
 
1069
 
 
1070
                // output type of format information (page number or normal text)
 
1071
                m_formatOutput += "<FORMAT id=\"";
 
1072
                if (charProperty->getIsPageNumber ())
 
1073
                        m_formatOutput += "4";
 
1074
                else
 
1075
                        m_formatOutput += "1";
 
1076
                m_formatOutput += "\" ";
 
1077
 
 
1078
                m_formatOutput += "pos=\""; m_formatOutput += QString::number (m_charInfoCountStart); m_formatOutput += "\" ";
 
1079
                m_formatOutput += "len=\""; m_formatOutput += QString::number (m_charInfoCountLen); m_formatOutput += "\">";
 
1080
 
 
1081
                m_charInfoCountStart += m_charInfoCountLen;
 
1082
                m_charInfoCountLen = 0;
 
1083
 
 
1084
                if (charProperty->getIsPageNumber ())
 
1085
                {
 
1086
                        m_formatOutput += "<VARIABLE>";
 
1087
                                m_formatOutput += "<TYPE key=\"NUMBER\" type=\"4\"/>";
 
1088
                                m_formatOutput += "<PGNUM subtype=\"0\" value=\"1\"/>";
 
1089
                        m_formatOutput += "</VARIABLE>";
 
1090
                }
 
1091
 
 
1092
                m_formatOutput += "<FONT name=\"";
 
1093
                        m_formatOutput += (const char *) (charProperty->getFont ()->getName ());
 
1094
                        m_formatOutput += "\"/>";
 
1095
                        m_formatOutput += "<SIZE value=\"";
 
1096
                        m_formatOutput += QString::number (charProperty->getFontSize ());
 
1097
                        m_formatOutput += "\"/>";
 
1098
 
 
1099
                if (charProperty->getIsBold ())
 
1100
                        m_formatOutput += "<WEIGHT value=\"75\"/>";
 
1101
        //else
 
1102
        //              m_formatOutput += "<WEIGHT value=\"50\" />";
 
1103
 
 
1104
                if (charProperty->getIsItalic ())
 
1105
                        m_formatOutput += "<ITALIC value=\"1\"/>";
 
1106
        //      else
 
1107
        //              m_formatOutput += "<ITALIC value=\"0\" />";
 
1108
 
 
1109
                if (charProperty->getIsUnderlined ())
 
1110
                        m_formatOutput += "<UNDERLINE value=\"1\"/>";
 
1111
        //      else
 
1112
        //              m_formatOutput += "<UNDERLINE value=\"0\" />";
 
1113
 
 
1114
                /*if (charProperty->isNormalPosition ())
 
1115
                        m_formatOutput += "<VERTALIGN value=\"0\" />";
 
1116
                else*/ if (charProperty->getIsSubscript ())
 
1117
                        m_formatOutput += "<VERTALIGN value=\"1\"/>";
 
1118
                else if (charProperty->getIsSuperscript ())
 
1119
                        m_formatOutput += "<VERTALIGN value=\"2\"/>";
 
1120
                /*else
 
1121
                        error ("unknown valign\n");*/
 
1122
 
 
1123
                m_formatOutput += "</FORMAT>";
 
1124
 
 
1125
                return true;
 
1126
        }
 
1127
 
 
1128
        bool writeBinary (const MSWrite::Byte *buffer, const MSWrite::DWord length)
 
1129
        {
 
1130
                kdDebug (30509) << "writeBinary()" << endl;
 
1131
 
 
1132
                // must be OLE, TODO: implement OLE properly
 
1133
                if (!m_paraIsImage)
 
1134
                        return true;
 
1135
 
 
1136
                WRIObject &obj = *m_objectList.begin (false);
 
1137
 
 
1138
                if (!obj.m_data)
 
1139
                        ErrorAndQuit (MSWrite::Error::InternalError, "object data not initialised\n");
 
1140
 
 
1141
                // consistency check: aren't going to write past end of array?
 
1142
                if (obj.m_dataUpto + length > obj.m_dataLength)
 
1143
                {
 
1144
                        kdDebug (30509) << "object image overrun: "
 
1145
                                                                        << obj.m_dataUpto << " + " << length
 
1146
                                                                        << " > " << obj.m_dataLength  << endl;
 
1147
                        ErrorAndQuit (MSWrite::Error::InternalError, "object image overrun\n");
 
1148
                }
 
1149
 
 
1150
                memcpy (obj.m_data + obj.m_dataUpto, buffer, length);
 
1151
                obj.m_dataUpto += length;
 
1152
 
 
1153
                return true;
 
1154
        }
 
1155
 
 
1156
 
 
1157
 
 
1158
        //
 
1159
        // text output functions
 
1160
        //
 
1161
 
 
1162
        bool writeText (const MSWrite::Byte *string)
 
1163
        {
 
1164
                // from Win Character Set...
 
1165
                QString strUnicode;
 
1166
 
 
1167
                // there is a codec, therefore there is a decoder...
 
1168
                if (m_codec)
 
1169
                {
 
1170
                        // output Unicode (UTF8)
 
1171
                        strUnicode = m_decoder->toUnicode ((const char *) string, strlen ((const char *) string));
 
1172
                }
 
1173
                else
 
1174
                {
 
1175
                        // output a plain string still in wrong Character Set
 
1176
                        // (hopefully the user won't notice)
 
1177
                        strUnicode = (const char *) string;
 
1178
                }
 
1179
 
 
1180
                // update character information counter (after charset conversion)
 
1181
                m_charInfoCountLen += strUnicode.length ();
 
1182
 
 
1183
                // make string XML-friendly (TODO: speed up)
 
1184
                strUnicode.replace ('&', "&amp;");
 
1185
                strUnicode.replace ('<', "&lt;");
 
1186
                strUnicode.replace ('>', "&gt;");
 
1187
                strUnicode.replace ('\"', "&quot;");
 
1188
                strUnicode.replace ('\'', "&apos;");
 
1189
 
 
1190
                return writeTextInternal (strUnicode);
 
1191
        }
 
1192
 
 
1193
        bool writeTextInternal (const MSWrite::Byte *str)
 
1194
        {
 
1195
        #if 0
 
1196
                return textWrite_lowLevel (QString (str));
 
1197
        #else   // while this is code duplication (of below func), this ensures that no
 
1198
                        // characters are mysteriously converted (this makes writeOptionalHyphen () work)
 
1199
                if (m_delayOutput)
 
1200
                {
 
1201
                        // header/footer must be written after main body
 
1202
                        m_heldOutput += (const char *) str;
 
1203
                        return true;
 
1204
                }
 
1205
                else
 
1206
                {
 
1207
                        int strLength = strlen ((const char *) str);
 
1208
 
 
1209
                        if (m_outfile->writeBlock ((const char *) str, strLength) != strLength)
 
1210
                        {
 
1211
                                ErrorAndQuit (MSWrite::Error::FileError, "could not write to maindoc.xml\n");
 
1212
                        }
 
1213
                        else
 
1214
                                return true;
 
1215
                }
 
1216
        #endif
 
1217
        }
 
1218
 
 
1219
        bool writeTextInternal (const QString &str)
 
1220
        {
 
1221
                if (m_delayOutput)
 
1222
                {
 
1223
                        // header/footer must be written after main body
 
1224
                        m_heldOutput += str;
 
1225
                        return true;
 
1226
                }
 
1227
                else
 
1228
                {
 
1229
                        QCString strUtf8 = str.utf8 ();
 
1230
                        int strLength = strUtf8.length ();
 
1231
 
 
1232
                        if (m_outfile->writeBlock (strUtf8, strLength) != strLength)
 
1233
                        {
 
1234
                                ErrorAndQuit (MSWrite::Error::FileError, "could not write to maindoc.xml (2)\n");
 
1235
                        }
 
1236
                        else
 
1237
                                return true;
 
1238
                }
 
1239
        }
 
1240
 
 
1241
        bool writeTextInternal (const int num)
 
1242
        {
 
1243
                return writeTextInternal (QString::number (num));
 
1244
        }
 
1245
 
 
1246
        bool writeTextInternal (const char *format, ...)
 
1247
        {
 
1248
                va_list list;
 
1249
                va_start (list, format);
 
1250
 
 
1251
                bool ret;
 
1252
                // This function is mainly for outputting tags (where XML characters are
 
1253
                // already escaped and the text is in the right character set...ASCII
 
1254
                // = UTF-8 for alphanumeric chars I hope).  So _don't_ pass user text
 
1255
                // to this function (that's what writeText() is for); otherwise you might
 
1256
                // exceed this 1024 limit.
 
1257
                char string [1024];
 
1258
 
 
1259
                vsnprintf (string, sizeof (string) - 1, format, list);
 
1260
                string [sizeof (string) - 1] = '\0';
 
1261
 
 
1262
                ret = writeTextInternal ((const MSWrite::Byte *) string);
 
1263
 
 
1264
                va_end (list);
 
1265
                return ret;
 
1266
        }
 
1267
 
 
1268
 
 
1269
        // writePageNew() is called for the pageTable
 
1270
        // -- however, pageTable can be very inaccurate, so we ignore it
 
1271
        bool writePageNew (const int)
 
1272
        {
 
1273
                return true;
 
1274
        }
 
1275
 
 
1276
        // handles explicit page breaks
 
1277
        bool writePageBreak (void)
 
1278
        {
 
1279
                // later used in paraEndWrite
 
1280
                m_pageBreak = true;
 
1281
                m_pageBreakOffset = m_charInfoCountStart + m_charInfoCountLen;
 
1282
 
 
1283
                return true;
 
1284
        }
 
1285
 
 
1286
        // handle "(page)" number
 
1287
        bool writePageNumber (void)
 
1288
        {
 
1289
                m_charInfoCountLen++;   // not incremented by writeTextInternal()
 
1290
                return writeTextInternal ("#");
 
1291
        }
 
1292
 
 
1293
        bool writeCarriageReturn (void)
 
1294
        {
 
1295
                return true;    // ignore CR
 
1296
        }
 
1297
 
 
1298
        // write newline unless end-of-paragraph
 
1299
        // (this is the support for paragraphs with multiple newlines)
 
1300
        bool writeNewLine (const bool endOfParagraph)
 
1301
        {
 
1302
                if (!endOfParagraph)
 
1303
                {
 
1304
                        m_charInfoCountLen++;   // not incremented by writeTextInternal()
 
1305
                        return writeTextInternal ("\n");
 
1306
                }
 
1307
                else
 
1308
                        return true;
 
1309
        }
 
1310
 
 
1311
        // aka "soft hyphen"
 
1312
        bool writeOptionalHyphen (void)
 
1313
        {
 
1314
                m_charInfoCountLen++;   // not incremented by writeTextInternal()
 
1315
                return writeTextInternal ("\xC2\xAD");
 
1316
        }
 
1317
 
 
1318
        void setKOfficeLink (MSWriteImport *kofficeLink)
 
1319
        {
 
1320
                m_koLink = kofficeLink;
 
1321
        }
 
1322
 
 
1323
        void sigProgress (const int value)
 
1324
        {
 
1325
                m_koLink->sigProgress (value);
 
1326
        }
 
1327
};
 
1328
 
 
1329
 
 
1330
 
 
1331
//
 
1332
// KoFilter
 
1333
//
 
1334
 
 
1335
MSWriteImport::MSWriteImport (KoFilter *, const char *, const QStringList &)
 
1336
                                        : m_device (NULL), m_parser (NULL), m_generator (NULL)
 
1337
{
 
1338
}
 
1339
 
 
1340
MSWriteImport::~MSWriteImport ()
 
1341
{
 
1342
        delete m_generator;
 
1343
        delete m_parser;
 
1344
        delete m_device;
 
1345
}
 
1346
 
 
1347
KoFilter::ConversionStatus MSWriteImport::convert (const QCString &from, const QCString &to)
 
1348
{
 
1349
        kdDebug (30509) << "MSWriteImport $Date: 2003/08/31 10:59:34 $ using LibMSWrite "
 
1350
                                                        << MSWrite::Version << endl;
 
1351
 
 
1352
        if (to != "application/x-kword" || from != "application/x-mswrite")
 
1353
        {
 
1354
                kdError (30509) << "Internal error!  Filter not implemented?" << endl;
 
1355
                return KoFilter::NotImplemented;
 
1356
        }
 
1357
 
 
1358
#if 0
 
1359
        //MSWriteImportDialog *dialog = new MSWriteImportDialog ();
 
1360
        MSWriteImportDialog dialog;
 
1361
 
 
1362
        /*debug ("DIALOG check alloc\n");
 
1363
        if (!dialog)
 
1364
        {
 
1365
                error ("Could not allocate memory for dialog\n");
 
1366
                return KoFilter::StupidError;
 
1367
        }*/
 
1368
 
 
1369
        debug ("DIALOG EXEC!!!\n");
 
1370
        if (!dialog.exec ())
 
1371
        {
 
1372
                error ("Dialog was aborted! Aborting filter!\n");
 
1373
                return KoFilter::UserCancelled;
 
1374
        }
 
1375
 
 
1376
        debug ("DIALOG GET!!!\n");
 
1377
 
 
1378
        // read settings from dialog
 
1379
        m_codec = dialog.getCodec ();
 
1380
        m_simulateLinespacing = dialog.getSimulateLinespacing ();
 
1381
        m_simulateImageOffset = dialog.getSimulateImageOffset ();
 
1382
        debug ("Import options: simulateLinespacing: %i\tsimulateImageOffset: %i\n",
 
1383
                                m_simulateLinespacing, m_simulateImageOffset);
 
1384
 
 
1385
        debug ("DIALOG DELETE\n");
 
1386
        //delete dialog;
 
1387
#endif
 
1388
 
 
1389
        // create the Device that will read from the .WRI file
 
1390
        m_device = new WRIDevice;
 
1391
        if (!m_device)
 
1392
        {
 
1393
                kdError (30509) << "Could not allocate memory for device" << endl;
 
1394
                return KoFilter::OutOfMemory;
 
1395
        }
 
1396
 
 
1397
        // open the .WRI file
 
1398
        if (!m_device->openFile (QFile::encodeName (m_chain->inputFile ())))
 
1399
        {
 
1400
                kdError (30509) << "Could not open \'" << m_chain->inputFile () << "\'" << endl;
 
1401
                return KoFilter::FileNotFound;
 
1402
        }
 
1403
 
 
1404
 
 
1405
        // create Parser that will interpret the .WRI file and call the Generator
 
1406
        m_parser = new MSWrite::InternalParser;
 
1407
        if (!m_parser)
 
1408
        {
 
1409
                kdError (30509) << "Could not allocate memory for parser" << endl;
 
1410
                return KoFilter::OutOfMemory;
 
1411
        }
 
1412
 
 
1413
        // tell the Parser to use the Device to read from the .WRI file
 
1414
        m_parser->setDevice (m_device);
 
1415
 
 
1416
 
 
1417
        // create Generator that will produce the .KWD file
 
1418
        m_generator = new KWordGenerator;
 
1419
        if (!m_generator)
 
1420
        {
 
1421
                kdError (30509) << "Could not allocate memory for generator" << endl;
 
1422
                return KoFilter::OutOfMemory;
 
1423
        }
 
1424
 
 
1425
        // give the Generator the Device for error-handling purposes
 
1426
        m_generator->setDevice (m_device);
 
1427
 
 
1428
        // give the Generator the chain
 
1429
        m_generator->setFilterChain (m_chain);
 
1430
 
 
1431
        // hand over sigProgess to give some feedback to the user
 
1432
        m_generator->setKOfficeLink (this);
 
1433
 
 
1434
 
 
1435
        // hook up Generator to Parser
 
1436
        m_parser->setGenerator (m_generator);
 
1437
 
 
1438
 
 
1439
        // filter!
 
1440
        if (!m_parser->parse ())
 
1441
        {
 
1442
                // try to return somewhat more meaningful errors than StupidError
 
1443
                // for the day that KOffice actually reports them to the user properly
 
1444
                int errorCode = m_device->bad ();
 
1445
                switch (errorCode)
 
1446
                {
 
1447
                case MSWrite::Error::Ok:
 
1448
                        kdDebug (30509) << "Error::Ok but aborted???" << endl;
 
1449
                        return KoFilter::InternalError;
 
1450
 
 
1451
                case MSWrite::Error::Warn:
 
1452
                        kdDebug (30509) << "Error::Warn" << endl;
 
1453
                        return KoFilter::InternalError; // warnings should _never_ set m_error
 
1454
 
 
1455
                case MSWrite::Error::InvalidFormat:
 
1456
                        kdDebug (30509) << "Error::InvalidFormat" << endl;
 
1457
                        return KoFilter::WrongFormat;
 
1458
 
 
1459
                case MSWrite::Error::OutOfMemory:
 
1460
                        kdDebug (30509) << "Error::OutOfMemory" << endl;
 
1461
                        return KoFilter::OutOfMemory;
 
1462
 
 
1463
                case MSWrite::Error::InternalError:
 
1464
                        kdDebug (30509) << "Error::InternalError" << endl;
 
1465
                        return KoFilter::InternalError;
 
1466
 
 
1467
                case MSWrite::Error::Unsupported:
 
1468
                        kdDebug (30509) << "Error::Unsupported" << endl;
 
1469
                        return KoFilter::InternalError;
 
1470
 
 
1471
                case MSWrite::Error::FileError:
 
1472
                        kdDebug (30509) << "Error::FileError" << endl;
 
1473
                        return KoFilter::StupidError;   // got a better return value?
 
1474
                }
 
1475
 
 
1476
                kdWarning (30509) << "Unknown error: " << errorCode << endl;
 
1477
                return KoFilter::StupidError;
 
1478
        }
 
1479
 
 
1480
        return KoFilter::OK;
 
1481
}
 
1482
 
 
1483
#include <mswriteimport.moc>