KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lowagie > text > pdf > PdfDocument


1 /*
2  * $Name$
3  * $Id: PdfDocument.java 2810 2007-05-30 16:18:36Z psoares33 $
4  *
5  * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie.
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.pdf;
52
53 import java.awt.Color JavaDoc;
54 import java.io.IOException JavaDoc;
55 import java.util.ArrayList JavaDoc;
56 import java.util.Arrays JavaDoc;
57 import java.util.HashMap JavaDoc;
58 import java.util.HashSet JavaDoc;
59 import java.util.Iterator JavaDoc;
60 import java.util.Map JavaDoc;
61 import java.util.Set JavaDoc;
62 import java.util.TreeMap JavaDoc;
63
64 import com.lowagie.text.Anchor;
65 import com.lowagie.text.Annotation;
66 import com.lowagie.text.BadElementException;
67 import com.lowagie.text.Chunk;
68 import com.lowagie.text.Document;
69 import com.lowagie.text.DocumentException;
70 import com.lowagie.text.Element;
71 import com.lowagie.text.ExceptionConverter;
72 import com.lowagie.text.Font;
73 import com.lowagie.text.HeaderFooter;
74 import com.lowagie.text.Image;
75 import com.lowagie.text.List;
76 import com.lowagie.text.ListItem;
77 import com.lowagie.text.MarkedObject;
78 import com.lowagie.text.MarkedSection;
79 import com.lowagie.text.Meta;
80 import com.lowagie.text.Paragraph;
81 import com.lowagie.text.Phrase;
82 import com.lowagie.text.Rectangle;
83 import com.lowagie.text.Section;
84 import com.lowagie.text.SimpleTable;
85 import com.lowagie.text.Table;
86 import com.lowagie.text.pdf.collection.PdfCollection;
87 import com.lowagie.text.pdf.internal.PdfAnnotationsImp;
88 import com.lowagie.text.pdf.internal.PdfViewerPreferencesImp;
89
90 /**
91  * <CODE>PdfDocument</CODE> is the class that is used by <CODE>PdfWriter</CODE>
92  * to translate a <CODE>Document</CODE> into a PDF with different pages.
93  * <P>
94  * A <CODE>PdfDocument</CODE> always listens to a <CODE>Document</CODE>
95  * and adds the Pdf representation of every <CODE>Element</CODE> that is
96  * added to the <CODE>Document</CODE>.
97  *
98  * @see com.lowagie.text.Document
99  * @see com.lowagie.text.DocListener
100  * @see PdfWriter
101  */

102
103 class PdfDocument extends Document {
104     
105     /**
106      * <CODE>PdfInfo</CODE> is the PDF InfoDictionary.
107      * <P>
108      * A document's trailer may contain a reference to an Info dictionary that provides information
109      * about the document. This optional dictionary may contain one or more keys, whose values
110      * should be strings.<BR>
111      * This object is described in the 'Portable Document Format Reference Manual version 1.3'
112      * section 6.10 (page 120-121)
113      */

114     
115     public static class PdfInfo extends PdfDictionary {
116         
117         /**
118          * Construct a <CODE>PdfInfo</CODE>-object.
119          */

120         
121         PdfInfo() {
122             super();
123             addProducer();
124             addCreationDate();
125         }
126         
127         /**
128          * Constructs a <CODE>PdfInfo</CODE>-object.
129          *
130          * @param author name of the author of the document
131          * @param title title of the document
132          * @param subject subject of the document
133          */

134         
135         PdfInfo(String JavaDoc author, String JavaDoc title, String JavaDoc subject) {
136             this();
137             addTitle(title);
138             addSubject(subject);
139             addAuthor(author);
140         }
141         
142         /**
143          * Adds the title of the document.
144          *
145          * @param title the title of the document
146          */

147         
148         void addTitle(String JavaDoc title) {
149             put(PdfName.TITLE, new PdfString(title, PdfObject.TEXT_UNICODE));
150         }
151         
152         /**
153          * Adds the subject to the document.
154          *
155          * @param subject the subject of the document
156          */

157         
158         void addSubject(String JavaDoc subject) {
159             put(PdfName.SUBJECT, new PdfString(subject, PdfObject.TEXT_UNICODE));
160         }
161         
162         /**
163          * Adds some keywords to the document.
164          *
165          * @param keywords the keywords of the document
166          */

167         
168         void addKeywords(String JavaDoc keywords) {
169             put(PdfName.KEYWORDS, new PdfString(keywords, PdfObject.TEXT_UNICODE));
170         }
171         
172         /**
173          * Adds the name of the author to the document.
174          *
175          * @param author the name of the author
176          */

177         
178         void addAuthor(String JavaDoc author) {
179             put(PdfName.AUTHOR, new PdfString(author, PdfObject.TEXT_UNICODE));
180         }
181         
182         /**
183          * Adds the name of the creator to the document.
184          *
185          * @param creator the name of the creator
186          */

187         
188         void addCreator(String JavaDoc creator) {
189             put(PdfName.CREATOR, new PdfString(creator, PdfObject.TEXT_UNICODE));
190         }
191         
192         /**
193          * Adds the name of the producer to the document.
194          */

195         
196         void addProducer() {
197             put(PdfName.PRODUCER, new PdfString(getVersion()));
198         }
199         
200         /**
201          * Adds the date of creation to the document.
202          */

203         
204         void addCreationDate() {
205             PdfString date = new PdfDate();
206             put(PdfName.CREATIONDATE, date);
207             put(PdfName.MODDATE, date);
208         }
209         
210         void addkey(String JavaDoc key, String JavaDoc value) {
211             if (key.equals("Producer") || key.equals("CreationDate"))
212                 return;
213             put(new PdfName(key), new PdfString(value, PdfObject.TEXT_UNICODE));
214         }
215     }
216     
217     /**
218      * <CODE>PdfCatalog</CODE> is the PDF Catalog-object.
219      * <P>
220      * The Catalog is a dictionary that is the root node of the document. It contains a reference
221      * to the tree of pages contained in the document, a reference to the tree of objects representing
222      * the document's outline, a reference to the document's article threads, and the list of named
223      * destinations. In addition, the Catalog indicates whether the document's outline or thumbnail
224      * page images should be displayed automatically when the document is viewed and wether some location
225      * other than the first page should be shown when the document is opened.<BR>
226      * In this class however, only the reference to the tree of pages is implemented.<BR>
227      * This object is described in the 'Portable Document Format Reference Manual version 1.3'
228      * section 6.2 (page 67-71)
229      */

230     
231     static class PdfCatalog extends PdfDictionary {
232         
233         /** The writer writing the PDF for which we are creating this catalog object. */
234         PdfWriter writer;
235         
236         /**
237          * Constructs a <CODE>PdfCatalog</CODE>.
238          *
239          * @param pages an indirect reference to the root of the document's Pages tree.
240          * @param writer the writer the catalog applies to
241          */

242         
243         PdfCatalog(PdfIndirectReference pages, PdfWriter writer) {
244             super(CATALOG);
245             this.writer = writer;
246             put(PdfName.PAGES, pages);
247         }
248         
249         /**
250          * Adds the names of the named destinations to the catalog.
251          * @param localDestinations the local destinations
252          * @param documentJavaScript the javascript used in the document
253          * @param writer the writer the catalog applies to
254          */

255         void addNames(TreeMap JavaDoc localDestinations, ArrayList JavaDoc documentJavaScript, HashMap JavaDoc documentFileAttachment, PdfWriter writer) {
256             if (localDestinations.isEmpty() && documentJavaScript.isEmpty() && documentFileAttachment.isEmpty())
257                 return;
258             try {
259                 PdfDictionary names = new PdfDictionary();
260                 if (!localDestinations.isEmpty()) {
261                     PdfArray ar = new PdfArray();
262                     for (Iterator JavaDoc i = localDestinations.entrySet().iterator(); i.hasNext();) {
263                         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
264                         String JavaDoc name = (String JavaDoc) entry.getKey();
265                         Object JavaDoc obj[] = (Object JavaDoc[]) entry.getValue();
266                         PdfIndirectReference ref = (PdfIndirectReference)obj[1];
267                         ar.add(new PdfString(name, null));
268                         ar.add(ref);
269                     }
270                     PdfDictionary dests = new PdfDictionary();
271                     dests.put(PdfName.NAMES, ar);
272                     names.put(PdfName.DESTS, writer.addToBody(dests).getIndirectReference());
273                 }
274                 if (!documentJavaScript.isEmpty()) {
275                     String JavaDoc s[] = new String JavaDoc[documentJavaScript.size()];
276                     for (int k = 0; k < s.length; ++k)
277                         s[k] = Integer.toHexString(k);
278                     Arrays.sort(s);
279                     PdfArray ar = new PdfArray();
280                     for (int k = 0; k < s.length; ++k) {
281                         ar.add(new PdfString(s[k]));
282                         ar.add((PdfIndirectReference)documentJavaScript.get(k));
283                     }
284                     PdfDictionary js = new PdfDictionary();
285                     js.put(PdfName.NAMES, ar);
286                     names.put(PdfName.JAVASCRIPT, writer.addToBody(js).getIndirectReference());
287                 }
288                 if (!documentFileAttachment.isEmpty()) {
289                     names.put(PdfName.EMBEDDEDFILES, writer.addToBody(PdfNameTree.writeTree(documentFileAttachment, writer)).getIndirectReference());
290                 }
291                 put(PdfName.NAMES, writer.addToBody(names).getIndirectReference());
292             }
293             catch (IOException JavaDoc e) {
294                 throw new ExceptionConverter(e);
295             }
296         }
297         
298         /**
299          * Adds an open action to the catalog.
300          * @param action the action that will be triggered upon opening the document
301          */

302         void setOpenAction(PdfAction action) {
303             put(PdfName.OPENACTION, action);
304         }
305         
306         
307         /**
308          * Sets the document level additional actions.
309          * @param actions dictionary of actions
310          */

311         void setAdditionalActions(PdfDictionary actions) {
312             try {
313                 put(PdfName.AA, writer.addToBody(actions).getIndirectReference());
314             } catch (Exception JavaDoc e) {
315                 throw new ExceptionConverter(e);
316             }
317         }
318     }
319
320 // CONSTRUCTING A PdfDocument/PdfWriter INSTANCE
321

322     /**
323      * Constructs a new PDF document.
324      * @throws DocumentException on error
325      */

326     public PdfDocument() {
327         super();
328         addProducer();
329         addCreationDate();
330     }
331
332     /** The <CODE>PdfWriter</CODE>. */
333     private PdfWriter writer;
334     
335     /**
336      * Adds a <CODE>PdfWriter</CODE> to the <CODE>PdfDocument</CODE>.
337      *
338      * @param writer the <CODE>PdfWriter</CODE> that writes everything
339      * what is added to this document to an outputstream.
340      * @throws DocumentException on error
341      */

342     public void addWriter(PdfWriter writer) throws DocumentException {
343         if (this.writer == null) {
344             this.writer = writer;
345             annotationsImp = new PdfAnnotationsImp(writer);
346             return;
347         }
348         throw new DocumentException("You can only add a writer to a PdfDocument once.");
349     }
350     
351 // LISTENER METHODS START
352

353 // [L0] ElementListener interface
354

355     /** This is the PdfContentByte object, containing the text. */
356     private PdfContentByte text;
357     
358     /** This is the PdfContentByte object, containing the borders and other Graphics. */
359     private PdfContentByte graphics;
360     
361     /** This represents the leading of the lines. */
362     private float leading = 0;
363     
364     /** This represents the current alignment of the PDF Elements. */
365     private int alignment = Element.ALIGN_LEFT;
366     
367     /** This is the current height of the document. */
368     private float currentHeight = 0;
369     
370     /** Signals that onParagraph is valid (to avoid that a Chapter/Section title is treated as a Paragraph). */
371     private boolean isParagraph = true;
372     
373     /** The current active <CODE>PdfAction</CODE> when processing an <CODE>Anchor</CODE>. */
374     private PdfAction anchorAction = null;
375     
376     /**
377      * Signals that an <CODE>Element</CODE> was added to the <CODE>Document</CODE>.
378      *
379      * @param element the element to add
380      * @return <CODE>true</CODE> if the element was added, <CODE>false</CODE> if not.
381      * @throws DocumentException when a document isn't open yet, or has been closed
382      */

383     public boolean add(Element element) throws DocumentException {
384         if (writer != null && writer.isPaused()) {
385             return false;
386         }
387         try {
388             switch(element.type()) {
389                 // Information (headers)
390
case Element.HEADER:
391                     info.addkey(((Meta)element).getName(), ((Meta)element).getContent());
392                     break;
393                 case Element.TITLE:
394                     info.addTitle(((Meta)element).getContent());
395                     break;
396                 case Element.SUBJECT:
397                     info.addSubject(((Meta)element).getContent());
398                     break;
399                 case Element.KEYWORDS:
400                     info.addKeywords(((Meta)element).getContent());
401                     break;
402                 case Element.AUTHOR:
403                     info.addAuthor(((Meta)element).getContent());
404                     break;
405                 case Element.CREATOR:
406                     info.addCreator(((Meta)element).getContent());
407                     break;
408                 case Element.PRODUCER:
409                     // you can not change the name of the producer
410
info.addProducer();
411                     break;
412                 case Element.CREATIONDATE:
413                     // you can not set the creation date, only reset it
414
info.addCreationDate();
415                     break;
416                     
417                 // content (text)
418
case Element.CHUNK: {
419                     // if there isn't a current line available, we make one
420
if (line == null) {
421                         carriageReturn();
422                     }
423                     
424                     // we cast the element to a chunk
425
PdfChunk chunk = new PdfChunk((Chunk) element, anchorAction);
426                     // we try to add the chunk to the line, until we succeed
427
{
428                         PdfChunk overflow;
429                         while ((overflow = line.add(chunk)) != null) {
430                             carriageReturn();
431                             chunk = overflow;
432                             chunk.trimFirstSpace();
433                         }
434                     }
435                     pageEmpty = false;
436                     if (chunk.isAttribute(Chunk.NEWPAGE)) {
437                         newPage();
438                     }
439                     break;
440                 }
441                 case Element.ANCHOR: {
442                     Anchor anchor = (Anchor) element;
443                     String JavaDoc url = anchor.getReference();
444                     leading = anchor.getLeading();
445                     if (url != null) {
446                         anchorAction = new PdfAction(url);
447                     }
448                     // we process the element
449
element.process(this);
450                     anchorAction = null;
451                     break;
452                 }
453                 case Element.ANNOTATION: {
454                     if (line == null) {
455                         carriageReturn();
456                     }
457                     Annotation annot = (Annotation) element;
458                     Rectangle rect = new Rectangle(0, 0);
459                     if (line != null)
460                         rect = new Rectangle(annot.llx(indentRight() - line.widthLeft()), annot.lly(indentTop() - currentHeight), annot.urx(indentRight() - line.widthLeft() + 20), annot.ury(indentTop() - currentHeight - 20));
461                     PdfAnnotation an = PdfAnnotationsImp.convertAnnotation(writer, annot, rect);
462                     annotationsImp.addPlainAnnotation(an);
463                     pageEmpty = false;
464                     break;
465                 }
466                 case Element.PHRASE: {
467                     // we cast the element to a phrase and set the leading of the document
468
leading = ((Phrase) element).getLeading();
469                     // we process the element
470
element.process(this);
471                     break;
472                 }
473                 case Element.PARAGRAPH: {
474                     // we cast the element to a paragraph
475
Paragraph paragraph = (Paragraph) element;
476                     
477                     addSpacing(paragraph.spacingBefore(), leading, paragraph.getFont());
478                     
479                     // we adjust the parameters of the document
480
alignment = paragraph.getAlignment();
481                     leading = paragraph.getTotalLeading();
482                     carriageReturn();
483                     
484                     // we don't want to make orphans/widows
485
if (currentHeight + line.height() + leading > indentTop() - indentBottom()) {
486                         newPage();
487                     }
488
489                     indentation.indentLeft += paragraph.getIndentationLeft();
490                     indentation.indentRight += paragraph.getIndentationRight();
491                     carriageReturn();
492      
493                     PdfPageEvent pageEvent = writer.getPageEvent();
494                     if (pageEvent != null && isParagraph)
495                         pageEvent.onParagraph(writer, this, indentTop() - currentHeight);
496                     
497                     // if a paragraph has to be kept together, we wrap it in a table object
498
if (paragraph.getKeepTogether()) {
499                         PdfPTable table = new PdfPTable(1);
500                         table.setWidthPercentage(100f);
501                         PdfPCell cell = new PdfPCell();
502                         cell.addElement(paragraph);
503                         cell.setBorder(Table.NO_BORDER);
504                         table.addCell(cell);
505                         this.add(table);
506                     }
507                     else {
508                         indentation.paragraph += paragraph.getIndentationLeft();
509                         line.setExtraIndent(paragraph.getFirstLineIndent());
510                         element.process(this);
511                         indentation.paragraph -= paragraph.getIndentationLeft();
512                     }
513                     
514                     addSpacing(paragraph.spacingAfter(), paragraph.getTotalLeading(), paragraph.getFont());
515
516                     if (pageEvent != null && isParagraph)
517                         pageEvent.onParagraphEnd(writer, this, indentTop() - currentHeight);
518                     
519                     alignment = Element.ALIGN_LEFT;
520                     indentation.indentLeft -= paragraph.getIndentationLeft();
521                     indentation.indentRight -= paragraph.getIndentationRight();
522                     carriageReturn();
523                     break;
524                 }
525                 case Element.SECTION:
526                 case Element.CHAPTER: {
527                     // Chapters and Sections only differ in their constructor
528
// so we cast both to a Section
529
Section section = (Section) element;
530                     
531                     boolean hasTitle = section.getTitle() != null;
532                     
533                     // if the section is a chapter, we begin a new page
534
if (section.isTriggerNewPage()) {
535                         newPage();
536                     }
537                     // otherwise, we begin a new line
538
else {
539                         newLine();
540                     }
541
542                     if (hasTitle) {
543                     float fith = indentTop() - currentHeight;
544                     int rotation = pageSize.getRotation();
545                     if (rotation == 90 || rotation == 180)
546                         fith = pageSize.getHeight() - fith;
547                         PdfDestination destination = new PdfDestination(PdfDestination.FITH, fith);
548                         while (currentOutline.level() >= section.getDepth()) {
549                             currentOutline = currentOutline.parent();
550                         }
551                         PdfOutline outline = new PdfOutline(currentOutline, destination, section.getBookmarkTitle(), section.isBookmarkOpen());
552                         currentOutline = outline;
553                     }
554                     
555                     // some values are set
556
carriageReturn();
557                     indentation.indentLeft += section.getIndentationLeft();
558                     indentation.indentRight += section.getIndentationRight();
559                     indentation.sectionIndentLeft += section.getIndentationLeft();
560                     indentation.sectionIndentRight += section.getIndentationRight();
561                     
562                     PdfPageEvent pageEvent = writer.getPageEvent();
563                     if (pageEvent != null)
564                         if (element.type() == Element.CHAPTER)
565                             pageEvent.onChapter(writer, this, indentTop() - currentHeight, section.getTitle());
566                         else
567                             pageEvent.onSection(writer, this, indentTop() - currentHeight, section.getDepth(), section.getTitle());
568                     
569                     // the title of the section (if any has to be printed)
570
if (hasTitle) {
571                         isParagraph = false;
572                         add(section.getTitle());
573                         isParagraph = true;
574                     }
575                     indentation.indentLeft += section.getIndentation();
576                     indentation.sectionIndentLeft += section.getIndentation();
577                     // we process the section
578
element.process(this);
579                     // some parameters are set back to normal again
580
indentation.indentLeft -= section.getIndentationLeft() + section.getIndentation();
581                     indentation.indentRight -= section.getIndentationRight();
582                     indentation.sectionIndentLeft -= section.getIndentationLeft() + section.getIndentation();
583                     indentation.sectionIndentRight -= section.getIndentationRight();
584                     
585                     if (pageEvent != null)
586                         if (element.type() == Element.CHAPTER)
587                             pageEvent.onChapterEnd(writer, this, indentTop() - currentHeight);
588                         else
589                             pageEvent.onSectionEnd(writer, this, indentTop() - currentHeight);
590                     
591                     break;
592                 }
593                 case Element.LIST: {
594                     // we cast the element to a List
595
List JavaDoc list = (List JavaDoc) element;
596                     if (list.isAlignindent()) {
597                         list.normalizeIndentation();
598                     }
599                     // we adjust the document
600
indentation.listIndentLeft += list.getIndentationLeft();
601                     indentation.indentRight += list.getIndentationRight();
602                     // we process the items in the list
603
element.process(this);
604                     // some parameters are set back to normal again
605
indentation.listIndentLeft -= list.getIndentationLeft();
606                     indentation.indentRight -= list.getIndentationRight();
607                     break;
608                 }
609                 case Element.LISTITEM: {
610                     // we cast the element to a ListItem
611
ListItem listItem = (ListItem) element;
612                     
613                     addSpacing(listItem.spacingBefore(), leading, listItem.getFont());
614                    
615                     // we adjust the document
616
alignment = listItem.getAlignment();
617                     indentation.listIndentLeft += listItem.getIndentationLeft();
618                     indentation.indentRight += listItem.getIndentationRight();
619                     leading = listItem.getTotalLeading();
620                     carriageReturn();
621                     
622                     // we prepare the current line to be able to show us the listsymbol
623
line.setListItem(listItem);
624                     // we process the item
625
element.process(this);
626
627                     addSpacing(listItem.spacingAfter(), listItem.getTotalLeading(), listItem.getFont());
628                    
629                     // if the last line is justified, it should be aligned to the left
630
if (line.hasToBeJustified()) {
631                         line.resetAlignment();
632                     }
633                     // some parameters are set back to normal again
634
carriageReturn();
635                     indentation.listIndentLeft -= listItem.getIndentationLeft();
636                     indentation.indentRight -= listItem.getIndentationRight();
637                     break;
638                 }
639                 case Element.RECTANGLE: {
640                     Rectangle rectangle = (Rectangle) element;
641                     graphics.rectangle(rectangle);
642                     pageEmpty = false;
643                     break;
644                 }
645                 case Element.PTABLE: {
646                     PdfPTable ptable = (PdfPTable)element;
647                     if (ptable.size() <= ptable.getHeaderRows())
648                         break; //nothing to do
649

650                     // before every table, we add a new line and flush all lines
651

652                     indentation.indentLeft -= indentation.paragraph + indentation.sectionIndentLeft;
653                     indentation.indentRight -= indentation.sectionIndentRight;
654                     ensureNewLine();
655                     flushLines();
656                     indentation.indentLeft += indentation.paragraph + indentation.sectionIndentLeft;
657                     indentation.indentRight += indentation.sectionIndentRight;
658                     
659                     addPTable(ptable);
660                     pageEmpty = false;
661                     newLine();
662                     break;
663                 }
664                 case Element.MULTI_COLUMN_TEXT: {
665                     ensureNewLine();
666                     flushLines();
667                     MultiColumnText multiText = (MultiColumnText) element;
668                     float height = multiText.write(writer.getDirectContent(), this, indentTop() - currentHeight);
669                     currentHeight += height;
670                     text.moveText(0, -1f* height);
671                     pageEmpty = false;
672                     break;
673                 }
674                 case Element.TABLE : {
675                     PdfTable table;
676                     if (element instanceof PdfTable) {
677                         // Already pre-rendered
678
table = (PdfTable)element;
679                         table.updateRowAdditions();
680                     } else if (element instanceof SimpleTable) {
681                         PdfPTable ptable = ((SimpleTable)element).createPdfPTable();
682                         if (ptable.size() <= ptable.getHeaderRows())
683                             break; //nothing to do
684

685                         // before every table, we add a new line and flush all lines
686
ensureNewLine();
687                         flushLines();
688                         addPTable(ptable);
689                         pageEmpty = false;
690                         break;
691                     } else if (element instanceof Table) {
692                         try {
693                             PdfPTable ptable = ((Table)element).createPdfPTable();
694                             if (ptable.size() <= ptable.getHeaderRows())
695                                 break; //nothing to do
696

697                             // before every table, we add a new line and flush all lines
698
ensureNewLine();
699                             flushLines();
700                             addPTable(ptable);
701                             pageEmpty = false;
702                             break;
703                         }
704                         catch(BadElementException bee) {
705                             // constructing the PdfTable
706
// Before the table, add a blank line using offset or default leading
707
float offset = ((Table)element).getOffset();
708                             if (Float.isNaN(offset))
709                                 offset = leading;
710                             carriageReturn();
711                             lines.add(new PdfLine(indentLeft(), indentRight(), alignment, offset));
712                             currentHeight += offset;
713                             table = getPdfTable((Table)element, false);
714                         }
715                     } else {
716                         return false;
717                     }
718                     add(table, false);
719                     break;
720                 }
721                 case Element.JPEG:
722                 case Element.IMGRAW:
723                 case Element.IMGTEMPLATE: {
724                     //carriageReturn(); suggestion by Marc Campforts
725
add((Image) element);
726                     break;
727                 }
728                 case Element.MARKED: {
729                     MarkedObject mo;
730                     if (element instanceof MarkedSection) {
731                         mo = ((MarkedSection)element).title();
732                         if (mo != null) {
733                             mo.process(this);
734                         }
735                     }
736                     mo = (MarkedObject)element;
737                     mo.process(this);
738                     break;
739                 }
740                 default:
741                     return false;
742             }
743             lastElementType = element.type();
744             return true;
745         }
746         catch(Exception JavaDoc e) {
747             throw new DocumentException(e);
748         }
749     }
750
751 // [L1] DocListener interface
752

753     /**
754      * Opens the document.
755      * <P>
756      * You have to open the document before you can begin to add content
757      * to the body of the document.
758      */

759     public void open() {
760         if (!open) {
761             super.open();
762             writer.open();
763             rootOutline = new PdfOutline(writer);
764             currentOutline = rootOutline;
765         }
766         try {
767             initPage();
768         }
769         catch(DocumentException de) {
770             throw new ExceptionConverter(de);
771         }
772     }
773
774 // [L2] DocListener interface
775

776     /**
777      * Closes the document.
778      * <B>
779      * Once all the content has been written in the body, you have to close
780      * the body. After that nothing can be written to the body anymore.
781      */

782     public void close() {
783         if (close) {
784             return;
785         }
786         try {
787             boolean wasImage = (imageWait != null);
788             newPage();
789             if (imageWait != null || wasImage) newPage();
790             if (annotationsImp.hasUnusedAnnotations())
791                 throw new RuntimeException JavaDoc("Not all annotations could be added to the document (the document doesn't have enough pages).");
792             PdfPageEvent pageEvent = writer.getPageEvent();
793             if (pageEvent != null)
794                 pageEvent.onCloseDocument(writer, this);
795             super.close();
796             
797             writer.addLocalDestinations(localDestinations);
798             calculateOutlineCount();
799             writeOutlines();
800         }
801         catch(Exception JavaDoc e) {
802             throw new ExceptionConverter(e);
803         }
804         
805         writer.close();
806     }
807
808 // [L3] DocListener interface
809

810     private boolean isNewpage = false;
811     private int textEmptySize;
812     
813     /**
814      * Makes a new page and sends it to the <CODE>PdfWriter</CODE>.
815      *
816      * @return a <CODE>boolean</CODE>
817      * @throws DocumentException on error
818      */

819     public boolean newPage() {
820         lastElementType = -1;
821         isNewpage = true;
822         if (writer == null || (writer.getDirectContent().size() == 0 && writer.getDirectContentUnder().size() == 0 && (pageEmpty || writer.isPaused()))) {
823             return false;
824         }
825         if (!open || close) {
826             throw new RuntimeException JavaDoc("The document isn't open.");
827         }
828         PdfPageEvent pageEvent = writer.getPageEvent();
829         if (pageEvent != null)
830             pageEvent.onEndPage(writer, this);
831         
832         //Added to inform any listeners that we are moving to a new page (added by David Freels)
833
super.newPage();
834         
835         // the following 2 lines were added by Pelikan Stephan
836
indentation.imageIndentLeft = 0;
837         indentation.imageIndentRight = 0;
838         
839         try {
840             // we flush the arraylist with recently written lines
841
flushLines();
842             
843             // we prepare the elements of the page dictionary
844

845             // [U1] page size and rotation
846
int rotation = pageSize.getRotation();
847             
848             // [C10]
849
if (writer.isPdfX()) {
850                 if (thisBoxSize.containsKey("art") && thisBoxSize.containsKey("trim"))
851                     throw new PdfXConformanceException("Only one of ArtBox or TrimBox can exist in the page.");
852                 if (!thisBoxSize.containsKey("art") && !thisBoxSize.containsKey("trim")) {
853                     if (thisBoxSize.containsKey("crop"))
854                         thisBoxSize.put("trim", thisBoxSize.get("crop"));
855                     else
856                         thisBoxSize.put("trim", new PdfRectangle(pageSize, pageSize.getRotation()));
857                 }
858             }
859             
860             // [M1]
861
pageResources.addDefaultColorDiff(writer.getDefaultColorspace());
862             PdfDictionary resources = pageResources.getResources();
863             
864             // we create the page dictionary
865

866             PdfPage page = new PdfPage(new PdfRectangle(pageSize, rotation), thisBoxSize, resources, rotation);
867
868             // we complete the page dictionary
869

870             // [U3] page actions: transition, duration, additional actions
871
if (this.transition!=null) {
872                 page.put(PdfName.TRANS, this.transition.getTransitionDictionary());
873                 transition = null;
874             }
875             if (this.duration>0) {
876                 page.put(PdfName.DUR,new PdfNumber(this.duration));
877                 duration = 0;
878             }
879             if (pageAA != null) {
880                 page.put(PdfName.AA, writer.addToBody(pageAA).getIndirectReference());
881                 pageAA = null;
882             }
883             
884             // [U4] we add the thumbs
885
if (thumb != null) {
886                 page.put(PdfName.THUMB, thumb);
887                 thumb = null;
888             }
889             
890             // [U8] we check if the userunit is defined
891
if (writer.getUserunit() > 0f) {
892                 page.put(PdfName.USERUNIT, new PdfNumber(writer.getUserunit()));
893             }
894             
895             // [C5] and [C8] we add the annotations
896
if (annotationsImp.hasUnusedAnnotations()) {
897                 PdfArray array = annotationsImp.rotateAnnotations(writer, pageSize);
898                 if (array.size() != 0)
899                     page.put(PdfName.ANNOTS, array);
900             }
901             
902             // [F12] we add tag info
903
if (writer.isTagged())
904                  page.put(PdfName.STRUCTPARENTS, new PdfNumber(writer.getCurrentPageNumber() - 1));
905             
906             if (text.size() > textEmptySize)
907                 text.endText();
908             else
909                 text = null;
910             writer.add(page, new PdfContents(writer.getDirectContentUnder(), graphics, text, writer.getDirectContent(), pageSize));
911             // we initialize the new page
912
initPage();
913         }
914         catch(DocumentException de) {
915             // maybe this never happens, but it's better to check.
916
throw new ExceptionConverter(de);
917         }
918         catch (IOException JavaDoc ioe) {
919             throw new ExceptionConverter(ioe);
920         }
921         isNewpage = false;
922         return true;
923     }
924
925 // [L4] DocListener interface
926

927     /**
928      * Sets the pagesize.
929      *
930      * @param pageSize the new pagesize
931      * @return <CODE>true</CODE> if the page size was set
932      */

933     public boolean setPageSize(Rectangle pageSize) {
934         if (writer != null && writer.isPaused()) {
935             return false;
936         }
937         nextPageSize = new Rectangle(pageSize);
938         return true;
939     }
940
941 // [L5] DocListener interface
942

943     /** margin in x direction starting from the left. Will be valid in the next page */
944     protected float nextMarginLeft;
945     
946     /** margin in x direction starting from the right. Will be valid in the next page */
947     protected float nextMarginRight;
948     
949     /** margin in y direction starting from the top. Will be valid in the next page */
950     protected float nextMarginTop;
951     
952     /** margin in y direction starting from the bottom. Will be valid in the next page */
953     protected float nextMarginBottom;
954     
955     /**
956      * Sets the margins.
957      *
958      * @param marginLeft the margin on the left
959      * @param marginRight the margin on the right
960      * @param marginTop the margin on the top
961      * @param marginBottom the margin on the bottom
962      * @return a <CODE>boolean</CODE>
963      */

964     public boolean setMargins(float marginLeft, float marginRight, float marginTop, float marginBottom) {
965         if (writer != null && writer.isPaused()) {
966             return false;
967         }
968         nextMarginLeft = marginLeft;
969         nextMarginRight = marginRight;
970         nextMarginTop = marginTop;
971         nextMarginBottom = marginBottom;
972         return true;
973     }
974
975 // [L6] DocListener interface
976

977     /**
978      * @see com.lowagie.text.DocListener#setMarginMirroring(boolean)
979      */

980     public boolean setMarginMirroring(boolean MarginMirroring) {
981         if (writer != null && writer.isPaused()) {
982             return false;
983         }
984         return super.setMarginMirroring(MarginMirroring);
985     }
986
987 // [L7] DocListener interface
988

989     /**
990      * Sets the page number.
991      *
992      * @param pageN the new page number
993      */

994     public void setPageCount(int pageN) {
995         if (writer != null && writer.isPaused()) {
996             return;
997         }
998         super.setPageCount(pageN);
999     }
1000
1001// [L8] DocListener interface
1002

1003    /**
1004     * Sets the page number to 0.
1005     */

1006    public void resetPageCount() {
1007        if (writer != null && writer.isPaused()) {
1008            return;
1009        }
1010        super.resetPageCount();
1011    }
1012
1013// [L9] DocListener interface
1014

1015    /**
1016     * Changes the header of this document.
1017     *
1018     * @param header the new header
1019     */

1020    public void setHeader(HeaderFooter header) {
1021        if (writer != null && writer.isPaused()) {
1022            return;
1023        }
1024        super.setHeader(header);
1025    }
1026
1027// [L10] DocListener interface
1028

1029    /**
1030     * Resets the header of this document.
1031     */

1032    public void resetHeader() {
1033        if (writer != null && writer.isPaused()) {
1034            return;
1035        }
1036        super.resetHeader();
1037    }
1038
1039// [L11] DocListener interface
1040

1041    /**
1042     * Changes the footer of this document.
1043     *
1044     * @param footer the new footer
1045     */

1046    public void setFooter(HeaderFooter footer) {
1047        if (writer != null && writer.isPaused()) {
1048            return;
1049        }
1050        super.setFooter(footer);
1051    }
1052
1053// [L12] DocListener interface
1054

1055    /**
1056     * Resets the footer of this document.
1057     */

1058    public void resetFooter() {
1059        if (writer != null && writer.isPaused()) {
1060            return;
1061        }
1062        super.resetFooter();
1063    }
1064    
1065// DOCLISTENER METHODS END
1066

1067    /** Signals that OnOpenDocument should be called. */
1068    private boolean firstPageEvent = true;
1069    
1070    /**
1071     * Initializes a page.
1072     * <P>
1073     * If the footer/header is set, it is printed.
1074     * @throws DocumentException on error
1075     */

1076    private void initPage() throws DocumentException {
1077        // the pagenumber is incremented
1078
pageN++;
1079
1080        // initialisation of some page objects
1081
annotationsImp.resetAnnotations();
1082        pageResources = new PageResources();
1083        
1084        writer.resetContent();
1085        graphics = new PdfContentByte(writer);
1086        text = new PdfContentByte(writer);
1087        text.reset();
1088        text.beginText();
1089        textEmptySize = text.size();
1090
1091        markPoint = 0;
1092        if (marginMirroring && (getPageNumber() & 1) == 0) {
1093            marginRight = nextMarginLeft;
1094            marginLeft = nextMarginRight;
1095        }
1096        else {
1097            marginLeft = nextMarginLeft;
1098            marginRight = nextMarginRight;
1099        }
1100        marginTop = nextMarginTop;
1101        marginBottom = nextMarginBottom;
1102        imageEnd = -1;
1103        indentation.imageIndentRight = 0;
1104        indentation.imageIndentLeft = 0;
1105        indentation.indentBottom = 0;
1106        indentation.indentTop = 0;
1107        currentHeight = 0;
1108        
1109        // backgroundcolors, etc...
1110
pageSize = nextPageSize;
1111        thisBoxSize = new HashMap JavaDoc(boxSize);
1112        if (pageSize.getBackgroundColor() != null
1113        || pageSize.hasBorders()
1114        || pageSize.getBorderColor() != null) {
1115            add(pageSize);
1116        }
1117
1118        float oldleading = leading;
1119        int oldAlignment = alignment;
1120        // if there is a footer, the footer is added
1121
doFooter();
1122        // we move to the left/top position of the page
1123
text.moveText(left(), top());
1124        doHeader();
1125        pageEmpty = true;
1126        // if there is an image waiting to be drawn, draw it
1127
try {
1128            if (imageWait != null) {
1129                add(imageWait);
1130                imageWait = null;
1131            }
1132        }
1133        catch(Exception JavaDoc e) {
1134            throw new ExceptionConverter(e);
1135        }
1136        leading = oldleading;
1137        alignment = oldAlignment;
1138        carriageReturn();
1139        
1140        PdfPageEvent pageEvent = writer.getPageEvent();
1141        if (pageEvent != null) {
1142            if (firstPageEvent) {
1143                pageEvent.onOpenDocument(writer, this);
1144            }
1145            pageEvent.onStartPage(writer, this);
1146        }
1147        firstPageEvent = false;
1148    }
1149
1150    /** The line that is currently being written. */
1151    private PdfLine line = null;
1152    /** The lines that are written until now. */
1153    private ArrayList JavaDoc lines = new ArrayList JavaDoc();
1154    
1155    /**
1156     * Adds the current line to the list of lines and also adds an empty line.
1157     * @throws DocumentException on error
1158     */

1159    private void newLine() throws DocumentException {
1160        lastElementType = -1;
1161        carriageReturn();
1162        if (lines != null && !lines.isEmpty()) {
1163            lines.add(line);
1164            currentHeight += line.height();
1165        }
1166        line = new PdfLine(indentLeft(), indentRight(), alignment, leading);
1167    }
1168    
1169    /**
1170     * If the current line is not empty or null, it is added to the arraylist
1171     * of lines and a new empty line is added.
1172     * @throws DocumentException on error
1173     */

1174    private void carriageReturn() {
1175        // the arraylist with lines may not be null
1176
if (lines == null) {
1177            lines = new ArrayList JavaDoc();
1178        }
1179        // If the current line is not null
1180
if (line != null) {
1181            // we check if the end of the page is reached (bugfix by Francois Gravel)
1182
if (currentHeight + line.height() + leading < indentTop() - indentBottom()) {
1183                // if so nonempty lines are added and the heigt is augmented
1184
if (line.size() > 0) {
1185                    currentHeight += line.height();
1186                    lines.add(line);
1187                    pageEmpty = false;
1188                }
1189            }
1190            // if the end of the line is reached, we start a new page
1191
else {
1192                newPage();
1193            }
1194        }
1195        if (imageEnd > -1 && currentHeight > imageEnd) {
1196            imageEnd = -1;
1197            indentation.imageIndentRight = 0;
1198            indentation.imageIndentLeft = 0;
1199        }
1200        // a new current line is constructed
1201
line = new PdfLine(indentLeft(), indentRight(), alignment, leading);
1202    }
1203    
1204    /**
1205     * Gets the current vertical page position.
1206     * @param ensureNewLine Tells whether a new line shall be enforced. This may cause side effects
1207     * for elements that do not terminate the lines they've started because those lines will get
1208     * terminated.
1209     * @return The current vertical page position.
1210     */

1211    public float getVerticalPosition(boolean ensureNewLine) {
1212        // ensuring that a new line has been started.
1213
if (ensureNewLine) {
1214          ensureNewLine();
1215        }
1216        return top() - currentHeight - indentation.indentTop;
1217    }
1218
1219    /** Holds the type of the last element, that has been added to the document. */
1220    private int lastElementType = -1;
1221    
1222    /**
1223     * Ensures that a new line has been started.
1224     */

1225    private void ensureNewLine() {
1226      try {
1227        if ((lastElementType == Element.PHRASE) ||
1228            (lastElementType == Element.CHUNK)) {
1229          newLine();
1230          flushLines();
1231        }
1232      } catch (DocumentException ex) {
1233        throw new ExceptionConverter(ex);
1234        }
1235    }
1236    
1237    /**
1238     * Writes all the lines to the text-object.
1239     *
1240     * @return the displacement that was caused
1241     * @throws DocumentException on error
1242     */

1243    private float flushLines() throws DocumentException {
1244        // checks if the ArrayList with the lines is not null
1245
if (lines == null) {
1246            return 0;
1247        }
1248        boolean newline=false;
1249        // checks if a new Line has to be made.
1250
if (line != null && line.size() > 0) {
1251            lines.add(line);
1252            line = new PdfLine(indentLeft(), indentRight(), alignment, leading);
1253            newline=true;
1254        }
1255        
1256        // checks if the ArrayList with the lines is empty
1257
if (lines.isEmpty()) {
1258            return 0;
1259        }
1260        
1261        // initialisation of some parameters
1262
Object JavaDoc currentValues[] = new Object JavaDoc[2];
1263        PdfFont currentFont = null;
1264        float displacement = 0;
1265        PdfLine l;
1266        Float JavaDoc lastBaseFactor = new Float JavaDoc(0);
1267        currentValues[1] = lastBaseFactor;
1268        // looping over all the lines
1269
for (Iterator JavaDoc i = lines.iterator(); i.hasNext(); ) {
1270                        
1271            // this is a line in the loop
1272
l = (PdfLine) i.next();
1273            
1274            if(isNewpage && newline) { // fix Ken@PDI
1275
newline=false;
1276                text.moveText(l.indentLeft() - indentLeft() + indentation.listIndentLeft + indentation.paragraph,-l.height());
1277            }
1278            else {
1279                text.moveText(l.indentLeft() - indentLeft() + indentation.listIndentLeft, -l.height());
1280            }
1281            
1282            // is the line preceeded by a symbol?
1283
if (l.listSymbol() != null) {
1284                ColumnText.showTextAligned(graphics, Element.ALIGN_LEFT, new Phrase(l.listSymbol()), text.getXTLM() - l.listIndent(), text.getYTLM(), 0);
1285            }
1286            
1287            currentValues[0] = currentFont;
1288            
1289            writeLineToContent(l, text, graphics, currentValues, writer.getSpaceCharRatio());
1290            
1291            currentFont = (PdfFont)currentValues[0];
1292            
1293            displacement += l.height();
1294            if (indentLeft() - indentation.listIndentLeft != l.indentLeft()) {
1295                text.moveText(indentLeft() - l.indentLeft() - indentation.listIndentLeft, 0);
1296            }
1297            
1298        }
1299        lines = new ArrayList JavaDoc();
1300        return displacement;
1301    }
1302    
1303    /** The characters to be applied the hanging punctuation. */
1304    static final String JavaDoc hangingPunctuation = ".,;:'";
1305    
1306    /**
1307     * Writes a text line to the document. It takes care of all the attributes.
1308     * <P>
1309     * Before entering the line position must have been established and the
1310     * <CODE>text</CODE> argument must be in text object scope (<CODE>beginText()</CODE>).
1311     * @param line the line to be written
1312     * @param text the <CODE>PdfContentByte</CODE> where the text will be written to
1313     * @param graphics the <CODE>PdfContentByte</CODE> where the graphics will be written to
1314     * @param currentValues the current font and extra spacing values
1315     * @param ratio
1316     * @throws DocumentException on error
1317     */

1318    void writeLineToContent(PdfLine line, PdfContentByte text, PdfContentByte graphics, Object JavaDoc currentValues[], float ratio) throws DocumentException {
1319        PdfFont currentFont = (PdfFont)(currentValues[0]);
1320        float lastBaseFactor = ((Float JavaDoc)(currentValues[1])).floatValue();
1321        PdfChunk chunk;
1322        int numberOfSpaces;
1323        int lineLen;
1324        boolean isJustified;
1325        float hangingCorrection = 0;
1326        float hScale = 1;
1327        float lastHScale = Float.NaN;
1328        float baseWordSpacing = 0;
1329        float baseCharacterSpacing = 0;
1330        
1331        numberOfSpaces = line.numberOfSpaces();
1332        lineLen = line.toString().length();
1333        // does the line need to be justified?
1334
isJustified = line.hasToBeJustified() && (numberOfSpaces != 0 || lineLen > 1);
1335        if (isJustified) {
1336            if (line.isNewlineSplit() && line.widthLeft() >= (lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1))) {
1337                if (line.isRTL()) {
1338                    text.moveText(line.widthLeft() - lastBaseFactor * (ratio * numberOfSpaces + lineLen - 1), 0);
1339                }
1340                baseWordSpacing = ratio * lastBaseFactor;
1341                baseCharacterSpacing = lastBaseFactor;
1342            }
1343            else {
1344                float width = line.widthLeft();
1345                PdfChunk last = line.getChunk(line.size() - 1);
1346                if (last != null) {
1347                    String JavaDoc s = last.toString();
1348                    char c;
1349                    if (s.length() > 0 && hangingPunctuation.indexOf((c = s.charAt(s.length() - 1))) >= 0) {
1350                        float oldWidth = width;
1351                        width += last.font().width(c) * 0.4f;
1352                        hangingCorrection = width - oldWidth;
1353                    }
1354                }
1355                float baseFactor = width / (ratio * numberOfSpaces + lineLen - 1);
1356                baseWordSpacing = ratio * baseFactor;
1357                baseCharacterSpacing = baseFactor;
1358                lastBaseFactor = baseFactor;
1359            }
1360        }
1361        
1362        int lastChunkStroke = line.getLastStrokeChunk();
1363        int chunkStrokeIdx = 0;
1364        float xMarker = text.getXTLM();
1365        float baseXMarker = xMarker;
1366        float yMarker = text.getYTLM();
1367        boolean adjustMatrix = false;
1368        
1369        // looping over all the chunks in 1 line
1370
for (Iterator JavaDoc j = line.iterator(); j.hasNext(); ) {
1371            chunk = (PdfChunk) j.next();
1372            Color JavaDoc color = chunk.color();
1373            hScale = 1;
1374            
1375            if (chunkStrokeIdx <= lastChunkStroke) {
1376                float width;
1377                if (isJustified) {
1378                    width = chunk.getWidthCorrected(baseCharacterSpacing, baseWordSpacing);
1379                }
1380                else
1381                    width = chunk.width();
1382                if (chunk.isStroked()) {
1383                    PdfChunk nextChunk = line.getChunk(chunkStrokeIdx + 1);
1384                    if (chunk.isAttribute(Chunk.BACKGROUND)) {
1385                        float subtract = lastBaseFactor;
1386                        if (nextChunk != null && nextChunk.isAttribute(Chunk.BACKGROUND))
1387                            subtract = 0;
1388                        if (nextChunk == null)
1389                            subtract += hangingCorrection;
1390                        float fontSize = chunk.font().size();
1391                        float ascender = chunk.font().getFont().getFontDescriptor(BaseFont.ASCENT, fontSize);
1392                        float descender = chunk.font().getFont().getFontDescriptor(BaseFont.DESCENT, fontSize);
1393                        Object JavaDoc bgr[] = (Object JavaDoc[])chunk.getAttribute(Chunk.BACKGROUND);
1394                        graphics.setColorFill((Color JavaDoc)bgr[0]);
1395                        float extra[] = (float[])bgr[1];
1396                        graphics.rectangle(xMarker - extra[0],
1397                            yMarker + descender - extra[1] + chunk.getTextRise(),
1398                            width - subtract + extra[0] + extra[2],
1399                            ascender - descender + extra[1] + extra[3]);
1400                        graphics.fill();
1401                        graphics.setGrayFill(0);
1402                    }
1403                    if (chunk.isAttribute(Chunk.UNDERLINE)) {
1404                        float subtract = lastBaseFactor;
1405                        if (nextChunk != null && nextChunk.isAttribute(Chunk.UNDERLINE))
1406                            subtract = 0;
1407                        if (nextChunk == null)
1408                            subtract += hangingCorrection;
1409                        Object JavaDoc unders[][] = (Object JavaDoc[][])chunk.getAttribute(Chunk.UNDERLINE);
1410                        Color JavaDoc scolor = null;
1411                        for (int k = 0; k < unders.length; ++k) {
1412                            Object JavaDoc obj[] = unders[k];
1413                            scolor = (Color JavaDoc)obj[0];
1414                            float ps[] = (float[])obj[1];
1415                            if (scolor == null)
1416                                scolor = color;
1417                            if (scolor != null)
1418                                graphics.setColorStroke(scolor);
1419                            float fsize = chunk.font().size();
1420                            graphics.setLineWidth(ps[0] + fsize * ps[1]);
1421                            float shift = ps[2] + fsize * ps[3];
1422                            int cap2 = (int)ps[4];
1423                            if (cap2 != 0)
1424                                graphics.setLineCap(cap2);
1425                            graphics.moveTo(xMarker, yMarker + shift);
1426                            graphics.lineTo(xMarker + width - subtract, yMarker + shift);
1427                            graphics.stroke();
1428                            if (scolor != null)
1429                                graphics.resetGrayStroke();
1430                            if (cap2 != 0)
1431                                graphics.setLineCap(0);
1432                        }
1433                        graphics.setLineWidth(1);
1434                    }
1435                    if (chunk.isAttribute(Chunk.ACTION)) {
1436                        float subtract = lastBaseFactor;
1437                        if (nextChunk != null && nextChunk.isAttribute(Chunk.ACTION))
1438                            subtract = 0;
1439                        if (nextChunk == null)
1440                            subtract += hangingCorrection;
1441                        text.addAnnotation(new PdfAnnotation(writer, xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size(), (PdfAction)chunk.getAttribute(Chunk.ACTION)));
1442                    }
1443                    if (chunk.isAttribute(Chunk.REMOTEGOTO)) {
1444                        float subtract = lastBaseFactor;
1445                        if (nextChunk != null && nextChunk.isAttribute(Chunk.REMOTEGOTO))
1446                            subtract = 0;
1447                        if (nextChunk == null)
1448                            subtract += hangingCorrection;
1449                        Object JavaDoc obj[] = (Object JavaDoc[])chunk.getAttribute(Chunk.REMOTEGOTO);
1450                        String JavaDoc filename = (String JavaDoc)obj[0];
1451                        if (obj[1] instanceof String JavaDoc)
1452                            remoteGoto(filename, (String JavaDoc)obj[1], xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1453                        else
1454                            remoteGoto(filename, ((Integer JavaDoc)obj[1]).intValue(), xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1455                    }
1456                    if (chunk.isAttribute(Chunk.LOCALGOTO)) {
1457                        float subtract = lastBaseFactor;
1458                        if (nextChunk != null && nextChunk.isAttribute(Chunk.LOCALGOTO))
1459                            subtract = 0;
1460                        if (nextChunk == null)
1461                            subtract += hangingCorrection;
1462                        localGoto((String JavaDoc)chunk.getAttribute(Chunk.LOCALGOTO), xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1463                    }
1464                    if (chunk.isAttribute(Chunk.LOCALDESTINATION)) {
1465                        float subtract = lastBaseFactor;
1466                        if (nextChunk != null && nextChunk.isAttribute(Chunk.LOCALDESTINATION))
1467                            subtract = 0;
1468                        if (nextChunk == null)
1469                            subtract += hangingCorrection;
1470                        localDestination((String JavaDoc)chunk.getAttribute(Chunk.LOCALDESTINATION), new PdfDestination(PdfDestination.XYZ, xMarker, yMarker + chunk.font().size(), 0));
1471                    }
1472                    if (chunk.isAttribute(Chunk.GENERICTAG)) {
1473                        float subtract = lastBaseFactor;
1474                        if (nextChunk != null && nextChunk.isAttribute(Chunk.GENERICTAG))
1475                            subtract = 0;
1476                        if (nextChunk == null)
1477                            subtract += hangingCorrection;
1478                        Rectangle rect = new Rectangle(xMarker, yMarker, xMarker + width - subtract, yMarker + chunk.font().size());
1479                        PdfPageEvent pev = writer.getPageEvent();
1480                        if (pev != null)
1481                            pev.onGenericTag(writer, this, rect, (String JavaDoc)chunk.getAttribute(Chunk.GENERICTAG));
1482                    }
1483                    if (chunk.isAttribute(Chunk.PDFANNOTATION)) {
1484                        float subtract = lastBaseFactor;
1485                        if (nextChunk != null && nextChunk.isAttribute(Chunk.PDFANNOTATION))
1486                            subtract = 0;
1487                        if (nextChunk == null)
1488                            subtract += hangingCorrection;
1489                        float fontSize = chunk.font().size();
1490                        float ascender = chunk.font().getFont().getFontDescriptor(BaseFont.ASCENT, fontSize);
1491                        float descender = chunk.font().getFont().getFontDescriptor(BaseFont.DESCENT, fontSize);
1492                        PdfAnnotation annot = PdfFormField.shallowDuplicate((PdfAnnotation)chunk.getAttribute(Chunk.PDFANNOTATION));
1493                        annot.put(PdfName.RECT, new PdfRectangle(xMarker, yMarker + descender, xMarker + width - subtract, yMarker + ascender));
1494                        text.addAnnotation(annot);
1495                    }
1496                    float params[] = (float[])chunk.getAttribute(Chunk.SKEW);
1497                    Float JavaDoc hs = (Float JavaDoc)chunk.getAttribute(Chunk.HSCALE);
1498                    if (params != null || hs != null) {
1499                        float b = 0, c = 0;
1500                        if (params != null) {
1501                            b = params[0];
1502                            c = params[1];
1503                        }
1504                        if (hs != null)
1505                            hScale = hs.floatValue();
1506                        text.setTextMatrix(hScale, b, c, 1, xMarker, yMarker);
1507                    }
1508                    if (chunk.isImage()) {
1509                        Image image = chunk.getImage();
1510                        float matrix[] = image.matrix();
1511                        matrix[Image.CX] = xMarker + chunk.getImageOffsetX() - matrix[Image.CX];
1512                        matrix[Image.CY] = yMarker + chunk.getImageOffsetY() - matrix[Image.CY];
1513                        graphics.addImage(image, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
1514                        text.moveText(xMarker + lastBaseFactor + image.getScaledWidth() - text.getXTLM(), 0);
1515                    }
1516                }
1517                xMarker += width;
1518                ++chunkStrokeIdx;
1519            }
1520
1521            if (chunk.font().compareTo(currentFont) != 0) {
1522                currentFont = chunk.font();
1523                text.setFontAndSize(currentFont.getFont(), currentFont.size());
1524            }
1525            float rise = 0;
1526            Object JavaDoc textRender[] = (Object JavaDoc[])chunk.getAttribute(Chunk.TEXTRENDERMODE);
1527            int tr = 0;
1528            float strokeWidth = 1;
1529            Color JavaDoc strokeColor = null;
1530            Float JavaDoc fr = (Float JavaDoc)chunk.getAttribute(Chunk.SUBSUPSCRIPT);
1531            if (textRender != null) {
1532                tr = ((Integer JavaDoc)textRender[0]).intValue() & 3;
1533                if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL)
1534                    text.setTextRenderingMode(tr);
1535                if (tr == PdfContentByte.TEXT_RENDER_MODE_STROKE || tr == PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE) {
1536                    strokeWidth = ((Float JavaDoc)textRender[1]).floatValue();
1537                    if (strokeWidth != 1)
1538                        text.setLineWidth(strokeWidth);
1539                    strokeColor = (Color JavaDoc)textRender[2];
1540                    if (strokeColor == null)
1541                        strokeColor = color;
1542                    if (strokeColor != null)
1543                        text.setColorStroke(strokeColor);
1544                }
1545            }
1546            if (fr != null)
1547                rise = fr.floatValue();
1548            if (color != null)
1549                text.setColorFill(color);
1550            if (rise != 0)
1551                text.setTextRise(rise);
1552            if (chunk.isImage()) {
1553                adjustMatrix = true;
1554            }
1555            // If it is a CJK chunk or Unicode TTF we will have to simulate the
1556
// space adjustment.
1557
else if (isJustified && numberOfSpaces > 0 && chunk.isSpecialEncoding()) {
1558                if (hScale != lastHScale) {
1559                    lastHScale = hScale;
1560                    text.setWordSpacing(baseWordSpacing / hScale);
1561                    text.setCharacterSpacing(baseCharacterSpacing / hScale);
1562                }
1563                String JavaDoc s = chunk.toString();
1564                int idx = s.indexOf(' ');
1565                if (idx < 0)
1566                    text.showText(chunk.toString());
1567                else {
1568                    float spaceCorrection = - baseWordSpacing * 1000f / chunk.font.size() / hScale;
1569                    PdfTextArray textArray = new PdfTextArray(s.substring(0, idx));
1570                    int lastIdx = idx;
1571                    while ((idx = s.indexOf(' ', lastIdx + 1)) >= 0) {
1572                        textArray.add(spaceCorrection);
1573                        textArray.add(s.substring(lastIdx, idx));
1574                        lastIdx = idx;
1575                    }
1576                    textArray.add(spaceCorrection);
1577                    textArray.add(s.substring(lastIdx));
1578                    text.showText(textArray);
1579                }
1580            }
1581            else {
1582                if (isJustified && hScale != lastHScale) {
1583                    lastHScale = hScale;
1584                    text.setWordSpacing(baseWordSpacing / hScale);
1585                    text.setCharacterSpacing(baseCharacterSpacing / hScale);
1586                }
1587                text.showText(chunk.toString());
1588            }
1589            
1590            if (rise != 0)
1591                text.setTextRise(0);
1592            if (color != null)
1593                text.resetRGBColorFill();
1594            if (tr != PdfContentByte.TEXT_RENDER_MODE_FILL)
1595                text.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL);
1596            if (strokeColor != null)
1597                text.resetRGBColorStroke();
1598            if (strokeWidth != 1)
1599                text.setLineWidth(1);
1600            if (chunk.isAttribute(Chunk.SKEW) || chunk.isAttribute(Chunk.HSCALE)) {
1601                adjustMatrix = true;
1602                text.setTextMatrix(xMarker, yMarker);
1603            }
1604        }
1605        if (isJustified) {
1606            text.setWordSpacing(0);
1607            text.setCharacterSpacing(0);
1608            if (line.isNewlineSplit())
1609                lastBaseFactor = 0;
1610        }
1611        if (adjustMatrix)
1612            text.moveText(baseXMarker - text.getXTLM(), 0);
1613        currentValues[0] = currentFont;
1614        currentValues[1] = new Float JavaDoc(lastBaseFactor);
1615    }
1616
1617    Indentation indentation = new Indentation();
1618    public static class Indentation {
1619        /** Indentation to the left caused by a paragraph. */
1620        float paragraph = 0;
1621        
1622        /** This represents the current indentation of the PDF Elements on the left side. */
1623        private float indentLeft = 0;
1624        
1625        /** Indentation to the left caused by a section. */
1626        private float sectionIndentLeft = 0;
1627        
1628        /** This represents the current indentation of the PDF Elements on the left side. */
1629        private float listIndentLeft = 0;
1630        
1631        /** This is the indentation caused by an image on the left. */
1632        private float imageIndentLeft = 0;
1633        
1634        /** This represents the current indentation of the PDF Elements on the right side. */
1635        private float indentRight = 0;
1636        
1637        /** Indentation to the right caused by a section. */
1638        private float sectionIndentRight = 0;
1639        
1640        /** This is the indentation caused by an image on the right. */
1641        private float imageIndentRight = 0;
1642        
1643        /** This represents the current indentation of the PDF Elements on the top side. */
1644        private float indentTop = 0;
1645        
1646        /** This represents the current indentation of the PDF Elements on the bottom side. */
1647        private float indentBottom = 0;
1648    }
1649    
1650    /**
1651     * Gets the indentation on the left side.
1652     *
1653     * @return a margin
1654     */

1655    
1656    private float indentLeft() {
1657        return left(indentation.indentLeft + indentation.listIndentLeft + indentation.imageIndentLeft);
1658    }
1659    
1660    /**
1661     * Gets the indentation on the right side.
1662     *
1663     * @return a margin
1664     */

1665    
1666    private float indentRight() {
1667        return right(indentation.indentRight + indentation.imageIndentRight);
1668    }
1669    
1670    /**
1671     * Gets the indentation on the top side.
1672     *
1673     * @return a margin
1674     */

1675    
1676    private float indentTop() {
1677        return top(indentation.indentTop);
1678    }
1679    
1680    /**
1681     * Gets the indentation on the bottom side.
1682     *
1683     * @return a margin
1684     */

1685    
1686    float indentBottom() {
1687        return bottom(indentation.indentBottom);
1688    }
1689    
1690    /**
1691     * Adds extra space.
1692     * This method should probably be rewritten.
1693     */

1694    private void addSpacing(float extraspace, float oldleading, Font f) {
1695        if (extraspace == 0) return;
1696        if (pageEmpty) return;
1697        if (currentHeight + line.height() + leading > indentTop() - indentBottom()) return;
1698        leading = extraspace;
1699        carriageReturn();
1700        Chunk space = new Chunk(" ", f);
1701        space.process(this);
1702        carriageReturn();
1703        leading = oldleading;
1704    }
1705    
1706// Info Dictionary and Catalog
1707

1708    /** some meta information about the Document. */
1709    private PdfInfo info = new PdfInfo();
1710    
1711    /**
1712     * Gets the <CODE>PdfInfo</CODE>-object.
1713     *
1714     * @return <CODE>PdfInfo</COPE>
1715     */

1716    
1717    PdfInfo getInfo() {
1718        return info;
1719    }
1720    
1721    /**
1722     * Gets the <CODE>PdfCatalog</CODE>-object.
1723     *
1724     * @param pages an indirect reference to this document pages
1725     * @return <CODE>PdfCatalog</CODE>
1726     */

1727    
1728    PdfCatalog getCatalog(PdfIndirectReference pages) {
1729        PdfCatalog catalog = new PdfCatalog(pages, writer);
1730        
1731        // [C1] outlines
1732
if (rootOutline.getKids().size() > 0) {
1733            catalog.put(PdfName.PAGEMODE, PdfName.USEOUTLINES);
1734            catalog.put(PdfName.OUTLINES, rootOutline.indirectReference());
1735        }
1736        
1737        // [C2] version
1738
writer.getPdfVersion().addToCatalog(catalog);
1739        
1740        // [C3] preferences
1741
viewerPreferences.addToCatalog(catalog);
1742        
1743        // [C4] pagelabels
1744
if (pageLabels != null) {
1745            catalog.put(PdfName.PAGELABELS, pageLabels.getDictionary());
1746        }
1747        
1748        // [C5] named objects
1749
catalog.addNames(localDestinations, documentJavaScript, documentFileAttachment, writer);
1750        
1751        // [C6] actions
1752
if (openActionName != null) {
1753            PdfAction action = getLocalGotoAction(openActionName);
1754            catalog.setOpenAction(action);
1755        }
1756        else if (openActionAction != null)
1757            catalog.setOpenAction(openActionAction);
1758        if (additionalActions != null) {
1759            catalog.setAdditionalActions(additionalActions);
1760        }
1761        
1762        // [C7] portable collections
1763
if (collection != null) {
1764            catalog.put(PdfName.COLLECTION, collection);
1765        }
1766
1767        // [C8] AcroForm
1768
if (annotationsImp.hasValidAcroForm()) {
1769            try {
1770                catalog.put(PdfName.ACROFORM, writer.addToBody(annotationsImp.getAcroForm()).getIndirectReference());
1771            }
1772            catch (IOException JavaDoc e) {
1773                throw new ExceptionConverter(e);
1774            }
1775        }
1776        
1777        return catalog;
1778    }
1779    
1780// [C1] outlines
1781

1782    /** This is the root outline of the document. */
1783    private PdfOutline rootOutline;
1784    
1785    /** This is the current <CODE>PdfOutline</CODE> in the hierarchy of outlines. */
1786    private PdfOutline currentOutline;
1787    
1788    /**
1789     * Adds a named outline to the document .
1790     * @param outline the outline to be added
1791     * @param name the name of this local destination
1792     */

1793    void addOutline(PdfOutline outline, String JavaDoc name) {
1794        localDestination(name, outline.getPdfDestination());
1795    }
1796    
1797    /**
1798     * Gets the root outline. All the outlines must be created with a parent.
1799     * The first level is created with this outline.
1800     * @return the root outline
1801     */

1802    public PdfOutline getRootOutline() {
1803        return rootOutline;
1804    }
1805
1806    
1807    /**
1808     * Updates the count in the outlines.
1809     */

1810    void calculateOutlineCount() {
1811        if (rootOutline.getKids().size() == 0)
1812            return;
1813        traverseOutlineCount(rootOutline);
1814    }
1815    
1816    /**
1817     * Recursive method to update the count in the outlines.
1818     */

1819    void traverseOutlineCount(PdfOutline outline) {
1820        ArrayList JavaDoc kids = outline.getKids();
1821        PdfOutline parent = outline.parent();
1822        if (kids.isEmpty()) {
1823            if (parent != null) {
1824                parent.setCount(parent.getCount() + 1);
1825            }
1826        }
1827        else {
1828            for (int k = 0; k < kids.size(); ++k) {
1829                traverseOutlineCount((PdfOutline)kids.get(k));
1830            }
1831            if (parent != null) {
1832                if (outline.isOpen()) {
1833                    parent.setCount(outline.getCount() + parent.getCount() + 1);
1834                }
1835                else {
1836                    parent.setCount(parent.getCount() + 1);
1837                    outline.setCount(-outline.getCount());
1838                }
1839            }
1840        }
1841    }
1842    
1843    /**
1844     * Writes the outline tree to the body of the PDF document.
1845     */

1846    void writeOutlines() throws IOException JavaDoc {
1847        if (rootOutline.getKids().size() == 0)
1848            return;
1849        outlineTree(rootOutline);
1850        writer.addToBody(rootOutline, rootOutline.indirectReference());
1851    }
1852    
1853    /**
1854     * Recursive method used to write outlines.
1855     */

1856    void outlineTree(PdfOutline outline) throws IOException JavaDoc {
1857        outline.setIndirectReference(writer.getPdfIndirectReference());
1858        if (outline.parent() != null)
1859            outline.put(PdfName.PARENT, outline.parent().indirectReference());
1860        ArrayList JavaDoc kids = outline.getKids();
1861        int size = kids.size();
1862        for (int k = 0; k < size; ++k)
1863            outlineTree((PdfOutline)kids.get(k));
1864        for (int k = 0; k < size; ++k) {
1865            if (k > 0)
1866                ((PdfOutline)kids.get(k)).put(PdfName.PREV, ((PdfOutline)kids.get(k - 1)).indirectReference());
1867            if (k < size - 1)
1868                ((PdfOutline)kids.get(k)).put(PdfName.NEXT, ((PdfOutline)kids.get(k + 1)).indirectReference());
1869        }
1870        if (size > 0) {
1871            outline.put(PdfName.FIRST, ((PdfOutline)kids.get(0)).indirectReference());
1872            outline.put(PdfName.LAST, ((PdfOutline)kids.get(size - 1)).indirectReference());
1873        }
1874        for (int k = 0; k < size; ++k) {
1875            PdfOutline kid = (PdfOutline)kids.get(k);
1876            writer.addToBody(kid, kid.indirectReference());
1877        }
1878    }
1879    
1880// [C3] PdfViewerPreferences interface
1881

1882    /** Contains the Viewer preferences of this PDF document. */
1883    protected PdfViewerPreferencesImp viewerPreferences = new PdfViewerPreferencesImp();
1884    /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#setViewerPreferences(int) */
1885    void setViewerPreferences(int preferences) {
1886        this.viewerPreferences.setViewerPreferences(preferences);
1887    }
1888
1889    /** @see com.lowagie.text.pdf.interfaces.PdfViewerPreferences#addViewerPreference(com.lowagie.text.pdf.PdfName, com.lowagie.text.pdf.PdfObject) */
1890    void addViewerPreference(PdfName key, PdfObject value) {
1891        this.viewerPreferences.addViewerPreference(key, value);
1892    }
1893 
1894// [C4] Page labels
1895

1896    protected PdfPageLabels pageLabels;
1897    /**
1898     * Sets the page labels
1899     * @param pageLabels the page labels
1900     */

1901    void setPageLabels(PdfPageLabels pageLabels) {
1902        this.pageLabels = pageLabels;
1903    }
1904    
1905// [C5] named objects: local destinations, javascript, embedded files
1906

1907    /**
1908     * Implements a link to other part of the document. The jump will
1909     * be made to a local destination with the same name, that must exist.
1910     * @param name the name for this link
1911     * @param llx the lower left x corner of the activation area
1912     * @param lly the lower left y corner of the activation area
1913     * @param urx the upper right x corner of the activation area
1914     * @param ury the upper right y corner of the activation area
1915     */

1916    void localGoto(String JavaDoc name, float llx, float lly, float urx, float ury) {
1917        PdfAction action = getLocalGotoAction(name);
1918        annotationsImp.addPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action));
1919    }
1920    
1921    /**
1922     * Implements a link to another document.
1923     * @param filename the filename for the remote document
1924     * @param name the name to jump to
1925     * @param llx the lower left x corner of the activation area
1926     * @param lly the lower left y corner of the activation area
1927     * @param urx the upper right x corner of the activation area
1928     * @param ury the upper right y corner of the activation area
1929     */

1930    void remoteGoto(String JavaDoc filename, String JavaDoc name, float llx, float lly, float urx, float ury) {
1931        annotationsImp.addPlainAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, name)));
1932    }
1933    
1934    /**
1935     * Implements a link to another document.
1936     * @param filename the filename for the remote document
1937     * @param page the page to jump to
1938     * @param llx the lower left x corner of the activation area
1939     * @param lly the lower left y corner of the activation area
1940     * @param urx the upper right x corner of the activation area
1941     * @param ury the upper right y corner of the activation area
1942     */

1943    void remoteGoto(String JavaDoc filename, int page, float llx, float lly, float urx, float ury) {
1944        addAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, new PdfAction(filename, page)));
1945    }
1946    
1947    /** Implements an action in an area.
1948     * @param action the <CODE>PdfAction</CODE>
1949     * @param llx the lower left x corner of the activation area
1950     * @param lly the lower left y corner of the activation area
1951     * @param urx the upper right x corner of the activation area
1952     * @param ury the upper right y corner of the activation area
1953     */

1954    void setAction(PdfAction action, float llx, float lly, float urx, float ury) {
1955        addAnnotation(new PdfAnnotation(writer, llx, lly, urx, ury, action));
1956    }
1957    
1958    /**
1959     * Stores the destinations keyed by name. Value is
1960     * <CODE>Object[]{PdfAction,PdfIndirectReference,PdfDestintion}</CODE>.
1961     */

1962    private TreeMap JavaDoc localDestinations = new TreeMap JavaDoc();
1963    
1964    PdfAction getLocalGotoAction(String JavaDoc name) {
1965        PdfAction action;
1966        Object JavaDoc obj[] = (Object JavaDoc[])localDestinations.get(name);
1967        if (obj == null)
1968            obj = new Object JavaDoc[3];
1969        if (obj[0] == null) {
1970            if (obj[1] == null) {
1971                obj[1] = writer.getPdfIndirectReference();
1972            }
1973            action = new PdfAction((PdfIndirectReference)obj[1]);
1974            obj[0] = action;
1975            localDestinations.put(name, obj);
1976        }
1977        else {
1978            action = (PdfAction)obj[0];
1979        }
1980        return action;
1981    }
1982    
1983    /**
1984     * The local destination to where a local goto with the same
1985     * name will jump to.
1986     * @param name the name of this local destination
1987     * @param destination the <CODE>PdfDestination</CODE> with the jump coordinates
1988     * @return <CODE>true</CODE> if the local destination was added,
1989     * <CODE>false</CODE> if a local destination with the same name
1990     * already existed
1991     */

1992    boolean localDestination(String JavaDoc name, PdfDestination destination) {
1993        Object JavaDoc obj[] = (Object JavaDoc[])localDestinations.get(name);
1994        if (obj == null)
1995            obj = new Object JavaDoc[3];
1996        if (obj[2] != null)
1997            return false;
1998        obj[2] = destination;
1999        localDestinations.put(name, obj);
2000        destination.addPage(writer.getCurrentPage());
2001        return true;
2002    }
2003    
2004    /**
2005     * Stores a list of document level JavaScript actions.
2006     */

2007    private ArrayList JavaDoc documentJavaScript = new ArrayList JavaDoc();
2008    void addJavaScript(PdfAction js) {
2009        if (js.get(PdfName.JS) == null)
2010            throw new RuntimeException JavaDoc("Only JavaScript actions are allowed.");
2011        try {
2012            documentJavaScript.add(writer.addToBody(js).getIndirectReference());
2013        }
2014        catch (IOException JavaDoc e) {
2015            throw new ExceptionConverter(e);
2016        }
2017    }
2018    
2019    ArrayList JavaDoc getDocumentJavaScript() {
2020        return documentJavaScript;
2021    }
2022    
2023    private HashMap JavaDoc documentFileAttachment = new HashMap JavaDoc();
2024
2025    void addFileAttachment(String JavaDoc description, PdfFileSpecification fs) throws IOException JavaDoc {
2026        if (description == null) {
2027            PdfString desc = (PdfString)fs.get(PdfName.DESC);
2028            if (desc == null) {
2029                description = "";
2030            }
2031            else {
2032                description = PdfEncodings.convertToString(desc.getBytes(), null);
2033            }
2034        }
2035        fs.addDescription(description, true);
2036        if (description.length() == 0)
2037            description = "Unnamed";
2038        String JavaDoc fn = PdfEncodings.convertToString(new PdfString(description, PdfObject.TEXT_UNICODE).getBytes(), null);
2039        int k = 0;
2040        while (documentFileAttachment.containsKey(fn)) {
2041            ++k;
2042            fn = PdfEncodings.convertToString(new PdfString(description + " " + k, PdfObject.TEXT_UNICODE).getBytes(), null);
2043        }
2044        documentFileAttachment.put(fn, fs.getReference());
2045    }
2046    
2047    HashMap JavaDoc getDocumentFileAttachment() {
2048        return documentFileAttachment;
2049    }
2050    
2051// [C6] document level actions
2052

2053    private String JavaDoc openActionName;
2054    
2055    void setOpenAction(String JavaDoc name) {
2056        openActionName = name;
2057        openActionAction = null;
2058    }
2059
2060    private PdfAction openActionAction;
2061    void setOpenAction(PdfAction action) {
2062        openActionAction = action;
2063        openActionName = null;
2064    }
2065
2066    private PdfDictionary additionalActions;
2067    void addAdditionalAction(PdfName actionType, PdfAction action) {
2068        if (additionalActions == null) {
2069            additionalActions = new PdfDictionary();
2070        }
2071        if (action == null)
2072            additionalActions.remove(actionType);
2073        else
2074            additionalActions.put(actionType, action);
2075        if (additionalActions.size() == 0)
2076            additionalActions = null;
2077    }
2078    
2079// [C7] portable collections
2080

2081    private PdfCollection collection;
2082
2083    /**
2084     * Sets the collection dictionary.
2085     * @param collection a dictionary of type PdfCollection
2086     */

2087    public void setCollection(PdfCollection collection) {
2088        this.collection = collection;
2089    }
2090    
2091// [C8] AcroForm
2092

2093    PdfAnnotationsImp annotationsImp;
2094    
2095    /**
2096     * Gets the AcroForm object.
2097     * @return the PdfAcroform object of the PdfDocument
2098     */

2099    PdfAcroForm getAcroForm() {
2100        return annotationsImp.getAcroForm();
2101    }
2102    
2103    void setSigFlags(int f) {
2104        annotationsImp.setSigFlags(f);
2105    }
2106    
2107    void addCalculationOrder(PdfFormField formField) {
2108        annotationsImp.addCalculationOrder(formField);
2109    }
2110    
2111    void addAnnotation(PdfAnnotation annot) {
2112        pageEmpty = false;
2113        annotationsImp.addAnnotation(annot);
2114    }
2115
2116// [F12] tagged PDF
2117

2118    protected int markPoint;
2119    
2120    int getMarkPoint() {
2121        return markPoint;
2122    }
2123     
2124    void incMarkPoint() {
2125        ++markPoint;
2126    }
2127    
2128// [U1] page sizes
2129

2130    /** This is the size of the next page. */
2131    protected Rectangle nextPageSize = null;
2132    
2133    /** This is the size of the several boxes of the current Page. */
2134    protected HashMap JavaDoc thisBoxSize = new HashMap JavaDoc();
2135    
2136    /** This is the size of the several boxes that will be used in
2137     * the next page. */

2138    protected HashMap JavaDoc boxSize = new HashMap JavaDoc();
2139    
2140    void setCropBoxSize(Rectangle crop) {
2141        setBoxSize("crop", crop);
2142    }
2143    
2144    void setBoxSize(String JavaDoc boxName, Rectangle size) {
2145        if (size == null)
2146            boxSize.remove(boxName);
2147        else
2148            boxSize.put(boxName, new PdfRectangle(size));
2149    }
2150    
2151    /**
2152     * Gives the size of a trim, art, crop or bleed box, or null if not defined.
2153     * @param boxName crop, trim, art or bleed
2154     */

2155    Rectangle getBoxSize(String JavaDoc boxName) {
2156        PdfRectangle r = (PdfRectangle)thisBoxSize.get(boxName);
2157        if (r != null) return r.getRectangle();
2158        return null;
2159    }
2160
2161// [U2] empty pages
2162

2163    /** This checks if the page is empty. */
2164    private boolean pageEmpty = true;
2165    
2166    void setPageEmpty(boolean pageEmpty) {
2167        this.pageEmpty = pageEmpty;
2168    }
2169    
2170// [U3] page actions
2171

2172    /** The duration of the page */
2173    protected int duration=-1; // negative values will indicate no duration
2174

2175    /** The page transition */
2176    protected PdfTransition transition=null;
2177        
2178    /**
2179     * Sets the display duration for the page (for presentations)
2180     * @param seconds the number of seconds to display the page
2181     */

2182    void setDuration(int seconds) {
2183        if (seconds > 0)
2184            this.duration=seconds;
2185        else
2186            this.duration=-1;
2187    }
2188        
2189    /**
2190     * Sets the transition for the page
2191     * @param transition the PdfTransition object
2192     */

2193    void setTransition(PdfTransition transition) {
2194        this.transition=transition;
2195    }
2196    
2197    protected PdfDictionary pageAA = null;
2198    void setPageAction(PdfName actionType, PdfAction action) {
2199        if (pageAA == null) {
2200            pageAA = new PdfDictionary();
2201        }
2202        pageAA.put(actionType, action);
2203    }
2204
2205// [U8] thumbnail images
2206

2207    private PdfIndirectReference thumb;
2208    void setThumbnail(Image image) throws PdfException, DocumentException {
2209        thumb = writer.getImageReference(writer.addDirectImageSimple(image));
2210    }
2211    
2212// [M0] Page resources contain references to fonts, extgstate, images,...
2213

2214    /** This are the page resources of the current Page. */
2215    protected PageResources pageResources;
2216    
2217    PageResources getPageResources() {
2218        return pageResources;
2219    }
2220    
2221// [M3] Images
2222

2223    /** Holds value of property strictImageSequence. */
2224    private boolean strictImageSequence = false;
2225    
2226    /** Getter for property strictImageSequence.
2227     * @return Value of property strictImageSequence.
2228     *
2229     */

2230    boolean isStrictImageSequence() {
2231        return this.strictImageSequence;
2232    }
2233    
2234    /** Setter for property strictImageSequence.
2235     * @param strictImageSequence New value of property strictImageSequence.
2236     *
2237     */

2238    void setStrictImageSequence(boolean strictImageSequence) {
2239        this.strictImageSequence = strictImageSequence;
2240    }
2241    
2242    /** This is the position where the image ends. */
2243    private float imageEnd = -1;
2244 
2245    /**
2246     * Method added by Pelikan Stephan
2247     */

2248    public void clearTextWrap() {
2249        float tmpHeight = imageEnd - currentHeight;
2250        if (line != null) {
2251            tmpHeight += line.height();
2252        }
2253        if ((imageEnd > -1) && (tmpHeight > 0)) {
2254            carriageReturn();
2255            currentHeight += tmpHeight;
2256        }
2257    }
2258    
2259    /** This is the image that could not be shown on a previous page. */
2260    private Image imageWait = null;
2261    
2262    /**
2263     * Adds an image to the document.
2264     * @param image the <CODE>Image</CODE> to add
2265     * @throws PdfException on error
2266     * @throws DocumentException on error
2267     */

2268    
2269    private void add(Image image) throws PdfException, DocumentException {
2270        
2271        if (image.hasAbsoluteY()) {
2272            graphics.addImage(image);
2273            pageEmpty = false;
2274            return;
2275        }
2276        
2277        // if there isn't enough room for the image on this page, save it for the next page
2278
if (currentHeight != 0 && indentTop() - currentHeight - image.getScaledHeight() < indentBottom()) {
2279            if (!strictImageSequence && imageWait == null) {
2280                imageWait = image;
2281                return;
2282            }
2283            newPage();
2284            if (currentHeight != 0 && indentTop() - currentHeight - image.getScaledHeight() < indentBottom()) {
2285                imageWait = image;
2286                return;
2287            }
2288        }
2289        pageEmpty = false;
2290        // avoid endless loops
2291
if (image == imageWait)
2292            imageWait = null;
2293        boolean textwrap = (image.getAlignment() & Image.TEXTWRAP) == Image.TEXTWRAP
2294        && !((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE);
2295        boolean underlying = (image.getAlignment() & Image.UNDERLYING) == Image.UNDERLYING;
2296        float diff = leading / 2;
2297        if (textwrap) {
2298            diff += leading;
2299        }
2300        float lowerleft = indentTop() - currentHeight - image.getScaledHeight() -diff;
2301        float mt[] = image.matrix();
2302        float startPosition = indentLeft() - mt[4];
2303        if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) startPosition = indentRight() - image.getScaledWidth() - mt[4];
2304        if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) startPosition = indentLeft() + ((indentRight() - indentLeft() - image.getScaledWidth()) / 2) - mt[4];
2305        if (image.hasAbsoluteX()) startPosition = image.getAbsoluteX();
2306        if (textwrap) {
2307            if (imageEnd < 0 || imageEnd < currentHeight + image.getScaledHeight() + diff) {
2308                imageEnd = currentHeight + image.getScaledHeight() + diff;
2309            }
2310            if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) {
2311                // indentation suggested by Pelikan Stephan
2312
indentation.imageIndentRight += image.getScaledWidth() + image.getIndentationLeft();
2313            }
2314            else {
2315                // indentation suggested by Pelikan Stephan
2316
indentation.imageIndentLeft += image.getScaledWidth() + image.getIndentationRight();
2317            }
2318        }
2319        else {
2320            if ((image.getAlignment() & Image.RIGHT) == Image.RIGHT) startPosition -= image.getIndentationRight();
2321            else if ((image.getAlignment() & Image.MIDDLE) == Image.MIDDLE) startPosition += image.getIndentationLeft() - image.getIndentationRight();
2322            else startPosition += image.getIndentationLeft();
2323        }
2324        graphics.addImage(image, mt[0], mt[1], mt[2], mt[3], startPosition, lowerleft - mt[5]);
2325        if (!(textwrap || underlying)) {
2326            currentHeight += image.getScaledHeight() + diff;
2327            flushLines();
2328            text.moveText(0, - (image.getScaledHeight() + diff));
2329            newLine();
2330        }
2331    }
2332   
2333// [M4] Adding a PdfPTable
2334

2335    /** Adds a <CODE>PdfPTable</CODE> to the document.
2336     * @param ptable the <CODE>PdfPTable</CODE> to be added to the document.
2337     * @throws DocumentException on error
2338     */

2339    void addPTable(PdfPTable ptable) throws DocumentException {
2340        ColumnText ct = new ColumnText(writer.getDirectContent());
2341        if (currentHeight > 0) {
2342            Paragraph p = new Paragraph();
2343            p.setLeading(0);
2344            ct.addElement(p);
2345            // if the table prefers to be on a single page, and it wouldn't
2346
//fit on the current page, start a new page.
2347
if (ptable.getKeepTogether() && !fitsPage(ptable, 0f)) {
2348                newPage();
2349            }
2350        }
2351        ct.addElement(ptable);
2352        boolean he = ptable.isHeadersInEvent();
2353        ptable.setHeadersInEvent(true);
2354        int loop = 0;
2355        while (true) {
2356            ct.setSimpleColumn(indentLeft(), indentBottom(), indentRight(), indentTop() - currentHeight);
2357            int status = ct.go();
2358            if ((status & ColumnText.NO_MORE_TEXT) != 0) {
2359                text.moveText(0, ct.getYLine() - indentTop() + currentHeight);
2360                currentHeight = indentTop() - ct.getYLine();
2361                break;
2362            }
2363            if (indentTop() - currentHeight == ct.getYLine())
2364                ++loop;
2365            else
2366                loop = 0;
2367            if (loop == 3) {
2368                add(new Paragraph("ERROR: Infinite table loop"));
2369                break;
2370            }
2371            newPage();
2372        }
2373        ptable.setHeadersInEvent(he);
2374    }
2375    
2376    /**
2377     * Checks if a <CODE>PdfPTable</CODE> fits the current page of the <CODE>PdfDocument</CODE>.
2378     *
2379     * @param table the table that has to be checked
2380     * @param margin a certain margin
2381     * @return <CODE>true</CODE> if the <CODE>PdfPTable</CODE> fits the page, <CODE>false</CODE> otherwise.
2382     */

2383    
2384    boolean fitsPage(PdfPTable table, float margin) {
2385        if (!table.isLockedWidth()) {
2386            float totalWidth = (indentRight() - indentLeft()) * table.getWidthPercentage() / 100;
2387            table.setTotalWidth(totalWidth);
2388        }
2389        // ensuring that a new line has been started.
2390
ensureNewLine();
2391        return table.getTotalHeight() <= indentTop() - currentHeight - indentBottom() - margin;
2392    }
2393
2394// [M4'] Adding a Table
2395

2396    /**
2397     * Gets a PdfTable object
2398     * (contributed by dperezcar@fcc.es)
2399     * @param table a high level table object
2400     * @param supportRowAdditions
2401     * @return returns a PdfTable object
2402     * @see PdfWriter#getPdfTable(Table)
2403     */

2404
2405    PdfTable getPdfTable(Table table, boolean supportRowAdditions) {
2406        return new PdfTable(table, indentLeft(), indentRight(), indentTop() - currentHeight, supportRowAdditions);
2407    }
2408    
2409    /**
2410     * This is a helper class for adding a Table to a document.
2411     */

2412    private static class RenderingContext {
2413        float pagetop = -1;
2414        float oldHeight = -1;
2415
2416        PdfContentByte cellGraphics = null;
2417        
2418        float lostTableBottom;
2419        
2420        float maxCellBottom;
2421        float maxCellHeight;
2422        
2423        Map JavaDoc rowspanMap;
2424        Map JavaDoc pageMap = new HashMap JavaDoc();
2425        /**
2426         * A PdfPTable
2427         */

2428        public PdfTable table;
2429        
2430        /**
2431         * Consumes the rowspan
2432         * @param c
2433         * @return a rowspan.
2434         */

2435        public int consumeRowspan(PdfCell c) {
2436            if (c.rowspan() == 1) {
2437                return 1;
2438            }
2439            
2440            Integer JavaDoc i = (Integer JavaDoc) rowspanMap.get(c);
2441            if (i == null) {
2442                i = new Integer JavaDoc(c.rowspan());
2443            }
2444            
2445            i = new Integer JavaDoc(i.intValue() - 1);
2446            rowspanMap.put(c, i);
2447
2448            if (i.intValue() < 1) {
2449                return 1;
2450            }
2451            return i.intValue();
2452        }
2453
2454        /**
2455         * Looks at the current rowspan.
2456         * @param c
2457         * @return the current rowspan
2458         */

2459        public int currentRowspan(PdfCell c) {
2460            Integer JavaDoc i = (Integer JavaDoc) rowspanMap.get(c);
2461            if (i == null) {
2462                return c.rowspan();
2463            } else {
2464                return i.intValue();
2465            }
2466        }
2467        
2468        public int cellRendered(PdfCell cell, int pageNumber) {
2469            Integer JavaDoc i = (Integer JavaDoc) pageMap.get(cell);
2470            if (i == null) {
2471                i = new Integer JavaDoc(1);
2472            } else {
2473                i = new Integer JavaDoc(i.intValue() + 1);
2474            }
2475            pageMap.put(cell, i);
2476
2477            Integer JavaDoc pageInteger = new Integer JavaDoc(pageNumber);
2478            Set JavaDoc set = (Set JavaDoc) pageMap.get(pageInteger);
2479            
2480            if (set == null) {
2481                set = new HashSet JavaDoc();
2482                pageMap.put(pageInteger, set);
2483            }
2484            
2485            set.add(cell);
2486            
2487            return i.intValue();
2488        }
2489
2490        public int numCellRendered(PdfCell cell) {
2491            Integer JavaDoc i = (Integer JavaDoc) pageMap.get(cell);
2492            if (i == null) {
2493                i = new Integer JavaDoc(0);
2494            }
2495            return i.intValue();
2496        }
2497        
2498        public boolean isCellRenderedOnPage(PdfCell cell, int pageNumber) {
2499            Integer JavaDoc pageInteger = new Integer JavaDoc(pageNumber);
2500            Set JavaDoc set = (Set JavaDoc) pageMap.get(pageInteger);
2501            
2502            if (set != null) {
2503                return set.contains(cell);
2504            }
2505            
2506            return false;
2507        }
2508    };
2509
2510    /**
2511     * Adds a new table to the document.
2512     * @param table Table to add. Rendered rows will be deleted after processing.
2513     * @param onlyFirstPage Render only the first full page
2514     * @throws DocumentException
2515     */

2516    private void add(PdfTable table, boolean onlyFirstPage) throws DocumentException {
2517        // before every table, we flush all lines
2518
flushLines();
2519        
2520        RenderingContext ctx = new RenderingContext();
2521        ctx.pagetop = indentTop();
2522        ctx.oldHeight = currentHeight;
2523        ctx.cellGraphics = new PdfContentByte(writer);
2524        ctx.rowspanMap = new HashMap JavaDoc();
2525        ctx.table = table;
2526        
2527        // initialisation of parameters
2528
PdfCell cell;
2529
2530        // drawing the table
2531
ArrayList JavaDoc dataCells = table.getCells();
2532                
2533        ArrayList JavaDoc headercells = table.getHeaderCells();
2534        // Check if we have removed header cells in a previous call
2535
if (!headercells.isEmpty() && (dataCells.isEmpty() || dataCells.get(0) != headercells.get(0))) {
2536            ArrayList JavaDoc allCells = new ArrayList JavaDoc(dataCells.size()+headercells.size());
2537            allCells.addAll(headercells);
2538            allCells.addAll(dataCells);
2539            dataCells = allCells;
2540        }
2541        
2542        ArrayList JavaDoc cells = dataCells;
2543        ArrayList JavaDoc rows = extractRows(cells, ctx);
2544        boolean isContinue = false;
2545        while (!cells.isEmpty()) {
2546            // initialisation of some extra parameters;
2547
ctx.lostTableBottom = 0;
2548                        
2549            // loop over the cells
2550
boolean cellsShown = false;
2551
2552            // draw the cells (line by line)
2553
Iterator JavaDoc iterator = rows.iterator();
2554              
2555            boolean atLeastOneFits = false;
2556            while (iterator.hasNext()) {
2557                ArrayList JavaDoc row = (ArrayList JavaDoc) iterator.next();
2558                analyzeRow(rows, ctx);
2559                renderCells(ctx, row, table.hasToFitPageCells() & atLeastOneFits);
2560                                
2561                if (!mayBeRemoved(row)) {
2562                    break;
2563                }
2564                consumeRowspan(row, ctx);
2565                iterator.remove();
2566                atLeastOneFits = true;
2567            }
2568
2569// compose cells array list for subsequent code
2570
cells.clear();
2571            Set JavaDoc opt = new HashSet JavaDoc();
2572            iterator = rows.iterator();
2573            while (iterator.hasNext()) {
2574                ArrayList JavaDoc row = (ArrayList JavaDoc) iterator.next();
2575                
2576                Iterator JavaDoc cellIterator = row.iterator();
2577                while (cellIterator.hasNext()) {
2578                    cell = (PdfCell) cellIterator.next();
2579                    
2580                    if (!opt.contains(cell)) {
2581                        cells.add(cell);
2582                        opt.add(cell);
2583                    }
2584                }
2585            }
2586            
2587            // we paint the graphics of the table after looping through all the cells
2588
Rectangle tablerec = new Rectangle(table);
2589            tablerec.setBorder(table.getBorder());
2590            tablerec.setBorderWidth(table.getBorderWidth());
2591            tablerec.setBorderColor(table.getBorderColor());
2592            tablerec.setBackgroundColor(table.getBackgroundColor());
2593            PdfContentByte under = writer.getDirectContentUnder();
2594            under.rectangle(tablerec.rectangle(top(), indentBottom()));
2595            under.add(ctx.cellGraphics);
2596            // bugfix by Gerald Fehringer: now again add the border for the table
2597
// since it might have been covered by cell backgrounds
2598
tablerec.setBackgroundColor(null);
2599            tablerec = tablerec.rectangle(top(), indentBottom());
2600            tablerec.setBorder(table.getBorder());
2601            under.rectangle(tablerec);
2602            // end bugfix
2603

2604            ctx.cellGraphics = new PdfContentByte(null);
2605            // if the table continues on the next page
2606

2607            if (!rows.isEmpty()) {
2608                isContinue = true;
2609                graphics.setLineWidth(table.getBorderWidth());
2610                if (cellsShown && (table.getBorder() & Rectangle.BOTTOM) == Rectangle.BOTTOM) {
2611                    // Draw the bottom line
2612

2613                    // the color is set to the color of the element
2614
Color JavaDoc tColor = table.getBorderColor();
2615                    if (tColor != null) {
2616                        graphics.setColorStroke(tColor);
2617                    }
2618                    graphics.moveTo(table.getLeft(), Math.max(table.getBottom(), indentBottom()));
2619                    graphics.lineTo(table.getRight(), Math.max(table.getBottom(), indentBottom()));
2620                    graphics.stroke();
2621                    if (tColor != null) {
2622                        graphics.resetRGBColorStroke();
2623                    }
2624                }
2625                            
2626                // old page
2627
pageEmpty = false;
2628                float difference = ctx.lostTableBottom;
2629
2630                // new page
2631
newPage();
2632                
2633                // G.F.: if something added in page event i.e. currentHeight > 0
2634
float heightCorrection = 0;
2635                boolean somethingAdded = false;
2636                if (currentHeight > 0) {
2637                    heightCorrection = 6;
2638                    currentHeight += heightCorrection;
2639                    somethingAdded = true;
2640                    newLine();
2641                    flushLines();
2642                    indentation.indentTop = currentHeight - leading;
2643                    currentHeight = 0;
2644                }
2645                else {
2646                    flushLines();
2647                }
2648                            
2649                // this part repeats the table headers (if any)
2650
int size = headercells.size();
2651                if (size > 0) {
2652                    // this is the top of the headersection
2653
cell = (PdfCell) headercells.get(0);
2654                    float oldTop = cell.getTop(0);
2655                    // loop over all the cells of the table header
2656
for (int i = 0; i < size; i++) {
2657                        cell = (PdfCell) headercells.get(i);
2658                        // calculation of the new cellpositions
2659
cell.setTop(indentTop() - oldTop + cell.getTop(0));
2660                        cell.setBottom(indentTop() - oldTop + cell.getBottom(0));
2661                        ctx.pagetop = cell.getBottom();
2662                        // we paint the borders of the cell
2663
ctx.cellGraphics.rectangle(cell.rectangle(indentTop(), indentBottom()));
2664                        // we write the text of the cell
2665
ArrayList JavaDoc images = cell.getImages(indentTop(), indentBottom());
2666                        for (Iterator JavaDoc im = images.iterator(); im.hasNext();) {
2667                            cellsShown = true;
2668                            Image image = (Image) im.next();
2669                            graphics.addImage(image);
2670                        }
2671                        lines = cell.getLines(indentTop(), indentBottom());
2672                        float cellTop = cell.getTop(indentTop());
2673                        text.moveText(0, cellTop-heightCorrection);
2674                        float cellDisplacement = flushLines() - cellTop+heightCorrection;
2675                        text.moveText(0, cellDisplacement);
2676                    }
2677                                
2678                    currentHeight = indentTop() - ctx.pagetop + table.cellspacing();
2679                    text.moveText(0, ctx.pagetop - indentTop() - currentHeight);
2680                }
2681                else {
2682                    if (somethingAdded) {
2683                        ctx.pagetop = indentTop();
2684                        text.moveText(0, -table.cellspacing());
2685                    }
2686                }
2687                ctx.oldHeight = currentHeight - heightCorrection;
2688                            
2689                // calculating the new positions of the table and the cells
2690
size = Math.min(cells.size(), table.columns());
2691                int i = 0;
2692                while (i < size) {
2693                    cell = (PdfCell) cells.get(i);
2694                    if (cell.getTop(-table.cellspacing()) > ctx.lostTableBottom) {
2695                        float newBottom = ctx.pagetop - difference + cell.getBottom();
2696                        float neededHeight = cell.remainingHeight();
2697                        if (newBottom > ctx.pagetop - neededHeight) {
2698                            difference += newBottom - (ctx.pagetop - neededHeight);
2699                        }
2700                    }
2701                    i++;
2702                }
2703                size = cells.size();
2704                table.setTop(indentTop());
2705                table.setBottom(ctx.pagetop - difference + table.getBottom(table.cellspacing()));
2706                for (i = 0; i < size; i++) {
2707                    cell = (PdfCell) cells.get(i);
2708                    float newBottom = ctx.pagetop - difference + cell.getBottom();
2709                    float newTop = ctx.pagetop - difference + cell.getTop(-table.cellspacing());
2710                    if (newTop > indentTop() - currentHeight) {
2711                        newTop = indentTop() - currentHeight;
2712                    }
2713               
2714                    cell.setTop(newTop );
2715                    cell.setBottom(newBottom );
2716                }
2717                if (onlyFirstPage) {
2718                    break;
2719                }
2720            }
2721        }
2722        
2723        float tableHeight = table.getTop() - table.getBottom();
2724        // bugfix by Adauto Martins when have more than two tables and more than one page
2725
// If continuation of table in other page (bug report #1460051)
2726
if (isContinue) {
2727            currentHeight = tableHeight;
2728            text.moveText(0, -(tableHeight - (ctx.oldHeight * 2)));
2729        } else {
2730            currentHeight = ctx.oldHeight + tableHeight;
2731            text.moveText(0, -tableHeight);
2732        }
2733        // end bugfix
2734
pageEmpty = false;
2735    }
2736    
2737    private void analyzeRow(ArrayList JavaDoc rows, RenderingContext ctx) {
2738        ctx.maxCellBottom = indentBottom();
2739
2740        // determine whether row(index) is in a rowspan
2741
int rowIndex = 0;
2742
2743        ArrayList JavaDoc row = (ArrayList JavaDoc) rows.get(rowIndex);
2744        int maxRowspan = 1;
2745        Iterator JavaDoc iterator = row.iterator();
2746        while (iterator.hasNext()) {
2747            PdfCell cell = (PdfCell) iterator.next();
2748            maxRowspan = Math.max(ctx.currentRowspan(cell), maxRowspan);
2749        }
2750        rowIndex += maxRowspan;
2751        
2752        boolean useTop = true;
2753        if (rowIndex == rows.size()) {
2754            rowIndex = rows.size() - 1;
2755            useTop = false;
2756        }
2757        
2758        if (rowIndex < 0 || rowIndex >= rows.size()) return;
2759        
2760        row = (ArrayList JavaDoc) rows.get(rowIndex);
2761        iterator = row.iterator();
2762        while (iterator.hasNext()) {
2763            PdfCell cell = (PdfCell) iterator.next();
2764            Rectangle cellRect = cell.rectangle(ctx.pagetop, indentBottom());
2765            if (useTop) {
2766                ctx.maxCellBottom = Math.max(ctx.maxCellBottom, cellRect.getTop());
2767            } else {
2768                if (ctx.currentRowspan(cell) == 1) {
2769                    ctx.maxCellBottom = Math.max(ctx.maxCellBottom, cellRect.getBottom());
2770                }
2771            }
2772        }
2773    }
2774
2775    private boolean mayBeRemoved(ArrayList JavaDoc row) {
2776        Iterator JavaDoc iterator = row.iterator();
2777        boolean mayBeRemoved = true;
2778        while (iterator.hasNext()) {
2779            PdfCell cell = (PdfCell) iterator.next();
2780           
2781            mayBeRemoved &= cell.mayBeRemoved();
2782        }
2783        return mayBeRemoved;
2784    }
2785
2786    private void consumeRowspan(ArrayList JavaDoc row, RenderingContext ctx) {
2787        Iterator JavaDoc iterator = row.iterator();
2788        while (iterator.hasNext()) {
2789            PdfCell c = (PdfCell) iterator.next();
2790            ctx.consumeRowspan(c);
2791        }
2792    }
2793    
2794    private ArrayList JavaDoc extractRows(ArrayList JavaDoc cells, RenderingContext ctx) {
2795        PdfCell cell;
2796        PdfCell previousCell = null;
2797        ArrayList JavaDoc rows = new ArrayList JavaDoc();
2798        java.util.List JavaDoc rowCells = new ArrayList JavaDoc();
2799        
2800        Iterator JavaDoc iterator = cells.iterator();
2801        while (iterator.hasNext()) {
2802            cell = (PdfCell) iterator.next();
2803
2804            boolean isAdded = false;
2805
2806            boolean isEndOfRow = !iterator.hasNext();
2807            boolean isCurrentCellPartOfRow = !iterator.hasNext();
2808            
2809            if (previousCell != null) {
2810                if (cell.getLeft() <= previousCell.getLeft()) {
2811                    isEndOfRow = true;
2812                    isCurrentCellPartOfRow = false;
2813                }
2814            }
2815            
2816            if (isCurrentCellPartOfRow) {
2817                rowCells.add(cell);
2818                isAdded = true;
2819            }
2820            
2821            if (isEndOfRow) {
2822                if (!rowCells.isEmpty()) {
2823                    // add to rowlist
2824
rows.add(rowCells);
2825                }
2826                
2827                // start a new list for next line
2828
rowCells = new ArrayList JavaDoc();
2829            }
2830
2831            if (!isAdded) {
2832                rowCells.add(cell);
2833            }
2834            
2835            previousCell = cell;
2836        }
2837        
2838        if (!rowCells.isEmpty()) {
2839            rows.add(rowCells);
2840        }
2841        
2842        // fill row information with rowspan cells to get complete "scan lines"
2843
for (int i = rows.size() - 1; i >= 0; i--) {
2844            ArrayList JavaDoc row = (ArrayList JavaDoc) rows.get(i);
2845            // iterator through row
2846
for (int j = 0; j < row.size(); j++) {
2847                PdfCell c = (PdfCell) row.get(j);
2848                int rowspan = c.rowspan();
2849                // fill in missing rowspan cells to complete "scan line"
2850
for (int k = 1; k < rowspan && rows.size() <= i+k; k++) {
2851                    ArrayList JavaDoc spannedRow = ((ArrayList JavaDoc) rows.get(i + k));
2852                    if (spannedRow.size() > j)
2853                        spannedRow.add(j, c);
2854                }
2855            }
2856        }
2857                
2858        return rows;
2859    }
2860
2861    private void renderCells(RenderingContext ctx, java.util.List JavaDoc cells, boolean hasToFit) throws DocumentException {
2862        PdfCell cell;
2863        Iterator JavaDoc iterator;
2864        if (hasToFit) {
2865            iterator = cells.iterator();
2866            while (iterator.hasNext()) {
2867                cell = (PdfCell) iterator.next();
2868                if (!cell.isHeader()) {
2869                    if (cell.getBottom() < indentBottom()) return;
2870                }
2871            }
2872        }
2873        iterator = cells.iterator();
2874        
2875        while (iterator.hasNext()) {
2876            cell = (PdfCell) iterator.next();
2877            if (!ctx.isCellRenderedOnPage(cell, getPageNumber())) {
2878
2879                float correction = 0;
2880                if (ctx.numCellRendered(cell) >= 1) {
2881                    correction = 1.0f;
2882                }
2883            
2884                lines = cell.getLines(ctx.pagetop, indentBottom() - correction);
2885                
2886                // if there is still text to render we render it
2887
if (lines != null && !lines.isEmpty()) {
2888                    
2889                    // we write the text
2890
float cellTop = cell.getTop(ctx.pagetop - ctx.oldHeight);
2891                    text.moveText(0, cellTop);
2892                    float cellDisplacement = flushLines() - cellTop;
2893                    
2894                    text.moveText(0, cellDisplacement);
2895                    if (ctx.oldHeight + cellDisplacement > currentHeight) {
2896                        currentHeight = ctx.oldHeight + cellDisplacement;
2897                    }
2898
2899                    ctx.cellRendered(cell, getPageNumber());
2900                }
2901                float indentBottom = Math.max(cell.getBottom(), indentBottom());
2902                Rectangle tableRect = ctx.table.rectangle(ctx.pagetop, indentBottom());
2903                indentBottom = Math.max(tableRect.getBottom(), indentBottom);
2904                
2905                // we paint the borders of the cells
2906
Rectangle cellRect = cell.rectangle(tableRect.getTop(), indentBottom);
2907                //cellRect.setBottom(cellRect.bottom());
2908
if (cellRect.getHeight() > 0) {
2909                    ctx.lostTableBottom = indentBottom;
2910                    ctx.cellGraphics.rectangle(cellRect);
2911                }
2912    
2913                // and additional graphics
2914
ArrayList JavaDoc images = cell.getImages(ctx.pagetop, indentBottom());
2915                for (Iterator JavaDoc i = images.iterator(); i.hasNext();) {
2916                    Image image = (Image) i.next();
2917                    graphics.addImage(image);
2918                }
2919                
2920            }
2921        }
2922    }
2923
2924    /**
2925     * @see PdfWriter#breakTableIfDoesntFit(PdfTable)
2926     * (contributed by dperezcar@fcc.es)
2927     * @param table Table to add
2928     * @return true if the table will be broken
2929     * @throws DocumentException
2930     * @deprecated
2931     */

2932    
2933    boolean breakTableIfDoesntFit(PdfTable table) throws DocumentException {
2934        table.updateRowAdditions();
2935        // Do we have any full page available?
2936
if (!table.hasToFitPageTable() && table.getBottom() <= indentation.indentBottom) {
2937            // Then output that page
2938
add(table, true);
2939            return true;
2940        }
2941        return false;
2942    }
2943    
2944    /**
2945     * Returns the bottomvalue of a <CODE>Table</CODE> if it were added to this document.
2946     *
2947     * @param table the table that may or may not be added to this document
2948     * @return a bottom value
2949     * @deprecated
2950     */

2951    
2952    float bottom(Table table) {
2953        // constructing a PdfTable
2954
PdfTable tmp = getPdfTable(table, false);
2955        return tmp.getBottom();
2956    }
2957    
2958// [M5] header/footer
2959
private void doFooter() throws DocumentException {
2960        if (footer == null) return;
2961        // Begin added by Edgar Leonardo Prieto Perilla
2962
// Avoid footer identation
2963
float tmpIndentLeft = indentation.indentLeft;
2964        float tmpIndentRight = indentation.indentRight;
2965        // Begin added: Bonf (Marc Schneider) 2003-07-29
2966
float tmpListIndentLeft = indentation.listIndentLeft;
2967        float tmpImageIndentLeft = indentation.imageIndentLeft;
2968        float tmpImageIndentRight = indentation.imageIndentRight;
2969        // End added: Bonf (Marc Schneider) 2003-07-29
2970

2971        indentation.indentLeft = indentation.indentRight = 0;
2972        // Begin added: Bonf (Marc Schneider) 2003-07-29
2973
indentation.listIndentLeft = 0;
2974        indentation.imageIndentLeft = 0;
2975        indentation.imageIndentRight = 0;
2976        // End added: Bonf (Marc Schneider) 2003-07-29
2977
// End Added by Edgar Leonardo Prieto Perilla
2978
footer.setPageNumber(pageN);
2979        leading = footer.paragraph().getTotalLeading();
2980        add(footer.paragraph());
2981        // adding the footer limits the height
2982
indentation.indentBottom = currentHeight;
2983        text.moveText(left(), indentBottom());
2984        flushLines();
2985        text.moveText(-left(), -bottom());
2986        footer.setTop(bottom(currentHeight));
2987        footer.setBottom(bottom() - (0.75f * leading));
2988        footer.setLeft(left());
2989        footer.setRight(right());
2990        graphics.rectangle(footer);
2991        indentation.indentBottom = currentHeight + leading * 2;
2992        currentHeight = 0;
2993        // Begin added by Edgar Leonardo Prieto Perilla
2994
indentation.indentLeft = tmpIndentLeft;
2995        indentation.indentRight = tmpIndentRight;
2996        // Begin added: Bonf (Marc Schneider) 2003-07-29
2997
indentation.listIndentLeft = tmpListIndentLeft;
2998        indentation.imageIndentLeft = tmpImageIndentLeft;
2999        indentation.imageIndentRight = tmpImageIndentRight;
3000        // End added: Bonf (Marc Schneider) 2003-07-29
3001
// End added by Edgar Leonardo Prieto Perilla
3002
}
3003    
3004    private void doHeader() throws DocumentException {
3005        // if there is a header, the header = added
3006
if (header == null) return;
3007        // Begin added by Edgar Leonardo Prieto Perilla
3008
// Avoid header identation
3009
float tmpIndentLeft = indentation.indentLeft;
3010        float tmpIndentRight = indentation.indentRight;
3011        // Begin added: Bonf (Marc Schneider) 2003-07-29
3012
float tmpListIndentLeft = indentation.listIndentLeft;
3013        float tmpImageIndentLeft = indentation.imageIndentLeft;
3014        float tmpImageIndentRight = indentation.imageIndentRight;
3015        // End added: Bonf (Marc Schneider) 2003-07-29
3016
indentation.indentLeft = indentation.indentRight = 0;
3017        // Added: Bonf
3018
indentation.listIndentLeft = 0;
3019        indentation.imageIndentLeft = 0;
3020        indentation.imageIndentRight = 0;
3021        // End added: Bonf
3022
// Begin added by Edgar Leonardo Prieto Perilla
3023
header.setPageNumber(pageN);
3024        leading = header.paragraph().getTotalLeading();
3025        text.moveText(0, leading);
3026        add(header.paragraph());
3027        newLine();
3028        indentation.indentTop = currentHeight - leading;
3029        header.setTop(top() + leading);
3030        header.setBottom(indentTop() + leading * 2 / 3);
3031        header.setLeft(left());
3032        header.setRight(right());
3033        graphics.rectangle(header);
3034        flushLines();
3035        currentHeight = 0;
3036        // Begin added by Edgar Leonardo Prieto Perilla
3037
// Restore identation
3038
indentation.indentLeft = tmpIndentLeft;
3039        indentation.indentRight = tmpIndentRight;
3040        // Begin added: Bonf (Marc Schneider) 2003-07-29
3041
indentation.listIndentLeft = tmpListIndentLeft;
3042        indentation.imageIndentLeft = tmpImageIndentLeft;
3043        indentation.imageIndentRight = tmpImageIndentRight;
3044        // End added: Bonf (Marc Schneider) 2003-07-29
3045
// End Added by Edgar Leonardo Prieto Perilla
3046
}
3047}
Popular Tags