oowriter/ExportFilter.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001, 2002, 2003, 2004 Nicolas GOUTTE <goutte@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 as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20/*
21 This file is based on the old file:
22 /home/kde/koffice/filters/kword/ascii/asciiexport.cpp
23
24 The old file was copyrighted by
25 Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
26 Copyright (c) 2000 ID-PRO Deutschland GmbH. All rights reserved.
27 Contact: Wolf-Michael Bolle <Bolle@ID-PRO.de>
28
29 The old file was licensed under the terms of the GNU Library General Public
30 License version 2.
31*/
32
33#include <tqmap.h>
34#include <tqiodevice.h>
35#include <tqbuffer.h>
36#include <tqtextstream.h>
37#include <tqdom.h>
38
39#include <kdebug.h>
40#include <tdelocale.h>
41#include <kzip.h>
42
43#include <KoPageLayout.h>
44#include <KoPictureKey.h>
45#include <KoPicture.h>
46
47#include <KWEFStructures.h>
48#include <KWEFUtil.h>
49#include <KWEFBaseWorker.h>
50#include <KWEFKWordLeader.h>
51
52#include "ExportFilter.h"
53
54OOWriterWorker::OOWriterWorker(void) : m_streamOut(NULL),
55 m_paperBorderTop(0.0),m_paperBorderLeft(0.0),
56 m_paperBorderBottom(0.0),m_paperBorderRight(0.0), m_zip(NULL), m_pictureNumber(0),
57 m_automaticParagraphStyleNumber(0), m_automaticTextStyleNumber(0),
58 m_footnoteNumber(0), m_tableNumber(0), m_textBoxNumber( 0 ),
59 m_columnspacing( 36.0 ), m_columns( 1 )
60{
61}
62
63TQString OOWriterWorker::escapeOOText(const TQString& strText) const
64{
65 // Escape quotes (needed in attributes)
66 // Escape apostrophs (allowed by XML)
67 return KWEFUtil::EscapeSgmlText(NULL,strText,true,true);
68}
69
70TQString OOWriterWorker::escapeOOSpan(const TQString& strText) const
71// We need not only to escape the classical XML stuff but also to take care of spaces and tabs.
72{
73 TQString strReturn;
74 TQChar ch;
75 int spaceNumber = 0; // How many spaces should be written
76
77 for (uint i=0; i<strText.length(); i++)
78 {
79 ch=strText[i];
80
81 if (ch!=' ')
82 {
83 // The next character is not a space (anymore)
84 if ( spaceNumber > 0 )
85 {
86 strReturn += ' ';
87 --spaceNumber;
88 if ( spaceNumber > 0 )
89 {
90 strReturn += "<text:s text:c=\"";
91 strReturn += TQString::number( spaceNumber );
92 strReturn += "\"/>";
93 }
94 spaceNumber = 0;
95 }
96 }
97
98 // ### TODO: would be switch/case or if/elseif the best?
99 switch (ch.unicode())
100 {
101 case 9: // Tab
102 {
103 strReturn+="<text:tab-stop/>";
104 break;
105 }
106 case 10: // Line-feed
107 {
108 strReturn+="<text:line-break/>";
109 break;
110 }
111 case 32: // Space
112 {
113 if ( spaceNumber > 0 )
114 {
115 ++spaceNumber;
116 }
117 else
118 {
119 spaceNumber = 1;
120 }
121 break;
122 }
123 case 38: // &
124 {
125 strReturn+="&amp;";
126 break;
127 }
128 case 60: // <
129 {
130 strReturn+="&lt;";
131 break;
132 }
133 case 62: // >
134 {
135 strReturn+="&gt;";
136 break;
137 }
138 case 34: // "
139 {
140 strReturn+="&quot;";
141 break;
142 }
143 case 39: // '
144 {
145 strReturn+="&apos;";
146 break;
147 }
148 case 1: // (Non-XML-compatible) replacement character from KWord 0.8
149 {
150 strReturn += '#'; //use KWord 1.[123] replacement character instead
151 break;
152 }
153 // Following characters are not allowed in XML (but some files from KWord 0.8 have some of them.)
154 case 0:
155 case 2:
156 case 3:
157 case 4:
158 case 5:
159 case 6:
160 case 7:
161 case 8:
162 case 11:
163 case 12:
164 case 14:
165 case 15:
166 case 16:
167 case 17:
168 case 18:
169 case 19:
170 case 20:
171 case 21:
172 case 22:
173 case 23:
174 case 24:
175 case 25:
176 case 26:
177 case 27:
178 case 28:
179 case 29:
180 case 30:
181 case 31:
182 {
183 kdWarning(30518) << "Not allowed XML character: " << ch.unicode() << endl;
184 strReturn += '?';
185 break;
186 }
187 case 13: // ### TODO: what to do with it?
188 default:
189 {
190 strReturn+=ch;
191 break;
192 }
193 }
194 }
195
196 if ( spaceNumber > 0 )
197 {
198 // The last characters were spaces
199 strReturn += ' ';
200 --spaceNumber;
201 if ( spaceNumber > 0 )
202 {
203 strReturn += "<text:s text:c=\"";
204 strReturn += TQString::number( spaceNumber );
205 strReturn += "\"/>";
206 }
207 spaceNumber = 0;
208 }
209
210 return strReturn;
211}
212
213bool OOWriterWorker::doOpenFile(const TQString& filenameOut, const TQString& )
214{
215 kdDebug(30518) << "Opening file: " << filenameOut
216 << " (in OOWriterWorker::doOpenFile)" << endl;
217
218 m_zip=new KZip(filenameOut); // How to check failure?
219
220 if (!m_zip->open(IO_WriteOnly))
221 {
222 kdError(30518) << "Could not open ZIP file for writing! Aborting!" << endl;
223 delete m_zip;
224 m_zip=NULL;
225 return false;
226 }
227
228 m_zip->setCompression( KZip::NoCompression );
229 m_zip->setExtraField( KZip::NoExtraField );
230
231 const TQCString appId( "application/vnd.sun.xml.writer" );
232
233 m_zip->writeFile( "mimetype", TQString(), TQString(), appId.length(), appId.data() );
234
235 m_zip->setCompression( KZip::DeflateCompression );
236
237 m_streamOut=new TQTextStream(m_contentBody, IO_WriteOnly);
238
239 m_streamOut->setEncoding( TQTextStream::UnicodeUTF8 );
240
241 return true;
242}
243
244bool OOWriterWorker::zipPrepareWriting(const TQString& name)
245{
246 if (!m_zip)
247 return false;
248 m_size=0;
249 return m_zip->prepareWriting(name, TQString(), TQString(), 0);
250}
251
252bool OOWriterWorker::zipDoneWriting(void)
253{
254 if (!m_zip)
255 return false;
256 return m_zip->doneWriting(m_size);
257}
258
259bool OOWriterWorker::zipWriteData(const char* str)
260{
261 if (!m_zip)
262 return false;
263 const uint size=strlen(str);
264 m_size+=size;
265 return m_zip->writeData(str,size);
266}
267
268bool OOWriterWorker::zipWriteData(const TQByteArray& array)
269{
270 if (!m_zip)
271 return false;
272 const uint size=array.size();
273 m_size+=size;
274 return m_zip->writeData(array.data(),size);
275}
276
277bool OOWriterWorker::zipWriteData(const TQCString& cstr)
278{
279 if (!m_zip)
280 return false;
281 const uint size=cstr.length();
282 m_size+=size;
283 return m_zip->writeData(cstr.data(),size);
284}
285
286bool OOWriterWorker::zipWriteData(const TQString& str)
287{
288 return zipWriteData(str.utf8());
289}
290
291void OOWriterWorker::writeStartOfFile(const TQString& type)
292{
293 const bool noType=type.isEmpty();
294 zipWriteData("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
295
296 zipWriteData("<!DOCTYPE office:document");
297 if (!noType)
298 {
299 // No type might happen for raw XML documents (which this filter does not support yet.)
300 zipWriteData("-");
301 zipWriteData(type);
302 }
303 zipWriteData(" PUBLIC \"-//OpenOffice.org//DTD OfficeDocument 1.0//EN\"");
304 zipWriteData(" \"office.dtd\"");
305 zipWriteData(">\n");
306
307 zipWriteData("<office:document");
308 if (!noType)
309 {
310 zipWriteData("-");
311 zipWriteData(type);
312 }
313
314 // The name spaces used by OOWriter (those not used by this filter are commented out)
315
316 // General namespaces
317 zipWriteData(" xmlns:office=\"http://openoffice.org/2000/office\"");
318 zipWriteData(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
319
320 // Namespaces for context.xml and style.xml
321 if ( type == "content" || type == "styles" || type.isEmpty() )
322 {
323 zipWriteData(" xmlns:style=\"http://openoffice.org/2000/style\"");
324 zipWriteData(" xmlns:text=\"http://openoffice.org/2000/text\"");
325 zipWriteData(" xmlns:table=\"http://openoffice.org/2000/table\"");
326 zipWriteData(" xmlns:draw=\"http://openoffice.org/2000/drawing\"");
327 zipWriteData(" xmlns:fo=\"http://www.w3.org/1999/XSL/Format\"");
328
329 //zipWriteData(" xmlns:number=\"http://openoffice.org/2000/datastyle\"");
330 zipWriteData(" xmlns:svg=\"http://www.w3.org/2000/svg\"");
331 //zipWriteData(" xmlns:chart=\"http://openoffice.org/2000/chart\"");
332 //zipWriteData(" xmlns:dr3d=\"http://openoffice.org/2000/dr3d\"");
333 //zipWriteData(" xmlns:math=\"http://www.w3.org/1998/Math/MathML"");
334 //zipWriteData(" xmlns:form=\"http://openoffice.org/2000/form\"");
335 //zipWriteData(" xmlns:script=\"http://openoffice.org/2000/script\"");
336 }
337
338 // Namespaces For meta.xml
339 if ( type == "meta" || type.isEmpty() )
340 {
341 zipWriteData(" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"");
342 zipWriteData(" xmlns:meta=\"http://openoffice.org/2000/meta\"");
343 }
344
345 zipWriteData(" office:class=\"text\"");
346
347
348#ifdef STRICT_OOWRITER_VERSION_1
349 zipWriteData(" office:version=\"1.0\"");
350#else
351 // We are using an (rejected draft OASIS) extension compared to version 1.0, so we cannot write the version string.
352 // (We do not even write it for context.xml and meta.xml, as OOWriter 1.0.1 does not like it in this case.)
353#endif
354
355 zipWriteData(">\n");
356}
357
358void OOWriterWorker::writeFontDeclaration(void)
359{
360 zipWriteData( " <office:font-decls>\n");
361 TQMap<TQString,TQString>::ConstIterator end(m_fontNames.end());
362 for (TQMap<TQString,TQString>::ConstIterator it=m_fontNames.begin(); it!=end; ++it)
363 {
364 const bool space=(it.key().find(' ')>=0); // Does the font has at least a space in its name
365 const TQString fontName(escapeOOText(it.key()));
366 zipWriteData(" <style:font-decl style:name=\"");
367 zipWriteData(fontName);
368 zipWriteData("\" fo:font-family=\"");
369 if (space)
370 { // It has a space, so (simple) quote it
371 zipWriteData("&apos;");
372 zipWriteData(fontName);
373 zipWriteData("&apos;");
374 }
375 else
376 { // The font has no space in its name, so it can be written normally.
377 zipWriteData(fontName);
378 }
379 zipWriteData("\" ");
380 zipWriteData(it.data()); // already in XML, so do not escape
381 zipWriteData(" />\n");
382 }
383 zipWriteData(" </office:font-decls>\n");
384}
385
386void OOWriterWorker::writeStylesXml(void)
387{
388 if (!m_zip)
389 return;
390
391 zipPrepareWriting("styles.xml");
392
393 writeStartOfFile("styles");
394
395 writeFontDeclaration();
396
397 zipWriteData(m_styles);
398
399 zipWriteData(" <office:automatic-styles>\n");
400 zipWriteData(" <style:page-master style:name=\"pm1\">\n"); // ### TODO: verify if style name is unique
401
402 zipWriteData(" <style:properties ");
403 zipWriteData( " style:page-usage=\"all\"" ); // ### TODO: check
404
405 zipWriteData(" fo:page-width=\"");
406 zipWriteData(TQString::number(m_paperWidth));
407 zipWriteData("pt\" fo:page-height=\"");
408 zipWriteData(TQString::number(m_paperHeight));
409 zipWriteData("pt\" ");
410
411 zipWriteData("style:print-orientation=\"");
412 if (1==m_paperOrientation)
413 {
414 zipWriteData("landscape");
415 }
416 else
417 {
418 zipWriteData("portrait");
419 }
420
421 zipWriteData("\" fo:margin-top=\"");
422 zipWriteData(TQString::number(m_paperBorderTop));
423 zipWriteData("pt\" fo:margin-bottom=\"");
424 zipWriteData(TQString::number(m_paperBorderBottom));
425 zipWriteData("pt\" fo:margin-left=\"");
426 zipWriteData(TQString::number(m_paperBorderLeft));
427 zipWriteData("pt\" fo:margin-right=\"");
428 zipWriteData(TQString::number(m_paperBorderRight));
429 zipWriteData("pt\" style:first-page-number=\"");
430 zipWriteData(TQString::number(m_varSet.startingPageNumber));
431 zipWriteData( "\">\n" );
432
433 if ( m_columns > 1 )
434 {
435 zipWriteData( " <style:columns" );
436 zipWriteData( " fo:column-count=\"" );
437 zipWriteData( TQString::number( m_columns ) );
438 zipWriteData( "\" fo:column-gap=\"" );
439 zipWriteData( TQString::number( m_columnspacing ) );
440 zipWriteData( "pt\">\n" );
441
442 for (int i=0; i < m_columns; ++i)
443 {
444 zipWriteData( " <style:column style:rel-width=\"1*\" fo:margin-left=\"0cm\" fo:margin-right=\"0cm\"/>\n" );
445 }
446
447 zipWriteData( " </style:columns>\n" );
448 }
449
450 zipWriteData(" </style:properties>\n");
451
452 zipWriteData(" </style:page-master>\n");
453 zipWriteData(" </office:automatic-styles>\n");
454
455 zipWriteData(" <office:master-styles>\n");
456 zipWriteData(" <style:master-page style:name=\"Standard\" style:page-master-name=\"pm1\" />\n");
457 zipWriteData(" </office:master-styles>\n");
458
459 zipWriteData( "</office:document-styles>\n" );
460
461 zipDoneWriting();
462}
463
464void OOWriterWorker::writeContentXml(void)
465{
466 if (!m_zip)
467 return;
468
469 zipPrepareWriting("content.xml");
470
471 writeStartOfFile("content");
472
473 writeFontDeclaration();
474
475 zipWriteData(" <office:automatic-styles>\n");
476 zipWriteData(m_contentAutomaticStyles);
477 m_contentAutomaticStyles = TQString(); // Release memory
478
479 zipWriteData(" </office:automatic-styles>\n");
480
481 zipWriteData(m_contentBody);
482 m_contentBody.resize( 0 ); // Release memory
483
484 zipWriteData( "</office:document-content>\n" );
485
486 zipDoneWriting();
487}
488
489void OOWriterWorker::writeMetaXml(void)
490{
491 if (!m_zip)
492 return;
493
494 zipPrepareWriting("meta.xml");
495
496 writeStartOfFile("meta");
497
498 zipWriteData(" <office:meta>\n");
499
500 // Tell who we are in case that we have a bug in our filter output!
501 zipWriteData(" <meta:generator>KWord's OOWriter Export Filter");
502 zipWriteData(TQString("$Revision: 515673 $").mid(10).remove('$')); // has a leading and a trailing space.
503
504 zipWriteData("</meta:generator>\n");
505
506 if (!m_docInfo.title.isEmpty())
507 {
508 zipWriteData(" <dc:title>");
509 zipWriteData(escapeOOText(m_docInfo.title));
510 zipWriteData("</dc:title>\n");
511 }
512 if (!m_docInfo.abstract.isEmpty())
513 {
514 zipWriteData(" <dc:description>");
515 zipWriteData(escapeOOText(m_docInfo.abstract));
516 zipWriteData("</dc:description>\n");
517 }
518
519 if (m_varSet.creationTime.isValid())
520 {
521 zipWriteData(" <meta:creation-date>");
522 zipWriteData(escapeOOText(m_varSet.creationTime.toString(TQt::ISODate)));
523 zipWriteData("</meta:creation-date>\n");
524 }
525
526 if (m_varSet.modificationTime.isValid())
527 {
528 zipWriteData(" <dc:date>");
529 zipWriteData(escapeOOText(m_varSet.modificationTime.toString(TQt::ISODate)));
530 zipWriteData("</dc:date>\n");
531 }
532
533 if (m_varSet.printTime.isValid())
534 {
535 zipWriteData(" <meta:print-date>");
536 zipWriteData(escapeOOText(m_varSet.printTime.toString(TQt::ISODate)));
537 zipWriteData("</meta:print-date>\n");
538 }
539
540 zipWriteData( " <meta:document-statistic" );
541
542 // KWord files coming from import filters mostly do not have no page count
543 if ( m_numPages > 0 )
544 {
545 zipWriteData( " meta:page-count=\"" );
546 zipWriteData( TQString::number ( m_numPages ) );
547 zipWriteData( "\"" );
548 }
549
550 zipWriteData( " meta:image-count=\"" ); // This is not specified in the OO specification section 2.1.19
551 zipWriteData( TQString::number ( m_pictureNumber ) );
552 zipWriteData( "\"" );
553
554 zipWriteData( " meta:table-count=\"" );
555 zipWriteData( TQString::number ( m_tableNumber ) );
556 zipWriteData( "\"" );
557
558 zipWriteData( "/>\n" ); // meta:document-statistic
559
560 zipWriteData(" </office:meta>\n");
561 zipWriteData("</office:document-meta>\n");
562
563 zipDoneWriting();
564}
565
566bool OOWriterWorker::doCloseFile(void)
567{
568 kdDebug(30518)<< "OOWriterWorker::doCloseFile" << endl;
569 if (m_zip)
570 {
571 writeContentXml();
572 writeMetaXml();
573 writeStylesXml();
574 m_zip->close();
575 }
576
577 delete m_zip;
578 m_zip=NULL;
579 return true;
580}
581
582bool OOWriterWorker::doOpenDocument(void)
583{
584 kdDebug(30518)<< "OOWriterWorker::doOpenDocument" << endl;
585
586 *m_streamOut << " <office:body>\n";
587
588 return true;
589}
590
591bool OOWriterWorker::doCloseDocument(void)
592{
593 *m_streamOut << " </office:body>\n";
594 return true;
595}
596
597bool OOWriterWorker::doOpenBody(void)
598{
599 TQValueList<FrameAnchor>::Iterator it;
600
601 // We have to process all non-inline pictures
602 kdDebug(30518) << "=== Processing non-inlined pictures ===" << endl;
603 for ( it = m_nonInlinedPictureAnchors.begin(); it != m_nonInlinedPictureAnchors.end(); ++it )
604 {
605 *m_streamOut << " ";
606 makePicture( *it, AnchorNonInlined );
607 *m_streamOut << "\n";
608 }
609 kdDebug(30518) << "=== Non-inlined pictures processed ===" << endl;
610
611 // We have to process all non-inline tables
612 kdDebug(30518) << "=== Processing non-inlined tables ===" << endl;
613 for ( it = m_nonInlinedTableAnchors.begin(); it != m_nonInlinedTableAnchors.end(); ++it )
614 {
615 *m_streamOut << " ";
616 makeTable( *it, AnchorNonInlined );
617 *m_streamOut << "\n";
618 }
619 kdDebug(30518) << "=== Non-inlined tables processed ===" << endl;
620
621 return true;
622}
623
624TQString OOWriterWorker::textFormatToStyle(const TextFormatting& formatOrigin,
625 const TextFormatting& formatData, const bool force, TQString& key)
626{
627 // TODO: rename variable formatData
628 TQString strElement; // TODO: rename this variable
629
630 // Font name
631 TQString fontName = formatData.fontName;
632 declareFont(fontName);
633 if ( !fontName.isEmpty()
634 && (force || (formatOrigin.fontName!=formatData.fontName)))
635 {
636 strElement+="style:font-name=\"";
637 strElement+= escapeOOText(fontName);
638 strElement+="\" ";
639 key += fontName;
640 }
641
642 key += ",";
643
644 if (force || (formatOrigin.italic!=formatData.italic))
645 {
646 // Font style
647 strElement+="fo:font-style=\"";
648 if ( formatData.italic )
649 {
650 strElement+="italic";
651 key+='I';
652 }
653 else
654 {
655 strElement+="normal";
656 key+='N';
657 }
658 strElement+="\" ";
659 }
660
661 key += ",";
662
663 if (force || ((formatOrigin.weight>=75)!=(formatData.weight>=75)))
664 {
665 strElement+="fo:font-weight=\"";
666 if ( formatData.weight >= 75 )
667 {
668 strElement+="bold";
669 key+='B';
670 }
671 else
672 {
673 strElement+="normal";
674 key+='N';
675 }
676 strElement+="\" ";
677 }
678
679 key += ",";
680
681 if (force || (formatOrigin.fontSize!=formatData.fontSize))
682 {
683 const int size=formatData.fontSize;
684 if (size>0)
685 {
686 strElement+="fo:font-size=\"";
687 strElement+=TQString::number(size,10);
688 strElement+="pt\" ";
689 key+=TQString::number(size,10);
690 }
691 }
692
693 key += ",";
694
695 if (force || (formatOrigin.fgColor!=formatData.fgColor))
696 {
697 if ( formatData.fgColor.isValid() )
698 {
699 strElement+="fo:color=\"";
700 strElement+=formatData.fgColor.name();
701 strElement+="\" ";
702 key+=formatData.fgColor.name();
703 }
704 }
705
706 key += ",";
707
708 if (force || (formatOrigin.bgColor!=formatData.bgColor))
709 {
710 if ( formatData.bgColor.isValid() )
711 {
712 strElement+="style:text-background-color=\""; // ### what is fo:background-color ?
713 strElement+=formatData.bgColor.name();
714 strElement+="\" ";
715 key+=formatData.bgColor.name();
716 }
717 }
718
719 key += ';'; // Another separator
720
721 if ( force || ( formatOrigin.underline != formatData.underline )
722 || ( formatOrigin.underlineColor != formatData.underlineColor )
723 || ( formatOrigin.underlineValue != formatData.underlineValue )
724 || ( formatOrigin.underlineStyle != formatData.underlineStyle ) )
725 {
726 strElement+="style:text-underline=\"";
727 if ( formatData.underline )
728 {
729 TQString underlineValue ( formatData.underlineValue );
730 TQString underlineStyle ( formatData.underlineStyle );
731
732 if ( underlineStyle.isEmpty() )
733 underlineStyle = "solid";
734 if ( underlineValue == "1" )
735 underlineValue = "single";
736
737 if ( underlineValue == "single" )
738 {
739 if ( underlineStyle == "dash" )
740 {
741 strElement += "dash";
742 key += "DA";
743 }
744 else if ( underlineStyle == "dot" )
745 {
746 strElement += "dotted";
747 key += "DO";
748 }
749 else if ( underlineStyle == "dashdot" )
750 {
751 strElement += "dot-dash";
752 key += "DDA";
753 }
754 else if ( underlineStyle == "dashdotdot" )
755 {
756 strElement += "dot-dot-dash";
757 key += "DDDA";
758 }
759 else
760 {
761 strElement += "single";
762 key += "1";
763 }
764 }
765 else if ( underlineValue == "double" )
766 {
767 strElement += "double";
768 key += "2";
769 }
770 else if ( underlineValue == "single-bold" )
771 {
772 strElement += "bold";
773 key += "BL";
774 }
775 else if ( underlineValue == "wave" )
776 {
777 strElement += "wave";
778 key += "WV";
779 }
780 else
781 {
782 strElement += "single";
783 key += "?";
784 }
785 }
786 else
787 {
788 strElement+="none";
789 key += 'N';
790 }
791 strElement += "\" ";
792
793 if ( formatData.underline && formatData.underlineColor.isValid() )
794 {
795 const TQString colorName( formatData.underlineColor.name() );
796 strElement += "style:text-underline-color=\"";
797 strElement += colorName;
798 strElement += "\" ";
799 key += colorName;
800 }
801
802 }
803
804 key += ',';
805
806 if ( force
807 || (formatOrigin.strikeout != formatData.strikeout )
808 || (formatOrigin.strikeoutType != formatData.strikeoutType ) )
809 {
810 // OOWriter can only do single, double, thick (and slash and X that KWord cannot do.)
811 // So no dash, dot and friends.
812
813 strElement+="style:text-crossing-out=\"";
814 if ( ( formatData.strikeoutType == "single" ) || ( formatData.strikeoutType == "1" ) )
815 {
816 strElement+="single-line";
817 key += "1";
818 }
819 else if ( formatData.strikeoutType == "double" )
820 {
821 strElement+="double-line";
822 key += "2";
823 }
824 else if ( formatData.strikeoutType == "single-bold" )
825 {
826 strElement+="thick";
827 key += "T";
828 }
829 else
830 {
831 strElement+="none";
832 key += 'N';
833 }
834 strElement+="\" ";
835 }
836
837 key += ',';
838
839 // It seems that OOWriter 1.1 does have problems with word-by-word (OO Issue #11873, #25187)
840 // It is supposed to be fixed in development versions of OO
841 if (force || ( formatOrigin.underlineWord != formatData.underlineWord )
842 || (formatOrigin.strikeoutWord != formatData.strikeoutWord ) )
843 {
844 // Strikeout and underline can only have one word-by-word behaviour in OO
845 // (OO Issue #????? ; will not be changed.)
846 strElement+="fo:score-spaces=\""; // Are space processed?
847 if ( formatData.underlineWord || formatData.strikeoutWord )
848 {
849 strElement += "false";
850 key += 'W';
851 }
852 else
853 {
854 strElement += "true";
855 key += 'N';
856 }
857 strElement += "\" ";
858 }
859
860 key += ',';
861
862 if ( force || ( formatOrigin.language != formatData.language ) )
863 {
864 const TQString lang ( formatData.language );
865 if ( ! lang.isEmpty() )
866 {
867 const int res = lang.find( '_' );
868
869 if ( res >= 0 )
870 {
871 kdDebug(30518) << "Language: " << lang << " => " << lang.left( res ) << " - " << lang.mid( res + 1 ) << endl;
872 strElement += "fo:language=\"";
873 strElement += lang.left( res );
874 strElement += "\" ";
875 strElement += "fo:country=\"";
876 strElement += lang.mid( res + 1 );
877 strElement += "\" ";
878 }
879 else
880 {
881 kdDebug(30518) << "Language without country: " << lang << endl;
882 strElement += "fo:language=\"";
883 strElement += lang;
884 strElement += "\" ";
885 }
886
887 key+=formatData.language;
888 }
889 }
890
891 key += ",";
892
893 if ( force || ( formatOrigin.fontAttribute != formatData.fontAttribute ) )
894 {
895 // Note: OOWriter does not like when both fo:text-transform and fo:font-variant exist (except if both are none/normal)
896 // (It is documented so, see sections 3.10.1 and 3.10.2)
897 if ( formatData.fontAttribute == "uppercase" )
898 {
899 strElement += "fo:text-transform=\"uppercase\" ";
900 key += 'U';
901 }
902 else if ( formatData.fontAttribute == "lowercase" )
903 {
904 strElement += "fo:text-transform=\"lowercase\" ";
905 key += 'L';
906 }
907 else if ( formatData.fontAttribute == "smallcaps" )
908 {
909 strElement += "fo:font-variant=\"small-caps\" ";
910 key += 'S';
911 }
912 else
913 {
914 strElement += "fo:text-transform=\"none\" ";
915 strElement += "fo:font-variant=\"normal\" ";
916 key += 'N';
917 }
918 }
919
920 key += ",";
921
922 if ( force || ( formatOrigin.verticalAlignment != formatData.verticalAlignment ) )
923 {
924 if ( 1 == formatData.verticalAlignment )
925 {
926 //Subscript
927 strElement += "style:text-position=\"sub\" ";
928 key += 'B';
929 }
930 else if ( 2 == formatData.verticalAlignment )
931 {
932 //Superscript
933 strElement += "style:text-position=\"super\" ";
934 key += 'P';
935 }
936 // ### TODO: how to reset it? "0pt" ?
937 }
938
939 return strElement.stripWhiteSpace(); // Remove especially trailing spaces
940}
941
942#define ALLOW_TABLE
943
944TQString OOWriterWorker::cellToProperties( const TableCell& cell, TQString& key) const
945{
946#ifdef ALLOW_TABLE
947 const FrameData& frame = cell.frame;
948 TQString properties;
949
950 key += "!L"; // left border
951 key += frame.lColor.name();
952 key += ",";
953 key += TQString::number( frame.lWidth );
954 properties += " fo:border-left=\"";
955 if ( frame.lColor.isValid() && frame.lWidth > 0.0 )
956 {
957 properties += TQString::number( frame.lWidth );
958 properties += "pt";
959 properties += " solid "; // ### TODO
960 properties += frame.lColor.name();
961 }
962 else
963 {
964 properties += "0pt none #000000";
965 }
966 properties += "\"";
967
968 key += "!R"; // right border
969 key += frame.rColor.name();
970 key += ",";
971 key += TQString::number( frame.rWidth );
972 properties += " fo:border-right=\"";
973 if ( frame.rColor.isValid() && frame.rWidth > 0.0 )
974 {
975 properties += TQString::number( frame.rWidth );
976 properties += "pt";
977 properties += " solid "; // ### TODO
978 properties += frame.rColor.name();
979 }
980 else
981 {
982 properties += "0pt none #000000";
983 }
984 properties += "\"";
985
986 key += "!T"; // top border
987 key += frame.tColor.name();
988 key += ",";
989 key += TQString::number( frame.tWidth );
990 properties += " fo:border-top=\"";
991 if ( frame.tColor.isValid() && frame.tWidth > 0.0 )
992 {
993 properties += TQString::number( frame.tWidth );
994 properties += "pt";
995 properties += " solid "; // ### TODO
996 properties += frame.tColor.name();
997 }
998 else
999 {
1000 properties += "0pt none #000000";
1001 }
1002 properties += "\"";
1003
1004 key += "!B"; // bottom border
1005 key += frame.bColor.name();
1006 key += ",";
1007 key += TQString::number( frame.bWidth );
1008 properties += " fo:border-bottom=\"";
1009 if ( frame.bColor.isValid() && frame.bWidth > 0.0 )
1010 {
1011 properties += TQString::number( frame.bWidth );
1012 properties += "pt";
1013 properties += " solid "; // ### TODO
1014 properties += frame.bColor.name();
1015 }
1016 else
1017 {
1018 properties += "0pt none #000000";
1019 }
1020 properties += "\"";
1021
1022 return properties;
1023#else
1024 return TQString();
1025#endif
1026}
1027
1028bool OOWriterWorker::makeTableRows( const TQString& tableName, const Table& table, int firstRowNumber )
1029{
1030#ifdef ALLOW_TABLE
1031 // ### TODO: rows
1032 // ### TODO: be careful that covered-cell can be due vertical spanning.
1033 // ### TODO: One way to find is the difference between the row variables (or against the last known column)
1034 // ### TODO: be careful that fully-covered rows might exist.
1035
1036 *m_streamOut << "<table:table-row>\n";
1037 int rowCurrent = firstRowNumber;
1038
1039 ulong cellNumber = 0L;
1040
1041 TQMap<TQString,TQString> mapCellStyleKeys;
1042
1043 for ( TQValueList<TableCell>::ConstIterator itCell ( table.cellList.begin() );
1044 itCell != table.cellList.end(); ++itCell)
1045 {
1046 if ( rowCurrent != (*itCell).row )
1047 {
1048 rowCurrent = (*itCell).row;
1049 *m_streamOut << "</table:table-row>\n";
1050 *m_streamOut << "<table:table-row>\n";
1051 }
1052
1053 TQString key;
1054 const TQString props ( cellToProperties( (*itCell), key ) );
1055
1056 TQString automaticCellStyle;
1057 TQMap<TQString,TQString>::ConstIterator it ( mapCellStyleKeys.find( key ) );
1058 if ( it == mapCellStyleKeys.end() )
1059 {
1060 automaticCellStyle = makeAutomaticStyleName( tableName + ".Cell", cellNumber );
1061 mapCellStyleKeys [ key ] = automaticCellStyle;
1062 kdDebug(30518) << "Creating automatic cell style: " << automaticCellStyle << " key: " << key << endl;
1063 m_contentAutomaticStyles += " <style:style";
1064 m_contentAutomaticStyles += " style:name=\"" + escapeOOText( automaticCellStyle ) + "\"";
1065 m_contentAutomaticStyles += " style:family=\"table-cell\"";
1066 m_contentAutomaticStyles += ">\n";
1067 m_contentAutomaticStyles += " <style:properties ";
1068 m_contentAutomaticStyles += props;
1069 m_contentAutomaticStyles += "/>\n";
1070 m_contentAutomaticStyles += " </style:style>\n";
1071 }
1072 else
1073 {
1074 automaticCellStyle = it.data();
1075 kdDebug(30518) << "Using automatic cell style: " << automaticCellStyle << " key: " << key << endl;
1076 }
1077
1078 *m_streamOut << "<table:table-cell table:value-type=\"string\" table:style-name=\""
1079 << escapeOOText( automaticCellStyle)
1080 << "\"";
1081
1082 // More than one column width?
1083 {
1084 *m_streamOut << " table:number-columns-spanned=\"" << (*itCell).m_cols << "\"";
1085 }
1086
1087 *m_streamOut << ">\n";
1088
1089 if (!doFullAllParagraphs(*(*itCell).paraList))
1090 {
1091 return false;
1092 }
1093
1094 *m_streamOut << "</table:table-cell>\n";
1095
1096 if ( (*itCell).m_cols > 1 )
1097 {
1098 // We need to add some placeholder for the "covered" cells
1099 for (int i = 1; i < (*itCell).m_cols; ++i)
1100 {
1101 *m_streamOut << "<table:covered-table-cell/>";
1102 }
1103 }
1104 }
1105
1106 *m_streamOut << "</table:table-row>\n";
1107 return true;
1108#else
1109 return false;
1110#endif
1111}
1112
1113#ifdef ALLOW_TABLE
1114static uint getColumnWidths( const Table& table, TQMemArray<double>& widthArray, int firstRowNumber )
1115{
1116 bool uniqueColumns = true; // We have not found any horizontally spanned cells yet.
1117 uint currentColumn = 0;
1118 int tryingRow = firstRowNumber; // We are trying the first row
1119 TQValueList<TableCell>::ConstIterator itCell;
1120
1121 for ( itCell = table.cellList.begin();
1122 itCell != table.cellList.end(); ++itCell )
1123 {
1124 kdDebug(30518) << "Column: " << (*itCell).col << " (Row: " << (*itCell).row << ")" << endl;
1125
1126 if ( (*itCell).row != tryingRow )
1127 {
1128 if ( uniqueColumns )
1129 {
1130 // We had a full row without any horizontally spanned cell, so we have the needed data
1131 return currentColumn;
1132 }
1133 else
1134 {
1135 // No luck in the previous row, so now try this new one
1136 tryingRow = (*itCell).row;
1137 uniqueColumns = true;
1138 currentColumn = 0;
1139 }
1140 }
1141
1142 if ( (*itCell).m_cols > 1 )
1143 {
1144 // We have a horizontally spanned cell
1145 uniqueColumns = false;
1146 // Do not waste the time to calculate the width
1147 continue;
1148 }
1149
1150 const double width = ( (*itCell).frame.right - (*itCell).frame.left );
1151
1152 if ( currentColumn >= widthArray.size() )
1153 widthArray.resize( currentColumn + 4, TQGArray::SpeedOptim);
1154
1155 widthArray.at( currentColumn ) = width;
1156 ++currentColumn;
1157 }
1158
1159 // If we are here, it can be:
1160 // - the table is either empty or there is not any row without horizontally spanned cells
1161 // - we have needed the last row for getting something usable
1162
1163 return uniqueColumns ? currentColumn : 0;
1164}
1165#endif
1166
1167#ifdef ALLOW_TABLE
1168static uint getFirstRowColumnWidths( const Table& table, TQMemArray<double>& widthArray, int firstRowNumber )
1169// Get the column widths only by the first row.
1170// This is used when all table rows have horizontally spanned cells.
1171{
1172 uint currentColumn = 0;
1173 TQValueList<TableCell>::ConstIterator itCell;
1174
1175 for ( itCell = table.cellList.begin();
1176 itCell != table.cellList.end(); ++itCell )
1177 {
1178 kdDebug(30518) << "Column: " << (*itCell).col << " (Row: " << (*itCell).row << ")" << endl;
1179 if ( (*itCell).row != firstRowNumber )
1180 break; // We have finished the first row
1181
1182 int cols = (*itCell).m_cols;
1183 if ( cols < 1)
1184 cols = 1;
1185
1186 // ### FIXME: the columns behind a larger cell do not need to be symmetrical
1187 const double width = ( (*itCell).frame.right - (*itCell).frame.left ) / cols;
1188
1189 if ( currentColumn + cols > widthArray.size() )
1190 widthArray.resize( currentColumn + 4, TQGArray::SpeedOptim);
1191
1192 for ( int i = 0; i < cols; ++i )
1193 {
1194 widthArray.at( currentColumn ) = width;
1195 ++currentColumn;
1196 }
1197 }
1198 return currentColumn;
1199}
1200#endif
1201
1202bool OOWriterWorker::makeTable( const FrameAnchor& anchor, const AnchorType anchorType )
1203{
1204#ifdef ALLOW_TABLE
1205
1206 // Be careful that while being similar the following 5 strings have different purposes
1207 const TQString automaticTableStyle ( makeAutomaticStyleName( "Table", m_tableNumber ) ); // It also increases m_tableNumber
1208 const TQString tableName( TQString( "Table" ) + TQString::number( m_tableNumber ) ); // m_tableNumber was already increased
1209 const TQString translatedName( i18n( "Object name", "Table %1").arg( m_tableNumber ) );
1210 const TQString automaticFrameStyle ( makeAutomaticStyleName( "TableFrame", m_textBoxNumber ) ); // It also increases m_textBoxNumber
1211 const TQString translatedFrameName( i18n( "Object name", "Table Frame %1").arg( m_textBoxNumber ) );
1212
1213 kdDebug(30518) << "Processing table " << anchor.key.toString() << " => " << tableName << endl;
1214
1215 const TQValueList<TableCell>::ConstIterator firstCell ( anchor.table.cellList.begin() );
1216
1217 if ( firstCell == anchor.table.cellList.end() )
1218 {
1219 kdError(30518) << "Table has not any cell!" << endl;
1220 return false;
1221 }
1222
1223 const int firstRowNumber = (*firstCell).row;
1224 kdDebug(30518) << "First row: " << firstRowNumber << endl;
1225
1226 TQMemArray<double> widthArray(4);
1227
1228 uint numberColumns = getColumnWidths( anchor.table, widthArray, firstRowNumber );
1229
1230 if ( numberColumns <= 0 )
1231 {
1232 kdDebug(30518) << "Could not get correct column widths, so approximating" << endl;
1233 // There was a problem, the width array cannot be trusted, so try to do a column width array with the first row
1234 numberColumns = getFirstRowColumnWidths( anchor.table, widthArray, firstRowNumber );
1235 if ( numberColumns <= 0 )
1236 {
1237 // Still not right? Then it is an error!
1238 kdError(30518) << "Cannot get column widths of table " << anchor.key.toString() << endl;
1239 return false;
1240 }
1241 }
1242
1243 kdDebug(30518) << "Number of columns: " << numberColumns << endl;
1244
1245
1246 double tableWidth = 0.0; // total width of table
1247 uint i; // We need the loop variable 2 times
1248 for ( i=0; i < numberColumns; ++i )
1249 {
1250 tableWidth += widthArray.at( i );
1251 }
1252 kdDebug(30518) << "Table width: " << tableWidth << endl;
1253
1254 // An inlined table, is an "as-char" text-box
1255 *m_streamOut << "<draw:text-box";
1256 *m_streamOut << " style:name=\"" << escapeOOText( automaticFrameStyle ) << "\"";
1257 *m_streamOut << " draw:name=\"" << escapeOOText( translatedFrameName ) << "\"";
1258 if ( anchorType == AnchorNonInlined )
1259 {
1260 // ### TODO: correctly set a OOWriter frame positioned on the page
1261 *m_streamOut << " text:anchor-type=\"paragraph\"";
1262 }
1263 else
1264 {
1265 *m_streamOut << " text:anchor-type=\"as-char\"";
1266 }
1267 *m_streamOut << " svg:width=\"" << tableWidth << "pt\""; // ### TODO: any supplement to the width?
1268 //*m_streamOut << " fo:min-height=\"1pt\"";// ### TODO: a better height (can be calulated from the KWord table frames)
1269 *m_streamOut << ">\n";
1270
1271 *m_streamOut << "<table:table table:name=\""
1272 << escapeOOText( translatedName )
1273 << "\" table:style-name=\""
1274 << escapeOOText( automaticTableStyle )
1275 << "\" >\n";
1276
1277
1278 // Now we have enough information to generate the style for the table and its frame
1279
1280 kdDebug(30518) << "Creating automatic frame style: " << automaticFrameStyle /* << " key: " << styleKey */ << endl;
1281 m_contentAutomaticStyles += " <style:style"; // for frame
1282 m_contentAutomaticStyles += " style:name=\"" + escapeOOText( automaticFrameStyle ) + "\"";
1283 m_contentAutomaticStyles += " style:family=\"graphics\"";
1284 m_contentAutomaticStyles += " style:parent-style-name=\"Frame\""; // ### TODO: parent style needs to be correctly defined
1285 m_contentAutomaticStyles += ">\n";
1286 m_contentAutomaticStyles += " <style:properties "; // ### TODO
1287 m_contentAutomaticStyles += " text:anchor-type=\"as-char\""; // ### TODO: needed?
1288 m_contentAutomaticStyles += " fo:padding=\"0pt\" fo:border=\"none\"";
1289 m_contentAutomaticStyles += " fo:margin-left=\"0pt\"";
1290 m_contentAutomaticStyles += " fo:margin-top=\"0pt\"";
1291 m_contentAutomaticStyles += " fo:margin-bottom=\"0pt\"";
1292 m_contentAutomaticStyles += " fo:margin-right=\"0pt\"";
1293 m_contentAutomaticStyles += "/>\n";
1294 m_contentAutomaticStyles += " </style:style>\n";
1295
1296 kdDebug(30518) << "Creating automatic table style: " << automaticTableStyle /* << " key: " << styleKey */ << endl;
1297 m_contentAutomaticStyles += " <style:style"; // for table
1298 m_contentAutomaticStyles += " style:name=\"" + escapeOOText( automaticTableStyle ) + "\"";
1299 m_contentAutomaticStyles += " style:family=\"table\"";
1300 m_contentAutomaticStyles += ">\n";
1301 m_contentAutomaticStyles += " <style:properties ";
1302 m_contentAutomaticStyles += " style:width=\"" + TQString::number( tableWidth ) + "pt\" ";
1303 m_contentAutomaticStyles += "/>\n";
1304 m_contentAutomaticStyles += " </style:style>\n";
1305
1306 TQValueList<TableCell>::ConstIterator itCell;
1307
1308 ulong columnNumber = 0L;
1309
1310 for ( i=0; i < numberColumns; ++i )
1311 {
1312 const TQString automaticColumnStyle ( makeAutomaticStyleName( tableName + ".Column", columnNumber ) );
1313 kdDebug(30518) << "Creating automatic column style: " << automaticColumnStyle /* << " key: " << styleKey */ << endl;
1314
1315 m_contentAutomaticStyles += " <style:style";
1316 m_contentAutomaticStyles += " style:name=\"" + escapeOOText( automaticColumnStyle ) + "\"";
1317 m_contentAutomaticStyles += " style:family=\"table-column\"";
1318 m_contentAutomaticStyles += ">\n";
1319 m_contentAutomaticStyles += " <style:properties ";
1320 // Despite that some OO specification examples use fo:width, OO specification section 4.19 tells to use style:column-width
1321 // and/or the relative variant: style:rel-column-width
1322 m_contentAutomaticStyles += " style:column-width=\"" + TQString::number( widthArray.at( i ) ) + "pt\" ";
1323 m_contentAutomaticStyles += "/>\n";
1324 m_contentAutomaticStyles += " </style:style>\n";
1325
1326 // ### TODO: find a way how to use table:number-columns-repeated for more that one cell's column(s)
1327 *m_streamOut << "<table:table-column table:style-name=\""
1328 << escapeOOText( automaticColumnStyle )
1329 << "\" table:number-columns-repeated=\"1\"/>\n";
1330 }
1331
1332 makeTableRows( tableName, anchor.table, firstRowNumber );
1333
1334 *m_streamOut << "</table:table>\n";
1335
1336 *m_streamOut << "</draw:text-box>"; // End of inline
1337
1338#endif
1339 return true;
1340}
1341
1342bool OOWriterWorker::makePicture( const FrameAnchor& anchor, const AnchorType anchorType )
1343{
1344 kdDebug(30518) << "New picture: " << anchor.picture.koStoreName
1345 << " , " << anchor.picture.key.toString() << endl;
1346
1347 const TQString koStoreName(anchor.picture.koStoreName);
1348
1349 TQByteArray image;
1350
1351 TQString strExtension(koStoreName.lower());
1352 const int result=koStoreName.findRev(".");
1353 if (result>=0)
1354 {
1355 strExtension=koStoreName.mid(result+1);
1356 }
1357
1358 bool isImageLoaded=false;
1359
1360 if (strExtension=="png")
1361 {
1362 isImageLoaded=loadSubFile(koStoreName,image);
1363 }
1364 else if ((strExtension=="jpg") || (strExtension=="jpeg"))
1365 {
1366 isImageLoaded=loadSubFile(koStoreName,image);
1367 strExtension="jpg"; // ### TODO: verify
1368 }
1369 else if ((strExtension=="tif") || (strExtension=="tiff"))
1370 {
1371 isImageLoaded=loadSubFile(koStoreName,image);
1372 strExtension="tif"; // ### TODO: verify
1373 }
1374 else if ((strExtension=="gif") || (strExtension=="wmf"))
1375 // ### TODO: Which other image formats does OOWriter support directly?
1376 {
1377 isImageLoaded=loadSubFile(koStoreName,image);
1378 }
1379 else
1380 {
1381 // All other picture types must be converted to PNG
1382 isImageLoaded=loadAndConvertToImage(koStoreName,strExtension,"PNG",image);
1383 strExtension="png";
1384 }
1385
1386 if (!isImageLoaded)
1387 {
1388 kdWarning(30518) << "Unable to load picture: " << koStoreName << endl;
1389 return true;
1390 }
1391
1392 kdDebug(30518) << "Picture loaded: " << koStoreName << endl;
1393
1394 double height = 0.0;
1395 double width = 0.0;
1396
1397 if ( anchorType == AnchorTextImage )
1398 {
1399 // Text image have no frameset, so the only size information is in the picture itself.
1400 TQBuffer buffer( image.copy() ); // Be more safe than sorry and do not allow shallow copy
1401 KoPicture pic;
1402 buffer.open( IO_ReadOnly );
1403 if ( pic.load( &buffer, strExtension ) )
1404 {
1405 const TQSize size ( pic.getOriginalSize() );
1406 height = size.height();
1407 width = size.width();
1408 }
1409 else
1410 {
1411 kdWarning(30518) << "Could not load KoPicture: " << koStoreName << endl;
1412 }
1413 buffer.close();
1414 }
1415 else
1416 {
1417 // Use frame size
1418 height=anchor.frame.bottom - anchor.frame.top;
1419 width =anchor.frame.right - anchor.frame.left;
1420 }
1421
1422 if ( height < 1.0 )
1423 {
1424 kdWarning(30518) << "Silly height for " << koStoreName << " : " << height << endl;
1425 height = 72.0;
1426 }
1427 if ( width < 1.0 )
1428 {
1429 kdWarning(30518) << "Silly width for " << koStoreName << " : " << width << endl;
1430 width = 72.0;
1431 }
1432
1433 // We need a 32 digit hex value of the picture number
1434 // Please note: it is an exact 32 digit value, truncated if the value is more than 512 bits wide. :-)
1435 TQString number;
1436 number.fill('0',32);
1437 number += TQString::number(++m_pictureNumber,16); // in hex
1438
1439 TQString ooName("Pictures/");
1440 ooName += number.right(32);
1441 ooName += '.';
1442 ooName += strExtension;
1443
1444 kdDebug(30518) << "Picture " << koStoreName << " => " << ooName << endl;
1445
1446 // TODO: we are only using the filename, not the rest of the key
1447 // TODO: (bad if there are two images of the same name, but of a different key)
1448 *m_streamOut << "<draw:image draw:name=\"" << anchor.picture.key.filename() << "\"";
1449 *m_streamOut << " draw:style-name=\"Graphics\""; // ### TODO: should be an automatic "graphic" style name instead
1450 if ( anchorType == AnchorNonInlined )
1451 {
1452 // ### TODO: correctly set a OOWriter frame positioned on the page
1453 *m_streamOut << " text:anchor-type=\"paragraph\"";
1454 }
1455 else
1456 {
1457 *m_streamOut << " text:anchor-type=\"as-char\"";
1458 }
1459 *m_streamOut << " svg:height=\"" << height << "pt\" svg:width=\"" << width << "pt\"";
1460 *m_streamOut << " draw:z-index=\"0\" xlink:href=\"#" << ooName << "\"";
1461 *m_streamOut << " xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"";
1462 *m_streamOut << "/>"; // NO end of line!
1463
1464 if (m_zip)
1465 {
1466#if 0
1467 // ### FIXME Why is the following line not working (at least with KDE 3.1)? (It makes unzip having problems with meta.xml)
1468 m_zip->writeFile(ooName,TQString(), TQString(), image.size(), image.data());
1469#else
1470 zipPrepareWriting(ooName);
1471 zipWriteData( image );
1472 zipDoneWriting();
1473#endif
1474 }
1475
1476 return true;
1477}
1478
1479void OOWriterWorker::processNormalText ( const TQString &paraText,
1480 const TextFormatting& formatLayout,
1481 const FormatData& formatData)
1482{
1483 // Retrieve text and escape it (and necessary space, tabs and line-break tags)
1484 const TQString partialText( escapeOOSpan( paraText.mid( formatData.pos, formatData.len ) ) );
1485
1486 if (formatData.text.missing)
1487 {
1488 // It's just normal text, so we do not need a <text:span> element!
1489 *m_streamOut << partialText;
1490 }
1491 else
1492 { // Text with properties, so use a <text:span> element!
1493 *m_streamOut << "<text:span";
1494
1495 TQString styleKey;
1496 const TQString props ( textFormatToStyle(formatLayout,formatData.text,false,styleKey) );
1497
1498 TQMap<TQString,TQString>::ConstIterator it ( m_mapTextStyleKeys.find(styleKey) );
1499 kdDebug(30518) << "Searching text key: " << styleKey << endl;
1500
1501 TQString automaticStyle;
1502 if (it==m_mapTextStyleKeys.end())
1503 {
1504 // We have not any match, so we need a new automatic text style
1505 automaticStyle=makeAutomaticStyleName("T", m_automaticTextStyleNumber);
1506 kdDebug(30518) << "Creating automatic text style: " << automaticStyle << " key: " << styleKey << endl;
1507 m_mapTextStyleKeys[styleKey]=automaticStyle;
1508
1509 m_contentAutomaticStyles += " <style:style";
1510 m_contentAutomaticStyles += " style:name=\"" + escapeOOText(automaticStyle) + "\"";
1511 m_contentAutomaticStyles += " style:family=\"text\"";
1512 m_contentAutomaticStyles += ">\n";
1513 m_contentAutomaticStyles += " <style:properties ";
1514 m_contentAutomaticStyles += props;
1515 m_contentAutomaticStyles += "/>\n";
1516 m_contentAutomaticStyles += " </style:style>\n";
1517 }
1518 else
1519 {
1520 // We have a match, so use the already defined automatic text style
1521 automaticStyle=it.data();
1522 kdDebug(30518) << "Using automatic text style: " << automaticStyle << " key: " << styleKey << endl;
1523 }
1524
1525 *m_streamOut << " text:style-name=\"" << escapeOOText(automaticStyle) << "\" ";
1526
1527 *m_streamOut << ">" << partialText << "</text:span>";
1528 }
1529}
1530
1531void OOWriterWorker::processFootnote( const VariableData& variable )
1532{
1533 // Footnote
1534 const TQValueList<ParaData> *paraList = variable.getFootnotePara();
1535 if( paraList )
1536 {
1537 const TQString value ( variable.getFootnoteValue() );
1538 //const bool automatic = formatData.variable.getFootnoteAuto();
1539 const bool flag = variable.getFootnoteType();
1540
1541 if ( flag )
1542 {
1543 *m_streamOut << "<text:footnote text:id=\"ft";
1544 *m_streamOut << (++m_footnoteNumber);
1545 *m_streamOut << "\">";
1546 *m_streamOut << "<text:footnote-citation>" << escapeOOText( value ) << "</text:footnote-citation>";
1547 *m_streamOut << "<text:footnote-body>\n";
1548
1549 doFullAllParagraphs( *paraList );
1550
1551 *m_streamOut << "\n</text:footnote-body>";
1552 *m_streamOut << "</text:footnote>";
1553 }
1554 else
1555 {
1556 *m_streamOut << "<text:endnote text:id=\"ft";
1557 *m_streamOut << (++m_footnoteNumber);
1558 *m_streamOut << "\">";
1559 *m_streamOut << "<text:endnote-citation>" << escapeOOText( value ) << "</text:endnote-citation>";
1560 *m_streamOut << "<text:endnote-body>\n";
1561
1562 doFullAllParagraphs( *paraList );
1563
1564 *m_streamOut << "\n</text:endnote-body>";
1565 *m_streamOut << "</text:endnote>";
1566 }
1567 }
1568}
1569
1570void OOWriterWorker::processNote( const VariableData& variable )
1571{
1572 // KWord 1.3's annotations are anonymous and undated,
1573 // however the OO specification tells that author and date are mandatory (even if OOWriter 1.1 consider them optional)
1574
1575 *m_streamOut << "<office:annotation office:create-date=\"";
1576
1577 // We use the document creation date as creation date for the annotation
1578 // (OOWriter uses only the date part, there is no time part)
1579 if ( m_varSet.creationTime.isValid() )
1580 *m_streamOut << escapeOOText( m_varSet.creationTime.date().toString( TQt::ISODate ) );
1581 else
1582 *m_streamOut << "1970-01-01";
1583
1584 *m_streamOut << "\" office:author=\"";
1585
1586 // We try to use the document author's name as annotation author
1587 if ( m_docInfo.fullName.isEmpty() )
1588 *m_streamOut << escapeOOText( i18n( "Pseudo-author for annotations", "KWord 1.3" ) );
1589 else
1590 *m_streamOut << escapeOOText( m_docInfo.fullName );
1591
1592 *m_streamOut << "\">\n";
1593 *m_streamOut << "<text:p>"
1594 << escapeOOSpan( variable.getGenericData( "note" ) )
1595 << "</text:p>\n"
1596 << "</office:annotation>";
1597}
1598
1599void OOWriterWorker::processVariable ( const TQString&,
1600 const TextFormatting& /*formatLayout*/,
1601 const FormatData& formatData)
1602{
1603 if (0==formatData.variable.m_type)
1604 {
1605 *m_streamOut << "<text:date/>"; // ### TODO: parameters
1606 }
1607 else if (2==formatData.variable.m_type)
1608 {
1609 *m_streamOut << "<text:time/>"; // ### TODO: parameters
1610 }
1611 else if (4==formatData.variable.m_type)
1612 {
1613 // ### TODO: the other under-types, other parameters
1614 if (formatData.variable.isPageNumber())
1615 {
1616 *m_streamOut << "<text:page-number text:select-page=\"current\"/>";
1617 }
1618 else if (formatData.variable.isPageCount())
1619 {
1620 *m_streamOut << "<text:page-count/>";
1621 }
1622 else
1623 {
1624 // Unknown subtype, therefore write out the result
1625 *m_streamOut << formatData.variable.m_text;
1626 }
1627 }
1628 else if (9==formatData.variable.m_type)
1629 {
1630 // A link
1631 *m_streamOut << "<text:a xlink:href=\""
1632 << escapeOOText(formatData.variable.getHrefName())
1633 << "\" xlink:type=\"simple\">"
1634 << escapeOOText(formatData.variable.getLinkName())
1635 << "</text:a>";
1636 }
1637 else if ( 10 == formatData.variable.m_type )
1638 { // Note (OOWriter: annotation)
1639 processNote ( formatData.variable );
1640 }
1641 else if (11==formatData.variable.m_type)
1642 {
1643 // Footnote
1644 processFootnote ( formatData.variable );
1645 }
1646 else
1647 {
1648 // Generic variable
1649 *m_streamOut << formatData.variable.m_text;
1650 }
1651}
1652
1653void OOWriterWorker::processAnchor ( const TQString&,
1654 const TextFormatting& /*formatLayout*/, //TODO
1655 const FormatData& formatData)
1656{
1657 // We have a picture or a table
1658 if ( (2==formatData.frameAnchor.type) // <IMAGE> or <PICTURE>
1659 || (5==formatData.frameAnchor.type) ) // <CLIPART>
1660 {
1661 makePicture( formatData.frameAnchor, AnchorInlined );
1662 }
1663 else if (6==formatData.frameAnchor.type)
1664 {
1665 makeTable( formatData.frameAnchor, AnchorInlined );
1666 }
1667 else
1668 {
1669 kdWarning(30518) << "Unsupported anchor type: "
1670 << formatData.frameAnchor.type << endl;
1671 }
1672}
1673
1674void OOWriterWorker::processTextImage ( const TQString&,
1675 const TextFormatting& /*formatLayout*/,
1676 const FormatData& formatData)
1677{
1678 kdDebug(30518) << "Text Image: " << formatData.frameAnchor.key.toString() << endl;
1679 makePicture( formatData.frameAnchor, AnchorTextImage );
1680}
1681
1682void OOWriterWorker::processParagraphData ( const TQString &paraText,
1683 const TextFormatting& formatLayout,
1684 const ValueListFormatData &paraFormatDataList)
1685{
1686 if ( paraText.length () > 0 )
1687 {
1688 ValueListFormatData::ConstIterator paraFormatDataIt;
1689
1690 for ( paraFormatDataIt = paraFormatDataList.begin ();
1691 paraFormatDataIt != paraFormatDataList.end ();
1692 paraFormatDataIt++ )
1693 {
1694 if (1==(*paraFormatDataIt).id)
1695 {
1696 processNormalText(paraText, formatLayout, (*paraFormatDataIt));
1697 }
1698 else if (2==(*paraFormatDataIt).id)
1699 {
1700 processTextImage(paraText, formatLayout, (*paraFormatDataIt));
1701 }
1702 else if ( 3 == (*paraFormatDataIt).id )
1703 {
1704 // Just a (KWord 0.8) tab stop, nothing else to do!
1705 *m_streamOut << "<text:tab-stop/>";
1706 }
1707 else if (4==(*paraFormatDataIt).id)
1708 {
1709 processVariable(paraText, formatLayout, (*paraFormatDataIt));
1710 }
1711 else if (6==(*paraFormatDataIt).id)
1712 {
1713 processAnchor(paraText, formatLayout, (*paraFormatDataIt));
1714 }
1715 else if ( 1001 == (*paraFormatDataIt).id ) // Start of bookmark
1716 {
1717 *m_streamOut << "<text:bookmark-start text:name=\""
1718 << escapeOOText( (*paraFormatDataIt).variable.m_text )
1719 <<"\"/>";
1720 }
1721 else if ( 1002 == (*paraFormatDataIt).id ) // End of bookmark
1722 {
1723 *m_streamOut << "<text:bookmark-end text:name=\""
1724 << escapeOOText( (*paraFormatDataIt).variable.m_text )
1725 <<"\"/>";
1726 }
1727 }
1728 }
1729}
1730
1731TQString OOWriterWorker::layoutToParagraphStyle(const LayoutData& layoutOrigin,
1732 const LayoutData& layout, const bool force, TQString& styleKey)
1733{
1734 TQString props; // Props has to remain empty, if there is no difference.
1735
1736 styleKey += layout.styleName;
1737 styleKey += ',';
1738
1739 if (force || (layoutOrigin.alignment!=layout.alignment))
1740 {
1741 // NOTE: OO 1.0.x uses start and end like left and right (section 3.11.4)
1742 // Unfortunately in XSL-FO's text-align, they are really supposed to be the start and the end.
1743 if (layout.alignment == "left")
1744 {
1745 props += "fo:text-align=\"start\" ";
1746 styleKey += 'L';
1747 }
1748 else if (layout.alignment == "right")
1749 {
1750 props += "fo:text-align=\"end\" ";
1751 styleKey += 'R';
1752 }
1753 else if (layout.alignment == "center")
1754 {
1755 props += "fo:text-align=\"center\" ";
1756 styleKey += 'C';
1757 }
1758 else if (layout.alignment == "justify")
1759 {
1760 props += "fo:text-align=\"justify\" ";
1761 styleKey += 'J';
1762 }
1763 else if (layout.alignment == "auto")
1764 {
1765 props += "fo:text-align=\"start\" ";
1766#ifndef STRICT_OOWRITER_VERSION_1
1767 props += "style:text-auto-align=\"true\" "; // rejected draft OASIS extension
1768#endif
1769 styleKey += 'A';
1770 }
1771 else
1772 {
1773 kdWarning(30518) << "Unknown alignment: " << layout.alignment << endl;
1774 }
1775 }
1776
1777 styleKey += ',';
1778
1779 if ((layout.indentLeft>=0.0)
1780 && (force || (layoutOrigin.indentLeft!=layout.indentLeft)))
1781 {
1782 props += TQString("fo:margin-left=\"%1pt\" ").arg(layout.indentLeft);
1783 styleKey += TQString::number(layout.indentLeft);
1784 }
1785
1786 styleKey += ',';
1787
1788 if ((layout.indentRight>=0.0)
1789 && (force || (layoutOrigin.indentRight!=layout.indentRight)))
1790 {
1791 props += TQString("fo:margin-right=\"%1pt\" ").arg(layout.indentRight);
1792 styleKey += TQString::number(layout.indentRight);
1793 }
1794
1795 styleKey += ',';
1796
1797 if (force || (layoutOrigin.indentLeft!=layout.indentLeft))
1798 {
1799 props += "fo:text-indent=\"";
1800 props += TQString::number(layout.indentFirst);
1801 props += "\" ";
1802 styleKey += TQString::number(layout.indentFirst);
1803 }
1804
1805 styleKey += ',';
1806
1807 if ((layout.marginBottom>=0.0)
1808 && ( force || ( layoutOrigin.marginBottom != layout.marginBottom ) ) )
1809 {
1810 props += TQString("fo:margin-bottom=\"%1pt\" ").arg(layout.marginBottom);
1811 styleKey += TQString::number(layout.marginBottom);
1812 }
1813
1814 styleKey += ',';
1815
1816 if ((layout.marginTop>=0.0)
1817 && ( force || ( layoutOrigin.marginTop != layout.marginTop ) ) )
1818 {
1819 props += TQString("fo:margin-top=\"%1pt\" ").arg(layout.marginTop);
1820 styleKey += TQString::number(layout.marginTop);
1821 }
1822
1823 styleKey += ',';
1824
1825 if (force
1826 || ( layoutOrigin.lineSpacingType != layout.lineSpacingType )
1827 || ( layoutOrigin.lineSpacing != layout.lineSpacing ) )
1828 {
1829 switch ( layout.lineSpacingType )
1830 {
1831 case LayoutData::LS_CUSTOM:
1832 {
1833 // We have a custom line spacing (in points)
1834 const TQString height ( TQString::number(layout.lineSpacing) ); // ### TODO: rounding?
1835 props += "style:line-spacing=\"";
1836 props += height;
1837 props += "pt\" ";
1838 styleKey += height;
1839 styleKey += 'C';
1840 break;
1841 }
1842 case LayoutData::LS_SINGLE:
1843 {
1844 props += "fo:line-height=\"normal\" "; // One
1845 styleKey += "100%"; // One
1846 break;
1847 }
1848 case LayoutData::LS_ONEANDHALF:
1849 {
1850 props += "fo:line-height=\"150%\" "; // One-and-half
1851 styleKey += "150%";
1852 break;
1853 }
1854 case LayoutData::LS_DOUBLE:
1855 {
1856 props += "fo:line-height=\"200%\" "; // Two
1857 styleKey += "200%";
1858 break;
1859 }
1860 case LayoutData::LS_MULTIPLE:
1861 {
1862 // OOWriter 1.1 only allows up to 200%
1863 const TQString mult ( TQString::number( tqRound( layout.lineSpacing * 100 ) ) );
1864 props += "fo:line-height=\"";
1865 props += mult;
1866 props += "%\" ";
1867 styleKey += mult;
1868 styleKey += "%";
1869 break;
1870 }
1871 case LayoutData::LS_FIXED:
1872 {
1873 // We have a fixed line height (in points)
1874 const TQString height ( TQString::number(layout.lineSpacing) ); // ### TODO: rounding?
1875 props += "fo:line-height=\"";
1876 props += height;
1877 props += "pt\" ";
1878 styleKey += height;
1879 styleKey += 'F';
1880 break;
1881 }
1882 case LayoutData::LS_ATLEAST:
1883 {
1884 // We have a at-least line height (in points)
1885 const TQString height ( TQString::number(layout.lineSpacing) ); // ### TODO: rounding?
1886 props += "style:line-height-at-least=\"";
1887 props += height;
1888 props += "pt\" ";
1889 styleKey += height;
1890 styleKey += 'A';
1891 break;
1892 }
1893 default:
1894 {
1895 kdWarning(30518) << "Unsupported lineSpacingType: " << layout.lineSpacingType << " (Ignoring!)" << endl;
1896 break;
1897 }
1898 }
1899 }
1900
1901 styleKey += ',';
1902
1903 if ( layout.pageBreakBefore )
1904 {
1905 // We have a page break before the paragraph
1906 props += "fo:page-break-before=\"page\" ";
1907 styleKey += 'B';
1908 }
1909
1910 styleKey += ',';
1911
1912 if ( layout.pageBreakAfter )
1913 {
1914 // We have a page break after the paragraph
1915 props += "fo:page-break-after=\"page\" ";
1916 styleKey += 'A';
1917 }
1918
1919 styleKey += '@'; // A more visible seperator
1920
1921 props += textFormatToStyle(layoutOrigin.formatData.text,layout.formatData.text,force,styleKey);
1922
1923 props += ">";
1924
1925 styleKey += '@'; // A more visible seperator
1926
1927 // ### TODO/FIXME: what if all tabulators must be erased?
1928 if (!layout.tabulatorList.isEmpty()
1929 && (force || (layoutOrigin.tabulatorList!=layout.tabulatorList) ))
1930 {
1931 props += "\n <style:tab-stops>\n";
1932 TabulatorList::ConstIterator it;
1933 TabulatorList::ConstIterator end(layout.tabulatorList.end());
1934 for (it=layout.tabulatorList.begin();it!=end;++it)
1935 {
1936 props+=" <style:tab-stop style:position=\"";
1937 props += TQString::number((*it).m_ptpos);
1938 props += "pt\"";
1939 styleKey += TQString::number((*it).m_ptpos);
1940 switch ((*it).m_type)
1941 {
1942 case 0: props += " style:type=\"left\""; styleKey += "L"; break;
1943 case 1: props += " style:type=\"center\""; styleKey += "C"; break;
1944 case 2: props += " style:type=\"right\""; styleKey += "R"; break;
1945 case 3: props += " style:type=\"char\" style:char=\".\""; styleKey += "D"; break; // decimal
1946 default: props += " style:type=\"left\""; styleKey += "L"; break;
1947 }
1948 switch ((*it).m_filling) // ### TODO: check if the characters are right
1949 {
1950 case TabulatorData::TF_NONE: break;
1951 case TabulatorData::TF_DOT: props += " style:leader-char=\".\""; break;
1952 case TabulatorData::TF_LINE: props += " style:leader-char=\"_\""; break;
1953
1954 case TabulatorData::TF_DASH:
1955 case TabulatorData::TF_DASHDOT:
1956 case TabulatorData::TF_DASHDOTDOT: props += " style:leader-char=\"-\""; break;
1957
1958 default: break;
1959 }
1960 props += "/>\n";
1961 styleKey +='/';
1962 }
1963 props += " </style:tab-stops>\n ";
1964 }
1965
1966 return props;
1967}
1968
1969bool OOWriterWorker::doFullParagraph(const TQString& paraText, const LayoutData& layout,
1970 const ValueListFormatData& paraFormatDataList)
1971{
1972 const bool header = ( (layout.counter.numbering == CounterData::NUM_CHAPTER)
1973 && (layout.counter.depth<10) ); // ### TODO: Does OOWriter really limits to 10?
1974
1975 if (header)
1976 {
1977 *m_streamOut << " <text:h text:level=\"";
1978 *m_streamOut << TQString::number(layout.counter.depth+1,10);
1979 *m_streamOut << "\" ";
1980 }
1981 else
1982 *m_streamOut << " <text:p ";
1983
1984 const LayoutData& styleLayout=m_styleMap[layout.styleName];
1985
1986 TQString styleKey;
1987 const TQString props(layoutToParagraphStyle(styleLayout,layout,false,styleKey));
1988
1989 TQString actualStyle(layout.styleName);
1990 if (!props.isEmpty())
1991 {
1992 TQMap<TQString,TQString>::ConstIterator it ( m_mapParaStyleKeys.find(styleKey) );
1993 kdDebug(30518) << "Searching paragraph key: " << styleKey << endl;
1994
1995 TQString automaticStyle;
1996
1997 if (it==m_mapParaStyleKeys.end())
1998 {
1999 // We have additional properties, so we need an automatic style for the paragraph
2000 automaticStyle = makeAutomaticStyleName("P", m_automaticParagraphStyleNumber);
2001 kdDebug(30518) << "Creating automatic paragraph style: " << automaticStyle << " key: " << styleKey << endl;
2002 m_mapParaStyleKeys[styleKey]=automaticStyle;
2003
2004 m_contentAutomaticStyles += " <style:style";
2005 m_contentAutomaticStyles += " style:name=\"" + escapeOOText(automaticStyle) + "\"";
2006 m_contentAutomaticStyles += " style:parent-style-name=\"" + escapeOOText(layout.styleName) + "\"";
2007 m_contentAutomaticStyles += " style:family=\"paragraph\" style:class=\"text\"";
2008 m_contentAutomaticStyles += ">\n";
2009 m_contentAutomaticStyles += " <style:properties ";
2010 m_contentAutomaticStyles += props;
2011 m_contentAutomaticStyles += "</style:properties>\n";
2012 m_contentAutomaticStyles += " </style:style>\n";
2013 }
2014 else
2015 {
2016 // We have a match, so use the already defined automatic paragraph style
2017 automaticStyle=it.data();
2018 kdDebug(30518) << "Using automatic paragraph style: " << automaticStyle << " key: " << styleKey << endl;
2019 }
2020
2021 actualStyle=automaticStyle;
2022 }
2023
2024 if (!actualStyle.isEmpty())
2025 {
2026 *m_streamOut << "text:style-name=\"" << escapeOOText(actualStyle) << "\" ";
2027 }
2028 else
2029 { // SHould not happen
2030 kdWarning(30518) << "No style for a paragraph!" << endl;
2031 }
2032
2033 *m_streamOut << ">";
2034
2035 processParagraphData(paraText, layout.formatData.text, paraFormatDataList);
2036
2037 if (header)
2038 *m_streamOut << "</text:h>\n";
2039 else
2040 *m_streamOut << "</text:p>\n";
2041
2042 return true;
2043}
2044
2045bool OOWriterWorker::doOpenStyles(void)
2046{
2047 m_styles += " <office:styles>\n";
2048 m_styles += " <style:style style:name=\"Graphics\" style:family=\"graphics\">\n"; // ### TODO: what if Graphics is a normal style
2049 m_styles += " <style:properties text:anchor-type=\"paragraph\" style:wrap=\"none\"/>\n";
2050 m_styles += " </style:style>\n";
2051 m_styles += " <style:style style:name=\"Frame\" style:family=\"graphics\">\n"; // ### TODO: what if Frame is a normal style
2052 m_styles += " <style:properties text:anchor-type=\"paragraph\" style:wrap=\"none\"/>\n";
2053 m_styles += " </style:style>\n";
2054 return true;
2055}
2056
2057bool OOWriterWorker::doFullDefineStyle(LayoutData& layout)
2058{
2059 //Register style in the style map
2060 m_styleMap[layout.styleName]=layout;
2061
2062 m_styles += " <style:style";
2063
2064 m_styles += " style:name=\"" + escapeOOText( layout.styleName ) + "\"";
2065 m_styles += " style:next-style-name=\"" + escapeOOText( layout.styleFollowing ) + "\"";
2066 m_styles += " style:family=\"paragraph\" style:class=\"text\"";
2067 m_styles += ">\n";
2068 m_styles += " <style:properties ";
2069
2070 TQString debugKey; // Not needed
2071 m_styles += layoutToParagraphStyle(layout,layout,true,debugKey);
2072 kdDebug(30518) << "Defining style: " << debugKey << endl;
2073
2074 m_styles += "</style:properties>\n";
2075 m_styles += " </style:style>\n";
2076
2077 return true;
2078}
2079
2080bool OOWriterWorker::doCloseStyles(void)
2081{
2082 m_styles += " </office:styles>\n";
2083 return true;
2084}
2085
2086bool OOWriterWorker::doFullPaperFormat(const int format,
2087 const double width, const double height, const int orientation)
2088{
2089 if ( ( format < 0 ) // Be careful that 0 is ISO A3
2090 || ( width < 1.0 )
2091 || ( height < 1.0 ) )
2092 {
2093 kdWarning(30518) << "Page size problem: format: " << format << " width: " << width << " height: " << height << endl;
2094 // Something is wrong with the page size
2095 KoFormat newFormat = KoFormat ( format );
2096 if ( ( format < 0 ) || ( format > PG_LAST_FORMAT ) )
2097 {
2098 // Bad or unknown format, so assume ISO A4
2099 newFormat = PG_DIN_A4;
2100 }
2101 m_paperWidth = KoPageFormat::width ( newFormat, KoOrientation( orientation ) ) * 72.0 / 25.4 ;
2102 m_paperHeight = KoPageFormat::height ( newFormat, KoOrientation( orientation ) ) * 72.0 / 25.4 ;
2103 m_paperFormat = newFormat;
2104 }
2105 else
2106 {
2107 m_paperFormat=format;
2108 m_paperWidth=width;
2109 m_paperHeight=height;
2110 }
2111 m_paperOrientation=orientation; // ### TODO: check if OOWriter needs the orignal size (without landscape) or the real size
2112 return true;
2113}
2114
2115bool OOWriterWorker::doFullPaperBorders (const double top, const double left,
2116 const double bottom, const double right)
2117{
2118 m_paperBorderTop=top;
2119 m_paperBorderLeft=left;
2120 m_paperBorderBottom=bottom;
2121 m_paperBorderRight=right;
2122 return true;
2123}
2124
2125bool OOWriterWorker::doFullPaperFormatOther ( const int columns, const double columnspacing, const int numPages )
2126{
2127 m_columns = columns;
2128 m_columnspacing = columnspacing;
2129 m_numPages = numPages;
2130 return true;
2131}
2132
2133bool OOWriterWorker::doFullDocumentInfo(const KWEFDocumentInfo& docInfo)
2134{
2135 m_docInfo=docInfo;
2136
2137 return true;
2138}
2139
2140bool OOWriterWorker::doVariableSettings(const VariableSettingsData& vs)
2141{
2142 m_varSet=vs;
2143
2144 return true;
2145}
2146
2147bool OOWriterWorker::doDeclareNonInlinedFramesets( TQValueList<FrameAnchor>& pictureAnchors, TQValueList<FrameAnchor>& tableAnchors )
2148{
2149 m_nonInlinedPictureAnchors = pictureAnchors;
2150 m_nonInlinedTableAnchors = tableAnchors;
2151 return true;
2152}
2153
2154void OOWriterWorker::declareFont(const TQString& fontName)
2155{
2156 if (fontName.isEmpty())
2157 return;
2158
2159 if (m_fontNames.find(fontName)==m_fontNames.end())
2160 {
2161 TQString props;
2162
2163 // Disabled, as TQFontInfo::styleHint() cannot guess
2164#if 0
2165 TQFont font(fontName);
2166 TQFontInfo info(font);
2167 props+="style:font-family-generic=\""
2168 switch (info.styleHint())
2169 {
2170 case TQFont::SansSerif:
2171 default:
2172 {
2173 props += "swiss";
2174 break;
2175 }
2176 case TQFont::Serif:
2177 {
2178 props += "roman";
2179 break;
2180 }
2181 case TQFont::Courier:
2182 {
2183 props += "modern";
2184 break;
2185 }
2186 case TQFont::OldEnglish:
2187 {
2188 props += "decorative";
2189 break;
2190 }
2191 }
2192 props +="\" ";
2193#endif
2194
2195 props +="style:font-pitch=\"variable\""; // ### TODO: check if font is variable or fixed
2196 // New font, so register it
2197 m_fontNames[fontName]=props;
2198 }
2199}
2200
2201TQString OOWriterWorker::makeAutomaticStyleName(const TQString& prefix, ulong& counter) const
2202{
2203 const TQString str (prefix + TQString::number(++counter,10));
2204
2205 // Checks if the automatic style has not the same name as a user one.
2206 // If it is the case, change it!
2207
2208 if (m_styleMap.find(str)==m_styleMap.end())
2209 return str; // Unique, so let's go!
2210
2211 TQString str2(str+"_bis");
2212 if (m_styleMap.find(str2)==m_styleMap.end())
2213 return str2;
2214
2215 str2 = str+"_ter";
2216 if (m_styleMap.find(str2)==m_styleMap.end())
2217 return str2;
2218
2219 // If it is still not unique, try a time stamp.
2220 const TQDateTime dt(TQDateTime::currentDateTime(TQt::UTC));
2221
2222 str2 = str + "_" + TQString::number(dt.toTime_t(),16);
2223 if (m_styleMap.find(str2)==m_styleMap.end())
2224 return str2;
2225
2226 kdWarning(30518) << "Could not make an unique style name: " << str2 << endl;
2227 return str2; // Still return, as we have nothing better
2228}
2229
@ NUM_CHAPTER
Numbered as a heading.
This is basically <FRAMESET> tag.
KoPictureKey key
Picture key.
For <FRAME> Tag.
Paragraph layout.
double lineSpacing
Space between lines in pt, if lineSpacingType==0.
TabulatorList tabulatorList
List of tabulators.
double indentFirst
indentation correction of first line (can be negative!)
double indentRight
right indentation (a negative value means invalid)
double indentLeft
left indentation (a negative value means invalid)
TQString alignment
left, right, center, justify
int lineSpacingType
0=custom, 10=one line, 15=one and half lines, 20= 2 lines
double marginTop
space before the paragraph (a negative value means invalid)
double marginBottom
space after the paragraph (a negative value means invalid)
This class hold a table.
TextFormatting is a container for data retrieved from the <FORMAT> tag and its subtags to be used in ...
bool underlineWord
true if word-by-word (i.e spaces are not underlined)
bool underline
Any underline? (If true, we do not know if simple or double or what else)
TQString language
Language code.
TQColor underlineColor
color of the line
bool strikeout
true if strikeout
TQString underlineStyle
underline style: solid, dash, dot dash, ....
TQString underlineValue
"value" of the underline: single, double, bold-single...
TQString strikeoutType
type of strikeout: single, bold, double
Data of variables.
TQString getFootnoteValue(void) const
Get the value (counter) of the footnote.
bool getFootnoteType(void) const
Get type of footnote.
TQValueList< ParaData > * getFootnotePara(void) const
Paragrapgh of the footnote.
TQString getGenericData(const TQString &key) const
Get generic variable data.
see <VARIABLESETTINGS> in the KWord DTD