package org.jboss.seam.pdf.ui; import java.io.IOException; import java.io.StringWriter; import javax.el.ValueExpression; import javax.faces.FacesException; import javax.faces.component.UIComponent; import javax.faces.component.UIComponentBase; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import org.jboss.seam.ui.util.JSF; import com.lowagie.text.Chunk; import com.lowagie.text.Document; import com.lowagie.text.DocumentException; import com.lowagie.text.Font; import com.lowagie.text.xml.simpleparser.EntitiesToUnicode; public abstract class ITextComponent extends UIComponentBase { public static final String COMPONENT_FAMILY = "org.jboss.seam.pdf"; protected String inFacet; protected Object currentFacet; /** * get the current Itext object */ abstract public Object getITextObject(); /** * signal that the component should create it's managed object * * @throws IOException * @throws DocumentException */ abstract public void createITextObject(FacesContext context) throws IOException, DocumentException; /** * remove the itext objext */ abstract public void removeITextObject(); /** * subcomponents should implement this to add child components to themselves */ abstract public void handleAdd(Object other); final public void add(Object other) { if (inFacet != null) { handleFacet(inFacet, other); } else { handleAdd(other); } } public void handleFacet(String facetName, Object obj) { currentFacet = obj; // facets.put(facetName,obj); } /** * look up the tree for an itext font */ public Font getFont() { UIFont fontComponent = (UIFont) findITextParent(this, UIFont.class); return fontComponent == null ? null : fontComponent.getFont(); } /** * look up the tree for the itext document */ public Document findDocument() { ITextComponent parent = findITextParent(this, UIDocument.class); if (parent != null) { return (Document) parent.getITextObject(); } else { return null; } } /** * find the first parent that is an itext component); */ public ITextComponent findITextParent(UIComponent parent) { return findITextParent(parent, null); } /** * find the first parent that is an itext component of a given type */ public ITextComponent findITextParent(UIComponent parent, Class<?> c) { if (parent == null) { return null; } if (parent instanceof ITextComponent) { if (c == null || c.isAssignableFrom(parent.getClass())) { return (ITextComponent) parent; } } return findITextParent(parent.getParent(), c); } /** * add a component (usually the current itext object) to the itext parent's * itext object */ public void addToITextParent(Object obj) { ITextComponent parent = findITextParent(getParent()); if (parent != null) { parent.add(obj); } else { noITextParentFound(); } } public void noITextParentFound() { throw new RuntimeException( "Couldn't find ITextComponent parent for component " + this.getClass().getName()); } public Object processFacet(String facetName) { if (inFacet != null && inFacet.equals(facetName)) { return null; } UIComponent facet = this.getFacet(facetName); Object result = null; if (facet != null) { currentFacet = null; inFacet = facetName; try { encode(FacesContext.getCurrentInstance(), facet); } catch (Exception e) { throw new RuntimeException(e); } finally { inFacet = null; result = currentFacet; currentFacet = null; } } return result; } public Object valueBinding(FacesContext context, String property, Object defaultValue) { Object value = defaultValue; ValueExpression expression = getValueExpression(property); if (expression != null) { value = expression.getValue(context.getELContext()); } return value; } public Object valueBinding(String property, Object defaultValue) { return valueBinding(FacesContext.getCurrentInstance(), property, defaultValue); } // ------------------------------------------------------ @Override public String getFamily() { return COMPONENT_FAMILY; } @Override public boolean getRendersChildren() { return true; } @Override public void encodeBegin(FacesContext context) throws IOException { try { createITextObject(context); } catch (DocumentException e) { throw new FacesException(e); } } @Override public void encodeEnd(FacesContext context) throws IOException { Object obj = getITextObject(); if (obj != null) { addToITextParent(getITextObject()); } removeITextObject(); } @SuppressWarnings("unchecked") @Override public void encodeChildren(FacesContext context) throws IOException { for (UIComponent child : this.getChildren()) { // ugly hack to be able to capture facelets text if (child.getFamily().equals("facelets.LiteralText")) { String text = EntitiesToUnicode.decodeString(extractText(context, child)); Font font = getFont(); Chunk chunk = null; if (font == null) { chunk = new Chunk(text); } else { chunk = new Chunk(text, getFont()); } add(chunk); } else { encode(context, child); } } } public String extractText(FacesContext context, UIComponent child) throws IOException { ResponseWriter response = context.getResponseWriter(); StringWriter stringWriter = new StringWriter(); ResponseWriter cachingResponseWriter = response.cloneWithWriter(stringWriter); context.setResponseWriter(cachingResponseWriter); JSF.renderChild(context, child); context.setResponseWriter(response); return stringWriter.getBuffer().toString(); } @SuppressWarnings("unchecked") public void encode(FacesContext context, UIComponent component) throws IOException { if (!component.isRendered()) { return; } component.encodeBegin(context); if (component.getChildCount() > 0) { if (component.getRendersChildren()) { component.encodeChildren(context); } else { for (UIComponent child : component.getChildren()) { encode(context, child); } } } component.encodeEnd(context); } }