001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2005, 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     * LegendItem.java
029     * ---------------
030     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   Andrzej Porebski;
034     *                   David Li;
035     *                   Wolfgang Irler;
036     *                   Luke Quinane;
037     *
038     * $Id: LegendItem.java,v 1.9.2.3 2005/11/28 12:06:34 mungady Exp $
039     *
040     * Changes (from 2-Oct-2002)
041     * -------------------------
042     * 02-Oct-2002 : Fixed errors reported by Checkstyle (DG);
043     * 17-Jan-2003 : Dropped outlineStroke attribute (DG);
044     * 08-Oct-2003 : Applied patch for displaying series line style, contributed by
045     *               Luke Quinane (DG);
046     * 21-Jan-2004 : Added the shapeFilled flag (DG);
047     * 04-Jun-2004 : Added equals() method, implemented Serializable (DG);
048     * 25-Nov-2004 : Changes required by new LegendTitle implementation (DG);
049     * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0 
050     *               release (DG);
051     * 20-Apr-2005 : Added tooltip and URL text (DG);
052     * 28-Nov-2005 : Separated constructors for AttributedString labels (DG);
053     * 
054     */
055    
056    package org.jfree.chart;
057    
058    import java.awt.BasicStroke;
059    import java.awt.Color;
060    import java.awt.Paint;
061    import java.awt.Shape;
062    import java.awt.Stroke;
063    import java.awt.geom.Line2D;
064    import java.io.IOException;
065    import java.io.ObjectInputStream;
066    import java.io.ObjectOutputStream;
067    import java.io.Serializable;
068    import java.text.AttributedString;
069    import java.text.CharacterIterator;
070    
071    import org.jfree.io.SerialUtilities;
072    import org.jfree.util.AttributedStringUtilities;
073    import org.jfree.util.ObjectUtilities;
074    import org.jfree.util.ShapeUtilities;
075    
076    /**
077     * A storage object for recording the properties of a legend item, without any 
078     * consideration for layout issues.  Instances of this class are immutable.
079     */
080    public class LegendItem implements Serializable {
081    
082        // TODO:  keeping this class immutable is becoming a lot of overhead, need 
083        // to look at the consequences of dropping immutability
084    
085        /** For serialization. */
086        private static final long serialVersionUID = -797214582948827144L;
087        
088        /** The label. */
089        private String label;
090        
091        /** The attributed label (if null, fall back to the regular label). */
092        private AttributedString attributedLabel;
093    
094        /** 
095         * The description (not currently used - could be displayed as a tool tip). 
096         */
097        private String description;
098        
099        /** The tool tip text. */
100        private String toolTipText;
101        
102        /** The url text. */
103        private String urlText;
104    
105        /** A flag that controls whether or not the shape is visible. */
106        private boolean shapeVisible;
107        
108        /** The shape. */
109        private transient Shape shape;
110        
111        /** A flag that controls whether or not the shape is filled. */
112        private boolean shapeFilled;
113    
114        /** The paint. */
115        private transient Paint fillPaint;
116        
117        /** A flag that controls whether or not the shape outline is visible. */
118        private boolean shapeOutlineVisible;
119        
120        /** The outline paint. */
121        private transient Paint outlinePaint;
122        
123        /** The outline stroke. */
124        private transient Stroke outlineStroke;
125    
126        /** A flag that controls whether or not the line is visible. */
127        private boolean lineVisible;
128        
129        /** The line. */
130        private transient Shape line;
131        
132        /** The stroke. */
133        private transient Stroke lineStroke;
134        
135        /** The line paint. */
136        private transient Paint linePaint;
137    
138        /**
139         * The shape must be non-null for a LegendItem - if no shape is required,
140         * use this.
141         */
142        private static final Shape UNUSED_SHAPE = new Line2D.Float();
143        
144        /**
145         * The stroke must be non-null for a LegendItem - if no stroke is required,
146         * use this.
147         */
148        private static final Stroke UNUSED_STROKE = new BasicStroke(0.0f);
149        
150        /**
151         * Creates a legend item with a filled shape.  The shape is not outlined,
152         * and no line is visible.
153         * 
154         * @param label  the label (<code>null</code> not permitted).
155         * @param description  the description (<code>null</code> permitted).
156         * @param toolTipText  the tool tip text (<code>null</code> permitted).
157         * @param urlText  the URL text (<code>null</code> permitted).
158         * @param shape  the shape (<code>null</code> not permitted).
159         * @param fillPaint  the paint used to fill the shape (<code>null</code>
160         *                   not permitted).
161         */
162        public LegendItem(String label, String description, 
163                          String toolTipText, String urlText, 
164                          Shape shape, Paint fillPaint) {
165            
166            this(label, description, toolTipText, urlText, 
167                    /* shape visible = */ true, shape, 
168                    /* shape filled = */ true, fillPaint, 
169                    /* shape outlined */ false, Color.black, UNUSED_STROKE,
170                    /* line visible */ false, UNUSED_SHAPE, UNUSED_STROKE,
171                    Color.black);
172    
173        }
174        
175        /**
176         * Creates a legend item with a filled and outlined shape.
177         * 
178         * @param label  the label (<code>null</code> not permitted).
179         * @param description  the description (<code>null</code> permitted).
180         * @param toolTipText  the tool tip text (<code>null</code> permitted).
181         * @param urlText  the URL text (<code>null</code> permitted).
182         * @param shape  the shape (<code>null</code> not permitted).
183         * @param fillPaint  the paint used to fill the shape (<code>null</code>
184         *                   not permitted).
185         * @param outlineStroke  the outline stroke (<code>null</code> not 
186         *                       permitted).
187         * @param outlinePaint  the outline paint (<code>null</code> not 
188         *                      permitted).
189         */
190        public LegendItem(String label, String description, 
191                          String toolTipText, String urlText, 
192                          Shape shape, Paint fillPaint, 
193                          Stroke outlineStroke, Paint outlinePaint) {
194            
195            this(label, description, toolTipText, urlText,
196                    /* shape visible = */ true, shape, 
197                    /* shape filled = */ true, fillPaint, 
198                    /* shape outlined = */ true, outlinePaint, outlineStroke,
199                    /* line visible */ false, UNUSED_SHAPE, UNUSED_STROKE,
200                    Color.black);
201    
202        }
203        
204        /**
205         * Creates a legend item using a line.
206         * 
207         * @param label  the label (<code>null</code> not permitted).
208         * @param description  the description (<code>null</code> permitted).
209         * @param toolTipText  the tool tip text (<code>null</code> permitted).
210         * @param urlText  the URL text (<code>null</code> permitted).
211         * @param line  the line (<code>null</code> not permitted).
212         * @param lineStroke  the line stroke (<code>null</code> not permitted).
213         * @param linePaint  the line paint (<code>null</code> not permitted).
214         */
215        public LegendItem(String label, String description, 
216                          String toolTipText, String urlText, 
217                          Shape line, Stroke lineStroke, Paint linePaint) {
218            
219            this(label, description, toolTipText, urlText,
220                    /* shape visible = */ false, UNUSED_SHAPE,
221                    /* shape filled = */ false, Color.black,
222                    /* shape outlined = */ false, Color.black, UNUSED_STROKE,
223                    /* line visible = */ true, line, lineStroke, linePaint);
224        }
225        
226        /**
227         * Creates a new legend item.
228         *
229         * @param label  the label (<code>null</code> not permitted).
230         * @param description  the description (not currently used, 
231         *        <code>null</code> permitted).
232         * @param toolTipText  the tool tip text (<code>null</code> permitted).
233         * @param urlText  the URL text (<code>null</code> permitted).
234         * @param shapeVisible  a flag that controls whether or not the shape is 
235         *                      displayed.
236         * @param shape  the shape (<code>null</code> permitted).
237         * @param shapeFilled  a flag that controls whether or not the shape is 
238         *                     filled.
239         * @param fillPaint  the fill paint (<code>null</code> not permitted).
240         * @param shapeOutlineVisible  a flag that controls whether or not the 
241         *                             shape is outlined.
242         * @param outlinePaint  the outline paint (<code>null</code> not permitted).
243         * @param outlineStroke  the outline stroke (<code>null</code> not 
244         *                       permitted).
245         * @param lineVisible  a flag that controls whether or not the line is 
246         *                     visible.
247         * @param line  the line.
248         * @param lineStroke  the stroke (<code>null</code> not permitted).
249         * @param linePaint  the line paint (<code>null</code> not permitted).
250         */
251        public LegendItem(String label, String description,
252                          String toolTipText, String urlText,
253                          boolean shapeVisible, Shape shape,
254                          boolean shapeFilled, Paint fillPaint, 
255                          boolean shapeOutlineVisible, Paint outlinePaint,
256                          Stroke outlineStroke,
257                          boolean lineVisible, Shape line,
258                          Stroke lineStroke, Paint linePaint) {
259            
260            if (label == null) {
261                throw new IllegalArgumentException("Null 'label' argument.");   
262            }
263            if (fillPaint == null) {
264                throw new IllegalArgumentException("Null 'fillPaint' argument.");   
265            }
266            if (lineStroke == null) {
267                throw new IllegalArgumentException("Null 'lineStroke' argument.");
268            }
269            if (outlinePaint == null) {
270                throw new IllegalArgumentException("Null 'outlinePaint' argument.");
271            }
272            if (outlineStroke == null) {
273                throw new IllegalArgumentException(
274                        "Null 'outlineStroke' argument.");   
275            }
276            this.label = label;
277            this.attributedLabel = null;
278            this.description = description;
279            this.shapeVisible = shapeVisible;
280            this.shape = shape;
281            this.shapeFilled = shapeFilled;
282            this.fillPaint = fillPaint;
283            this.shapeOutlineVisible = shapeOutlineVisible;
284            this.outlinePaint = outlinePaint;
285            this.outlineStroke = outlineStroke;
286            this.lineVisible = lineVisible;
287            this.line = line;
288            this.lineStroke = lineStroke;
289            this.linePaint = linePaint;
290            this.toolTipText = toolTipText;
291            this.urlText = urlText;
292        }
293        
294        /**
295         * Creates a legend item with a filled shape.  The shape is not outlined,
296         * and no line is visible.
297         * 
298         * @param label  the label (<code>null</code> not permitted).
299         * @param description  the description (<code>null</code> permitted).
300         * @param toolTipText  the tool tip text (<code>null</code> permitted).
301         * @param urlText  the URL text (<code>null</code> permitted).
302         * @param shape  the shape (<code>null</code> not permitted).
303         * @param fillPaint  the paint used to fill the shape (<code>null</code>
304         *                   not permitted).
305         */
306        public LegendItem(AttributedString label, String description, 
307                          String toolTipText, String urlText, 
308                          Shape shape, Paint fillPaint) {
309            
310            this(label, description, toolTipText, urlText, 
311                    /* shape visible = */ true, shape,
312                    /* shape filled = */ true, fillPaint,
313                    /* shape outlined = */ false, Color.black, UNUSED_STROKE,
314                    /* line visible = */ false, UNUSED_SHAPE, UNUSED_STROKE,
315                    Color.black);
316            
317        }
318        
319        /**
320         * Creates a legend item with a filled and outlined shape.
321         * 
322         * @param label  the label (<code>null</code> not permitted).
323         * @param description  the description (<code>null</code> permitted).
324         * @param toolTipText  the tool tip text (<code>null</code> permitted).
325         * @param urlText  the URL text (<code>null</code> permitted).
326         * @param shape  the shape (<code>null</code> not permitted).
327         * @param fillPaint  the paint used to fill the shape (<code>null</code>
328         *                   not permitted).
329         * @param outlineStroke  the outline stroke (<code>null</code> not 
330         *                       permitted).
331         * @param outlinePaint  the outline paint (<code>null</code> not 
332         *                      permitted).
333         */
334        public LegendItem(AttributedString label, String description, 
335                          String toolTipText, String urlText, 
336                          Shape shape, Paint fillPaint, 
337                          Stroke outlineStroke, Paint outlinePaint) {
338            
339            this(label, description, toolTipText, urlText,
340                    /* shape visible = */ true, shape,
341                    /* shape filled = */ true, fillPaint,
342                    /* shape outlined = */ true, outlinePaint, outlineStroke,
343                    /* line visible = */ false, UNUSED_SHAPE, UNUSED_STROKE,
344                    Color.black);
345        }
346        
347        /**
348         * Creates a legend item using a line.
349         * 
350         * @param label  the label (<code>null</code> not permitted).
351         * @param description  the description (<code>null</code> permitted).
352         * @param toolTipText  the tool tip text (<code>null</code> permitted).
353         * @param urlText  the URL text (<code>null</code> permitted).
354         * @param line  the line (<code>null</code> not permitted).
355         * @param lineStroke  the line stroke (<code>null</code> not permitted).
356         * @param linePaint  the line paint (<code>null</code> not permitted).
357         */
358        public LegendItem(AttributedString label, String description, 
359                          String toolTipText, String urlText, 
360                          Shape line, Stroke lineStroke, Paint linePaint) {
361            
362            this(label, description, toolTipText, urlText,
363                    /* shape visible = */ false, UNUSED_SHAPE,
364                    /* shape filled = */ false, Color.black,
365                    /* shape outlined = */ false, Color.black, UNUSED_STROKE,
366                    /* line visible = */ true, line, lineStroke, linePaint
367            );
368        }
369        
370        /**
371         * Creates a new legend item.
372         *
373         * @param label  the label (<code>null</code> not permitted).
374         * @param description  the description (not currently used, 
375         *        <code>null</code> permitted).
376         * @param toolTipText  the tool tip text (<code>null</code> permitted).
377         * @param urlText  the URL text (<code>null</code> permitted).
378         * @param shapeVisible  a flag that controls whether or not the shape is 
379         *                      displayed.
380         * @param shape  the shape (<code>null</code> permitted).
381         * @param shapeFilled  a flag that controls whether or not the shape is 
382         *                     filled.
383         * @param fillPaint  the fill paint (<code>null</code> not permitted).
384         * @param shapeOutlineVisible  a flag that controls whether or not the 
385         *                             shape is outlined.
386         * @param outlinePaint  the outline paint (<code>null</code> not permitted).
387         * @param outlineStroke  the outline stroke (<code>null</code> not 
388         *                       permitted).
389         * @param lineVisible  a flag that controls whether or not the line is 
390         *                     visible.
391         * @param line  the line.
392         * @param lineStroke  the stroke (<code>null</code> not permitted).
393         * @param linePaint  the line paint (<code>null</code> not permitted).
394         */
395        public LegendItem(AttributedString label, String description,
396                          String toolTipText, String urlText,
397                          boolean shapeVisible, Shape shape,
398                          boolean shapeFilled, Paint fillPaint, 
399                          boolean shapeOutlineVisible, Paint outlinePaint,
400                          Stroke outlineStroke,
401                          boolean lineVisible, Shape line, Stroke lineStroke,
402                          Paint linePaint) {
403            
404            if (label == null) {
405                throw new IllegalArgumentException("Null 'label' argument.");   
406            }
407            if (fillPaint == null) {
408                throw new IllegalArgumentException("Null 'fillPaint' argument.");   
409            }
410            if (lineStroke == null) {
411                throw new IllegalArgumentException("Null 'lineStroke' argument.");
412            }
413            if (outlinePaint == null) {
414                throw new IllegalArgumentException("Null 'outlinePaint' argument.");
415            }
416            if (outlineStroke == null) {
417                throw new IllegalArgumentException(
418                    "Null 'outlineStroke' argument.");   
419            }
420            this.label = characterIteratorToString(label.getIterator());
421            this.attributedLabel = label;
422            this.description = description;
423            this.shapeVisible = shapeVisible;
424            this.shape = shape;
425            this.shapeFilled = shapeFilled;
426            this.fillPaint = fillPaint;
427            this.shapeOutlineVisible = shapeOutlineVisible;
428            this.outlinePaint = outlinePaint;
429            this.outlineStroke = outlineStroke;
430            this.lineVisible = lineVisible;
431            this.line = line;
432            this.lineStroke = lineStroke;
433            this.linePaint = linePaint;
434            this.toolTipText = toolTipText;
435            this.urlText = urlText;
436        }
437    
438        /**
439         * Returns a string containing the characters from the given iterator.
440         * 
441         * @param iterator  the iterator (<code>null</code> not permitted).
442         * 
443         * @return A string.
444         */
445        private String characterIteratorToString(CharacterIterator iterator) {
446            int endIndex = iterator.getEndIndex();
447            int beginIndex = iterator.getBeginIndex();
448            int count = endIndex - beginIndex;
449            if (count <= 0) {
450                return "";
451            }
452            char[] chars = new char[count];
453            int i = 0;
454            char c = iterator.first();
455            while (c != CharacterIterator.DONE) {
456                chars[i] = c;
457                i++;
458                c = iterator.next();
459            }
460            return new String(chars);
461        }
462        
463        /**
464         * Returns the label.
465         *
466         * @return The label (never <code>null</code>).
467         */
468        public String getLabel() {
469            return this.label;
470        }
471    
472        /**
473         * Returns the attributed label.
474         *
475         * @return The attributed label (possibly <code>null</code>).
476         */
477        public AttributedString getAttributedLabel() {
478            return this.attributedLabel;
479        }
480    
481        /**
482         * Returns the description for the legend item.
483         * 
484         * @return The description.
485         */
486        public String getDescription() {
487            return this.description;   
488        }
489        
490        /**
491         * Returns the tool tip text.
492         * 
493         * @return The tool tip text (possibly <code>null</code>).
494         */
495        public String getToolTipText() {
496            return this.toolTipText;   
497        }
498        
499        /**
500         * Returns the URL text.
501         * 
502         * @return The URL text (possibly <code>null</code>).
503         */
504        public String getURLText() {
505            return this.urlText; 
506        }
507        
508        /**
509         * Returns a flag that indicates whether or not the shape is visible.
510         * 
511         * @return A boolean.
512         */
513        public boolean isShapeVisible() {
514            return this.shapeVisible;
515        }
516        
517        /**
518         * Returns the shape used to label the series represented by this legend 
519         * item.
520         *
521         * @return The shape (never <code>null</code>).
522         */
523        public Shape getShape() {
524            return this.shape;
525        }
526        
527        /**
528         * Returns a flag that controls whether or not the shape is filled.
529         * 
530         * @return A boolean.
531         */
532        public boolean isShapeFilled() {
533            return this.shapeFilled;
534        }
535    
536        /**
537         * Returns the fill paint.
538         *
539         * @return The fill paint (never <code>null</code>).
540         */
541        public Paint getFillPaint() {
542            return this.fillPaint;
543        }
544    
545        /**
546         * Returns the flag that controls whether or not the shape outline
547         * is visible.
548         * 
549         * @return A boolean.
550         */
551        public boolean isShapeOutlineVisible() {
552            return this.shapeOutlineVisible;
553        }
554        
555        /**
556         * Returns the line stroke for the series.
557         *
558         * @return The stroke (never <code>null</code>).
559         */
560        public Stroke getLineStroke() {
561            return this.lineStroke;
562        }
563        
564        /**
565         * Returns the paint used for lines.
566         * 
567         * @return The paint.
568         */
569        public Paint getLinePaint() {
570            return this.linePaint;
571        }
572        
573        /**
574         * Returns the outline paint.
575         *
576         * @return The outline paint (never <code>null</code>).
577         */
578        public Paint getOutlinePaint() {
579            return this.outlinePaint;
580        }
581    
582        /**
583         * Returns the outline stroke.
584         *
585         * @return The outline stroke (never <code>null</code>).
586         */
587        public Stroke getOutlineStroke() {
588            return this.outlineStroke;
589        }
590        
591        /**
592         * Returns a flag that indicates whether or not the line is visible.
593         * 
594         * @return A boolean.
595         */
596        public boolean isLineVisible() {
597            return this.lineVisible;
598        }
599        
600        /**
601         * Returns the line.
602         * 
603         * @return The line.
604         */
605        public Shape getLine() {
606            return this.line;
607        }
608        
609        /**
610         * Tests this item for equality with an arbitrary object.
611         * 
612         * @param obj  the object (<code>null</code> permitted).
613         * 
614         * @return A boolean.
615         */
616        public boolean equals(Object obj) {
617            if (obj == this) {
618                return true;   
619            }
620            if (!(obj instanceof LegendItem)) {
621                    return false;
622            }
623            LegendItem that = (LegendItem) obj;
624            if (!this.label.equals(that.label)) {
625                return false;
626            }
627            if (!AttributedStringUtilities.equal(this.attributedLabel, 
628                    that.attributedLabel)) {
629                return false;
630            }
631            if (!ObjectUtilities.equal(this.description, that.description)) {
632                return false;
633            }
634            if (this.shapeVisible != that.shapeVisible) {
635                return false;
636            }
637            if (!ShapeUtilities.equal(this.shape, that.shape)) {
638                return false;
639            }
640            if (this.shapeFilled != that.shapeFilled) {
641                return false;
642            }
643            if (!this.fillPaint.equals(that.fillPaint)) {
644                return false;   
645            }
646            if (this.shapeOutlineVisible != that.shapeOutlineVisible) {
647                return false;
648            }
649            if (!this.outlineStroke.equals(that.outlineStroke)) {
650                return false;   
651            }
652            if (!this.outlinePaint.equals(that.outlinePaint)) {
653                return false;   
654            }
655            if (!this.lineVisible == that.lineVisible) {
656                return false;
657            }
658            if (!ShapeUtilities.equal(this.line, that.line)) {
659                return false;
660            }
661            if (!this.lineStroke.equals(that.lineStroke)) {
662                return false;   
663            }
664            if (!this.linePaint.equals(that.linePaint)) {
665                return false;
666            }
667            return true;
668        }
669        
670        /**
671         * Provides serialization support.
672         *
673         * @param stream  the output stream (<code>null</code> not permitted).
674         *
675         * @throws IOException  if there is an I/O error.
676         */
677        private void writeObject(ObjectOutputStream stream) throws IOException {
678            stream.defaultWriteObject();
679            SerialUtilities.writeShape(this.shape, stream);
680            SerialUtilities.writePaint(this.fillPaint, stream);
681            SerialUtilities.writeStroke(this.outlineStroke, stream);
682            SerialUtilities.writePaint(this.outlinePaint, stream);
683            SerialUtilities.writeShape(this.line, stream);
684            SerialUtilities.writeStroke(this.lineStroke, stream);
685            SerialUtilities.writePaint(this.linePaint, stream);
686        }
687    
688        /**
689         * Provides serialization support.
690         *
691         * @param stream  the input stream (<code>null</code> not permitted).
692         *
693         * @throws IOException  if there is an I/O error.
694         * @throws ClassNotFoundException  if there is a classpath problem.
695         */
696        private void readObject(ObjectInputStream stream) 
697            throws IOException, ClassNotFoundException {
698            stream.defaultReadObject();
699            this.shape = SerialUtilities.readShape(stream);
700            this.fillPaint = SerialUtilities.readPaint(stream);
701            this.outlineStroke = SerialUtilities.readStroke(stream);
702            this.outlinePaint = SerialUtilities.readPaint(stream);
703            this.line = SerialUtilities.readShape(stream);
704            this.lineStroke = SerialUtilities.readStroke(stream);
705            this.linePaint = SerialUtilities.readPaint(stream);
706        }
707        
708    }