Document.java
/*
* $Id: Document.java 4106 2009-11-27 12:59:39Z blowagie $
*
* Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie.
*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the License.
*
* The Original Code is 'iText, a free JAVA-PDF library'.
*
* The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
* the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
* All Rights Reserved.
* Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
* are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
*
* Contributor(s): all the names of the contributors are added in the source code
* where applicable.
*
* Alternatively, the contents of this file may be used under the terms of the
* LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
* provisions of LGPL are applicable instead of those above. If you wish to
* allow use of your version of this file only under the terms of the LGPL
* License and not to allow others to use your version of this file under
* the MPL, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the LGPL.
* If you do not delete the provisions above, a recipient may use your version
* of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MPL as stated above or under the terms of the GNU
* Library General Public License as published by the Free Software Foundation;
* either version 2 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
* details.
*
* If you didn't download this code from the following link, you should check if
* you aren't using an obsolete version:
* https://github.com/LibrePDF/OpenPDF
*/
package org.openpdf.text;
import org.openpdf.text.error_messages.MessageLocalization;
import org.openpdf.text.pdf.PdfDate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* A generic Document class.
* <p>
* All kinds of Text-elements can be added to a <CODE>HTMLDocument</CODE>. The <CODE>Document</CODE> signals all the
* listeners when an element has been added.
* <p>
* Remark:
* <OL>
* <LI>Once a document is created you can add some meta information.
* <LI>You can also set the headers/footers.
* <LI>You have to open the document before you can write content.
* <LI>You can only write content (no more meta-formation!) once a document is
* opened.
* <LI>When you change the header/footer on a certain page, this will be
* effective starting on the next page.
* <LI>After closing the document, every listener (as well as its <CODE>
* OutputStream</CODE>) is closed too.
* </OL>
* Example: <BLOCKQUOTE>
*
* <PRE>// creation of the document with a certain size and certain margins
* <STRONG>Document document = new Document(new Rectangle(595, 842), 50, 50, 50, 50);
* </STRONG> try {
* // creation of the different writers HtmlWriter.getInstance(<STRONG>document </STRONG>, System.out);
* PdfWriter.getInstance(<STRONG>document </STRONG>, new FileOutputStream("text.pdf")); // we add some meta information
* to the document
* <STRONG>document.addAuthor("Bruno Lowagie"); </STRONG>
* <STRONG>document.addSubject("This is the result of a Test."); </STRONG>
* // we open the document for writing
* <STRONG>document.open(); </STRONG>
* <STRONG>document.add(new Paragraph("Hello world"));</STRONG>
* } catch(DocumentException de) { System.err.println(de.getMessage()); }
* <STRONG>document.close();</STRONG>
* </PRE>
*
* </BLOCKQUOTE>
*/
public class Document implements DocListener {
// membervariables
private static final String OPENPDF = "OpenPDF";
private static final String RELEASE;
private static final String OPENPDF_VERSION;
/**
* Allows the pdf documents to be produced without compression for debugging purposes.
*/
public static boolean compress = true;
/**
* When true the file access is not done through a memory mapped file. Use it if the file is too big to be mapped in
* your address space.
*/
public static boolean plainRandomAccess = false;
static {
RELEASE = getVersionNumber();
OPENPDF_VERSION = OPENPDF + " " + RELEASE;
}
/**
* The DocListener.
*/
private final List<DocListener> listeners = new ArrayList<>();
/**
* Is the document open or not?
*/
protected boolean open;
/**
* Has the document already been closed?
*/
protected boolean close;
/**
* The size of the page.
*/
protected Rectangle pageSize;
// membervariables concerning the layout
/**
* margin in x direction starting from the left
*/
protected float marginLeft = 0;
/**
* margin in x direction starting from the right
*/
protected float marginRight = 0;
/**
* margin in y direction starting from the top
*/
protected float marginTop = 0;
/**
* margin in y direction starting from the bottom
*/
protected float marginBottom = 0;
/**
* Current pagenumber
*/
protected int pageN = 0;
/**
* This is a chapter number in case ChapterAutoNumber is used.
*/
/**
* Text rendering options, including the default language of the document and a flag to enable font glyph
* substitution (if FOP is available)
*
* @since 3.1.15
*/
TextRenderingOptions textRenderingOptions = new TextRenderingOptions();
// constructor
/**
* Constructs a new <CODE>Document</CODE> -object with the A4 page size.
*/
public Document() {
this(new RectangleReadOnly(595, 842));
}
/**
* Constructs a new <CODE>Document</CODE> -object using the given rectangle as page size and default margin of 36.
*
* @param pageSize the pageSize
*/
public Document(Rectangle pageSize) {
this(pageSize, 36, 36, 36, 36);
}
/**
* Constructs a new <CODE>Document</CODE> -object.
*
* @param pageSize the pageSize
* @param marginLeft the margin on the left
* @param marginRight the margin on the right
* @param marginTop the margin on the top
* @param marginBottom the margin on the bottom
*/
public Document(Rectangle pageSize, float marginLeft, float marginRight,
float marginTop, float marginBottom) {
this.pageSize = pageSize;
this.marginLeft = marginLeft;
this.marginRight = marginRight;
this.marginTop = marginTop;
this.marginBottom = marginBottom;
}
private static String getVersionNumber() {
return "PlantUML";
}
// listener methods
// methods implementing the DocListener interface
/**
* Gets the iText version.
*
* @return iText version
*/
public static String getVersion() {
return OPENPDF_VERSION;
}
/**
* Adds a <CODE>DocListener</CODE> to the <CODE>Document</CODE>.
*
* @param listener the new DocListener.
*/
public void addDocListener(DocListener listener) {
listeners.add(listener);
}
/**
* Adds an <CODE>Element</CODE> to the <CODE>Document</CODE>.
*
* @param element the <CODE>Element</CODE> to add
* @return <CODE>true</CODE> if the element was added, <CODE>false
* </CODE> if not
* @throws DocumentException when a document isn't open yet, or has been closed
*/
public boolean add(Element element) throws DocumentException {
if (close) {
throw new DocumentException(
MessageLocalization.getComposedMessage("the.document.has.been.closed.you.can.t.add.any.elements"));
}
if (!open && element.isContent()) {
throw new DocumentException(MessageLocalization.getComposedMessage(
"the.document.is.not.open.yet.you.can.only.add.meta.information"));
}
boolean success = false;
for (DocListener listener : listeners) {
success |= listener.add(element);
}
return success;
}
/**
* Opens the document.
* <p>
* Once the document is opened, you can't write any meta-information anymore. If you change the header/footer after
* opening the document, the change will be effective starting from the second page. You have to open the document
* before you can begin to add content to the body of the document.
*/
public void open() {
if (!close) {
open = true;
}
for (DocListener listener : listeners) {
listener.setPageSize(pageSize);
listener.setMargins(marginLeft, marginRight, marginTop,
marginBottom);
listener.open();
}
}
/**
* Sets the pagesize.
* <p>
* This change will be effective starting from the next page. If you want to change the page size of the first page,
* you need to set it before opening the document.
*
* @param pageSize the new pagesize
* @return a <CODE>boolean</CODE>
*/
public boolean setPageSize(Rectangle pageSize) {
this.pageSize = pageSize;
for (DocListener listener : listeners) {
listener.setPageSize(pageSize);
}
return true;
}
/**
* Sets the margins.
* <p>
* This change will be effective starting from the next page. If you want to change margins on the first page, you
* need to set it before opening the document.
* <p>
* A new page is created when you call:
* <ul>
* <li>Document.open()</li>
* <li>Document.newPage(), only if the current page has some content, otherwise no new page will be created</li>
* </ul>
* </p>
*
* @param marginLeft the margin on the left
* @param marginRight the margin on the right
* @param marginTop the margin on the top
* @param marginBottom the margin on the bottom
* @return a <CODE>boolean</CODE>
*/
public boolean setMargins(float marginLeft, float marginRight,
float marginTop, float marginBottom) {
this.marginLeft = marginLeft;
this.marginRight = marginRight;
this.marginTop = marginTop;
this.marginBottom = marginBottom;
for (DocListener listener : listeners) {
listener.setMargins(marginLeft, marginRight, marginTop,
marginBottom);
}
return true;
}
/**
* Signals to all listeners, that a new page has to be started. New pages can only be added on already opened and
* not yet closed documents.
*
* @return <CODE>true</CODE> if the page was added, <CODE>false</CODE>
* if not.
*/
public boolean newPage() {
if (!open || close) {
return false;
}
for (DocListener listener : listeners) {
listener.newPage();
}
return true;
}
// methods concerning the header or some meta information
/**
* Closes the document.
* <p>
* Once all the content has been written in the body, you have to close the body. After that nothing can be written
* to the body anymore.
*/
@Override
public void close() {
if (!close) {
open = false;
close = true;
}
for (DocListener listener : listeners) {
listener.close();
}
}
/**
* Adds the title to a Document.
* <p/>
* In case of a PDF this will be visible in the document properties panel.
* <p/>
* In case of a HTML file this will be visible as the <CODE>title</CODE> <CODE>meta</CODE> tag in the
* <CODE>HEAD</CODE> part of the file.
* <p/>
* Shortcut method to call: <CODE>add(new Meta(Element.TITLE, title))</CODE>
*
* @param title the title
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addTitle(String title) {
try {
return add(new Meta(Element.TITLE, title));
} catch (DocumentException de) {
throw new ExceptionConverter(de);
}
}
/**
* Adds the subject to a Document.
* <p/>
* In case of a PDF this will be visible in the document properties panel.
* <p/>
* In case of a HTML file this will be visible as the <CODE>subject</CODE> <CODE>meta</CODE> tag in the
* <CODE>HEAD</CODE> part of the file.
*
* @param subject the subject
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addSubject(String subject) {
try {
return add(new Meta(Element.SUBJECT, subject));
} catch (DocumentException de) {
throw new ExceptionConverter(de);
}
}
/**
* Adds the author to a Document.
* <p/>
* In case of a PDF this will be visible in the document properties panel.
* <p/>
* In case of a HTML file this will be visible as the <CODE>author</CODE> <CODE>meta</CODE> tag in the
* <CODE>HEAD</CODE> part of the file.
*
* @param author the name of the author
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addAuthor(String author) {
try {
return add(new Meta(Element.AUTHOR, author));
} catch (DocumentException de) {
throw new ExceptionConverter(de);
}
}
/**
* Adds the producer to a Document.
* <p/>
* In case of a PDF this will be visible in the document properties panel.
* <p/>
* In case of a HTML file this will be visible as comment in the <CODE>HEAD</CODE> part of the file.
*
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addProducer() {
return this.addProducer(getVersion());
}
/**
* Adds the provided value as the producer to a Document.
* <p/>
* The default producer is <CODE>OpenPDF XX.YY.ZZ</CODE> where <CODE>XX.YY.ZZ</CODE> is the version of the OpenPDF
* library used to produce the document
* <p/>
* In case of a PDF this will be visible in the document properties panel.
* <p/>
* In case of a HTML file this will be visible as comment in the <CODE>HEAD</CODE> part of the file.
*
* @param producer new producer line value
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addProducer(final String producer) {
return add(new Meta(Element.PRODUCER, producer));
}
/**
* Adds the current date and time to a Document.
* <p/>
* In case of a PDF this will be visible in the document properties panel.
* <p/>
* In case of a HTML file this will be visible as comment in the <CODE>HEAD</CODE> part of the file.
*
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addCreationDate() {
try {
/* bugfix by 'taqua' (Thomas) */
final SimpleDateFormat sdf = new SimpleDateFormat(
"EEE MMM dd HH:mm:ss zzz yyyy");
return add(new Meta(Element.CREATIONDATE, sdf.format(new Date())));
} catch (DocumentException de) {
throw new ExceptionConverter(de);
}
}
// methods to get the layout of the document.
/**
* Adds the current date and time to a Document.
*
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addCreationDate(PdfDate date) {
try {
return add(new Meta(Element.CREATIONDATE, date.toString()));
} catch (DocumentException de) {
throw new ExceptionConverter(de);
}
}
/**
* Adds the current date and time to a Document.
*
* @return <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise
*/
public boolean addModificationDate(PdfDate date) {
try {
return add(new Meta(Element.MODIFICATIONDATE, date.toString()));
} catch (DocumentException de) {
throw new ExceptionConverter(de);
}
}
/**
* Returns the left margin.
*
* @return the left margin
*/
/**
* Return the right margin.
*
* @return the right margin
*/
/**
* Returns the top margin.
*
* @return the top margin
*/
/**
* Returns the bottom margin.
*
* @return the bottom margin
*/
/**
* Returns the lower left x-coordinate.
*
* @return the lower left x-coordinate
*/
/**
* Returns the upper right x-coordinate.
*
* @return the upper right x-coordinate
*/
/**
* Returns the upper right y-coordinate.
*
* @return the upper right y-coordinate
*/
/**
* Returns the lower left y-coordinate.
*
* @return the lower left y-coordinate
*/
/**
* Returns the lower left x-coordinate considering a given margin.
*
* @param margin a margin
* @return the lower left x-coordinate
*/
/**
* Returns the upper right x-coordinate, considering a given margin.
*
* @param margin a margin
* @return the upper right x-coordinate
*/
/**
* Returns the upper right y-coordinate, considering a given margin.
*
* @param margin a margin
* @return the upper right y-coordinate
*/
/**
* Returns the lower left y-coordinate, considering a given margin.
*
* @param margin a margin
* @return the lower left y-coordinate
*/
/**
* Gets the pagesize.
*
* @return the page size
*/
/**
* Checks if the document is open.
*
* @return <CODE>true</CODE> if the document is open
*/
public boolean isOpen() {
return open;
}
/**
* Gets the JavaScript onLoad command.
*
* @return the JavaScript onLoad command
*/
/**
* Adds a JavaScript onLoad function to the HTML body tag
*
* @param code the JavaScript code to be executed on load of the HTML page
*/
/**
* Gets the JavaScript onUnLoad command.
*
* @return the JavaScript onUnLoad command
*/
/**
* Adds a JavaScript onUnLoad function to the HTML body tag
*
* @param code the JavaScript code to be executed on unload of the HTML page
*/
/**
* Gets the style class of the HTML body tag
*
* @return the style class of the HTML body tag
*/
/**
* Adds a style class to the HTML body tag
*
* @param htmlStyleClass the style class for the HTML body tag
*/
/**
* Gets the text rendering options.
*
* @return the text rendering options
*/
public TextRenderingOptions getTextRenderingOptions() {
return textRenderingOptions;
}
/**
* Sets the text rendering options.
*
* @param textRenderingOptions the text rendering options
*/
public void setTextRenderingOptions(TextRenderingOptions textRenderingOptions) {
this.textRenderingOptions = textRenderingOptions == null ? new TextRenderingOptions() : textRenderingOptions;
}
}