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.4 2006/07/03 15:55:15 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     *
058     */
059    
060    package org.jfree.chart.plot;
061    
062    import java.awt.BasicStroke;
063    import java.awt.Color;
064    import java.awt.Font;
065    import java.awt.Paint;
066    import java.awt.Stroke;
067    import java.io.IOException;
068    import java.io.ObjectInputStream;
069    import java.io.ObjectOutputStream;
070    import java.io.Serializable;
071    
072    import org.jfree.io.SerialUtilities;
073    import org.jfree.ui.LengthAdjustmentType;
074    import org.jfree.ui.RectangleAnchor;
075    import org.jfree.ui.RectangleInsets;
076    import org.jfree.ui.TextAnchor;
077    import org.jfree.util.ObjectUtilities;
078    import org.jfree.util.PaintUtilities;
079    
080    /**
081     * The base class for markers that can be added to plots to highlight a value 
082     * or range of values.
083     * <br><br>
084     * Note that there is no listener mechanism for markers, so changing the
085     * attributes for a marker will not lead to any automatic chart repainting.
086     */
087    public abstract class Marker implements Cloneable, Serializable {
088    
089        /** For serialization. */
090        private static final long serialVersionUID = -734389651405327166L;
091    
092        /** The paint. */
093        private transient Paint paint;
094    
095        /** The stroke. */
096        private transient Stroke stroke;
097        
098        /** The outline paint. */
099        private transient Paint outlinePaint;
100    
101        /** The outline stroke. */
102        private transient Stroke outlineStroke;
103    
104        /** The alpha transparency. */
105        private float alpha;
106    
107        /** The label. */
108        private String label = null;
109    
110        /** The label font. */
111        private Font labelFont;
112    
113        /** The label paint. */
114        private transient Paint labelPaint;
115    
116        /** The label position. */
117        private RectangleAnchor labelAnchor;
118        
119        /** The text anchor for the label. */
120        private TextAnchor labelTextAnchor;
121    
122        /** The label offset from the marker rectangle. */
123        private RectangleInsets labelOffset;
124        
125        /** 
126         * The offset type for the domain or range axis (never <code>null</code>). 
127         */
128        private LengthAdjustmentType labelOffsetType;
129        
130        /**
131         * Creates a new marker with default attributes.
132         */
133        protected Marker() {
134            this(Color.gray);
135        }
136    
137        /**
138         * Constructs a new marker.
139         *
140         * @param paint  the paint (<code>null</code> not permitted).
141         */
142        protected Marker(Paint paint) {
143            this(paint, new BasicStroke(0.5f), Color.gray, new BasicStroke(0.5f), 
144                    0.80f);
145        }
146    
147        /**
148         * Constructs a new marker.
149         *
150         * @param paint  the paint (<code>null</code> not permitted).
151         * @param stroke  the stroke (<code>null</code> not permitted).
152         * @param outlinePaint  the outline paint (<code>null</code> permitted).
153         * @param outlineStroke  the outline stroke (<code>null</code> permitted).
154         * @param alpha  the alpha transparency (must be in the range 0.0f to 
155         *     1.0f).
156         *     
157         * @throws IllegalArgumentException if <code>paint</code> or 
158         *     <code>stroke</code> is <code>null</code>, or <code>alpha</code> is 
159         *     not in the specified range.
160         */
161        protected Marker(Paint paint, Stroke stroke, 
162                         Paint outlinePaint, Stroke outlineStroke, 
163                         float alpha) {
164    
165            if (paint == null) {
166                throw new IllegalArgumentException("Null 'paint' argument.");
167            }
168            if (stroke == null) {
169                throw new IllegalArgumentException("Null 'stroke' argument.");
170            }
171            if (alpha < 0.0f || alpha > 1.0f)
172                throw new IllegalArgumentException(
173                        "The 'alpha' value must be in the range 0.0f to 1.0f");
174            
175            this.paint = paint;
176            this.stroke = stroke;
177            this.outlinePaint = outlinePaint;
178            this.outlineStroke = outlineStroke;
179            this.alpha = alpha;
180            
181            this.labelFont = new Font("SansSerif", Font.PLAIN, 9);
182            this.labelPaint = Color.black;
183            this.labelAnchor = RectangleAnchor.TOP_LEFT;
184            this.labelOffset = new RectangleInsets(3.0, 3.0, 3.0, 3.0);
185            this.labelOffsetType = LengthAdjustmentType.CONTRACT;
186            this.labelTextAnchor = TextAnchor.CENTER;
187            
188        }
189    
190        /**
191         * Returns the paint.
192         *
193         * @return The paint (never <code>null</code>).
194         * 
195         * @see #setPaint(Paint)
196         */
197        public Paint getPaint() {
198            return this.paint;
199        }
200        
201        /**
202         * Sets the paint.
203         * 
204         * @param paint  the paint (<code>null</code> not permitted).
205         * 
206         * @see #getPaint()
207         */
208        public void setPaint(Paint paint) {
209            if (paint == null) {
210                throw new IllegalArgumentException("Null 'paint' argument.");
211            }
212            this.paint = paint;
213        }
214    
215        /**
216         * Returns the stroke.
217         *
218         * @return The stroke (never <code>null</code>).
219         * 
220         * @see #setStroke(Stroke)
221         */
222        public Stroke getStroke() {
223            return this.stroke;
224        }
225        
226        /**
227         * Sets the stroke.
228         * 
229         * @param stroke  the stroke (<code>null</code> not permitted).
230         * 
231         * @see #getStroke()
232         */
233        public void setStroke(Stroke stroke) {
234            if (stroke == null) {
235                throw new IllegalArgumentException("Null 'stroke' argument.");
236            }
237            this.stroke = stroke;
238        }
239    
240        /**
241         * Returns the outline paint.
242         *
243         * @return The outline paint (possibly <code>null</code>).
244         * 
245         * @see #setOutlinePaint(Paint)
246         */
247        public Paint getOutlinePaint() {
248            return this.outlinePaint;
249        }
250        
251        /**
252         * Sets the outline paint.
253         * 
254         * @param paint  the paint (<code>null</code> permitted).
255         * 
256         * @see #getOutlinePaint()
257         */
258        public void setOutlinePaint(Paint paint) {
259            this.outlinePaint = paint;
260        }
261    
262        /**
263         * Returns the outline stroke.
264         *
265         * @return The outline stroke (possibly <code>null</code>).
266         * 
267         * @see #setOutlineStroke(Stroke)
268         */
269        public Stroke getOutlineStroke() {
270            return this.outlineStroke;
271        }
272        
273        /**
274         * Sets the outline stroke.
275         * 
276         * @param stroke  the stroke (<code>null</code> permitted).
277         * 
278         * @see #getOutlineStroke()
279         */
280        public void setOutlineStroke(Stroke stroke) {
281            this.outlineStroke = stroke;
282        }
283    
284        /**
285         * Returns the alpha transparency.
286         *
287         * @return The alpha transparency.
288         * 
289         * @see #setAlpha(float)
290         */
291        public float getAlpha() {
292            return this.alpha;
293        }
294        
295        /**
296         * Sets the alpha transparency that should be used when drawing the 
297         * marker.  This is a value in the range 0.0f (completely transparent) to
298         * 1.0f (completely opaque).
299         * 
300         * @param alpha  the alpha transparency (must be in the range 0.0f to 
301         *     1.0f).
302         *     
303         * @throws IllegalArgumentException if <code>alpha</code> is not in the
304         *     specified range.
305         *     
306         * @see #getAlpha()
307         */
308        public void setAlpha(float alpha) {
309            if (alpha < 0.0f || alpha > 1.0f)
310                throw new IllegalArgumentException(
311                        "The 'alpha' value must be in the range 0.0f to 1.0f");
312            this.alpha = alpha;
313        }
314    
315        /**
316         * Returns the label (if <code>null</code> no label is displayed).
317         *
318         * @return The label (possibly <code>null</code>).
319         * 
320         * @see #setLabel(String)
321         */
322        public String getLabel() {
323            return this.label;
324        }
325    
326        /**
327         * Sets the label (if <code>null</code> no label is displayed).
328         *
329         * @param label  the label (<code>null</code> permitted).
330         * 
331         * @see #getLabel()
332         */
333        public void setLabel(String label) {
334            this.label = label;
335        }
336    
337        /**
338         * Returns the label font.
339         *
340         * @return The label font (never <code>null</code>).
341         * 
342         * @see #setLabelFont(Font)
343         */
344        public Font getLabelFont() {
345            return this.labelFont;
346        }
347    
348        /**
349         * Sets the label font.
350         *
351         * @param font  the font (<code>null</code> not permitted).
352         * 
353         * @see #getLabelFont()
354         */
355        public void setLabelFont(Font font) {
356            if (font == null) {
357                throw new IllegalArgumentException("Null 'font' argument.");
358            }
359            this.labelFont = font;
360        }
361    
362        /**
363         * Returns the label paint.
364         *
365         * @return The label paint (never </code>null</code>).
366         * 
367         * @see #setLabelPaint(Paint)
368         */
369        public Paint getLabelPaint() {
370            return this.labelPaint;
371        }
372    
373        /**
374         * Sets the label paint.
375         *
376         * @param paint  the paint (<code>null</code> not permitted).
377         * 
378         * @see #getLabelPaint()
379         */
380        public void setLabelPaint(Paint paint) {
381            if (paint == null) {
382                throw new IllegalArgumentException("Null 'paint' argument.");
383            }
384            this.labelPaint = paint;
385        }
386    
387        /**
388         * Returns the label anchor.  This defines the position of the label 
389         * anchor, relative to the bounds of the marker.
390         *
391         * @return The label anchor (never <code>null</code>).
392         * 
393         * @see #setLabelAnchor(RectangleAnchor)
394         */
395        public RectangleAnchor getLabelAnchor() {
396            return this.labelAnchor;
397        }
398    
399        /**
400         * Sets the label anchor.  This defines the position of the label 
401         * anchor, relative to the bounds of the marker.
402         *
403         * @param anchor  the anchor (<code>null</code> not permitted).
404         * 
405         * @see #getLabelAnchor()
406         */
407        public void setLabelAnchor(RectangleAnchor anchor) {
408            if (anchor == null) {
409                throw new IllegalArgumentException("Null 'anchor' argument.");
410            }
411            this.labelAnchor = anchor;
412        }
413    
414        /**
415         * Returns the label offset.
416         * 
417         * @return The label offset (never <code>null</code>).
418         * 
419         * @see #setLabelOffset(RectangleInsets)
420         */
421        public RectangleInsets getLabelOffset() {
422            return this.labelOffset;
423        }
424        
425        /**
426         * Sets the label offset.
427         * 
428         * @param offset  the label offset (<code>null</code> not permitted).
429         * 
430         * @see #getLabelOffset()
431         */
432        public void setLabelOffset(RectangleInsets offset) {
433            if (offset == null) {
434                throw new IllegalArgumentException("Null 'offset' argument.");
435            }
436            this.labelOffset = offset;
437        }
438        
439        /**
440         * Returns the label offset type.
441         * 
442         * @return The type (never <code>null</code>).
443         * 
444         * @see #setLabelOffsetType(LengthAdjustmentType)
445         */
446        public LengthAdjustmentType getLabelOffsetType() {
447            return this.labelOffsetType;   
448        }
449        
450        /**
451         * Sets the label offset type.
452         * 
453         * @param adj  the type (<code>null</code> not permitted).
454         * 
455         * @see #getLabelOffsetType()
456         */
457        public void setLabelOffsetType(LengthAdjustmentType adj) {
458            if (adj == null) {
459                throw new IllegalArgumentException("Null 'adj' argument.");
460            }
461            this.labelOffsetType = adj;    
462        }
463            
464        /**
465         * Returns the label text anchor.
466         * 
467         * @return The label text anchor (never <code>null</code>).
468         * 
469         * @see #setLabelTextAnchor(TextAnchor)
470         */
471        public TextAnchor getLabelTextAnchor() {
472            return this.labelTextAnchor;
473        }
474        
475        /**
476         * Sets the label text anchor.
477         * 
478         * @param anchor  the label text anchor (<code>null</code> not permitted).
479         * 
480         * @see #getLabelTextAnchor()
481         */
482        public void setLabelTextAnchor(TextAnchor anchor) {
483            if (anchor == null) { 
484                throw new IllegalArgumentException("Null 'anchor' argument.");
485            }
486            this.labelTextAnchor = anchor;
487        }
488        
489        /**
490         * Tests the marker for equality with an arbitrary object.
491         * 
492         * @param obj  the object (<code>null</code> permitted).
493         * 
494         * @return A boolean.
495         */
496        public boolean equals(Object obj) {
497            if (obj == this) {
498                return true;
499            }
500            if (!(obj instanceof Marker)) {
501                return false;
502            }
503            Marker that = (Marker) obj;
504            if (!PaintUtilities.equal(this.paint, that.paint)) {
505                return false;   
506            }
507            if (!ObjectUtilities.equal(this.stroke, that.stroke)) {
508                return false;
509            }
510            if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
511                return false;   
512            }
513            if (!ObjectUtilities.equal(this.outlineStroke, that.outlineStroke)) {
514                return false;
515            }
516            if (this.alpha != that.alpha) {
517                return false;
518            }
519            if (!ObjectUtilities.equal(this.label, that.label)) {
520                return false;
521            }
522            if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) {
523                return false;
524            }
525            if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) {
526                return false;
527            }
528            if (this.labelAnchor != that.labelAnchor) {
529                return false;
530            }
531            if (this.labelTextAnchor != that.labelTextAnchor) {
532                return false;   
533            }
534            if (!ObjectUtilities.equal(this.labelOffset, that.labelOffset)) {
535                return false;
536            }
537            if (!this.labelOffsetType.equals(that.labelOffsetType)) {
538                return false;
539            }
540            return true;
541        }
542        
543        /**
544         * Creates a clone of the marker.
545         * 
546         * @return A clone.
547         * 
548         * @throws CloneNotSupportedException never.
549         */
550        public Object clone() throws CloneNotSupportedException {
551            return super.clone();
552        }
553        
554        /**
555         * Provides serialization support.
556         *
557         * @param stream  the output stream.
558         *
559         * @throws IOException  if there is an I/O error.
560         */
561        private void writeObject(ObjectOutputStream stream) throws IOException {
562            stream.defaultWriteObject();
563            SerialUtilities.writePaint(this.paint, stream);
564            SerialUtilities.writeStroke(this.stroke, stream);
565            SerialUtilities.writePaint(this.outlinePaint, stream);
566            SerialUtilities.writeStroke(this.outlineStroke, stream);
567            SerialUtilities.writePaint(this.labelPaint, stream);
568        }
569    
570        /**
571         * Provides serialization support.
572         *
573         * @param stream  the input stream.
574         *
575         * @throws IOException  if there is an I/O error.
576         * @throws ClassNotFoundException  if there is a classpath problem.
577         */
578        private void readObject(ObjectInputStream stream) 
579            throws IOException, ClassNotFoundException {
580            stream.defaultReadObject();
581            this.paint = SerialUtilities.readPaint(stream);
582            this.stroke = SerialUtilities.readStroke(stream);
583            this.outlinePaint = SerialUtilities.readPaint(stream);
584            this.outlineStroke = SerialUtilities.readStroke(stream);
585            this.labelPaint = SerialUtilities.readPaint(stream);
586        }
587    
588    }