001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2000, Institut de Recherche pour le Développement
006: * (C) 1999, Pêches et Océans Canada
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Lesser General Public
010: * License as published by the Free Software Foundation; either
011: * version 2.1 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Lesser General Public License for more details.
017: */
018: package org.geotools.axis;
019:
020: // J2SE dependencies
021: import java.awt.RenderingHints;
022: import java.text.Format;
023: import java.text.NumberFormat;
024: import java.util.Locale;
025:
026: // Units dependencies
027: import javax.units.Unit;
028: import javax.units.Converter;
029: import javax.units.ConversionException;
030:
031: /**
032: * A graduation using numbers on a linear axis.
033: *
034: * @since 2.0
035: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/axis/NumberGraduation.java $
036: * @version $Id: NumberGraduation.java 23632 2006-12-29 22:13:51Z desruisseaux $
037: * @author Martin Desruisseaux
038: */
039: public class NumberGraduation extends AbstractGraduation {
040: /**
041: * Serial number for interoperability with different versions.
042: */
043: private static final long serialVersionUID = -3074504745332240845L;
044:
045: /**
046: * The minimal value for this graduation. Default to 0.
047: */
048: private double minimum = 0;
049:
050: /**
051: * The maximal value for this graduation. Default to 10.
052: */
053: private double maximum = 10;
054:
055: /**
056: * Construct a graduation with the supplied units.
057: *
058: * @param unit The axis's units, or {@code null} if unknow.
059: */
060: public NumberGraduation(final Unit unit) {
061: super (unit);
062: }
063:
064: /**
065: * Set the minimum value for this graduation. If the new minimum is greater
066: * than the current maximum, then the maximum will also be set to a value
067: * greater than or equals to the minimum.
068: *
069: * @param value The new minimum in {@link #getUnit} units.
070: * @return {@code true} if the state of this graduation changed
071: * as a result of this call, or {@code false} if the new
072: * value is identical to the previous one.
073: * @throws IllegalArgumentException Si {@code value} is NaN ou infinite.
074: *
075: * @see #getMinimum
076: * @see #setMaximum(double)
077: */
078: public synchronized boolean setMinimum(final double value)
079: throws IllegalArgumentException {
080: ensureFinite("minimum", value);
081: double old = minimum;
082: minimum = value;
083: final Double valueObject = new Double(value);
084: listenerList.firePropertyChange("minimum", new Double(old),
085: valueObject);
086: if (maximum < value) {
087: old = maximum;
088: maximum = value;
089: listenerList.firePropertyChange("maximum", new Double(old),
090: valueObject);
091: return true;
092: }
093: return Double.doubleToLongBits(value) != Double
094: .doubleToLongBits(old);
095: }
096:
097: /**
098: * Set the maximum value for this graduation. If the new maximum is less than the current
099: * minimum, then the minimum will also be set to a value less than or equals to the maximum.
100: *
101: * @param value The new maximum in {@link #getUnit} units.
102: * @return {@code true} if the state of this graduation changed as a result of this call,
103: * or {@code false} if the new value is identical to the previous one.
104: * @throws IllegalArgumentException If {@code value} is NaN ou infinite.
105: *
106: * @see #getMaximum
107: * @see #setMinimum(double)
108: */
109: public synchronized boolean setMaximum(final double value)
110: throws IllegalArgumentException {
111: ensureFinite("maximum", value);
112: double old = maximum;
113: maximum = value;
114: final Double valueObject = new Double(value);
115: listenerList.firePropertyChange("maximum", new Double(old),
116: valueObject);
117: if (minimum > value) {
118: old = minimum;
119: minimum = value;
120: listenerList.firePropertyChange("minimum", new Double(old),
121: valueObject);
122: return true;
123: }
124: return Double.doubleToLongBits(value) != Double
125: .doubleToLongBits(old);
126: }
127:
128: /**
129: * Returns the minimal value for this graduation
130: *
131: * @return The minimal value in {@link #getUnit} units.
132: *
133: * @see #setMinimum(double)
134: * @see #getMaximum
135: * @see #getRange
136: */
137: public double getMinimum() {
138: return minimum;
139: }
140:
141: /**
142: * Returns the maximal value for this graduation.
143: *
144: * @return The maximal value in {@link #getUnit} units.
145: *
146: * @see #setMaximum(double)
147: * @see #getMinimum
148: * @see #getRange
149: */
150: public double getMaximum() {
151: return maximum;
152: }
153:
154: /**
155: * Returns the graduation's range. This is equivalents to computing
156: * <code>{@link #getMaximum}-{@link #getMinimum}</code>.
157: */
158: public synchronized double getRange() {
159: return (maximum - minimum);
160: }
161:
162: /**
163: * Sets the graduation's minimum, maximum and units. This method will fire property change
164: * events for {@code "minimum"}, {@code "maximum"} and {@code "unit"} property names.
165: */
166: public void setRange(final double min, final double max,
167: final Unit unit) {
168: final Double oldMin;
169: final Double oldMax;
170: synchronized (this ) {
171: oldMin = new Double(minimum);
172: oldMax = new Double(maximum);
173: this .minimum = Math.min(min, max);
174: this .maximum = Math.max(min, max);
175: setUnit(unit);
176: }
177: listenerList.firePropertyChange("minimum", oldMin, new Double(
178: min));
179: listenerList.firePropertyChange("maximum", oldMax, new Double(
180: max));
181: }
182:
183: /**
184: * Changes the graduation's units. This method will automatically convert minimum and
185: * maximum values from the old units to the new one.
186: *
187: * @param newUnit The new units, or {@code null} if unknow.
188: * If null, minimum and maximum values are not converted.
189: * @throws ConversionException if units are not convertible.
190: */
191: public synchronized void setUnit(final Unit newUnit)
192: throws ConversionException {
193: double min = minimum;
194: double max = maximum;
195: final Unit unit = getUnit();
196: if (unit != null && newUnit != null) {
197: final Converter converter = unit.getConverterTo(newUnit);
198: min = converter.convert(min);
199: max = converter.convert(max);
200: }
201: setRange(min, max, newUnit);
202: }
203:
204: /**
205: * Returns the format to use for formatting labels. The format really used by
206: * {@link TickIterator#currentLabel} may not be the same. For example, some
207: * iterators may adjust automatically the number of fraction digits.
208: */
209: public Format getFormat() {
210: return NumberFormat.getNumberInstance(getLocale());
211: }
212:
213: /**
214: * Returns an iterator object that iterates along the graduation ticks and provides access to
215: * the graduation values. If an optional {@link RenderingHints} is specified, tick locations are
216: * adjusted according values for {@link #VISUAL_AXIS_LENGTH} and {@link #VISUAL_TICK_SPACING}
217: * keys.
218: *
219: * @param hints Rendering hints, or {@code null} for the default hints.
220: * @param reuse An iterator to reuse if possible, or {@code null} to create a new one. A
221: * non-null object may help to reduce the number of object garbage-collected when
222: * rendering the axis.
223: * @return A iterator to use for iterating through the graduation. This
224: * iterator may or may not be the {@code reuse} object.
225: */
226: public synchronized TickIterator getTickIterator(
227: final RenderingHints hints, final TickIterator reuse) {
228: final float visualAxisLength = getVisualAxisLength(hints);
229: final float visualTickSpacing = getVisualTickSpacing(hints);
230: double minimum = this .minimum;
231: double maximum = this .maximum;
232: if (!(minimum < maximum)) {
233: minimum = (minimum + maximum) * 0.5 - 0.5;
234: maximum = minimum + 1;
235: }
236: final NumberIterator it = getTickIterator(reuse, getLocale());
237: it.init(minimum, maximum, visualAxisLength, visualTickSpacing);
238: return it;
239: }
240:
241: /**
242: * Constructs or reuses an iterator. This method is overridden by
243: * {@link LogarithmicNumberGraduation}.
244: */
245: NumberIterator getTickIterator(final TickIterator reuse,
246: final Locale locale) {
247: if (reuse != null
248: && reuse.getClass().equals(NumberIterator.class)) {
249: final NumberIterator it = (NumberIterator) reuse;
250: it.setLocale(locale);
251: return it;
252: } else {
253: return new NumberIterator(locale);
254: }
255: }
256:
257: /**
258: * Compares this graduation with the specified object for equality.
259: * This method do not compare registered listeners.
260: */
261: public boolean equals(final Object object) {
262: if (object == this ) {
263: return true;
264: }
265: if (super .equals(object)) {
266: final NumberGraduation that = (NumberGraduation) object;
267: return Double.doubleToLongBits(this .minimum) == Double
268: .doubleToLongBits(that.minimum)
269: && Double.doubleToLongBits(this .maximum) == Double
270: .doubleToLongBits(that.maximum);
271: }
272: return false;
273: }
274:
275: /**
276: * Returns a hash value for this graduation.
277: */
278: public int hashCode() {
279: final long code = Double.doubleToLongBits(minimum) + 37
280: * Double.doubleToLongBits(maximum);
281: return (int) code ^ (int) (code >>> 32) ^ super.hashCode();
282: }
283: }
|