Source for org.jfree.chart.block.GridArrangement

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * --------------------
  28:  * GridArrangement.java
  29:  * --------------------
  30:  * (C) Copyright 2005, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * $Id: GridArrangement.java,v 1.6.2.1 2005/10/25 20:39:38 mungady Exp $
  36:  *
  37:  * Changes:
  38:  * --------
  39:  * 08-Feb-2005 : Version 1 (DG);
  40:  * 
  41:  */
  42: 
  43: package org.jfree.chart.block;
  44: 
  45: import java.awt.Graphics2D;
  46: import java.awt.geom.Rectangle2D;
  47: import java.io.Serializable;
  48: import java.util.Iterator;
  49: import java.util.List;
  50: 
  51: import org.jfree.ui.Size2D;
  52: 
  53: /**
  54:  * Arranges blocks in a grid within their container.
  55:  */
  56: public class GridArrangement implements Arrangement, Serializable {
  57:     
  58:     /** For serialization. */
  59:     private static final long serialVersionUID = -2563758090144655938L;
  60:     
  61:     /** The rows. */
  62:     private int rows;
  63:     
  64:     /** The columns. */
  65:     private int columns;
  66:     
  67:     /**
  68:      * Creates a new grid arrangement.
  69:      * 
  70:      * @param rows  the row count.
  71:      * @param columns  the column count.
  72:      */
  73:     public GridArrangement(int rows, int columns) {
  74:         this.rows = rows;
  75:         this.columns = columns;
  76:     }
  77:     
  78:     /**
  79:      * Adds a block and a key which can be used to determine the position of 
  80:      * the block in the arrangement.  This method is called by the container 
  81:      * (you don't need to call this method directly) and gives the arrangement
  82:      * an opportunity to record the details if they are required.
  83:      * 
  84:      * @param block  the block.
  85:      * @param key  the key (<code>null</code> permitted).
  86:      */
  87:     public void add(Block block, Object key) {
  88:         // can safely ignore   
  89:     }
  90:     
  91:     /**
  92:      * Arranges the blocks within the specified container, subject to the given
  93:      * constraint.
  94:      * 
  95:      * @param container  the container.
  96:      * @param constraint  the constraint.
  97:      * @param g2  the graphics device.
  98:      * 
  99:      * @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: }