    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 * CenterArrangement.java
    029 * ----------------------
    030 * (C) Copyright 2005-2008, by Object Refinery Limited.
    031 *
    032 * Original Author:  David Gilbert (for Object Refinery Limited);
    033 * Contributor(s):   -;
    034 *
    035 * Changes:
    036 * --------
    037 * 08-Mar-2005 : Version 1 (DG);
    038 * ------------- JFREECHART 1.0.x ---------------------------------------------
    039 * 20-Jul-2006 : Set bounds of contained block when arranging (DG);
    040 *
    041 */
    042
    043package org.jfree.chart.block;
    044
    045import java.awt.Graphics2D;
    046import java.awt.geom.Rectangle2D;
    047import java.io.Serializable;
    048import java.util.List;
    049
    050import org.jfree.ui.Size2D;
    051
    052/**
    053 * Arranges a block in the center of its container.  This class is immutable.
    054 */
    055public class CenterArrangement implements Arrangement, Serializable {
    056
    057    /** For serialization. */
    058    private static final long serialVersionUID = -353308149220382047L;
    059
    060    /**
    061     * Creates a new instance.
    062     */
    063    public CenterArrangement() {
    064    }
    065
    066    /**
    067     * Adds a block to be managed by this instance.  This method is usually
    068     * called by the {@link BlockContainer}, you shouldn't need to call it
    069     * directly.
    070     *
    071     * @param block  the block.
    072     * @param key  a key that controls the position of the block.
    073     */
    074    public void add(Block block, Object key) {
    075        // since the flow layout is relatively straightforward,
    076        // no information needs to be recorded here
    077    }
    078
    079    /**
    080     * Calculates and sets the bounds of all the items in the specified
    081     * container, subject to the given constraint.  The <code>Graphics2D</code>
    082     * can be used by some items (particularly items containing text) to
    083     * calculate sizing parameters.
    084     *
    085     * @param container  the container whose items are being arranged.
    086     * @param g2  the graphics device.
    087     * @param constraint  the size constraint.
    088     *
    089     * @return The size of the container after arrangement of the contents.
    090     */
    091    public Size2D arrange(BlockContainer container, Graphics2D g2,
    092                          RectangleConstraint constraint) {
    093
    094        LengthConstraintType w = constraint.getWidthConstraintType();
    095        LengthConstraintType h = constraint.getHeightConstraintType();
    096        if (w == LengthConstraintType.NONE) {
    097            if (h == LengthConstraintType.NONE) {
    098                return arrangeNN(container, g2);
    099            }
    100            else if (h == LengthConstraintType.FIXED) {
    101                throw new RuntimeException("Not implemented.");
    102            }
    103            else if (h == LengthConstraintType.RANGE) {
    104                throw new RuntimeException("Not implemented.");
    105            }
    106        }
    107        else if (w == LengthConstraintType.FIXED) {
    108            if (h == LengthConstraintType.NONE) {
    109                return arrangeFN(container, g2, constraint);
    110            }
    111            else if (h == LengthConstraintType.FIXED) {
    112                throw new RuntimeException("Not implemented.");
    113            }
    114            else if (h == LengthConstraintType.RANGE) {
    115                throw new RuntimeException("Not implemented.");
    116            }
    117        }
    118        else if (w == LengthConstraintType.RANGE) {
    119            if (h == LengthConstraintType.NONE) {
    120                return arrangeRN(container, g2, constraint);
    121            }
    122            else if (h == LengthConstraintType.FIXED) {
    123                return arrangeRF(container, g2, constraint);
    124            }
    125            else if (h == LengthConstraintType.RANGE) {
    126                return arrangeRR(container, g2, constraint);
    127            }
    128        }
    129        throw new IllegalArgumentException("Unknown LengthConstraintType.");
    130
    131    }
    132
    133    /**
    134     * Arranges the blocks in the container with a fixed width and no height
    135     * constraint.
    136     *
    137     * @param container  the container.
    138     * @param g2  the graphics device.
    139     * @param constraint  the constraint.
    140     *
    141     * @return The size.
    142     */
    143    protected Size2D arrangeFN(BlockContainer container, Graphics2D g2,
    144                               RectangleConstraint constraint) {
    145
    146        List blocks = container.getBlocks();
    147        Block b = (Block) blocks.get(0);
    148        Size2D s = b.arrange(g2, RectangleConstraint.NONE);
    149        double width = constraint.getWidth();
    150        Rectangle2D bounds = new Rectangle2D.Double((width - s.width) / 2.0,
    151                0.0, s.width, s.height);
    152        b.setBounds(bounds);
    153        return new Size2D((width - s.width) / 2.0, s.height);
    154    }
    155
    156    /**
    157     * Arranges the blocks in the container with a fixed with and a range
    158     * constraint on the height.
    159     *
    160     * @param container  the container.
    161     * @param g2  the graphics device.
    162     * @param constraint  the constraint.
    163     *
    164     * @return The size following the arrangement.
    165     */
    166    protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
    167                               RectangleConstraint constraint) {
    168
    169        Size2D s = arrangeFN(container, g2, constraint);
    170        if (constraint.getHeightRange().contains(s.height)) {
    171            return s;
    172        }
    173        else {
    174            RectangleConstraint c = constraint.toFixedHeight(
    175                    constraint.getHeightRange().constrain(s.getHeight()));
    176            return arrangeFF(container, g2, c);
    177        }
    178    }
    179
    180    /**
    181     * Arranges the blocks in the container with the overall height and width
    182     * specified as fixed constraints.
    183     *
    184     * @param container  the container.
    185     * @param g2  the graphics device.
    186     * @param constraint  the constraint.
    187     *
    188     * @return The size following the arrangement.
    189     */
    190    protected Size2D arrangeFF(BlockContainer container, Graphics2D g2,
    191                               RectangleConstraint constraint) {
    192
    193        // TODO: implement this properly
    194        return arrangeFN(container, g2, constraint);
    195    }
    196
    197    /**
    198     * Arranges the blocks with the overall width and height to fit within
    199     * specified ranges.
    200     *
    201     * @param container  the container.
    202     * @param g2  the graphics device.
    203     * @param constraint  the constraint.
    204     *
    205     * @return The size after the arrangement.
    206     */
    207    protected Size2D arrangeRR(BlockContainer container, Graphics2D g2,
    208                               RectangleConstraint constraint) {
    209
    210        // first arrange without constraints, and see if this fits within
    211        // the required ranges...
    212        Size2D s1 = arrangeNN(container, g2);
    213        if (constraint.getWidthRange().contains(s1.width)) {
    214            return s1;  // TODO: we didn't check the height yet
    215        }
    216        else {
    217            RectangleConstraint c = constraint.toFixedWidth(
    218                    constraint.getWidthRange().getUpperBound());
    219            return arrangeFR(container, g2, c);
    220        }
    221    }
    222
    223    /**
    224     * Arranges the blocks in the container with a range constraint on the
    225     * width and a fixed height.
    226     *
    227     * @param container  the container.
    228     * @param g2  the graphics device.
    229     * @param constraint  the constraint.
    230     *
    231     * @return The size following the arrangement.
    232     */
    233    protected Size2D arrangeRF(BlockContainer container, Graphics2D g2,
    234                               RectangleConstraint constraint) {
    235
    236        Size2D s = arrangeNF(container, g2, constraint);
    237        if (constraint.getWidthRange().contains(s.width)) {
    238            return s;
    239        }
    240        else {
    241            RectangleConstraint c = constraint.toFixedWidth(
    242                    constraint.getWidthRange().constrain(s.getWidth()));
    243            return arrangeFF(container, g2, c);
    244        }
    245    }
    246
    247    /**
    248     * Arranges the block with a range constraint on the width, and no
    249     * constraint on the height.
    250     *
    251     * @param container  the container.
    252     * @param g2  the graphics device.
    253     * @param constraint  the constraint.
    254     *
    255     * @return The size following the arrangement.
    256     */
    257    protected Size2D arrangeRN(BlockContainer container, Graphics2D g2,
    258                               RectangleConstraint constraint) {
    259        // first arrange without constraints, then see if the width fits
    260        // within the required range...if not, call arrangeFN() at max width
    261        Size2D s1 = arrangeNN(container, g2);
    262        if (constraint.getWidthRange().contains(s1.width)) {
    263            return s1;
    264        }
    265        else {
    266            RectangleConstraint c = constraint.toFixedWidth(
    267                    constraint.getWidthRange().getUpperBound());
    268            return arrangeFN(container, g2, c);
    269        }
    270    }
    271
    272    /**
    273     * Arranges the blocks without any constraints.  This puts all blocks
    274     * into a single row.
    275     *
    276     * @param container  the container.
    277     * @param g2  the graphics device.
    278     *
    279     * @return The size after the arrangement.
    280     */
    281    protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) {
    282        List blocks = container.getBlocks();
    283        Block b = (Block) blocks.get(0);
    284        Size2D s = b.arrange(g2, RectangleConstraint.NONE);
    285        b.setBounds(new Rectangle2D.Double(0.0, 0.0, s.width, s.height));
    286        return new Size2D(s.width, s.height);
    287    }
    288
    289    /**
    290     * Arranges the blocks with no width constraint and a fixed height
    291     * constraint.  This puts all blocks into a single row.
    292     *
    293     * @param container  the container.
    294     * @param g2  the graphics device.
    295     * @param constraint  the constraint.
    296     *
    297     * @return The size after the arrangement.
    298     */
    299    protected Size2D arrangeNF(BlockContainer container, Graphics2D g2,
    300                               RectangleConstraint constraint) {
    301        // TODO: for now we are ignoring the height constraint
    302        return arrangeNN(container, g2);
    303    }
    304
    305    /**
    306     * Clears any cached information.
    307     */
    308    public void clear() {
    309        // no action required.
    310    }
    311
    312    /**
    313     * Tests this instance for equality with an arbitrary object.
    314     *
    315     * @param obj  the object (<code>null</code> permitted).
    316     *
    317     * @return A boolean.
    318     */
    319    public boolean equals(Object obj) {
    320        if (obj == this) {
    321            return true;
    322        }
    323        if (!(obj instanceof CenterArrangement)) {
    324            return false;
    325        }
    326        return true;
    327    }
    328
    329}