001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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-2008, 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     * Changes (from 2-Oct-2002)
039     * -------------------------
040     * 02-Oct-2002 : Fixed errors reported by Checkstyle (DG);
041     * 17-Jan-2003 : Dropped outlineStroke attribute (DG);
042     * 08-Oct-2003 : Applied patch for displaying series line style, contributed by
043     *               Luke Quinane (DG);
044     * 21-Jan-2004 : Added the shapeFilled flag (DG);
045     * 04-Jun-2004 : Added equals() method, implemented Serializable (DG);
046     * 25-Nov-2004 : Changes required by new LegendTitle implementation (DG);
047     * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0
048     *               release (DG);
049     * 20-Apr-2005 : Added tooltip and URL text (DG);
050     * 28-Nov-2005 : Separated constructors for AttributedString labels (DG);
051     * 10-Dec-2005 : Fixed serialization bug (1377239) (DG);
052     * ------------- JFREECHART 1.0.x ---------------------------------------------
053     * 20-Jul-2006 : Added dataset and series index fields (DG);
054     * 13-Dec-2006 : Added fillPaintTransformer attribute (DG);
055     * 18-May-2007 : Added dataset and seriesKey fields (DG);
056     * 03-Aug-2007 : Fixed null pointer exception (DG);
057     * 23-Apr-2008 : Added new constructor and implemented Cloneable (DG);
058     * 17-Jun-2008 : Added optional labelFont and labelPaint attributes (DG);
059     *
060     */
061    
062    package org.jfree.chart;
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.Shape;
069    import java.awt.Stroke;
070    import java.awt.geom.Line2D;
071    import java.awt.geom.Rectangle2D;
072    import java.io.IOException;
073    import java.io.ObjectInputStream;
074    import java.io.ObjectOutputStream;
075    import java.io.Serializable;
076    import java.text.AttributedString;
077    import java.text.CharacterIterator;
078    
079    import org.jfree.data.general.Dataset;
080    import org.jfree.io.SerialUtilities;
081    import org.jfree.ui.GradientPaintTransformer;
082    import org.jfree.ui.StandardGradientPaintTransformer;
083    import org.jfree.util.AttributedStringUtilities;
084    import org.jfree.util.ObjectUtilities;
085    import org.jfree.util.PaintUtilities;
086    import org.jfree.util.PublicCloneable;
087    import org.jfree.util.ShapeUtilities;
088    
089    /**
090     * A temporary storage object for recording the properties of a legend item,
091     * without any consideration for layout issues.
092     */
093    public class LegendItem implements Cloneable, Serializable {
094    
095        /** For serialization. */
096        private static final long serialVersionUID = -797214582948827144L;
097    
098        /**
099         * The dataset.
100         *
101         * @since 1.0.6
102         */
103        private Dataset dataset;
104    
105        /**
106         * The series key.
107         *
108         * @since 1.0.6
109         */
110        private Comparable seriesKey;
111    
112        /** The dataset index. */
113        private int datasetIndex;
114    
115        /** The series index. */
116        private int series;
117    
118        /** The label. */
119        private String label;
120    
121        /**
122         * The label font (<code>null</code> is permitted).
123         *
124         * @since 1.0.11
125         */
126        private Font labelFont;
127    
128        /**
129         * The label paint (<code>null</code> is permitted).
130         *
131         * @since 1.0.11
132         */
133        private transient Paint labelPaint;
134    
135        /** The attributed label (if null, fall back to the regular label). */
136        private transient AttributedString attributedLabel;
137    
138        /**
139         * The description (not currently used - could be displayed as a tool tip).
140         */
141        private String description;
142    
143        /** The tool tip text. */
144        private String toolTipText;
145    
146        /** The url text. */
147        private String urlText;
148    
149        /** A flag that controls whether or not the shape is visible. */
150        private boolean shapeVisible;
151    
152        /** The shape. */
153        private transient Shape shape;
154    
155        /** A flag that controls whether or not the shape is filled. */
156        private boolean shapeFilled;
157    
158        /** The paint. */
159        private transient Paint fillPaint;
160    
161        /**
162         * A gradient paint transformer.
163         *
164         * @since 1.0.4
165         */
166        private GradientPaintTransformer fillPaintTransformer;
167    
168        /** A flag that controls whether or not the shape outline is visible. */
169        private boolean shapeOutlineVisible;
170    
171        /** The outline paint. */
172        private transient Paint outlinePaint;
173    
174        /** The outline stroke. */
175        private transient Stroke outlineStroke;
176    
177        /** A flag that controls whether or not the line is visible. */
178        private boolean lineVisible;
179    
180        /** The line. */
181        private transient Shape line;
182    
183        /** The stroke. */
184        private transient Stroke lineStroke;
185    
186        /** The line paint. */
187        private transient Paint linePaint;
188    
189        /**
190         * The shape must be non-null for a LegendItem - if no shape is required,
191         * use this.
192         */
193        private static final Shape UNUSED_SHAPE = new Line2D.Float();
194    
195        /**
196         * The stroke must be non-null for a LegendItem - if no stroke is required,
197         * use this.
198         */
199        private static final Stroke UNUSED_STROKE = new BasicStroke(0.0f);
200    
201        /**
202         * Creates a legend item with the specified label.  The remaining
203         * attributes take default values.
204         *
205         * @param label  the label (<code>null</code> not permitted).
206         *
207         * @since 1.0.10
208         */
209        public LegendItem(String label) {
210            this(label, null, null, null, new Rectangle2D.Double(-4.0, -4.0, 8.0,
211                    8.0), Color.black);
212        }
213    
214        /**
215         * Creates a legend item with a filled shape.  The shape is not outlined,
216         * and no line is visible.
217         *
218         * @param label  the label (<code>null</code> not permitted).
219         * @param description  the description (<code>null</code> permitted).
220         * @param toolTipText  the tool tip text (<code>null</code> permitted).
221         * @param urlText  the URL text (<code>null</code> permitted).
222         * @param shape  the shape (<code>null</code> not permitted).
223         * @param fillPaint  the paint used to fill the shape (<code>null</code>
224         *                   not permitted).
225         */
226        public LegendItem(String label, String description,
227                          String toolTipText, String urlText,
228                          Shape shape, Paint fillPaint) {
229    
230            this(label, description, toolTipText, urlText,
231                    /* shape visible = */ true, shape,
232                    /* shape filled = */ true, fillPaint,
233                    /* shape outlined */ false, Color.black, UNUSED_STROKE,
234                    /* line visible */ false, UNUSED_SHAPE, UNUSED_STROKE,
235                    Color.black);
236    
237        }
238    
239        /**
240         * Creates a legend item with a filled and outlined shape.
241         *
242         * @param label  the label (<code>null</code> not permitted).
243         * @param description  the description (<code>null</code> permitted).
244         * @param toolTipText  the tool tip text (<code>null</code> permitted).
245         * @param urlText  the URL text (<code>null</code> permitted).
246         * @param shape  the shape (<code>null</code> not permitted).
247         * @param fillPaint  the paint used to fill the shape (<code>null</code>
248         *                   not permitted).
249         * @param outlineStroke  the outline stroke (<code>null</code> not
250         *                       permitted).
251         * @param outlinePaint  the outline paint (<code>null</code> not
252         *                      permitted).
253         */
254        public LegendItem(String label, String description,
255                          String toolTipText, String urlText,
256                          Shape shape, Paint fillPaint,
257                          Stroke outlineStroke, Paint outlinePaint) {
258    
259            this(label, description, toolTipText, urlText,
260                    /* shape visible = */ true, shape,
261                    /* shape filled = */ true, fillPaint,
262                    /* shape outlined = */ true, outlinePaint, outlineStroke,
263                    /* line visible */ false, UNUSED_SHAPE, UNUSED_STROKE,
264                    Color.black);
265    
266        }
267    
268        /**
269         * Creates a legend item using a line.
270         *
271         * @param label  the label (<code>null</code> not permitted).
272         * @param description  the description (<code>null</code> permitted).
273         * @param toolTipText  the tool tip text (<code>null</code> permitted).
274         * @param urlText  the URL text (<code>null</code> permitted).
275         * @param line  the line (<code>null</code> not permitted).
276         * @param lineStroke  the line stroke (<code>null</code> not permitted).
277         * @param linePaint  the line paint (<code>null</code> not permitted).
278         */
279        public LegendItem(String label, String description,
280                          String toolTipText, String urlText,
281                          Shape line, Stroke lineStroke, Paint linePaint) {
282    
283            this(label, description, toolTipText, urlText,
284                    /* shape visible = */ false, UNUSED_SHAPE,
285                    /* shape filled = */ false, Color.black,
286                    /* shape outlined = */ false, Color.black, UNUSED_STROKE,
287                    /* line visible = */ true, line, lineStroke, linePaint);
288        }
289    
290        /**
291         * Creates a new legend item.
292         *
293         * @param label  the label (<code>null</code> not permitted).
294         * @param description  the description (not currently used,
295         *        <code>null</code> permitted).
296         * @param toolTipText  the tool tip text (<code>null</code> permitted).
297         * @param urlText  the URL text (<code>null</code> permitted).
298         * @param shapeVisible  a flag that controls whether or not the shape is
299         *                      displayed.
300         * @param shape  the shape (<code>null</code> permitted).
301         * @param shapeFilled  a flag that controls whether or not the shape is
302         *                     filled.
303         * @param fillPaint  the fill paint (<code>null</code> not permitted).
304         * @param shapeOutlineVisible  a flag that controls whether or not the
305         *                             shape is outlined.
306         * @param outlinePaint  the outline paint (<code>null</code> not permitted).
307         * @param outlineStroke  the outline stroke (<code>null</code> not
308         *                       permitted).
309         * @param lineVisible  a flag that controls whether or not the line is
310         *                     visible.
311         * @param line  the line.
312         * @param lineStroke  the stroke (<code>null</code> not permitted).
313         * @param linePaint  the line paint (<code>null</code> not permitted).
314         */
315        public LegendItem(String label, String description,
316                          String toolTipText, String urlText,
317                          boolean shapeVisible, Shape shape,
318                          boolean shapeFilled, Paint fillPaint,
319                          boolean shapeOutlineVisible, Paint outlinePaint,
320                          Stroke outlineStroke,
321                          boolean lineVisible, Shape line,
322                          Stroke lineStroke, Paint linePaint) {
323    
324            if (label == null) {
325                throw new IllegalArgumentException("Null 'label' argument.");
326            }
327            if (fillPaint == null) {
328                throw new IllegalArgumentException("Null 'fillPaint' argument.");
329            }
330            if (lineStroke == null) {
331                throw new IllegalArgumentException("Null 'lineStroke' argument.");
332            }
333            if (outlinePaint == null) {
334                throw new IllegalArgumentException("Null 'outlinePaint' argument.");
335            }
336            if (outlineStroke == null) {
337                throw new IllegalArgumentException(
338                        "Null 'outlineStroke' argument.");
339            }
340            this.label = label;
341            this.labelPaint = null;
342            this.attributedLabel = null;
343            this.description = description;
344            this.shapeVisible = shapeVisible;
345            this.shape = shape;
346            this.shapeFilled = shapeFilled;
347            this.fillPaint = fillPaint;
348            this.fillPaintTransformer = new StandardGradientPaintTransformer();
349            this.shapeOutlineVisible = shapeOutlineVisible;
350            this.outlinePaint = outlinePaint;
351            this.outlineStroke = outlineStroke;
352            this.lineVisible = lineVisible;
353            this.line = line;
354            this.lineStroke = lineStroke;
355            this.linePaint = linePaint;
356            this.toolTipText = toolTipText;
357            this.urlText = urlText;
358        }
359    
360        /**
361         * Creates a legend item with a filled shape.  The shape is not outlined,
362         * and no line is visible.
363         *
364         * @param label  the label (<code>null</code> not permitted).
365         * @param description  the description (<code>null</code> permitted).
366         * @param toolTipText  the tool tip text (<code>null</code> permitted).
367         * @param urlText  the URL text (<code>null</code> permitted).
368         * @param shape  the shape (<code>null</code> not permitted).
369         * @param fillPaint  the paint used to fill the shape (<code>null</code>
370         *                   not permitted).
371         */
372        public LegendItem(AttributedString label, String description,
373                          String toolTipText, String urlText,
374                          Shape shape, Paint fillPaint) {
375    
376            this(label, description, toolTipText, urlText,
377                    /* shape visible = */ true, shape,
378                    /* shape filled = */ true, fillPaint,
379                    /* shape outlined = */ false, Color.black, UNUSED_STROKE,
380                    /* line visible = */ false, UNUSED_SHAPE, UNUSED_STROKE,
381                    Color.black);
382    
383        }
384    
385        /**
386         * Creates a legend item with a filled and outlined shape.
387         *
388         * @param label  the label (<code>null</code> not permitted).
389         * @param description  the description (<code>null</code> permitted).
390         * @param toolTipText  the tool tip text (<code>null</code> permitted).
391         * @param urlText  the URL text (<code>null</code> permitted).
392         * @param shape  the shape (<code>null</code> not permitted).
393         * @param fillPaint  the paint used to fill the shape (<code>null</code>
394         *                   not permitted).
395         * @param outlineStroke  the outline stroke (<code>null</code> not
396         *                       permitted).
397         * @param outlinePaint  the outline paint (<code>null</code> not
398         *                      permitted).
399         */
400        public LegendItem(AttributedString label, String description,
401                          String toolTipText, String urlText,
402                          Shape shape, Paint fillPaint,
403                          Stroke outlineStroke, Paint outlinePaint) {
404    
405            this(label, description, toolTipText, urlText,
406                    /* shape visible = */ true, shape,
407                    /* shape filled = */ true, fillPaint,
408                    /* shape outlined = */ true, outlinePaint, outlineStroke,
409                    /* line visible = */ false, UNUSED_SHAPE, UNUSED_STROKE,
410                    Color.black);
411        }
412    
413        /**
414         * Creates a legend item using a line.
415         *
416         * @param label  the label (<code>null</code> not permitted).
417         * @param description  the description (<code>null</code> permitted).
418         * @param toolTipText  the tool tip text (<code>null</code> permitted).
419         * @param urlText  the URL text (<code>null</code> permitted).
420         * @param line  the line (<code>null</code> not permitted).
421         * @param lineStroke  the line stroke (<code>null</code> not permitted).
422         * @param linePaint  the line paint (<code>null</code> not permitted).
423         */
424        public LegendItem(AttributedString label, String description,
425                          String toolTipText, String urlText,
426                          Shape line, Stroke lineStroke, Paint linePaint) {
427    
428            this(label, description, toolTipText, urlText,
429                    /* shape visible = */ false, UNUSED_SHAPE,
430                    /* shape filled = */ false, Color.black,
431                    /* shape outlined = */ false, Color.black, UNUSED_STROKE,
432                    /* line visible = */ true, line, lineStroke, linePaint);
433        }
434    
435        /**
436         * Creates a new legend item.
437         *
438         * @param label  the label (<code>null</code> not permitted).
439         * @param description  the description (not currently used,
440         *        <code>null</code> permitted).
441         * @param toolTipText  the tool tip text (<code>null</code> permitted).
442         * @param urlText  the URL text (<code>null</code> permitted).
443         * @param shapeVisible  a flag that controls whether or not the shape is
444         *                      displayed.
445         * @param shape  the shape (<code>null</code> permitted).
446         * @param shapeFilled  a flag that controls whether or not the shape is
447         *                     filled.
448         * @param fillPaint  the fill paint (<code>null</code> not permitted).
449         * @param shapeOutlineVisible  a flag that controls whether or not the
450         *                             shape is outlined.
451         * @param outlinePaint  the outline paint (<code>null</code> not permitted).
452         * @param outlineStroke  the outline stroke (<code>null</code> not
453         *                       permitted).
454         * @param lineVisible  a flag that controls whether or not the line is
455         *                     visible.
456         * @param line  the line (<code>null</code> not permitted).
457         * @param lineStroke  the stroke (<code>null</code> not permitted).
458         * @param linePaint  the line paint (<code>null</code> not permitted).
459         */
460        public LegendItem(AttributedString label, String description,
461                          String toolTipText, String urlText,
462                          boolean shapeVisible, Shape shape,
463                          boolean shapeFilled, Paint fillPaint,
464                          boolean shapeOutlineVisible, Paint outlinePaint,
465                          Stroke outlineStroke,
466                          boolean lineVisible, Shape line, Stroke lineStroke,
467                          Paint linePaint) {
468    
469            if (label == null) {
470                throw new IllegalArgumentException("Null 'label' argument.");
471            }
472            if (fillPaint == null) {
473                throw new IllegalArgumentException("Null 'fillPaint' argument.");
474            }
475            if (lineStroke == null) {
476                throw new IllegalArgumentException("Null 'lineStroke' argument.");
477            }
478            if (line == null) {
479                throw new IllegalArgumentException("Null 'line' argument.");
480            }
481            if (linePaint == null) {
482                throw new IllegalArgumentException("Null 'linePaint' argument.");
483            }
484            if (outlinePaint == null) {
485                throw new IllegalArgumentException("Null 'outlinePaint' argument.");
486            }
487            if (outlineStroke == null) {
488                throw new IllegalArgumentException(
489                    "Null 'outlineStroke' argument.");
490            }
491            this.label = characterIteratorToString(label.getIterator());
492            this.attributedLabel = label;
493            this.description = description;
494            this.shapeVisible = shapeVisible;
495            this.shape = shape;
496            this.shapeFilled = shapeFilled;
497            this.fillPaint = fillPaint;
498            this.fillPaintTransformer = new StandardGradientPaintTransformer();
499            this.shapeOutlineVisible = shapeOutlineVisible;
500            this.outlinePaint = outlinePaint;
501            this.outlineStroke = outlineStroke;
502            this.lineVisible = lineVisible;
503            this.line = line;
504            this.lineStroke = lineStroke;
505            this.linePaint = linePaint;
506            this.toolTipText = toolTipText;
507            this.urlText = urlText;
508        }
509    
510        /**
511         * Returns a string containing the characters from the given iterator.
512         *
513         * @param iterator  the iterator (<code>null</code> not permitted).
514         *
515         * @return A string.
516         */
517        private String characterIteratorToString(CharacterIterator iterator) {
518            int endIndex = iterator.getEndIndex();
519            int beginIndex = iterator.getBeginIndex();
520            int count = endIndex - beginIndex;
521            if (count <= 0) {
522                return "";
523            }
524            char[] chars = new char[count];
525            int i = 0;
526            char c = iterator.first();
527            while (c != CharacterIterator.DONE) {
528                chars[i] = c;
529                i++;
530                c = iterator.next();
531            }
532            return new String(chars);
533        }
534    
535        /**
536         * Returns the dataset.
537         *
538         * @return The dataset.
539         *
540         * @since 1.0.6
541         *
542         * @see #setDatasetIndex(int)
543         */
544        public Dataset getDataset() {
545            return this.dataset;
546        }
547    
548        /**
549         * Sets the dataset.
550         *
551         * @param dataset  the dataset.
552         *
553         * @since 1.0.6
554         */
555        public void setDataset(Dataset dataset) {
556            this.dataset = dataset;
557        }
558    
559        /**
560         * Returns the dataset index for this legend item.
561         *
562         * @return The dataset index.
563         *
564         * @since 1.0.2
565         *
566         * @see #setDatasetIndex(int)
567         * @see #getDataset()
568         */
569        public int getDatasetIndex() {
570            return this.datasetIndex;
571        }
572    
573        /**
574         * Sets the dataset index for this legend item.
575         *
576         * @param index  the index.
577         *
578         * @since 1.0.2
579         *
580         * @see #getDatasetIndex()
581         */
582        public void setDatasetIndex(int index) {
583            this.datasetIndex = index;
584        }
585    
586        /**
587         * Returns the series key.
588         *
589         * @return The series key.
590         *
591         * @since 1.0.6
592         *
593         * @see #setSeriesKey(Comparable)
594         */
595        public Comparable getSeriesKey() {
596            return this.seriesKey;
597        }
598    
599        /**
600         * Sets the series key.
601         *
602         * @param key  the series key.
603         *
604         * @since 1.0.6
605         */
606        public void setSeriesKey(Comparable key) {
607            this.seriesKey = key;
608        }
609    
610        /**
611         * Returns the series index for this legend item.
612         *
613         * @return The series index.
614         *
615         * @since 1.0.2
616         */
617        public int getSeriesIndex() {
618            return this.series;
619        }
620    
621        /**
622         * Sets the series index for this legend item.
623         *
624         * @param index  the index.
625         *
626         * @since 1.0.2
627         */
628        public void setSeriesIndex(int index) {
629            this.series = index;
630        }
631    
632        /**
633         * Returns the label.
634         *
635         * @return The label (never <code>null</code>).
636         */
637        public String getLabel() {
638            return this.label;
639        }
640    
641        /**
642         * Returns the label font.
643         *
644         * @return The label font (possibly <code>null</code>).
645         *
646         * @since 1.0.11
647         */
648        public Font getLabelFont() {
649            return this.labelFont;
650        }
651    
652        /**
653         * Sets the label font.
654         *
655         * @param font  the font (<code>null</code> permitted).
656         *
657         * @since 1.0.11
658         */
659        public void setLabelFont(Font font) {
660            this.labelFont = font;
661        }
662    
663        /**
664         * Returns the paint used to draw the label.
665         *
666         * @return The paint (possibly <code>null</code>).
667         *
668         * @since 1.0.11
669         */
670        public Paint getLabelPaint() {
671            return this.labelPaint;
672        }
673    
674        /**
675         * Sets the paint used to draw the label.
676         *
677         * @param paint  the paint (<code>null</code> permitted).
678         *
679         * @since 1.0.11
680         */
681        public void setLabelPaint(Paint paint) {
682            this.labelPaint = paint;
683        }
684    
685        /**
686         * Returns the attributed label.
687         *
688         * @return The attributed label (possibly <code>null</code>).
689         */
690        public AttributedString getAttributedLabel() {
691            return this.attributedLabel;
692        }
693    
694        /**
695         * Returns the description for the legend item.
696         *
697         * @return The description.
698         */
699        public String getDescription() {
700            return this.description;
701        }
702    
703        /**
704         * Returns the tool tip text.
705         *
706         * @return The tool tip text (possibly <code>null</code>).
707         */
708        public String getToolTipText() {
709            return this.toolTipText;
710        }
711    
712        /**
713         * Returns the URL text.
714         *
715         * @return The URL text (possibly <code>null</code>).
716         */
717        public String getURLText() {
718            return this.urlText;
719        }
720    
721        /**
722         * Returns a flag that indicates whether or not the shape is visible.
723         *
724         * @return A boolean.
725         */
726        public boolean isShapeVisible() {
727            return this.shapeVisible;
728        }
729    
730        /**
731         * Returns the shape used to label the series represented by this legend
732         * item.
733         *
734         * @return The shape (never <code>null</code>).
735         */
736        public Shape getShape() {
737            return this.shape;
738        }
739    
740        /**
741         * Returns a flag that controls whether or not the shape is filled.
742         *
743         * @return A boolean.
744         */
745        public boolean isShapeFilled() {
746            return this.shapeFilled;
747        }
748    
749        /**
750         * Returns the fill paint.
751         *
752         * @return The fill paint (never <code>null</code>).
753         */
754        public Paint getFillPaint() {
755            return this.fillPaint;
756        }
757    
758        /**
759         * Sets the fill paint.
760         *
761         * @param paint  the paint (<code>null</code> not permitted).
762         *
763         * @since 1.0.11
764         */
765        public void setFillPaint(Paint paint) {
766            if (paint == null) {
767                throw new IllegalArgumentException("Null 'paint' argument.");
768            }
769            this.fillPaint = paint;
770        }
771    
772        /**
773         * Returns the flag that controls whether or not the shape outline
774         * is visible.
775         *
776         * @return A boolean.
777         */
778        public boolean isShapeOutlineVisible() {
779            return this.shapeOutlineVisible;
780        }
781    
782        /**
783         * Returns the line stroke for the series.
784         *
785         * @return The stroke (never <code>null</code>).
786         */
787        public Stroke getLineStroke() {
788            return this.lineStroke;
789        }
790    
791        /**
792         * Returns the paint used for lines.
793         *
794         * @return The paint (never <code>null</code>).
795         */
796        public Paint getLinePaint() {
797            return this.linePaint;
798        }
799    
800        /**
801         * Sets the line paint.
802         *
803         * @param paint  the paint (<code>null</code> not permitted).
804         *
805         * @since 1.0.11
806         */
807        public void setLinePaint(Paint paint) {
808            if (paint == null) {
809                throw new IllegalArgumentException("Null 'paint' argument.");
810            }
811            this.linePaint = paint;
812        }
813    
814        /**
815         * Returns the outline paint.
816         *
817         * @return The outline paint (never <code>null</code>).
818         */
819        public Paint getOutlinePaint() {
820            return this.outlinePaint;
821        }
822    
823        /**
824         * Sets the outline paint.
825         *
826         * @param paint  the paint (<code>null</code> not permitted).
827         *
828         * @since 1.0.11
829         */
830        public void setOutlinePaint(Paint paint) {
831            if (paint == null) {
832                throw new IllegalArgumentException("Null 'paint' argument.");
833            }
834            this.outlinePaint = paint;
835        }
836    
837        /**
838         * Returns the outline stroke.
839         *
840         * @return The outline stroke (never <code>null</code>).
841         */
842        public Stroke getOutlineStroke() {
843            return this.outlineStroke;
844        }
845    
846        /**
847         * Returns a flag that indicates whether or not the line is visible.
848         *
849         * @return A boolean.
850         */
851        public boolean isLineVisible() {
852            return this.lineVisible;
853        }
854    
855        /**
856         * Returns the line.
857         *
858         * @return The line (never <code>null</code>).
859         */
860        public Shape getLine() {
861            return this.line;
862        }
863    
864        /**
865         * Returns the transformer used when the fill paint is an instance of
866         * <code>GradientPaint</code>.
867         *
868         * @return The transformer (never <code>null</code>).
869         *
870         * @since 1.0.4
871         *
872         * @see #setFillPaintTransformer(GradientPaintTransformer)
873         */
874        public GradientPaintTransformer getFillPaintTransformer() {
875            return this.fillPaintTransformer;
876        }
877    
878        /**
879         * Sets the transformer used when the fill paint is an instance of
880         * <code>GradientPaint</code>.
881         *
882         * @param transformer  the transformer (<code>null</code> not permitted).
883         *
884         * @since 1.0.4
885         *
886         * @see #getFillPaintTransformer()
887         */
888        public void setFillPaintTransformer(GradientPaintTransformer transformer) {
889            if (transformer == null) {
890                throw new IllegalArgumentException("Null 'transformer' attribute.");
891            }
892            this.fillPaintTransformer = transformer;
893        }
894    
895        /**
896         * Tests this item for equality with an arbitrary object.
897         *
898         * @param obj  the object (<code>null</code> permitted).
899         *
900         * @return A boolean.
901         */
902        public boolean equals(Object obj) {
903            if (obj == this) {
904                return true;
905            }
906            if (!(obj instanceof LegendItem)) {
907                    return false;
908            }
909            LegendItem that = (LegendItem) obj;
910            if (this.datasetIndex != that.datasetIndex) {
911                return false;
912            }
913            if (this.series != that.series) {
914                return false;
915            }
916            if (!this.label.equals(that.label)) {
917                return false;
918            }
919            if (!AttributedStringUtilities.equal(this.attributedLabel,
920                    that.attributedLabel)) {
921                return false;
922            }
923            if (!ObjectUtilities.equal(this.description, that.description)) {
924                return false;
925            }
926            if (this.shapeVisible != that.shapeVisible) {
927                return false;
928            }
929            if (!ShapeUtilities.equal(this.shape, that.shape)) {
930                return false;
931            }
932            if (this.shapeFilled != that.shapeFilled) {
933                return false;
934            }
935            if (!PaintUtilities.equal(this.fillPaint, that.fillPaint)) {
936                return false;
937            }
938            if (!ObjectUtilities.equal(this.fillPaintTransformer,
939                    that.fillPaintTransformer)) {
940                return false;
941            }
942            if (this.shapeOutlineVisible != that.shapeOutlineVisible) {
943                return false;
944            }
945            if (!this.outlineStroke.equals(that.outlineStroke)) {
946                return false;
947            }
948            if (!PaintUtilities.equal(this.outlinePaint, that.outlinePaint)) {
949                return false;
950            }
951            if (!this.lineVisible == that.lineVisible) {
952                return false;
953            }
954            if (!ShapeUtilities.equal(this.line, that.line)) {
955                return false;
956            }
957            if (!this.lineStroke.equals(that.lineStroke)) {
958                return false;
959            }
960            if (!PaintUtilities.equal(this.linePaint, that.linePaint)) {
961                return false;
962            }
963            if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) {
964                return false;
965            }
966            if (!PaintUtilities.equal(this.labelPaint, that.labelPaint)) {
967                return false;
968            }
969            return true;
970        }
971    
972        /**
973         * Returns an independent copy of this object (except that the clone will
974         * still reference the same dataset as the original
975         * <code>LegendItem</code>).
976         *
977         * @return A clone.
978         *
979         * @throws CloneNotSupportedException if the legend item cannot be cloned.
980         *
981         * @since 1.0.10
982         */
983        public Object clone() throws CloneNotSupportedException {
984            LegendItem clone = (LegendItem) super.clone();
985            if (this.seriesKey instanceof PublicCloneable) {
986                PublicCloneable pc = (PublicCloneable) this.seriesKey;
987                clone.seriesKey = (Comparable) pc.clone();
988            }
989            // FIXME: Clone the attributed string if it is not null
990            clone.shape = ShapeUtilities.clone(this.shape);
991            if (this.fillPaintTransformer instanceof PublicCloneable) {
992                PublicCloneable pc = (PublicCloneable) this.fillPaintTransformer;
993                clone.fillPaintTransformer = (GradientPaintTransformer) pc.clone();
994    
995            }
996            clone.line = ShapeUtilities.clone(this.line);
997            return clone;
998        }
999    
1000        /**
1001         * Provides serialization support.
1002         *
1003         * @param stream  the output stream (<code>null</code> not permitted).
1004         *
1005         * @throws IOException  if there is an I/O error.
1006         */
1007        private void writeObject(ObjectOutputStream stream) throws IOException {
1008            stream.defaultWriteObject();
1009            SerialUtilities.writeAttributedString(this.attributedLabel, stream);
1010            SerialUtilities.writeShape(this.shape, stream);
1011            SerialUtilities.writePaint(this.fillPaint, stream);
1012            SerialUtilities.writeStroke(this.outlineStroke, stream);
1013            SerialUtilities.writePaint(this.outlinePaint, stream);
1014            SerialUtilities.writeShape(this.line, stream);
1015            SerialUtilities.writeStroke(this.lineStroke, stream);
1016            SerialUtilities.writePaint(this.linePaint, stream);
1017            SerialUtilities.writePaint(this.labelPaint, stream);
1018        }
1019    
1020        /**
1021         * Provides serialization support.
1022         *
1023         * @param stream  the input stream (<code>null</code> not permitted).
1024         *
1025         * @throws IOException  if there is an I/O error.
1026         * @throws ClassNotFoundException  if there is a classpath problem.
1027         */
1028        private void readObject(ObjectInputStream stream)
1029            throws IOException, ClassNotFoundException {
1030            stream.defaultReadObject();
1031            this.attributedLabel = SerialUtilities.readAttributedString(stream);
1032            this.shape = SerialUtilities.readShape(stream);
1033            this.fillPaint = SerialUtilities.readPaint(stream);
1034            this.outlineStroke = SerialUtilities.readStroke(stream);
1035            this.outlinePaint = SerialUtilities.readPaint(stream);
1036            this.line = SerialUtilities.readShape(stream);
1037            this.lineStroke = SerialUtilities.readStroke(stream);
1038            this.linePaint = SerialUtilities.readPaint(stream);
1039            this.labelPaint = SerialUtilities.readPaint(stream);
1040        }
1041    
1042    }