KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > rtf > RtfWriter


1 /*
2  * $Id: RtfWriter.java 2752 2007-05-15 14:58:33Z blowagie $
3  * $Name$
4  *
5  * Copyright 2001, 2002 by Mark Hall
6  *
7  * The contents of this file are subject to the Mozilla Public License Version 1.1
8  * (the "License"); you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the License.
14  *
15  * The Original Code is 'iText, a free JAVA-PDF library'.
16  *
17  * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
18  * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
19  * All Rights Reserved.
20  * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
21  * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
22  *
23  * Contributor(s): all the names of the contributors are added in the source code
24  * where applicable.
25  *
26  * Alternatively, the contents of this file may be used under the terms of the
27  * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the
28  * provisions of LGPL are applicable instead of those above. If you wish to
29  * allow use of your version of this file only under the terms of the LGPL
30  * License and not to allow others to use your version of this file under
31  * the MPL, indicate your decision by deleting the provisions above and
32  * replace them with the notice and other provisions required by the LGPL.
33  * If you do not delete the provisions above, a recipient may use your version
34  * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
35  *
36  * This library is free software; you can redistribute it and/or modify it
37  * under the terms of the MPL as stated above or under the terms of the GNU
38  * Library General Public License as published by the Free Software Foundation;
39  * either version 2 of the License, or any later version.
40  *
41  * This library is distributed in the hope that it will be useful, but WITHOUT
42  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
43  * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
44  * details.
45  *
46  * If you didn't download this code from the following link, you should check if
47  * you aren't using an obsolete version:
48  * http://www.lowagie.com/iText/
49  */

50
51 package com.lowagie.text.rtf;
52
53 import java.awt.Color JavaDoc;
54 import java.io.ByteArrayInputStream JavaDoc;
55 import java.io.ByteArrayOutputStream JavaDoc;
56 import java.io.IOException JavaDoc;
57 import java.io.InputStream JavaDoc;
58 import java.io.OutputStream JavaDoc;
59 import java.text.ParsePosition JavaDoc;
60 import java.text.SimpleDateFormat JavaDoc;
61 import java.util.ArrayList JavaDoc;
62 import java.util.Calendar JavaDoc;
63 import java.util.Date JavaDoc;
64 import java.util.Iterator JavaDoc;
65 import java.util.ListIterator JavaDoc;
66
67 import com.lowagie.text.Anchor;
68 import com.lowagie.text.Annotation;
69 import com.lowagie.text.Chunk;
70 import com.lowagie.text.DocWriter;
71 import com.lowagie.text.Document;
72 import com.lowagie.text.DocumentException;
73 import com.lowagie.text.Element;
74 import com.lowagie.text.ExceptionConverter;
75 import com.lowagie.text.Font;
76 import com.lowagie.text.HeaderFooter;
77 import com.lowagie.text.Image;
78 import com.lowagie.text.ListItem;
79 import com.lowagie.text.Meta;
80 import com.lowagie.text.PageSize;
81 import com.lowagie.text.Paragraph;
82 import com.lowagie.text.Phrase;
83 import com.lowagie.text.Rectangle;
84 import com.lowagie.text.Section;
85 import com.lowagie.text.SimpleTable;
86 import com.lowagie.text.Table;
87 import com.lowagie.text.pdf.codec.wmf.MetaDo;
88
89 /**
90  * If you are creating a new project using the rtf part of iText, please
91  * consider using the new RtfWriter2. The RtfWriter is in bug-fix-only mode,
92  * will be deprecated end of 2005 and removed end of 2007.
93  *
94  * A <CODE>DocWriter</CODE> class for Rich Text Files (RTF).
95  * <P>
96  * A <CODE>RtfWriter</CODE> can be added as a <CODE>DocListener</CODE>
97  * to a certain <CODE>Document</CODE> by getting an instance.
98  * Every <CODE>Element</CODE> added to the original <CODE>Document</CODE>
99  * will be written to the <CODE>OutputStream</CODE> of this <CODE>RtfWriter</CODE>.
100  * <P>
101  * Example:
102  * <BLOCKQUOTE><PRE>
103  * // creation of the document with a certain size and certain margins
104  * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
105  * try {
106  * // this will write RTF to the Standard OutputStream
107  * <STRONG>RtfWriter.getInstance(document, System.out);</STRONG>
108  * // this will write Rtf to a file called text.rtf
109  * <STRONG>RtfWriter.getInstance(document, new FileOutputStream("text.rtf"));</STRONG>
110  * // this will write Rtf to for instance the OutputStream of a HttpServletResponse-object
111  * <STRONG>RtfWriter.getInstance(document, response.getOutputStream());</STRONG>
112  * }
113  * catch(DocumentException de) {
114  * System.err.println(de.getMessage());
115  * }
116  * // this will close the document and all the OutputStreams listening to it
117  * <STRONG>document.close();</CODE>
118  * </PRE></BLOCKQUOTE>
119  * <P>
120  * <STRONG>LIMITATIONS</STRONG><BR>
121  * There are currently still a few limitations on what the RTF Writer can do:
122  * <ul>
123  * <li>Watermarks</li>
124  * <li>Viewer preferences</li>
125  * <li>Encryption</li>
126  * <li>Embedded fonts</li>
127  * <li>Phrases with a leading</li>
128  * <li>Lists with non-bullet symbols</li>
129  * <li>Nested tables</li>
130  * <li>Images other than JPEG and PNG</li>
131  * <li>Rotated images</li>
132  * </ul>
133  * <br />
134  *
135  * @author Mark Hall (mhall@edu.uni-klu.ac.at)
136  * @author Steffen Stundzig (Steffen.Stundzig@smb-tec.com)
137  * @author Eric Mattes (ericmattes@yahoo.com)
138  * @author Raul Wegmann (raul.wegmann@uam.es)
139  * @deprecated The RtfWriter is deprecated and will be removed from the iText library end of 2007
140  */

141 public class RtfWriter extends DocWriter {
142     /**
143      * Static Constants
144      */

145
146     /**
147      * General
148      */

149
150     /** This is the escape character which introduces RTF tags. */
151     public static final byte escape = (byte) '\\';
152
153     /** This is another escape character which introduces RTF tags. */
154     private static final byte[] extendedEscape = "\\*\\".getBytes();
155
156     /** This is the delimiter between RTF tags and normal text. */
157     protected static final byte delimiter = (byte) ' ';
158
159     /** This is another delimiter between RTF tags and normal text. */
160     private static final byte commaDelimiter = (byte) ';';
161
162     /** This is the character for beginning a new group. */
163     public static final byte openGroup = (byte) '{';
164
165     /** This is the character for closing a group. */
166     public static final byte closeGroup = (byte) '}';
167
168     /**
169      * RTF Information
170      */

171
172     /** RTF begin and version. */
173     private static final byte[] docBegin = "rtf1".getBytes();
174
175     /** RTF encoding. */
176     private static final byte[] ansi = "ansi".getBytes();
177
178     /** RTF encoding codepage. */
179     private static final byte[] ansiCodepage = "ansicpg".getBytes();
180
181     /**
182      *Font Data
183      */

184
185     /** Begin the font table tag. */
186     private static final byte[] fontTable = "fonttbl".getBytes();
187
188     /** Font number tag. */
189     protected static final byte fontNumber = (byte) 'f';
190
191     /** Font size tag. */
192     protected static final byte[] fontSize = "fs".getBytes();
193
194     /** Font color tag. */
195     protected static final byte[] fontColor = "cf".getBytes();
196
197     /** Modern font tag. */
198     private static final byte[] fontModern = "fmodern".getBytes();
199
200     /** Swiss font tag. */
201     private static final byte[] fontSwiss = "fswiss".getBytes();
202
203     /** Roman font tag. */
204     private static final byte[] fontRoman = "froman".getBytes();
205
206     /** Tech font tag. */
207     private static final byte[] fontTech = "ftech".getBytes();
208
209     /** Font charset tag. */
210     private static final byte[] fontCharset = "fcharset".getBytes();
211
212     /** Font Courier tag. */
213     private static final byte[] fontCourier = "Courier".getBytes();
214
215     /** Font Arial tag. */
216     private static final byte[] fontArial = "Arial".getBytes();
217
218     /** Font Symbol tag. */
219     private static final byte[] fontSymbol = "Symbol".getBytes();
220
221     /** Font Times New Roman tag. */
222     private static final byte[] fontTimesNewRoman = "Times New Roman".getBytes();
223
224     /** Font Windings tag. */
225     private static final byte[] fontWindings = "Windings".getBytes();
226
227     /** Default Font. */
228     private static final byte[] defaultFont = "deff".getBytes();
229
230     /** First indent tag. */
231     private static final byte[] firstIndent = "fi".getBytes();
232
233     /** Left indent tag. */
234     private static final byte[] listIndent = "li".getBytes();
235
236     /** Right indent tag. */
237     private static final byte[] rightIndent = "ri".getBytes();
238
239     /**
240      * Sections / Paragraphs
241      */

242
243     /** Reset section defaults tag. */
244     private static final byte[] sectionDefaults = "sectd".getBytes();
245
246     /** Begin new section tag. */
247     private static final byte[] section = "sect".getBytes();
248
249     /** Reset paragraph defaults tag. */
250     public static final byte[] paragraphDefaults = "pard".getBytes();
251
252     /** Begin new paragraph tag. */
253     public static final byte[] paragraph = "par".getBytes();
254
255     /** Page width of a section. */
256     public static final byte[] sectionPageWidth = "pgwsxn".getBytes();
257
258     /** Page height of a section. */
259     public static final byte[] sectionPageHeight = "pghsxn".getBytes();
260
261     /**
262      * Lists
263      */

264
265     /** Begin the List Table */
266     private static final byte[] listtableGroup = "listtable".getBytes();
267
268     /** Begin the List Override Table */
269     private static final byte[] listoverridetableGroup = "listoverridetable".getBytes();
270
271     /** Begin a List definition */
272     private static final byte[] listDefinition = "list".getBytes();
273
274     /** List Template ID */
275     private static final byte[] listTemplateID = "listtemplateid".getBytes();
276
277     /** RTF Writer outputs hybrid lists */
278     private static final byte[] hybridList = "hybrid".getBytes();
279
280     /** Current List level */
281     private static final byte[] listLevelDefinition = "listlevel".getBytes();
282
283     /** Level numbering (old) */
284     private static final byte[] listLevelTypeOld = "levelnfc".getBytes();
285
286     /** Level numbering (new) */
287     private static final byte[] listLevelTypeNew = "levelnfcn".getBytes();
288
289     /** Level alignment (old) */
290     private static final byte[] listLevelAlignOld = "leveljc".getBytes();
291
292     /** Level alignment (new) */
293     private static final byte[] listLevelAlignNew = "leveljcn".getBytes();
294
295     /** Level starting number */
296     private static final byte[] listLevelStartAt = "levelstartat".getBytes();
297
298     /** Level text group */
299     private static final byte[] listLevelTextDefinition = "leveltext".getBytes();
300
301     /** Filler for Level Text Length */
302     private static final byte[] listLevelTextLength = "\'0".getBytes();
303
304     /** Level Text Numbering Style */
305     private static final byte[] listLevelTextStyleNumbers = "\'00.".getBytes();
306
307     /** Level Text Bullet Style */
308     private static final byte[] listLevelTextStyleBullet = "u-3913 ?".getBytes();
309
310     /** Level Numbers Definition */
311     private static final byte[] listLevelNumbersDefinition = "levelnumbers".getBytes();
312
313     /** Filler for Level Numbers */
314     private static final byte[] listLevelNumbers = "\\'0".getBytes();
315
316     /** Tab Stop */
317     private static final byte[] tabStop = "tx".getBytes();
318
319     /** Actual list begin */
320     private static final byte[] listBegin = "ls".getBytes();
321
322     /** Current list level */
323     private static final byte[] listCurrentLevel = "ilvl".getBytes();
324
325     /** List text group for older browsers */
326     private static final byte[] listTextOld = "listtext".getBytes();
327
328     /** Tab */
329     private static final byte[] tab = "tab".getBytes();
330
331     /** Old Bullet Style */
332     private static final byte[] listBulletOld = "\'b7".getBytes();
333
334     /** Current List ID */
335     private static final byte[] listID = "listid".getBytes();
336
337     /** List override */
338     private static final byte[] listOverride = "listoverride".getBytes();
339
340     /** Number of overrides */
341     private static final byte[] listOverrideCount = "listoverridecount".getBytes();
342
343     /**
344      * Text Style
345      */

346
347     /** Bold tag. */
348     protected static final byte bold = (byte) 'b';
349
350     /** Italic tag. */
351     protected static final byte italic = (byte) 'i';
352
353     /** Underline tag. */
354     protected static final byte[] underline = "ul".getBytes();
355
356     /** Strikethrough tag. */
357     protected static final byte[] strikethrough = "strike".getBytes();
358
359     /** Text alignment left tag. */
360     public static final byte[] alignLeft = "ql".getBytes();
361
362     /** Text alignment center tag. */
363     public static final byte[] alignCenter = "qc".getBytes();
364
365     /** Text alignment right tag. */
366     public static final byte[] alignRight = "qr".getBytes();
367
368     /** Text alignment justify tag. */
369     public static final byte[] alignJustify = "qj".getBytes();
370
371     /**
372      * Colors
373      */

374
375     /** Begin colour table tag. */
376     private static final byte[] colorTable = "colortbl".getBytes();
377
378     /** Red value tag. */
379     private static final byte[] colorRed = "red".getBytes();
380
381     /** Green value tag. */
382     private static final byte[] colorGreen = "green".getBytes();
383
384     /** Blue value tag. */
385     private static final byte[] colorBlue = "blue".getBytes();
386
387     /**
388      * Information Group
389      */

390
391     /** Begin the info group tag.*/
392     private static final byte[] infoBegin = "info".getBytes();
393
394     /** Author tag. */
395     private static final byte[] metaAuthor = "author".getBytes();
396
397     /** Subject tag. */
398     private static final byte[] metaSubject = "subject".getBytes();
399
400     /** Keywords tag. */
401     private static final byte[] metaKeywords = "keywords".getBytes();
402
403     /** Title tag. */
404     private static final byte[] metaTitle = "title".getBytes();
405
406     /** Producer tag. */
407     private static final byte[] metaProducer = "operator".getBytes();
408
409     /** Creation Date tag. */
410     private static final byte[] metaCreationDate = "creationdate".getBytes();
411
412     /** Year tag. */
413     private static final byte[] year = "yr".getBytes();
414
415     /** Month tag. */
416     private static final byte[] month = "mo".getBytes();
417
418     /** Day tag. */
419     private static final byte[] day = "dy".getBytes();
420
421     /** Hour tag. */
422     private static final byte[] hour = "hr".getBytes();
423
424     /** Minute tag. */
425     private static final byte[] minute = "min".getBytes();
426
427     /** Second tag. */
428     private static final byte[] second = "sec".getBytes();
429
430     /** Start superscript. */
431     private static final byte[] startSuper = "super".getBytes();
432
433     /** Start subscript. */
434     private static final byte[] startSub = "sub".getBytes();
435
436     /** End super/sub script. */
437     private static final byte[] endSuperSub = "nosupersub".getBytes();
438
439     /**
440      * Header / Footer
441      */

442
443     /** Title Page tag */
444     private static final byte[] titlePage = "titlepg".getBytes();
445
446     /** Facing pages tag */
447     private static final byte[] facingPages = "facingp".getBytes();
448
449     /** Begin header group tag. */
450     private static final byte[] headerBegin = "header".getBytes();
451
452     /** Begin footer group tag. */
453     private static final byte[] footerBegin = "footer".getBytes();
454
455     // header footer 'left', 'right', 'first'
456
private static final byte[] headerlBegin = "headerl".getBytes();
457
458     private static final byte[] footerlBegin = "footerl".getBytes();
459
460     private static final byte[] headerrBegin = "headerr".getBytes();
461
462     private static final byte[] footerrBegin = "footerr".getBytes();
463
464     private static final byte[] headerfBegin = "headerf".getBytes();
465
466     private static final byte[] footerfBegin = "footerf".getBytes();
467
468     /**
469      * Paper Properties
470      */

471
472     /** Paper width tag. */
473     private static final byte[] rtfPaperWidth = "paperw".getBytes();
474
475     /** Paper height tag. */
476     private static final byte[] rtfPaperHeight = "paperh".getBytes();
477
478     /** Margin left tag. */
479     private static final byte[] rtfMarginLeft = "margl".getBytes();
480
481     /** Margin right tag. */
482     private static final byte[] rtfMarginRight = "margr".getBytes();
483
484     /** Margin top tag. */
485     private static final byte[] rtfMarginTop = "margt".getBytes();
486
487     /** Margin bottom tag. */
488     private static final byte[] rtfMarginBottom = "margb".getBytes();
489
490     /** New Page tag. */
491     private static final byte[] newPage = "page".getBytes();
492
493     /** Document Landscape tag 1. */
494     private static final byte[] landscapeTag1 = "landscape".getBytes();
495
496     /** Document Landscape tag 2. */
497     private static final byte[] landscapeTag2 = "lndscpsxn".getBytes();
498
499     /**
500      * Annotations
501      */

502
503     /** Annotation ID tag. */
504     private static final byte[] annotationID = "atnid".getBytes();
505
506     /** Annotation Author tag. */
507     private static final byte[] annotationAuthor = "atnauthor".getBytes();
508
509     /** Annotation text tag. */
510     private static final byte[] annotation = "annotation".getBytes();
511
512     /**
513      * Images
514      */

515
516     /** Begin the main Picture group tag */
517     private static final byte[] pictureGroup = "shppict".getBytes();
518
519     /** Begin the picture tag */
520     private static final byte[] picture = "pict".getBytes();
521
522     /** PNG Image */
523     private static final byte[] picturePNG = "pngblip".getBytes();
524
525     /** JPEG Image */
526     private static final byte[] pictureJPEG = "jpegblip".getBytes();
527
528     /** BMP Image */
529     private static final byte[] pictureBMP = "dibitmap0".getBytes();
530
531     /** WMF Image */
532     private static final byte[] pictureWMF = "wmetafile8".getBytes();
533
534     /** Picture width */
535     private static final byte[] pictureWidth = "picw".getBytes();
536
537     /** Picture height */
538     private static final byte[] pictureHeight = "pich".getBytes();
539
540     /** Picture scale horizontal percent */
541     private static final byte[] pictureScaleX = "picscalex".getBytes();
542
543     /** Picture scale vertical percent */
544     private static final byte[] pictureScaleY = "picscaley".getBytes();
545
546     /**
547      * Fields (for page numbering)
548      */

549
550     /** Begin field tag */
551     protected static final byte[] field = "field".getBytes();
552
553     /** Content fo the field */
554     protected static final byte[] fieldContent = "fldinst".getBytes();
555
556     /** PAGE numbers */
557     protected static final byte[] fieldPage = "PAGE".getBytes();
558
559     /** HYPERLINK field */
560     protected static final byte[] fieldHyperlink = "HYPERLINK".getBytes();
561
562     /** Last page number (not used) */
563     protected static final byte[] fieldDisplay = "fldrslt".getBytes();
564
565
566     /** Class variables */
567
568     /**
569      * Because of the way RTF works and the way itext works, the text has to be
570      * stored and is only written to the actual OutputStream at the end.
571      */

572
573     /** This <code>ArrayList</code> contains all fonts used in the document. */
574     private ArrayList JavaDoc fontList = new ArrayList JavaDoc();
575
576     /** This <code>ArrayList</code> contains all colours used in the document. */
577     private ArrayList JavaDoc colorList = new ArrayList JavaDoc();
578
579     /** This <code>ByteArrayOutputStream</code> contains the main body of the document. */
580     private ByteArrayOutputStream JavaDoc content = null;
581
582     /** This <code>ByteArrayOutputStream</code> contains the information group. */
583     private ByteArrayOutputStream JavaDoc info = null;
584
585     /** This <code>ByteArrayOutputStream</code> contains the list table. */
586     private ByteArrayOutputStream JavaDoc listtable = null;
587
588     /** This <code>ByteArrayOutputStream</code> contains the list override table. */
589     private ByteArrayOutputStream JavaDoc listoverride = null;
590
591     /** Document header. */
592     private HeaderFooter header = null;
593
594     /** Document footer. */
595     private HeaderFooter footer = null;
596
597     /** Left margin. */
598     private int marginLeft = 1800;
599
600     /** Right margin. */
601     private int marginRight = 1800;
602
603     /** Top margin. */
604     private int marginTop = 1440;
605
606     /** Bottom margin. */
607     private int marginBottom = 1440;
608
609     /** Page width. */
610     private int pageWidth = 11906;
611
612     /** Page height. */
613     private int pageHeight = 16838;
614
615     /** Factor to use when converting. */
616     public final static double TWIPSFACTOR = 20;//20.57140;
617

618     /** Current list ID. */
619     private int currentListID = 1;
620
621     /** List of current Lists. */
622     private ArrayList JavaDoc listIds = null;
623
624     /** Current List Level. */
625     private int listLevel = 0;
626
627     /** Current maximum List Level. */
628     private int maxListLevel = 0;
629
630     /** Write a TOC */
631     private boolean writeTOC = false;
632
633     /** Special title page */
634     private boolean hasTitlePage = false;
635
636     /** Currently writing either Header or Footer */
637     private boolean inHeaderFooter = false;
638
639     /** Currently writing a Table */
640     private boolean inTable = false;
641
642     /** Landscape or Portrait Document */
643     private boolean landscape = false;
644
645     /** Protected Constructor */
646
647     /**
648      * Constructs a <CODE>RtfWriter</CODE>.
649      *
650      * @param doc The <CODE>Document</CODE> that is to be written as RTF
651      * @param os The <CODE>OutputStream</CODE> the writer has to write to.
652      */

653
654     protected RtfWriter(Document doc, OutputStream JavaDoc os) {
655         super(doc, os);
656         document.addDocListener(this);
657         initDefaults();
658     }
659
660     /** Public functions special to the RtfWriter */
661
662     /**
663      * This method controls whether TOC entries are automatically generated
664      *
665      * @param writeTOC boolean value indicating whether a TOC is to be generated
666      */

667     public void setGenerateTOCEntries(boolean writeTOC) {
668         this.writeTOC = writeTOC;
669     }
670
671     /**
672      * Gets the current setting of writeTOC
673      *
674      * @return boolean value indicating whether a TOC is being generated
675      */

676     public boolean getGeneratingTOCEntries() {
677         return writeTOC;
678     }
679
680     /**
681      * This method controls whether the first page is a title page
682      *
683      * @param hasTitlePage boolean value indicating whether the first page is a title page
684      */

685     public void setHasTitlePage(boolean hasTitlePage) {
686         this.hasTitlePage = hasTitlePage;
687     }
688
689     /**
690      * Gets the current setting of hasTitlePage
691      *
692      * @return boolean value indicating whether the first page is a title page
693      */

694     public boolean getHasTitlePage() {
695         return hasTitlePage;
696     }
697
698     /**
699      * Explicitly sets the page format to use.
700      * Otherwise the RtfWriter will try to guess the format by comparing pagewidth and pageheight
701      *
702      * @param landscape boolean value indicating whether we are using landscape format or not
703      */

704     public void setLandscape(boolean landscape) {
705         this.landscape = landscape;
706     }
707
708     /**
709      * Returns the current landscape setting
710      *
711      * @return boolean value indicating the current page format
712      */

713     public boolean getLandscape() {
714         return landscape;
715     }
716
717     /** Public functions from the DocWriter Interface */
718
719     /**
720      * Gets an instance of the <CODE>RtfWriter</CODE>.
721      *
722      * @param document The <CODE>Document</CODE> that has to be written
723      * @param os The <CODE>OutputStream</CODE> the writer has to write to.
724      * @return a new <CODE>RtfWriter</CODE>
725      */

726     public static RtfWriter getInstance(Document document, OutputStream JavaDoc os) {
727         return new RtfWriter(document, os);
728     }
729
730     /**
731      * Signals that the <CODE>Document</CODE> has been opened and that
732      * <CODE>Elements</CODE> can be added.
733      */

734     public void open() {
735         super.open();
736     }
737
738     /**
739      * Signals that the <CODE>Document</CODE> was closed and that no other
740      * <CODE>Elements</CODE> will be added.
741      * <p>
742      * The content of the font table, color table, information group, content, header, footer are merged into the final
743      * <code>OutputStream</code>
744      */

745     public void close() {
746         if (open) {
747             writeDocument();
748             super.close();
749         }
750     }
751
752     /**
753      * Adds the footer to the bottom of the <CODE>Document</CODE>.
754      * @param footer
755      */

756     public void setFooter(HeaderFooter footer) {
757         this.footer = footer;
758         processHeaderFooter(this.footer);
759     }
760
761     /**
762      * Adds the header to the top of the <CODE>Document</CODE>.
763      * @param header
764      */

765     public void setHeader(HeaderFooter header) {
766         this.header = header;
767         processHeaderFooter(this.header);
768     }
769
770     /**
771      * Resets the footer.
772      */

773     public void resetFooter() {
774         setFooter(null);
775     }
776
777     /**
778      * Resets the header.
779      */

780     public void resetHeader() {
781         setHeader(null);
782     }
783
784     /**
785      * Tells the <code>RtfWriter</code> that a new page is to be begun.
786      *
787      * @return <code>true</code> if a new Page was begun.
788      * @throws DocumentException if the Document was not open or had been closed.
789      */

790     public boolean newPage() {
791         try {
792             content.write(escape);
793             content.write(newPage);
794             content.write(escape);
795             content.write(paragraph);
796         } catch (IOException JavaDoc e) {
797             throw new ExceptionConverter(e);
798         }
799         return true;
800     }
801
802     /**
803      * Sets the page margins
804      *
805      * @param marginLeft The left margin
806      * @param marginRight The right margin
807      * @param marginTop The top margin
808      * @param marginBottom The bottom margin
809      *
810      * @return <code>true</code> if the page margins were set.
811      */

812     public boolean setMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) {
813         this.marginLeft = (int) (marginLeft * TWIPSFACTOR);
814         this.marginRight = (int) (marginRight * TWIPSFACTOR);
815         this.marginTop = (int) (marginTop * TWIPSFACTOR);
816         this.marginBottom = (int) (marginBottom * TWIPSFACTOR);
817         return true;
818     }
819
820     /**
821      * Sets the page size
822      *
823      * @param pageSize A <code>Rectangle</code> specifying the page size
824      *
825      * @return <code>true</code> if the page size was set
826      */

827     public boolean setPageSize(Rectangle pageSize) {
828         if (!parseFormat(pageSize, false)) {
829             pageWidth = (int) (pageSize.getWidth() * TWIPSFACTOR);
830             pageHeight = (int) (pageSize.getHeight() * TWIPSFACTOR);
831             landscape = pageWidth > pageHeight;
832         }
833         return true;
834     }
835
836     /**
837      * Write the table of contents.
838      *
839      * @param tocTitle The title that will be displayed above the TOC
840      * @param titleFont The <code>Font</code> that will be used for the tocTitle
841      * @param showTOCasEntry Set this to true if you want the TOC to appear as an entry in the TOC
842      * @param showTOCEntryFont Use this <code>Font</code> to specify what Font to use when showTOCasEntry is true
843      *
844      * @return <code>true</code> if the TOC was added.
845      */

846     public boolean writeTOC(String JavaDoc tocTitle, Font titleFont, boolean showTOCasEntry, Font showTOCEntryFont) {
847         try {
848             RtfTOC toc = new RtfTOC(tocTitle, titleFont);
849             if (showTOCasEntry) {
850                 toc.addTOCAsTOCEntry(tocTitle, showTOCEntryFont);
851             }
852             add(new Paragraph(toc));
853         } catch (DocumentException de) {
854             return false;
855         }
856         return true;
857     }
858
859     /**
860      * Signals that an <CODE>Element</CODE> was added to the <CODE>Document</CODE>.
861      *
862      * @param element A high level object to add
863      * @return <CODE>true</CODE> if the element was added, <CODE>false</CODE> if not.
864      * @throws DocumentException if a document isn't open yet, or has been closed
865      */

866     public boolean add(Element element) throws DocumentException {
867         if (pause) {
868             return false;
869         }
870         return addElement(element, content);
871     }
872
873
874     /** Private functions */
875
876     /**
877      * Adds an <CODE>Element</CODE> to the <CODE>Document</CODE>.
878      * @param element the high level element to add
879      * @param out the outputstream to which the RTF data is sent
880      * @return <CODE>true</CODE> if the element was added, <CODE>false</CODE> if not.
881      * @throws DocumentException if a document isn't open yet, or has been closed
882      */

883     protected boolean addElement(Element element, ByteArrayOutputStream JavaDoc out) throws DocumentException {
884         try {
885             switch (element.type()) {
886                 case Element.CHUNK:
887                     writeChunk((Chunk) element, out);
888                     break;
889                 case Element.PARAGRAPH:
890                     writeParagraph((Paragraph) element, out);
891                     break;
892                 case Element.ANCHOR:
893                     writeAnchor((Anchor) element, out);
894                     break;
895                 case Element.PHRASE:
896                     writePhrase((Phrase) element, out);
897                     break;
898                 case Element.CHAPTER:
899                 case Element.SECTION:
900                     writeSection((Section) element, out);
901                     break;
902                 case Element.LIST:
903                     writeList((com.lowagie.text.List) element, out);
904                     break;
905                 case Element.TABLE:
906                     try {
907                         writeTable((Table) element, out);
908                     }
909                     catch(ClassCastException JavaDoc cce) {
910                         writeTable(((SimpleTable)element).createTable(), out);
911                     }
912                     break;
913                 case Element.ANNOTATION:
914                     writeAnnotation((Annotation) element, out);
915                     break;
916                 case Element.IMGRAW:
917                 case Element.IMGTEMPLATE:
918                 case Element.JPEG:
919                     Image img = (Image)element;
920                     writeImage(img, out);
921                     break;
922
923                 case Element.AUTHOR:
924                     writeMeta(metaAuthor, (Meta) element);
925                     break;
926                 case Element.SUBJECT:
927                     writeMeta(metaSubject, (Meta) element);
928                     break;
929                 case Element.KEYWORDS:
930                     writeMeta(metaKeywords, (Meta) element);
931                     break;
932                 case Element.TITLE:
933                     writeMeta(metaTitle, (Meta) element);
934                     break;
935                 case Element.PRODUCER:
936                     writeMeta(metaProducer, (Meta) element);
937                     break;
938                 case Element.CREATIONDATE:
939                     writeMeta(metaCreationDate, (Meta) element);
940                     break;
941             }
942         } catch (IOException JavaDoc e) {
943             return false;
944         }
945         return true;
946     }
947
948     /**
949      * Write the beginning of a new <code>Section</code>
950      *
951      * @param sectionElement The <code>Section</code> be written
952      * @param out The <code>ByteArrayOutputStream</code> to write to
953      *
954      * @throws IOException
955      * @throws DocumentException
956      */

957     private void writeSection(Section sectionElement, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc, DocumentException {
958         if (sectionElement.type() == Element.CHAPTER) {
959             out.write(escape);
960             out.write(sectionDefaults);
961             writeSectionDefaults(out);
962         }
963         if (sectionElement.getTitle() != null) {
964             if (writeTOC) {
965                 StringBuffer JavaDoc title = new StringBuffer JavaDoc("");
966                 for (ListIterator JavaDoc li = sectionElement.getTitle().getChunks().listIterator(); li.hasNext();) {
967                     title.append(((Chunk) li.next()).getContent());
968                 }
969                 add(new RtfTOCEntry(title.toString(), sectionElement.getTitle().getFont()));
970             } else {
971                 add(sectionElement.getTitle());
972             }
973             out.write(escape);
974             out.write(paragraph);
975         }
976         sectionElement.process(this);
977         if (sectionElement.type() == Element.CHAPTER) {
978             out.write(escape);
979             out.write(section);
980         }
981         if (sectionElement.type() == Element.SECTION) {
982             out.write(escape);
983             out.write(paragraph);
984         }
985     }
986
987     /**
988      * Write the beginning of a new <code>Paragraph</code>
989      *
990      * @param paragraphElement The <code>Paragraph</code> to be written
991      * @param out The <code>ByteArrayOutputStream</code> to write to
992      *
993      * @throws IOException
994      */

995     private void writeParagraph(Paragraph paragraphElement, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc {
996         out.write(escape);
997         out.write(paragraphDefaults);
998         if (inTable) {
999             out.write(escape);
1000            out.write(RtfCell.cellInTable);
1001        }
1002        switch (paragraphElement.getAlignment()) {
1003            case Element.ALIGN_LEFT:
1004                out.write(escape);
1005                out.write(alignLeft);
1006                break;
1007            case Element.ALIGN_RIGHT:
1008                out.write(escape);
1009                out.write(alignRight);
1010                break;
1011            case Element.ALIGN_CENTER:
1012                out.write(escape);
1013                out.write(alignCenter);
1014                break;
1015            case Element.ALIGN_JUSTIFIED:
1016            case Element.ALIGN_JUSTIFIED_ALL:
1017                out.write(escape);
1018                out.write(alignJustify);
1019                break;
1020        }
1021        out.write(escape);
1022        out.write(listIndent);
1023        writeInt(out, (int) (paragraphElement.getIndentationLeft() * TWIPSFACTOR));
1024        out.write(escape);
1025        out.write(rightIndent);
1026        writeInt(out, (int) (paragraphElement.getIndentationRight() * TWIPSFACTOR));
1027        Iterator JavaDoc chunks = paragraphElement.getChunks().iterator();
1028        while (chunks.hasNext()) {
1029            Chunk ch = (Chunk) chunks.next();
1030            ch.setFont(paragraphElement.getFont().difference(ch.getFont()));
1031        }
1032        ByteArrayOutputStream JavaDoc save = content;
1033        content = out;
1034        paragraphElement.process(this);
1035        content = save;
1036        if (!inTable) {
1037            out.write(escape);
1038            out.write(paragraph);
1039        }
1040    }
1041
1042    /**
1043     * Write a <code>Phrase</code>.
1044     *
1045     * @param phrase The <code>Phrase</code> item to be written
1046     * @param out The <code>ByteArrayOutputStream</code> to write to
1047     *
1048     * @throws IOException
1049     */

1050    private void writePhrase(Phrase phrase, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc {
1051        out.write(escape);
1052        out.write(paragraphDefaults);
1053        if (inTable) {
1054            out.write(escape);
1055            out.write(RtfCell.cellInTable);
1056        }
1057        Iterator JavaDoc chunks = phrase.getChunks().iterator();
1058        while (chunks.hasNext()) {
1059            Chunk ch = (Chunk) chunks.next();
1060            ch.setFont(phrase.getFont().difference(ch.getFont()));
1061        }
1062        ByteArrayOutputStream JavaDoc save = content;
1063        content = out;
1064        phrase.process(this);
1065        content = save;
1066    }
1067
1068    /**
1069     * Write an <code>Anchor</code>. Anchors are treated like Phrases.
1070     *
1071     * @param anchor The <code>Chunk</code> item to be written
1072     * @param out The <code>ByteArrayOutputStream</code> to write to
1073     *
1074     * @throws IOException
1075     */

1076    private void writeAnchor(Anchor anchor, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc {
1077        if (anchor.getUrl() != null) {
1078            out.write(openGroup);
1079            out.write(escape);
1080            out.write(field);
1081            out.write(openGroup);
1082            out.write(extendedEscape);
1083            out.write(fieldContent);
1084            out.write(openGroup);
1085            out.write(fieldHyperlink);
1086            out.write(delimiter);
1087            out.write(anchor.getUrl().toString().getBytes());
1088            out.write(closeGroup);
1089            out.write(closeGroup);
1090            out.write(openGroup);
1091            out.write(escape);
1092            out.write(fieldDisplay);
1093            out.write(delimiter);
1094            writePhrase(anchor, out);
1095            out.write(closeGroup);
1096            out.write(closeGroup);
1097        } else {
1098            writePhrase(anchor, out);
1099        }
1100    }
1101
1102    /**
1103     * Write a <code>Chunk</code> and all its font properties.
1104     *
1105     * @param chunk The <code>Chunk</code> item to be written
1106     * @param out The <code>ByteArrayOutputStream</code> to write to
1107     *
1108     * @throws IOException
1109     * @throws DocumentException
1110     */

1111    private void writeChunk(Chunk chunk, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc, DocumentException {
1112        if (chunk instanceof RtfField) {
1113            ((RtfField) chunk).write(this, out);
1114        } else {
1115            if (chunk.getImage() != null) {
1116                writeImage(chunk.getImage(), out);
1117            } else {
1118                writeInitialFontSignature(out, chunk);
1119                out.write(filterSpecialChar(chunk.getContent(), false).getBytes());
1120                writeFinishingFontSignature(out, chunk);
1121            }
1122        }
1123    }
1124
1125
1126    protected void writeInitialFontSignature(OutputStream JavaDoc out, Chunk chunk) throws IOException JavaDoc {
1127        Font font = chunk.getFont();
1128
1129        out.write(escape);
1130        out.write(fontNumber);
1131        if (!font.getFamilyname().equalsIgnoreCase("unknown")) {
1132            writeInt(out, addFont(font));
1133        } else {
1134            writeInt(out, 0);
1135        }
1136        out.write(escape);
1137        out.write(fontSize);
1138        if (font.getSize() > 0) {
1139            writeInt(out, (int) (font.getSize() * 2));
1140        } else {
1141            writeInt(out, 20);
1142        }
1143        out.write(escape);
1144        out.write(fontColor);
1145        writeInt(out, addColor(font.getColor()));
1146        if (font.isBold()) {
1147            out.write(escape);
1148            out.write(bold);
1149        }
1150        if (font.isItalic()) {
1151            out.write(escape);
1152            out.write(italic);
1153        }
1154        if (font.isUnderlined()) {
1155            out.write(escape);
1156            out.write(underline);
1157        }
1158        if (font.isStrikethru()) {
1159            out.write(escape);
1160            out.write(strikethrough);
1161        }
1162
1163        /*
1164         * Superscript / Subscript added by Scott Dietrich (sdietrich@emlab.com)
1165         */

1166        if (chunk.getAttributes() != null) {
1167            Float JavaDoc f = (Float JavaDoc) chunk.getAttributes().get(Chunk.SUBSUPSCRIPT);
1168            if (f != null)
1169                if (f.floatValue() > 0) {
1170                    out.write(escape);
1171                    out.write(startSuper);
1172                } else if (f.floatValue() < 0) {
1173                    out.write(escape);
1174                    out.write(startSub);
1175                }
1176        }
1177
1178        out.write(delimiter);
1179    }
1180
1181
1182    protected void writeFinishingFontSignature(OutputStream JavaDoc out, Chunk chunk) throws IOException JavaDoc {
1183        Font font = chunk.getFont();
1184
1185        if (font.isBold()) {
1186            out.write(escape);
1187            out.write(bold);
1188            writeInt(out, 0);
1189        }
1190        if (font.isItalic()) {
1191            out.write(escape);
1192            out.write(italic);
1193            writeInt(out, 0);
1194        }
1195        if (font.isUnderlined()) {
1196            out.write(escape);
1197            out.write(underline);
1198            writeInt(out, 0);
1199        }
1200        if (font.isStrikethru()) {
1201            out.write(escape);
1202            out.write(strikethrough);
1203            writeInt(out, 0);
1204        }
1205
1206        /*
1207         * Superscript / Subscript added by Scott Dietrich (sdietrich@emlab.com)
1208         */

1209        if (chunk.getAttributes() != null) {
1210            Float JavaDoc f = (Float JavaDoc) chunk.getAttributes().get(Chunk.SUBSUPSCRIPT);
1211            if (f != null)
1212                if (f.floatValue() != 0) {
1213                    out.write(escape);
1214                    out.write(endSuperSub);
1215                }
1216        }
1217    }
1218
1219    /**
1220     * Write a <code>ListItem</code>
1221     *
1222     * @param listItem The <code>ListItem</code> to be written
1223     * @param out The <code>ByteArrayOutputStream</code> to write to
1224     *
1225     * @throws IOException
1226     * @throws DocumentException
1227     */

1228    private void writeListElement(ListItem listItem, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc, DocumentException {
1229        Iterator JavaDoc chunks = listItem.getChunks().iterator();
1230        while (chunks.hasNext()) {
1231            Chunk ch = (Chunk) chunks.next();
1232            addElement(ch, out);
1233        }
1234        out.write(escape);
1235        out.write(paragraph);
1236    }
1237
1238    /**
1239     * Write a <code>List</code>
1240     *
1241     * @param list The <code>List</code> to be written
1242     * @param out The <code>ByteArrayOutputStream</code> to write to
1243     *
1244     * @throws IOException
1245     * @throws DocumentException
1246     */

1247    private void writeList(com.lowagie.text.List list, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc, DocumentException {
1248        int type = 0;
1249        int align = 0;
1250        int fontNr = addFont(new Font(Font.SYMBOL, 10, Font.NORMAL, new Color JavaDoc(0, 0, 0)));
1251        if (!list.isNumbered()) type = 23;
1252        if (listLevel == 0) {
1253            maxListLevel = 0;
1254            listtable.write(openGroup);
1255            listtable.write(escape);
1256            listtable.write(listDefinition);
1257            int i = getRandomInt();
1258            listtable.write(escape);
1259            listtable.write(listTemplateID);
1260            writeInt(listtable, i);
1261            listtable.write(escape);
1262            listtable.write(hybridList);
1263            listtable.write((byte) '\n');
1264        }
1265        if (listLevel >= maxListLevel) {
1266            maxListLevel++;
1267            listtable.write(openGroup);
1268            listtable.write(escape);
1269            listtable.write(listLevelDefinition);
1270            listtable.write(escape);
1271            listtable.write(listLevelTypeOld);
1272            writeInt(listtable, type);
1273            listtable.write(escape);
1274            listtable.write(listLevelTypeNew);
1275            writeInt(listtable, type);
1276            listtable.write(escape);
1277            listtable.write(listLevelAlignOld);
1278            writeInt(listtable, align);
1279            listtable.write(escape);
1280            listtable.write(listLevelAlignNew);
1281            writeInt(listtable, align);
1282            listtable.write(escape);
1283            listtable.write(listLevelStartAt);
1284            writeInt(listtable, 1);
1285            listtable.write(openGroup);
1286            listtable.write(escape);
1287            listtable.write(listLevelTextDefinition);
1288            listtable.write(escape);
1289            listtable.write(listLevelTextLength);
1290            if (list.isNumbered()) {
1291                writeInt(listtable, 2);
1292            } else {
1293                writeInt(listtable, 1);
1294            }
1295            listtable.write(escape);
1296            if (list.isNumbered()) {
1297                listtable.write(listLevelTextStyleNumbers);
1298            } else {
1299                listtable.write(listLevelTextStyleBullet);
1300            }
1301            listtable.write(commaDelimiter);
1302            listtable.write(closeGroup);
1303            listtable.write(openGroup);
1304            listtable.write(escape);
1305            listtable.write(listLevelNumbersDefinition);
1306            if (list.isNumbered()) {
1307                listtable.write(delimiter);
1308                listtable.write(listLevelNumbers);
1309                writeInt(listtable, listLevel + 1);
1310            }
1311            listtable.write(commaDelimiter);
1312            listtable.write(closeGroup);
1313            if (!list.isNumbered()) {
1314                listtable.write(escape);
1315                listtable.write(fontNumber);
1316                writeInt(listtable, fontNr);
1317            }
1318            listtable.write(escape);
1319            listtable.write(firstIndent);
1320            writeInt(listtable, (int) (list.getIndentationLeft() * TWIPSFACTOR * -1));
1321            listtable.write(escape);
1322            listtable.write(listIndent);
1323            writeInt(listtable, (int) ((list.getIndentationLeft() + list.getSymbolIndent()) * TWIPSFACTOR));
1324            listtable.write(escape);
1325            listtable.write(rightIndent);
1326            writeInt(listtable, (int) (list.getIndentationRight() * TWIPSFACTOR));
1327            listtable.write(escape);
1328            listtable.write(tabStop);
1329            writeInt(listtable, (int) (list.getSymbolIndent() * TWIPSFACTOR));
1330            listtable.write(closeGroup);
1331            listtable.write((byte) '\n');
1332        }
1333        // Actual List Begin in Content
1334
out.write(escape);
1335        out.write(paragraphDefaults);
1336        out.write(escape);
1337        out.write(alignLeft);
1338        out.write(escape);
1339        out.write(firstIndent);
1340        writeInt(out, (int) (list.getIndentationLeft() * TWIPSFACTOR * -1));
1341        out.write(escape);
1342        out.write(listIndent);
1343        writeInt(out, (int) ((list.getIndentationLeft() + list.getSymbolIndent()) * TWIPSFACTOR));
1344        out.write(escape);
1345        out.write(rightIndent);
1346        writeInt(out, (int) (list.getIndentationRight() * TWIPSFACTOR));
1347        out.write(escape);
1348        out.write(fontSize);
1349        writeInt(out, 20);
1350        out.write(escape);
1351        out.write(listBegin);
1352        writeInt(out, currentListID);
1353        if (listLevel > 0) {
1354            out.write(escape);
1355            out.write(listCurrentLevel);
1356            writeInt(out, listLevel);
1357        }
1358        out.write(openGroup);
1359        ListIterator JavaDoc listItems = list.getItems().listIterator();
1360        Element listElem;
1361        int count = 1;
1362        while (listItems.hasNext()) {
1363            listElem = (Element) listItems.next();
1364            if (listElem.type() == Element.CHUNK) {
1365                listElem = new ListItem((Chunk) listElem);
1366            }
1367            if (listElem.type() == Element.LISTITEM) {
1368                out.write(openGroup);
1369                out.write(escape);
1370                out.write(listTextOld);
1371                out.write(escape);
1372                out.write(paragraphDefaults);
1373                out.write(escape);
1374                out.write(fontNumber);
1375                if (list.isNumbered()) {
1376                    writeInt(out, addFont(new Font(Font.TIMES_ROMAN, Font.NORMAL, 10, new Color JavaDoc(0, 0, 0))));
1377                } else {
1378                    writeInt(out, fontNr);
1379                }
1380                out.write(escape);
1381                out.write(firstIndent);
1382                writeInt(out, (int) (list.getIndentationLeft() * TWIPSFACTOR * -1));
1383                out.write(escape);
1384                out.write(listIndent);
1385                writeInt(out, (int) ((list.getIndentationLeft() + list.getSymbolIndent()) * TWIPSFACTOR));
1386                out.write(escape);
1387                out.write(rightIndent);
1388                writeInt(out, (int) (list.getIndentationRight() * TWIPSFACTOR));
1389                out.write(delimiter);
1390                if (list.isNumbered()) {
1391                    writeInt(out, count);
1392                    out.write(".".getBytes());
1393                } else {
1394                    out.write(escape);
1395                    out.write(listBulletOld);
1396                }
1397                out.write(escape);
1398                out.write(tab);
1399                out.write(closeGroup);
1400                writeListElement((ListItem) listElem, out);
1401                count++;
1402            } else if (listElem.type() == Element.LIST) {
1403                listLevel++;
1404                writeList((com.lowagie.text.List) listElem, out);
1405                listLevel--;
1406                out.write(escape);
1407                out.write(paragraphDefaults);
1408                out.write(escape);
1409                out.write(alignLeft);
1410                out.write(escape);
1411                out.write(firstIndent);
1412                writeInt(out, (int) (list.getIndentationLeft() * TWIPSFACTOR * -1));
1413                out.write(escape);
1414                out.write(listIndent);
1415                writeInt(out, (int) ((list.getIndentationLeft() + list.getSymbolIndent()) * TWIPSFACTOR));
1416                out.write(escape);
1417                out.write(rightIndent);
1418                writeInt(out, (int) (list.getIndentationRight() * TWIPSFACTOR));
1419                out.write(escape);
1420                out.write(fontSize);
1421                writeInt(out, 20);
1422                out.write(escape);
1423                out.write(listBegin);
1424                writeInt(out, currentListID);
1425                if (listLevel > 0) {
1426                    out.write(escape);
1427                    out.write(listCurrentLevel);
1428                    writeInt(out, listLevel);
1429                }
1430            }
1431            out.write((byte) '\n');
1432        }
1433        out.write(closeGroup);
1434        if (listLevel == 0) {
1435            int i = getRandomInt();
1436            listtable.write(escape);
1437            listtable.write(listID);
1438            writeInt(listtable, i);
1439            listtable.write(closeGroup);
1440            listtable.write((byte) '\n');
1441            listoverride.write(openGroup);
1442            listoverride.write(escape);
1443            listoverride.write(listOverride);
1444            listoverride.write(escape);
1445            listoverride.write(listID);
1446            writeInt(listoverride, i);
1447            listoverride.write(escape);
1448            listoverride.write(listOverrideCount);
1449            writeInt(listoverride, 0);
1450            listoverride.write(escape);
1451            listoverride.write(listBegin);
1452            writeInt(listoverride, currentListID);
1453            currentListID++;
1454            listoverride.write(closeGroup);
1455            listoverride.write((byte) '\n');
1456        }
1457        out.write(escape);
1458        out.write(paragraphDefaults);
1459    }
1460
1461    /**
1462     * Write a <code>Table</code>.
1463     *
1464     * @param table The <code>table</code> to be written
1465     * @param out The <code>ByteArrayOutputStream</code> to write to
1466     *
1467     * Currently no nesting of tables is supported. If a cell contains anything but a Cell Object it is ignored.
1468     *
1469     * @throws IOException
1470     * @throws DocumentException
1471     */

1472    private void writeTable(Table table, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc, DocumentException {
1473        inTable = true;
1474        table.complete();
1475        RtfTable rtfTable = new RtfTable(this);
1476        rtfTable.importTable(table, pageWidth - marginLeft - marginRight);
1477        rtfTable.writeTable(out);
1478        inTable = false;
1479    }
1480
1481
1482    /**
1483     * Write an <code>Image</code>.
1484     *
1485     * @param image The <code>image</code> to be written
1486     * @param out The <code>ByteArrayOutputStream</code> to write to
1487     *
1488     * At the moment only PNG and JPEG Images are supported.
1489     *
1490     * @throws IOException
1491     * @throws DocumentException
1492     */

1493    private void writeImage(Image image, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc, DocumentException {
1494        int type = image.getOriginalType();
1495        if (!(type == Image.ORIGINAL_JPEG || type == Image.ORIGINAL_BMP
1496            || type == Image.ORIGINAL_PNG || type == Image.ORIGINAL_WMF))
1497            throw new DocumentException("Only BMP, PNG, WMF and JPEG images are supported by the RTF Writer");
1498        switch (image.getAlignment()) {
1499            case Element.ALIGN_LEFT:
1500                out.write(escape);
1501                out.write(alignLeft);
1502                break;
1503            case Element.ALIGN_RIGHT:
1504                out.write(escape);
1505                out.write(alignRight);
1506                break;
1507            case Element.ALIGN_CENTER:
1508                out.write(escape);
1509                out.write(alignCenter);
1510                break;
1511            case Element.ALIGN_JUSTIFIED:
1512                out.write(escape);
1513                out.write(alignJustify);
1514                break;
1515        }
1516        out.write(openGroup);
1517        out.write(extendedEscape);
1518        out.write(pictureGroup);
1519        out.write(openGroup);
1520        out.write(escape);
1521        out.write(picture);
1522        out.write(escape);
1523        switch (type) {
1524            case Image.ORIGINAL_JPEG:
1525                out.write(pictureJPEG);
1526                break;
1527            case Image.ORIGINAL_PNG:
1528                out.write(picturePNG);
1529                break;
1530            case Image.ORIGINAL_WMF:
1531            case Image.ORIGINAL_BMP:
1532                out.write(pictureWMF);
1533                break;
1534        }
1535        out.write(escape);
1536        out.write(pictureWidth);
1537        writeInt(out, (int) (image.getPlainWidth() * TWIPSFACTOR));
1538        out.write(escape);
1539        out.write(pictureHeight);
1540        writeInt(out, (int) (image.getPlainHeight() * TWIPSFACTOR));
1541
1542
1543// For some reason this messes up the intended image size. It makes it too big. Weird
1544
//
1545
// out.write(escape);
1546
// out.write(pictureIntendedWidth);
1547
// writeInt(out, (int) (image.plainWidth() * twipsFactor));
1548
// out.write(escape);
1549
// out.write(pictureIntendedHeight);
1550
// writeInt(out, (int) (image.plainHeight() * twipsFactor));
1551

1552
1553        if (image.getWidth() > 0) {
1554            out.write(escape);
1555            out.write(pictureScaleX);
1556            writeInt(out, (int) (100 / image.getWidth() * image.getPlainWidth()));
1557        }
1558        if (image.getHeight() > 0) {
1559            out.write(escape);
1560            out.write(pictureScaleY);
1561            writeInt(out, (int) (100 / image.getHeight() * image.getPlainHeight()));
1562        }
1563        out.write(delimiter);
1564        InputStream JavaDoc imgIn;
1565        if (type == Image.ORIGINAL_BMP) {
1566            imgIn = new ByteArrayInputStream JavaDoc(MetaDo.wrapBMP(image));
1567        }
1568        else {
1569            if (image.getOriginalData() == null) {
1570                imgIn = image.getUrl().openStream();
1571            } else {
1572                imgIn = new ByteArrayInputStream JavaDoc(image.getOriginalData());
1573            }
1574            if (type == Image.ORIGINAL_WMF) { //remove the placeable header
1575
long skipLength = 22;
1576                while(skipLength > 0) {
1577                    skipLength = skipLength - imgIn.skip(skipLength);
1578                }
1579            }
1580        }
1581        int buffer = -1;
1582        int count = 0;
1583        out.write((byte) '\n');
1584        while ((buffer = imgIn.read()) != -1) {
1585            String JavaDoc helperStr = Integer.toHexString(buffer);
1586            if (helperStr.length() < 2) helperStr = "0" + helperStr;
1587            out.write(helperStr.getBytes());
1588            count++;
1589            if (count == 64) {
1590                out.write((byte) '\n');
1591                count = 0;
1592            }
1593        }
1594        imgIn.close();
1595        out.write(closeGroup);
1596        out.write(closeGroup);
1597        out.write((byte) '\n');
1598    }
1599
1600    /**
1601     * Write an <code>Annotation</code>
1602     *
1603     * @param annotationElement The <code>Annotation</code> to be written
1604     * @param out The <code>ByteArrayOutputStream</code> to write to
1605     *
1606     * @throws IOException
1607     */

1608    private void writeAnnotation(Annotation annotationElement, ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc {
1609        int id = getRandomInt();
1610        out.write(openGroup);
1611        out.write(extendedEscape);
1612        out.write(annotationID);
1613        out.write(delimiter);
1614        writeInt(out, id);
1615        out.write(closeGroup);
1616        out.write(openGroup);
1617        out.write(extendedEscape);
1618        out.write(annotationAuthor);
1619        out.write(delimiter);
1620        out.write(annotationElement.title().getBytes());
1621        out.write(closeGroup);
1622        out.write(openGroup);
1623        out.write(extendedEscape);
1624        out.write(annotation);
1625        out.write(escape);
1626        out.write(paragraphDefaults);
1627        out.write(delimiter);
1628        out.write(annotationElement.content().getBytes());
1629        out.write(closeGroup);
1630    }
1631
1632    /**
1633     * Add a <code>Meta</code> element. It is written to the Inforamtion Group
1634     * and merged with the main <code>ByteArrayOutputStream</code> when the
1635     * Document is closed.
1636     *
1637     * @param metaName The type of <code>Meta</code> element to be added
1638     * @param meta The <code>Meta</code> element to be added
1639     *
1640     * Currently only the Meta Elements Author, Subject, Keywords, Title, Producer and CreationDate are supported.
1641     *
1642     * @throws IOException
1643     */

1644    private void writeMeta(byte[] metaName, Meta meta) throws IOException JavaDoc {
1645        info.write(openGroup);
1646        try {
1647            info.write(escape);
1648            info.write(metaName);
1649            info.write(delimiter);
1650            if (meta.type() == Meta.CREATIONDATE) {
1651                writeFormatedDateTime(meta.getContent());
1652            } else {
1653                info.write(meta.getContent().getBytes());
1654            }
1655        } finally {
1656            info.write(closeGroup);
1657        }
1658    }
1659
1660    /**
1661     * Writes a date. The date is formated <strong>Year, Month, Day, Hour, Minute, Second</strong>
1662     *
1663     * @param date The date to be written
1664     *
1665     * @throws IOException
1666     */

1667    private void writeFormatedDateTime(String JavaDoc date) throws IOException JavaDoc {
1668        Calendar JavaDoc cal = Calendar.getInstance();
1669        SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc("EEE MMM dd HH:mm:ss zzz yyyy");
1670        ParsePosition JavaDoc pp = new ParsePosition JavaDoc(0);
1671        Date JavaDoc d = sdf.parse(date, pp);
1672        if (d == null) {
1673            d = new Date JavaDoc();
1674        }
1675        cal.setTime(d);
1676        info.write(escape);
1677        info.write(year);
1678        writeInt(info, cal.get(Calendar.YEAR));
1679        info.write(escape);
1680        info.write(month);
1681        writeInt(info, cal.get(Calendar.MONTH));
1682        info.write(escape);
1683        info.write(day);
1684        writeInt(info, cal.get(Calendar.DAY_OF_MONTH));
1685        info.write(escape);
1686        info.write(hour);
1687        writeInt(info, cal.get(Calendar.HOUR_OF_DAY));
1688        info.write(escape);
1689        info.write(minute);
1690        writeInt(info, cal.get(Calendar.MINUTE));
1691        info.write(escape);
1692        info.write(second);
1693        writeInt(info, cal.get(Calendar.SECOND));
1694    }
1695
1696    /**
1697     * Add a new <code>Font</code> to the list of fonts. If the <code>Font</code>
1698     * already exists in the list of fonts, then it is not added again.
1699     *
1700     * @param newFont The <code>Font</code> to be added
1701     *
1702     * @return The index of the <code>Font</code> in the font list
1703     */

1704    protected int addFont(Font newFont) {
1705        int fn = -1;
1706
1707        for (int i = 0; i < fontList.size(); i++) {
1708            if (newFont.getFamilyname().equals(((Font) fontList.get(i)).getFamilyname())) {
1709                fn = i;
1710            }
1711        }
1712        if (fn == -1) {
1713            fontList.add(newFont);
1714            return fontList.size() - 1;
1715        }
1716        return fn;
1717    }
1718
1719    /**
1720     * Add a new <code>Color</code> to the list of colours. If the <code>Color</code>
1721     * already exists in the list of colours, then it is not added again.
1722     *
1723     * @param newColor The <code>Color</code> to be added
1724     *
1725     * @return The index of the <code>color</code> in the colour list
1726     */

1727    protected int addColor(Color JavaDoc newColor) {
1728        int cn = 0;
1729        if (newColor == null) {
1730            return cn;
1731        }
1732        cn = colorList.indexOf(newColor);
1733        if (cn == -1) {
1734            colorList.add(newColor);
1735            return colorList.size() - 1;
1736        }
1737        return cn;
1738    }
1739
1740    /**
1741     * Merge all the different <code>ArrayList</code>s and <code>ByteArrayOutputStream</code>s
1742     * to the final <code>ByteArrayOutputStream</code>
1743     *
1744     * @return <code>true</code> if all information was sucessfully written to the <code>ByteArrayOutputStream</code>
1745     */

1746    private boolean writeDocument() {
1747        try {
1748            writeDocumentIntro();
1749            writeFontList();
1750            os.write((byte) '\n');
1751            writeColorList();
1752            os.write((byte) '\n');
1753            writeList();
1754            os.write((byte) '\n');
1755            writeInfoGroup();
1756            os.write((byte) '\n');
1757            writeDocumentFormat();
1758            os.write((byte) '\n');
1759            ByteArrayOutputStream JavaDoc hf = new ByteArrayOutputStream JavaDoc();
1760            writeSectionDefaults(hf);
1761            hf.writeTo(os);
1762            content.writeTo(os);
1763            os.write(closeGroup);
1764            return true;
1765        } catch (IOException JavaDoc e) {
1766            System.err.println(e.getMessage());
1767            return false;
1768        }
1769
1770    }
1771
1772    /** Write the Rich Text file settings
1773     * @throws IOException
1774     */

1775    private void writeDocumentIntro() throws IOException JavaDoc {
1776        os.write(openGroup);
1777        os.write(escape);
1778        os.write(docBegin);
1779        os.write(escape);
1780        os.write(ansi);
1781        os.write(escape);
1782        os.write(ansiCodepage);
1783        writeInt(os, 1252);
1784        os.write((byte)'\n');
1785        os.write(escape);
1786        os.write(defaultFont);
1787        writeInt(os, 0);
1788    }
1789
1790    /**
1791     * Write the font list to the final <code>ByteArrayOutputStream</code>
1792     * @throws IOException
1793     */

1794    private void writeFontList() throws IOException JavaDoc {
1795        Font fnt;
1796
1797        os.write(openGroup);
1798        os.write(escape);
1799        os.write(fontTable);
1800        for (int i = 0; i < fontList.size(); i++) {
1801            fnt = (Font) fontList.get(i);
1802            os.write(openGroup);
1803            os.write(escape);
1804            os.write(fontNumber);
1805            writeInt(os, i);
1806            os.write(escape);
1807            switch (Font.getFamilyIndex(fnt.getFamilyname())) {
1808                case Font.COURIER:
1809                    os.write(fontModern);
1810                    os.write(escape);
1811                    os.write(fontCharset);
1812                    writeInt(os, 0);
1813                    os.write(delimiter);
1814                    os.write(fontCourier);
1815                    break;
1816                case Font.HELVETICA:
1817                    os.write(fontSwiss);
1818                    os.write(escape);
1819                    os.write(fontCharset);
1820                    writeInt(os, 0);
1821                    os.write(delimiter);
1822                    os.write(fontArial);
1823                    break;
1824                case Font.SYMBOL:
1825                    os.write(fontRoman);
1826                    os.write(escape);
1827                    os.write(fontCharset);
1828                    writeInt(os, 2);
1829                    os.write(delimiter);
1830                    os.write(fontSymbol);
1831                    break;
1832                case Font.TIMES_ROMAN:
1833                    os.write(fontRoman);
1834                    os.write(escape);
1835                    os.write(fontCharset);
1836                    writeInt(os, 0);
1837                    os.write(delimiter);
1838                    os.write(fontTimesNewRoman);
1839                    break;
1840                case Font.ZAPFDINGBATS:
1841                    os.write(fontTech);
1842                    os.write(escape);
1843                    os.write(fontCharset);
1844                    writeInt(os, 0);
1845                    os.write(delimiter);
1846                    os.write(fontWindings);
1847                    break;
1848                default:
1849                    os.write(fontRoman);
1850                    os.write(escape);
1851                    os.write(fontCharset);
1852                    writeInt(os, 0);
1853                    os.write(delimiter);
1854                    os.write(filterSpecialChar(fnt.getFamilyname(), true).getBytes());
1855            }
1856            os.write(commaDelimiter);
1857            os.write(closeGroup);
1858        }
1859        os.write(closeGroup);
1860    }
1861
1862    /**
1863     * Write the colour list to the final <code>ByteArrayOutputStream</code>
1864     * @throws IOException
1865     */

1866    private void writeColorList() throws IOException JavaDoc {
1867        Color JavaDoc color = null;
1868
1869        os.write(openGroup);
1870        os.write(escape);
1871        os.write(colorTable);
1872        for (int i = 0; i < colorList.size(); i++) {
1873            color = (Color JavaDoc) colorList.get(i);
1874            os.write(escape);
1875            os.write(colorRed);
1876            writeInt(os, color.getRed());
1877            os.write(escape);
1878            os.write(colorGreen);
1879            writeInt(os, color.getGreen());
1880            os.write(escape);
1881            os.write(colorBlue);
1882            writeInt(os, color.getBlue());
1883            os.write(commaDelimiter);
1884        }
1885        os.write(closeGroup);
1886    }
1887
1888    /**
1889     * Write the Information Group to the final <code>ByteArrayOutputStream</code>
1890     * @throws IOException
1891     */

1892    private void writeInfoGroup() throws IOException JavaDoc {
1893        os.write(openGroup);
1894        os.write(escape);
1895        os.write(infoBegin);
1896        info.writeTo(os);
1897        os.write(closeGroup);
1898    }
1899
1900    /**
1901     * Write the listtable and listoverridetable to the final <code>ByteArrayOutputStream</code>
1902     * @throws IOException
1903     */

1904    private void writeList() throws IOException JavaDoc {
1905        listtable.write(closeGroup);
1906        listoverride.write(closeGroup);
1907        listtable.writeTo(os);
1908        os.write((byte) '\n');
1909        listoverride.writeTo(os);
1910    }
1911
1912    /**
1913     * Write an integer
1914     *
1915     * @param out The <code>OuputStream</code> to which the <code>int</code> value is to be written
1916     * @param i The <code>int</code> value to be written
1917     * @throws IOException
1918     */

1919    public final static void writeInt(OutputStream JavaDoc out, int i) throws IOException JavaDoc {
1920        out.write(Integer.toString(i).getBytes());
1921    }
1922
1923    /**
1924     * Get a random integer.
1925     * This returns a <b>unique</b> random integer to be used with listids.
1926     *
1927     * @return Random <code>int</code> value.
1928     */

1929    private int getRandomInt() {
1930        boolean ok = false;
1931        Integer JavaDoc newInt = null;
1932        Integer JavaDoc oldInt = null;
1933        while (!ok) {
1934            newInt = new Integer JavaDoc((int) (Math.random() * Integer.MAX_VALUE));
1935            ok = true;
1936            for (int i = 0; i < listIds.size(); i++) {
1937                oldInt = (Integer JavaDoc) listIds.get(i);
1938                if (oldInt.equals(newInt)) {
1939                    ok = true;
1940                }
1941            }
1942        }
1943        listIds.add(newInt);
1944        return newInt.intValue();
1945    }
1946
1947    /**
1948     * Write the current header and footer to a <code>ByteArrayOutputStream</code>
1949     *
1950     * @param os The <code>ByteArrayOutputStream</code> to which the header and footer will be written.
1951     * @throws IOException
1952     */

1953    public void writeHeadersFooters(ByteArrayOutputStream JavaDoc os) throws IOException JavaDoc {
1954        if (this.footer instanceof RtfHeaderFooters) {
1955            RtfHeaderFooters rtfHf = (RtfHeaderFooters) this.footer;
1956            HeaderFooter hf = rtfHf.get(RtfHeaderFooters.ALL_PAGES);
1957            if (hf != null) {
1958                writeHeaderFooter(hf, footerBegin, os);
1959            }
1960            hf = rtfHf.get(RtfHeaderFooters.LEFT_PAGES);
1961            if (hf != null) {
1962                writeHeaderFooter(hf, footerlBegin, os);
1963            }
1964            hf = rtfHf.get(RtfHeaderFooters.RIGHT_PAGES);
1965            if (hf != null) {
1966                writeHeaderFooter(hf, footerrBegin, os);
1967            }
1968            hf = rtfHf.get(RtfHeaderFooters.FIRST_PAGE);
1969            if (hf != null) {
1970                writeHeaderFooter(hf, footerfBegin, os);
1971            }
1972        } else {
1973            writeHeaderFooter(this.footer, footerBegin, os);
1974        }
1975        if (this.header instanceof RtfHeaderFooters) {
1976            RtfHeaderFooters rtfHf = (RtfHeaderFooters) this.header;
1977            HeaderFooter hf = rtfHf.get(RtfHeaderFooters.ALL_PAGES);
1978            if (hf != null) {
1979                writeHeaderFooter(hf, headerBegin, os);
1980            }
1981            hf = rtfHf.get(RtfHeaderFooters.LEFT_PAGES);
1982            if (hf != null) {
1983                writeHeaderFooter(hf, headerlBegin, os);
1984            }
1985            hf = rtfHf.get(RtfHeaderFooters.RIGHT_PAGES);
1986            if (hf != null) {
1987                writeHeaderFooter(hf, headerrBegin, os);
1988            }
1989            hf = rtfHf.get(RtfHeaderFooters.FIRST_PAGE);
1990            if (hf != null) {
1991                writeHeaderFooter(hf, headerfBegin, os);
1992            }
1993        } else {
1994            writeHeaderFooter(this.header, headerBegin, os);
1995        }
1996    }
1997
1998    /**
1999     * Write a <code>HeaderFooter</code> to a <code>ByteArrayOutputStream</code>
2000     *
2001     * @param headerFooter The <code>HeaderFooter</code> object to be written.
2002     * @param hfType The type of header or footer to be added.
2003     * @param target The <code>ByteArrayOutputStream</code> to which the <code>HeaderFooter</code> will be written.
2004     * @throws IOException
2005     */

2006    private void writeHeaderFooter(HeaderFooter headerFooter, byte[] hfType, ByteArrayOutputStream JavaDoc target) throws IOException JavaDoc {
2007        inHeaderFooter = true;
2008        try {
2009            target.write(openGroup);
2010            target.write(escape);
2011            target.write(hfType);
2012            target.write(delimiter);
2013            if (headerFooter != null) {
2014                if (headerFooter instanceof RtfHeaderFooter && ((RtfHeaderFooter) headerFooter).content() != null) {
2015                    this.addElement(((RtfHeaderFooter) headerFooter).content(), target);
2016                } else {
2017                    Paragraph par = new Paragraph();
2018                    par.setAlignment(headerFooter.alignment());
2019                    if (headerFooter.getBefore() != null) {
2020                        par.add(headerFooter.getBefore());
2021                    }
2022                    if (headerFooter.isNumbered()) {
2023                        par.add(new RtfPageNumber("", headerFooter.getBefore().getFont()));
2024                    }
2025                    if (headerFooter.getAfter() != null) {
2026                        par.add(headerFooter.getAfter());
2027                    }
2028                    this.addElement(par, target);
2029                }
2030            }
2031            target.write(closeGroup);
2032        } catch (DocumentException e) {
2033            throw new IOException JavaDoc("DocumentException - " + e.getMessage());
2034        }
2035        inHeaderFooter = false;
2036    }
2037
2038    /**
2039     * Write the <code>Document</code>'s Paper and Margin Size
2040     * to the final <code>ByteArrayOutputStream</code>
2041     * @throws IOException
2042     */

2043    private void writeDocumentFormat() throws IOException JavaDoc {
2044// os.write(openGroup);
2045
os.write(escape);
2046        os.write(rtfPaperWidth);
2047        writeInt(os, pageWidth);
2048        os.write(escape);
2049        os.write(rtfPaperHeight);
2050        writeInt(os, pageHeight);
2051        os.write(escape);
2052        os.write(rtfMarginLeft);
2053        writeInt(os, marginLeft);
2054        os.write(escape);
2055        os.write(rtfMarginRight);
2056        writeInt(os, marginRight);
2057        os.write(escape);
2058        os.write(rtfMarginTop);
2059        writeInt(os, marginTop);
2060        os.write(escape);
2061        os.write(rtfMarginBottom);
2062        writeInt(os, marginBottom);
2063// os.write(closeGroup);
2064
}
2065
2066    /**
2067     * Initialise all helper classes.
2068     * Clears alls lists, creates new <code>ByteArrayOutputStream</code>'s
2069     */

2070    private void initDefaults() {
2071        fontList.clear();
2072        colorList.clear();
2073        info = new ByteArrayOutputStream JavaDoc();
2074        content = new ByteArrayOutputStream JavaDoc();
2075        listtable = new ByteArrayOutputStream JavaDoc();
2076        listoverride = new ByteArrayOutputStream JavaDoc();
2077        document.addProducer();
2078        document.addCreationDate();
2079        addFont(new Font(Font.TIMES_ROMAN, 10, Font.NORMAL));
2080        addColor(new Color JavaDoc(0, 0, 0));
2081        addColor(new Color JavaDoc(255, 255, 255));
2082        listIds = new ArrayList JavaDoc();
2083        try {
2084            listtable.write(openGroup);
2085            listtable.write(extendedEscape);
2086            listtable.write(listtableGroup);
2087            listtable.write((byte) '\n');
2088            listoverride.write(openGroup);
2089            listoverride.write(extendedEscape);
2090            listoverride.write(listoverridetableGroup);
2091            listoverride.write((byte) '\n');
2092        } catch (IOException JavaDoc e) {
2093            System.err.println("InitDefaultsError" + e);
2094        }
2095    }
2096
2097    /**
2098     * Writes the default values for the current Section
2099     *
2100     * @param out The <code>ByteArrayOutputStream</code> to be written to
2101     * @throws IOException
2102     */

2103    private void writeSectionDefaults(ByteArrayOutputStream JavaDoc out) throws IOException JavaDoc {
2104        if (header instanceof RtfHeaderFooters || footer instanceof RtfHeaderFooters) {
2105            RtfHeaderFooters rtfHeader = (RtfHeaderFooters) header;
2106            RtfHeaderFooters rtfFooter = (RtfHeaderFooters) footer;
2107            if ((rtfHeader != null && (rtfHeader.get(RtfHeaderFooters.LEFT_PAGES) != null || rtfHeader.get(RtfHeaderFooters.RIGHT_PAGES) != null)) || (rtfFooter != null && (rtfFooter.get(RtfHeaderFooters.LEFT_PAGES) != null || rtfFooter.get(RtfHeaderFooters.RIGHT_PAGES) != null))) {
2108                out.write(escape);
2109                out.write(facingPages);
2110            }
2111        }
2112        if (hasTitlePage) {
2113            out.write(escape);
2114            out.write(titlePage);
2115        }
2116        writeHeadersFooters(out);
2117        if (landscape) {
2118            //out.write(escape);
2119
//out.write(landscapeTag1);
2120
out.write(escape);
2121            out.write(landscapeTag2);
2122            out.write(escape);
2123            out.write(sectionPageWidth);
2124            writeInt(out, pageWidth);
2125            out.write(escape);
2126            out.write(sectionPageHeight);
2127            writeInt(out, pageHeight);
2128        } else {
2129            out.write(escape);
2130            out.write(sectionPageWidth);
2131            writeInt(out, pageWidth);
2132            out.write(escape);
2133            out.write(sectionPageHeight);
2134            writeInt(out, pageHeight);
2135        }
2136    }
2137
2138    /**
2139     * This method tries to fit the <code>Rectangle pageSize</code> to one of the predefined PageSize rectangles.
2140     * If a match is found the pageWidth and pageHeight will be set according to values determined from files
2141     * generated by MS Word2000 and OpenOffice 641. If no match is found the method will try to match the rotated
2142     * Rectangle by calling itself with the parameter rotate set to true.
2143     * @param pageSize a rectangle defining the size of the page
2144     * @param rotate portrait or lanscape?
2145     * @return true if the format parsing succeeded
2146     */

2147    private boolean parseFormat(Rectangle pageSize, boolean rotate) {
2148        if (rotate) {
2149            pageSize = pageSize.rotate();
2150        }
2151        if (rectEquals(pageSize, PageSize.A3)) {
2152            pageWidth = 16837;
2153            pageHeight = 23811;
2154            landscape = rotate;
2155            return true;
2156        }
2157        if (rectEquals(pageSize, PageSize.A4)) {
2158            pageWidth = 11907;
2159            pageHeight = 16840;
2160            landscape = rotate;
2161            return true;
2162        }
2163        if (rectEquals(pageSize, PageSize.A5)) {
2164            pageWidth = 8391;
2165            pageHeight = 11907;
2166            landscape = rotate;
2167            return true;
2168        }
2169        if (rectEquals(pageSize, PageSize.A6)) {
2170            pageWidth = 5959;
2171            pageHeight = 8420;
2172            landscape = rotate;
2173            return true;
2174        }
2175        if (rectEquals(pageSize, PageSize.B4)) {
2176            pageWidth = 14570;
2177            pageHeight = 20636;
2178            landscape = rotate;
2179            return true;
2180        }
2181        if (rectEquals(pageSize, PageSize.B5)) {
2182            pageWidth = 10319;
2183            pageHeight = 14572;
2184            landscape = rotate;
2185            return true;
2186        }
2187        if (rectEquals(pageSize, PageSize.HALFLETTER)) {
2188            pageWidth = 7927;
2189            pageHeight = 12247;
2190            landscape = rotate;
2191            return true;
2192        }
2193        if (rectEquals(pageSize, PageSize.LETTER)) {
2194            pageWidth = 12242;
2195            pageHeight = 15842;
2196            landscape = rotate;
2197            return true;
2198        }
2199        if (rectEquals(pageSize, PageSize.LEGAL)) {
2200            pageWidth = 12252;
2201            pageHeight = 20163;
2202            landscape = rotate;
2203            return true;
2204        }
2205        if (!rotate && parseFormat(pageSize, true)) {
2206            int x = pageWidth;
2207            pageWidth = pageHeight;
2208            pageHeight = x;
2209            return true;
2210        }
2211        return false;
2212    }
2213
2214    /**
2215     * This method compares to Rectangles. They are considered equal if width and height are the same
2216     * @param rect1
2217     * @param rect2
2218     * @return true if rect1 and rect2 represent the same rectangle
2219     */

2220    private boolean rectEquals(Rectangle rect1, Rectangle rect2) {
2221        return (rect1.getWidth() == rect2.getWidth()) && (rect1.getHeight() == rect2.getHeight());
2222    }
2223
2224    /**
2225     * Returns whether we are currently writing a header or footer
2226     *
2227     * @return the value of inHeaderFooter
2228     */

2229    public boolean writingHeaderFooter() {
2230        return inHeaderFooter;
2231    }
2232
2233    /**
2234     * Replaces special characters with their unicode values
2235     *
2236     * @param str The original <code>String</code>
2237     * @param useHex
2238     * @return The converted String
2239     */

2240    public final static String JavaDoc filterSpecialChar(String JavaDoc str, boolean useHex) {
2241        int length = str.length();
2242        int z = (int) 'z';
2243        StringBuffer JavaDoc ret = new StringBuffer JavaDoc(length);
2244        for (int i = 0; i < length; i++) {
2245            char ch = str.charAt(i);
2246
2247            if (ch == '\\') {
2248                ret.append("\\\\");
2249            } else if (ch == '\n') {
2250                ret.append("\\par ");
2251            } else if (((int) ch) > z) {
2252                if(useHex) {
2253                    ret.append("\\\'").append(Long.toHexString((long) ch));
2254                } else {
2255                ret.append("\\u").append((long) ch).append('?');
2256                }
2257            } else {
2258                ret.append(ch);
2259            }
2260        }
2261        String JavaDoc s = ret.toString();
2262        if(s.indexOf("$newpage$") >= 0) {
2263            String JavaDoc before = s.substring(0, s.indexOf("$newpage$"));
2264            String JavaDoc after = s.substring(s.indexOf("$newpage$") + 9);
2265            ret = new StringBuffer JavaDoc(before);
2266            ret.append("\\page\\par ");
2267            ret.append(after);
2268            return ret.toString();
2269        }
2270        return s;
2271    }
2272
2273    private void addHeaderFooterFontColor(HeaderFooter hf) {
2274        if(hf instanceof RtfHeaderFooter) {
2275            RtfHeaderFooter rhf = (RtfHeaderFooter) hf;
2276            if(rhf.content() instanceof Chunk) {
2277                addFont(((Chunk) rhf.content()).getFont());
2278                addColor(((Chunk) rhf.content()).getFont().getColor());
2279            } else if(rhf.content() instanceof Phrase) {
2280                addFont(((Phrase) rhf.content()).getFont());
2281                addColor(((Phrase) rhf.content()).getFont().getColor());
2282            }
2283        }
2284        if(hf.getBefore() != null) {
2285            addFont(hf.getBefore().getFont());
2286            addColor(hf.getBefore().getFont().getColor());
2287        }
2288        if(hf.getAfter() != null) {
2289            addFont(hf.getAfter().getFont());
2290            addColor(hf.getAfter().getFont().getColor());
2291        }
2292    }
2293
2294    private void processHeaderFooter(HeaderFooter hf) {
2295        if(hf != null) {
2296            if(hf instanceof RtfHeaderFooters) {
2297                RtfHeaderFooters rhf = (RtfHeaderFooters) hf;
2298                if(rhf.get(RtfHeaderFooters.ALL_PAGES) != null) {
2299                    addHeaderFooterFontColor(rhf.get(RtfHeaderFooters.ALL_PAGES));
2300                }
2301                if(rhf.get(RtfHeaderFooters.LEFT_PAGES) != null) {
2302                    addHeaderFooterFontColor(rhf.get(RtfHeaderFooters.LEFT_PAGES));
2303                }
2304                if(rhf.get(RtfHeaderFooters.RIGHT_PAGES) != null) {
2305                    addHeaderFooterFontColor(rhf.get(RtfHeaderFooters.RIGHT_PAGES));
2306                }
2307                if(rhf.get(RtfHeaderFooters.FIRST_PAGE) != null) {
2308                    addHeaderFooterFontColor(rhf.get(RtfHeaderFooters.FIRST_PAGE));
2309                }
2310            } else {
2311                addHeaderFooterFontColor(hf);
2312            }
2313        }
2314    }
2315    
2316    /**
2317     * @see com.lowagie.text.DocListener#setMarginMirroring(boolean)
2318     */

2319    public boolean setMarginMirroring(boolean MarginMirroring) {
2320        return false;
2321    }
2322    
2323}
2324
2325
Popular Tags