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