001/* 002 * $Id: Document.java 4905 2011-06-08 12:26:03Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text; 045 046import java.text.SimpleDateFormat; 047import java.util.ArrayList; 048import java.util.Date; 049 050import com.itextpdf.text.error_messages.MessageLocalization; 051 052/** 053 * A generic Document class. 054 * <P> 055 * All kinds of Text-elements can be added to a <CODE>HTMLDocument</CODE>. 056 * The <CODE>Document</CODE> signals all the listeners when an element has 057 * been added. 058 * <P> 059 * Remark: 060 * <OL> 061 * <LI>Once a document is created you can add some meta information. 062 * <LI>You can also set the headers/footers. 063 * <LI>You have to open the document before you can write content. 064 * <LI>You can only write content (no more meta-formation!) once a document is 065 * opened. 066 * <LI>When you change the header/footer on a certain page, this will be 067 * effective starting on the next page. 068 * <LI>After closing the document, every listener (as well as its <CODE> 069 * OutputStream</CODE>) is closed too. 070 * </OL> 071 * Example: <BLOCKQUOTE> 072 * 073 * <PRE>// creation of the document with a certain size and certain margins 074 * <STRONG>Document document = new Document(PageSize.A4, 50, 50, 50, 50); 075 * </STRONG> try { 076 * // creation of the different writers 077 * HtmlWriter.getInstance(<STRONG>document </STRONG>, System.out); 078 * PdfWriter.getInstance(<STRONG>document </STRONG>, new FileOutputStream("text.pdf")); 079 * // we add some meta information to the document 080 * <STRONG>document.addAuthor("Bruno Lowagie"); </STRONG> 081 * <STRONG>document.addSubject("This is the result of a Test."); </STRONG> 082 * // we open the document for writing 083 * <STRONG>document.open(); </STRONG> 084 * <STRONG>document.add(new Paragraph("Hello world"));</STRONG> 085 * } catch(DocumentException de) { 086 * System.err.println(de.getMessage()); 087 * } 088 * <STRONG>document.close();</STRONG> 089 * </PRE> 090 * 091 * </BLOCKQUOTE> 092 */ 093 094public class Document implements DocListener { 095 096 // membervariables 097 /** 098 * This constant contains the name of the product. 099 * iText is a registered trademark. 100 * Please don't change this constant. 101 * @since 2.1.6 102 */ 103 private static final String ITEXT = "iText\u00ae"; 104 /** 105 * This constant contains the version number of this iText release. 106 * For debugging purposes, we request you NOT to change this constant. 107 * @since 2.1.6 108 */ 109 private static final String RELEASE = "5.1.2-SNAPSHOT"; 110 /** 111 * This constant the iText version as shown in the producer line. 112 * iText is a product developed by 1T3XT BVBA. 113 * 1T3XT requests that you retain the iText producer line 114 * in every PDF that is created or manipulated using iText. 115 */ 116 private static final String ITEXT_VERSION = ITEXT + " " + RELEASE + " \u00a92000-2011 1T3XT BVBA"; 117 118 /** 119 * Allows the pdf documents to be produced without compression for debugging 120 * purposes. 121 */ 122 public static boolean compress = true; 123 124 /** 125 * When true the file access is not done through a memory mapped file. Use it if the file 126 * is too big to be mapped in your address space. 127 */ 128 public static boolean plainRandomAccess = false; 129 130 /** Scales the WMF font size. The default value is 0.86. */ 131 public static float wmfFontCorrection = 0.86f; 132 133 /** 134 * The DocListener. 135 * @since iText 5.1.0 changed from private to protected 136 */ 137 protected ArrayList<DocListener> listeners = new ArrayList<DocListener>(); 138 139 /** Is the document open or not? */ 140 protected boolean open; 141 142 /** Has the document already been closed? */ 143 protected boolean close; 144 145 // membervariables concerning the layout 146 147 /** The size of the page. */ 148 protected Rectangle pageSize; 149 150 /** margin in x direction starting from the left */ 151 protected float marginLeft = 0; 152 153 /** margin in x direction starting from the right */ 154 protected float marginRight = 0; 155 156 /** margin in y direction starting from the top */ 157 protected float marginTop = 0; 158 159 /** margin in y direction starting from the bottom */ 160 protected float marginBottom = 0; 161 162 /** mirroring of the left/right margins */ 163 protected boolean marginMirroring = false; 164 165 /** 166 * mirroring of the top/bottom margins 167 * @since 2.1.6 168 */ 169 protected boolean marginMirroringTopBottom = false; 170 171 /** Content of JavaScript onLoad function */ 172 protected String javaScript_onLoad = null; 173 174 /** Content of JavaScript onUnLoad function */ 175 protected String javaScript_onUnLoad = null; 176 177 /** Style class in HTML body tag */ 178 protected String htmlStyleClass = null; 179 180 // headers, footers 181 182 /** Current pagenumber */ 183 protected int pageN = 0; 184 185 /** This is a chapter number in case ChapterAutoNumber is used. */ 186 protected int chapternumber = 0; 187 188 // constructor 189 190 /** 191 * Constructs a new <CODE>Document</CODE> -object. 192 */ 193 194 public Document() { 195 this(PageSize.A4); 196 } 197 198 /** 199 * Constructs a new <CODE>Document</CODE> -object. 200 * 201 * @param pageSize 202 * the pageSize 203 */ 204 205 public Document(Rectangle pageSize) { 206 this(pageSize, 36, 36, 36, 36); 207 } 208 209 /** 210 * Constructs a new <CODE>Document</CODE> -object. 211 * 212 * @param pageSize 213 * the pageSize 214 * @param marginLeft 215 * the margin on the left 216 * @param marginRight 217 * the margin on the right 218 * @param marginTop 219 * the margin on the top 220 * @param marginBottom 221 * the margin on the bottom 222 */ 223 224 public Document(Rectangle pageSize, float marginLeft, float marginRight, 225 float marginTop, float marginBottom) { 226 this.pageSize = pageSize; 227 this.marginLeft = marginLeft; 228 this.marginRight = marginRight; 229 this.marginTop = marginTop; 230 this.marginBottom = marginBottom; 231 } 232 233 // listener methods 234 235 /** 236 * Adds a <CODE>DocListener</CODE> to the <CODE>Document</CODE>. 237 * 238 * @param listener 239 * the new DocListener. 240 */ 241 242 public void addDocListener(DocListener listener) { 243 listeners.add(listener); 244 } 245 246 /** 247 * Removes a <CODE>DocListener</CODE> from the <CODE>Document</CODE>. 248 * 249 * @param listener 250 * the DocListener that has to be removed. 251 */ 252 253 public void removeDocListener(DocListener listener) { 254 listeners.remove(listener); 255 } 256 257 // methods implementing the DocListener interface 258 259 /** 260 * Adds an <CODE>Element</CODE> to the <CODE>Document</CODE>. 261 * 262 * @param element 263 * the <CODE>Element</CODE> to add 264 * @return <CODE>true</CODE> if the element was added, <CODE>false 265 * </CODE> if not 266 * @throws DocumentException 267 * when a document isn't open yet, or has been closed 268 */ 269 270 public boolean add(Element element) throws DocumentException { 271 if (close) { 272 throw new DocumentException(MessageLocalization.getComposedMessage("the.document.has.been.closed.you.can.t.add.any.elements")); 273 } 274 if (!open && element.isContent()) { 275 throw new DocumentException(MessageLocalization.getComposedMessage("the.document.is.not.open.yet.you.can.only.add.meta.information")); 276 } 277 boolean success = false; 278 if (element instanceof ChapterAutoNumber) { 279 chapternumber = ((ChapterAutoNumber)element).setAutomaticNumber(chapternumber); 280 } 281 for (DocListener listener : listeners) { 282 success |= listener.add(element); 283 } 284 if (element instanceof LargeElement) { 285 LargeElement e = (LargeElement)element; 286 if (!e.isComplete()) 287 e.flushContent(); 288 } 289 return success; 290 } 291 292 /** 293 * Opens the document. 294 * <P> 295 * Once the document is opened, you can't write any Header- or 296 * Meta-information anymore. You have to open the document before you can 297 * begin to add content to the body of the document. 298 */ 299 300 public void open() { 301 if (!close) { 302 open = true; 303 } 304 for (DocListener listener : listeners) { 305 listener.setPageSize(pageSize); 306 listener.setMargins(marginLeft, marginRight, marginTop, 307 marginBottom); 308 listener.open(); 309 } 310 } 311 312 /** 313 * Sets the pagesize. 314 * 315 * @param pageSize 316 * the new pagesize 317 * @return a <CODE>boolean</CODE> 318 */ 319 320 public boolean setPageSize(Rectangle pageSize) { 321 this.pageSize = pageSize; 322 for (DocListener listener : listeners) { 323 listener.setPageSize(pageSize); 324 } 325 return true; 326 } 327 328 /** 329 * Sets the margins. 330 * 331 * @param marginLeft 332 * the margin on the left 333 * @param marginRight 334 * the margin on the right 335 * @param marginTop 336 * the margin on the top 337 * @param marginBottom 338 * the margin on the bottom 339 * @return a <CODE>boolean</CODE> 340 */ 341 342 public boolean setMargins(float marginLeft, float marginRight, 343 float marginTop, float marginBottom) { 344 this.marginLeft = marginLeft; 345 this.marginRight = marginRight; 346 this.marginTop = marginTop; 347 this.marginBottom = marginBottom; 348 for (DocListener listener : listeners) { 349 listener.setMargins(marginLeft, marginRight, marginTop, 350 marginBottom); 351 } 352 return true; 353 } 354 355 /** 356 * Signals that an new page has to be started. 357 * 358 * @return <CODE>true</CODE> if the page was added, <CODE>false</CODE> 359 * if not. 360 */ 361 362 public boolean newPage() { 363 if (!open || close) { 364 return false; 365 } 366 for (DocListener listener : listeners) { 367 listener.newPage(); 368 } 369 return true; 370 } 371 372 /** 373 * Sets the page number to 0. 374 */ 375 376 public void resetPageCount() { 377 pageN = 0; 378 for (DocListener listener: listeners) { 379 listener.resetPageCount(); 380 } 381 } 382 383 /** 384 * Sets the page number. 385 * 386 * @param pageN 387 * the new page number 388 */ 389 390 public void setPageCount(int pageN) { 391 this.pageN = pageN; 392 for (DocListener listener: listeners) { 393 listener.setPageCount(pageN); 394 } 395 } 396 397 /** 398 * Returns the current page number. 399 * 400 * @return the current page number 401 */ 402 403 public int getPageNumber() { 404 return this.pageN; 405 } 406 407 /** 408 * Closes the document. 409 * <P> 410 * Once all the content has been written in the body, you have to close the 411 * body. After that nothing can be written to the body anymore. 412 */ 413 414 public void close() { 415 if (!close) { 416 open = false; 417 close = true; 418 } 419 for (DocListener listener : listeners) { 420 listener.close(); 421 } 422 } 423 424 // methods concerning the header or some meta information 425 426 /** 427 * Adds a user defined header to the document. 428 * 429 * @param name 430 * the name of the header 431 * @param content 432 * the content of the header 433 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 434 */ 435 436 public boolean addHeader(String name, String content) { 437 try { 438 return add(new Header(name, content)); 439 } catch (DocumentException de) { 440 throw new ExceptionConverter(de); 441 } 442 } 443 444 /** 445 * Adds the title to a Document. 446 * 447 * @param title 448 * the title 449 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 450 */ 451 452 public boolean addTitle(String title) { 453 try { 454 return add(new Meta(Element.TITLE, title)); 455 } catch (DocumentException de) { 456 throw new ExceptionConverter(de); 457 } 458 } 459 460 /** 461 * Adds the subject to a Document. 462 * 463 * @param subject 464 * the subject 465 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 466 */ 467 468 public boolean addSubject(String subject) { 469 try { 470 return add(new Meta(Element.SUBJECT, subject)); 471 } catch (DocumentException de) { 472 throw new ExceptionConverter(de); 473 } 474 } 475 476 /** 477 * Adds the keywords to a Document. 478 * 479 * @param keywords 480 * adds the keywords to the document 481 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 482 */ 483 484 public boolean addKeywords(String keywords) { 485 try { 486 return add(new Meta(Element.KEYWORDS, keywords)); 487 } catch (DocumentException de) { 488 throw new ExceptionConverter(de); 489 } 490 } 491 492 /** 493 * Adds the author to a Document. 494 * 495 * @param author 496 * the name of the author 497 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 498 */ 499 500 public boolean addAuthor(String author) { 501 try { 502 return add(new Meta(Element.AUTHOR, author)); 503 } catch (DocumentException de) { 504 throw new ExceptionConverter(de); 505 } 506 } 507 508 /** 509 * Adds the creator to a Document. 510 * 511 * @param creator 512 * the name of the creator 513 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 514 */ 515 516 public boolean addCreator(String creator) { 517 try { 518 return add(new Meta(Element.CREATOR, creator)); 519 } catch (DocumentException de) { 520 throw new ExceptionConverter(de); 521 } 522 } 523 524 /** 525 * Adds the producer to a Document. 526 * 527 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 528 */ 529 530 public boolean addProducer() { 531 try { 532 return add(new Meta(Element.PRODUCER, getVersion())); 533 } catch (DocumentException de) { 534 throw new ExceptionConverter(de); 535 } 536 } 537 538 /** 539 * Adds the current date and time to a Document. 540 * 541 * @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise 542 */ 543 544 public boolean addCreationDate() { 545 try { 546 /* bugfix by 'taqua' (Thomas) */ 547 final SimpleDateFormat sdf = new SimpleDateFormat( 548 "EEE MMM dd HH:mm:ss zzz yyyy"); 549 return add(new Meta(Element.CREATIONDATE, sdf.format(new Date()))); 550 } catch (DocumentException de) { 551 throw new ExceptionConverter(de); 552 } 553 } 554 555 // methods to get the layout of the document. 556 557 /** 558 * Returns the left margin. 559 * 560 * @return the left margin 561 */ 562 563 public float leftMargin() { 564 return marginLeft; 565 } 566 567 /** 568 * Return the right margin. 569 * 570 * @return the right margin 571 */ 572 573 public float rightMargin() { 574 return marginRight; 575 } 576 577 /** 578 * Returns the top margin. 579 * 580 * @return the top margin 581 */ 582 583 public float topMargin() { 584 return marginTop; 585 } 586 587 /** 588 * Returns the bottom margin. 589 * 590 * @return the bottom margin 591 */ 592 593 public float bottomMargin() { 594 return marginBottom; 595 } 596 597 /** 598 * Returns the lower left x-coordinate. 599 * 600 * @return the lower left x-coordinate 601 */ 602 603 public float left() { 604 return pageSize.getLeft(marginLeft); 605 } 606 607 /** 608 * Returns the upper right x-coordinate. 609 * 610 * @return the upper right x-coordinate 611 */ 612 613 public float right() { 614 return pageSize.getRight(marginRight); 615 } 616 617 /** 618 * Returns the upper right y-coordinate. 619 * 620 * @return the upper right y-coordinate 621 */ 622 623 public float top() { 624 return pageSize.getTop(marginTop); 625 } 626 627 /** 628 * Returns the lower left y-coordinate. 629 * 630 * @return the lower left y-coordinate 631 */ 632 633 public float bottom() { 634 return pageSize.getBottom(marginBottom); 635 } 636 637 /** 638 * Returns the lower left x-coordinate considering a given margin. 639 * 640 * @param margin 641 * a margin 642 * @return the lower left x-coordinate 643 */ 644 645 public float left(float margin) { 646 return pageSize.getLeft(marginLeft + margin); 647 } 648 649 /** 650 * Returns the upper right x-coordinate, considering a given margin. 651 * 652 * @param margin 653 * a margin 654 * @return the upper right x-coordinate 655 */ 656 657 public float right(float margin) { 658 return pageSize.getRight(marginRight + margin); 659 } 660 661 /** 662 * Returns the upper right y-coordinate, considering a given margin. 663 * 664 * @param margin 665 * a margin 666 * @return the upper right y-coordinate 667 */ 668 669 public float top(float margin) { 670 return pageSize.getTop(marginTop + margin); 671 } 672 673 /** 674 * Returns the lower left y-coordinate, considering a given margin. 675 * 676 * @param margin 677 * a margin 678 * @return the lower left y-coordinate 679 */ 680 681 public float bottom(float margin) { 682 return pageSize.getBottom(marginBottom + margin); 683 } 684 685 /** 686 * Gets the pagesize. 687 * 688 * @return the page size 689 */ 690 691 public Rectangle getPageSize() { 692 return this.pageSize; 693 } 694 695 /** 696 * Checks if the document is open. 697 * 698 * @return <CODE>true</CODE> if the document is open 699 */ 700 public boolean isOpen() { 701 return open; 702 } 703 704 /** 705 * Gets the product name. 706 * This method may only be changed by Paulo Soares and/or Bruno Lowagie. 707 * @return the product name 708 * @since 2.1.6 709 */ 710 public static final String getProduct() { 711 return ITEXT; 712 } 713 714 /** 715 * Gets the release number. 716 * This method may only be changed by Paulo Soares and/or Bruno Lowagie. 717 * @return the product name 718 * @since 2.1.6 719 */ 720 public static final String getRelease() { 721 return RELEASE; 722 } 723 724 /** 725 * Returns the iText version as shown in the producer line. 726 * iText is a product developed by 1T3XT BVBA. 727 * 1T3XT requests that you retain the iText producer line 728 * in every PDF that is created or manipulated using iText. 729 * @return iText version 730 */ 731 public static final String getVersion() { 732 return ITEXT_VERSION; 733 } 734 735 /** 736 * Adds a JavaScript onLoad function to the HTML body tag 737 * 738 * @param code 739 * the JavaScript code to be executed on load of the HTML page 740 */ 741 742 public void setJavaScript_onLoad(String code) { 743 this.javaScript_onLoad = code; 744 } 745 746 /** 747 * Gets the JavaScript onLoad command. 748 * 749 * @return the JavaScript onLoad command 750 */ 751 752 public String getJavaScript_onLoad() { 753 return this.javaScript_onLoad; 754 } 755 756 /** 757 * Adds a JavaScript onUnLoad function to the HTML body tag 758 * 759 * @param code 760 * the JavaScript code to be executed on unload of the HTML page 761 */ 762 763 public void setJavaScript_onUnLoad(String code) { 764 this.javaScript_onUnLoad = code; 765 } 766 767 /** 768 * Gets the JavaScript onUnLoad command. 769 * 770 * @return the JavaScript onUnLoad command 771 */ 772 773 public String getJavaScript_onUnLoad() { 774 return this.javaScript_onUnLoad; 775 } 776 777 /** 778 * Adds a style class to the HTML body tag 779 * 780 * @param htmlStyleClass 781 * the style class for the HTML body tag 782 */ 783 784 public void setHtmlStyleClass(String htmlStyleClass) { 785 this.htmlStyleClass = htmlStyleClass; 786 } 787 788 /** 789 * Gets the style class of the HTML body tag 790 * 791 * @return the style class of the HTML body tag 792 */ 793 794 public String getHtmlStyleClass() { 795 return this.htmlStyleClass; 796 } 797 798 /** 799 * Set the margin mirroring. It will mirror right/left margins for odd/even pages. 800 * 801 * @param marginMirroring 802 * <CODE>true</CODE> to mirror the margins 803 * @return always <CODE>true</CODE> 804 */ 805 public boolean setMarginMirroring(boolean marginMirroring) { 806 this.marginMirroring = marginMirroring; 807 DocListener listener; 808 for (Object element : listeners) { 809 listener = (DocListener) element; 810 listener.setMarginMirroring(marginMirroring); 811 } 812 return true; 813 } 814 815 /** 816 * Set the margin mirroring. It will mirror top/bottom margins for odd/even pages. 817 * 818 * @param marginMirroringTopBottom 819 * <CODE>true</CODE> to mirror the margins 820 * @return always <CODE>true</CODE> 821 * @since 2.1.6 822 */ 823 public boolean setMarginMirroringTopBottom(boolean marginMirroringTopBottom) { 824 this.marginMirroringTopBottom = marginMirroringTopBottom; 825 DocListener listener; 826 for (Object element : listeners) { 827 listener = (DocListener) element; 828 listener.setMarginMirroringTopBottom(marginMirroringTopBottom); 829 } 830 return true; 831 } 832 833 /** 834 * Gets the margin mirroring flag. 835 * 836 * @return the margin mirroring flag 837 */ 838 public boolean isMarginMirroring() { 839 return marginMirroring; 840 } 841}