/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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 Lesser General Public License for more details.
*
* Copyright (c) 2009 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.layout.richtext;
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.CSS;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import org.pentaho.reporting.engine.classic.core.AttributeNames;
import org.pentaho.reporting.engine.classic.core.Band;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.filter.types.ContentType;
import org.pentaho.reporting.engine.classic.core.filter.types.LabelType;
import org.pentaho.reporting.engine.classic.core.modules.parser.base.ReportParserUtil;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.BorderStyle;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleKey;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.TextWrap;
import org.pentaho.reporting.engine.classic.core.style.VerticalTextAlign;
import org.pentaho.reporting.engine.classic.core.style.WhitespaceCollapse;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.xmlns.parser.ParseException;
/**
* This handles HTML 3.2 with some CSS support. It uses the Swing HTML parser to process the document.
*
* @author Thomas Morgner.
*/
public class HtmlRichTextConverter implements RichTextConverter
{
private HTMLEditorKit editorKit;
private static final Set BLOCK_ELEMENTS;
static
{
final HashSet blockElements = new HashSet();
blockElements.add(HTML.Tag.IMPLIED);
blockElements.add(HTML.Tag.APPLET);
blockElements.add(HTML.Tag.BODY);
blockElements.add(HTML.Tag.BLOCKQUOTE);
blockElements.add(HTML.Tag.DIV);
blockElements.add(HTML.Tag.FORM);
blockElements.add(HTML.Tag.FRAME);
blockElements.add(HTML.Tag.FRAMESET);
blockElements.add(HTML.Tag.H1);
blockElements.add(HTML.Tag.H2);
blockElements.add(HTML.Tag.H3);
blockElements.add(HTML.Tag.H4);
blockElements.add(HTML.Tag.H5);
blockElements.add(HTML.Tag.H6);
blockElements.add(HTML.Tag.HR);
blockElements.add(HTML.Tag.HTML);
blockElements.add(HTML.Tag.LI);
blockElements.add(HTML.Tag.NOFRAMES);
blockElements.add(HTML.Tag.OBJECT);
blockElements.add(HTML.Tag.OL);
blockElements.add(HTML.Tag.P);
blockElements.add(HTML.Tag.PRE);
blockElements.add(HTML.Tag.TABLE);
blockElements.add(HTML.Tag.TR);
blockElements.add(HTML.Tag.UL);
BLOCK_ELEMENTS = Collections.unmodifiableSet(blockElements);
}
public HtmlRichTextConverter()
{
editorKit = new HTMLEditorKit();
}
public boolean isRecognizedType(final String mimeType)
{
if ("text/html".equals(mimeType))
{
return true;
}
return false;
}
public Object convert(final Element source, final Object value)
{
try
{
final Document doc = RichTextConverterUtilities.parseDocument(editorKit, value);
if (doc == null)
{
return value;
}
final Element element = process(doc.getDefaultRootElement());
return RichTextConverterUtilities.convertToBand(StyleKey.getDefinedStyleKeys(), source, element);
}
catch (Exception e)
{
return value;
}
}
private static AttributeSet computeStyle(final javax.swing.text.Element elem, final StyleSheet styles)
{
final AttributeSet a = elem.getAttributes();
final AttributeSet htmlAttr = styles.translateHTMLToCSS(a);
final ArrayList muxList = new ArrayList();
if (htmlAttr.getAttributeCount() != 0)
{
muxList.add(htmlAttr);
}
if (elem.isLeaf())
{
// The swing-parser has a very weird way of storing attributes for the HTML elements. The
// tag-name is used as key for the attribute set, so you have to know the element type before
// you can do anything sensible with it. Or as we do here, you have to search for the HTML.Tag
// object. Arghh.
final Enumeration keys = a.getAttributeNames();
while (keys.hasMoreElements())
{
final Object key = keys.nextElement();
if (!(key instanceof HTML.Tag))
{
continue;
}
if (key == HTML.Tag.A)
{
final Object o = a.getAttribute(key);
if (o instanceof AttributeSet)
{
final AttributeSet attr = (AttributeSet) o;
if (attr.getAttribute(HTML.Attribute.HREF) == null)
{
continue;
}
}
}
final AttributeSet cssRule = styles.getRule((HTML.Tag) key, elem);
if (cssRule != null)
{
muxList.add(cssRule);
}
}
}
else
{
final HTML.Tag t = (HTML.Tag) a.getAttribute(StyleConstants.NameAttribute);
final AttributeSet cssRule = styles.getRule(t, elem);
if (cssRule != null)
{
muxList.add(cssRule);
}
}
final MutableAttributeSet retval = new SimpleAttributeSet();
for (int i = muxList.size() - 1; i >= 0; i--)
{
final AttributeSet o = (AttributeSet) muxList.get(i);
retval.addAttributes(o);
}
return retval;
}
private Object convertURL(final String srcAttr)
{
try
{
return new URL(srcAttr);
}
catch (MalformedURLException e)
{
// ignore ..
return srcAttr;
}
}
private Element process(final javax.swing.text.Element textElement) throws BadLocationException
{
if (isInvisible(textElement))
{
return null;
}
if (textElement.isLeaf())
{
final AttributeSet attributes = textElement.getAttributes();
if (HTML.Tag.IMG.equals(attributes.getAttribute(StyleConstants.NameAttribute)))
{
final Element result = new Element();
result.setName(textElement.getName());
result.setElementType(ContentType.INSTANCE);
final String src = (String) attributes.getAttribute(HTML.Attribute.SRC);
final String alt = (String) attributes.getAttribute(HTML.Attribute.TITLE);
result.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, convertURL(src));
result.setAttribute(AttributeNames.Html.NAMESPACE, AttributeNames.Html.TITLE, alt);
result.setAttribute(AttributeNames.Html.NAMESPACE, AttributeNames.Swing.TOOLTIP, alt);
if (attributes.isDefined(HTML.Attribute.WIDTH) &&
attributes.isDefined(HTML.Attribute.HEIGHT))
{
result.getStyle().setStyleProperty(ElementStyleKeys.SCALE, Boolean.TRUE);
result.getStyle().setStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO, Boolean.FALSE);
result.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH,
parseLength(String.valueOf(attributes.getAttribute(HTML.Attribute.WIDTH))));
result.getStyle().setStyleProperty(ElementStyleKeys.MIN_HEIGHT,
parseLength(String.valueOf(attributes.getAttribute(HTML.Attribute.HEIGHT))));
}
else if (attributes.isDefined(HTML.Attribute.WIDTH))
{
result.getStyle().setStyleProperty(ElementStyleKeys.SCALE, Boolean.TRUE);
result.getStyle().setStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO, Boolean.TRUE);
result.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH,
parseLength(String.valueOf(attributes.getAttribute(HTML.Attribute.WIDTH))));
result.getStyle().setStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT, Boolean.TRUE);
}
else if (attributes.isDefined(HTML.Attribute.HEIGHT))
{
result.getStyle().setStyleProperty(ElementStyleKeys.SCALE, Boolean.TRUE);
result.getStyle().setStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO, Boolean.TRUE);
result.getStyle().setStyleProperty(ElementStyleKeys.MIN_HEIGHT,
parseLength(String.valueOf(attributes.getAttribute(HTML.Attribute.HEIGHT))));
result.getStyle().setStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT, Boolean.TRUE);
}
else
{
result.getStyle().setStyleProperty(ElementStyleKeys.SCALE, Boolean.FALSE);
result.getStyle().setStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO, Boolean.TRUE);
result.getStyle().setStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT, Boolean.TRUE);
}
configureStyle(textElement, result);
return result;
}
final javax.swing.text.Element parent = textElement.getParentElement();
final int endOffset = textElement.getEndOffset();
final int startOffset = textElement.getStartOffset();
final String text = textElement.getDocument().getText(startOffset, endOffset - startOffset);
if (parent != null)
{
final HTML.Tag tag = findTag(parent.getAttributes());
if ("\n".equals(text))
{
if (BLOCK_ELEMENTS.contains(tag) ||
"paragraph".equals(textElement.getName()) ||
"section".equals(textElement.getName()))
{
if (parent.getElementCount() > 0 && parent.getElement(parent.getElementCount() - 1) == textElement)
{
// Skipping an artificial \n at the end of paragraph element. This is generated by the swing
// parser and really messes things up here.
return null;
}
}
}
}
final Element result = new Element();
result.setName(textElement.getName());
result.setElementType(LabelType.INSTANCE);
result.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, text);
configureStyle(textElement, result);
if (HTML.Tag.BR.equals(textElement.getAttributes().getAttribute(StyleConstants.NameAttribute)))
{
result.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, "\n");
result.getStyle().setStyleProperty(TextStyleKeys.TRIM_TEXT_CONTENT, Boolean.FALSE);
result.getStyle().setStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE, WhitespaceCollapse.PRESERVE);
}
return result;
}
// we need to intercept for <UL> and <OL> here
final Band band = new Band();
configureStyle(textElement, band);
configureBand(textElement, band);
final boolean bandIsInline = isInlineElement(band);
final int size = textElement.getElementCount();
Band inlineContainer = null;
for (int i = 0; i < size; i++)
{
final Element element = process(textElement.getElement(i));
if (element == null)
{
continue;
}
if (isInlineElement(element) == bandIsInline)
{
band.addElement(element);
continue;
}
if (band.getElementCount() == 0)
{
inlineContainer = new Band();
inlineContainer.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "inline");
inlineContainer.addElement(element);
band.addElement(inlineContainer);
continue;
}
final Element maybeInlineContainer = (Element) band.getElement(band.getElementCount() - 1);
if (maybeInlineContainer == inlineContainer)
{
// InlineContainer cannot be null at this point, as band.getElement never returns null.
//noinspection ConstantConditions
inlineContainer.addElement(element);
continue;
}
inlineContainer = new Band();
inlineContainer.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "inline");
inlineContainer.addElement(element);
band.addElement(inlineContainer);
}
return band;
}
private boolean isInlineElement(final Element element)
{
if (element instanceof Band)
{
if ("inline".equals(element.getStyle().getStyleProperty(BandStyleKeys.LAYOUT, "inline")))
{
return true;
}
return false;
}
return true;
}
private boolean isInvisible(final javax.swing.text.Element textElement)
{
final HTMLDocument htmlDocument = (HTMLDocument) textElement.getDocument();
final StyleSheet sheet = htmlDocument.getStyleSheet();
final AttributeSet attr = computeStyle(textElement, sheet);
final Object o = attr.getAttribute(CSS.Attribute.DISPLAY);
if ("none".equals(String.valueOf(o)))
{
return true;
}
final Object tag = findTag(textElement.getAttributes());
if (tag == HTML.Tag.COMMENT)
{
return true;
}
if (tag == HTML.Tag.SCRIPT)
{
return true;
}
if (tag == HTML.Tag.HEAD)
{
return true;
}
return false;
}
private void configureStyle(final javax.swing.text.Element textElement, final Element result)
{
final HTMLDocument htmlDocument = (HTMLDocument) textElement.getDocument();
final StyleSheet sheet = htmlDocument.getStyleSheet();
final AttributeSet attr = computeStyle(textElement, sheet);
parseBorderAndBackgroundStyle(result, sheet, attr);
parseBoxStyle(result, attr);
final Font font = sheet.getFont(attr);
if (font != null)
{
result.getStyle().setStyleProperty(TextStyleKeys.FONT, font.getFamily());
result.getStyle().setStyleProperty(TextStyleKeys.FONTSIZE, new Integer(font.getSize()));
result.getStyle().setBooleanStyleProperty(TextStyleKeys.ITALIC, font.isItalic());
result.getStyle().setBooleanStyleProperty(TextStyleKeys.BOLD, font.isBold());
}
final Object letterSpacing = attr.getAttribute(CSS.Attribute.LETTER_SPACING);
if (letterSpacing != null)
{
result.getStyle().setStyleProperty
(TextStyleKeys.X_OPTIMUM_LETTER_SPACING, parseLength(String.valueOf(letterSpacing)));
}
final Object wordSpacing = attr.getAttribute(CSS.Attribute.WORD_SPACING);
if (wordSpacing != null)
{
result.getStyle().setStyleProperty
(TextStyleKeys.WORD_SPACING, parseLength(String.valueOf(wordSpacing)));
}
final Object lineHeight = attr.getAttribute(CSS.Attribute.LINE_HEIGHT);
if (lineHeight != null)
{
result.getStyle().setStyleProperty
(TextStyleKeys.LINEHEIGHT, parseLength(String.valueOf(lineHeight)));
}
final Object textAlign = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
if (textAlign != null)
{
try
{
result.getStyle().setStyleProperty(ElementStyleKeys.ALIGNMENT,
ReportParserUtil.parseHorizontalElementAlignment(String.valueOf(textAlign), null));
}
catch (ParseException e)
{
// ignore ..
}
}
final Object textDecoration = attr.getAttribute(CSS.Attribute.TEXT_DECORATION);
if (textDecoration != null)
{
final String[] strings = StringUtils.split(String.valueOf(textDecoration));
result.getStyle().setStyleProperty(TextStyleKeys.STRIKETHROUGH, Boolean.FALSE);
result.getStyle().setStyleProperty(TextStyleKeys.UNDERLINED, Boolean.FALSE);
for (int i = 0; i < strings.length; i++)
{
final String value = strings[i];
if ("line-through".equals(value))
{
result.getStyle().setStyleProperty(TextStyleKeys.STRIKETHROUGH, Boolean.TRUE);
}
if ("underline".equals(value))
{
result.getStyle().setStyleProperty(TextStyleKeys.UNDERLINED, Boolean.TRUE);
}
}
}
final Object valign = attr.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
if (valign != null)
{
final VerticalTextAlign valignValue = VerticalTextAlign.valueOf(String.valueOf(valign));
result.getStyle().setStyleProperty(TextStyleKeys.VERTICAL_TEXT_ALIGNMENT, valignValue);
try
{
result.getStyle().setStyleProperty(ElementStyleKeys.VALIGNMENT,
ReportParserUtil.parseVerticalElementAlignment(String.valueOf(valign), null));
}
catch (ParseException e)
{
// ignore ..
}
}
final Object whitespaceText = attr.getAttribute(CSS.Attribute.WHITE_SPACE);
if (whitespaceText != null)
{
final String value = String.valueOf(whitespaceText);
if ("pre".equals(value))
{
result.getStyle().setStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE, WhitespaceCollapse.PRESERVE);
result.getStyle().setStyleProperty(TextStyleKeys.TEXT_WRAP, TextWrap.NONE);
}
else if ("nowrap".equals(value))
{
result.getStyle().setStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE, WhitespaceCollapse.PRESERVE_BREAKS);
result.getStyle().setStyleProperty(TextStyleKeys.TEXT_WRAP, TextWrap.NONE);
}
else
{
result.getStyle().setStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE, WhitespaceCollapse.COLLAPSE);
result.getStyle().setStyleProperty(TextStyleKeys.TEXT_WRAP, TextWrap.WRAP);
}
}
else
{
result.getStyle().setStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE, WhitespaceCollapse.COLLAPSE);
result.getStyle().setStyleProperty(TextStyleKeys.TEXT_WRAP, TextWrap.WRAP);
}
final Object alignAttribute = attr.getAttribute(HTML.Attribute.ALIGN);
if (alignAttribute != null)
{
try
{
result.getStyle().setStyleProperty(ElementStyleKeys.ALIGNMENT,
ReportParserUtil.parseHorizontalElementAlignment(String.valueOf(alignAttribute), null));
}
catch (ParseException e)
{
// ignore ..
}
}
final Object titleAttribute = attr.getAttribute(HTML.Attribute.TITLE);
if (titleAttribute != null)
{
result.setAttribute(AttributeNames.Html.NAMESPACE, AttributeNames.Html.TITLE,
String.valueOf(titleAttribute));
}
final Object textIndentStyle = attr.getAttribute(CSS.Attribute.TEXT_INDENT);
if (textIndentStyle != null)
{
result.getStyle().setStyleProperty
(TextStyleKeys.FIRST_LINE_INDENT, parseLength(String.valueOf(textIndentStyle)));
}
// attr.getAttribute(CSS.Attribute.LIST_STYLE_TYPE);
// attr.getAttribute(CSS.Attribute.LIST_STYLE_TYPE);
// attr.getAttribute(CSS.Attribute.LIST_STYLE_POSITION);
}
private HTML.Tag findTag(final AttributeSet attr)
{
final Enumeration names = attr.getAttributeNames();
while (names.hasMoreElements())
{
final Object name = names.nextElement();
final Object o = attr.getAttribute(name);
if (o instanceof HTML.Tag)
{
if (HTML.Tag.CONTENT == o)
{
continue;
}
if (HTML.Tag.COMMENT == o)
{
continue;
}
return (HTML.Tag) o;
}
}
return null;
}
private void parseBoxStyle(final Element result, final AttributeSet attr)
{
final Object paddingText = attr.getAttribute(CSS.Attribute.PADDING);
if (paddingText != null)
{
final Float padding = parseLength(String.valueOf(paddingText));
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_TOP, padding);
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_LEFT, padding);
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_BOTTOM, padding);
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_RIGHT, padding);
}
final Object paddingTop = attr.getAttribute(CSS.Attribute.PADDING_TOP);
if (paddingTop != null)
{
final Float padding = parseLength(String.valueOf(paddingTop));
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_TOP, padding);
}
final Object paddingLeft = attr.getAttribute(CSS.Attribute.PADDING_LEFT);
if (paddingLeft != null)
{
final Float padding = parseLength(String.valueOf(paddingLeft));
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_LEFT, padding);
}
final Object paddingBottom = attr.getAttribute(CSS.Attribute.PADDING_BOTTOM);
if (paddingBottom != null)
{
final Float padding = parseLength(String.valueOf(paddingBottom));
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_BOTTOM, padding);
}
final Object paddingRight = attr.getAttribute(CSS.Attribute.PADDING_RIGHT);
if (paddingRight != null)
{
final Float padding = parseLength(String.valueOf(paddingRight));
result.getStyle().setStyleProperty(ElementStyleKeys.PADDING_RIGHT, padding);
}
final Object heightText = attr.getAttribute(CSS.Attribute.HEIGHT);
if (heightText != null)
{
result.getStyle().setStyleProperty(ElementStyleKeys.MIN_HEIGHT, parseLength(String.valueOf(heightText)));
}
final Object widthText = attr.getAttribute(CSS.Attribute.WIDTH);
if (widthText != null)
{
result.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, parseLength(String.valueOf(widthText)));
}
}
private void parseBorderAndBackgroundStyle(final Element result, final StyleSheet sheet, final AttributeSet attr)
{
final Object backgroundColor = attr.getAttribute(CSS.Attribute.BACKGROUND_COLOR);
if (backgroundColor != null)
{
result.getStyle().setStyleProperty
(ElementStyleKeys.BACKGROUND_COLOR, sheet.stringToColor(String.valueOf(backgroundColor)));
}
final Object borderStyleText = attr.getAttribute(CSS.Attribute.BORDER_STYLE);
if (borderStyleText != null)
{
final BorderStyle borderStyle = BorderStyle.getBorderStyle(String.valueOf(borderStyleText));
if (borderStyle != null)
{
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_BOTTOM_STYLE, borderStyle);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_TOP_STYLE, borderStyle);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_LEFT_STYLE, borderStyle);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_RIGHT_STYLE, borderStyle);
}
}
final Object borderWidthText = attr.getAttribute(CSS.Attribute.BORDER_WIDTH);
if (borderWidthText != null)
{
final Float borderWidth = parseLength(String.valueOf(borderWidthText));
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_BOTTOM_WIDTH, borderWidth);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_TOP_WIDTH, borderWidth);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_LEFT_WIDTH, borderWidth);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_RIGHT_WIDTH, borderWidth);
}
final Object borderBottomWidthText = attr.getAttribute(CSS.Attribute.BORDER_BOTTOM_WIDTH);
if (borderBottomWidthText != null)
{
final Float borderWidth = parseLength(String.valueOf(borderBottomWidthText));
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_BOTTOM_WIDTH, borderWidth);
}
final Object borderRightWidthText = attr.getAttribute(CSS.Attribute.BORDER_RIGHT_WIDTH);
if (borderRightWidthText != null)
{
final Float borderWidth = parseLength(String.valueOf(borderRightWidthText));
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_RIGHT_WIDTH, borderWidth);
}
final Object borderTopWidthText = attr.getAttribute(CSS.Attribute.BORDER_TOP_WIDTH);
if (borderTopWidthText != null)
{
final Float borderWidth = parseLength(String.valueOf(borderTopWidthText));
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_TOP_WIDTH, borderWidth);
}
final Object borderLeftWidth = attr.getAttribute(CSS.Attribute.BORDER_LEFT_WIDTH);
if (borderLeftWidth != null)
{
final Float borderWidth = parseLength(String.valueOf(borderLeftWidth));
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_LEFT_WIDTH, borderWidth);
}
final Object colorText = attr.getAttribute(CSS.Attribute.COLOR);
if (colorText != null)
{
final Color color = sheet.stringToColor(String.valueOf(colorText));
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_BOTTOM_COLOR, color);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_TOP_COLOR, color);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_LEFT_COLOR, color);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_RIGHT_COLOR, color);
result.getStyle().setStyleProperty
(ElementStyleKeys.PAINT, color);
}
final Object borderColorText = attr.getAttribute(CSS.Attribute.BORDER_COLOR);
if (borderColorText != null)
{
final Color borderColor = sheet.stringToColor(String.valueOf(borderColorText));
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_BOTTOM_COLOR, borderColor);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_TOP_COLOR, borderColor);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_LEFT_COLOR, borderColor);
result.getStyle().setStyleProperty
(ElementStyleKeys.BORDER_RIGHT_COLOR, borderColor);
}
}
private Float parseLength(final String value)
{
if (value == null)
{
return null;
}
try
{
final StreamTokenizer strtok = new StreamTokenizer(new StringReader(value));
strtok.parseNumbers();
final int firstToken = strtok.nextToken();
if (firstToken != StreamTokenizer.TT_NUMBER)
{
return null;
}
final double nval = strtok.nval;
final int nextToken = strtok.nextToken();
if (nextToken != StreamTokenizer.TT_WORD)
{
// yeah, this is against the standard, but we are dealing with deadly ugly non-standard documents here
// maybe we will be able to integrate a real HTML processor at some point.
return new Float(nval);
}
final String unit = strtok.sval;
if ("%".equals(unit))
{
return new Float(-nval);
}
if ("cm".equals(unit))
{
return new Float(nval * 25.4 / 72);
}
if ("mm".equals(unit))
{
return new Float(nval * 2.54 / 72);
}
if ("pt".equals(unit))
{
return new Float(nval);
}
if ("in".equals(unit))
{
return new Float(nval * 72);
}
if ("px".equals(unit))
{
return new Float(nval * 72);
}
if ("pc".equals(unit))
{
return new Float(nval * 12);
}
return null;
}
catch (IOException ioe)
{
return null;
}
}
private void configureBand(final javax.swing.text.Element textElement, final Band band)
{
final HTML.Tag tag = findTag(textElement.getAttributes());
if (tag == null)
{
if ("paragraph".equals(textElement.getName()) ||
"section".equals(textElement.getName()))
{
band.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "block");
band.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(-100));
band.setName(textElement.getName());
}
else
{
band.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "inline");
band.setName(textElement.getName());
}
return;
}
if (BLOCK_ELEMENTS.contains(tag))
{
band.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "block");
band.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(-100));
band.setName(String.valueOf(tag));
}
else
{
band.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "inline");
band.setName(String.valueOf(tag));
}
}
}