001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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     * 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    
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.List;
049    
050    import org.jfree.ui.Size2D;
051    
052    /**
053     * Arranges a block in the center of its container.  This class is immutable.
054     */
055    public 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    }