/*
* 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) 2001 - 2009 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.layout.model.context;
import java.awt.Color;
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.RenderLength;
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.BoxSizing;
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.StyleSheet;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility;
import org.pentaho.reporting.libraries.base.util.LFUMap;
/**
* Creation-Date: 27.04.2007, 22:09:05
*
* @author Thomas Morgner
*/
public final class BoxDefinitionFactory
{
private static class CacheKey
{
private Object instanceId;
private String styleClass;
protected CacheKey()
{
}
protected CacheKey(final Object instanceId, final String styleClass)
{
if (instanceId == null)
{
throw new NullPointerException();
}
if (styleClass == null)
{
throw new NullPointerException();
}
this.instanceId = instanceId;
this.styleClass = styleClass;
}
public Object getInstanceId()
{
return instanceId;
}
public void setInstanceId(final Object instanceId)
{
this.instanceId = instanceId;
}
public String getStyleClass()
{
return styleClass;
}
public void setStyleClass(final String styleClass)
{
this.styleClass = styleClass;
}
public boolean equals(final Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
final CacheKey cacheKey = (CacheKey) o;
if (!instanceId.equals(cacheKey.instanceId))
{
return false;
}
if (!styleClass.equals(cacheKey.styleClass))
{
return false;
}
return true;
}
public int hashCode()
{
int result = instanceId.hashCode();
result = 31 * result + styleClass.hashCode();
return result;
}
public String toString()
{
return "CacheKey{" +
"instanceId=" + instanceId +
", styleClass='" + styleClass + '\'' +
'}';
}
}
private static class CacheCarrier
{
private long changeTracker;
private BoxDefinition boxDefinition;
protected CacheCarrier(final long changeTracker, final BoxDefinition border)
{
this.changeTracker = changeTracker;
this.boxDefinition = border;
}
public long getChangeTracker()
{
return changeTracker;
}
public BoxDefinition getBoxDefinition()
{
return boxDefinition;
}
}
private LFUMap cache;
public BoxDefinitionFactory()
{
this.cache = new LFUMap(500);
}
public BoxDefinition getBoxDefinition(final StyleSheet es)
{
final InstanceID id = es.getId();
final CacheKey key = new CacheKey(id, es.getClass().getName());
final CacheCarrier cc = (CacheCarrier) cache.get(key);
if (cc == null)
{
final BoxDefinition boxDefinition = createBoxDefinition(es);
cache.put(key, new CacheCarrier(es.getChangeTracker(), boxDefinition));
return boxDefinition;
}
if (cc.getChangeTracker() != es.getChangeTracker())
{
final BoxDefinition boxDefinition = createBoxDefinition(es);
cache.put(key, new CacheCarrier(es.getChangeTracker(), boxDefinition));
return boxDefinition;
}
return cc.getBoxDefinition();
}
private BoxDefinition createBoxDefinition(final StyleSheet style)
{
final BoxDefinition box = new BoxDefinition();
box.setPreferredWidth(produceFromStyle(style, ElementStyleKeys.WIDTH, RenderLength.AUTO));
box.setPreferredHeight(produceFromStyle(style, ElementStyleKeys.HEIGHT, RenderLength.AUTO));
box.setMinimumWidth(produceFromStyle(style, ElementStyleKeys.MIN_WIDTH, RenderLength.EMPTY));
box.setMinimumHeight(produceFromStyle(style, ElementStyleKeys.MIN_HEIGHT, RenderLength.EMPTY));
box.setSizeSpecifiesBorderBox(BoxSizing.BORDER_BOX.equals(style.getStyleProperty(ElementStyleKeys.BOX_SIZING)));
box.setMaximumWidth(produceFromStyle(style, ElementStyleKeys.MAX_WIDTH, RenderLength.AUTO));
box.setMaximumHeight(produceFromStyle(style, ElementStyleKeys.MAX_HEIGHT, RenderLength.AUTO));
box.setFixedPosition(produceFromStyle(style, BandStyleKeys.FIXED_POSITION, RenderLength.AUTO));
box.setPaddingTop(Math.max(0, StrictGeomUtility.toInternalValue
(style.getDoubleStyleProperty(ElementStyleKeys.PADDING_TOP, 0))));
box.setPaddingLeft(Math.max(0, StrictGeomUtility.toInternalValue
(style.getDoubleStyleProperty(ElementStyleKeys.PADDING_LEFT, 0))));
box.setPaddingBottom(Math.max(0, StrictGeomUtility.toInternalValue
(style.getDoubleStyleProperty(ElementStyleKeys.PADDING_BOTTOM, 0))));
box.setPaddingRight(Math.max(0, StrictGeomUtility.toInternalValue
(style.getDoubleStyleProperty(ElementStyleKeys.PADDING_RIGHT, 0))));
final BorderEdge edgeTop = createEdge(style, ElementStyleKeys.BORDER_TOP_STYLE,
ElementStyleKeys.BORDER_TOP_COLOR, ElementStyleKeys.BORDER_TOP_WIDTH);
final BorderEdge edgeLeft = createEdge(style, ElementStyleKeys.BORDER_LEFT_STYLE,
ElementStyleKeys.BORDER_LEFT_COLOR, ElementStyleKeys.BORDER_LEFT_WIDTH);
final BorderEdge edgeBottom = createEdge(style, ElementStyleKeys.BORDER_BOTTOM_STYLE,
ElementStyleKeys.BORDER_BOTTOM_COLOR, ElementStyleKeys.BORDER_BOTTOM_WIDTH);
final BorderEdge edgeRight = createEdge(style, ElementStyleKeys.BORDER_RIGHT_STYLE,
ElementStyleKeys.BORDER_RIGHT_COLOR, ElementStyleKeys.BORDER_RIGHT_WIDTH);
final BorderEdge edgeBreak = createEdge(style, ElementStyleKeys.BORDER_BREAK_STYLE,
ElementStyleKeys.BORDER_BREAK_COLOR, ElementStyleKeys.BORDER_BREAK_WIDTH);
if (BorderEdge.EMPTY.equals(edgeBottom) &&
BorderEdge.EMPTY.equals(edgeLeft) &&
BorderEdge.EMPTY.equals(edgeBreak) &&
BorderEdge.EMPTY.equals(edgeRight) &&
BorderEdge.EMPTY.equals(edgeTop))
{
box.setBorder(Border.EMPTY_BORDER);
}
else
{
final BorderCorner topLeftCorner = createCorner
(style, ElementStyleKeys.BORDER_TOP_LEFT_RADIUS_WIDTH, ElementStyleKeys.BORDER_TOP_LEFT_RADIUS_HEIGHT);
final BorderCorner topRightCorner = createCorner
(style, ElementStyleKeys.BORDER_TOP_RIGHT_RADIUS_WIDTH, ElementStyleKeys.BORDER_TOP_RIGHT_RADIUS_HEIGHT);
final BorderCorner bottmLeftCorner = createCorner
(style, ElementStyleKeys.BORDER_BOTTOM_LEFT_RADIUS_WIDTH, ElementStyleKeys.BORDER_BOTTOM_LEFT_RADIUS_HEIGHT);
final BorderCorner bottomRightCorner = createCorner
(style, ElementStyleKeys.BORDER_BOTTOM_RIGHT_RADIUS_WIDTH,
ElementStyleKeys.BORDER_BOTTOM_RIGHT_RADIUS_HEIGHT);
box.setBorder(new Border(edgeTop, edgeLeft, edgeBottom, edgeRight, edgeBreak,
topLeftCorner, topRightCorner, bottmLeftCorner, bottomRightCorner));
}
return box;
}
private BorderCorner createCorner(final StyleSheet style, final StyleKey radiusKeyX, final StyleKey radiusKeyY)
{
final float dimX = (float) style.getDoubleStyleProperty(radiusKeyX, 0);
final float dimY = (float) style.getDoubleStyleProperty(radiusKeyY, 0);
if (dimX <= 0 || dimY <= 0)
{
return BorderCorner.EMPTY;
}
return new BorderCorner(StrictGeomUtility.toInternalValue(dimX), StrictGeomUtility.toInternalValue(dimY));
}
private BorderEdge createEdge(final StyleSheet style, final StyleKey borderStyleKey,
final StyleKey borderColorKey, final StyleKey borderWidthKey)
{
final BorderStyle styleRight = (BorderStyle) style.getStyleProperty(borderStyleKey);
if (styleRight == null || BorderStyle.NONE.equals(styleRight))
{
return BorderEdge.EMPTY;
}
final Color color = (Color) style.getStyleProperty(borderColorKey);
final double width = style.getDoubleStyleProperty(borderWidthKey, 0);
if (color == null || width <= 0)
{
return BorderEdge.EMPTY;
}
return new BorderEdge(styleRight, color, StrictGeomUtility.toInternalValue(width));
}
private RenderLength produceFromStyle(final StyleSheet styleSheet, final StyleKey key, final RenderLength retval)
{
final Float value = (Float) styleSheet.getStyleProperty(key);
if (value == null)
{
return retval;
}
return RenderLength.createFromRaw(value.doubleValue());
}
}