001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2013, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
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
043package org.jfree.chart.block;
044
045import java.awt.Graphics2D;
046import java.awt.geom.Rectangle2D;
047import java.io.Serializable;
048import java.util.List;
049
050import org.jfree.ui.Size2D;
051
052/**
053 * Arranges a block in the center of its container.  This class is immutable.
054 */
055public 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    @Override
075    public void add(Block block, Object key) {
076        // since the flow layout is relatively straightforward,
077        // no information needs to be recorded here
078    }
079
080    /**
081     * Calculates and sets the bounds of all the items in the specified
082     * container, subject to the given constraint.  The <code>Graphics2D</code>
083     * can be used by some items (particularly items containing text) to
084     * calculate sizing parameters.
085     *
086     * @param container  the container whose items are being arranged.
087     * @param g2  the graphics device.
088     * @param constraint  the size constraint.
089     *
090     * @return The size of the container after arrangement of the contents.
091     */
092    @Override
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    @Override
311    public void clear() {
312        // no action required.
313    }
314
315    /**
316     * Tests this instance for equality with an arbitrary object.
317     *
318     * @param obj  the object (<code>null</code> permitted).
319     *
320     * @return A boolean.
321     */
322    @Override
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}