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