zul/src/main/java/org/zkoss/zul/DialModelScale.java

Summary

Maintainability
D
2 days
Test Coverage
/* DialModelScale.java

    Purpose:
        
    Description:
        
    History:
        Jun 24, 2009 5:21:08 PM, Created by henrichen

Copyright (C) 2009 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
    This program is distributed under LGPL Version 2.0 in the hope that
    it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/

package org.zkoss.zul;

import java.awt.Font;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.zkoss.lang.Objects;
import org.zkoss.zul.event.ChartDataEvent;
import org.zkoss.zul.event.DialChartDataEvent;

/**
 * A set of information of a scale in a Dial chart. You cannot new a DialModelScale
 * directly; instead, use {@link DialModel#newScale()} to start setting the scale.
 * @author henrichen
 *
 */
public class DialModelScale implements Serializable {
    private DialModel _model;

    //data
    private double _value;

    //text annotation
    private String _text;
    private Font _textFont; //14, 10
    private double _textRadius = 0.7; //0.7, 0.5

    //value indicator
    private Font _valueFont; //10, 10
    private double _valueRadius = 0.6; //0.6, 0.6
    private double _valueAngle = -90; //-103.0, -77.0 

    //tick
    private Font _tickFont; //14, 10
    private double _tickRadius = 0.88; //0.88, 0.50
    private String _tickColor; //tick, 0xFF0000
    private int[] _tickRGB; //tick, red, green, blue (0 ~ 255, 0 ~ 255, 0 ~ 255)
    private double _tickLabelOffset = 0.20; //offset between tick and tick label

    //scale
    double _lowerBound;
    double _upperBound;
    double _startAngle;
    double _extent;
    double _majorTickInterval;
    int _minorTickCount;

    //ranges
    private List<DialModelRange> _ranges = new ArrayList<DialModelRange>(4);

    //needle
    private String _needleType = "pointer"; //"pointer", "pin"
    private String _needleColor; //needle, 0xFF0000
    private int[] _needleRGB; //needle, red, green, blue (0 ~ 255, 0 ~ 255, 0 ~ 255)
    private double _needleRadius = 0.9; //0.9, 0.55

    /*package*/ DialModelScale(DialModel model) {
        _model = model;
    }

    public int getIndex() {
        return _model.indexOf(this);
    }

    /** Get the value */
    public double getValue() {
        return _value;
    }

    public void setValue(double val) {
        if (Double.compare(_value, val) != 0) {
            _value = val;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.SCALE_VALUE, val);
        }
    }

    /**
     * Returns the text annotation of this scale.
     */
    public String getText() {
        return _text;
    }

    /**
     * Sets the text annotation of this scale; e.g. "Temperature" for a temperature dial meter.
     * @param text text annotation(subtitle) of this scale.
     */
    public void setText(String text) {
        if (!Objects.equals(text, _text)) {
            _text = text;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.SCALE_TEXT, text);
        }
    }

    /**
     * Returns the text annotation font.
     * @return the text annotation font.
     */
    public Font getTextFont() {
        return _textFont;
    }

    /**
     * Sets the text annotation font.
     * @param font the text annotation font.
     */
    public void setTextFont(Font font) {
        if (!Objects.equals(font, _textFont)) {
            _textFont = font;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.SCALE_FONT, font);
        }
    }

    /**
     * Return the radius percentage(0 ~ 1) to place the text annotation.
     * @return the radius percentage(0 ~ 1) to place the text annotation.
     */
    public double getTextRadius() {
        return _textRadius;
    }

    /**
     * Sets the radius percentage(0 ~ 1) to place the text annotation.
     * @param radius radius percentage(0 ~ 1) to place the text annotation.
     */
    public void setTextRadius(double radius) {
        if (Double.compare(_textRadius, radius) != 0) {
            _textRadius = radius;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.TEXT_RADIUS, radius);
        }
    }

    /**
     * Returns the value font.
     * @return the value font.
     */
    public Font getValueFont() {
        return _valueFont;
    }

    /**
     * Sets the value font.
     * @param font the value font.
     */
    public void setValueFont(Font font) {
        if (!Objects.equals(font, _valueFont)) {
            _valueFont = font;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.VALUE_FONT, font);
        }
    }

    /**
     * Return the radius percentage(0 ~ 1) to place the value.
     * @return the radius percentage(0 ~ 1) to place the value.
     */
    public double getValueRadius() {
        return _valueRadius;
    }

    /**
     * Sets the radius percentage(0 ~ 1) to place the value.
     * @param radius radius percentage(0 ~ 1) to place the value.
     */
    public void setValueRadius(double radius) {
        if (Double.compare(_valueRadius, radius) != 0) {
            _valueRadius = radius;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.VALUE_RADIUS, radius);
        }
    }

    /**
     * Return the angle to place the value (counter clockwise is positive).
     * @return the angle to place the value (counter clockwise is positive).
     */
    public double getValueAngle() {
        return _valueAngle;
    }

    /**
     * Sets the angle in degree to place the value (counter clockwise is positive).
     * @param angle angle in degree to place the value (counter clockwise is positive).
     */
    public void setValueAngle(double angle) {
        if (Double.compare(_valueAngle, angle) != 0) {
            _valueAngle = angle;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.VALUE_ANGLE, angle);
        }
    }

    /**
     * Sets the scale information of this DialModelScale.
     * @param lowerBound lower bound of this scale.
     * @param upperBound upper bound of this scale.
     * @param startAngle starting angle in degree associated to the sclae's lower bound(0 degree point to east, counter-clockwise is positive). 
     * @param extent angles in degree extended from the starting angle (counter clockwise is positive).
     * @param majorTickInterval the interval between major tick (in lower bound and upper bound).
     * @param minorTickCount the number of minor ticks between major tick.
     */
    public void setScale(double lowerBound, double upperBound, double startAngle, double extent,
            double majorTickInterval, int minorTickCount) {
        if (Double.compare(lowerBound, _lowerBound) != 0 || Double.compare(upperBound, _upperBound) != 0
                || Double.compare(startAngle, _startAngle) != 0 || Double.compare(extent, _extent) != 0
                || Double.compare(majorTickInterval, _majorTickInterval) != 0
                || Double.compare(minorTickCount, _minorTickCount) != 0) {
            _lowerBound = lowerBound;
            _upperBound = upperBound;
            _startAngle = startAngle;
            _extent = extent;
            _majorTickInterval = majorTickInterval;
            _minorTickCount = minorTickCount;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.SCALE, this);
        }
    }

    /**
     * Returns the scale's lower bound.
     * @return the scale's lower bound.
     */
    public double getScaleLowerBound() {
        return _lowerBound;
    }

    /**
     * Returns the scale's upper bound.
     * @return the scale's upper bound.
     */
    public double getScaleUpperBound() {
        return _upperBound;
    }

    /**
     * Returns starting angle in degree associated to the sclae's lower bound
     * (0 degree point to east, counter-clockwise is positive).
     * @return starting angle in degree associated to the sclae's lower bound
     * (0 degree point to east, counter-clockwise is positive).
     */
    public double getScaleStartAngle() {
        return _startAngle;
    }

    /**
     * Returns angles in degree extended from the starting angle (counter clockwise is positive).
     * @return angles in degree extended from the starting angle (counter clockwise is positive).
     */
    public double getScaleExtent() {
        return _extent;
    }

    /**
     * Returns the interval between major tick (in lower bound and upper bound).
     * @return the interval between major tick (in lower bound and upper bound).
     */
    public double getMajorTickInterval() {
        return _majorTickInterval;
    }

    /**
     * returns the number of minor ticks between major tick.
     * @return the number of minor ticks between major tick.
     */
    public int getMinorTickCount() {
        return _minorTickCount;
    }

    /**
     * Returns the tick label font.
     * @return the tick label font.
     */
    public Font getTickFont() {
        return _tickFont;
    }

    /**
     * Sets the tick label font.
     * @param font the tick label font.
     */
    public void setTickFont(Font font) {
        if (!Objects.equals(font, _tickFont)) {
            _tickFont = font;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.TICK_FONT, font);
        }
    }

    /**
     * Return the radius percentage(0 ~ 1) to place the tick label.
     * @return the radius percentage(0 ~ 1) to place the tick label.
     */
    public double getTickRadius() {
        return _tickRadius;
    }

    /**
     * Sets the radius percentage(0 ~ 1) to place the tick label.
     * @param radius radius percentage(0 ~ 1) to place the tick label.
     */
    public void setTickRadius(double radius) {
        if (Double.compare(_tickRadius, radius) != 0) {
            _tickRadius = radius;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.TICK_RADIUS, radius);
        }
    }

    /**
     * Returns the radius offset in percentage(0 ~ 1) between the tick and tick label.
     * @return the radius offset in percentage(0 ~ 1) between the tick and tick label.
     */
    public double getTickLabelOffset() {
        return _tickLabelOffset;
    }

    /**
     * Sets the radius offset in percentage(0 ~ 1) between the tick and tick label.
     * @param tickLabelOffset the radius offset in percentage(0 ~ 1) between the tick and tick label.
     */
    public void setTickLabelOffset(double tickLabelOffset) {
        if (Double.compare(_tickLabelOffset, tickLabelOffset) != 0) {
            _tickLabelOffset = tickLabelOffset;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.TICK_LABEL_OFFSET, tickLabelOffset);
        }
    }

    /**
     * Set the tick color.
     * @param color in #RRGGBB format (hexadecimal).
     */
    public void setTickColor(String color) {
        if (Objects.equals(color, _tickColor)) {
            return;
        }
        _tickColor = color;
        if (_tickColor == null) {
            _tickRGB = null;
        } else {
            _tickRGB = new int[3];
            Chart.decode(_tickColor, _tickRGB);
        }
        fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.TICK_COLOR, color);
    }

    /**
     * Get the tick color of this scale(in string as #RRGGBB).
     * null means default.
     */
    public String getTickColor() {
        return _tickColor;
    }

    /**
     * Get the tick color of this scale in int array (0: red, 1: green, 2:blue).
     * null means default.
     */
    public int[] getTickRGB() {
        return _tickRGB;
    }

    /**
     * Setup the DailModel range.
     * @param lower the lower bound in the scale.
     * @param upper the upper bound in the scale.
     * @param color the color in #RRGGBB format (hexadecimal); default to blue.
     * @param innerRadius the inner radius percentage(0 ~ 1) of the range; default to 0.7.
     * @param outerRadius the outer radius percentage(0 ~ 1) of the range; default to 0.8;
     */
    public DialModelRange newRange(double lower, double upper, String color, double innerRadius, double outerRadius) {
        final DialModelRange range = new DialModelRange(this);
        range.setRange(lower, upper, color, innerRadius, outerRadius);
        _ranges.add(range);
        fireEvent(ChartDataEvent.ADDED, DialChartDataEvent.RANGE, range);
        return range;
    }

    /** Returns the number of ranges associated with this scale.
     * 
     * @return the number of ranges associated with this scale.
     */
    public int rangeSize() {
        return _ranges.size();
    }

    /** Returns the color range of the specified index.
     * 
     * @param index the specified index.
     * @return the color range of the specified index.
     */
    public DialModelRange getRange(int index) {
        return _ranges.get(index);
    }

    /**
     * Removes the specified range from this scale.
     * @param range the range to be removed.
     */
    public void removeRange(DialModelRange range) {
        int index = _ranges.indexOf(range);
        _ranges.remove(range);
        fireEvent(ChartDataEvent.REMOVED, DialChartDataEvent.RANGE, index);
    }

    /**
     * Returns the needle type of this scale ("pointer" or "pin")
     * @return the needle type of this scale ("pointer" or "pin")
     */
    public String getNeedleType() {
        return _needleType;
    }

    /**
     * Sets the needle type of this scale ("pointer" or "pin")
     * @param type the needle type of this scale ("pointer" or "pin")
     */
    public void setNeedleType(String type) {
        if (!Objects.equals(_needleType, type)) {
            _needleType = type;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.NEEDLE_TYPE, type);
        }
    }

    /**
     * Set the needle color.
     * @param color in #RRGGBB format (hexadecimal).
     */
    public void setNeedleColor(String color) {
        if (Objects.equals(color, _needleColor)) {
            return;
        }
        _needleColor = color;
        if (_needleColor == null) {
            _needleRGB = null;
        } else {
            _needleRGB = new int[3];
            Chart.decode(_needleColor, _needleRGB);
        }
        fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.NEEDLE_COLOR, color);
    }

    /**
     * Get the needle color of this scale(in string as #RRGGBB).
     * null means default.
     */
    public String getNeedleColor() {
        return _needleColor;
    }

    /**
     * Get the needle color of this scale in int array (0: red, 1: green, 2:blue).
     * null means default.
     */
    public int[] getNeedleRGB() {
        return _needleRGB;
    }

    /**
     * Sets the radius percentage(0 ~ 1) of the scale's needle; default to 0.9.
     * @param radius the radius percentage(0 ~ 1) of the scale's needle; default to 0.9.
     */
    public void setNeedleRadius(double radius) {
        if (Double.compare(_needleRadius, radius) != 0) {
            _needleRadius = radius;
            fireEvent(ChartDataEvent.CHANGED, DialChartDataEvent.NEEDLE_RADIUS, radius);
        }
    }

    /**
     * Return the radius percentage(0 ~ 1) of the scale's needle; default to 0.9.
     * @return the radius percentage(0 ~ 1) of the scale's needle; default to 0.9.
     */
    public double getNeedleRadius() {
        return _needleRadius;
    }

    /**
     * Utility method to delegate event to {@link DialModel}
     * @param evt the {@link ChartDataEvent}.
     */
    /*package*/ void fireEvent(int evt, String propertyKey, Object data) {
        if (_model != null)
            _model.fireEvent(evt, propertyKey, data);
    }
}