/*
* 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) 2006 - 2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.output.table.html.helper;
import java.awt.Color;
import java.text.NumberFormat;
import org.pentaho.reporting.engine.classic.core.ElementAlignment;
import org.pentaho.reporting.engine.classic.core.layout.model.Border;
import org.pentaho.reporting.engine.classic.core.layout.model.BorderCorner;
import org.pentaho.reporting.engine.classic.core.layout.model.BorderEdge;
import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinition;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.CellBackground;
import org.pentaho.reporting.engine.classic.core.modules.output.table.html.util.HtmlColors;
import org.pentaho.reporting.engine.classic.core.modules.output.table.html.util.HtmlEncoderUtil;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.WhitespaceCollapse;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility;
import org.pentaho.reporting.libraries.base.config.Configuration;
@SuppressWarnings("HardCodedStringLiteral")
public class DefaultStyleBuilderFactory implements StyleBuilderFactory
{
private boolean safariLengthFix;
private boolean useWhitespacePreWrap;
private boolean enableRoundBorderCorner;
public DefaultStyleBuilderFactory()
{
}
public boolean isSafariLengthFix()
{
return safariLengthFix;
}
public boolean isUseWhitespacePreWrap()
{
return useWhitespacePreWrap;
}
public boolean isEnableRoundBorderCorner()
{
return enableRoundBorderCorner;
}
public StyleBuilder produceTextStyle(StyleBuilder styleBuilder,
final StyleSheet styleSheet,
final BoxDefinition boxDefinition,
final boolean includeBorder,
final StyleBuilder.StyleCarrier[] parentElementStyle)
{
if (styleSheet == null)
{
throw new NullPointerException();
}
if (styleBuilder == null)
{
styleBuilder = new DefaultStyleBuilder(this);
}
else
{
styleBuilder.clear();
}
final FilterStyleBuilder filterStyleBuilder = new FilterStyleBuilder(styleBuilder, parentElementStyle);
final NumberFormat pointConverter = filterStyleBuilder.getPointConverter();
final Color textColor = (Color) styleSheet.getStyleProperty(ElementStyleKeys.PAINT);
final Color backgroundColor = (Color) styleSheet.getStyleProperty(ElementStyleKeys.BACKGROUND_COLOR);
if (backgroundColor != null)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.BACKGROUND_COLOR, HtmlColors.getColorString(backgroundColor));
}
if (includeBorder)
{
processBorder(styleSheet, boxDefinition, filterStyleBuilder, pointConverter);
}
if (textColor != null)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.COLOR, HtmlColors.getColorString(textColor));
}
processFontStyle(styleSheet, filterStyleBuilder, pointConverter);
processTextDecoration(styleSheet, filterStyleBuilder);
final ElementAlignment align = (ElementAlignment) styleSheet.getStyleProperty(ElementStyleKeys.ALIGNMENT);
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.TEXT_ALIGN, translateHorizontalAlignment(align));
final double wordSpacing = styleSheet.getDoubleStyleProperty(TextStyleKeys.WORD_SPACING, 0);
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.WORD_SPACING, pointConverter.format
(fixLengthForSafari(wordSpacing)), "pt");
final double minLetterSpacing = styleSheet.getDoubleStyleProperty(TextStyleKeys.X_MIN_LETTER_SPACING, 0);
final double maxLetterSpacing = styleSheet.getDoubleStyleProperty(TextStyleKeys.X_MAX_LETTER_SPACING, 0);
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.LETTER_SPACING, pointConverter.format
(fixLengthForSafari(Math.min(minLetterSpacing, maxLetterSpacing))), "pt");
processWhiteSpaceCollapse(styleSheet, filterStyleBuilder);
return styleBuilder;
}
private void processWhiteSpaceCollapse(final StyleSheet styleSheet, final FilterStyleBuilder filterStyleBuilder)
{
final WhitespaceCollapse wsCollapse = (WhitespaceCollapse)
styleSheet.getStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE);
if (WhitespaceCollapse.PRESERVE.equals(wsCollapse))
{
if (useWhitespacePreWrap)
{
// this style does not work for IE6 and IE7, but heck, in that case they just behave as if normal mode is
// selected. In that case multiple spaces are collapsed into a single space.
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.WHITE_SPACE, "pre-wrap");
}
else
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.WHITE_SPACE, "pre");
}
}
else if (WhitespaceCollapse.PRESERVE_BREAKS.equals(wsCollapse))
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.WHITE_SPACE, "nowrap");
}
else
{
// discard is handled on the layouter level already;
// collapse is the normal way of handling whitespaces in the engine.
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.WHITE_SPACE, "normal");
}
}
private void processFontStyle(final StyleSheet styleSheet,
final FilterStyleBuilder filterStyleBuilder,
final NumberFormat pointConverter)
{
filterStyleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.FONT_FAMILY, translateFontFamily(styleSheet));
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.FONT_SIZE, pointConverter.format
(fixLengthForSafari(styleSheet.getDoubleStyleProperty(TextStyleKeys.FONTSIZE, 0))), "pt");
if (styleSheet.getBooleanStyleProperty(TextStyleKeys.BOLD))
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.FONT_WEIGHT, "bold");
}
else
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.FONT_WEIGHT, "normal");
}
if (styleSheet.getBooleanStyleProperty(TextStyleKeys.ITALIC))
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.FONT_STYLE, "italic");
}
else
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.FONT_STYLE, "normal");
}
}
private void processTextDecoration(final StyleSheet styleSheet, final FilterStyleBuilder filterStyleBuilder)
{
final boolean underlined = styleSheet.getBooleanStyleProperty(TextStyleKeys.UNDERLINED);
final boolean strikeThrough = styleSheet.getBooleanStyleProperty(TextStyleKeys.STRIKETHROUGH);
if (underlined && strikeThrough)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.TEXT_DECORATION, "underline line-through");
}
else if (strikeThrough)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.TEXT_DECORATION, "line-through");
}
if (underlined)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.TEXT_DECORATION, "underline");
}
else
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.TEXT_DECORATION, "none");
}
}
private void processBorder(final StyleSheet styleSheet,
final BoxDefinition boxDefinition,
final FilterStyleBuilder filterStyleBuilder,
final NumberFormat pointConverter)
{
final Border border = boxDefinition.getBorder();
final BorderEdge top = border.getTop();
final BorderEdge left = border.getLeft();
final BorderEdge bottom = border.getBottom();
final BorderEdge right = border.getRight();
if (top.equals(left) &&
top.equals(right) &&
top.equals(bottom))
{
if (BorderEdge.EMPTY.equals(top) == false)
{
filterStyleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER, filterStyleBuilder.printEdgeAsCSS(top));
}
}
else
{
if (top != null && BorderEdge.EMPTY.equals(top) == false)
{
filterStyleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_TOP, filterStyleBuilder.printEdgeAsCSS(top));
}
if (left != null && BorderEdge.EMPTY.equals(left) == false)
{
filterStyleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_LEFT, filterStyleBuilder.printEdgeAsCSS(left));
}
if (bottom != null && BorderEdge.EMPTY.equals(bottom) == false)
{
filterStyleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_BOTTOM, filterStyleBuilder.printEdgeAsCSS(bottom));
}
if (right != null && BorderEdge.EMPTY.equals(right) == false)
{
filterStyleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_RIGHT, filterStyleBuilder.printEdgeAsCSS(right));
}
}
if (enableRoundBorderCorner)
{
final double blW = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_BOTTOM_LEFT_RADIUS_WIDTH, 0));
final double blH = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_BOTTOM_LEFT_RADIUS_HEIGHT, 0));
if (blW > 0 && blH > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_BOTTOM_LEFT,
pointConverter.format(fixLengthForSafari(blW)) + "pt " +
pointConverter.format(fixLengthForSafari(blH)) + "pt");
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_BOTTOM_LEFT_RADIUS,
pointConverter.format(fixLengthForSafari(blW)) + "pt " +
pointConverter.format(fixLengthForSafari(blH)) + "pt");
}
final double brW = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_BOTTOM_RIGHT_RADIUS_WIDTH, 0));
final double brH = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_BOTTOM_RIGHT_RADIUS_HEIGHT, 0));
if (brW > 0 && brH > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_BOTTOM_RIGHT,
pointConverter.format(fixLengthForSafari(brW)) + "pt " +
pointConverter.format(fixLengthForSafari(brH)) + "pt");
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_BOTTOM_RIGHT_RADIUS,
pointConverter.format(fixLengthForSafari(brW)) + "pt " +
pointConverter.format(fixLengthForSafari(brH)) + "pt");
}
final double tlW = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_TOP_LEFT_RADIUS_WIDTH, 0));
final double tlH = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_TOP_LEFT_RADIUS_HEIGHT, 0));
if (tlW > 0 && tlH > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_TOP_LEFT,
pointConverter.format(fixLengthForSafari(tlW)) + "pt " +
pointConverter.format(fixLengthForSafari(tlH)) + "pt");
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_TOP_LEFT_RADIUS,
pointConverter.format(fixLengthForSafari(tlW)) + "pt " +
pointConverter.format(fixLengthForSafari(tlH)) + "pt");
}
final double trW = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_TOP_RIGHT_RADIUS_WIDTH, 0));
final double trH = Math.max(0, styleSheet.getDoubleStyleProperty(ElementStyleKeys.BORDER_TOP_RIGHT_RADIUS_HEIGHT, 0));
if (trW > 0 && trH > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_TOP_RIGHT,
pointConverter.format(fixLengthForSafari(trW)) + "pt " +
pointConverter.format(fixLengthForSafari(trH)) + "pt");
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_TOP_RIGHT_RADIUS,
pointConverter.format(fixLengthForSafari(trW)) + "pt " +
pointConverter.format(fixLengthForSafari(trH)) + "pt");
}
}
final long paddingTop = boxDefinition.getPaddingTop();
final long paddingLeft = boxDefinition.getPaddingLeft();
final long paddingBottom = boxDefinition.getPaddingBottom();
final long paddingRight = boxDefinition.getPaddingRight();
if (paddingTop == paddingLeft && paddingTop == paddingRight && paddingTop == paddingBottom)
{
if (paddingTop > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.PADDING, pointConverter.format
(fixLengthForSafari(StrictGeomUtility.toExternalValue(paddingTop))), "pt");
}
}
else
{
if (paddingTop > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.PADDING_TOP, pointConverter.format
(fixLengthForSafari(StrictGeomUtility.toExternalValue(paddingTop))), "pt");
}
if (paddingLeft > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.PADDING_LEFT, pointConverter.format
(fixLengthForSafari(StrictGeomUtility.toExternalValue(paddingLeft))), "pt");
}
if (paddingBottom > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.PADDING_BOTTOM, pointConverter.format
(fixLengthForSafari(StrictGeomUtility.toExternalValue(paddingBottom))), "pt");
}
if (paddingRight > 0)
{
filterStyleBuilder.append(DefaultStyleBuilder.CSSKeys.PADDING_RIGHT, pointConverter.format
(fixLengthForSafari(StrictGeomUtility.toExternalValue(paddingRight))), "pt");
}
}
}
private static String translateFontFamily(final StyleSheet box)
{
final String family = (String) box.getStyleProperty(TextStyleKeys.FONT);
if ("Serif".equalsIgnoreCase(family))
{
return "serif";
}
else if ("Sans-serif".equalsIgnoreCase(family) || "SanSerif".equalsIgnoreCase(
family) || "SansSerif".equalsIgnoreCase(family) ||
"Dialog".equalsIgnoreCase(family) || "DialogInput".equalsIgnoreCase(family))
{
return "sans-serif";
}
else if ("Monospaced".equalsIgnoreCase(family))
{
return "monospace";
}
else
{
return '\"' + HtmlEncoderUtil.encodeCSS(family) + '\"';
}
}
public double fixLengthForSafari(final double border)
{
if (safariLengthFix == false)
{
return border;
}
if (border == 0)
{
return 0;
}
return Math.max(1, Math.round(border));
}
/**
* Translates the JFreeReport horizontal element alignment into a HTML alignment constant.
*
* @param ea the element alignment
* @return the translated alignment name.
*/
public static String translateHorizontalAlignment(final ElementAlignment ea)
{
if (ElementAlignment.JUSTIFY.equals(ea))
{
return "justify";
}
if (ElementAlignment.RIGHT.equals(ea))
{
return "right";
}
if (ElementAlignment.CENTER.equals(ea))
{
return "center";
}
return "left";
}
public void configure(final Configuration configuration)
{
safariLengthFix = ("true".equals(configuration.getConfigProperty
("org.pentaho.reporting.engine.classic.core.modules.output.table.html.SafariLengthHack")));
useWhitespacePreWrap = ("true".equals(configuration.getConfigProperty
("org.pentaho.reporting.engine.classic.core.modules.output.table.html.UseWhitespacePreWrap")));
enableRoundBorderCorner = ("true".equals(configuration.getConfigProperty
("org.pentaho.reporting.engine.classic.core.modules.output.table.html.EnableRoundBorderCorner")));
}
public StyleBuilder createCellStyle(StyleBuilder styleBuilder,
final CellBackground background,
final StyleBuilder.CSSKeys[] extraStyleKeys,
final String[] extraStyleValues)
{
return createCellStyle(styleBuilder, null, null, background, extraStyleKeys, extraStyleValues);
}
public StyleBuilder createCellStyle(StyleBuilder styleBuilder,
final StyleSheet styleSheet,
final BoxDefinition boxDefinition,
final CellBackground background,
final StyleBuilder.CSSKeys[] extraStyleKeys,
final String[] extraStyleValues)
{
if (styleBuilder == null)
{
throw new NullPointerException();
}
if (styleSheet == null)
{
styleBuilder.clear();
}
else
{
styleBuilder = produceTextStyle(styleBuilder, styleSheet, boxDefinition, true, null);
}
// Add the extra styles
if (extraStyleKeys != null
&& extraStyleValues != null
&& extraStyleKeys.length == extraStyleValues.length)
{
for (int i = 0; i < extraStyleKeys.length; ++i)
{
styleBuilder.append(extraStyleKeys[i], extraStyleValues[i], false);
}
}
if (background != null)
{
final Color colorValue = (background.getBackgroundColor());
if (colorValue != null)
{
styleBuilder.append(DefaultStyleBuilder.CSSKeys.BACKGROUND_COLOR, HtmlColors.getColorString(colorValue));
}
final BorderEdge topEdge = background.getTop();
final BorderEdge leftEdge = background.getLeft();
final BorderEdge bottomEdge = background.getBottom();
final BorderEdge rightEdge = background.getRight();
if (topEdge.equals(leftEdge) &&
topEdge.equals(rightEdge) &&
topEdge.equals(bottomEdge))
{
if (BorderEdge.EMPTY.equals(topEdge) == false)
{
styleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER, styleBuilder.printEdgeAsCSS(topEdge));
}
}
else
{
if (BorderEdge.EMPTY.equals(topEdge) == false)
{
styleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_TOP, styleBuilder.printEdgeAsCSS(topEdge));
}
if (BorderEdge.EMPTY.equals(leftEdge) == false)
{
styleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_LEFT, styleBuilder.printEdgeAsCSS(leftEdge));
}
if (BorderEdge.EMPTY.equals(bottomEdge) == false)
{
styleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_BOTTOM, styleBuilder.printEdgeAsCSS(bottomEdge));
}
if (BorderEdge.EMPTY.equals(rightEdge) == false)
{
styleBuilder.appendRaw(DefaultStyleBuilder.CSSKeys.BORDER_RIGHT, styleBuilder.printEdgeAsCSS(rightEdge));
}
}
if (isEnableRoundBorderCorner())
{
final BorderCorner topLeft = background.getTopLeft();
if (BorderCorner.EMPTY.equals(topLeft) == false)
{
styleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_TOP_LEFT, styleBuilder.printCornerAsCSS(topLeft));
styleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_TOP_LEFT_RADIUS, styleBuilder.printCornerAsCSS(topLeft));
}
final BorderCorner topRight = background.getTopRight();
if (BorderCorner.EMPTY.equals(topRight) == false)
{
styleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_TOP_RIGHT, styleBuilder.printCornerAsCSS(topRight));
styleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_TOP_RIGHT_RADIUS, styleBuilder.printCornerAsCSS(topRight));
}
final BorderCorner bottomLeft = background.getBottomLeft();
if (BorderCorner.EMPTY.equals(bottomLeft) == false)
{
styleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_BOTTOM_LEFT, styleBuilder.printCornerAsCSS(bottomLeft));
styleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_BOTTOM_LEFT_RADIUS, styleBuilder.printCornerAsCSS(bottomLeft));
}
final BorderCorner bottomRight = background.getBottomRight();
if (BorderCorner.EMPTY.equals(bottomRight) == false)
{
styleBuilder.append(DefaultStyleBuilder.CSSKeys.MOZ_BORDER_RADIUS_BOTTOM_RIGHT, styleBuilder.printCornerAsCSS(bottomRight));
styleBuilder.append(DefaultStyleBuilder.CSSKeys.BORDER_BOTTOM_RIGHT_RADIUS, styleBuilder.printCornerAsCSS(bottomRight));
}
}
}
return styleBuilder;
}
}