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: * GridArrangement.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: GridArrangement.java,v 1.6.2.1 2005/10/25 20:39:38 mungady Exp $
036: *
037: * Changes:
038: * --------
039: * 08-Feb-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.Iterator;
049: import java.util.List;
050:
051: import org.jfree.ui.Size2D;
052:
053: /**
054: * Arranges blocks in a grid within their container.
055: */
056: public class GridArrangement implements Arrangement, Serializable {
057:
058: /** For serialization. */
059: private static final long serialVersionUID = -2563758090144655938L;
060:
061: /** The rows. */
062: private int rows;
063:
064: /** The columns. */
065: private int columns;
066:
067: /**
068: * Creates a new grid arrangement.
069: *
070: * @param rows the row count.
071: * @param columns the column count.
072: */
073: public GridArrangement(int rows, int columns) {
074: this .rows = rows;
075: this .columns = columns;
076: }
077:
078: /**
079: * Adds a block and a key which can be used to determine the position of
080: * the block in the arrangement. This method is called by the container
081: * (you don't need to call this method directly) and gives the arrangement
082: * an opportunity to record the details if they are required.
083: *
084: * @param block the block.
085: * @param key the key (<code>null</code> permitted).
086: */
087: public void add(Block block, Object key) {
088: // can safely ignore
089: }
090:
091: /**
092: * Arranges the blocks within the specified container, subject to the given
093: * constraint.
094: *
095: * @param container the container.
096: * @param constraint the constraint.
097: * @param g2 the graphics device.
098: *
099: * @return The size following the arrangement.
100: */
101: public Size2D arrange(BlockContainer container, Graphics2D g2,
102: RectangleConstraint constraint) {
103: LengthConstraintType w = constraint.getWidthConstraintType();
104: LengthConstraintType h = constraint.getHeightConstraintType();
105: if (w == LengthConstraintType.NONE) {
106: if (h == LengthConstraintType.NONE) {
107: return arrangeNN(container, g2);
108: } else if (h == LengthConstraintType.FIXED) {
109:
110: throw new RuntimeException("Not yet implemented.");
111: } else if (h == LengthConstraintType.RANGE) {
112: // find optimum height, then map to range
113: throw new RuntimeException("Not yet implemented.");
114: }
115: } else if (w == LengthConstraintType.FIXED) {
116: if (h == LengthConstraintType.NONE) {
117: // find optimum height
118: return arrangeFN(container, g2, constraint);
119: } else if (h == LengthConstraintType.FIXED) {
120: return arrangeFF(container, g2, constraint);
121: } else if (h == LengthConstraintType.RANGE) {
122: // find optimum height and map to range
123: return arrangeFR(container, g2, constraint);
124: }
125: } else if (w == LengthConstraintType.RANGE) {
126: // find optimum width and map to range
127: if (h == LengthConstraintType.NONE) {
128: // find optimum height
129: throw new RuntimeException("Not yet implemented.");
130: } else if (h == LengthConstraintType.FIXED) {
131: // fixed width
132: throw new RuntimeException("Not yet implemented.");
133: } else if (h == LengthConstraintType.RANGE) {
134: throw new RuntimeException("Not yet implemented.");
135: }
136: }
137: return new Size2D(); // TODO: complete this
138: }
139:
140: /**
141: * Arranges the container with no constraint on the width or height.
142: *
143: * @param container the container.
144: * @param g2 the graphics device.
145: *
146: * @return The size.
147: */
148: protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) {
149: double maxW = 0.0;
150: double maxH = 0.0;
151: List blocks = container.getBlocks();
152: Iterator iterator = blocks.iterator();
153: while (iterator.hasNext()) {
154: Block b = (Block) iterator.next();
155: Size2D s = b.arrange(g2, RectangleConstraint.NONE);
156: maxW = Math.max(maxW, s.width);
157: maxH = Math.max(maxH, s.height);
158: }
159: double width = this .columns * maxW;
160: double height = this .rows * maxH;
161: RectangleConstraint c = new RectangleConstraint(width, height);
162: return arrangeFF(container, g2, c);
163: }
164:
165: /**
166: * Arranges the container with a fixed overall width and height.
167: *
168: * @param container the container.
169: * @param g2 the graphics device.
170: * @param constraint the constraint.
171: *
172: * @return The size following the arrangement.
173: */
174: protected Size2D arrangeFF(BlockContainer container, Graphics2D g2,
175: RectangleConstraint constraint) {
176: double width = constraint.getWidth() / this .columns;
177: double height = constraint.getHeight() / this .rows;
178: List blocks = container.getBlocks();
179: for (int c = 0; c < this .columns; c++) {
180: for (int r = 0; r < this .rows; r++) {
181: int index = r * this .columns + c;
182: if (index == blocks.size()) {
183: break;
184: }
185: Block b = (Block) blocks.get(index);
186: b.setBounds(new Rectangle2D.Double(c * width, r
187: * height, width, height));
188: }
189: }
190: return new Size2D(this .columns * width, this .rows * height);
191: }
192:
193: /**
194: * Arrange with a fixed width and a height within a given range.
195: *
196: * @param container the container.
197: * @param constraint the constraint.
198: * @param g2 the graphics device.
199: *
200: * @return The size of the arrangement.
201: */
202: protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
203: RectangleConstraint constraint) {
204:
205: RectangleConstraint c1 = constraint.toUnconstrainedHeight();
206: Size2D size1 = arrange(container, g2, c1);
207:
208: if (constraint.getHeightRange().contains(size1.getHeight())) {
209: return size1;
210: } else {
211: double h = constraint.getHeightRange().constrain(
212: size1.getHeight());
213: RectangleConstraint c2 = constraint.toFixedHeight(h);
214: return arrange(container, g2, c2);
215: }
216: }
217:
218: /**
219: * Arrange with a fixed width and a height within a given range.
220: *
221: * @param container the container.
222: * @param g2 the graphics device.
223: * @param constraint the constraint.
224: *
225: * @return The size of the arrangement.
226: */
227: protected Size2D arrangeFN(BlockContainer container, Graphics2D g2,
228: RectangleConstraint constraint) {
229:
230: double width = constraint.getWidth() / this .columns;
231: RectangleConstraint constraint2 = constraint
232: .toFixedWidth(width);
233: List blocks = container.getBlocks();
234: double maxH = 0.0;
235: for (int r = 0; r < this .rows; r++) {
236: for (int c = 0; c < this .columns; c++) {
237: int index = r * this .columns + c;
238: if (index == blocks.size()) {
239: break;
240: }
241: Block b = (Block) blocks.get(index);
242: Size2D s = b.arrange(g2, constraint2);
243: maxH = Math.max(maxH, s.getHeight());
244: }
245: }
246: RectangleConstraint constraint3 = constraint.toFixedHeight(maxH
247: * this .rows);
248: return arrange(container, g2, constraint3);
249: }
250:
251: /**
252: * Clears any cached layout information retained by the arrangement.
253: */
254: public void clear() {
255: // nothing to clear
256: }
257:
258: /**
259: * Compares this layout manager for equality with an arbitrary object.
260: *
261: * @param obj the object.
262: *
263: * @return A boolean.
264: */
265: public boolean equals(Object obj) {
266: if (obj == this ) {
267: return true;
268: }
269: if (!(obj instanceof GridArrangement)) {
270: return false;
271: }
272: GridArrangement that = (GridArrangement) obj;
273: if (this .columns != that.columns) {
274: return false;
275: }
276: if (this .rows != that.rows) {
277: return false;
278: }
279: return true;
280: }
281:
282: }
|