    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     * GridArrangement.java
    029     * --------------------
    030     * (C) Copyright 2005, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * $Id: GridArrangement.java,v 1.6.2.1 2005/10/25 20:39:38 mungady Exp $
    036     *
    037     * Changes:
    038     * --------
    039     * 08-Feb-2005 : Version 1 (DG);
    040     *
    041     */
    042
    043    package org.jfree.chart.block;
    044
    045    import java.awt.Graphics2D;
    046    import java.awt.geom.Rectangle2D;
    047    import java.io.Serializable;
    048    import java.util.Iterator;
    049    import java.util.List;
    050
    051    import org.jfree.ui.Size2D;
    052
    053    /**
    054     * Arranges blocks in a grid within their container.
    055     */
    056    public class GridArrangement implements Arrangement, Serializable {
    057
    058        /** For serialization. */
    059        private static final long serialVersionUID = -2563758090144655938L;
    060
    061        /** The rows. */
    062        private int rows;
    063
    064        /** The columns. */
    065        private int columns;
    066
    067        /**
    068         * Creates a new grid arrangement.
    069         *
    070         * @param rows  the row count.
    071         * @param columns  the column count.
    072         */
    073        public GridArrangement(int rows, int columns) {
    074            this.rows = rows;
    075            this.columns = columns;
    076        }
    077
    078        /**
    079         * Adds a block and a key which can be used to determine the position of
    080         * the block in the arrangement.  This method is called by the container
    081         * (you don't need to call this method directly) and gives the arrangement
    082         * an opportunity to record the details if they are required.
    083         *
    084         * @param block  the block.
    085         * @param key  the key (<code>null</code> permitted).
    086         */
    087        public void add(Block block, Object key) {
    088            // can safely ignore
    089        }
    090
    091        /**
    092         * Arranges the blocks within the specified container, subject to the given
    093         * constraint.
    094         *
    095         * @param container  the container.
    096         * @param constraint  the constraint.
    097         * @param g2  the graphics device.
    098         *
    099         * @return The size following the arrangement.
    100         */
    101        public Size2D arrange(BlockContainer container, Graphics2D g2,
    102                              RectangleConstraint constraint) {
    103            LengthConstraintType w = constraint.getWidthConstraintType();
    104            LengthConstraintType h = constraint.getHeightConstraintType();
    105            if (w == LengthConstraintType.NONE) {
    106                if (h == LengthConstraintType.NONE) {
    107                    return arrangeNN(container, g2);
    108                }
    109                else if (h == LengthConstraintType.FIXED) {
    110
    111                    throw new RuntimeException("Not yet implemented.");
    112                }
    113                else if (h == LengthConstraintType.RANGE) {
    114                    // find optimum height, then map to range
    115                    throw new RuntimeException("Not yet implemented.");
    116                }
    117            }
    118            else if (w == LengthConstraintType.FIXED) {
    119                if (h == LengthConstraintType.NONE) {
    120                    // find optimum height
    121                    return arrangeFN(container, g2, constraint);
    122                }
    123                else if (h == LengthConstraintType.FIXED) {
    124                    return arrangeFF(container, g2, constraint);
    125                }
    126                else if (h == LengthConstraintType.RANGE) {
    127                    // find optimum height and map to range
    128                    return arrangeFR(container, g2, constraint);
    129                }
    130            }
    131            else if (w == LengthConstraintType.RANGE) {
    132                // find optimum width and map to range
    133                if (h == LengthConstraintType.NONE) {
    134                    // find optimum height
    135                    throw new RuntimeException("Not yet implemented.");
    136                }
    137                else if (h == LengthConstraintType.FIXED) {
    138                    // fixed width
    139                    throw new RuntimeException("Not yet implemented.");
    140                }
    141                else if (h == LengthConstraintType.RANGE) {
    142                    throw new RuntimeException("Not yet implemented.");
    143                }
    144            }
    145            return new Size2D();  // TODO: complete this
    146        }
    147
    148        /**
    149         * Arranges the container with no constraint on the width or height.
    150         *
    151         * @param container  the container.
    152         * @param g2  the graphics device.
    153         *
    154         * @return The size.
    155         */
    156        protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) {
    157            double maxW = 0.0;
    158            double maxH = 0.0;
    159            List blocks = container.getBlocks();
    160            Iterator iterator = blocks.iterator();
    161            while (iterator.hasNext()) {
    162                Block b = (Block) iterator.next();
    163                Size2D s = b.arrange(g2, RectangleConstraint.NONE);
    164                maxW = Math.max(maxW, s.width);
    165                maxH = Math.max(maxH, s.height);
    166            }
    167            double width = this.columns * maxW;
    168            double height = this.rows * maxH;
    169            RectangleConstraint c = new RectangleConstraint(width, height);
    170            return arrangeFF(container, g2, c);
    171        }
    172
    173        /**
    174         * Arranges the container with a fixed overall width and height.
    175         *
    176         * @param container  the container.
    177         * @param g2  the graphics device.
    178         * @param constraint  the constraint.
    179         *
    180         * @return The size following the arrangement.
    181         */
    182        protected Size2D arrangeFF(BlockContainer container, Graphics2D g2,
    183                                   RectangleConstraint constraint) {
    184            double width = constraint.getWidth() /  this.columns;
    185            double height = constraint.getHeight() / this.rows;
    186            List blocks = container.getBlocks();
    187            for (int c = 0; c < this.columns; c++) {
    188                for (int r = 0; r < this.rows; r++) {
    189                    int index = r * this.columns + c;
    190                    if (index == blocks.size()) {
    191                        break;
    192                    }
    193                    Block b = (Block) blocks.get(index);
    194                    b.setBounds(new Rectangle2D.Double(
    195                        c * width, r * height, width, height
    196                    ));
    197                }
    198            }
    199            return new Size2D(this.columns * width, this.rows * height);
    200        }
    201
    202        /**
    203         * Arrange with a fixed width and a height within a given range.
    204         *
    205         * @param container  the container.
    206         * @param constraint  the constraint.
    207         * @param g2  the graphics device.
    208         *
    209         * @return The size of the arrangement.
    210         */
    211        protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
    212                                   RectangleConstraint constraint) {
    213
    214            RectangleConstraint c1 = constraint.toUnconstrainedHeight();
    215            Size2D size1 = arrange(container, g2, c1);
    216
    217            if (constraint.getHeightRange().contains(size1.getHeight())) {
    218                return size1;
    219            }
    220            else {
    221                double h = constraint.getHeightRange().constrain(size1.getHeight());
    222                RectangleConstraint c2 = constraint.toFixedHeight(h);
    223                return arrange(container, g2, c2);
    224            }
    225        }
    226
    227        /**
    228         * Arrange with a fixed width and a height within a given range.
    229         *
    230         * @param container  the container.
    231         * @param g2  the graphics device.
    232         * @param constraint  the constraint.
    233         *
    234         * @return The size of the arrangement.
    235         */
    236        protected Size2D arrangeFN(BlockContainer container, Graphics2D g2,
    237                                   RectangleConstraint constraint) {
    238
    239            double width = constraint.getWidth() /  this.columns;
    240            RectangleConstraint constraint2 = constraint.toFixedWidth(width);
    241            List blocks = container.getBlocks();
    242            double maxH = 0.0;
    243            for (int r = 0; r < this.rows; r++) {
    244                for (int c = 0; c < this.columns; c++) {
    245                    int index = r * this.columns + c;
    246                    if (index == blocks.size()) {
    247                        break;
    248                    }
    249                    Block b = (Block) blocks.get(index);
    250                    Size2D s = b.arrange(g2, constraint2);
    251                    maxH = Math.max(maxH, s.getHeight());
    252                }
    253            }
    254            RectangleConstraint constraint3 = constraint.toFixedHeight(
    255                maxH * this.rows
    256            );
    257            return arrange(container, g2, constraint3);
    258        }
    259
    260        /**
    261         * Clears any cached layout information retained by the arrangement.
    262         */
    263        public void clear() {
    264            // nothing to clear
    265        }
    266
    267        /**
    268         * Compares this layout manager for equality with an arbitrary object.
    269         *
    270         * @param obj  the object.
    271         *
    272         * @return A boolean.
    273         */
    274        public boolean equals(Object obj) {
    275            if (obj == this) {
    276                return true;
    277            }
    278            if (!(obj instanceof GridArrangement)) {
    279                return false;
    280            }
    281            GridArrangement that = (GridArrangement) obj;
    282            if (this.columns != that.columns) {
    283                return false;
    284            }
    285            if (this.rows != that.rows) {
    286                return false;
    287            }
    288            return true;
    289        }
    290
    291    }