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     * CenterArrangement.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-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    }