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-2007, 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, 2007, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * Changes:
  36:  * --------
  37:  * 08-Feb-2005 : Version 1 (DG);
  38:  * 
  39:  */
  40: 
  41: package org.jfree.chart.block;
  42: 
  43: import java.awt.Graphics2D;
  44: import java.awt.geom.Rectangle2D;
  45: import java.io.Serializable;
  46: import java.util.Iterator;
  47: import java.util.List;
  48: 
  49: import org.jfree.ui.Size2D;
  50: 
  51: /**
  52:  * Arranges blocks in a grid within their container.
  53:  */
  54: public class GridArrangement implements Arrangement, Serializable {
  55:     
  56:     /** For serialization. */
  57:     private static final long serialVersionUID = -2563758090144655938L;
  58:     
  59:     /** The rows. */
  60:     private int rows;
  61:     
  62:     /** The columns. */
  63:     private int columns;
  64:     
  65:     /**
  66:      * Creates a new grid arrangement.
  67:      * 
  68:      * @param rows  the row count.
  69:      * @param columns  the column count.
  70:      */
  71:     public GridArrangement(int rows, int columns) {
  72:         this.rows = rows;
  73:         this.columns = columns;
  74:     }
  75:     
  76:     /**
  77:      * Adds a block and a key which can be used to determine the position of 
  78:      * the block in the arrangement.  This method is called by the container 
  79:      * (you don't need to call this method directly) and gives the arrangement
  80:      * an opportunity to record the details if they are required.
  81:      * 
  82:      * @param block  the block.
  83:      * @param key  the key (<code>null</code> permitted).
  84:      */
  85:     public void add(Block block, Object key) {
  86:         // can safely ignore   
  87:     }
  88:     
  89:     /**
  90:      * Arranges the blocks within the specified container, subject to the given
  91:      * constraint.
  92:      * 
  93:      * @param container  the container.
  94:      * @param constraint  the constraint.
  95:      * @param g2  the graphics device.
  96:      * 
  97:      * @return The size following the arrangement.
  98:      */
  99:     public Size2D arrange(BlockContainer container, Graphics2D g2,
 100:                           RectangleConstraint constraint) {
 101:         LengthConstraintType w = constraint.getWidthConstraintType();
 102:         LengthConstraintType h = constraint.getHeightConstraintType();
 103:         if (w == LengthConstraintType.NONE) {
 104:             if (h == LengthConstraintType.NONE) {
 105:                 return arrangeNN(container, g2);  
 106:             }
 107:             else if (h == LengthConstraintType.FIXED) {
 108:                 
 109:                 throw new RuntimeException("Not yet implemented.");  
 110:             }
 111:             else if (h == LengthConstraintType.RANGE) {
 112:                 // find optimum height, then map to range
 113:                 throw new RuntimeException("Not yet implemented.");  
 114:             }
 115:         }
 116:         else if (w == LengthConstraintType.FIXED) {
 117:             if (h == LengthConstraintType.NONE) {
 118:                 // find optimum height
 119:                 return arrangeFN(container, g2, constraint);  
 120:             }
 121:             else if (h == LengthConstraintType.FIXED) {
 122:                 return arrangeFF(container, g2, constraint);
 123:             }
 124:             else if (h == LengthConstraintType.RANGE) {
 125:                 // find optimum height and map to range
 126:                 return arrangeFR(container, g2, constraint);  
 127:             }
 128:         }
 129:         else if (w == LengthConstraintType.RANGE) {
 130:             // find optimum width and map to range
 131:             if (h == LengthConstraintType.NONE) {
 132:                 // find optimum height
 133:                 throw new RuntimeException("Not yet implemented.");  
 134:             }
 135:             else if (h == LengthConstraintType.FIXED) {
 136:                 // fixed width
 137:                 throw new RuntimeException("Not yet implemented.");  
 138:             }
 139:             else if (h == LengthConstraintType.RANGE) {
 140:                 throw new RuntimeException("Not yet implemented.");  
 141:             }
 142:         }
 143:         return new Size2D();  // TODO: complete this
 144:     }
 145:     
 146:     /**
 147:      * Arranges the container with no constraint on the width or height.
 148:      * 
 149:      * @param container  the container.
 150:      * @param g2  the graphics device.
 151:      * 
 152:      * @return The size.
 153:      */
 154:     protected Size2D arrangeNN(BlockContainer container, Graphics2D g2) {
 155:         double maxW = 0.0;
 156:         double maxH = 0.0;
 157:         List blocks = container.getBlocks();
 158:         Iterator iterator = blocks.iterator();
 159:         while (iterator.hasNext()) {
 160:             Block b = (Block) iterator.next();
 161:             Size2D s = b.arrange(g2, RectangleConstraint.NONE);
 162:             maxW = Math.max(maxW, s.width);
 163:             maxH = Math.max(maxH, s.height);
 164:         }
 165:         double width = this.columns * maxW;
 166:         double height = this.rows * maxH;
 167:         RectangleConstraint c = new RectangleConstraint(width, height);
 168:         return arrangeFF(container, g2, c);
 169:     }
 170:     
 171:     /**
 172:      * Arranges the container with a fixed overall width and height.
 173:      * 
 174:      * @param container  the container.
 175:      * @param g2  the graphics device.
 176:      * @param constraint  the constraint.
 177:      * 
 178:      * @return The size following the arrangement.
 179:      */
 180:     protected Size2D arrangeFF(BlockContainer container, Graphics2D g2,
 181:                                RectangleConstraint constraint) {
 182:         double width = constraint.getWidth() /  this.columns;
 183:         double height = constraint.getHeight() / this.rows;
 184:         List blocks = container.getBlocks();
 185:         for (int c = 0; c < this.columns; c++) {
 186:             for (int r = 0; r < this.rows; r++) {
 187:                 int index = r * this.columns + c;
 188:                 if (index == blocks.size()) {
 189:                     break;   
 190:                 }
 191:                 Block b = (Block) blocks.get(index);
 192:                 b.setBounds(new Rectangle2D.Double(
 193:                     c * width, r * height, width, height
 194:                 ));
 195:             }
 196:         }
 197:         return new Size2D(this.columns * width, this.rows * height);
 198:     }
 199: 
 200:     /**
 201:      * Arrange with a fixed width and a height within a given range.
 202:      * 
 203:      * @param container  the container.
 204:      * @param constraint  the constraint.
 205:      * @param g2  the graphics device.
 206:      * 
 207:      * @return The size of the arrangement.
 208:      */
 209:     protected Size2D arrangeFR(BlockContainer container, Graphics2D g2,
 210:                                RectangleConstraint constraint) {
 211:         
 212:         RectangleConstraint c1 = constraint.toUnconstrainedHeight();
 213:         Size2D size1 = arrange(container, g2, c1);
 214: 
 215:         if (constraint.getHeightRange().contains(size1.getHeight())) {
 216:             return size1;   
 217:         }
 218:         else {
 219:             double h = constraint.getHeightRange().constrain(size1.getHeight());
 220:             RectangleConstraint c2 = constraint.toFixedHeight(h);
 221:             return arrange(container, g2, c2);
 222:         }
 223:     }
 224: 
 225:     /**
 226:      * Arrange with a fixed width and a height within a given range.
 227:      * 
 228:      * @param container  the container.
 229:      * @param g2  the graphics device.
 230:      * @param constraint  the constraint.
 231:      * 
 232:      * @return The size of the arrangement.
 233:      */
 234:     protected Size2D arrangeFN(BlockContainer container, Graphics2D g2,
 235:                                RectangleConstraint constraint) {
 236:         
 237:         double width = constraint.getWidth() /  this.columns;
 238:         RectangleConstraint constraint2 = constraint.toFixedWidth(width);
 239:         List blocks = container.getBlocks();
 240:         double maxH = 0.0;
 241:         for (int r = 0; r < this.rows; r++) {
 242:             for (int c = 0; c < this.columns; c++) {
 243:                 int index = r * this.columns + c;
 244:                 if (index == blocks.size()) {
 245:                     break;   
 246:                 }
 247:                 Block b = (Block) blocks.get(index);
 248:                 Size2D s = b.arrange(g2, constraint2);
 249:                 maxH = Math.max(maxH, s.getHeight());
 250:             }
 251:         }
 252:         RectangleConstraint constraint3 = constraint.toFixedHeight(
 253:             maxH * this.rows
 254:         );
 255:         return arrange(container, g2, constraint3);
 256:     }
 257: 
 258:     /**
 259:      * Clears any cached layout information retained by the arrangement.
 260:      */
 261:     public void clear() {
 262:         // nothing to clear   
 263:     }
 264:     
 265:     /**
 266:      * Compares this layout manager for equality with an arbitrary object.
 267:      * 
 268:      * @param obj  the object.
 269:      * 
 270:      * @return A boolean.
 271:      */
 272:     public boolean equals(Object obj) {
 273:         if (obj == this) {
 274:             return true;
 275:         }
 276:         if (!(obj instanceof GridArrangement)) {
 277:             return false;   
 278:         }
 279:         GridArrangement that = (GridArrangement) obj;
 280:         if (this.columns != that.columns) {
 281:             return false;   
 282:         }
 283:         if (this.rows != that.rows) {
 284:             return false;   
 285:         }
 286:         return true;
 287:     }
 288: 
 289: }