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