    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 * CategoryLabelPositions.java
    029 * ---------------------------
    030 * (C) Copyright 2004-2008, by Object Refinery Limited and Contributors.
    031 *
    032 * Original Author:  David Gilbert (for Object Refinery Limited);
    033 * Contributor(s):   -;
    034 *
    035 * Changes
    036 * -------
    037 * 06-Jan-2004 : Version 1 (DG);
    038 * 17-Feb-2004 : Added equals() method (DG);
    039 * 05-Nov-2004 : Adjusted settings for UP_90 and DOWN_90 (DG);
    040 *
    041 */
    042
    043package org.jfree.chart.axis;
    044
    045import java.io.Serializable;
    046
    047import org.jfree.text.TextBlockAnchor;
    048import org.jfree.ui.RectangleAnchor;
    049import org.jfree.ui.RectangleEdge;
    050import org.jfree.ui.TextAnchor;
    051
    052/**
    053 * Records the label positions for a category axis.  Instances of this class
    054 * are immutable.
    055 */
    056public class CategoryLabelPositions implements Serializable {
    057
    058    /** For serialization. */
    059    private static final long serialVersionUID = -8999557901920364580L;
    060
    061    /** STANDARD category label positions. */
    062    public static final CategoryLabelPositions
    063        STANDARD = new CategoryLabelPositions(
    064            new CategoryLabelPosition(
    065                RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_CENTER
    066            ), // TOP
    067            new CategoryLabelPosition(
    068                RectangleAnchor.TOP, TextBlockAnchor.TOP_CENTER
    069            ), // BOTTOM
    070            new CategoryLabelPosition(
    071                RectangleAnchor.RIGHT, TextBlockAnchor.CENTER_RIGHT,
    072                CategoryLabelWidthType.RANGE, 0.30f
    073            ), // LEFT
    074            new CategoryLabelPosition(
    075                RectangleAnchor.LEFT, TextBlockAnchor.CENTER_LEFT,
    076                CategoryLabelWidthType.RANGE, 0.30f
    077            ) // RIGHT
    078        );
    079
    080    /** UP_90 category label positions. */
    081    public static final CategoryLabelPositions
    082        UP_90 = new CategoryLabelPositions(
    083            new CategoryLabelPosition(
    084                RectangleAnchor.BOTTOM, TextBlockAnchor.CENTER_LEFT,
    085                TextAnchor.CENTER_LEFT, -Math.PI / 2.0,
    086                CategoryLabelWidthType.RANGE, 0.30f
    087            ), // TOP
    088            new CategoryLabelPosition(
    089                RectangleAnchor.TOP, TextBlockAnchor.CENTER_RIGHT,
    090                TextAnchor.CENTER_RIGHT, -Math.PI / 2.0,
    091                CategoryLabelWidthType.RANGE, 0.30f
    092            ), // BOTTOM
    093            new CategoryLabelPosition(
    094                RectangleAnchor.RIGHT, TextBlockAnchor.BOTTOM_CENTER,
    095                TextAnchor.BOTTOM_CENTER, -Math.PI / 2.0,
    096                CategoryLabelWidthType.CATEGORY, 0.9f
    097            ), // LEFT
    098            new CategoryLabelPosition(
    099                RectangleAnchor.LEFT, TextBlockAnchor.TOP_CENTER,
    100                TextAnchor.TOP_CENTER, -Math.PI / 2.0,
    101                CategoryLabelWidthType.CATEGORY, 0.90f
    102            ) // RIGHT
    103        );
    104
    105    /** DOWN_90 category label positions. */
    106    public static final CategoryLabelPositions
    107        DOWN_90 = new CategoryLabelPositions(
    108            new CategoryLabelPosition(
    109                RectangleAnchor.BOTTOM, TextBlockAnchor.CENTER_RIGHT,
    110                TextAnchor.CENTER_RIGHT, Math.PI / 2.0,
    111                CategoryLabelWidthType.RANGE, 0.30f
    112            ), // TOP
    113            new CategoryLabelPosition(
    114                RectangleAnchor.TOP, TextBlockAnchor.CENTER_LEFT,
    115                TextAnchor.CENTER_LEFT, Math.PI / 2.0,
    116                CategoryLabelWidthType.RANGE, 0.30f
    117            ), // BOTTOM
    118            new CategoryLabelPosition(
    119                RectangleAnchor.RIGHT, TextBlockAnchor.TOP_CENTER,
    120                TextAnchor.TOP_CENTER, Math.PI / 2.0,
    121                CategoryLabelWidthType.CATEGORY, 0.90f
    122            ), // LEFT
    123            new CategoryLabelPosition(
    124                RectangleAnchor.LEFT, TextBlockAnchor.BOTTOM_CENTER,
    125                TextAnchor.BOTTOM_CENTER, Math.PI / 2.0,
    126                CategoryLabelWidthType.CATEGORY, 0.90f
    127            ) // RIGHT
    128        );
    129
    130    /** UP_45 category label positions. */
    131    public static final CategoryLabelPositions UP_45
    132        = createUpRotationLabelPositions(Math.PI / 4.0);
    133
    134    /** DOWN_45 category label positions. */
    135    public static final CategoryLabelPositions DOWN_45
    136        = createDownRotationLabelPositions(Math.PI / 4.0);
    137
    138    /**
    139     * Creates a new instance where the category labels angled upwards by the
    140     * specified amount.
    141     *
    142     * @param angle  the rotation angle (should be < Math.PI / 2.0).
    143     *
    144     * @return A category label position specification.
    145     */
    146    public static CategoryLabelPositions createUpRotationLabelPositions(
    147            double angle) {
    148        return new CategoryLabelPositions(
    149            new CategoryLabelPosition(
    150                RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_LEFT,
    151                TextAnchor.BOTTOM_LEFT, -angle,
    152                CategoryLabelWidthType.RANGE, 0.50f
    153            ), // TOP
    154            new CategoryLabelPosition(
    155                RectangleAnchor.TOP, TextBlockAnchor.TOP_RIGHT,
    156                TextAnchor.TOP_RIGHT, -angle,
    157                CategoryLabelWidthType.RANGE, 0.50f
    158            ), // BOTTOM
    159            new CategoryLabelPosition(
    160                RectangleAnchor.RIGHT, TextBlockAnchor.BOTTOM_RIGHT,
    161                TextAnchor.BOTTOM_RIGHT, -angle,
    162                CategoryLabelWidthType.RANGE, 0.50f
    163            ), // LEFT
    164            new CategoryLabelPosition(
    165                RectangleAnchor.LEFT, TextBlockAnchor.TOP_LEFT,
    166                TextAnchor.TOP_LEFT, -angle,
    167                CategoryLabelWidthType.RANGE, 0.50f
    168            ) // RIGHT
    169        );
    170    }
    171
    172    /**
    173     * Creates a new instance where the category labels angled downwards by the
    174     * specified amount.
    175     *
    176     * @param angle  the rotation angle (should be < Math.PI / 2.0).
    177     *
    178     * @return A category label position specification.
    179     */
    180    public static CategoryLabelPositions createDownRotationLabelPositions(
    181            double angle) {
    182        return new CategoryLabelPositions(
    183            new CategoryLabelPosition(
    184                RectangleAnchor.BOTTOM, TextBlockAnchor.BOTTOM_RIGHT,
    185                TextAnchor.BOTTOM_RIGHT, angle,
    186                CategoryLabelWidthType.RANGE, 0.50f
    187            ), // TOP
    188            new CategoryLabelPosition(
    189                RectangleAnchor.TOP, TextBlockAnchor.TOP_LEFT,
    190                TextAnchor.TOP_LEFT, angle,
    191                CategoryLabelWidthType.RANGE, 0.50f
    192            ), // BOTTOM
    193            new CategoryLabelPosition(
    194                RectangleAnchor.RIGHT, TextBlockAnchor.TOP_RIGHT,
    195                TextAnchor.TOP_RIGHT, angle,
    196                CategoryLabelWidthType.RANGE, 0.50f
    197            ), // LEFT
    198            new CategoryLabelPosition(
    199                RectangleAnchor.LEFT, TextBlockAnchor.BOTTOM_LEFT,
    200                TextAnchor.BOTTOM_LEFT, angle,
    201                CategoryLabelWidthType.RANGE, 0.50f
    202            ) // RIGHT
    203        );
    204    }
    205
    206    /**
    207     * The label positioning details used when an axis is at the top of a
    208     * chart.
    209     */
    210    private CategoryLabelPosition positionForAxisAtTop;
    211
    212    /**
    213     * The label positioning details used when an axis is at the bottom of a
    214     * chart.
    215     */
    216    private CategoryLabelPosition positionForAxisAtBottom;
    217
    218    /**
    219     * The label positioning details used when an axis is at the left of a
    220     * chart.
    221     */
    222    private CategoryLabelPosition positionForAxisAtLeft;
    223
    224    /**
    225     * The label positioning details used when an axis is at the right of a
    226     * chart.
    227     */
    228    private CategoryLabelPosition positionForAxisAtRight;
    229
    230    /**
    231     * Default constructor.
    232     */
    233    public CategoryLabelPositions() {
    234        this.positionForAxisAtTop = new CategoryLabelPosition();
    235        this.positionForAxisAtBottom = new CategoryLabelPosition();
    236        this.positionForAxisAtLeft = new CategoryLabelPosition();
    237        this.positionForAxisAtRight = new CategoryLabelPosition();
    238    }
    239
    240    /**
    241     * Creates a new position specification.
    242     *
    243     * @param top  the label position info used when an axis is at the top
    244     *             (<code>null</code> not permitted).
    245     * @param bottom  the label position info used when an axis is at the
    246     *                bottom (<code>null</code> not permitted).
    247     * @param left  the label position info used when an axis is at the left
    248     *              (<code>null</code> not permitted).
    249     * @param right  the label position info used when an axis is at the right
    250     *               (<code>null</code> not permitted).
    251     */
    252    public CategoryLabelPositions(CategoryLabelPosition top,
    253                                  CategoryLabelPosition bottom,
    254                                  CategoryLabelPosition left,
    255                                  CategoryLabelPosition right) {
    256
    257        if (top == null) {
    258            throw new IllegalArgumentException("Null 'top' argument.");
    259        }
    260        if (bottom == null) {
    261            throw new IllegalArgumentException("Null 'bottom' argument.");
    262        }
    263        if (left == null) {
    264            throw new IllegalArgumentException("Null 'left' argument.");
    265        }
    266        if (right == null) {
    267            throw new IllegalArgumentException("Null 'right' argument.");
    268        }
    269
    270        this.positionForAxisAtTop = top;
    271        this.positionForAxisAtBottom = bottom;
    272        this.positionForAxisAtLeft = left;
    273        this.positionForAxisAtRight = right;
    274
    275    }
    276
    277    /**
    278     * Returns the category label position specification for an axis at the
    279     * given location.
    280     *
    281     * @param edge  the axis location.
    282     *
    283     * @return The category label position specification.
    284     */
    285    public CategoryLabelPosition getLabelPosition(RectangleEdge edge) {
    286        CategoryLabelPosition result = null;
    287        if (edge == RectangleEdge.TOP) {
    288            result = this.positionForAxisAtTop;
    289        }
    290        else if (edge == RectangleEdge.BOTTOM) {
    291            result = this.positionForAxisAtBottom;
    292        }
    293        else if (edge == RectangleEdge.LEFT) {
    294            result = this.positionForAxisAtLeft;
    295        }
    296        else if (edge == RectangleEdge.RIGHT) {
    297            result = this.positionForAxisAtRight;
    298        }
    299        return result;
    300    }
    301
    302    /**
    303     * Returns a new instance based on an existing instance but with the top
    304     * position changed.
    305     *
    306     * @param base  the base (<code>null</code> not permitted).
    307     * @param top  the top position (<code>null</code> not permitted).
    308     *
    309     * @return A new instance (never <code>null</code>).
    310     */
    311    public static CategoryLabelPositions replaceTopPosition(
    312            CategoryLabelPositions base, CategoryLabelPosition top) {
    313
    314        if (base == null) {
    315            throw new IllegalArgumentException("Null 'base' argument.");
    316        }
    317        if (top == null) {
    318            throw new IllegalArgumentException("Null 'top' argument.");
    319        }
    320
    321        return new CategoryLabelPositions(
    322            top,
    323            base.getLabelPosition(RectangleEdge.BOTTOM),
    324            base.getLabelPosition(RectangleEdge.LEFT),
    325            base.getLabelPosition(RectangleEdge.RIGHT)
    326        );
    327    }
    328
    329    /**
    330     * Returns a new instance based on an existing instance but with the bottom
    331     * position changed.
    332     *
    333     * @param base  the base (<code>null</code> not permitted).
    334     * @param bottom  the bottom position (<code>null</code> not permitted).
    335     *
    336     * @return A new instance (never <code>null</code>).
    337     */
    338    public static CategoryLabelPositions replaceBottomPosition(
    339            CategoryLabelPositions base, CategoryLabelPosition bottom) {
    340
    341        if (base == null) {
    342            throw new IllegalArgumentException("Null 'base' argument.");
    343        }
    344        if (bottom == null) {
    345            throw new IllegalArgumentException("Null 'bottom' argument.");
    346        }
    347
    348        return new CategoryLabelPositions(
    349            base.getLabelPosition(RectangleEdge.TOP),
    350            bottom,
    351            base.getLabelPosition(RectangleEdge.LEFT),
    352            base.getLabelPosition(RectangleEdge.RIGHT)
    353        );
    354    }
    355
    356    /**
    357     * Returns a new instance based on an existing instance but with the left
    358     * position changed.
    359     *
    360     * @param base  the base (<code>null</code> not permitted).
    361     * @param left  the left position (<code>null</code> not permitted).
    362     *
    363     * @return A new instance (never <code>null</code>).
    364     */
    365    public static CategoryLabelPositions replaceLeftPosition(
    366            CategoryLabelPositions base, CategoryLabelPosition left) {
    367
    368        if (base == null) {
    369            throw new IllegalArgumentException("Null 'base' argument.");
    370        }
    371        if (left == null) {
    372            throw new IllegalArgumentException("Null 'left' argument.");
    373        }
    374
    375        return new CategoryLabelPositions(
    376            base.getLabelPosition(RectangleEdge.TOP),
    377            base.getLabelPosition(RectangleEdge.BOTTOM),
    378            left,
    379            base.getLabelPosition(RectangleEdge.RIGHT)
    380        );
    381    }
    382
    383    /**
    384     * Returns a new instance based on an existing instance but with the right
    385     * position changed.
    386     *
    387     * @param base  the base (<code>null</code> not permitted).
    388     * @param right  the right position (<code>null</code> not permitted).
    389     *
    390     * @return A new instance (never <code>null</code>).
    391     */
    392    public static CategoryLabelPositions replaceRightPosition(
    393            CategoryLabelPositions base, CategoryLabelPosition right) {
    394
    395        if (base == null) {
    396            throw new IllegalArgumentException("Null 'base' argument.");
    397        }
    398        if (right == null) {
    399            throw new IllegalArgumentException("Null 'right' argument.");
    400        }
    401
    402        return new CategoryLabelPositions(
    403            base.getLabelPosition(RectangleEdge.TOP),
    404            base.getLabelPosition(RectangleEdge.BOTTOM),
    405            base.getLabelPosition(RectangleEdge.LEFT),
    406            right
    407        );
    408    }
    409
    410    /**
    411     * Returns <code>true</code> if this object is equal to the specified
    412     * object, and <code>false</code> otherwise.
    413     *
    414     * @param obj  the other object.
    415     *
    416     * @return A boolean.
    417     */
    418    public boolean equals(Object obj) {
    419
    420        if (this == obj) {
    421            return true;
    422        }
    423        if (!(obj instanceof CategoryLabelPositions)) {
    424            return false;
    425        }
    426
    427        CategoryLabelPositions that = (CategoryLabelPositions) obj;
    428        if (!this.positionForAxisAtTop.equals(that.positionForAxisAtTop)) {
    429            return false;
    430        }
    431        if (!this.positionForAxisAtBottom.equals(
    432                that.positionForAxisAtBottom)) {
    433            return false;
    434        }
    435        if (!this.positionForAxisAtLeft.equals(that.positionForAxisAtLeft)) {
    436            return false;
    437        }
    438        if (!this.positionForAxisAtRight.equals(that.positionForAxisAtRight)) {
    439            return false;
    440        }
    441
    442        return true;
    443
    444    }
    445
    446    /**
    447     * Returns a hash code for this object.
    448     *
    449     * @return A hash code.
    450     */
    451    public int hashCode() {
    452        int result = 19;
    453        result = 37 * result + this.positionForAxisAtTop.hashCode();
    454        result = 37 * result + this.positionForAxisAtBottom.hashCode();
    455        result = 37 * result + this.positionForAxisAtLeft.hashCode();
    456        result = 37 * result + this.positionForAxisAtRight.hashCode();
    457        return result;
    458    }
    459}