package gutenberg.itext.pegdown; import com.google.common.base.Optional; import com.itextpdf.text.Chunk; import com.itextpdf.text.Element; import com.itextpdf.text.Paragraph; import gutenberg.itext.ITextUtils; import gutenberg.pegdown.TreeNavigation; import gutenberg.pegdown.plugin.AttributesNode; import gutenberg.util.Attributes; import gutenberg.util.KeyValues; import org.pegdown.ast.Node; import org.pegdown.ast.ParaNode; import java.util.List; import static gutenberg.pegdown.TreeNavigation.*; /** * @author <a href="http://twitter.com/aloyer">@aloyer</a> */ public class ParaNodeProcessor extends Processor { public static final Object PARAGRAPH_SPACING_BEFORE = "paragraph-spacing-before"; public static final Object PARAGRAPH_SPACING_AFTER = "paragraph-spacing-after"; @Override public void process(int level, Node node, InvocationContext context) { List<Element> subs = context.collectChildren(level, node); Paragraph p = new Paragraph(); for (Element sub : subs) { p.add(discardNewline(sub)); } KeyValues kvs = context.iTextContext().keyValues(); Float spacingBefore = kvs.<Float>getNullable(PARAGRAPH_SPACING_BEFORE).or(5f); Float spacingAfter = kvs.<Float>getNullable(PARAGRAPH_SPACING_AFTER).or(5f); p.setSpacingBefore(spacingBefore); p.setSpacingAfter(spacingAfter); applyAttributes(context, p); context.append(p); } private void applyAttributes(InvocationContext context, Paragraph p) { Attributes attributes = lookupAttributes(context); ITextUtils.applyAttributes(p, attributes); } private static Element discardNewline(Element sub) { if (sub instanceof Chunk) { Chunk c = (Chunk) sub; String content = c.getContent(); if (content.endsWith("\n") && content.length() < 2) { return new Chunk(" "); } } return sub; } private Attributes lookupAttributes(InvocationContext context) { TreeNavigation nav = context.treeNavigation(); Optional<TreeNavigation> attrNode = firstAncestorOfType(ParaNode.class) .then(siblingBefore()) .then(ofType(AttributesNode.class)) .query(nav); Attributes attributes; if (attrNode.isPresent()) { attributes = attrNode.get().peek(AttributesNode.class).asAttributes(); } else { attributes = new Attributes(); } return attributes; } }