0001: /*
0002: * $Id: RtfWriter.java 2849 2007-06-20 19:31:09Z xlv $
0003: * $Name$
0004: *
0005: * Copyright 2001, 2002 by Mark Hall
0006: *
0007: * The contents of this file are subject to the Mozilla Public License Version 1.1
0008: * (the "License"); you may not use this file except in compliance with the License.
0009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the License.
0014: *
0015: * The Original Code is 'iText, a free JAVA-PDF library'.
0016: *
0017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0019: * All Rights Reserved.
0020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0022: *
0023: * Contributor(s): all the names of the contributors are added in the source code
0024: * where applicable.
0025: *
0026: * Alternatively, the contents of this file may be used under the terms of the
0027: * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the
0028: * provisions of LGPL are applicable instead of those above. If you wish to
0029: * allow use of your version of this file only under the terms of the LGPL
0030: * License and not to allow others to use your version of this file under
0031: * the MPL, indicate your decision by deleting the provisions above and
0032: * replace them with the notice and other provisions required by the LGPL.
0033: * If you do not delete the provisions above, a recipient may use your version
0034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0035: *
0036: * This library is free software; you can redistribute it and/or modify it
0037: * under the terms of the MPL as stated above or under the terms of the GNU
0038: * Library General Public License as published by the Free Software Foundation;
0039: * either version 2 of the License, or any later version.
0040: *
0041: * This library is distributed in the hope that it will be useful, but WITHOUT
0042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0044: * details.
0045: *
0046: * If you didn't download this code from the following link, you should check if
0047: * you aren't using an obsolete version:
0048: * http://www.lowagie.com/iText/
0049: */
0050:
0051: package com.lowagie.text.rtf;
0052:
0053: import java.awt.Color;
0054: import java.io.ByteArrayInputStream;
0055: import java.io.ByteArrayOutputStream;
0056: import java.io.IOException;
0057: import java.io.InputStream;
0058: import java.io.OutputStream;
0059: import java.text.ParsePosition;
0060: import java.text.SimpleDateFormat;
0061: import java.util.ArrayList;
0062: import java.util.Calendar;
0063: import java.util.Date;
0064: import java.util.Iterator;
0065: import java.util.ListIterator;
0066:
0067: import com.lowagie.text.Anchor;
0068: import com.lowagie.text.Annotation;
0069: import com.lowagie.text.Chunk;
0070: import com.lowagie.text.DocWriter;
0071: import com.lowagie.text.Document;
0072: import com.lowagie.text.DocumentException;
0073: import com.lowagie.text.Element;
0074: import com.lowagie.text.ExceptionConverter;
0075: import com.lowagie.text.Font;
0076: import com.lowagie.text.HeaderFooter;
0077: import com.lowagie.text.Image;
0078: import com.lowagie.text.ListItem;
0079: import com.lowagie.text.Meta;
0080: import com.lowagie.text.PageSize;
0081: import com.lowagie.text.Paragraph;
0082: import com.lowagie.text.Phrase;
0083: import com.lowagie.text.Rectangle;
0084: import com.lowagie.text.Section;
0085: import com.lowagie.text.SimpleTable;
0086: import com.lowagie.text.Table;
0087: import com.lowagie.text.pdf.codec.wmf.MetaDo;
0088:
0089: /**
0090: * If you are creating a new project using the rtf part of iText, please
0091: * consider using the new RtfWriter2. The RtfWriter is in bug-fix-only mode,
0092: * will be deprecated end of 2005 and removed end of 2007.
0093: *
0094: * A <CODE>DocWriter</CODE> class for Rich Text Files (RTF).
0095: * <P>
0096: * A <CODE>RtfWriter</CODE> can be added as a <CODE>DocListener</CODE>
0097: * to a certain <CODE>Document</CODE> by getting an instance.
0098: * Every <CODE>Element</CODE> added to the original <CODE>Document</CODE>
0099: * will be written to the <CODE>OutputStream</CODE> of this <CODE>RtfWriter</CODE>.
0100: * <P>
0101: * Example:
0102: * <BLOCKQUOTE><PRE>
0103: * // creation of the document with a certain size and certain margins
0104: * Document document = new Document(PageSize.A4, 50, 50, 50, 50);
0105: * try {
0106: * // this will write RTF to the Standard OutputStream
0107: * <STRONG>RtfWriter.getInstance(document, System.out);</STRONG>
0108: * // this will write Rtf to a file called text.rtf
0109: * <STRONG>RtfWriter.getInstance(document, new FileOutputStream("text.rtf"));</STRONG>
0110: * // this will write Rtf to for instance the OutputStream of a HttpServletResponse-object
0111: * <STRONG>RtfWriter.getInstance(document, response.getOutputStream());</STRONG>
0112: * }
0113: * catch(DocumentException de) {
0114: * System.err.println(de.getMessage());
0115: * }
0116: * // this will close the document and all the OutputStreams listening to it
0117: * <STRONG>document.close();</CODE>
0118: * </PRE></BLOCKQUOTE>
0119: * <P>
0120: * <STRONG>LIMITATIONS</STRONG><BR>
0121: * There are currently still a few limitations on what the RTF Writer can do:
0122: * <ul>
0123: * <li>Watermarks</li>
0124: * <li>Viewer preferences</li>
0125: * <li>Encryption</li>
0126: * <li>Embedded fonts</li>
0127: * <li>Phrases with a leading</li>
0128: * <li>Lists with non-bullet symbols</li>
0129: * <li>Nested tables</li>
0130: * <li>Images other than JPEG and PNG</li>
0131: * <li>Rotated images</li>
0132: * </ul>
0133: * <br />
0134: *
0135: * @author Mark Hall (mhall@edu.uni-klu.ac.at)
0136: * @author Steffen Stundzig (Steffen.Stundzig@smb-tec.com)
0137: * @author Eric Mattes (ericmattes@yahoo.com)
0138: * @author Raul Wegmann (raul.wegmann@uam.es)
0139: * @deprecated The RtfWriter is deprecated and will be removed from the iText library end of 2007
0140: */
0141: public class RtfWriter extends DocWriter {
0142: /**
0143: * Static Constants
0144: */
0145:
0146: /**
0147: * General
0148: */
0149:
0150: /** This is the escape character which introduces RTF tags. */
0151: public static final byte escape = (byte) '\\';
0152:
0153: /** This is another escape character which introduces RTF tags. */
0154: private static final byte[] extendedEscape = "\\*\\".getBytes();
0155:
0156: /** This is the delimiter between RTF tags and normal text. */
0157: protected static final byte delimiter = (byte) ' ';
0158:
0159: /** This is another delimiter between RTF tags and normal text. */
0160: private static final byte commaDelimiter = (byte) ';';
0161:
0162: /** This is the character for beginning a new group. */
0163: public static final byte openGroup = (byte) '{';
0164:
0165: /** This is the character for closing a group. */
0166: public static final byte closeGroup = (byte) '}';
0167:
0168: /**
0169: * RTF Information
0170: */
0171:
0172: /** RTF begin and version. */
0173: private static final byte[] docBegin = "rtf1".getBytes();
0174:
0175: /** RTF encoding. */
0176: private static final byte[] ansi = "ansi".getBytes();
0177:
0178: /** RTF encoding codepage. */
0179: private static final byte[] ansiCodepage = "ansicpg".getBytes();
0180:
0181: /**
0182: *Font Data
0183: */
0184:
0185: /** Begin the font table tag. */
0186: private static final byte[] fontTable = "fonttbl".getBytes();
0187:
0188: /** Font number tag. */
0189: protected static final byte fontNumber = (byte) 'f';
0190:
0191: /** Font size tag. */
0192: protected static final byte[] fontSize = "fs".getBytes();
0193:
0194: /** Font color tag. */
0195: protected static final byte[] fontColor = "cf".getBytes();
0196:
0197: /** Modern font tag. */
0198: private static final byte[] fontModern = "fmodern".getBytes();
0199:
0200: /** Swiss font tag. */
0201: private static final byte[] fontSwiss = "fswiss".getBytes();
0202:
0203: /** Roman font tag. */
0204: private static final byte[] fontRoman = "froman".getBytes();
0205:
0206: /** Tech font tag. */
0207: private static final byte[] fontTech = "ftech".getBytes();
0208:
0209: /** Font charset tag. */
0210: private static final byte[] fontCharset = "fcharset".getBytes();
0211:
0212: /** Font Courier tag. */
0213: private static final byte[] fontCourier = "Courier".getBytes();
0214:
0215: /** Font Arial tag. */
0216: private static final byte[] fontArial = "Arial".getBytes();
0217:
0218: /** Font Symbol tag. */
0219: private static final byte[] fontSymbol = "Symbol".getBytes();
0220:
0221: /** Font Times New Roman tag. */
0222: private static final byte[] fontTimesNewRoman = "Times New Roman"
0223: .getBytes();
0224:
0225: /** Font Windings tag. */
0226: private static final byte[] fontWindings = "Windings".getBytes();
0227:
0228: /** Default Font. */
0229: private static final byte[] defaultFont = "deff".getBytes();
0230:
0231: /** First indent tag. */
0232: private static final byte[] firstIndent = "fi".getBytes();
0233:
0234: /** Left indent tag. */
0235: private static final byte[] listIndent = "li".getBytes();
0236:
0237: /** Right indent tag. */
0238: private static final byte[] rightIndent = "ri".getBytes();
0239:
0240: /**
0241: * Sections / Paragraphs
0242: */
0243:
0244: /** Reset section defaults tag. */
0245: private static final byte[] sectionDefaults = "sectd".getBytes();
0246:
0247: /** Begin new section tag. */
0248: private static final byte[] section = "sect".getBytes();
0249:
0250: /** Reset paragraph defaults tag. */
0251: public static final byte[] paragraphDefaults = "pard".getBytes();
0252:
0253: /** Begin new paragraph tag. */
0254: public static final byte[] paragraph = "par".getBytes();
0255:
0256: /** Page width of a section. */
0257: public static final byte[] sectionPageWidth = "pgwsxn".getBytes();
0258:
0259: /** Page height of a section. */
0260: public static final byte[] sectionPageHeight = "pghsxn".getBytes();
0261:
0262: /**
0263: * Lists
0264: */
0265:
0266: /** Begin the List Table */
0267: private static final byte[] listtableGroup = "listtable".getBytes();
0268:
0269: /** Begin the List Override Table */
0270: private static final byte[] listoverridetableGroup = "listoverridetable"
0271: .getBytes();
0272:
0273: /** Begin a List definition */
0274: private static final byte[] listDefinition = "list".getBytes();
0275:
0276: /** List Template ID */
0277: private static final byte[] listTemplateID = "listtemplateid"
0278: .getBytes();
0279:
0280: /** RTF Writer outputs hybrid lists */
0281: private static final byte[] hybridList = "hybrid".getBytes();
0282:
0283: /** Current List level */
0284: private static final byte[] listLevelDefinition = "listlevel"
0285: .getBytes();
0286:
0287: /** Level numbering (old) */
0288: private static final byte[] listLevelTypeOld = "levelnfc"
0289: .getBytes();
0290:
0291: /** Level numbering (new) */
0292: private static final byte[] listLevelTypeNew = "levelnfcn"
0293: .getBytes();
0294:
0295: /** Level alignment (old) */
0296: private static final byte[] listLevelAlignOld = "leveljc"
0297: .getBytes();
0298:
0299: /** Level alignment (new) */
0300: private static final byte[] listLevelAlignNew = "leveljcn"
0301: .getBytes();
0302:
0303: /** Level starting number */
0304: private static final byte[] listLevelStartAt = "levelstartat"
0305: .getBytes();
0306:
0307: /** Level text group */
0308: private static final byte[] listLevelTextDefinition = "leveltext"
0309: .getBytes();
0310:
0311: /** Filler for Level Text Length */
0312: private static final byte[] listLevelTextLength = "\'0".getBytes();
0313:
0314: /** Level Text Numbering Style */
0315: private static final byte[] listLevelTextStyleNumbers = "\'00."
0316: .getBytes();
0317:
0318: /** Level Text Bullet Style */
0319: private static final byte[] listLevelTextStyleBullet = "u-3913 ?"
0320: .getBytes();
0321:
0322: /** Level Numbers Definition */
0323: private static final byte[] listLevelNumbersDefinition = "levelnumbers"
0324: .getBytes();
0325:
0326: /** Filler for Level Numbers */
0327: private static final byte[] listLevelNumbers = "\\'0".getBytes();
0328:
0329: /** Tab Stop */
0330: private static final byte[] tabStop = "tx".getBytes();
0331:
0332: /** Actual list begin */
0333: private static final byte[] listBegin = "ls".getBytes();
0334:
0335: /** Current list level */
0336: private static final byte[] listCurrentLevel = "ilvl".getBytes();
0337:
0338: /** List text group for older browsers */
0339: private static final byte[] listTextOld = "listtext".getBytes();
0340:
0341: /** Tab */
0342: private static final byte[] tab = "tab".getBytes();
0343:
0344: /** Old Bullet Style */
0345: private static final byte[] listBulletOld = "\'b7".getBytes();
0346:
0347: /** Current List ID */
0348: private static final byte[] listID = "listid".getBytes();
0349:
0350: /** List override */
0351: private static final byte[] listOverride = "listoverride"
0352: .getBytes();
0353:
0354: /** Number of overrides */
0355: private static final byte[] listOverrideCount = "listoverridecount"
0356: .getBytes();
0357:
0358: /**
0359: * Text Style
0360: */
0361:
0362: /** Bold tag. */
0363: protected static final byte bold = (byte) 'b';
0364:
0365: /** Italic tag. */
0366: protected static final byte italic = (byte) 'i';
0367:
0368: /** Underline tag. */
0369: protected static final byte[] underline = "ul".getBytes();
0370:
0371: /** Strikethrough tag. */
0372: protected static final byte[] strikethrough = "strike".getBytes();
0373:
0374: /** Text alignment left tag. */
0375: public static final byte[] alignLeft = "ql".getBytes();
0376:
0377: /** Text alignment center tag. */
0378: public static final byte[] alignCenter = "qc".getBytes();
0379:
0380: /** Text alignment right tag. */
0381: public static final byte[] alignRight = "qr".getBytes();
0382:
0383: /** Text alignment justify tag. */
0384: public static final byte[] alignJustify = "qj".getBytes();
0385:
0386: /**
0387: * Colors
0388: */
0389:
0390: /** Begin colour table tag. */
0391: private static final byte[] colorTable = "colortbl".getBytes();
0392:
0393: /** Red value tag. */
0394: private static final byte[] colorRed = "red".getBytes();
0395:
0396: /** Green value tag. */
0397: private static final byte[] colorGreen = "green".getBytes();
0398:
0399: /** Blue value tag. */
0400: private static final byte[] colorBlue = "blue".getBytes();
0401:
0402: /**
0403: * Information Group
0404: */
0405:
0406: /** Begin the info group tag.*/
0407: private static final byte[] infoBegin = "info".getBytes();
0408:
0409: /** Author tag. */
0410: private static final byte[] metaAuthor = "author".getBytes();
0411:
0412: /** Subject tag. */
0413: private static final byte[] metaSubject = "subject".getBytes();
0414:
0415: /** Keywords tag. */
0416: private static final byte[] metaKeywords = "keywords".getBytes();
0417:
0418: /** Title tag. */
0419: private static final byte[] metaTitle = "title".getBytes();
0420:
0421: /** Producer tag. */
0422: private static final byte[] metaProducer = "operator".getBytes();
0423:
0424: /** Creation Date tag. */
0425: private static final byte[] metaCreationDate = "creationdate"
0426: .getBytes();
0427:
0428: /** Year tag. */
0429: private static final byte[] year = "yr".getBytes();
0430:
0431: /** Month tag. */
0432: private static final byte[] month = "mo".getBytes();
0433:
0434: /** Day tag. */
0435: private static final byte[] day = "dy".getBytes();
0436:
0437: /** Hour tag. */
0438: private static final byte[] hour = "hr".getBytes();
0439:
0440: /** Minute tag. */
0441: private static final byte[] minute = "min".getBytes();
0442:
0443: /** Second tag. */
0444: private static final byte[] second = "sec".getBytes();
0445:
0446: /** Start superscript. */
0447: private static final byte[] startSuper = "super".getBytes();
0448:
0449: /** Start subscript. */
0450: private static final byte[] startSub = "sub".getBytes();
0451:
0452: /** End super/sub script. */
0453: private static final byte[] endSuperSub = "nosupersub".getBytes();
0454:
0455: /**
0456: * Header / Footer
0457: */
0458:
0459: /** Title Page tag */
0460: private static final byte[] titlePage = "titlepg".getBytes();
0461:
0462: /** Facing pages tag */
0463: private static final byte[] facingPages = "facingp".getBytes();
0464:
0465: /** Begin header group tag. */
0466: private static final byte[] headerBegin = "header".getBytes();
0467:
0468: /** Begin footer group tag. */
0469: private static final byte[] footerBegin = "footer".getBytes();
0470:
0471: // header footer 'left', 'right', 'first'
0472: private static final byte[] headerlBegin = "headerl".getBytes();
0473:
0474: private static final byte[] footerlBegin = "footerl".getBytes();
0475:
0476: private static final byte[] headerrBegin = "headerr".getBytes();
0477:
0478: private static final byte[] footerrBegin = "footerr".getBytes();
0479:
0480: private static final byte[] headerfBegin = "headerf".getBytes();
0481:
0482: private static final byte[] footerfBegin = "footerf".getBytes();
0483:
0484: /**
0485: * Paper Properties
0486: */
0487:
0488: /** Paper width tag. */
0489: private static final byte[] rtfPaperWidth = "paperw".getBytes();
0490:
0491: /** Paper height tag. */
0492: private static final byte[] rtfPaperHeight = "paperh".getBytes();
0493:
0494: /** Margin left tag. */
0495: private static final byte[] rtfMarginLeft = "margl".getBytes();
0496:
0497: /** Margin right tag. */
0498: private static final byte[] rtfMarginRight = "margr".getBytes();
0499:
0500: /** Margin top tag. */
0501: private static final byte[] rtfMarginTop = "margt".getBytes();
0502:
0503: /** Margin bottom tag. */
0504: private static final byte[] rtfMarginBottom = "margb".getBytes();
0505:
0506: /** New Page tag. */
0507: private static final byte[] newPage = "page".getBytes();
0508:
0509: /** Document Landscape tag 1. */
0510: private static final byte[] landscapeTag1 = "landscape".getBytes();
0511:
0512: /** Document Landscape tag 2. */
0513: private static final byte[] landscapeTag2 = "lndscpsxn".getBytes();
0514:
0515: /**
0516: * Annotations
0517: */
0518:
0519: /** Annotation ID tag. */
0520: private static final byte[] annotationID = "atnid".getBytes();
0521:
0522: /** Annotation Author tag. */
0523: private static final byte[] annotationAuthor = "atnauthor"
0524: .getBytes();
0525:
0526: /** Annotation text tag. */
0527: private static final byte[] annotation = "annotation".getBytes();
0528:
0529: /**
0530: * Images
0531: */
0532:
0533: /** Begin the main Picture group tag */
0534: private static final byte[] pictureGroup = "shppict".getBytes();
0535:
0536: /** Begin the picture tag */
0537: private static final byte[] picture = "pict".getBytes();
0538:
0539: /** PNG Image */
0540: private static final byte[] picturePNG = "pngblip".getBytes();
0541:
0542: /** JPEG Image */
0543: private static final byte[] pictureJPEG = "jpegblip".getBytes();
0544:
0545: /** BMP Image */
0546: private static final byte[] pictureBMP = "dibitmap0".getBytes();
0547:
0548: /** WMF Image */
0549: private static final byte[] pictureWMF = "wmetafile8".getBytes();
0550:
0551: /** Picture width */
0552: private static final byte[] pictureWidth = "picw".getBytes();
0553:
0554: /** Picture height */
0555: private static final byte[] pictureHeight = "pich".getBytes();
0556:
0557: /** Picture scale horizontal percent */
0558: private static final byte[] pictureScaleX = "picscalex".getBytes();
0559:
0560: /** Picture scale vertical percent */
0561: private static final byte[] pictureScaleY = "picscaley".getBytes();
0562:
0563: /**
0564: * Fields (for page numbering)
0565: */
0566:
0567: /** Begin field tag */
0568: protected static final byte[] field = "field".getBytes();
0569:
0570: /** Content fo the field */
0571: protected static final byte[] fieldContent = "fldinst".getBytes();
0572:
0573: /** PAGE numbers */
0574: protected static final byte[] fieldPage = "PAGE".getBytes();
0575:
0576: /** HYPERLINK field */
0577: protected static final byte[] fieldHyperlink = "HYPERLINK"
0578: .getBytes();
0579:
0580: /** Last page number (not used) */
0581: protected static final byte[] fieldDisplay = "fldrslt".getBytes();
0582:
0583: /** Class variables */
0584:
0585: /**
0586: * Because of the way RTF works and the way itext works, the text has to be
0587: * stored and is only written to the actual OutputStream at the end.
0588: */
0589:
0590: /** This <code>ArrayList</code> contains all fonts used in the document. */
0591: private ArrayList fontList = new ArrayList();
0592:
0593: /** This <code>ArrayList</code> contains all colours used in the document. */
0594: private ArrayList colorList = new ArrayList();
0595:
0596: /** This <code>ByteArrayOutputStream</code> contains the main body of the document. */
0597: private ByteArrayOutputStream content = null;
0598:
0599: /** This <code>ByteArrayOutputStream</code> contains the information group. */
0600: private ByteArrayOutputStream info = null;
0601:
0602: /** This <code>ByteArrayOutputStream</code> contains the list table. */
0603: private ByteArrayOutputStream listtable = null;
0604:
0605: /** This <code>ByteArrayOutputStream</code> contains the list override table. */
0606: private ByteArrayOutputStream listoverride = null;
0607:
0608: /** Document header. */
0609: private HeaderFooter header = null;
0610:
0611: /** Document footer. */
0612: private HeaderFooter footer = null;
0613:
0614: /** Left margin. */
0615: private int marginLeft = 1800;
0616:
0617: /** Right margin. */
0618: private int marginRight = 1800;
0619:
0620: /** Top margin. */
0621: private int marginTop = 1440;
0622:
0623: /** Bottom margin. */
0624: private int marginBottom = 1440;
0625:
0626: /** Page width. */
0627: private int pageWidth = 11906;
0628:
0629: /** Page height. */
0630: private int pageHeight = 16838;
0631:
0632: /** Factor to use when converting. */
0633: public final static double TWIPSFACTOR = 20;//20.57140;
0634:
0635: /** Current list ID. */
0636: private int currentListID = 1;
0637:
0638: /** List of current Lists. */
0639: private ArrayList listIds = null;
0640:
0641: /** Current List Level. */
0642: private int listLevel = 0;
0643:
0644: /** Current maximum List Level. */
0645: private int maxListLevel = 0;
0646:
0647: /** Write a TOC */
0648: private boolean writeTOC = false;
0649:
0650: /** Special title page */
0651: private boolean hasTitlePage = false;
0652:
0653: /** Currently writing either Header or Footer */
0654: private boolean inHeaderFooter = false;
0655:
0656: /** Currently writing a Table */
0657: private boolean inTable = false;
0658:
0659: /** Landscape or Portrait Document */
0660: private boolean landscape = false;
0661:
0662: /** Protected Constructor */
0663:
0664: /**
0665: * Constructs a <CODE>RtfWriter</CODE>.
0666: *
0667: * @param doc The <CODE>Document</CODE> that is to be written as RTF
0668: * @param os The <CODE>OutputStream</CODE> the writer has to write to.
0669: */
0670:
0671: protected RtfWriter(Document doc, OutputStream os) {
0672: super (doc, os);
0673: document.addDocListener(this );
0674: initDefaults();
0675: }
0676:
0677: /** Public functions special to the RtfWriter */
0678:
0679: /**
0680: * This method controls whether TOC entries are automatically generated
0681: *
0682: * @param writeTOC boolean value indicating whether a TOC is to be generated
0683: */
0684: public void setGenerateTOCEntries(boolean writeTOC) {
0685: this .writeTOC = writeTOC;
0686: }
0687:
0688: /**
0689: * Gets the current setting of writeTOC
0690: *
0691: * @return boolean value indicating whether a TOC is being generated
0692: */
0693: public boolean getGeneratingTOCEntries() {
0694: return writeTOC;
0695: }
0696:
0697: /**
0698: * This method controls whether the first page is a title page
0699: *
0700: * @param hasTitlePage boolean value indicating whether the first page is a title page
0701: */
0702: public void setHasTitlePage(boolean hasTitlePage) {
0703: this .hasTitlePage = hasTitlePage;
0704: }
0705:
0706: /**
0707: * Gets the current setting of hasTitlePage
0708: *
0709: * @return boolean value indicating whether the first page is a title page
0710: */
0711: public boolean getHasTitlePage() {
0712: return hasTitlePage;
0713: }
0714:
0715: /**
0716: * Explicitly sets the page format to use.
0717: * Otherwise the RtfWriter will try to guess the format by comparing pagewidth and pageheight
0718: *
0719: * @param landscape boolean value indicating whether we are using landscape format or not
0720: */
0721: public void setLandscape(boolean landscape) {
0722: this .landscape = landscape;
0723: }
0724:
0725: /**
0726: * Returns the current landscape setting
0727: *
0728: * @return boolean value indicating the current page format
0729: */
0730: public boolean getLandscape() {
0731: return landscape;
0732: }
0733:
0734: /** Public functions from the DocWriter Interface */
0735:
0736: /**
0737: * Gets an instance of the <CODE>RtfWriter</CODE>.
0738: *
0739: * @param document The <CODE>Document</CODE> that has to be written
0740: * @param os The <CODE>OutputStream</CODE> the writer has to write to.
0741: * @return a new <CODE>RtfWriter</CODE>
0742: */
0743: public static RtfWriter getInstance(Document document,
0744: OutputStream os) {
0745: return new RtfWriter(document, os);
0746: }
0747:
0748: /**
0749: * Signals that the <CODE>Document</CODE> was closed and that no other
0750: * <CODE>Elements</CODE> will be added.
0751: * <p>
0752: * The content of the font table, color table, information group, content, header, footer are merged into the final
0753: * <code>OutputStream</code>
0754: */
0755: public void close() {
0756: if (open) {
0757: writeDocument();
0758: super .close();
0759: }
0760: }
0761:
0762: /**
0763: * Adds the footer to the bottom of the <CODE>Document</CODE>.
0764: * @param footer
0765: */
0766: public void setFooter(HeaderFooter footer) {
0767: this .footer = footer;
0768: processHeaderFooter(this .footer);
0769: }
0770:
0771: /**
0772: * Adds the header to the top of the <CODE>Document</CODE>.
0773: * @param header
0774: */
0775: public void setHeader(HeaderFooter header) {
0776: this .header = header;
0777: processHeaderFooter(this .header);
0778: }
0779:
0780: /**
0781: * Resets the footer.
0782: */
0783: public void resetFooter() {
0784: setFooter(null);
0785: }
0786:
0787: /**
0788: * Resets the header.
0789: */
0790: public void resetHeader() {
0791: setHeader(null);
0792: }
0793:
0794: /**
0795: * Tells the <code>RtfWriter</code> that a new page is to be begun.
0796: *
0797: * @return <code>true</code> if a new Page was begun.
0798: * @throws DocumentException if the Document was not open or had been closed.
0799: */
0800: public boolean newPage() {
0801: try {
0802: content.write(escape);
0803: content.write(newPage);
0804: content.write(escape);
0805: content.write(paragraph);
0806: } catch (IOException e) {
0807: throw new ExceptionConverter(e);
0808: }
0809: return true;
0810: }
0811:
0812: /**
0813: * Sets the page margins
0814: *
0815: * @param marginLeft The left margin
0816: * @param marginRight The right margin
0817: * @param marginTop The top margin
0818: * @param marginBottom The bottom margin
0819: *
0820: * @return <code>true</code> if the page margins were set.
0821: */
0822: public boolean setMargins(float marginLeft, float marginRight,
0823: float marginTop, float marginBottom) {
0824: this .marginLeft = (int) (marginLeft * TWIPSFACTOR);
0825: this .marginRight = (int) (marginRight * TWIPSFACTOR);
0826: this .marginTop = (int) (marginTop * TWIPSFACTOR);
0827: this .marginBottom = (int) (marginBottom * TWIPSFACTOR);
0828: return true;
0829: }
0830:
0831: /**
0832: * Sets the page size
0833: *
0834: * @param pageSize A <code>Rectangle</code> specifying the page size
0835: *
0836: * @return <code>true</code> if the page size was set
0837: */
0838: public boolean setPageSize(Rectangle pageSize) {
0839: if (!parseFormat(pageSize, false)) {
0840: pageWidth = (int) (pageSize.getWidth() * TWIPSFACTOR);
0841: pageHeight = (int) (pageSize.getHeight() * TWIPSFACTOR);
0842: landscape = pageWidth > pageHeight;
0843: }
0844: return true;
0845: }
0846:
0847: /**
0848: * Write the table of contents.
0849: *
0850: * @param tocTitle The title that will be displayed above the TOC
0851: * @param titleFont The <code>Font</code> that will be used for the tocTitle
0852: * @param showTOCasEntry Set this to true if you want the TOC to appear as an entry in the TOC
0853: * @param showTOCEntryFont Use this <code>Font</code> to specify what Font to use when showTOCasEntry is true
0854: *
0855: * @return <code>true</code> if the TOC was added.
0856: */
0857: public boolean writeTOC(String tocTitle, Font titleFont,
0858: boolean showTOCasEntry, Font showTOCEntryFont) {
0859: try {
0860: RtfTOC toc = new RtfTOC(tocTitle, titleFont);
0861: if (showTOCasEntry) {
0862: toc.addTOCAsTOCEntry(tocTitle, showTOCEntryFont);
0863: }
0864: add(new Paragraph(toc));
0865: } catch (DocumentException de) {
0866: return false;
0867: }
0868: return true;
0869: }
0870:
0871: /**
0872: * Signals that an <CODE>Element</CODE> was added to the <CODE>Document</CODE>.
0873: *
0874: * @param element A high level object to add
0875: * @return <CODE>true</CODE> if the element was added, <CODE>false</CODE> if not.
0876: * @throws DocumentException if a document isn't open yet, or has been closed
0877: */
0878: public boolean add(Element element) throws DocumentException {
0879: if (pause) {
0880: return false;
0881: }
0882: return addElement(element, content);
0883: }
0884:
0885: /** Private functions */
0886:
0887: /**
0888: * Adds an <CODE>Element</CODE> to the <CODE>Document</CODE>.
0889: * @param element the high level element to add
0890: * @param out the outputstream to which the RTF data is sent
0891: * @return <CODE>true</CODE> if the element was added, <CODE>false</CODE> if not.
0892: * @throws DocumentException if a document isn't open yet, or has been closed
0893: */
0894: protected boolean addElement(Element element,
0895: ByteArrayOutputStream out) throws DocumentException {
0896: try {
0897: switch (element.type()) {
0898: case Element.CHUNK:
0899: writeChunk((Chunk) element, out);
0900: break;
0901: case Element.PARAGRAPH:
0902: writeParagraph((Paragraph) element, out);
0903: break;
0904: case Element.ANCHOR:
0905: writeAnchor((Anchor) element, out);
0906: break;
0907: case Element.PHRASE:
0908: writePhrase((Phrase) element, out);
0909: break;
0910: case Element.CHAPTER:
0911: case Element.SECTION:
0912: writeSection((Section) element, out);
0913: break;
0914: case Element.LIST:
0915: writeList((com.lowagie.text.List) element, out);
0916: break;
0917: case Element.TABLE:
0918: try {
0919: writeTable((Table) element, out);
0920: } catch (ClassCastException cce) {
0921: writeTable(((SimpleTable) element).createTable(),
0922: out);
0923: }
0924: break;
0925: case Element.ANNOTATION:
0926: writeAnnotation((Annotation) element, out);
0927: break;
0928: case Element.IMGRAW:
0929: case Element.IMGTEMPLATE:
0930: case Element.JPEG:
0931: Image img = (Image) element;
0932: writeImage(img, out);
0933: break;
0934:
0935: case Element.AUTHOR:
0936: writeMeta(metaAuthor, (Meta) element);
0937: break;
0938: case Element.SUBJECT:
0939: writeMeta(metaSubject, (Meta) element);
0940: break;
0941: case Element.KEYWORDS:
0942: writeMeta(metaKeywords, (Meta) element);
0943: break;
0944: case Element.TITLE:
0945: writeMeta(metaTitle, (Meta) element);
0946: break;
0947: case Element.PRODUCER:
0948: writeMeta(metaProducer, (Meta) element);
0949: break;
0950: case Element.CREATIONDATE:
0951: writeMeta(metaCreationDate, (Meta) element);
0952: break;
0953: }
0954: } catch (IOException e) {
0955: return false;
0956: }
0957: return true;
0958: }
0959:
0960: /**
0961: * Write the beginning of a new <code>Section</code>
0962: *
0963: * @param sectionElement The <code>Section</code> be written
0964: * @param out The <code>ByteArrayOutputStream</code> to write to
0965: *
0966: * @throws IOException
0967: * @throws DocumentException
0968: */
0969: private void writeSection(Section sectionElement,
0970: ByteArrayOutputStream out) throws IOException,
0971: DocumentException {
0972: if (sectionElement.type() == Element.CHAPTER) {
0973: out.write(escape);
0974: out.write(sectionDefaults);
0975: writeSectionDefaults(out);
0976: }
0977: if (sectionElement.getTitle() != null) {
0978: if (writeTOC) {
0979: StringBuffer title = new StringBuffer("");
0980: for (ListIterator li = sectionElement.getTitle()
0981: .getChunks().listIterator(); li.hasNext();) {
0982: title.append(((Chunk) li.next()).getContent());
0983: }
0984: add(new RtfTOCEntry(title.toString(), sectionElement
0985: .getTitle().getFont()));
0986: } else {
0987: add(sectionElement.getTitle());
0988: }
0989: out.write(escape);
0990: out.write(paragraph);
0991: }
0992: sectionElement.process(this );
0993: if (sectionElement.type() == Element.CHAPTER) {
0994: out.write(escape);
0995: out.write(section);
0996: }
0997: if (sectionElement.type() == Element.SECTION) {
0998: out.write(escape);
0999: out.write(paragraph);
1000: }
1001: }
1002:
1003: /**
1004: * Write the beginning of a new <code>Paragraph</code>
1005: *
1006: * @param paragraphElement The <code>Paragraph</code> to be written
1007: * @param out The <code>ByteArrayOutputStream</code> to write to
1008: *
1009: * @throws IOException
1010: */
1011: private void writeParagraph(Paragraph paragraphElement,
1012: ByteArrayOutputStream out) throws IOException {
1013: out.write(escape);
1014: out.write(paragraphDefaults);
1015: if (inTable) {
1016: out.write(escape);
1017: out.write(RtfCell.cellInTable);
1018: }
1019: switch (paragraphElement.getAlignment()) {
1020: case Element.ALIGN_LEFT:
1021: out.write(escape);
1022: out.write(alignLeft);
1023: break;
1024: case Element.ALIGN_RIGHT:
1025: out.write(escape);
1026: out.write(alignRight);
1027: break;
1028: case Element.ALIGN_CENTER:
1029: out.write(escape);
1030: out.write(alignCenter);
1031: break;
1032: case Element.ALIGN_JUSTIFIED:
1033: case Element.ALIGN_JUSTIFIED_ALL:
1034: out.write(escape);
1035: out.write(alignJustify);
1036: break;
1037: }
1038: out.write(escape);
1039: out.write(listIndent);
1040: writeInt(
1041: out,
1042: (int) (paragraphElement.getIndentationLeft() * TWIPSFACTOR));
1043: out.write(escape);
1044: out.write(rightIndent);
1045: writeInt(
1046: out,
1047: (int) (paragraphElement.getIndentationRight() * TWIPSFACTOR));
1048: Iterator chunks = paragraphElement.getChunks().iterator();
1049: while (chunks.hasNext()) {
1050: Chunk ch = (Chunk) chunks.next();
1051: ch.setFont(paragraphElement.getFont().difference(
1052: ch.getFont()));
1053: }
1054: ByteArrayOutputStream save = content;
1055: content = out;
1056: paragraphElement.process(this );
1057: content = save;
1058: if (!inTable) {
1059: out.write(escape);
1060: out.write(paragraph);
1061: }
1062: }
1063:
1064: /**
1065: * Write a <code>Phrase</code>.
1066: *
1067: * @param phrase The <code>Phrase</code> item to be written
1068: * @param out The <code>ByteArrayOutputStream</code> to write to
1069: *
1070: * @throws IOException
1071: */
1072: private void writePhrase(Phrase phrase, ByteArrayOutputStream out)
1073: throws IOException {
1074: out.write(escape);
1075: out.write(paragraphDefaults);
1076: if (inTable) {
1077: out.write(escape);
1078: out.write(RtfCell.cellInTable);
1079: }
1080: Iterator chunks = phrase.getChunks().iterator();
1081: while (chunks.hasNext()) {
1082: Chunk ch = (Chunk) chunks.next();
1083: ch.setFont(phrase.getFont().difference(ch.getFont()));
1084: }
1085: ByteArrayOutputStream save = content;
1086: content = out;
1087: phrase.process(this );
1088: content = save;
1089: }
1090:
1091: /**
1092: * Write an <code>Anchor</code>. Anchors are treated like Phrases.
1093: *
1094: * @param anchor The <code>Chunk</code> item to be written
1095: * @param out The <code>ByteArrayOutputStream</code> to write to
1096: *
1097: * @throws IOException
1098: */
1099: private void writeAnchor(Anchor anchor, ByteArrayOutputStream out)
1100: throws IOException {
1101: if (anchor.getUrl() != null) {
1102: out.write(openGroup);
1103: out.write(escape);
1104: out.write(field);
1105: out.write(openGroup);
1106: out.write(extendedEscape);
1107: out.write(fieldContent);
1108: out.write(openGroup);
1109: out.write(fieldHyperlink);
1110: out.write(delimiter);
1111: out.write(anchor.getUrl().toString().getBytes());
1112: out.write(closeGroup);
1113: out.write(closeGroup);
1114: out.write(openGroup);
1115: out.write(escape);
1116: out.write(fieldDisplay);
1117: out.write(delimiter);
1118: writePhrase(anchor, out);
1119: out.write(closeGroup);
1120: out.write(closeGroup);
1121: } else {
1122: writePhrase(anchor, out);
1123: }
1124: }
1125:
1126: /**
1127: * Write a <code>Chunk</code> and all its font properties.
1128: *
1129: * @param chunk The <code>Chunk</code> item to be written
1130: * @param out The <code>ByteArrayOutputStream</code> to write to
1131: *
1132: * @throws IOException
1133: * @throws DocumentException
1134: */
1135: private void writeChunk(Chunk chunk, ByteArrayOutputStream out)
1136: throws IOException, DocumentException {
1137: if (chunk instanceof RtfField) {
1138: ((RtfField) chunk).write(this , out);
1139: } else {
1140: if (chunk.getImage() != null) {
1141: writeImage(chunk.getImage(), out);
1142: } else {
1143: writeInitialFontSignature(out, chunk);
1144: out.write(filterSpecialChar(chunk.getContent(), false)
1145: .getBytes());
1146: writeFinishingFontSignature(out, chunk);
1147: }
1148: }
1149: }
1150:
1151: protected void writeInitialFontSignature(OutputStream out,
1152: Chunk chunk) throws IOException {
1153: Font font = chunk.getFont();
1154:
1155: out.write(escape);
1156: out.write(fontNumber);
1157: if (!font.getFamilyname().equalsIgnoreCase("unknown")) {
1158: writeInt(out, addFont(font));
1159: } else {
1160: writeInt(out, 0);
1161: }
1162: out.write(escape);
1163: out.write(fontSize);
1164: if (font.getSize() > 0) {
1165: writeInt(out, (int) (font.getSize() * 2));
1166: } else {
1167: writeInt(out, 20);
1168: }
1169: out.write(escape);
1170: out.write(fontColor);
1171: writeInt(out, addColor(font.getColor()));
1172: if (font.isBold()) {
1173: out.write(escape);
1174: out.write(bold);
1175: }
1176: if (font.isItalic()) {
1177: out.write(escape);
1178: out.write(italic);
1179: }
1180: if (font.isUnderlined()) {
1181: out.write(escape);
1182: out.write(underline);
1183: }
1184: if (font.isStrikethru()) {
1185: out.write(escape);
1186: out.write(strikethrough);
1187: }
1188:
1189: /*
1190: * Superscript / Subscript added by Scott Dietrich (sdietrich@emlab.com)
1191: */
1192: if (chunk.getAttributes() != null) {
1193: Float f = (Float) chunk.getAttributes().get(
1194: Chunk.SUBSUPSCRIPT);
1195: if (f != null)
1196: if (f.floatValue() > 0) {
1197: out.write(escape);
1198: out.write(startSuper);
1199: } else if (f.floatValue() < 0) {
1200: out.write(escape);
1201: out.write(startSub);
1202: }
1203: }
1204:
1205: out.write(delimiter);
1206: }
1207:
1208: protected void writeFinishingFontSignature(OutputStream out,
1209: Chunk chunk) throws IOException {
1210: Font font = chunk.getFont();
1211:
1212: if (font.isBold()) {
1213: out.write(escape);
1214: out.write(bold);
1215: writeInt(out, 0);
1216: }
1217: if (font.isItalic()) {
1218: out.write(escape);
1219: out.write(italic);
1220: writeInt(out, 0);
1221: }
1222: if (font.isUnderlined()) {
1223: out.write(escape);
1224: out.write(underline);
1225: writeInt(out, 0);
1226: }
1227: if (font.isStrikethru()) {
1228: out.write(escape);
1229: out.write(strikethrough);
1230: writeInt(out, 0);
1231: }
1232:
1233: /*
1234: * Superscript / Subscript added by Scott Dietrich (sdietrich@emlab.com)
1235: */
1236: if (chunk.getAttributes() != null) {
1237: Float f = (Float) chunk.getAttributes().get(
1238: Chunk.SUBSUPSCRIPT);
1239: if (f != null)
1240: if (f.floatValue() != 0) {
1241: out.write(escape);
1242: out.write(endSuperSub);
1243: }
1244: }
1245: }
1246:
1247: /**
1248: * Write a <code>ListItem</code>
1249: *
1250: * @param listItem The <code>ListItem</code> to be written
1251: * @param out The <code>ByteArrayOutputStream</code> to write to
1252: *
1253: * @throws IOException
1254: * @throws DocumentException
1255: */
1256: private void writeListElement(ListItem listItem,
1257: ByteArrayOutputStream out) throws IOException,
1258: DocumentException {
1259: Iterator chunks = listItem.getChunks().iterator();
1260: while (chunks.hasNext()) {
1261: Chunk ch = (Chunk) chunks.next();
1262: addElement(ch, out);
1263: }
1264: out.write(escape);
1265: out.write(paragraph);
1266: }
1267:
1268: /**
1269: * Write a <code>List</code>
1270: *
1271: * @param list The <code>List</code> to be written
1272: * @param out The <code>ByteArrayOutputStream</code> to write to
1273: *
1274: * @throws IOException
1275: * @throws DocumentException
1276: */
1277: private void writeList(com.lowagie.text.List list,
1278: ByteArrayOutputStream out) throws IOException,
1279: DocumentException {
1280: int type = 0;
1281: int align = 0;
1282: int fontNr = addFont(new Font(Font.SYMBOL, 10, Font.NORMAL,
1283: new Color(0, 0, 0)));
1284: if (!list.isNumbered())
1285: type = 23;
1286: if (listLevel == 0) {
1287: maxListLevel = 0;
1288: listtable.write(openGroup);
1289: listtable.write(escape);
1290: listtable.write(listDefinition);
1291: int i = getRandomInt();
1292: listtable.write(escape);
1293: listtable.write(listTemplateID);
1294: writeInt(listtable, i);
1295: listtable.write(escape);
1296: listtable.write(hybridList);
1297: listtable.write((byte) '\n');
1298: }
1299: if (listLevel >= maxListLevel) {
1300: maxListLevel++;
1301: listtable.write(openGroup);
1302: listtable.write(escape);
1303: listtable.write(listLevelDefinition);
1304: listtable.write(escape);
1305: listtable.write(listLevelTypeOld);
1306: writeInt(listtable, type);
1307: listtable.write(escape);
1308: listtable.write(listLevelTypeNew);
1309: writeInt(listtable, type);
1310: listtable.write(escape);
1311: listtable.write(listLevelAlignOld);
1312: writeInt(listtable, align);
1313: listtable.write(escape);
1314: listtable.write(listLevelAlignNew);
1315: writeInt(listtable, align);
1316: listtable.write(escape);
1317: listtable.write(listLevelStartAt);
1318: writeInt(listtable, 1);
1319: listtable.write(openGroup);
1320: listtable.write(escape);
1321: listtable.write(listLevelTextDefinition);
1322: listtable.write(escape);
1323: listtable.write(listLevelTextLength);
1324: if (list.isNumbered()) {
1325: writeInt(listtable, 2);
1326: } else {
1327: writeInt(listtable, 1);
1328: }
1329: listtable.write(escape);
1330: if (list.isNumbered()) {
1331: listtable.write(listLevelTextStyleNumbers);
1332: } else {
1333: listtable.write(listLevelTextStyleBullet);
1334: }
1335: listtable.write(commaDelimiter);
1336: listtable.write(closeGroup);
1337: listtable.write(openGroup);
1338: listtable.write(escape);
1339: listtable.write(listLevelNumbersDefinition);
1340: if (list.isNumbered()) {
1341: listtable.write(delimiter);
1342: listtable.write(listLevelNumbers);
1343: writeInt(listtable, listLevel + 1);
1344: }
1345: listtable.write(commaDelimiter);
1346: listtable.write(closeGroup);
1347: if (!list.isNumbered()) {
1348: listtable.write(escape);
1349: listtable.write(fontNumber);
1350: writeInt(listtable, fontNr);
1351: }
1352: listtable.write(escape);
1353: listtable.write(firstIndent);
1354: writeInt(listtable, (int) (list.getIndentationLeft()
1355: * TWIPSFACTOR * -1));
1356: listtable.write(escape);
1357: listtable.write(listIndent);
1358: writeInt(listtable,
1359: (int) ((list.getIndentationLeft() + list
1360: .getSymbolIndent()) * TWIPSFACTOR));
1361: listtable.write(escape);
1362: listtable.write(rightIndent);
1363: writeInt(listtable,
1364: (int) (list.getIndentationRight() * TWIPSFACTOR));
1365: listtable.write(escape);
1366: listtable.write(tabStop);
1367: writeInt(listtable,
1368: (int) (list.getSymbolIndent() * TWIPSFACTOR));
1369: listtable.write(closeGroup);
1370: listtable.write((byte) '\n');
1371: }
1372: // Actual List Begin in Content
1373: out.write(escape);
1374: out.write(paragraphDefaults);
1375: out.write(escape);
1376: out.write(alignLeft);
1377: out.write(escape);
1378: out.write(firstIndent);
1379: writeInt(out,
1380: (int) (list.getIndentationLeft() * TWIPSFACTOR * -1));
1381: out.write(escape);
1382: out.write(listIndent);
1383: writeInt(out, (int) ((list.getIndentationLeft() + list
1384: .getSymbolIndent()) * TWIPSFACTOR));
1385: out.write(escape);
1386: out.write(rightIndent);
1387: writeInt(out, (int) (list.getIndentationRight() * TWIPSFACTOR));
1388: out.write(escape);
1389: out.write(fontSize);
1390: writeInt(out, 20);
1391: out.write(escape);
1392: out.write(listBegin);
1393: writeInt(out, currentListID);
1394: if (listLevel > 0) {
1395: out.write(escape);
1396: out.write(listCurrentLevel);
1397: writeInt(out, listLevel);
1398: }
1399: out.write(openGroup);
1400: ListIterator listItems = list.getItems().listIterator();
1401: Element listElem;
1402: int count = 1;
1403: while (listItems.hasNext()) {
1404: listElem = (Element) listItems.next();
1405: if (listElem.type() == Element.CHUNK) {
1406: listElem = new ListItem((Chunk) listElem);
1407: }
1408: if (listElem.type() == Element.LISTITEM) {
1409: out.write(openGroup);
1410: out.write(escape);
1411: out.write(listTextOld);
1412: out.write(escape);
1413: out.write(paragraphDefaults);
1414: out.write(escape);
1415: out.write(fontNumber);
1416: if (list.isNumbered()) {
1417: writeInt(out, addFont(new Font(Font.TIMES_ROMAN,
1418: Font.NORMAL, 10, new Color(0, 0, 0))));
1419: } else {
1420: writeInt(out, fontNr);
1421: }
1422: out.write(escape);
1423: out.write(firstIndent);
1424: writeInt(out, (int) (list.getIndentationLeft()
1425: * TWIPSFACTOR * -1));
1426: out.write(escape);
1427: out.write(listIndent);
1428: writeInt(out, (int) ((list.getIndentationLeft() + list
1429: .getSymbolIndent()) * TWIPSFACTOR));
1430: out.write(escape);
1431: out.write(rightIndent);
1432: writeInt(
1433: out,
1434: (int) (list.getIndentationRight() * TWIPSFACTOR));
1435: out.write(delimiter);
1436: if (list.isNumbered()) {
1437: writeInt(out, count);
1438: out.write(".".getBytes());
1439: } else {
1440: out.write(escape);
1441: out.write(listBulletOld);
1442: }
1443: out.write(escape);
1444: out.write(tab);
1445: out.write(closeGroup);
1446: writeListElement((ListItem) listElem, out);
1447: count++;
1448: } else if (listElem.type() == Element.LIST) {
1449: listLevel++;
1450: writeList((com.lowagie.text.List) listElem, out);
1451: listLevel--;
1452: out.write(escape);
1453: out.write(paragraphDefaults);
1454: out.write(escape);
1455: out.write(alignLeft);
1456: out.write(escape);
1457: out.write(firstIndent);
1458: writeInt(out, (int) (list.getIndentationLeft()
1459: * TWIPSFACTOR * -1));
1460: out.write(escape);
1461: out.write(listIndent);
1462: writeInt(out, (int) ((list.getIndentationLeft() + list
1463: .getSymbolIndent()) * TWIPSFACTOR));
1464: out.write(escape);
1465: out.write(rightIndent);
1466: writeInt(
1467: out,
1468: (int) (list.getIndentationRight() * TWIPSFACTOR));
1469: out.write(escape);
1470: out.write(fontSize);
1471: writeInt(out, 20);
1472: out.write(escape);
1473: out.write(listBegin);
1474: writeInt(out, currentListID);
1475: if (listLevel > 0) {
1476: out.write(escape);
1477: out.write(listCurrentLevel);
1478: writeInt(out, listLevel);
1479: }
1480: }
1481: out.write((byte) '\n');
1482: }
1483: out.write(closeGroup);
1484: if (listLevel == 0) {
1485: int i = getRandomInt();
1486: listtable.write(escape);
1487: listtable.write(listID);
1488: writeInt(listtable, i);
1489: listtable.write(closeGroup);
1490: listtable.write((byte) '\n');
1491: listoverride.write(openGroup);
1492: listoverride.write(escape);
1493: listoverride.write(listOverride);
1494: listoverride.write(escape);
1495: listoverride.write(listID);
1496: writeInt(listoverride, i);
1497: listoverride.write(escape);
1498: listoverride.write(listOverrideCount);
1499: writeInt(listoverride, 0);
1500: listoverride.write(escape);
1501: listoverride.write(listBegin);
1502: writeInt(listoverride, currentListID);
1503: currentListID++;
1504: listoverride.write(closeGroup);
1505: listoverride.write((byte) '\n');
1506: }
1507: out.write(escape);
1508: out.write(paragraphDefaults);
1509: }
1510:
1511: /**
1512: * Write a <code>Table</code>.
1513: *
1514: * @param table The <code>table</code> to be written
1515: * @param out The <code>ByteArrayOutputStream</code> to write to
1516: *
1517: * Currently no nesting of tables is supported. If a cell contains anything but a Cell Object it is ignored.
1518: *
1519: * @throws IOException
1520: * @throws DocumentException
1521: */
1522: private void writeTable(Table table, ByteArrayOutputStream out)
1523: throws IOException, DocumentException {
1524: inTable = true;
1525: table.complete();
1526: RtfTable rtfTable = new RtfTable(this );
1527: rtfTable.importTable(table, pageWidth - marginLeft
1528: - marginRight);
1529: rtfTable.writeTable(out);
1530: inTable = false;
1531: }
1532:
1533: /**
1534: * Write an <code>Image</code>.
1535: *
1536: * @param image The <code>image</code> to be written
1537: * @param out The <code>ByteArrayOutputStream</code> to write to
1538: *
1539: * At the moment only PNG and JPEG Images are supported.
1540: *
1541: * @throws IOException
1542: * @throws DocumentException
1543: */
1544: private void writeImage(Image image, ByteArrayOutputStream out)
1545: throws IOException, DocumentException {
1546: int type = image.getOriginalType();
1547: if (!(type == Image.ORIGINAL_JPEG || type == Image.ORIGINAL_BMP
1548: || type == Image.ORIGINAL_PNG || type == Image.ORIGINAL_WMF))
1549: throw new DocumentException(
1550: "Only BMP, PNG, WMF and JPEG images are supported by the RTF Writer");
1551: switch (image.getAlignment()) {
1552: case Element.ALIGN_LEFT:
1553: out.write(escape);
1554: out.write(alignLeft);
1555: break;
1556: case Element.ALIGN_RIGHT:
1557: out.write(escape);
1558: out.write(alignRight);
1559: break;
1560: case Element.ALIGN_CENTER:
1561: out.write(escape);
1562: out.write(alignCenter);
1563: break;
1564: case Element.ALIGN_JUSTIFIED:
1565: out.write(escape);
1566: out.write(alignJustify);
1567: break;
1568: }
1569: out.write(openGroup);
1570: out.write(extendedEscape);
1571: out.write(pictureGroup);
1572: out.write(openGroup);
1573: out.write(escape);
1574: out.write(picture);
1575: out.write(escape);
1576: switch (type) {
1577: case Image.ORIGINAL_JPEG:
1578: out.write(pictureJPEG);
1579: break;
1580: case Image.ORIGINAL_PNG:
1581: out.write(picturePNG);
1582: break;
1583: case Image.ORIGINAL_WMF:
1584: case Image.ORIGINAL_BMP:
1585: out.write(pictureWMF);
1586: break;
1587: }
1588: out.write(escape);
1589: out.write(pictureWidth);
1590: writeInt(out, (int) (image.getPlainWidth() * TWIPSFACTOR));
1591: out.write(escape);
1592: out.write(pictureHeight);
1593: writeInt(out, (int) (image.getPlainHeight() * TWIPSFACTOR));
1594:
1595: // For some reason this messes up the intended image size. It makes it too big. Weird
1596: //
1597: // out.write(escape);
1598: // out.write(pictureIntendedWidth);
1599: // writeInt(out, (int) (image.plainWidth() * twipsFactor));
1600: // out.write(escape);
1601: // out.write(pictureIntendedHeight);
1602: // writeInt(out, (int) (image.plainHeight() * twipsFactor));
1603:
1604: if (image.getWidth() > 0) {
1605: out.write(escape);
1606: out.write(pictureScaleX);
1607: writeInt(out, (int) (100 / image.getWidth() * image
1608: .getPlainWidth()));
1609: }
1610: if (image.getHeight() > 0) {
1611: out.write(escape);
1612: out.write(pictureScaleY);
1613: writeInt(out, (int) (100 / image.getHeight() * image
1614: .getPlainHeight()));
1615: }
1616: out.write(delimiter);
1617: InputStream imgIn;
1618: if (type == Image.ORIGINAL_BMP) {
1619: imgIn = new ByteArrayInputStream(MetaDo.wrapBMP(image));
1620: } else {
1621: if (image.getOriginalData() == null) {
1622: imgIn = image.getUrl().openStream();
1623: } else {
1624: imgIn = new ByteArrayInputStream(image
1625: .getOriginalData());
1626: }
1627: if (type == Image.ORIGINAL_WMF) { //remove the placeable header
1628: long skipLength = 22;
1629: while (skipLength > 0) {
1630: skipLength = skipLength - imgIn.skip(skipLength);
1631: }
1632: }
1633: }
1634: int buffer = -1;
1635: int count = 0;
1636: out.write((byte) '\n');
1637: while ((buffer = imgIn.read()) != -1) {
1638: String helperStr = Integer.toHexString(buffer);
1639: if (helperStr.length() < 2)
1640: helperStr = "0" + helperStr;
1641: out.write(helperStr.getBytes());
1642: count++;
1643: if (count == 64) {
1644: out.write((byte) '\n');
1645: count = 0;
1646: }
1647: }
1648: imgIn.close();
1649: out.write(closeGroup);
1650: out.write(closeGroup);
1651: out.write((byte) '\n');
1652: }
1653:
1654: /**
1655: * Write an <code>Annotation</code>
1656: *
1657: * @param annotationElement The <code>Annotation</code> to be written
1658: * @param out The <code>ByteArrayOutputStream</code> to write to
1659: *
1660: * @throws IOException
1661: */
1662: private void writeAnnotation(Annotation annotationElement,
1663: ByteArrayOutputStream out) throws IOException {
1664: int id = getRandomInt();
1665: out.write(openGroup);
1666: out.write(extendedEscape);
1667: out.write(annotationID);
1668: out.write(delimiter);
1669: writeInt(out, id);
1670: out.write(closeGroup);
1671: out.write(openGroup);
1672: out.write(extendedEscape);
1673: out.write(annotationAuthor);
1674: out.write(delimiter);
1675: out.write(annotationElement.title().getBytes());
1676: out.write(closeGroup);
1677: out.write(openGroup);
1678: out.write(extendedEscape);
1679: out.write(annotation);
1680: out.write(escape);
1681: out.write(paragraphDefaults);
1682: out.write(delimiter);
1683: out.write(annotationElement.content().getBytes());
1684: out.write(closeGroup);
1685: }
1686:
1687: /**
1688: * Add a <code>Meta</code> element. It is written to the Inforamtion Group
1689: * and merged with the main <code>ByteArrayOutputStream</code> when the
1690: * Document is closed.
1691: *
1692: * @param metaName The type of <code>Meta</code> element to be added
1693: * @param meta The <code>Meta</code> element to be added
1694: *
1695: * Currently only the Meta Elements Author, Subject, Keywords, Title, Producer and CreationDate are supported.
1696: *
1697: * @throws IOException
1698: */
1699: private void writeMeta(byte[] metaName, Meta meta)
1700: throws IOException {
1701: info.write(openGroup);
1702: try {
1703: info.write(escape);
1704: info.write(metaName);
1705: info.write(delimiter);
1706: if (meta.type() == Meta.CREATIONDATE) {
1707: writeFormatedDateTime(meta.getContent());
1708: } else {
1709: info.write(meta.getContent().getBytes());
1710: }
1711: } finally {
1712: info.write(closeGroup);
1713: }
1714: }
1715:
1716: /**
1717: * Writes a date. The date is formated <strong>Year, Month, Day, Hour, Minute, Second</strong>
1718: *
1719: * @param date The date to be written
1720: *
1721: * @throws IOException
1722: */
1723: private void writeFormatedDateTime(String date) throws IOException {
1724: Calendar cal = Calendar.getInstance();
1725: SimpleDateFormat sdf = new SimpleDateFormat(
1726: "EEE MMM dd HH:mm:ss zzz yyyy");
1727: ParsePosition pp = new ParsePosition(0);
1728: Date d = sdf.parse(date, pp);
1729: if (d == null) {
1730: d = new Date();
1731: }
1732: cal.setTime(d);
1733: info.write(escape);
1734: info.write(year);
1735: writeInt(info, cal.get(Calendar.YEAR));
1736: info.write(escape);
1737: info.write(month);
1738: writeInt(info, cal.get(Calendar.MONTH));
1739: info.write(escape);
1740: info.write(day);
1741: writeInt(info, cal.get(Calendar.DAY_OF_MONTH));
1742: info.write(escape);
1743: info.write(hour);
1744: writeInt(info, cal.get(Calendar.HOUR_OF_DAY));
1745: info.write(escape);
1746: info.write(minute);
1747: writeInt(info, cal.get(Calendar.MINUTE));
1748: info.write(escape);
1749: info.write(second);
1750: writeInt(info, cal.get(Calendar.SECOND));
1751: }
1752:
1753: /**
1754: * Add a new <code>Font</code> to the list of fonts. If the <code>Font</code>
1755: * already exists in the list of fonts, then it is not added again.
1756: *
1757: * @param newFont The <code>Font</code> to be added
1758: *
1759: * @return The index of the <code>Font</code> in the font list
1760: */
1761: protected int addFont(Font newFont) {
1762: int fn = -1;
1763:
1764: for (int i = 0; i < fontList.size(); i++) {
1765: if (newFont.getFamilyname().equals(
1766: ((Font) fontList.get(i)).getFamilyname())) {
1767: fn = i;
1768: }
1769: }
1770: if (fn == -1) {
1771: fontList.add(newFont);
1772: return fontList.size() - 1;
1773: }
1774: return fn;
1775: }
1776:
1777: /**
1778: * Add a new <code>Color</code> to the list of colours. If the <code>Color</code>
1779: * already exists in the list of colours, then it is not added again.
1780: *
1781: * @param newColor The <code>Color</code> to be added
1782: *
1783: * @return The index of the <code>color</code> in the colour list
1784: */
1785: protected int addColor(Color newColor) {
1786: int cn = 0;
1787: if (newColor == null) {
1788: return cn;
1789: }
1790: cn = colorList.indexOf(newColor);
1791: if (cn == -1) {
1792: colorList.add(newColor);
1793: return colorList.size() - 1;
1794: }
1795: return cn;
1796: }
1797:
1798: /**
1799: * Merge all the different <code>ArrayList</code>s and <code>ByteArrayOutputStream</code>s
1800: * to the final <code>ByteArrayOutputStream</code>
1801: *
1802: * @return <code>true</code> if all information was sucessfully written to the <code>ByteArrayOutputStream</code>
1803: */
1804: private boolean writeDocument() {
1805: try {
1806: writeDocumentIntro();
1807: writeFontList();
1808: os.write((byte) '\n');
1809: writeColorList();
1810: os.write((byte) '\n');
1811: writeList();
1812: os.write((byte) '\n');
1813: writeInfoGroup();
1814: os.write((byte) '\n');
1815: writeDocumentFormat();
1816: os.write((byte) '\n');
1817: ByteArrayOutputStream hf = new ByteArrayOutputStream();
1818: writeSectionDefaults(hf);
1819: hf.writeTo(os);
1820: content.writeTo(os);
1821: os.write(closeGroup);
1822: return true;
1823: } catch (IOException e) {
1824: System.err.println(e.getMessage());
1825: return false;
1826: }
1827:
1828: }
1829:
1830: /** Write the Rich Text file settings
1831: * @throws IOException
1832: */
1833: private void writeDocumentIntro() throws IOException {
1834: os.write(openGroup);
1835: os.write(escape);
1836: os.write(docBegin);
1837: os.write(escape);
1838: os.write(ansi);
1839: os.write(escape);
1840: os.write(ansiCodepage);
1841: writeInt(os, 1252);
1842: os.write((byte) '\n');
1843: os.write(escape);
1844: os.write(defaultFont);
1845: writeInt(os, 0);
1846: }
1847:
1848: /**
1849: * Write the font list to the final <code>ByteArrayOutputStream</code>
1850: * @throws IOException
1851: */
1852: private void writeFontList() throws IOException {
1853: Font fnt;
1854:
1855: os.write(openGroup);
1856: os.write(escape);
1857: os.write(fontTable);
1858: for (int i = 0; i < fontList.size(); i++) {
1859: fnt = (Font) fontList.get(i);
1860: os.write(openGroup);
1861: os.write(escape);
1862: os.write(fontNumber);
1863: writeInt(os, i);
1864: os.write(escape);
1865: switch (Font.getFamilyIndex(fnt.getFamilyname())) {
1866: case Font.COURIER:
1867: os.write(fontModern);
1868: os.write(escape);
1869: os.write(fontCharset);
1870: writeInt(os, 0);
1871: os.write(delimiter);
1872: os.write(fontCourier);
1873: break;
1874: case Font.HELVETICA:
1875: os.write(fontSwiss);
1876: os.write(escape);
1877: os.write(fontCharset);
1878: writeInt(os, 0);
1879: os.write(delimiter);
1880: os.write(fontArial);
1881: break;
1882: case Font.SYMBOL:
1883: os.write(fontRoman);
1884: os.write(escape);
1885: os.write(fontCharset);
1886: writeInt(os, 2);
1887: os.write(delimiter);
1888: os.write(fontSymbol);
1889: break;
1890: case Font.TIMES_ROMAN:
1891: os.write(fontRoman);
1892: os.write(escape);
1893: os.write(fontCharset);
1894: writeInt(os, 0);
1895: os.write(delimiter);
1896: os.write(fontTimesNewRoman);
1897: break;
1898: case Font.ZAPFDINGBATS:
1899: os.write(fontTech);
1900: os.write(escape);
1901: os.write(fontCharset);
1902: writeInt(os, 0);
1903: os.write(delimiter);
1904: os.write(fontWindings);
1905: break;
1906: default:
1907: os.write(fontRoman);
1908: os.write(escape);
1909: os.write(fontCharset);
1910: writeInt(os, 0);
1911: os.write(delimiter);
1912: os.write(filterSpecialChar(fnt.getFamilyname(), true)
1913: .getBytes());
1914: }
1915: os.write(commaDelimiter);
1916: os.write(closeGroup);
1917: }
1918: os.write(closeGroup);
1919: }
1920:
1921: /**
1922: * Write the colour list to the final <code>ByteArrayOutputStream</code>
1923: * @throws IOException
1924: */
1925: private void writeColorList() throws IOException {
1926: Color color = null;
1927:
1928: os.write(openGroup);
1929: os.write(escape);
1930: os.write(colorTable);
1931: for (int i = 0; i < colorList.size(); i++) {
1932: color = (Color) colorList.get(i);
1933: os.write(escape);
1934: os.write(colorRed);
1935: writeInt(os, color.getRed());
1936: os.write(escape);
1937: os.write(colorGreen);
1938: writeInt(os, color.getGreen());
1939: os.write(escape);
1940: os.write(colorBlue);
1941: writeInt(os, color.getBlue());
1942: os.write(commaDelimiter);
1943: }
1944: os.write(closeGroup);
1945: }
1946:
1947: /**
1948: * Write the Information Group to the final <code>ByteArrayOutputStream</code>
1949: * @throws IOException
1950: */
1951: private void writeInfoGroup() throws IOException {
1952: os.write(openGroup);
1953: os.write(escape);
1954: os.write(infoBegin);
1955: info.writeTo(os);
1956: os.write(closeGroup);
1957: }
1958:
1959: /**
1960: * Write the listtable and listoverridetable to the final <code>ByteArrayOutputStream</code>
1961: * @throws IOException
1962: */
1963: private void writeList() throws IOException {
1964: listtable.write(closeGroup);
1965: listoverride.write(closeGroup);
1966: listtable.writeTo(os);
1967: os.write((byte) '\n');
1968: listoverride.writeTo(os);
1969: }
1970:
1971: /**
1972: * Write an integer
1973: *
1974: * @param out The <code>OuputStream</code> to which the <code>int</code> value is to be written
1975: * @param i The <code>int</code> value to be written
1976: * @throws IOException
1977: */
1978: public final static void writeInt(OutputStream out, int i)
1979: throws IOException {
1980: out.write(Integer.toString(i).getBytes());
1981: }
1982:
1983: /**
1984: * Get a random integer.
1985: * This returns a <b>unique</b> random integer to be used with listids.
1986: *
1987: * @return Random <code>int</code> value.
1988: */
1989: private int getRandomInt() {
1990: boolean ok = false;
1991: Integer newInt = null;
1992: Integer oldInt = null;
1993: while (!ok) {
1994: newInt = new Integer(
1995: (int) (Math.random() * Integer.MAX_VALUE));
1996: ok = true;
1997: for (int i = 0; i < listIds.size(); i++) {
1998: oldInt = (Integer) listIds.get(i);
1999: if (oldInt.equals(newInt)) {
2000: ok = true;
2001: }
2002: }
2003: }
2004: listIds.add(newInt);
2005: return newInt.intValue();
2006: }
2007:
2008: /**
2009: * Write the current header and footer to a <code>ByteArrayOutputStream</code>
2010: *
2011: * @param os The <code>ByteArrayOutputStream</code> to which the header and footer will be written.
2012: * @throws IOException
2013: */
2014: public void writeHeadersFooters(ByteArrayOutputStream os)
2015: throws IOException {
2016: if (this .footer instanceof RtfHeaderFooters) {
2017: RtfHeaderFooters rtfHf = (RtfHeaderFooters) this .footer;
2018: HeaderFooter hf = rtfHf.get(RtfHeaderFooters.ALL_PAGES);
2019: if (hf != null) {
2020: writeHeaderFooter(hf, footerBegin, os);
2021: }
2022: hf = rtfHf.get(RtfHeaderFooters.LEFT_PAGES);
2023: if (hf != null) {
2024: writeHeaderFooter(hf, footerlBegin, os);
2025: }
2026: hf = rtfHf.get(RtfHeaderFooters.RIGHT_PAGES);
2027: if (hf != null) {
2028: writeHeaderFooter(hf, footerrBegin, os);
2029: }
2030: hf = rtfHf.get(RtfHeaderFooters.FIRST_PAGE);
2031: if (hf != null) {
2032: writeHeaderFooter(hf, footerfBegin, os);
2033: }
2034: } else {
2035: writeHeaderFooter(this .footer, footerBegin, os);
2036: }
2037: if (this .header instanceof RtfHeaderFooters) {
2038: RtfHeaderFooters rtfHf = (RtfHeaderFooters) this .header;
2039: HeaderFooter hf = rtfHf.get(RtfHeaderFooters.ALL_PAGES);
2040: if (hf != null) {
2041: writeHeaderFooter(hf, headerBegin, os);
2042: }
2043: hf = rtfHf.get(RtfHeaderFooters.LEFT_PAGES);
2044: if (hf != null) {
2045: writeHeaderFooter(hf, headerlBegin, os);
2046: }
2047: hf = rtfHf.get(RtfHeaderFooters.RIGHT_PAGES);
2048: if (hf != null) {
2049: writeHeaderFooter(hf, headerrBegin, os);
2050: }
2051: hf = rtfHf.get(RtfHeaderFooters.FIRST_PAGE);
2052: if (hf != null) {
2053: writeHeaderFooter(hf, headerfBegin, os);
2054: }
2055: } else {
2056: writeHeaderFooter(this .header, headerBegin, os);
2057: }
2058: }
2059:
2060: /**
2061: * Write a <code>HeaderFooter</code> to a <code>ByteArrayOutputStream</code>
2062: *
2063: * @param headerFooter The <code>HeaderFooter</code> object to be written.
2064: * @param hfType The type of header or footer to be added.
2065: * @param target The <code>ByteArrayOutputStream</code> to which the <code>HeaderFooter</code> will be written.
2066: * @throws IOException
2067: */
2068: private void writeHeaderFooter(HeaderFooter headerFooter,
2069: byte[] hfType, ByteArrayOutputStream target)
2070: throws IOException {
2071: inHeaderFooter = true;
2072: try {
2073: target.write(openGroup);
2074: target.write(escape);
2075: target.write(hfType);
2076: target.write(delimiter);
2077: if (headerFooter != null) {
2078: if (headerFooter instanceof RtfHeaderFooter
2079: && ((RtfHeaderFooter) headerFooter).content() != null) {
2080: this .addElement(((RtfHeaderFooter) headerFooter)
2081: .content(), target);
2082: } else {
2083: Paragraph par = new Paragraph();
2084: par.setAlignment(headerFooter.alignment());
2085: if (headerFooter.getBefore() != null) {
2086: par.add(headerFooter.getBefore());
2087: }
2088: if (headerFooter.isNumbered()) {
2089: par.add(new RtfPageNumber("", headerFooter
2090: .getBefore().getFont()));
2091: }
2092: if (headerFooter.getAfter() != null) {
2093: par.add(headerFooter.getAfter());
2094: }
2095: this .addElement(par, target);
2096: }
2097: }
2098: target.write(closeGroup);
2099: } catch (DocumentException e) {
2100: throw new IOException("DocumentException - "
2101: + e.getMessage());
2102: }
2103: inHeaderFooter = false;
2104: }
2105:
2106: /**
2107: * Write the <code>Document</code>'s Paper and Margin Size
2108: * to the final <code>ByteArrayOutputStream</code>
2109: * @throws IOException
2110: */
2111: private void writeDocumentFormat() throws IOException {
2112: // os.write(openGroup);
2113: os.write(escape);
2114: os.write(rtfPaperWidth);
2115: writeInt(os, pageWidth);
2116: os.write(escape);
2117: os.write(rtfPaperHeight);
2118: writeInt(os, pageHeight);
2119: os.write(escape);
2120: os.write(rtfMarginLeft);
2121: writeInt(os, marginLeft);
2122: os.write(escape);
2123: os.write(rtfMarginRight);
2124: writeInt(os, marginRight);
2125: os.write(escape);
2126: os.write(rtfMarginTop);
2127: writeInt(os, marginTop);
2128: os.write(escape);
2129: os.write(rtfMarginBottom);
2130: writeInt(os, marginBottom);
2131: // os.write(closeGroup);
2132: }
2133:
2134: /**
2135: * Initialise all helper classes.
2136: * Clears alls lists, creates new <code>ByteArrayOutputStream</code>'s
2137: */
2138: private void initDefaults() {
2139: fontList.clear();
2140: colorList.clear();
2141: info = new ByteArrayOutputStream();
2142: content = new ByteArrayOutputStream();
2143: listtable = new ByteArrayOutputStream();
2144: listoverride = new ByteArrayOutputStream();
2145: document.addProducer();
2146: document.addCreationDate();
2147: addFont(new Font(Font.TIMES_ROMAN, 10, Font.NORMAL));
2148: addColor(new Color(0, 0, 0));
2149: addColor(new Color(255, 255, 255));
2150: listIds = new ArrayList();
2151: try {
2152: listtable.write(openGroup);
2153: listtable.write(extendedEscape);
2154: listtable.write(listtableGroup);
2155: listtable.write((byte) '\n');
2156: listoverride.write(openGroup);
2157: listoverride.write(extendedEscape);
2158: listoverride.write(listoverridetableGroup);
2159: listoverride.write((byte) '\n');
2160: } catch (IOException e) {
2161: System.err.println("InitDefaultsError" + e);
2162: }
2163: }
2164:
2165: /**
2166: * Writes the default values for the current Section
2167: *
2168: * @param out The <code>ByteArrayOutputStream</code> to be written to
2169: * @throws IOException
2170: */
2171: private void writeSectionDefaults(ByteArrayOutputStream out)
2172: throws IOException {
2173: if (header instanceof RtfHeaderFooters
2174: || footer instanceof RtfHeaderFooters) {
2175: RtfHeaderFooters rtfHeader = (RtfHeaderFooters) header;
2176: RtfHeaderFooters rtfFooter = (RtfHeaderFooters) footer;
2177: if ((rtfHeader != null && (rtfHeader
2178: .get(RtfHeaderFooters.LEFT_PAGES) != null || rtfHeader
2179: .get(RtfHeaderFooters.RIGHT_PAGES) != null))
2180: || (rtfFooter != null && (rtfFooter
2181: .get(RtfHeaderFooters.LEFT_PAGES) != null || rtfFooter
2182: .get(RtfHeaderFooters.RIGHT_PAGES) != null))) {
2183: out.write(escape);
2184: out.write(facingPages);
2185: }
2186: }
2187: if (hasTitlePage) {
2188: out.write(escape);
2189: out.write(titlePage);
2190: }
2191: writeHeadersFooters(out);
2192: if (landscape) {
2193: //out.write(escape);
2194: //out.write(landscapeTag1);
2195: out.write(escape);
2196: out.write(landscapeTag2);
2197: out.write(escape);
2198: out.write(sectionPageWidth);
2199: writeInt(out, pageWidth);
2200: out.write(escape);
2201: out.write(sectionPageHeight);
2202: writeInt(out, pageHeight);
2203: } else {
2204: out.write(escape);
2205: out.write(sectionPageWidth);
2206: writeInt(out, pageWidth);
2207: out.write(escape);
2208: out.write(sectionPageHeight);
2209: writeInt(out, pageHeight);
2210: }
2211: }
2212:
2213: /**
2214: * This method tries to fit the <code>Rectangle pageSize</code> to one of the predefined PageSize rectangles.
2215: * If a match is found the pageWidth and pageHeight will be set according to values determined from files
2216: * generated by MS Word2000 and OpenOffice 641. If no match is found the method will try to match the rotated
2217: * Rectangle by calling itself with the parameter rotate set to true.
2218: * @param pageSize a rectangle defining the size of the page
2219: * @param rotate portrait or lanscape?
2220: * @return true if the format parsing succeeded
2221: */
2222: private boolean parseFormat(Rectangle pageSize, boolean rotate) {
2223: if (rotate) {
2224: pageSize = pageSize.rotate();
2225: }
2226: if (rectEquals(pageSize, PageSize.A3)) {
2227: pageWidth = 16837;
2228: pageHeight = 23811;
2229: landscape = rotate;
2230: return true;
2231: }
2232: if (rectEquals(pageSize, PageSize.A4)) {
2233: pageWidth = 11907;
2234: pageHeight = 16840;
2235: landscape = rotate;
2236: return true;
2237: }
2238: if (rectEquals(pageSize, PageSize.A5)) {
2239: pageWidth = 8391;
2240: pageHeight = 11907;
2241: landscape = rotate;
2242: return true;
2243: }
2244: if (rectEquals(pageSize, PageSize.A6)) {
2245: pageWidth = 5959;
2246: pageHeight = 8420;
2247: landscape = rotate;
2248: return true;
2249: }
2250: if (rectEquals(pageSize, PageSize.B4)) {
2251: pageWidth = 14570;
2252: pageHeight = 20636;
2253: landscape = rotate;
2254: return true;
2255: }
2256: if (rectEquals(pageSize, PageSize.B5)) {
2257: pageWidth = 10319;
2258: pageHeight = 14572;
2259: landscape = rotate;
2260: return true;
2261: }
2262: if (rectEquals(pageSize, PageSize.HALFLETTER)) {
2263: pageWidth = 7927;
2264: pageHeight = 12247;
2265: landscape = rotate;
2266: return true;
2267: }
2268: if (rectEquals(pageSize, PageSize.LETTER)) {
2269: pageWidth = 12242;
2270: pageHeight = 15842;
2271: landscape = rotate;
2272: return true;
2273: }
2274: if (rectEquals(pageSize, PageSize.LEGAL)) {
2275: pageWidth = 12252;
2276: pageHeight = 20163;
2277: landscape = rotate;
2278: return true;
2279: }
2280: if (!rotate && parseFormat(pageSize, true)) {
2281: int x = pageWidth;
2282: pageWidth = pageHeight;
2283: pageHeight = x;
2284: return true;
2285: }
2286: return false;
2287: }
2288:
2289: /**
2290: * This method compares to Rectangles. They are considered equal if width and height are the same
2291: * @param rect1
2292: * @param rect2
2293: * @return true if rect1 and rect2 represent the same rectangle
2294: */
2295: private boolean rectEquals(Rectangle rect1, Rectangle rect2) {
2296: return (rect1.getWidth() == rect2.getWidth())
2297: && (rect1.getHeight() == rect2.getHeight());
2298: }
2299:
2300: /**
2301: * Returns whether we are currently writing a header or footer
2302: *
2303: * @return the value of inHeaderFooter
2304: */
2305: public boolean writingHeaderFooter() {
2306: return inHeaderFooter;
2307: }
2308:
2309: /**
2310: * Replaces special characters with their unicode values
2311: *
2312: * @param str The original <code>String</code>
2313: * @param useHex
2314: * @return The converted String
2315: */
2316: public final static String filterSpecialChar(String str,
2317: boolean useHex) {
2318: int length = str.length();
2319: int z = (int) 'z';
2320: StringBuffer ret = new StringBuffer(length);
2321: for (int i = 0; i < length; i++) {
2322: char ch = str.charAt(i);
2323:
2324: if (ch == '\\') {
2325: ret.append("\\\\");
2326: } else if (ch == '\n') {
2327: ret.append("\\par ");
2328: } else if (((int) ch) > z) {
2329: if (useHex) {
2330: ret.append("\\\'").append(
2331: Long.toHexString((long) ch));
2332: } else {
2333: ret.append("\\u").append((long) ch).append('?');
2334: }
2335: } else {
2336: ret.append(ch);
2337: }
2338: }
2339: String s = ret.toString();
2340: if (s.indexOf("$newpage$") >= 0) {
2341: String before = s.substring(0, s.indexOf("$newpage$"));
2342: String after = s.substring(s.indexOf("$newpage$") + 9);
2343: ret = new StringBuffer(before);
2344: ret.append("\\page\\par ");
2345: ret.append(after);
2346: return ret.toString();
2347: }
2348: return s;
2349: }
2350:
2351: private void addHeaderFooterFontColor(HeaderFooter hf) {
2352: if (hf instanceof RtfHeaderFooter) {
2353: RtfHeaderFooter rhf = (RtfHeaderFooter) hf;
2354: if (rhf.content() instanceof Chunk) {
2355: addFont(((Chunk) rhf.content()).getFont());
2356: addColor(((Chunk) rhf.content()).getFont().getColor());
2357: } else if (rhf.content() instanceof Phrase) {
2358: addFont(((Phrase) rhf.content()).getFont());
2359: addColor(((Phrase) rhf.content()).getFont().getColor());
2360: }
2361: }
2362: if (hf.getBefore() != null) {
2363: addFont(hf.getBefore().getFont());
2364: addColor(hf.getBefore().getFont().getColor());
2365: }
2366: if (hf.getAfter() != null) {
2367: addFont(hf.getAfter().getFont());
2368: addColor(hf.getAfter().getFont().getColor());
2369: }
2370: }
2371:
2372: private void processHeaderFooter(HeaderFooter hf) {
2373: if (hf != null) {
2374: if (hf instanceof RtfHeaderFooters) {
2375: RtfHeaderFooters rhf = (RtfHeaderFooters) hf;
2376: if (rhf.get(RtfHeaderFooters.ALL_PAGES) != null) {
2377: addHeaderFooterFontColor(rhf
2378: .get(RtfHeaderFooters.ALL_PAGES));
2379: }
2380: if (rhf.get(RtfHeaderFooters.LEFT_PAGES) != null) {
2381: addHeaderFooterFontColor(rhf
2382: .get(RtfHeaderFooters.LEFT_PAGES));
2383: }
2384: if (rhf.get(RtfHeaderFooters.RIGHT_PAGES) != null) {
2385: addHeaderFooterFontColor(rhf
2386: .get(RtfHeaderFooters.RIGHT_PAGES));
2387: }
2388: if (rhf.get(RtfHeaderFooters.FIRST_PAGE) != null) {
2389: addHeaderFooterFontColor(rhf
2390: .get(RtfHeaderFooters.FIRST_PAGE));
2391: }
2392: } else {
2393: addHeaderFooterFontColor(hf);
2394: }
2395: }
2396: }
2397:
2398: /**
2399: * @see com.lowagie.text.DocListener#setMarginMirroring(boolean)
2400: */
2401: public boolean setMarginMirroring(boolean MarginMirroring) {
2402: return false;
2403: }
2404:
2405: }
|