    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
    064    package org.jfree.chart;
    065
    066    import java.awt.BasicStroke;
    067    import java.awt.Color;
    068    import java.awt.Font;
    069    import java.awt.Paint;
    070    import java.awt.Shape;
    071    import java.awt.Stroke;
    072    import java.awt.geom.Line2D;
    073    import java.awt.geom.Rectangle2D;
    074    import java.io.IOException;
    075    import java.io.ObjectInputStream;
    076    import java.io.ObjectOutputStream;
    077    import java.io.Serializable;
    078    import java.text.AttributedString;
    079    import java.text.CharacterIterator;
    080
    081    import org.jfree.data.general.Dataset;
    082    import org.jfree.io.SerialUtilities;
    083    import org.jfree.ui.GradientPaintTransformer;
    084    import org.jfree.ui.StandardGradientPaintTransformer;
    085    import org.jfree.util.AttributedStringUtilities;
    086    import org.jfree.util.ObjectUtilities;
    087    import org.jfree.util.PaintUtilities;
    088    import org.jfree.util.PublicCloneable;
    089    import 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     */
    095    public 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    }