001: /* ===========================================================
002: * JFreeChart : a free chart library for the Java(tm) platform
003: * ===========================================================
004: *
005: * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jfreechart/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * -----------
028: * Marker.java
029: * -----------
030: * (C) Copyright 2002-2006, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): Nicolas Brodu;
034: *
035: * $Id: Marker.java,v 1.10.2.5 2006/09/05 14:34:23 mungady Exp $
036: *
037: * Changes (since 2-Jul-2002)
038: * --------------------------
039: * 02-Jul-2002 : Added extra constructor, standard header and Javadoc
040: * comments (DG);
041: * 20-Aug-2002 : Added the outline stroke attribute (DG);
042: * 02-Oct-2002 : Fixed errors reported by Checkstyle (DG);
043: * 16-Oct-2002 : Added new constructor (DG);
044: * 26-Mar-2003 : Implemented Serializable (DG);
045: * 21-May-2003 : Added labels (DG);
046: * 11-Sep-2003 : Implemented Cloneable (NB);
047: * 05-Nov-2003 : Added checks to ensure some attributes are never null (DG);
048: * 11-Feb-2003 : Moved to org.jfree.chart.plot package, plus significant API
049: * changes to support IntervalMarker in plots (DG);
050: * 14-Jun-2004 : Updated equals() method (DG);
051: * 21-Jan-2005 : Added settings to control direction of horizontal and
052: * vertical label offsets (DG);
053: * 01-Jun-2005 : Modified to use only one label offset type - this will be
054: * applied to the domain or range axis as appropriate (DG);
055: * 06-Jun-2005 : Fix equals() method to handle GradientPaint (DG);
056: * 19-Aug-2005 : Changed constructor from public --> protected (DG);
057: * ------------- JFREECHART 1.0.0 ---------------------------------------------
058: * 05-Sep-2006 : Added MarkerChangeListener support (DG);
059: *
060: */
061:
062: package org.jfree.chart.plot;
063:
064: import java.awt.BasicStroke;
065: import java.awt.Color;
066: import java.awt.Font;
067: import java.awt.Paint;
068: import java.awt.Stroke;
069: import java.io.IOException;
070: import java.io.ObjectInputStream;
071: import java.io.ObjectOutputStream;
072: import java.io.Serializable;
073: import java.util.EventListener;
074:
075: import javax.swing.event.EventListenerList;
076:
077: import org.jfree.chart.event.MarkerChangeEvent;
078: import org.jfree.chart.event.MarkerChangeListener;
079: import org.jfree.io.SerialUtilities;
080: import org.jfree.ui.LengthAdjustmentType;
081: import org.jfree.ui.RectangleAnchor;
082: import org.jfree.ui.RectangleInsets;
083: import org.jfree.ui.TextAnchor;
084: import org.jfree.util.ObjectUtilities;
085: import org.jfree.util.PaintUtilities;
086:
087: /**
088: * The base class for markers that can be added to plots to highlight a value
089: * or range of values.
090: * <br><br>
091: * An event notification mechanism was added to this class in JFreeChart
092: * version 1.0.3.
093: */
094: public abstract class Marker implements Cloneable, Serializable {
095:
096: /** For serialization. */
097: private static final long serialVersionUID = -734389651405327166L;
098:
099: /** The paint. */
100: private transient Paint paint;
101:
102: /** The stroke. */
103: private transient Stroke stroke;
104:
105: /** The outline paint. */
106: private transient Paint outlinePaint;
107:
108: /** The outline stroke. */
109: private transient Stroke outlineStroke;
110:
111: /** The alpha transparency. */
112: private float alpha;
113:
114: /** The label. */
115: private String label = null;
116:
117: /** The label font. */
118: private Font labelFont;
119:
120: /** The label paint. */
121: private transient Paint labelPaint;
122:
123: /** The label position. */
124: private RectangleAnchor labelAnchor;
125:
126: /** The text anchor for the label. */
127: private TextAnchor labelTextAnchor;
128:
129: /** The label offset from the marker rectangle. */
130: private RectangleInsets labelOffset;
131:
132: /**
133: * The offset type for the domain or range axis (never <code>null</code>).
134: */
135: private LengthAdjustmentType labelOffsetType;
136:
137: /** Storage for registered change listeners. */
138: private transient EventListenerList listenerList;
139:
140: /**
141: * Creates a new marker with default attributes.
142: */
143: protected Marker() {
144: this (Color.gray);
145: }
146:
147: /**
148: * Constructs a new marker.
149: *
150: * @param paint the paint (<code>null</code> not permitted).
151: */
152: protected Marker(Paint paint) {
153: this (paint, new BasicStroke(0.5f), Color.gray, new BasicStroke(
154: 0.5f), 0.80f);
155: }
156:
157: /**
158: * Constructs a new marker.
159: *
160: * @param paint the paint (<code>null</code> not permitted).
161: * @param stroke the stroke (<code>null</code> not permitted).
162: * @param outlinePaint the outline paint (<code>null</code> permitted).
163: * @param outlineStroke the outline stroke (<code>null</code> permitted).
164: * @param alpha the alpha transparency (must be in the range 0.0f to
165: * 1.0f).
166: *
167: * @throws IllegalArgumentException if <code>paint</code> or
168: * <code>stroke</code> is <code>null</code>, or <code>alpha</code> is
169: * not in the specified range.
170: */
171: protected Marker(Paint paint, Stroke stroke, Paint outlinePaint,
172: Stroke outlineStroke, float alpha) {
173:
174: if (paint == null) {
175: throw new IllegalArgumentException("Null 'paint' argument.");
176: }
177: if (stroke == null) {
178: throw new IllegalArgumentException(
179: "Null 'stroke' argument.");
180: }
181: if (alpha < 0.0f || alpha > 1.0f)
182: throw new IllegalArgumentException(
183: "The 'alpha' value must be in the range 0.0f to 1.0f");
184:
185: this .paint = paint;
186: this .stroke = stroke;
187: this .outlinePaint = outlinePaint;
188: this .outlineStroke = outlineStroke;
189: this .alpha = alpha;
190:
191: this .labelFont = new Font("SansSerif", Font.PLAIN, 9);
192: this .labelPaint = Color.black;
193: this .labelAnchor = RectangleAnchor.TOP_LEFT;
194: this .labelOffset = new RectangleInsets(3.0, 3.0, 3.0, 3.0);
195: this .labelOffsetType = LengthAdjustmentType.CONTRACT;
196: this .labelTextAnchor = TextAnchor.CENTER;
197:
198: this .listenerList = new EventListenerList();
199: }
200:
201: /**
202: * Returns the paint.
203: *
204: * @return The paint (never <code>null</code>).
205: *
206: * @see #setPaint(Paint)
207: */
208: public Paint getPaint() {
209: return this .paint;
210: }
211:
212: /**
213: * Sets the paint and sends a {@link MarkerChangeEvent} to all registered
214: * listeners.
215: *
216: * @param paint the paint (<code>null</code> not permitted).
217: *
218: * @see #getPaint()
219: */
220: public void setPaint(Paint paint) {
221: if (paint == null) {
222: throw new IllegalArgumentException("Null 'paint' argument.");
223: }
224: this .paint = paint;
225: notifyListeners(new MarkerChangeEvent(this ));
226: }
227:
228: /**
229: * Returns the stroke.
230: *
231: * @return The stroke (never <code>null</code>).
232: *
233: * @see #setStroke(Stroke)
234: */
235: public Stroke getStroke() {
236: return this .stroke;
237: }
238:
239: /**
240: * Sets the stroke and sends a {@link MarkerChangeEvent} to all registered
241: * listeners.
242: *
243: * @param stroke the stroke (<code>null</code> not permitted).
244: *
245: * @see #getStroke()
246: */
247: public void setStroke(Stroke stroke) {
248: if (stroke == null) {
249: throw new IllegalArgumentException(
250: "Null 'stroke' argument.");
251: }
252: this .stroke = stroke;
253: notifyListeners(new MarkerChangeEvent(this ));
254: }
255:
256: /**
257: * Returns the outline paint.
258: *
259: * @return The outline paint (possibly <code>null</code>).
260: *
261: * @see #setOutlinePaint(Paint)
262: */
263: public Paint getOutlinePaint() {
264: return this .outlinePaint;
265: }
266:
267: /**
268: * Sets the outline paint and sends a {@link MarkerChangeEvent} to all
269: * registered listeners.
270: *
271: * @param paint the paint (<code>null</code> permitted).
272: *
273: * @see #getOutlinePaint()
274: */
275: public void setOutlinePaint(Paint paint) {
276: this .outlinePaint = paint;
277: notifyListeners(new MarkerChangeEvent(this ));
278: }
279:
280: /**
281: * Returns the outline stroke.
282: *
283: * @return The outline stroke (possibly <code>null</code>).
284: *
285: * @see #setOutlineStroke(Stroke)
286: */
287: public Stroke getOutlineStroke() {
288: return this .outlineStroke;
289: }
290:
291: /**
292: * Sets the outline stroke and sends a {@link MarkerChangeEvent} to all
293: * registered listeners.
294: *
295: * @param stroke the stroke (<code>null</code> permitted).
296: *
297: * @see #getOutlineStroke()
298: */
299: public void setOutlineStroke(Stroke stroke) {
300: this .outlineStroke = stroke;
301: notifyListeners(new MarkerChangeEvent(this ));
302: }
303:
304: /**
305: * Returns the alpha transparency.
306: *
307: * @return The alpha transparency.
308: *
309: * @see #setAlpha(float)
310: */
311: public float getAlpha() {
312: return this .alpha;
313: }
314:
315: /**
316: * Sets the alpha transparency that should be used when drawing the
317: * marker, and sends a {@link MarkerChangeEvent} to all registered
318: * listeners. The alpha transparency is a value in the range 0.0f
319: * (completely transparent) to 1.0f (completely opaque).
320: *
321: * @param alpha the alpha transparency (must be in the range 0.0f to
322: * 1.0f).
323: *
324: * @throws IllegalArgumentException if <code>alpha</code> is not in the
325: * specified range.
326: *
327: * @see #getAlpha()
328: */
329: public void setAlpha(float alpha) {
330: if (alpha < 0.0f || alpha > 1.0f)
331: throw new IllegalArgumentException(
332: "The 'alpha' value must be in the range 0.0f to 1.0f");
333: this .alpha = alpha;
334: notifyListeners(new MarkerChangeEvent(this ));
335: }
336:
337: /**
338: * Returns the label (if <code>null</code> no label is displayed).
339: *
340: * @return The label (possibly <code>null</code>).
341: *
342: * @see #setLabel(String)
343: */
344: public String getLabel() {
345: return this .label;
346: }
347:
348: /**
349: * Sets the label (if <code>null</code> no label is displayed) and sends a
350: * {@link MarkerChangeEvent} to all registered listeners.
351: *
352: * @param label the label (<code>null</code> permitted).
353: *
354: * @see #getLabel()
355: */
356: public void setLabel(String label) {
357: this .label = label;
358: notifyListeners(new MarkerChangeEvent(this ));
359: }
360:
361: /**
362: * Returns the label font.
363: *
364: * @return The label font (never <code>null</code>).
365: *
366: * @see #setLabelFont(Font)
367: */
368: public Font getLabelFont() {
369: return this .labelFont;
370: }
371:
372: /**
373: * Sets the label font and sends a {@link MarkerChangeEvent} to all
374: * registered listeners.
375: *
376: * @param font the font (<code>null</code> not permitted).
377: *
378: * @see #getLabelFont()
379: */
380: public void setLabelFont(Font font) {
381: if (font == null) {
382: throw new IllegalArgumentException("Null 'font' argument.");
383: }
384: this .labelFont = font;
385: notifyListeners(new MarkerChangeEvent(this ));
386: }
387:
388: /**
389: * Returns the label paint.
390: *
391: * @return The label paint (never </code>null</code>).
392: *
393: * @see #setLabelPaint(Paint)
394: */
395: public Paint getLabelPaint() {
396: return this .labelPaint;
397: }
398:
399: /**
400: * Sets the label paint and sends a {@link MarkerChangeEvent} to all
401: * registered listeners.
402: *
403: * @param paint the paint (<code>null</code> not permitted).
404: *
405: * @see #getLabelPaint()
406: */
407: public void setLabelPaint(Paint paint) {
408: if (paint == null) {
409: throw new IllegalArgumentException("Null 'paint' argument.");
410: }
411: this .labelPaint = paint;
412: notifyListeners(new MarkerChangeEvent(this ));
413: }
414:
415: /**
416: * Returns the label anchor. This defines the position of the label
417: * anchor, relative to the bounds of the marker.
418: *
419: * @return The label anchor (never <code>null</code>).
420: *
421: * @see #setLabelAnchor(RectangleAnchor)
422: */
423: public RectangleAnchor getLabelAnchor() {
424: return this .labelAnchor;
425: }
426:
427: /**
428: * Sets the label anchor and sends a {@link MarkerChangeEvent} to all
429: * registered listeners. The anchor defines the position of the label
430: * anchor, relative to the bounds of the marker.
431: *
432: * @param anchor the anchor (<code>null</code> not permitted).
433: *
434: * @see #getLabelAnchor()
435: */
436: public void setLabelAnchor(RectangleAnchor anchor) {
437: if (anchor == null) {
438: throw new IllegalArgumentException(
439: "Null 'anchor' argument.");
440: }
441: this .labelAnchor = anchor;
442: notifyListeners(new MarkerChangeEvent(this ));
443: }
444:
445: /**
446: * Returns the label offset.
447: *
448: * @return The label offset (never <code>null</code>).
449: *
450: * @see #setLabelOffset(RectangleInsets)
451: */
452: public RectangleInsets getLabelOffset() {
453: return this .labelOffset;
454: }
455:
456: /**
457: * Sets the label offset and sends a {@link MarkerChangeEvent} to all
458: * registered listeners.
459: *
460: * @param offset the label offset (<code>null</code> not permitted).
461: *
462: * @see #getLabelOffset()
463: */
464: public void setLabelOffset(RectangleInsets offset) {
465: if (offset == null) {
466: throw new IllegalArgumentException(
467: "Null 'offset' argument.");
468: }
469: this .labelOffset = offset;
470: notifyListeners(new MarkerChangeEvent(this ));
471: }
472:
473: /**
474: * Returns the label offset type.
475: *
476: * @return The type (never <code>null</code>).
477: *
478: * @see #setLabelOffsetType(LengthAdjustmentType)
479: */
480: public LengthAdjustmentType getLabelOffsetType() {
481: return this .labelOffsetType;
482: }
483:
484: /**
485: * Sets the label offset type and sends a {@link MarkerChangeEvent} to all
486: * registered listeners.
487: *
488: * @param adj the type (<code>null</code> not permitted).
489: *
490: * @see #getLabelOffsetType()
491: */
492: public void setLabelOffsetType(LengthAdjustmentType adj) {
493: if (adj == null) {
494: throw new IllegalArgumentException("Null 'adj' argument.");
495: }
496: this .labelOffsetType = adj;
497: notifyListeners(new MarkerChangeEvent(this ));
498: }
499:
500: /**
501: * Returns the label text anchor.
502: *
503: * @return The label text anchor (never <code>null</code>).
504: *
505: * @see #setLabelTextAnchor(TextAnchor)
506: */
507: public TextAnchor getLabelTextAnchor() {
508: return this .labelTextAnchor;
509: }
510:
511: /**
512: * Sets the label text anchor and sends a {@link MarkerChangeEvent} to
513: * all registered listeners.
514: *
515: * @param anchor the label text anchor (<code>null</code> not permitted).
516: *
517: * @see #getLabelTextAnchor()
518: */
519: public void setLabelTextAnchor(TextAnchor anchor) {
520: if (anchor == null) {
521: throw new IllegalArgumentException(
522: "Null 'anchor' argument.");
523: }
524: this .labelTextAnchor = anchor;
525: notifyListeners(new MarkerChangeEvent(this ));
526: }
527:
528: /**
529: * Registers an object for notification of changes to the marker.
530: *
531: * @param listener the object to be registered.
532: *
533: * @since 1.0.3
534: */
535: public void addChangeListener(MarkerChangeListener listener) {
536: this .listenerList.add(MarkerChangeListener.class, listener);
537: }
538:
539: /**
540: * Unregisters an object for notification of changes to the marker.
541: *
542: * @param listener the object to be unregistered.
543: *
544: * @since 1.0.3
545: */
546: public void removeChangeListener(MarkerChangeListener listener) {
547: this .listenerList.remove(MarkerChangeListener.class, listener);
548: }
549:
550: /**
551: * Notifies all registered listeners that the marker has been modified.
552: *
553: * @param event information about the change event.
554: *
555: * @since 1.0.3
556: */
557: public void notifyListeners(MarkerChangeEvent event) {
558:
559: Object[] listeners = this .listenerList.getListenerList();
560: for (int i = listeners.length - 2; i >= 0; i -= 2) {
561: if (listeners[i] == MarkerChangeListener.class) {
562: ((MarkerChangeListener) listeners[i + 1])
563: .markerChanged(event);
564: }
565: }
566:
567: }
568:
569: /**
570: * Returns an array containing all the listeners of the specified type.
571: *
572: * @param listenerType the listener type.
573: *
574: * @return The array of listeners.
575: *
576: * @since 1.0.3
577: */
578: public EventListener[] getListeners(Class listenerType) {
579: return this .listenerList.getListeners(listenerType);
580: }
581:
582: /**
583: * Tests the marker for equality with an arbitrary object.
584: *
585: * @param obj the object (<code>null</code> permitted).
586: *
587: * @return A boolean.
588: */
589: public boolean equals(Object obj) {
590: if (obj == this ) {
591: return true;
592: }
593: if (!(obj instanceof Marker)) {
594: return false;
595: }
596: Marker that = (Marker) obj;
597: if (!PaintUtilities.equal(this .paint, that.paint)) {
598: return false;
599: }
600: if (!ObjectUtilities.equal(this .stroke, that.stroke)) {
601: return false;
602: }
603: if (!PaintUtilities.equal(this .outlinePaint, that.outlinePaint)) {
604: return false;
605: }
606: if (!ObjectUtilities.equal(this .outlineStroke,
607: that.outlineStroke)) {
608: return false;
609: }
610: if (this .alpha != that.alpha) {
611: return false;
612: }
613: if (!ObjectUtilities.equal(this .label, that.label)) {
614: return false;
615: }
616: if (!ObjectUtilities.equal(this .labelFont, that.labelFont)) {
617: return false;
618: }
619: if (!PaintUtilities.equal(this .labelPaint, that.labelPaint)) {
620: return false;
621: }
622: if (this .labelAnchor != that.labelAnchor) {
623: return false;
624: }
625: if (this .labelTextAnchor != that.labelTextAnchor) {
626: return false;
627: }
628: if (!ObjectUtilities.equal(this .labelOffset, that.labelOffset)) {
629: return false;
630: }
631: if (!this .labelOffsetType.equals(that.labelOffsetType)) {
632: return false;
633: }
634: return true;
635: }
636:
637: /**
638: * Creates a clone of the marker.
639: *
640: * @return A clone.
641: *
642: * @throws CloneNotSupportedException never.
643: */
644: public Object clone() throws CloneNotSupportedException {
645: return super .clone();
646: }
647:
648: /**
649: * Provides serialization support.
650: *
651: * @param stream the output stream.
652: *
653: * @throws IOException if there is an I/O error.
654: */
655: private void writeObject(ObjectOutputStream stream)
656: throws IOException {
657: stream.defaultWriteObject();
658: SerialUtilities.writePaint(this .paint, stream);
659: SerialUtilities.writeStroke(this .stroke, stream);
660: SerialUtilities.writePaint(this .outlinePaint, stream);
661: SerialUtilities.writeStroke(this .outlineStroke, stream);
662: SerialUtilities.writePaint(this .labelPaint, stream);
663: }
664:
665: /**
666: * Provides serialization support.
667: *
668: * @param stream the input stream.
669: *
670: * @throws IOException if there is an I/O error.
671: * @throws ClassNotFoundException if there is a classpath problem.
672: */
673: private void readObject(ObjectInputStream stream)
674: throws IOException, ClassNotFoundException {
675: stream.defaultReadObject();
676: this.paint = SerialUtilities.readPaint(stream);
677: this.stroke = SerialUtilities.readStroke(stream);
678: this.outlinePaint = SerialUtilities.readPaint(stream);
679: this.outlineStroke = SerialUtilities.readStroke(stream);
680: this.labelPaint = SerialUtilities.readPaint(stream);
681: }
682:
683: }
|