userinterface.graph.SeriesSettings.java Source code

Java tutorial

Introduction

Here is the source code for userinterface.graph.SeriesSettings.java

Source

//==============================================================================
//   
//   Copyright (c) 2002-
//   Authors:
//   * Mark Kattenbelt <mark.kattenbelt@comlab.ox.ac.uk> (University of Oxford)
//   * Alistair John Strachan <alistair@devzero.co.uk> (University of Edinburgh)
//   * Mike Arthur <mike@mikearthur.co.uk> (University of Edinburgh)
//   * Zak Cohen <zakcohen@gmail.com> (University of Edinburgh)
//   
//------------------------------------------------------------------------------
//   
//   This file is part of PRISM.
//   
//   PRISM is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation; either version 2 of the License, or
//   (at your option) any later version.
//   
//   PRISM 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 General Public License for more details.
//   
//   You should have received a copy of the GNU General Public License
//   along with PRISM; if not, write to the Free Software Foundation,
//   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//   
//==============================================================================

package userinterface.graph;

import java.util.*;

import java.awt.*;
import java.awt.geom.*;

import javax.swing.*;
import org.jfree.chart.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.util.*;
import org.w3c.dom.Element;

import settings.*;

/** 
 * A class representing a series of a Graph. This class should not be used to
 * modify data, use Graph for this. The intention is that this class
 * represents all properties (colour, lines, heading, etc.) other than data.
 */
public class SeriesSettings extends Observable implements SettingOwner {
    /** shape index constants */
    public static final int CIRCLE = 0;
    public static final int SQUARE = 1;
    public static final int TRIANGLE = 2;
    public static final int RECTANGLE_H = 3;
    public static final int RECTANGLE_V = 4;
    public static final int NONE = 5;

    public static final int SOLID = 0;
    public static final int DASHED = 1;
    public static final int DOT_DASHED = 2;

    public static final int BLUE = 0;
    public static final int GREEN = 1;
    public static final int RED = 2;
    public static final int CYAN = 3;
    public static final int PURPLE = 4;
    public static final int YELLOW = 5;
    public static final int BROWN = 5;

    public static final Shape[] DEFAULT_SHAPE_SEQUENCE = { DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[1], // CIRCLE
            DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[0], // SQUARE
            DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[2], // TRIANGLE
            DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[4], // RECTANGLE_H
            DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE[8], // RECTANGLE_V
    };

    // Use slightly smaller point shapes than the JFreeChart standards
    protected static int triPointsX[] = { -2, 2, 0 };
    protected static int triPointsY[] = { -2, -2, 2 };

    /* List of all shapes, including empty shape */
    protected static final Shape[] SHAPES = { new Ellipse2D.Double(-2, -2, 4, 4),
            new Rectangle2D.Double(-2, -2, 4, 4), new Polygon(triPointsX, triPointsY, 3),
            new Rectangle2D.Double(-2, -1, 4, 2), new Rectangle2D.Double(-1, -2, 2, 4),
            new Rectangle2D.Double(0, 0, 0, 0) // NONE       
    };

    protected static final Shape[] DEFAULT_SHAPES = { SHAPES[CIRCLE], SHAPES[SQUARE], SHAPES[TRIANGLE],
            SHAPES[RECTANGLE_H], SHAPES[RECTANGLE_V] };

    protected static final Paint[] DEFAULT_PAINTS = { Color.blue, new Color(0, 127, 0), Color.red,
            new Color(0, 191, 191), new Color(191, 0, 191), new Color(191, 191, 0), new Color(0.6f, 0.2f, 0f) };

    /** Graph object. */
    private Graph graph;

    /** JFreeChart representation of graphs. */
    private JFreeChart chart;

    /** XYPlot of this JFreeChart */
    private XYPlot plot;

    /** Key of this series. */
    private Graph.SeriesKey key;

    /** The XYItemRenderer for this series. */
    private XYLineAndShapeRenderer renderer;

    /** Settings of a series. */
    private SingleLineStringSetting seriesHeading;
    private ColorSetting seriesColour;
    private BooleanSetting showPoints;
    private ChoiceSetting seriesShape;
    private BooleanSetting showLines;
    private DoubleSetting lineWidth;
    private ChoiceSetting lineStyle;
    //  private SeriesDataSetting dataProp;    

    /** Display for settings. */
    private SettingDisplay display;

    private GraphSeriesIcon icon;

    public SeriesSettings(Graph graph, Graph.SeriesKey key) {
        this.graph = graph;
        this.key = key;
        this.chart = graph.getChart();
        this.plot = chart.getXYPlot();

        /* This should really be checked first. */
        this.renderer = (XYLineAndShapeRenderer) plot.getRenderer();

        seriesHeading = new SingleLineStringSetting("heading", "heading",
                "The heading for this series, as displayed in the legend.", this, true);
        seriesColour = new ColorSetting("colour", Color.black,
                "The colour for all lines and points in this series.", this, true);
        showPoints = new BooleanSetting("show points", new Boolean(true),
                "Should points be displayed for this series?", this, true);
        String[] choices = { "Circle", "Square", "Triangle", "Horizontal Rectangle", "Vertical Rectangle", "None" };
        seriesShape = new ChoiceSetting("point shape", choices, choices[0], "The shape of points for this series.",
                this, true);
        showLines = new BooleanSetting("show lines", new Boolean(true),
                "Should lines be displayed for this series?", this, true);
        lineWidth = new DoubleSetting("line width", new Double(1.0), "The line width for this series.", this, true,
                new RangeConstraint("0.0,"));
        String[] styles = { "---------", "- - - - -", "- -- - --" };
        lineStyle = new ChoiceSetting("line style", styles, styles[0], "The line style for this series.", this,
                true);

        /** JFreeChart is smart enough to choose sensible values for colours, shapes etc. Lets try to use these if we can. */
        synchronized (graph.getSeriesLock()) {
            int seriesIndex = graph.getJFreeChartIndex(key);

            if (seriesIndex >= 0) {
                /* Set series colour. */
                if (renderer.lookupSeriesPaint(seriesIndex) instanceof Color) {
                    try {
                        seriesColour.setValue((Color) renderer.getSeriesPaint(seriesIndex));
                    } catch (SettingException e) {
                    }
                }

                /* Set series heading. */
                try {
                    seriesHeading.setValue(graph.getXYSeries(key).getKey());
                } catch (SettingException e) {
                }

                /* Set showPoints. */
                try {
                    // just do it.
                    Boolean pointsVisibleFlag = true;
                    showPoints.setValue(new Boolean(pointsVisibleFlag == null || pointsVisibleFlag.booleanValue()));
                } catch (SettingException e) {
                }

                /* Set seriesShape. */
                Shape shape = renderer.lookupSeriesShape(seriesIndex);

                try {
                    boolean foundShape = false;

                    for (int i = CIRCLE; i < NONE; i++) {
                        if (ShapeUtilities.equal(shape, SHAPES[i])) {
                            seriesShape.setSelectedIndex(i);
                            foundShape = true;
                            break;
                        }
                    }

                    if (!foundShape)
                        seriesShape.setSelectedIndex(NONE);
                } catch (SettingException e) {
                    e.printStackTrace();
                }

                /* Set showLines. */
                try {
                    Boolean linesVisibleFlag = true;
                    showLines.setValue(new Boolean(linesVisibleFlag == null || linesVisibleFlag.booleanValue()));
                } catch (SettingException e) {
                }
            }
        }

        updateSeries();
    }

    public SettingDisplay getDisplay() {
        return display;
    }

    public int getNumSettings() {
        return 7;
    }

    public Setting getSetting(int index) {
        switch (index) {
        case 0:
            return seriesHeading;
        case 1:
            return seriesColour;
        case 2:
            return showPoints;
        case 3:
            return seriesShape;
        case 4:
            return showLines;
        case 5:
            return lineWidth;
        case 6:
            return lineStyle;
        default:
            return null;
        }
    }

    public String getSettingOwnerClassName() {
        return "Series";
    }

    public int getSettingOwnerID() {
        return prism.PropertyConstants.GRAPH_DISPLAY;
    }

    public String getSettingOwnerName() {
        return seriesHeading.getStringValue();
    }

    public void notifySettingChanged(Setting setting) {
        updateSeries();
        setChanged();
        notifyObservers(this);
    }

    public void setDisplay(SettingDisplay display) {
        this.display = display;
    }

    public int compareTo(Object o) {
        if (o instanceof SettingOwner) {
            SettingOwner po = (SettingOwner) o;
            if (getSettingOwnerID() < po.getSettingOwnerID())
                return -1;
            else if (getSettingOwnerID() > po.getSettingOwnerID())
                return 1;
            else
                return 0;
        } else
            return 0;
    }

    /**
     * Getter for property seriesHeading.
     * @return Value of property seriesHeading.
     */
    public String getSeriesHeading() {
        return seriesHeading.getStringValue();
    }

    /**
     * Setter for property seriesHeading.
     * @param value Value of property seriesHeading.
     */
    public void setSeriesHeading(String value) {
        try {
            seriesHeading.setValue(value);
            updateSeries();
            setChanged();
            notifyObservers(this);
        } catch (SettingException e) {
            // Shouldn't happen.
        }
    }

    /**
     * Getter for property seriesColour.
     * @return Value of property seriesColour.
     */
    public Color getSeriesColour() {
        return seriesColour.getColorValue();
    }

    /**
     * Setter for property seriesColour.
     * @param value Value of property seriesColour.
     */
    public void setSeriesColour(Color value) {
        try {
            seriesColour.setValue(value);
            updateSeries();
            setChanged();
            notifyObservers(this);
        } catch (SettingException e) {
            // Shouldn't happen.
        }
    }

    /**
     * Getter for property showPoints.
     * @return Value of property showPoints.
     */
    public boolean showPoints() {
        return showPoints.getBooleanValue();
    }

    /**
     * Setter for property showPoints.
     * @param value Value of property showPoints.
     */
    public void showPoints(boolean value) {
        try {
            showPoints.setValue(new Boolean(value));
            updateSeries();
            setChanged();
            notifyObservers(this);
        } catch (SettingException e) {
            // Shouldn't happen.
        }
    }

    /**
     * Getter for property seriesShape.
     * @return Value of property seriesShape.
     */
    public int getSeriesShape() {
        return seriesShape.getCurrentIndex();
    }

    /**
     * Setter for property seriesShape.
     * @param value Value of property seriesShape.
     */
    public void setSeriesShape(int value) throws SettingException {
        seriesShape.setSelectedIndex(new Integer(value));
        updateSeries();
        setChanged();
        notifyObservers(this);
    }

    /**
     * Getter for property showLines.
     * @return Value of property showLines.
     */
    public boolean showLines() {
        return showLines.getBooleanValue();
    }

    /**
     * Setter for property showLines.
     * @param value Value of property showLines.
     */
    public void showLines(boolean value) {
        try {
            showLines.setValue(new Boolean(value));
            updateSeries();
            setChanged();
            notifyObservers(this);
        } catch (SettingException e) {
            // Shouldn't happen.
        }
    }

    /**
     * Getter for property lineWidth.
     * @return Value of property lineWidth.
     */
    public double getLineWidth() {
        return lineWidth.getDoubleValue();
    }

    /**
     * Setter for property lineWidth.
     * @param value Value of property lineWidth.
     */
    public void setLineWidth(double value) throws SettingException {
        lineWidth.setValue(new Double(value));
        updateSeries();
        setChanged();
        notifyObservers();
    }

    /**
     * Getter for property lineStyle.
     * @return Value of property lineStyle.
     */
    public int getLineStyle() {
        return lineStyle.getCurrentIndex();
    }

    /**
     * Setter for property lineStyle.
     * @param value Value of property lineStyle (SOLID, DASHED, DOT_DASHED).
     */
    public void setLineStyle(int value) throws SettingException {
        lineStyle.setSelectedIndex(new Integer(value));
        updateSeries();
        setChanged();
        notifyObservers(this);
    }

    public String toString() {
        return this.seriesHeading.getStringValue();
    }

    public void updateSeries() {
        // We don't want series to change while we are updating.
        synchronized (graph.getSeriesLock()) {
            int seriesIndex = graph.getJFreeChartIndex(key);

            if (seriesIndex >= 0) {
                /* Set series colour. */
                if (renderer.getSeriesPaint(seriesIndex) == null
                        || !renderer.getSeriesPaint(seriesIndex).equals(seriesColour)) {
                    renderer.setSeriesPaint(seriesIndex, seriesColour.getColorValue());
                }

                /* Set series heading. */
                if (!graph.getXYSeries(key).getKey().equals(seriesHeading.getStringValue())) {
                    graph.changeSeriesName(key, seriesHeading.getStringValue());
                    try {
                        seriesHeading.setValue(graph.getXYSeries(key).getKey());
                    } catch (SettingException e) {
                    }
                }

                /* Set showPoints. */
                Boolean pointsVisibleFlag = renderer.getSeriesShapesVisible(seriesIndex);

                if (pointsVisibleFlag == null || pointsVisibleFlag.booleanValue() != showPoints.getBooleanValue()) {
                    renderer.setSeriesShapesVisible(seriesIndex, showPoints.getBooleanValue());
                }

                /* Set seriesShape. */
                Shape shape = renderer.getSeriesShape(seriesIndex);
                int shapeIndex = seriesShape.getCurrentIndex();

                if (!ShapeUtilities.equal(shape, SHAPES[shapeIndex]))
                    renderer.setSeriesShape(seriesIndex, SHAPES[shapeIndex]);

                /* Set showLines. */
                Boolean linesVisibleFlag = renderer.getSeriesLinesVisible(seriesIndex);
                if (linesVisibleFlag == null || linesVisibleFlag.booleanValue() != showLines.getBooleanValue()) {
                    renderer.setSeriesLinesVisible(seriesIndex, showLines.getBooleanValue());
                }

                /* Set stroke - hard to check*/
                if (lineStyle.getCurrentIndex() == SOLID) // solid
                {
                    BasicStroke newStroke = new BasicStroke((float) lineWidth.getDoubleValue(),
                            BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f);
                    renderer.setSeriesStroke(seriesIndex, newStroke);
                } else if (lineStyle.getCurrentIndex() == DASHED) // Just dash
                {
                    float dash[] = { 2.0f, 3.0f };
                    BasicStroke newStroke = new BasicStroke((float) lineWidth.getDoubleValue(),
                            BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, dash, 1.0f);
                    renderer.setSeriesStroke(seriesIndex, newStroke);
                } else // Funny dash
                {
                    float dash[] = { 1.0f, 3.0f, 5.0f, 3.0f };
                    BasicStroke newStroke = new BasicStroke((float) lineWidth.getDoubleValue(),
                            BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, dash, 0.0f);
                    renderer.setSeriesStroke(seriesIndex, newStroke);
                }
            }

            icon = new GraphSeriesIcon(renderer.getSeriesShape(seriesIndex), renderer.getSeriesStroke(seriesIndex),
                    seriesColour.getColorValue(), showLines.getBooleanValue(), showPoints.getBooleanValue());
            icon.setOpaque(false);
            icon.setMinimumSize(new Dimension(20, 10));
            icon.setMaximumSize(new Dimension(50, 20));
            icon.setPreferredSize(new Dimension(30, 10));
        }
    }

    public Graph.SeriesKey getSeriesKey() {
        return key;
    }

    /** Creates a renderer for the icon of this series in the options dialog. */
    public JComponent getIcon() {
        return this.icon;
    }

    private class GraphSeriesIcon extends JComponent {
        private Shape shape;
        private Stroke stroke;
        private Color color;

        private boolean showLines;
        private boolean showShapes;

        public GraphSeriesIcon(Shape shape, Stroke stroke, Color color, boolean showLines, boolean showShapes) {
            this.shape = shape;
            this.stroke = stroke;
            this.color = color;

            this.showLines = showLines;
            this.showShapes = showShapes;
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            float width = this.getWidth();
            float height = this.getHeight();

            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            g2d.setColor(color);
            g2d.setStroke(stroke);
            g2d.translate(width / 2, height / 2);

            if (showLines)
                g2d.drawLine(-(int) width / 2, 0, (int) width / 2, 0);
            if (showShapes)
                g2d.fill(shape);

            g2d.dispose();
        }
    }

    public void save(Element series) throws SettingException {
        series.setAttribute("seriesHeading", getSeriesHeading());
        series.setAttribute("lineWidth", "" + getLineWidth());

        Color seriesColor = getSeriesColour();
        series.setAttribute("seriesColourR", "" + seriesColor.getRed());
        series.setAttribute("seriesColourG", "" + seriesColor.getGreen());
        series.setAttribute("seriesColourB", "" + seriesColor.getBlue());

        series.setAttribute("showPoints", showPoints() ? "true" : "false");
        series.setAttribute("showLines", showLines() ? "true" : "false");

        int lineStyle = getLineStyle();

        switch (lineStyle) {
        case (DASHED):
            series.setAttribute("lineStyle", "dashed");
            break;
        case (DOT_DASHED):
            series.setAttribute("lineStyle", "dotDashed");
            break;
        default:
            series.setAttribute("lineStyle", "normal");
        }

        int seriesShape = getSeriesShape();

        switch (seriesShape) {
        case (CIRCLE):
            series.setAttribute("seriesShape", "circle");
            break;
        case (SQUARE):
            series.setAttribute("seriesShape", "square");
            break;
        case (TRIANGLE):
            series.setAttribute("seriesShape", "triangle");
            break;
        case (RECTANGLE_H):
            series.setAttribute("seriesShape", "rectangle_h");
            break;
        case (RECTANGLE_V):
            series.setAttribute("seriesShape", "rectangle_v");
            break;
        default:
            series.setAttribute("seriesShape", "none");
        }
    }

    public void load(Element series) throws SettingException {
        setSeriesHeading(series.getAttribute("seriesHeading"));

        double lineWidth = Graph.parseDouble(series.getAttribute("lineWidth"));

        if (!Double.isNaN(lineWidth)) {
            setLineWidth(lineWidth);
        }

        String seriesColourR = series.getAttribute("seriesColourR");
        String seriesColourG = series.getAttribute("seriesColourG");
        String seriesColourB = series.getAttribute("seriesColourB");

        Color seriesColor = Graph.parseColor(seriesColourR, seriesColourG, seriesColourB);

        setSeriesColour(seriesColor);
        showPoints(Graph.parseBoolean(series.getAttribute("showPoints")));
        showLines(Graph.parseBoolean(series.getAttribute("showLines")));

        String lineStyle = series.getAttribute("lineStyle");

        if (lineStyle.equals("dashed"))
            this.setLineStyle(DASHED);
        else if (lineStyle.equals("dotDashed"))
            this.setLineStyle(DOT_DASHED);
        else
            this.setLineStyle(SOLID);

        String seriesShape = series.getAttribute("seriesShape");

        if (seriesShape.equals("circle"))
            this.setSeriesShape(CIRCLE);
        else if (seriesShape.equals("square"))
            this.setSeriesShape(SQUARE);
        else if (seriesShape.equals("triangle"))
            this.setSeriesShape(TRIANGLE);
        else if (seriesShape.equals("rectangle_h"))
            this.setSeriesShape(RECTANGLE_H);
        else if (seriesShape.equals("rectangle_v"))
            this.setSeriesShape(RECTANGLE_V);
        else
            this.setSeriesShape(NONE);
    }
}