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 }
109 else if (h == LengthConstraintType.FIXED) {
110
111 throw new RuntimeException("Not yet implemented.");
112 }
113 else if (h == LengthConstraintType.RANGE) {
114 // find optimum height, then map to range
115 throw new RuntimeException("Not yet implemented.");
116 }
117 }
118 else if (w == LengthConstraintType.FIXED) {
119 if (h == LengthConstraintType.NONE) {
120 // find optimum height
121 return arrangeFN(container, g2, constraint);
122 }
123 else if (h == LengthConstraintType.FIXED) {
124 return arrangeFF(container, g2, constraint);
125 }
126 else if (h == LengthConstraintType.RANGE) {
127 // find optimum height and map to range
128 return arrangeFR(container, g2, constraint);
129 }
130 }
131 else if (w == LengthConstraintType.RANGE) {
132 // find optimum width and map to range
133 if (h == LengthConstraintType.NONE) {
134 // find optimum height
135 throw new RuntimeException("Not yet implemented.");
136 }
137 else if (h == LengthConstraintType.FIXED) {
138 // fixed width
139 throw new RuntimeException("Not yet implemented.");
140 }
141 else if (h == LengthConstraintType.RANGE) {
142 throw new RuntimeException("Not yet implemented.");
143 }
144 }
145 return new Size2D(); // TODO: complete this
146 }
147
148 /**
149 * Arranges the container with no constraint on the width or height.
150 *
151 * @param container the container.
152 * @param g2 the graphics device.
153 *
154 * @return The size.
155 */
156 protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) {
157 double maxW = 0.0;
158 double maxH = 0.0;
159 List blocks = container.getBlocks();
160 Iterator iterator = blocks.iterator();
161 while (iterator.hasNext()) {
162 Block b = (Block) iterator.next();
163 Size2D s = b.arrange(g2, RectangleConstraint.NONE);
164 maxW = Math.max(maxW, s.width);
165 maxH = Math.max(maxH, s.height);
166 }
167 double width = this.columns * maxW;
168 double height = this.rows * maxH;
169 RectangleConstraint c = new RectangleConstraint(width, height);
170 return arrangeFF(container, g2, c);
171 }
172
173 /**
174 * Arranges the container with a fixed overall width and height.
175 *
176 * @param container the container.
177 * @param g2 the graphics device.
178 * @param constraint the constraint.
179 *
180 * @return The size following the arrangement.
181 */
182 protected Size2D arrangeFF(BlockContainer container, Graphics2D g2,
183 RectangleConstraint constraint) {
184 double width = constraint.getWidth() / this.columns;
185 double height = constraint.getHeight() / this.rows;
186 List blocks = container.getBlocks();
187 for (int c = 0; c < this.columns; c++) {
188 for (int r = 0; r < this.rows; r++) {
189 int index = r * this.columns + c;
190 if (index == blocks.size()) {
191 break;
192 }
193 Block b = (Block) blocks.get(index);
194 b.setBounds(new Rectangle2D.Double(
195 c * width, r * height, width, height
196 ));
197 }
198 }
199 return new Size2D(this.columns * width, this.rows * height);
200 }
201
202 /**
203 * Arrange with a fixed width and a height within a given range.
204 *
205 * @param container the container.
206 * @param constraint the constraint.
207 * @param g2 the graphics device.
208 *
209 * @return The size of the arrangement.
210 */
211 protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
212 RectangleConstraint constraint) {
213
214 RectangleConstraint c1 = constraint.toUnconstrainedHeight();
215 Size2D size1 = arrange(container, g2, c1);
216
217 if (constraint.getHeightRange().contains(size1.getHeight())) {
218 return size1;
219 }
220 else {
221 double h = constraint.getHeightRange().constrain(size1.getHeight());
222 RectangleConstraint c2 = constraint.toFixedHeight(h);
223 return arrange(container, g2, c2);
224 }
225 }
226
227 /**
228 * Arrange with a fixed width and a height within a given range.
229 *
230 * @param container the container.
231 * @param g2 the graphics device.
232 * @param constraint the constraint.
233 *
234 * @return The size of the arrangement.
235 */
236 protected Size2D arrangeFN(BlockContainer container, Graphics2D g2,
237 RectangleConstraint constraint) {
238
239 double width = constraint.getWidth() / this.columns;
240 RectangleConstraint constraint2 = constraint.toFixedWidth(width);
241 List blocks = container.getBlocks();
242 double maxH = 0.0;
243 for (int r = 0; r < this.rows; r++) {
244 for (int c = 0; c < this.columns; c++) {
245 int index = r * this.columns + c;
246 if (index == blocks.size()) {
247 break;
248 }
249 Block b = (Block) blocks.get(index);
250 Size2D s = b.arrange(g2, constraint2);
251 maxH = Math.max(maxH, s.getHeight());
252 }
253 }
254 RectangleConstraint constraint3 = constraint.toFixedHeight(
255 maxH * this.rows
256 );
257 return arrange(container, g2, constraint3);
258 }
259
260 /**
261 * Clears any cached layout information retained by the arrangement.
262 */
263 public void clear() {
264 // nothing to clear
265 }
266
267 /**
268 * Compares this layout manager for equality with an arbitrary object.
269 *
270 * @param obj the object.
271 *
272 * @return A boolean.
273 */
274 public boolean equals(Object obj) {
275 if (obj == this) {
276 return true;
277 }
278 if (!(obj instanceof GridArrangement)) {
279 return false;
280 }
281 GridArrangement that = (GridArrangement) obj;
282 if (this.columns != that.columns) {
283 return false;
284 }
285 if (this.rows != that.rows) {
286 return false;
287 }
288 return true;
289 }
290
291 }