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