blob: 3c8d70948e6fc9247cf1356ae125ec527ead6a03 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2015 David Green and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* David Green - initial API and implementation
* Torkild U. Resheim - bugs 337405, 336592, 336683, 336813
*******************************************************************************/
package org.eclipse.mylyn.wikitext.parser.builder;
import java.io.Writer;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.TreeMap;
import java.util.logging.Logger;
import org.eclipse.mylyn.wikitext.parser.Attributes;
import org.eclipse.mylyn.wikitext.parser.ImageAttributes;
import org.eclipse.mylyn.wikitext.parser.LinkAttributes;
import org.eclipse.mylyn.wikitext.parser.ListAttributes;
import org.eclipse.mylyn.wikitext.parser.TableAttributes;
import org.eclipse.mylyn.wikitext.parser.TableCellAttributes;
import org.eclipse.mylyn.wikitext.parser.TableRowAttributes;
import org.eclipse.mylyn.wikitext.parser.css.CssParser;
import org.eclipse.mylyn.wikitext.parser.css.CssRule;
import org.eclipse.mylyn.wikitext.parser.outline.OutlineItem;
import org.eclipse.mylyn.wikitext.util.XmlStreamWriter;
/**
* A document builder that produces XSL-FO output. XSL-FO is suitable for conversion to other formats such as PDF.
*
* @see XslfoDocumentBuilder.Configuration Configuration for configurable settings
* @see <a href="http://www.w3.org/TR/2001/REC-xsl-20011015/">XSL-FO 1.0 specification</a>
* @see <a href="http://en.wikipedia.org/wiki/XSL_Formatting_Objects">XSL-FO (WikiPedia)</a>
* @see <a href="http://www.w3schools.com/xslfo/default.asp">XSL-FO Tutorial</a>
* @author David Green
* @author Torkild U. Resheim
* @since 3.0
*/
public class XslfoDocumentBuilder extends AbstractXmlDocumentBuilder {
private static final String CSS_RULE_BORDER_STYLE = "border-style"; //$NON-NLS-1$
private static final String CSS_RULE_BORDER_WIDTH = "border-width";; //$NON-NLS-1$
private static final String CSS_RULE_BORDER_COLOR = "border-color";; //$NON-NLS-1$
private static final String CSS_RULE_BACKGROUND_COLOR = "background-color"; //$NON-NLS-1$
private static final String CSS_RULE_COLOR = "color"; //$NON-NLS-1$
private static final String CSS_RULE_VERTICAL_ALIGN = "vertical-align"; //$NON-NLS-1$
private static final String CSS_RULE_TEXT_ALIGN = "text-align"; //$NON-NLS-1$
private static final String CSS_RULE_TEXT_DECORATION = "text-decoration"; //$NON-NLS-1$
private static final String CSS_RULE_FONT_FAMILY = "font-family"; //$NON-NLS-1$
private static final String CSS_RULE_FONT_SIZE = "font-size"; //$NON-NLS-1$
private static final String CSS_RULE_FONT_WEIGHT = "font-weight"; //$NON-NLS-1$
private static final String CSS_RULE_FONT_STYLE = "font-style"; //$NON-NLS-1$
private static final char[] BULLET_CHARS = new char[] { '\u2022' };
private static Map<BlockType, String> blockTypeToCssStyles = new HashMap<BlockType, String>();
static {
blockTypeToCssStyles.put(BlockType.CODE, "font-family: monospace;"); //$NON-NLS-1$
blockTypeToCssStyles.put(BlockType.PREFORMATTED, "font-family: monospace;"); //$NON-NLS-1$
blockTypeToCssStyles.put(BlockType.TABLE_CELL_HEADER, "font-weight: bold;"); //$NON-NLS-1$
}
private static Map<SpanType, String> spanTypeToCssStyles = new HashMap<SpanType, String>();
static {
spanTypeToCssStyles.put(SpanType.STRONG, "font-weight: bold;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.BOLD, "font-weight: bold;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.MARK, "font-style: italic;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.MONOSPACE, "font-family: monospace;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.CODE, "font-family: monospace;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.CITATION, "font-style: italic;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.EMPHASIS, "font-style: italic;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.ITALIC, "font-style: italic;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.DELETED, "text-decoration: line-through;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.INSERTED, "text-decoration: underline;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.UNDERLINED, "text-decoration: underline;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.SUBSCRIPT, "vertical-align: sub;"); //$NON-NLS-1$
spanTypeToCssStyles.put(SpanType.SUPERSCRIPT, "vertical-align: super;"); //$NON-NLS-1$
}
private final String foNamespaceUri = "http://www.w3.org/1999/XSL/Format"; //$NON-NLS-1$
private boolean pageOpen = false;
private int h1Count = 0;
private final Stack<ElementInfo> elementInfos = new Stack<ElementInfo>();
private Configuration configuration = new Configuration();
private OutlineItem outline;
public XslfoDocumentBuilder(Writer out) {
super(out);
}
public XslfoDocumentBuilder(XmlStreamWriter writer) {
super(writer);
}
@Override
public void acronym(String text, String definition) {
characters(text);
}
/**
*
*/
public OutlineItem getOutline() {
return outline;
}
/**
* If an outline item is set, the document builder will output XSL:FO bookmarks at the beginning of the resulting
* document.
*
* @param outline
* the root outline item.
*/
public void setOutline(OutlineItem outline) {
this.outline = outline;
}
private static class ElementInfo {
int size = 1;
}
private static class SpanInfo extends ElementInfo {
@SuppressWarnings("unused")
final SpanType type;
public SpanInfo(SpanType type) {
super();
this.type = type;
}
}
private static class BlockInfo extends ElementInfo {
final BlockType type;
int listItemCount;
BlockInfo previousChild;
public BlockInfo(BlockType type) {
this.type = type;
}
}
@Override
public void beginBlock(BlockType type, Attributes attributes) {
BlockInfo thisInfo = new BlockInfo(type);
BlockInfo parentBlock = findCurrentBlock();
String cssStyles = blockTypeToCssStyles.get(type);
Map<String, String> attrs = cssStyles == null ? null : attributesFromCssStyles(cssStyles);
if (attributes.getCssStyle() != null) {
Map<String, String> otherAttrs = attributesFromCssStyles(attributes.getCssStyle());
if (attrs == null) {
attrs = otherAttrs;
} else if (!otherAttrs.isEmpty()) {
attrs.putAll(otherAttrs);
}
}
switch (type) {
case DEFINITION_LIST:
case BULLETED_LIST:
case NUMERIC_LIST:
writer.writeStartElement(foNamespaceUri, "list-block"); //$NON-NLS-1$
writer.writeAttribute("provisional-label-separation", "0.2em"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("provisional-distance-between-starts", "1.2em"); //$NON-NLS-1$ //$NON-NLS-2$
if (findBlockInfo(BlockType.LIST_ITEM) == null) {
addSpaceBefore();
}
break;
case DEFINITION_ITEM:
if (parentBlock == null || parentBlock.type != BlockType.DEFINITION_LIST) {
throw new IllegalStateException();
}
boolean firstItem = false;
if (parentBlock.previousChild != null && parentBlock.previousChild.type == BlockType.DEFINITION_TERM) {
firstItem = true;
writer.writeEndElement(); // list-item-label
--parentBlock.size;
writer.writeStartElement(foNamespaceUri, "list-item-body"); //$NON-NLS-1$
++parentBlock.size;
writer.writeAttribute("start-indent", "body-start()"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeEmptyElement(foNamespaceUri, "block"); //$NON-NLS-1$
}
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
writer.writeAttribute("space-before", firstItem ? "1.2em" : "0.2em"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
break;
case DEFINITION_TERM:
if (parentBlock == null || parentBlock.type != BlockType.DEFINITION_LIST) {
throw new IllegalStateException();
}
if (parentBlock.previousChild != null && parentBlock.previousChild.type == BlockType.DEFINITION_ITEM) {
writer.writeEndElement(); // list-item-body
--parentBlock.size;
writer.writeEndElement(); // list-item
--parentBlock.size;
}
if (parentBlock.previousChild == null || parentBlock.previousChild.type != BlockType.DEFINITION_TERM) {
writer.writeStartElement(foNamespaceUri, "list-item"); //$NON-NLS-1$
writer.writeAttribute("space-before", "0.2em"); //$NON-NLS-1$ //$NON-NLS-2$
++parentBlock.size;
writer.writeStartElement(foNamespaceUri, "list-item-label"); //$NON-NLS-1$
writer.writeAttribute("end-indent", "label-end()"); //$NON-NLS-1$ //$NON-NLS-2$
++parentBlock.size;
}
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
if (attrs == null || !attrs.containsKey("font-weight")) { //$NON-NLS-1$
writer.writeAttribute("font-weight", "bold"); //$NON-NLS-1$//$NON-NLS-2$
}
break;
case LIST_ITEM:
BlockInfo listInfo = getListBlockInfo();
++listInfo.listItemCount;
writer.writeStartElement(foNamespaceUri, "list-item"); //$NON-NLS-1$
// addSpaceBefore();
writer.writeStartElement(foNamespaceUri, "list-item-label"); //$NON-NLS-1$
writer.writeAttribute("end-indent", "label-end()"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
configureFontSize(0);
// FIXME: nested list numbering, list style
if (listInfo.type == BlockType.NUMERIC_LIST) {
if (attributes instanceof ListAttributes) {
// start attribute
ListAttributes listAttributes = (ListAttributes) attributes;
if (listAttributes.getStart() != null) {
try {
thisInfo.listItemCount = Integer.parseInt(listAttributes.getStart(), 10) - 1;
} catch (NumberFormatException e) {
// ignore
}
}
}
writer.writeCharacters(String.format("%s.", listInfo.listItemCount)); //$NON-NLS-1$
} else {
writer.writeCharacters(BULLET_CHARS, 0, BULLET_CHARS.length);
}
writer.writeEndElement(); // block
writer.writeEndElement(); // list-item-label
writer.writeStartElement(foNamespaceUri, "list-item-body"); //$NON-NLS-1$
++thisInfo.size;
writer.writeAttribute("start-indent", "body-start()"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
configureFontSize(0);
++thisInfo.size;
break;
case FOOTNOTE:
case PARAGRAPH:
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
addSpaceBefore();
break;
case CODE:
case PREFORMATTED:
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
writer.writeAttribute("hyphenate", "false"); //$NON-NLS-1$ //$NON-NLS-2$
// writer.writeAttribute("wrap-option", "no-wrap"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("white-space-collapse", "false"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("white-space-treatment", "preserve"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("linefeed-treatment", "preserve"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("text-align", "start"); //$NON-NLS-1$ //$NON-NLS-2$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
addSpaceBefore();
break;
case QUOTE:
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
// indent
indentLeftAndRight(attrs, "2em"); //$NON-NLS-1$
addSpaceBefore();
break;
case DIV:
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
// no space before
break;
case INFORMATION:
case NOTE:
case TIP:
case WARNING:
case PANEL:
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
indentLeftAndRight(attrs, "2em"); //$NON-NLS-1$
addSpaceBefore();
// create the titled panel effect if a title is specified
if (attributes.getTitle() != null || configuration.panelText) {
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (configuration.panelText) {
String text = null;
switch (type) {
case NOTE:
text = Messages.getString("XslfoDocumentBuilder.Note"); //$NON-NLS-1$
break;
case TIP:
text = Messages.getString("XslfoDocumentBuilder.Tip"); //$NON-NLS-1$
break;
case WARNING:
text = Messages.getString("XslfoDocumentBuilder.Warning"); //$NON-NLS-1$
break;
}
if (text != null) {
writer.writeStartElement(foNamespaceUri, "inline"); //$NON-NLS-1$
writer.writeAttribute("font-style", "italic"); //$NON-NLS-1$//$NON-NLS-2$
characters(text);
writer.writeEndElement(); // inline
}
}
if (attributes.getTitle() != null) {
writer.writeStartElement(foNamespaceUri, "inline"); //$NON-NLS-1$
writer.writeAttribute("font-weight", "bold"); //$NON-NLS-1$//$NON-NLS-2$
characters(attributes.getTitle());
writer.writeEndElement(); // inline
}
writer.writeEndElement(); // block
}
break;
case TABLE:
writer.writeStartElement(foNamespaceUri, "table"); //$NON-NLS-1$
applyTableAttributes(attributes);
writer.writeStartElement(foNamespaceUri, "table-body"); //$NON-NLS-1$
++thisInfo.size;
break;
case TABLE_CELL_HEADER:
case TABLE_CELL_NORMAL:
writer.writeStartElement(foNamespaceUri, "table-cell"); //$NON-NLS-1$
applyTableCellAttributes(attributes);
writer.writeAttribute("padding-left", "2pt"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("padding-right", "2pt"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("padding-top", "2pt"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("padding-bottom", "2pt"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (attrs == null || !attrs.containsKey("font-size")) { //$NON-NLS-1$
configureFontSize(0);
}
++thisInfo.size;
break;
case TABLE_ROW:
writer.writeStartElement(foNamespaceUri, "table-row"); //$NON-NLS-1$
applyTableRowAttributes(attributes);
break;
default:
throw new IllegalStateException(type.name());
}
if (attrs != null) {
// output attributes with stable order
for (Entry<String, String> ent : new TreeMap<String, String>(attrs).entrySet()) {
writer.writeAttribute(ent.getKey(), ent.getValue());
}
}
if (parentBlock != null) {
parentBlock.previousChild = thisInfo;
}
elementInfos.push(thisInfo);
}
private void indentLeftAndRight(Map<String, String> attrs, String indentSize) {
if (attrs == null || !attrs.containsKey("margin-left")) { //$NON-NLS-1$
writer.writeAttribute("margin-left", indentSize); //$NON-NLS-1$
}
if (attrs == null || !attrs.containsKey("margin-right")) { //$NON-NLS-1$
writer.writeAttribute("margin-right", indentSize); //$NON-NLS-1$
}
}
private void configureFontSize(int level) {
writer.writeAttribute("font-size", String.format("%spt", configuration.fontSizes[level])); //$NON-NLS-1$ //$NON-NLS-2$
}
private void addSpaceBefore() {
writer.writeAttribute("space-before.optimum", "1em"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("space-before.minimum", "0.8em"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("space-before.maximum", "1.2em"); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public void endBlock() {
ElementInfo elementInfo = elementInfos.pop();
if (!(elementInfo instanceof BlockInfo)) {
throw new IllegalStateException();
}
close(elementInfo);
}
private void close(ElementInfo elementInfo) {
while (elementInfo.size > 0) {
--elementInfo.size;
writer.writeEndElement();
}
}
private void applyTableAttributes(Attributes attributes) {
// applyAttributes(attributes);
boolean haveWidth = false;
if (attributes instanceof TableAttributes) {
TableAttributes tableAttributes = (TableAttributes) attributes;
if (tableAttributes.getBgcolor() != null) {
writer.writeAttribute(CSS_RULE_BACKGROUND_COLOR, tableAttributes.getBgcolor());
}
// FIXME border
// if (tableAttributes.getBorder() != null) {
// writer.writeAttribute("border", tableAttributes.getBorder()); //$NON-NLS-1$
// }
// if (tableAttributes.getCellpadding() != null) {
// writer.writeAttribute("cellpadding", tableAttributes.getCellpadding()); //$NON-NLS-1$
// }
// if (tableAttributes.getCellspacing() != null) {
// writer.writeAttribute("cellspacing", tableAttributes.getCellspacing()); //$NON-NLS-1$
// }
// if (tableAttributes.getFrame() != null) {
// writer.writeAttribute("frame", tableAttributes.getFrame()); //$NON-NLS-1$
// }
// if (tableAttributes.getRules() != null) {
// writer.writeAttribute("rules", tableAttributes.getRules()); //$NON-NLS-1$
// }
// if (tableAttributes.getSummary() != null) {
// writer.writeAttribute("summary", tableAttributes.getSummary()); //$NON-NLS-1$
// }
if (tableAttributes.getWidth() != null) {
writer.writeAttribute("width", tableAttributes.getWidth()); //$NON-NLS-1$
haveWidth = true;
}
}
// FIXME default border
if (!haveWidth) {
writer.writeAttribute("width", "auto"); //$NON-NLS-1$ //$NON-NLS-2$
}
writer.writeAttribute("border-collapse", "collapse"); //$NON-NLS-1$ //$NON-NLS-2$
}
private void applyTableCellAttributes(Attributes attributes) {
if (attributes instanceof TableCellAttributes) {
TableCellAttributes cellAttributes = (TableCellAttributes) attributes;
if (cellAttributes.getBgcolor() != null) {
writer.writeAttribute(CSS_RULE_BACKGROUND_COLOR, cellAttributes.getBgcolor());
}
if (cellAttributes.getColspan() != null) {
writer.writeAttribute("number-columns-spanned", cellAttributes.getColspan()); //$NON-NLS-1$
}
if (cellAttributes.getRowspan() != null) {
writer.writeAttribute("number-rows-spanned", cellAttributes.getRowspan()); //$NON-NLS-1$
}
// Expecting values left, right, center, justify or inherit
if (cellAttributes.getAlign() != null) {
writer.writeAttribute("text-align", cellAttributes.getAlign()); //$NON-NLS-1$
}
// Vertical align may be top, middle and bottom
if (cellAttributes.getValign() != null) {
String value = cellAttributes.getAlign();
if (cellAttributes.getValign().equals("top")) { //$NON-NLS-1$
value = "before"; //$NON-NLS-1$
} else if (cellAttributes.getValign().equals("middle")) { //$NON-NLS-1$
value = "center"; //$NON-NLS-1$
} else if (cellAttributes.getValign().equals("bottom")) { //$NON-NLS-1$
value = "after"; //$NON-NLS-1$
}
if (value != null) {
writer.writeAttribute("display-align", value); //$NON-NLS-1$
}
}
}
}
private void applyTableRowAttributes(Attributes attributes) {
if (attributes instanceof TableRowAttributes) {
TableRowAttributes rowAttributes = (TableRowAttributes) attributes;
if (rowAttributes.getBgcolor() != null) {
writer.writeAttribute(CSS_RULE_BACKGROUND_COLOR, rowAttributes.getBgcolor());
}
// Vertical align may be top, middle and bottom
if (rowAttributes.getValign() != null) {
String value = rowAttributes.getAlign();
if (rowAttributes.getValign().equals("top")) { //$NON-NLS-1$
value = "before"; //$NON-NLS-1$
} else if (rowAttributes.getValign().equals("middle")) { //$NON-NLS-1$
value = "center"; //$NON-NLS-1$
} else if (rowAttributes.getValign().equals("bottom")) { //$NON-NLS-1$
value = "after"; //$NON-NLS-1$
}
if (value != null) {
writer.writeAttribute("display-align", value); //$NON-NLS-1$
}
}
}
}
private BlockInfo getListBlockInfo() {
for (int x = elementInfos.size() - 1; x >= 0; --x) {
ElementInfo elementInfo = elementInfos.get(x);
if (elementInfo instanceof BlockInfo) {
BlockInfo info = (BlockInfo) elementInfo;
if (info.type == BlockType.BULLETED_LIST || info.type == BlockType.NUMERIC_LIST
|| info.type == BlockType.DEFINITION_LIST) {
return info;
}
}
}
return null;
}
private BlockInfo findBlockInfo(BlockType type) {
for (int x = elementInfos.size() - 1; x >= 0; --x) {
ElementInfo elementInfo = elementInfos.get(x);
if (elementInfo instanceof BlockInfo) {
BlockInfo info = (BlockInfo) elementInfo;
if (info.type == type) {
return info;
}
}
}
return null;
}
private BlockInfo findCurrentBlock() {
for (int x = elementInfos.size() - 1; x >= 0; --x) {
ElementInfo elementInfo = elementInfos.get(x);
if (elementInfo instanceof BlockInfo) {
return (BlockInfo) elementInfo;
}
}
return null;
}
private void writeMargins(Margins margins, XmlStreamWriter writer) {
if (margins == null) {
return;
}
writer.writeAttribute("margin-top", String.format("%scm", margins.marginTop)); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("margin-bottom", String.format("%scm", margins.marginBottom)); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("margin-left", String.format("%scm", margins.marginLeft)); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("margin-right", String.format("%scm", margins.marginRight)); //$NON-NLS-1$ //$NON-NLS-2$
}
private void writeRegion(Region region, XmlStreamWriter writer) {
if (region == null) {
return;
}
writer.writeEmptyElement(foNamespaceUri, "region-" + region.location); //$NON-NLS-1$
writer.writeAttribute("extent", String.format("%scm", region.extent)); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("precedence", Boolean.toString(region.precedence)); //$NON-NLS-1$
if (region.name != null) {
writer.writeAttribute("region-name", region.name); //$NON-NLS-1$
}
}
@Override
public void beginDocument() {
writer.setDefaultNamespace(foNamespaceUri);
writer.writeStartElement(foNamespaceUri, "root"); //$NON-NLS-1$
writer.writeNamespace("", foNamespaceUri); //$NON-NLS-1$
writer.writeStartElement(foNamespaceUri, "layout-master-set"); //$NON-NLS-1$
writer.writeStartElement(foNamespaceUri, "simple-page-master"); //$NON-NLS-1$
writer.writeAttribute("master-name", "page-layout"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("page-height", String.format("%scm", configuration.pageHeight)); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("page-width", String.format("%scm", configuration.pageWidth)); //$NON-NLS-1$ //$NON-NLS-2$
if (configuration.getPageMargins() == null) {
writer.writeAttribute("margin", String.format("%scm", configuration.pageMargin)); //$NON-NLS-1$ //$NON-NLS-2$
} else {
writeMargins(configuration.getPageMargins(), writer);
}
writer.writeEmptyElement(foNamespaceUri, "region-body"); //$NON-NLS-1$
if (configuration.getBodyMargins() == null) {
if (hasPageFooter()) {
writer.writeAttribute("margin-bottom", "3cm"); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
writeMargins(configuration.getBodyMargins(), writer);
}
if (configuration.bodyAfterRegion == null) {
if (hasPageFooter()) {
writeRegion(new Region("after", "footer", 2, false), writer); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
writeRegion(configuration.getBodyAfterRegion(), writer);
}
writeRegion(configuration.getBodyBeforeRegion(), writer);
writeRegion(configuration.getBodyEndRegion(), writer);
writeRegion(configuration.getBodyStartRegion(), writer);
writer.writeEndElement(); // simple-page-master
writer.writeEndElement(); // layout-master-set
if (outline != null && !outline.getChildren().isEmpty()) {
writer.writeStartElement("bookmark-tree"); //$NON-NLS-1$
emitToc(writer, outline.getChildren());
writer.writeEndElement(); // bookmark-tree
}
if (configuration.getTitle() != null) {
emitTitlePage();
}
openPage();
openFlow(false);
}
private boolean hasPageFooter() {
return configuration.copyright != null || configuration.pageNumbering;
}
private void emitTitlePage() {
openPage();
openFlow(true);
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
if (configuration.title != null) {
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
writer.writeAttribute("font-weight", "bold"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("font-size", "25pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("text-align", "center"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("space-before", "19pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeCharacters(configuration.title);
writer.writeEndElement(); // block
}
if (configuration.subTitle != null) {
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
writer.writeAttribute("font-weight", "bold"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("font-size", "18pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("text-align", "center"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("space-before", "15pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeCharacters(configuration.subTitle);
writer.writeEndElement(); // block
}
if (configuration.version != null) {
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
writer.writeAttribute("font-weight", "bold"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("font-size", "14pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("text-align", "center"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("space-before", "13pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeCharacters(configuration.version);
writer.writeEndElement(); // block
}
if (configuration.date != null) {
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
writer.writeAttribute("font-weight", "bold"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("font-size", "14pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("text-align", "center"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeAttribute("space-before", "13pt"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeCharacters(configuration.date);
writer.writeEndElement(); // block
}
writer.writeEmptyElement(foNamespaceUri, "block"); //$NON-NLS-1$
writer.writeAttribute("break-after", "page"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeEndElement(); // block
closeFlow();
closePage();
}
private void openFlow(boolean titlePage) {
if (hasPageFooter()) {
final boolean hasCopyrightText = configuration.copyright != null
&& configuration.copyright.trim().length() > 0;
final boolean hasPageNumber = configuration.pageNumbering && !titlePage;
if (hasCopyrightText || hasPageNumber) {
writer.writeStartElement(foNamespaceUri, "static-content"); //$NON-NLS-1$
writer.writeAttribute("flow-name", "footer"); //$NON-NLS-1$//$NON-NLS-2$
if (hasCopyrightText) {
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
configureFontSize(0);
writer.writeAttribute("text-align", "center"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeCharacters(configuration.copyright);
writer.writeEndElement(); // block
}
if (hasPageNumber) {
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
configureFontSize(0);
writer.writeAttribute("text-align", "outside"); //$NON-NLS-1$//$NON-NLS-2$
//
// // output the section header into the footer using retrieve-marker
// writer.writeEmptyElement(foNamespaceUri, "retrieve-marker"); //$NON-NLS-1$
// writer.writeAttribute("retrieve-boundary", "page-sequence"); //$NON-NLS-1$//$NON-NLS-2$
// writer.writeAttribute("retrieve-position", "first-starting-within-page"); //$NON-NLS-1$//$NON-NLS-2$
// writer.writeAttribute("retrieve-class-name", "section-title"); //$NON-NLS-1$//$NON-NLS-2$
writer.writeEmptyElement(foNamespaceUri, "page-number"); //$NON-NLS-1$
writer.writeEndElement(); // block
}
writer.writeEndElement(); // static-content
}
}
writer.writeStartElement(foNamespaceUri, "flow"); //$NON-NLS-1$
writer.writeAttribute("flow-name", "xsl-region-body"); //$NON-NLS-1$ //$NON-NLS-2$
}
private void closeFlow() {
writer.writeEndElement(); // flow
}
private void openPage() {
pageOpen = true;
writer.writeStartElement(foNamespaceUri, "page-sequence"); //$NON-NLS-1$
writer.writeAttribute("master-reference", "page-layout"); //$NON-NLS-1$ //$NON-NLS-2$
}
private void closePage() {
writer.writeEndElement(); // page-sequence
pageOpen = false;
}
private void emitToc(XmlStreamWriter writer, List<OutlineItem> children) {
for (OutlineItem item : children) {
writer.writeStartElement("bookmark"); //$NON-NLS-1$
writer.writeAttribute("internal-destination", item.getId()); //$NON-NLS-1$
writer.writeStartElement("bookmark-title"); //$NON-NLS-1$
writer.writeCharacters(item.getLabel());
writer.writeEndElement();
if (!item.getChildren().isEmpty()) {
emitToc(writer, item.getChildren());
}
writer.writeEndElement(); // bookmark
}
}
@Override
public void endDocument() {
if (pageOpen) {
closeFlow();
closePage();
}
writer.writeEndElement(); // root
writer.close();
}
@Override
public void beginHeading(int level, Attributes attributes) {
if (level == 1 && ++h1Count > 1 && configuration.pageBreakOnHeading1) {
if (pageOpen) {
closeFlow();
closePage();
}
openPage();
openFlow(false);
}
writer.writeStartElement(foNamespaceUri, "block"); //$NON-NLS-1$
writer.writeAttribute("keep-with-next.within-column", "always"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("font-weight", "bold"); //$NON-NLS-1$ //$NON-NLS-2$
configureFontSize(level);
writer.writeAttribute("space-before.optimum", "10pt"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("space-before.minimum", "10pt * 0.8"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("space-before.maximum", "10pt * 1.2"); //$NON-NLS-1$ //$NON-NLS-2$
if (attributes.getId() != null) {
writer.writeAttribute("id", attributes.getId()); //$NON-NLS-1$
}
}
@Override
public void endHeading() {
writer.writeEndElement(); // block
}
private Map<String, String> attributesFromCssStyles(String styles) {
if (styles == null) {
return Collections.emptyMap();
}
List<CssRule> rules = new CssParser().parseBlockContent(styles);
if (rules.isEmpty()) {
return Collections.emptyMap();
}
Map<String, String> mapping = new HashMap<String, String>();
for (CssRule rule : rules) {
if (CSS_RULE_VERTICAL_ALIGN.equals(rule.name)) {
String cssValue = rule.value;
if (cssValue.equals("super")) { //$NON-NLS-1$
mapping.put("font-size", "75%"); //$NON-NLS-1$ //$NON-NLS-2$
mapping.put("baseline-shift", "super"); //$NON-NLS-1$ //$NON-NLS-2$
} else if (cssValue.equals("sub")) { //$NON-NLS-1$
mapping.put("font-size", "75%"); //$NON-NLS-1$ //$NON-NLS-2$
mapping.put("baseline-shift", "sub"); //$NON-NLS-1$ //$NON-NLS-2$
} else if (cssValue.equals("top")) { //$NON-NLS-1$
mapping.put("display-align", "before"); //$NON-NLS-1$ //$NON-NLS-2$
} else if (cssValue.equals("middle")) { //$NON-NLS-1$
mapping.put("display-align", "center"); //$NON-NLS-1$ //$NON-NLS-2$
} else if (cssValue.equals("bottom")) { //$NON-NLS-1$
mapping.put("display-align", "after"); //$NON-NLS-1$ //$NON-NLS-2$
}
} else if (CSS_RULE_TEXT_DECORATION.equals(rule.name) || //
CSS_RULE_FONT_FAMILY.equals(rule.name) || //
CSS_RULE_FONT_SIZE.equals(rule.name) || //
CSS_RULE_FONT_WEIGHT.equals(rule.name) || //
CSS_RULE_FONT_STYLE.equals(rule.name) || //
CSS_RULE_BACKGROUND_COLOR.equals(rule.name) || //
CSS_RULE_COLOR.equals(rule.name)) {
mapping.put(rule.name, rule.value);
} else if (CSS_RULE_BORDER_STYLE.equals(rule.name)) {
mapping.put(rule.name, rule.value);
} else if (CSS_RULE_BORDER_WIDTH.equals(rule.name)) {
mapping.put(rule.name, rule.value);
} else if (CSS_RULE_BORDER_COLOR.equals(rule.name)) {
mapping.put(rule.name, rule.value);
} else if (CSS_RULE_TEXT_ALIGN.equals(rule.name)) {
mapping.put(rule.name, rule.value);
}
}
return mapping;
}
@Override
public void beginSpan(SpanType type, Attributes attributes) {
final SpanInfo info = new SpanInfo(type);
elementInfos.push(info);
if (type == SpanType.LINK && attributes instanceof LinkAttributes) {
String href = ((LinkAttributes) attributes).getHref();
emitLink(attributes, href);
} else {
writer.writeStartElement(foNamespaceUri, "inline"); //$NON-NLS-1$
}
String cssStyles = spanTypeToCssStyles.get(type);
Map<String, String> attrs = cssStyles == null ? null : attributesFromCssStyles(cssStyles);
if (attributes.getCssStyle() != null) {
Map<String, String> otherAttrs = attributesFromCssStyles(attributes.getCssStyle());
if (attrs == null) {
attrs = otherAttrs;
} else if (!otherAttrs.isEmpty()) {
attrs.putAll(otherAttrs);
}
}
if (attrs != null) {
// output attributes with stable order
for (Entry<String, String> ent : new TreeMap<String, String>(attrs).entrySet()) {
writer.writeAttribute(ent.getKey(), ent.getValue());
}
}
}
@Override
public void endSpan() {
ElementInfo elementInfo = elementInfos.pop();
if (!(elementInfo instanceof SpanInfo)) {
throw new IllegalStateException();
}
close(elementInfo);
}
@Override
public void characters(String text) {
writer.writeCharacters(text);
}
@Override
public void charactersUnescaped(String literal) {
Logger.getLogger(XslfoDocumentBuilder.class.getName()).warning("escaping XML literal"); //$NON-NLS-1$
writer.writeCharacters(literal);
}
@Override
public void entityReference(String entity) {
writer.writeEntityRef(entity);
}
@Override
public void image(Attributes attributes, String url) {
// <fo:external-graphic src="url(images/editor-command-help.png)" width="auto" height="auto" content-width="auto" content-height="auto"/>
writer.writeEmptyElement(foNamespaceUri, "external-graphic"); //$NON-NLS-1$
writer.writeAttribute("src", String.format("url(%s)", makeUrlAbsolute(url))); //$NON-NLS-1$//$NON-NLS-2$
applyImageAttributes(attributes);
}
private void applyImageAttributes(Attributes attributes) {
boolean sizeSpecified = false;
boolean scaleToFit = true;
if (attributes instanceof ImageAttributes) {
ImageAttributes imageAttributes = (ImageAttributes) attributes;
if (imageAttributes.getWidth() > 0) {
sizeSpecified = true;
emitImageSize("width", imageAttributes.getWidth(), imageAttributes.isWidthPercentage()); //$NON-NLS-1$
}
if (imageAttributes.getHeight() > 0) {
sizeSpecified = true;
emitImageSize("height", imageAttributes.getHeight(), imageAttributes.isHeightPercentage()); //$NON-NLS-1$
}
}
if (!sizeSpecified) {
writer.writeAttribute("width", "100%"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("content-height", "100%"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (scaleToFit) {
writer.writeAttribute("content-width", "scale-to-fit"); //$NON-NLS-1$ //$NON-NLS-2$
writer.writeAttribute("scaling", "uniform"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
private void emitImageSize(String attributeName, int units, boolean isPercentage) {
writer.writeAttribute(attributeName, String.format("%s%s", units, isPercentage ? "%" : "px")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Override
public void imageLink(Attributes linkAttributes, Attributes imageAttributes, String href, String imageUrl) {
writer.writeStartElement(foNamespaceUri, "basic-link"); //$NON-NLS-1$
String destinationUrl = makeUrlAbsolute(href);
if (destinationUrl.startsWith("#")) { //$NON-NLS-1$
writer.writeAttribute("internal-destination", destinationUrl.substring(1)); //$NON-NLS-1$
} else {
writer.writeAttribute("external-destination", String.format("url(%s)", destinationUrl)); //$NON-NLS-1$//$NON-NLS-2$
}
image(imageAttributes, imageUrl);
writer.writeEndElement();// basic-link
}
@Override
public void lineBreak() {
// an empty block does the trick
writer.writeEmptyElement(foNamespaceUri, "block"); //$NON-NLS-1$
}
@Override
public void link(Attributes attributes, String hrefOrHashName, String text) {
emitLink(attributes, hrefOrHashName);
characters(text);
writer.writeEndElement();// basic-link
}
private void emitLink(Attributes attributes, String hrefOrHashName) {
writer.writeStartElement(foNamespaceUri, "basic-link"); //$NON-NLS-1$
String destinationUrl = makeUrlAbsolute(hrefOrHashName);
boolean internal = destinationUrl.startsWith("#"); //$NON-NLS-1$
if (internal) {
if (configuration.underlineLinks) {
writer.writeAttribute("text-decoration", "underline"); //$NON-NLS-1$ //$NON-NLS-2$
}
writer.writeAttribute("internal-destination", destinationUrl.substring(1)); //$NON-NLS-1$
} else {
if (configuration.showExternalLinks) {
if (configuration.underlineLinks) {
writer.writeAttribute("text-decoration", "underline"); //$NON-NLS-1$ //$NON-NLS-2$
}
writer.writeAttribute("external-destination", String.format("url(%s)", destinationUrl)); //$NON-NLS-1$//$NON-NLS-2$
}
}
}
/**
* The current configuration of this builder. The returned value is mutable and changes to it affect this builder's
* configuration.
*
* @see Configuration Configuration class for configurable settings
*/
public Configuration getConfiguration() {
return configuration;
}
/**
* The current configuration of this builder.
*
* @see Configuration Configuration class for configurable settings
*/
public void setConfiguration(Configuration configuration) {
if (configuration == null) {
throw new IllegalArgumentException();
}
this.configuration = configuration;
}
/**
* This type represents a XSL:FO page region.
*
* @author Torkild U. Resheim, MARINTEK
*/
public static class Region implements Cloneable {
private float extent = 3.0f;
private boolean precedence = false;
private String location = null;
private String name = null;
/**
* Creates a new region with default values.
*/
public Region() {
// Only use default values here
}
public Region(String name, float extent, boolean precedence) {
this.name = name;
this.extent = extent;
this.precedence = precedence;
}
public Region(String location, String name, float extent, boolean precedence) {
this.location = location;
this.extent = extent;
this.precedence = precedence;
this.name = name;
}
/**
* Sets the extent of the region in cm.
*
* @param extent
* the region extent in cm
*/
public void setExtent(float extent) {
this.extent = extent;
}
/**
* Return the region extent in cm. Defaults to 3cm.
*
* @return value of the region extent in cms
*/
public float getExtent() {
return extent;
}
/**
* Sets the precedence of the region. Defaults to <code>false</code>
*
* @param precedence
* the new precedence value
*/
public void setPrecedence(boolean precedence) {
this.precedence = precedence;
}
/**
* Returns whether or not the region has precedence. Defaults to <code>false</code>.
*
* @return the region precedence
*/
public boolean isPrecedence() {
return precedence;
}
/**
* Assigns a name to the region. The default is to have no name.
*
* @param name
* the region name
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the name of the region. The default is to have no name.
*
* @return the region name
*/
public String getName() {
return name;
}
}
/**
* This type represents a XSL:FO page or body margin.
*
* @author Torkild U. Resheim, MARINTEK
*/
public static class Margins implements Cloneable {
private float marginTop = 1.5f;
private float marginBottom = 1.5f;
private float marginLeft = 1.5f;
private float marginRight = 1.5f;
/**
* Creates a new set of margins with the default values.
*/
public Margins() {
// Use default values
}
/**
* Creates a new set of margins with the specified values.
*
* @param top
* value of the top margin in cm
* @param bottom
* value of the bottom margin in cm
* @param left
* value of the left margin in cm
* @param right
* value of the right margin in cm
*/
public Margins(float top, float bottom, float left, float right) {
this.marginTop = top;
this.marginBottom = bottom;
this.marginLeft = left;
this.marginRight = right;
}
/**
* Sets the <b>margin-top</b> property in cm. Defaults to 1.5cm.
*
* @param marginTop
* new value of the top margin in cm
*/
public void setMarginTop(float marginTop) {
this.marginTop = marginTop;
}
/**
* Returns the <b>margin-top</b> propert in cm. Defaults to 1.5cm.
*
* @return value of the top margin in cm.
*/
public float getMarginTop() {
return marginTop;
}
/**
* Sets the <b>margin-bottom</b> property in cm. Defaults to 1.5cm.
*
* @param marginBottom
* new value of the top margin in cm
*/
public void setMarginBottom(float marginBottom) {
this.marginBottom = marginBottom;
}
/**
* Returns the <b>margin-bottom</b> property in cm. Defaults to 1.5cm.
*
* @return value of the bottom margin in cm.
*/
public float getMarginBottom() {
return marginBottom;
}
/**
* Sets the <b>margin-left</b> property in cm. Defaults to 1.5cm.
*
* @param marginLeft
* new value of the left margin in cm
*/
public void setMarginLeft(float marginLeft) {
this.marginLeft = marginLeft;
}
/**
* Returns the <b>margin-left</b> property in cm. Defaults to 1.5cm.
*
* @return value of the left margin in cm.
*/
public float getMarginLeft() {
return marginLeft;
}
/**
* Sets the <b>margin-right</b> property in cm. Defaults to 1.5cm.
*
* @param marginRight
* new value of the right margin in cm
*/
public void setMarginRight(float marginRight) {
this.marginRight = marginRight;
}
/**
* Returns the <b>margin-right</b> property of the master page in cm. Defaults to 1.5cm.
*
* @return the master page right margin in cm.
*/
public float getMarginRight() {
return marginRight;
}
}
/**
* A class that encapsulates all configurable settings of the {@link XslfoDocumentBuilder}. This class implements
* the template design pattern via {@link Configuration#clone()}.
*
* @author David Green
* @author Torkild U. Resheim, MARINTEK
*/
public static class Configuration implements Cloneable {
private float[] fontSizes = new float[] { 12.0f, 18.0f, 15.0f, 13.2f, 12.0f, 10.4f, 8.0f };
private final float[] fontSizeMultipliers = new float[] { 1.0f, 1.5f, 1.25f, 1.1f, 1.0f, 0.83f, 0.67f };
private boolean pageBreakOnHeading1 = true;
private boolean showExternalLinks = true;
private boolean underlineLinks = false;
private boolean panelText = true;
private String title;
private String subTitle;
private String version;
private String date;
private String author;
private String copyright;
private boolean pageNumbering = true;
private float pageMargin = 1.5f;
private float pageHeight = 29.7f;
private float pageWidth = 21.0f;
private Margins pageMargins = null;
private Margins bodyMargins = null;
private Region bodyBeforeRegion = null;
private Region bodyAfterRegion = null;
private Region bodyStartRegion = null;
private Region bodyEndRegion = null;
private float referenceOrientation = 90f;
public Configuration() {
setFontSize(10.0f);
}
@Override
public Configuration clone() {
try {
return (Configuration) super.clone();
} catch (CloneNotSupportedException e) {
throw new IllegalStateException(e);
}
}
/**
* Set the base font size. The base font size is 10.0 by default
*/
public void setFontSize(float fontSize) {
fontSizes = new float[fontSizeMultipliers.length];
for (int x = 0; x < fontSizeMultipliers.length; ++x) {
fontSizes[x] = fontSizeMultipliers[x] * fontSize;
}
}
/**
* Get the base font size. The base font size is 10.0 by default
*/
public float getFontSize() {
return fontSizes[0];
}
/**
* Set the font size multipliers. Multipliers are used to determine the actual size of fonts by multiplying the
* {@link #getFontSize() base font size} by the multiplier to determine the size of a font for a heading.
*
* @param fontSizeMultipliers
* an array of size 7, where position 1-6 correspond to headings h1 to h6
*/
public void setFontSizeMultipliers(float[] fontSizeMultipliers) {
if (fontSizeMultipliers.length != 7) {
throw new IllegalArgumentException();
}
for (float fontSizeMultiplier : fontSizeMultipliers) {
if (fontSizeMultiplier < 0.2) {
throw new IllegalArgumentException();
}
}
System.arraycopy(fontSizeMultipliers, 0, this.fontSizeMultipliers, 0, 7);
}
/**
* The font size multipliers. Multipliers are used to determine the actual size of fonts by multiplying the
* {@link #getFontSize() base font size} by the multiplier to determine the size of a font for a heading.
*
* @return an array of size 7, where position 1-6 correspond to headings h1 to h6
*/
public float[] getFontSizeMultipliers() {
float[] values = new float[7];
System.arraycopy(fontSizeMultipliers, 0, values, 0, 7);
return values;
}
/**
* indicate if external link URLs should be emitted in the text. The default is true.
*/
public boolean isShowExternalLinks() {
return showExternalLinks;
}
/**
* indicate if external link URLs should be emitted in the text. The default is true.
*/
public void setShowExternalLinks(boolean showExternalLinks) {
this.showExternalLinks = showExternalLinks;
}
/**
* Indicate if links should be underlined. The default is false.
*/
public boolean isUnderlineLinks() {
return underlineLinks;
}
/**
* Indicate if links should be underlined. The default is false.
*/
public void setUnderlineLinks(boolean underlineLinks) {
this.underlineLinks = underlineLinks;
}
/**
* Indicate if h1 headings should start a new page. The default is true.
*/
public boolean isPageBreakOnHeading1() {
return pageBreakOnHeading1;
}
/**
* Indicate if h1 headings should start a new page. The default is true.
*/
public void setPageBreakOnHeading1(boolean pageBreakOnHeading1) {
this.pageBreakOnHeading1 = pageBreakOnHeading1;
}
/**
* a title to be emitted on the title page
*/
public String getTitle() {
return title;
}
/**
* a title to be emitted on the title page
*/
public void setTitle(String title) {
this.title = title;
}
/**
* a sub-title to be emitted on the title page
*/
public String getSubTitle() {
return subTitle;
}
/**
* a sub-title to be emitted on the title page
*/
public void setSubTitle(String subTitle) {
this.subTitle = subTitle;
}
/**
* indicate if the text 'Note: ', 'Tip: ', and 'Warning: ' should be added to blocks of type
* {@link BlockType#NOTE}, {@link BlockType#TIP}, and {@link BlockType#WARNING} respectively.
*/
public boolean isPanelText() {
return panelText;
}
/**
* indicate if the text 'Note: ', 'Tip: ', and 'Warning: ' should be added to blocks of type
* {@link BlockType#NOTE}, {@link BlockType#TIP}, and {@link BlockType#WARNING} respectively.
*/
public void setPanelText(boolean panelText) {
this.panelText = panelText;
}
/**
* a document version number to emit on the title page
*/
public String getVersion() {
return version;
}
/**
* a document version number to emit on the title page
*/
public void setVersion(String version) {
this.version = version;
}
/**
* a date to emit on the title page
*/
public String getDate() {
return date;
}
/**
* a date to emit on the title page
*/
public void setDate(String date) {
this.date = date;
}
/**
* an author to emit on the title page
*/
public String getAuthor() {
return author;
}
/**
* an author to emit on the title page
*/
public void setAuthor(String author) {
this.author = author;
}
/**
* a copyright to emit in the document page footer
*/
public String getCopyright() {
return copyright;
}
/**
* a copyright to emit in the document page footer
*/
public void setCopyright(String copyright) {
this.copyright = copyright;
}
/**
* indicate if pages should be numbered
*/
public boolean isPageNumbering() {
return pageNumbering;
}
/**
* indicate if pages should be numbered
*/
public void setPageNumbering(boolean pageNumbering) {
this.pageNumbering = pageNumbering;
}
/**
* The page margin in cm. Defaults to 1.5cm.
*/
public float getPageMargin() {
return pageMargin;
}
/**
* The page margin in cm. Defaults to 1.5cm.
*/
public void setPageMargin(float pageMargin) {
this.pageMargin = pageMargin;
}
/**
* The page height in cm. Defaults to A4 sizing (29.7cm)
*/
public float getPageHeight() {
return pageHeight;
}
/**
* The page height in cm. Defaults to A4 sizing (29.7cm)
*/
public void setPageHeight(float pageHeight) {
this.pageHeight = pageHeight;
}
/**
* The page width in cm. Defaults to A4 sizing (21.0cm)
*/
public float getPageWidth() {
return pageWidth;
}
/**
* The page width in cm. Defaults to A4 sizing (21.0cm)
*/
public void setPageWidth(float pageWidth) {
this.pageWidth = pageWidth;
}
/**
* Sets the <b>reference-orientation</b> property of the master page in degrees. Defaults to 90 degrees.
*
* @param referenceOrientation
* the master page orientation in degrees.
*/
public void setReferenceOrientation(float referenceOrientation) {
this.referenceOrientation = referenceOrientation;
}
/**
* The <b>reference-orientation</b> property of the master page in degrees. Defaults to 90 degrees.
*
* @return the master page orientation in degrees.
*/
public float getReferenceOrientation() {
return referenceOrientation;
}
/**
* Returns the margins of the master page.
*
* @return master page margins
*/
public Margins getPageMargins() {
return pageMargins;
}
/**
* Returns the body margins.
*
* @return body margins
*/
public Margins getBodyMargins() {
return bodyMargins;
}
/**
* Sets the page margins. This method allows each margin to be specified individually.
*
* @param pageMargins
* the page margins.
* @see #setPageMargin(float)
*/
public void setPageMargins(Margins pageMargins) {
this.pageMargins = pageMargins;
}
/**
* Sets the body margins. This method allows each margin to be specified individually.
*
* @param boduMargins
* the page margins.
*/
public void setBodyMargins(Margins bodyMargins) {
this.bodyMargins = bodyMargins;
}
/**
*
*/
public void setBodyBeforeRegion(Region region) {
region.setName("before"); //$NON-NLS-1$
this.bodyBeforeRegion = region;
}
/**
*
*/
public Region getBodyBeforeRegion() {
return bodyBeforeRegion;
}
/**
*
*/
public void setBodyAfterRegion(Region region) {
region.setName("after"); //$NON-NLS-1$
this.bodyAfterRegion = region;
}
/**
*
*/
public Region getBodyAfterRegion() {
return bodyAfterRegion;
}
/**
*
*/
public void setBodyStartRegion(Region region) {
region.setName("start"); //$NON-NLS-1$
this.bodyStartRegion = region;
}
/**
*
*/
public Region getBodyStartRegion() {
return bodyStartRegion;
}
/**
*
*/
public void setBodyEndRegion(Region region) {
region.setName("end"); //$NON-NLS-1$
this.bodyEndRegion = region;
}
/**
*
*/
public Region getBodyEndRegion() {
return bodyEndRegion;
}
}
}