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