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     * CenterArrangement.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: CenterArrangement.java,v 1.3.2.1 2005/10/25 20:39:38 mungady Exp $
036     *
037     * Changes:
038     * --------
039     * 08-Mar-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.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(
151                (width - s.width) / 2.0, 0.0, s.width, s.height
152            );
153            b.setBounds(bounds);
154            return new Size2D((width - s.width) / 2.0, s.height);  
155        }
156        
157        /**
158         * Arranges the blocks in the container with a fixed with and a range
159         * constraint on the height.
160         * 
161         * @param container  the container.
162         * @param g2  the graphics device.
163         * @param constraint  the constraint.
164         * 
165         * @return The size following the arrangement.
166         */
167        protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
168                                   RectangleConstraint constraint) {
169    
170            Size2D s = arrangeFN(container, g2, constraint);
171            if (constraint.getHeightRange().contains(s.height)) {
172                return s;   
173            }
174            else {
175                RectangleConstraint c = constraint.toFixedHeight(
176                    constraint.getHeightRange().constrain(s.getHeight())
177                );
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                );
222                return arrangeFR(container, g2, c);
223            }
224        }
225        
226        /**
227         * Arranges the blocks in the container with a range constraint on the
228         * width and a fixed height.
229         * 
230         * @param container  the container.
231         * @param g2  the graphics device.
232         * @param constraint  the constraint.
233         * 
234         * @return The size following the arrangement.
235         */
236        protected Size2D arrangeRF(BlockContainer container, Graphics2D g2,
237                                   RectangleConstraint constraint) {
238    
239            Size2D s = arrangeNF(container, g2, constraint);
240            if (constraint.getWidthRange().contains(s.width)) {
241                return s;   
242            }
243            else {
244                RectangleConstraint c = constraint.toFixedWidth(
245                    constraint.getWidthRange().constrain(s.getWidth())
246                );
247                return arrangeFF(container, g2, c);
248            }
249        }
250    
251        /**
252         * Arranges the block with a range constraint on the width, and no 
253         * constraint on the height.
254         * 
255         * @param container  the container.
256         * @param g2  the graphics device.
257         * @param constraint  the constraint.
258         * 
259         * @return The size following the arrangement.
260         */
261        protected Size2D arrangeRN(BlockContainer container, Graphics2D g2,
262                                   RectangleConstraint constraint) {
263            // first arrange without constraints, then see if the width fits
264            // within the required range...if not, call arrangeFN() at max width
265            Size2D s1 = arrangeNN(container, g2);
266            if (constraint.getWidthRange().contains(s1.width)) {
267                return s1;   
268            }
269            else {
270                RectangleConstraint c = constraint.toFixedWidth(
271                    constraint.getWidthRange().getUpperBound()
272                );
273                return arrangeFN(container, g2, c);
274            }
275        }
276        
277        /**
278         * Arranges the blocks without any constraints.  This puts all blocks
279         * into a single row.
280         * 
281         * @param container  the container.
282         * @param g2  the graphics device.
283         * 
284         * @return The size after the arrangement.
285         */
286        protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) {
287            List blocks = container.getBlocks();
288            Block b = (Block) blocks.get(0);
289            Size2D s = b.arrange(g2, RectangleConstraint.NONE);
290            return new Size2D(s.width, s.height);  
291        }
292        
293        /**
294         * Arranges the blocks with no width constraint and a fixed height 
295         * constraint.  This puts all blocks into a single row.
296         * 
297         * @param container  the container.
298         * @param g2  the graphics device.
299         * @param constraint  the constraint.
300         * 
301         * @return The size after the arrangement.
302         */
303        protected Size2D arrangeNF(BlockContainer container, Graphics2D g2,
304                                   RectangleConstraint constraint) {
305            // TODO: for now we are ignoring the height constraint
306            return arrangeNN(container, g2);
307        }
308        
309        /**
310         * Clears any cached information.
311         */
312        public void clear() {
313            // no action required.
314        }
315        
316        /**
317         * Tests this instance for equality with an arbitrary object.
318         * 
319         * @param obj  the object (<code>null</code> permitted).
320         * 
321         * @return A boolean.
322         */
323        public boolean equals(Object obj) {
324            if (obj == this) {
325                return true;   
326            }
327            if (!(obj instanceof CenterArrangement)) {
328                return false;   
329            }
330            return true;
331        }
332        
333    }