ingo@304: package de.intevation.gnv.chart;
ingo@304: 
ingo@304: import java.awt.Font;
ingo@304: import java.awt.Color;
ingo@327: import java.awt.geom.Ellipse2D;
ingo@304: import java.lang.NumberFormatException;
ingo@304: 
ingo@304: import org.apache.log4j.Logger;
ingo@304: 
ingo@304: import org.jfree.chart.StandardChartTheme;
ingo@304: import org.jfree.chart.plot.XYPlot;
ingo@327: import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
ingo@304: import org.jfree.ui.RectangleInsets;
ingo@304: import org.jfree.util.UnitType;
ingo@304: 
ingo@304: 
ingo@304: import org.w3c.dom.Document;
ingo@304: 
ingo@304: import de.intevation.artifactdatabase.Config;
ingo@304: 
ingo@304: /**
ingo@304:  * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
ingo@304:  */
ingo@304: public class XMLChartTheme
ingo@304: extends      StandardChartTheme
ingo@304: {
ingo@304:     private static final Color DEFAULT_COLOR = Color.BLACK;
ingo@304: 
ingo@304:     private Logger log = Logger.getLogger(XMLChartTheme.class);
ingo@304: 
ingo@304:     protected boolean domainCrosshairVisible;
ingo@304:     protected boolean rangeCrosshairVisible;
ingo@327:     protected boolean renderLines;
ingo@327:     protected boolean renderShapes;
ingo@327: 
ingo@327:     protected int pointWidth;
ingo@327:     protected int pointHeight;
ingo@304: 
ingo@304: 
ingo@304:     public XMLChartTheme(String name) {
ingo@304:         super(name);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     public void setDomainCrosshairVisible(boolean visible) {
ingo@304:         this.domainCrosshairVisible = visible;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     public boolean getDomainCrosshairVisible() {
ingo@304:         return domainCrosshairVisible;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     public boolean getRangeCrosshairVisible() {
ingo@304:         return rangeCrosshairVisible;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     public void setRangeCrosshairVisible(boolean visible) {
ingo@304:         this.rangeCrosshairVisible = visible;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     public void applyXMLConfiguration(Document document) {
ingo@304:         log.debug("create XMLChartTheme");
ingo@304: 
ingo@304:         init(document);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private void init(Document document) {
ingo@304:         log.debug("init XMLChartTheme parameters");
ingo@304: 
ingo@304:         initChartParameters(document);
ingo@304:         initTitleParameters(document);
ingo@304:         initSubtitleParameters(document);
ingo@304:         initPlotParameters(document);
ingo@304:         initAxisParameters(document);
ingo@304:         initLegendParameters(document);
ingo@327:         initRenderer(document);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private void initTitleParameters(Document document) {
ingo@304:         log.debug("init title parameters.");
ingo@304: 
ingo@304:         int     size  = getInt(document, "theme/title/font/size/@value");
ingo@304:         String  type  = getString(document, "theme/title/font/type/@value");
ingo@304:         boolean bold  = getBool(document, "theme/title/font/bold/@value");
ingo@304: 
ingo@304:         setExtraLargeFont(createFont(type, size, bold));
ingo@304: 
ingo@304:         String color = getString(document, "theme/title/font/color/@value");
ingo@304:         Color  c     = decodeColor(color);
ingo@304:         if (c != null)
ingo@304:             setTitlePaint(c);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private void initSubtitleParameters(Document document) {
ingo@304:         log.debug("init title parameters.");
ingo@304: 
ingo@304:         int     size  = getInt(document, "theme/subtitle/font/size/@value");
ingo@304:         String  type  = getString(document, "theme/subtitle/font/type/@value");
ingo@304:         boolean bold  = getBool(document, "theme/subtitle/font/bold/@value");
ingo@304: 
ingo@304:         setLargeFont(createFont(type, size, bold));
ingo@304: 
ingo@304:         String col  = getString(document, "theme/subtitle/font/color/@value");
ingo@304:         setSubtitlePaint(Color.decode(col));
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private void initChartParameters(Document document) {
ingo@304:         log.debug("init chart parameters.");
ingo@304: 
ingo@304:         String bg = getString(document, "theme/chart/background/color/@value");
ingo@304:         Color  c  = decodeColor(bg);
ingo@304:         if (c != null)
ingo@304:             setChartBackgroundPaint(c);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private void initPlotParameters(Document document) {
ingo@304:         log.debug("init plot parameters.");
ingo@304: 
ingo@304:         String tmp = null;
ingo@304:         tmp        = getString(document, "theme/plot/background/color/@value");
ingo@304:         Color  c   = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setPlotBackgroundPaint(c);
ingo@304: 
ingo@304:         tmp = getString(document, "theme/plot/outline/color/@value");
ingo@304:         c   = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setPlotOutlinePaint(c);
ingo@304: 
ingo@304:         tmp = getString(document, "theme/plot/domaingridline/color/@value");
ingo@304:         c   = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setDomainGridlinePaint(c);
ingo@304: 
ingo@304:         tmp = getString(document, "theme/plot/rangegridline/color/@value");
ingo@304:         c   = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setRangeGridlinePaint(c);
ingo@304: 
ingo@304:         boolean rangeCrosshairVisible = getBool(
ingo@304:             document, "theme/plot/rangecrosshair/visible/@value");
ingo@304:         setRangeCrosshairVisible(rangeCrosshairVisible);
ingo@304: 
ingo@304:         boolean domainCrosshairVisible = getBool(
ingo@304:             document, "theme/plot/domaincrosshair/visible/@value");
ingo@304:         setDomainCrosshairVisible(domainCrosshairVisible);
ingo@304: 
ingo@304:         int top    = getInt(document, "theme/plot/offset/top/@value");
ingo@304:         int bottom = getInt(document, "theme/plot/offset/bottom/@value");
ingo@304:         int left   = getInt(document, "theme/plot/offset/left/@value");
ingo@304:         int right  = getInt(document, "theme/plot/offset/right/@value");
ingo@304:         setAxisOffset(new RectangleInsets(
ingo@304:             UnitType.RELATIVE,
ingo@304:             top, left, bottom, right)
ingo@304:         );
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private void initAxisParameters(Document document) {
ingo@304:         log.debug("init axis parameters.");
ingo@304: 
ingo@304:         String tmp = null;
ingo@304:         tmp        = getString(document, "theme/axis/label/color/@value");
ingo@304:         Color c    = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setAxisLabelPaint(c);
ingo@304: 
ingo@304:         tmp = getString(document, "theme/axis/ticklabel/color/@value");
ingo@304:         c   = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setTickLabelPaint(c);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private void initLegendParameters(Document document) {
ingo@304:         log.debug("init legend parameters.");
ingo@304: 
ingo@304:         String tmp = null;
ingo@304:         tmp        = getString(document, "theme/legend/font/color/@value");
ingo@304:         Color c    = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setLegendItemPaint(c);
ingo@304: 
ingo@304:         tmp = getString(document, "theme/legend/background/color/@value");
ingo@304:         c   = decodeColor(tmp);
ingo@304:         if (c != null)
ingo@304:             setLegendBackgroundPaint(c);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@327:     private void initRenderer(Document document) {
ingo@327:         log.debug("init renderer parameters.");
ingo@327: 
ingo@327:         pointWidth  = getInt(document, "theme/plot/itemrenderer/width/@value");
ingo@327:         log.debug("Read point width of " + pointWidth);
ingo@327:         pointHeight = getInt(document, "theme/plot/itemrenderer/height/@value");
ingo@327:         log.debug("Read point height of " + pointHeight);
ingo@327:         renderLines = getBool(
ingo@327:             document, "theme/plot/itemrenderer/renderLines/@value"
ingo@327:         );
ingo@327:         renderShapes = getBool(
ingo@327:             document, "theme/plot/itemrenderer/renderPoints/@value"
ingo@327:         );
ingo@327:     }
ingo@327: 
ingo@327: 
ingo@304:     private static String getString(Document document, String xpath) {
ingo@304:         return Config.getStringXPath(document, xpath);
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private static int getInt(Document document, String xpath) {
ingo@304:         String tmp = getString(document, xpath);
ingo@304: 
ingo@304:         if (tmp != null)
ingo@304:             return Integer.parseInt(tmp);
ingo@304:         else
ingo@304:             return 0;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     private static boolean getBool(Document document, String xpath) {
ingo@304:         String tmp = getString(document, xpath);
ingo@304: 
ingo@304:         if (tmp != null)
ingo@304:             return Boolean.parseBoolean(tmp);
ingo@304:         else
ingo@304:             return false;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     protected Color decodeColor(String color) {
ingo@304:         try {
ingo@304:             if (color == null)
ingo@304:                 return null;
ingo@304: 
ingo@304:             return Color.decode(color);
ingo@304:         }
ingo@304:         catch (NumberFormatException nfe) {
ingo@304:             log.warn("Error while parsing color: " + color, nfe);
ingo@304:         }
ingo@304: 
ingo@304:         return null;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     protected Font createFont(String type, int size, boolean bold) {
ingo@304:         Font font = null;
ingo@304:         if (bold)
ingo@304:             font = new Font(type, Font.BOLD, size);
ingo@304:         else
ingo@304:             font = new Font(type, Font.PLAIN, size);
ingo@304: 
ingo@304:         return font;
ingo@304:     }
ingo@304: 
ingo@304: 
ingo@304:     protected void applyToXYPlot(XYPlot plot) {
ingo@304:         log.debug("apply theme parameter to XYPlot");
ingo@304: 
ingo@304:         super.applyToXYPlot(plot);
ingo@304:         plot.setDomainCrosshairVisible(this.domainCrosshairVisible);
ingo@304:         plot.setRangeCrosshairVisible(this.rangeCrosshairVisible);
ingo@327: 
ingo@327:         applyToXYLineAndShapeRenderer(plot);
ingo@327:     }
ingo@327: 
ingo@327: 
ingo@327:     protected void applyToXYLineAndShapeRenderer(XYPlot plot) {
ingo@327:         if (plot == null)
ingo@327:             return;
ingo@327: 
ingo@327:         XYLineAndShapeRenderer renderer =
ingo@327:             (XYLineAndShapeRenderer) plot.getRenderer();
ingo@327: 
ingo@327:         Ellipse2D.Double point = new Ellipse2D.Double(
ingo@327:             -(pointWidth/2), -(pointHeight/2), pointWidth, pointHeight
ingo@327:         );
ingo@327: 
ingo@327:         renderer.setSeriesShape(0, point);
ingo@327:         renderer.setSeriesShapesVisible(0, renderShapes);
ingo@327:         renderer.setSeriesLinesVisible(0, renderLines);
ingo@327: 
ingo@327:         plot.setRenderer(renderer);
ingo@304:     }
ingo@304: }