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