package org.jboss.seam.excel.jxl;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import jxl.HeaderFooter;
import jxl.HeaderFooter.Contents;
import jxl.biff.DisplayFormat;
import jxl.biff.FontRecord;
import jxl.format.Alignment;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.Colour;
import jxl.format.Orientation;
import jxl.format.PageOrientation;
import jxl.format.PaperSize;
import jxl.format.Pattern;
import jxl.format.ScriptStyle;
import jxl.format.UnderlineStyle;
import jxl.format.VerticalAlignment;
import jxl.write.WritableFont;
import jxl.write.WriteException;
import org.jboss.seam.core.Interpolator;
import org.jboss.seam.excel.ExcelWorkbookException;
import org.jboss.seam.excel.css.CellStyle;
import org.jboss.seam.excel.ui.ExcelComponent;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
/**
* Factory for creating JExcelAPI objects
*
* @author karlsnic
*/
public class JXLFactory
{
// Class names for JExcelAPI objects
private static final String DATEFORMATS_CLASSNAME = "jxl.write.DateFormats";
private static final String NUMBERFORMATS_CLASSNAME = "jxl.write.NumberFormats";
private static final String ALIGNMENT_CLASS_NAME = "jxl.format.Alignment";
private static final String ORIENTATION_CLASS_NAME = "jxl.format.Orientation";
private static final String VERTICAL_ALIGNMENT_CLASS_NAME = "jxl.format.VerticalAlignment";
private static final String COLOR_CLASS_NAME = "jxl.format.Colour";
private static final String BORDER_CLASS_NAME = "jxl.format.Border";
private static final String BORDER_LINE_STYLE_CLASS_NAME = "jxl.format.BorderLineStyle";
private static final String PATTERN_CLASS_NAME = "jxl.format.Pattern";
private static final String PAGE_ORIENTATION_CLASS_NAME = "jxl.format.PageOrientation";
private static final String PAPER_SIZE_CLASS_NAME = "jxl.format.PaperSize";
private static final String SCRIPT_STYLE_CLASS_NAME = "jxl.format.ScriptStyle";
private static final String UNDERLINE_STYLE_CLASS_NAME = "jxl.format.UnderlineStyle";
private static final String HEADERFOOTER_COMMAND_MARKER = "#";
private static final String HEADERFOOTER_PAIR_DELIMITER = "=";
private static final String HF_CMD_FONT_SIZE = "font_size";
private static final String HF_CMD_FONT_NAME = "font_name";
private static final String HF_CMD_UNDERLINE = "underline";
private static final String HF_CMD_SUPERSCRIPT = "superscript";
private static final String HF_CMD_SUBSCRIPT = "subscript";
private static final String HF_CMD_STRIKETHROUGH = "strikethrough";
private static final String HF_CMD_SHADOW = "shadow";
private static final String HF_CMD_OUTLINE = "outline";
private static final String HF_CMD_ITALICS = "italics";
private static final String HF_CMD_DOUBLE_UNDERLINE = "double_underline";
private static final String HF_CMD_BOLD = "bold";
private static final String HF_CMD_WORKSHEET_NAME = "worksheet_name";
private static final String HF_CMD_WORKBOOK_NAME = "workbook_name";
private static final String HF_CMD_TOTAL_PAGES = "total_pages";
private static final String HF_CMD_TIME = "time";
private static final String HF_CMD_PAGE_NUMBER = "page_number";
private static final Log log = Logging.getLog(JXLFactory.class);
/**
* Checks if text is a border line style
*
* @param text The text to check
* @return True if border line style, false otherwise
*/
public static boolean isBorderLineStyle(String text)
{
return getValidContants(BORDER_LINE_STYLE_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Checks if text is a pattern
*
* @param text The text to check
* @return True if pattern, false otherwise
*/
public static boolean isPattern(String text)
{
return getValidContants(PATTERN_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Checks if text is a color
*
* @param text The text to check
* @return True if color, false otherwise
*/
public static boolean isColor(String text)
{
return getValidContants(COLOR_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Checks if text is an alignment
*
* @param text The text to check
* @return True if alignment, false otherwise
*/
public static boolean isAlignment(String text)
{
return getValidContants(ALIGNMENT_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Checks if text is an orientation
*
* @param text The text to check
* @return True if orientation, false otherwise
*/
public static boolean isOrientation(String text)
{
return getValidContants(ORIENTATION_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Checks if text is an vertical alignment
*
* @param text The text to check
* @return True if vertical alignment, false otherwise
*/
public static boolean isVerticalAlignment(String text)
{
return getValidContants(VERTICAL_ALIGNMENT_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Checks if text is an underline style
*
* @param text The text to check
* @return True if underline style, false otherwise
*/
public static boolean isUnderlineStyle(String text)
{
return getValidContants(UNDERLINE_STYLE_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Checks if text is a script style
*
* @param text The text to check
* @return True if script style, false otherwise
*/
public static boolean isScriptStyle(String text)
{
return getValidContants(SCRIPT_STYLE_CLASS_NAME).contains(text.toLowerCase());
}
/**
* Gets a list of constants from a class
*
* @param className The class to examine
* @return A list of constants
*/
private static List<String> getValidContants(String className)
{
List<String> constants = new ArrayList<String>();
if (log.isTraceEnabled())
{
log.trace("Getting valid constants from #0", className);
}
Class clazz = null;
try
{
clazz = Class.forName(className);
}
catch (ClassNotFoundException e)
{
throw new ExcelWorkbookException("Could not find class while getting valid constants", e);
}
// Loop through the fields
for (Field field : clazz.getFields())
{
int modifiers = field.getModifiers();
// Append to list if it's public and static (as most our constants are)
if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers))
{
constants.add(field.getName().toLowerCase());
}
}
return constants;
}
/**
* Gets a suggestion string of available constants from a class.
*
* @param className The class to examine
* @return The suggestion string
*/
public static String getValidConstantsSuggestion(String className)
{
List<String> constants = getValidContants(className);
StringBuffer buffer = new StringBuffer();
int i = 0;
// Loop through the fields
for (String field : constants)
{
buffer.append(i++ == 0 ? field : ", " + field);
}
return Interpolator.instance().interpolate("[#0]", buffer.toString());
}
/**
* Gets a constant from a class
*
* @param className The class name to examine
* @param fieldName The field to read
* @return The constant
* @throws NoSuchFieldException If the field is not available
*/
private static Object getConstant(String className, String fieldName) throws NoSuchFieldException
{
if (log.isTraceEnabled())
{
log.trace("Looking for constant #0 in class #1", fieldName.toUpperCase(), className);
}
try
{
return Class.forName(className).getField(fieldName.toUpperCase()).get(null);
}
catch (NoSuchFieldException e)
{
throw e;
}
catch (Exception e)
{
throw new ExcelWorkbookException(Interpolator.instance().interpolate("Could not read field #0 from class #1", fieldName, className), e);
}
}
/**
* Creates a JExcelAPI representation of an alignment
*
* @param alignment The requested alignment
* @return The alignment representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/Alignment.html">Alignment</a>
*/
public static Alignment createAlignment(String alignment)
{
if (log.isTraceEnabled())
{
log.trace("Creating alignment for #0", alignment);
}
try
{
return alignment == null ? Alignment.LEFT : (Alignment) getConstant(ALIGNMENT_CLASS_NAME, alignment.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Alignment {0} not supported, try {1}", alignment, getValidConstantsSuggestion(ALIGNMENT_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of an script style
*
* @param mask The requested script style
* @return The script style representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/ScriptStyle.html">ScriptStyle</a>
*/
private static ScriptStyle createScriptStyle(String scriptStyle)
{
if (log.isTraceEnabled())
{
log.trace("Creating script style for #0", scriptStyle);
}
try
{
return scriptStyle == null ? ScriptStyle.NORMAL_SCRIPT : (ScriptStyle) getConstant(SCRIPT_STYLE_CLASS_NAME, scriptStyle.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Script style {0} not supported, try {1}", scriptStyle, getValidConstantsSuggestion(SCRIPT_STYLE_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of an underline style
*
* @param mask The requested underline style
* @return The underline style representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/UnderlineStyle.html">UnderlineStyle</a>
*/
private static UnderlineStyle createUnderlineStyle(String underlineStyle)
{
if (log.isTraceEnabled())
{
log.trace("Creating underline style for #0", underlineStyle);
}
try
{
return underlineStyle == null ? UnderlineStyle.NO_UNDERLINE : (UnderlineStyle) getConstant(UNDERLINE_STYLE_CLASS_NAME, underlineStyle.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Underline style {0} not supported, try {1}", underlineStyle, getValidConstantsSuggestion(UNDERLINE_STYLE_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of a font
*
* @param fontspecs The font specifications
* @return The font
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/write/WritableFont.html">WritableFont</a>
*/
public static FontRecord createFont(CellStyle.Font fontspecs) throws WriteException
{
WritableFont font = null;
if (fontspecs.family != null)
{
font = new WritableFont(WritableFont.createFont(fontspecs.family));
}
else
{
font = new WritableFont(WritableFont.ARIAL);
}
if (fontspecs.pointSize != null)
{
font.setPointSize(fontspecs.pointSize);
}
if (fontspecs.color != null)
{
font.setColour(createColor(fontspecs.color));
}
if (fontspecs.bold != null)
{
font.setBoldStyle(fontspecs.bold ? WritableFont.BOLD : WritableFont.NO_BOLD);
}
if (fontspecs.italic != null)
{
font.setItalic(fontspecs.italic);
}
if (fontspecs.struckOut != null)
{
font.setStruckout(fontspecs.struckOut);
}
if (fontspecs.scriptStyle != null)
{
font.setScriptStyle(createScriptStyle(fontspecs.scriptStyle));
}
if (fontspecs.underlineStyle != null)
{
font.setUnderlineStyle(createUnderlineStyle(fontspecs.underlineStyle));
}
return font;
}
/**
* Creates a JExcelAPI number display format
*
* @param formatMask The format mask
* @return The display format
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/write/NumberFormat.html">NumberFormat</a>
*/
public static DisplayFormat createNumberFormat(String formatMask)
{
if (log.isTraceEnabled())
{
log.trace("Creating number format for mask #0", formatMask);
}
try
{
return (DisplayFormat) getConstant(NUMBERFORMATS_CLASSNAME, formatMask);
}
catch (NoSuchFieldException e)
{
// Look! An empty catch block! But this one is documented. We are using
// this to see if there is a constant
// defines for this in the class
return null;
}
}
/**
* Creates a JExcelAPI date display format
*
* @param mask The format mask
* @return The display format
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/write/DateFormat.html">DateFormat</a>
*/
public static DisplayFormat createDateFormat(String mask)
{
if (log.isTraceEnabled())
{
log.trace("Creating date format for mask #0", mask);
}
try
{
return (DisplayFormat) getConstant(DATEFORMATS_CLASSNAME, mask.toUpperCase());
}
catch (NoSuchFieldException e)
{
// Look! An empty catch block! But this one is documented. We are using
// this to see if there is a constant
// defines for this in the class
return null;
}
}
/**
* Creates a JExcelAPI representation of an color
*
* @param color The requested color
* @return The color representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/Color.html">Color</a>
*/
public static Colour createColor(String color)
{
if (log.isTraceEnabled())
{
log.trace("Creating color for #0", color);
}
// Workaround for the feature that black is... well not always black in
// Excel (ref: Andy Khan on yahoo groups)
if (color.equalsIgnoreCase("black"))
{
color = "palette_black";
}
try
{
return color == null ? Colour.AUTOMATIC : (Colour) getConstant(COLOR_CLASS_NAME, color.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Color {0} not supported, try {1}", color, getValidConstantsSuggestion(COLOR_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of an orientation
*
* @param orientation The requested orientation
* @return The orientation representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/Orientation.html">Orientation</a>
*/
public static Orientation createOrientation(String orientation)
{
if (log.isTraceEnabled())
{
log.trace("Creating orientation for #0", orientation);
}
try
{
return orientation == null ? Orientation.HORIZONTAL : (Orientation) getConstant(ORIENTATION_CLASS_NAME, orientation.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Orientation {0} not supported, try {1}", orientation, getValidConstantsSuggestion(ORIENTATION_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of a vertical alignment
*
* @param verticalAlignment The requested alignment
* @return The alignment representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/VerticalAlignment.html">VerticalAlignment</a>
*/
public static VerticalAlignment createVerticalAlignment(String verticalAlignment)
{
if (log.isTraceEnabled())
{
log.trace("Creating verical alignment for #0", verticalAlignment);
}
try
{
return verticalAlignment == null ? VerticalAlignment.BOTTOM : (VerticalAlignment) getConstant(VERTICAL_ALIGNMENT_CLASS_NAME, verticalAlignment.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Verical alignment {0} not supported, try {1}", verticalAlignment, getValidConstantsSuggestion(VERTICAL_ALIGNMENT_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of a border
*
* @param border The requested border
* @return border representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/Border.html">Border</a>
*/
public static Border createBorder(String border)
{
if (log.isTraceEnabled())
{
log.trace("Creating border for #0", border);
}
try
{
return border == null ? Border.ALL : (Border) getConstant(BORDER_CLASS_NAME, border.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Border {0} not supported, try {1}", border, getValidConstantsSuggestion(BORDER_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of a border line style
*
* @param borderLineStyle The requested border line style
* @return The border line style representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/BorderLineStyle.html">BorderLineStyle</a>
*/
public static BorderLineStyle createLineStyle(String borderLineStyle)
{
if (log.isTraceEnabled())
{
log.trace("Creating border line style for #0", borderLineStyle);
}
try
{
return borderLineStyle == null ? BorderLineStyle.NONE : (BorderLineStyle) getConstant(BORDER_LINE_STYLE_CLASS_NAME, borderLineStyle.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Border line style {0} not supported, try {1}", borderLineStyle, getValidConstantsSuggestion(BORDER_LINE_STYLE_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of a pattern
*
* @param pattern The requested pattern
* @return The pattern representation
* @see <a
* href="http://jexcelapi.sourceforge.net/resources/javadocs/2_6/docs/jxl/format/Pattern.html">Pattern</a>
*/
public static Pattern createPattern(String pattern)
{
if (log.isTraceEnabled())
{
log.trace("Creating pattern for #0", pattern);
}
try
{
return pattern == null ? Pattern.SOLID : (Pattern) getConstant(PATTERN_CLASS_NAME, pattern.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Pattern {0} not supported, try {1}", pattern, getValidConstantsSuggestion(PATTERN_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of a page orientation
*
* @param orientation The type of orientation to create
* @return The page orientation representation
*/
public static PageOrientation createPageOrientation(String orientation)
{
if (log.isTraceEnabled())
{
log.trace("Creating page orientation for #0", orientation);
}
try
{
return orientation == null ? PageOrientation.LANDSCAPE : (PageOrientation) getConstant(PAGE_ORIENTATION_CLASS_NAME, orientation.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Page orientation {0} not supported, try {1}", orientation, getValidConstantsSuggestion(PAGE_ORIENTATION_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI representation of a paper size
*
* @param paperSize The type of paper size to create
* @return The paper size representation
*/
public static PaperSize createPaperSize(String paperSize)
{
if (log.isTraceEnabled())
{
log.trace("Creating paper size for #0", paperSize);
}
try
{
return paperSize == null ? PaperSize.A4 : (PaperSize) getConstant(PAPER_SIZE_CLASS_NAME, paperSize.toUpperCase());
}
catch (NoSuchFieldException e)
{
String message = Interpolator.instance().interpolate("Page size {0} not supported, try {1}", paperSize, getValidConstantsSuggestion(PAPER_SIZE_CLASS_NAME));
throw new ExcelWorkbookException(message, e);
}
}
/**
* Creates a JExcelAPI header or footer representation. Processes the left,
* center and right facets using a helper method
*
* @param uiHeaderFooter The UI header or footer to interpret
* @param headerFooter The JExcelAPI header or footer representation to add
* to
* @return The JExcelAPI header or footer representation
*/
public static HeaderFooter createHeaderFooter(UIComponent uiHeaderFooter, HeaderFooter headerFooter)
{
if (log.isTraceEnabled())
{
log.trace("Processing header/footer #0", uiHeaderFooter);
}
processHeaderFooterFacet(headerFooter.getLeft(), uiHeaderFooter.getFacet("left"));
processHeaderFooterFacet(headerFooter.getCentre(), uiHeaderFooter.getFacet("center"));
processHeaderFooterFacet(headerFooter.getRight(), uiHeaderFooter.getFacet("right"));
return headerFooter;
}
/**
* Processes a header or footer facet. A header or footer facet in JExcelAPI
* is split into three parts, left, center and right and the UI
* representation has facets with the same namings. Gets the requested facet
* from the UI component and calls helper methods for processing the header
* commands in sequence
*
* @param headerFooter The JExcelAPI header or footer facet to process
* @param facetName The name of the facet to process (left, center, right)
* @param uiHeaderFooter The UI representation to interpret
*/
private static void processHeaderFooterFacet(HeaderFooter.Contents contents, UIComponent facet)
{
if (log.isTraceEnabled())
{
log.trace("Processing facet #0 of header/footer #1", facet, contents);
}
// No facet found
if (facet == null)
{
return;
}
String facetContent = null;
try
{
facetContent = ExcelComponent.cmp2String(FacesContext.getCurrentInstance(), facet);
}
catch (IOException e)
{
throw new ExcelWorkbookException("Could not get content from header facet", e);
}
if (facetContent == null)
{
return;
}
facetContent = facetContent.trim();
int firstHash;
int secondHash;
String command;
String pre;
while (!"".equals(facetContent))
{
firstHash = -1;
secondHash = -1;
firstHash = facetContent.indexOf(HEADERFOOTER_COMMAND_MARKER);
if (firstHash >= 0)
{
secondHash = facetContent.indexOf(HEADERFOOTER_COMMAND_MARKER, firstHash + 1);
}
if (firstHash >= 0 && secondHash >= 0 && firstHash != secondHash)
{
pre = facetContent.substring(0, firstHash);
if (!"".equals(pre))
{
contents.append(pre);
}
command = facetContent.substring(firstHash + 1, secondHash);
processCommand(contents, command);
facetContent = facetContent.substring(secondHash + 1);
}
else
{
contents.append(facetContent);
facetContent = "";
}
}
}
/**
* Processes a header or footer command, adding itself to the contents
*
* @param contents The target contents
* @param command The command to execute
*/
private static void processCommand(Contents contents, String command)
{
command = command.toLowerCase();
if (command.startsWith("date"))
{
contents.appendDate();
}
else if (command.startsWith(HF_CMD_PAGE_NUMBER))
{
contents.appendPageNumber();
}
else if (command.startsWith(HF_CMD_TIME))
{
contents.appendTime();
}
else if (command.startsWith(HF_CMD_TOTAL_PAGES))
{
contents.appendTotalPages();
}
else if (command.startsWith(HF_CMD_WORKBOOK_NAME))
{
contents.appendWorkbookName();
}
else if (command.startsWith(HF_CMD_WORKSHEET_NAME))
{
contents.appendWorkSheetName();
}
else if (command.startsWith(HF_CMD_BOLD))
{
contents.toggleBold();
}
else if (command.startsWith(HF_CMD_DOUBLE_UNDERLINE))
{
contents.toggleDoubleUnderline();
}
else if (command.startsWith(HF_CMD_ITALICS))
{
contents.toggleItalics();
}
else if (command.startsWith(HF_CMD_OUTLINE))
{
contents.toggleOutline();
}
else if (command.startsWith(HF_CMD_SHADOW))
{
contents.toggleShadow();
}
else if (command.startsWith(HF_CMD_STRIKETHROUGH))
{
contents.toggleStrikethrough();
}
else if (command.startsWith(HF_CMD_SUBSCRIPT))
{
contents.toggleSubScript();
}
else if (command.startsWith(HF_CMD_SUPERSCRIPT))
{
contents.toggleSuperScript();
}
else if (command.startsWith(HF_CMD_UNDERLINE))
{
contents.toggleUnderline();
}
else if (command.startsWith(HF_CMD_FONT_NAME))
{
String[] parts = command.split(HEADERFOOTER_PAIR_DELIMITER);
if (parts.length != 2)
{
log.warn("Header/Footer font name error in #0", command);
}
contents.setFontName(parts[1].trim());
}
else if (command.startsWith(HF_CMD_FONT_SIZE))
{
String[] parts = command.split(HEADERFOOTER_PAIR_DELIMITER);
if (parts.length != 2)
{
log.warn("Header/Footer font size error in #0", command);
}
contents.setFontSize(Integer.parseInt(parts[1].trim()));
}
}
}