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