001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert 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 * BlockContainer.java 029 * ------------------- 030 * (C) Copyright 2004-present, by David Gilbert. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): Tracy Hiltbrand (equals/hashCode comply with EqualsVerifier); 034 * 035 */ 036 037package org.jfree.chart.block; 038 039import java.awt.Graphics2D; 040import java.awt.geom.Rectangle2D; 041import java.io.Serializable; 042import java.util.ArrayList; 043import java.util.Collections; 044import java.util.Iterator; 045import java.util.List; 046import java.util.Objects; 047 048import org.jfree.chart.entity.EntityCollection; 049import org.jfree.chart.entity.StandardEntityCollection; 050import org.jfree.chart.ui.Size2D; 051import org.jfree.chart.util.Args; 052import org.jfree.chart.util.PublicCloneable; 053 054/** 055 * A container for a collection of {@link Block} objects. The container uses 056 * an {@link Arrangement} object to handle the position of each block. 057 */ 058public class BlockContainer extends AbstractBlock 059 implements Block, Cloneable, PublicCloneable, Serializable { 060 061 /** For serialization. */ 062 private static final long serialVersionUID = 8199508075695195293L; 063 064 /** The blocks within the container. */ 065 private final List blocks; 066 067 /** The object responsible for laying out the blocks. */ 068 private Arrangement arrangement; 069 070 /** 071 * Creates a new instance with default settings. 072 */ 073 public BlockContainer() { 074 this(new BorderArrangement()); 075 } 076 077 /** 078 * Creates a new instance with the specified arrangement. 079 * 080 * @param arrangement the arrangement manager ({@code null} not 081 * permitted). 082 */ 083 public BlockContainer(Arrangement arrangement) { 084 Args.nullNotPermitted(arrangement, "arrangement"); 085 this.arrangement = arrangement; 086 this.blocks = new ArrayList(); 087 } 088 089 /** 090 * Returns the arrangement (layout) manager for the container. 091 * 092 * @return The arrangement manager (never {@code null}). 093 */ 094 public Arrangement getArrangement() { 095 return this.arrangement; 096 } 097 098 /** 099 * Sets the arrangement (layout) manager. 100 * 101 * @param arrangement the arrangement ({@code null} not permitted). 102 */ 103 public void setArrangement(Arrangement arrangement) { 104 Args.nullNotPermitted(arrangement, "arrangement"); 105 this.arrangement = arrangement; 106 } 107 108 /** 109 * Returns {@code true} if there are no blocks in the container, and 110 * {@code false} otherwise. 111 * 112 * @return A boolean. 113 */ 114 public boolean isEmpty() { 115 return this.blocks.isEmpty(); 116 } 117 118 /** 119 * Returns an unmodifiable list of the {@link Block} objects managed by 120 * this arrangement. 121 * 122 * @return A list of blocks. 123 */ 124 public List getBlocks() { 125 return Collections.unmodifiableList(this.blocks); 126 } 127 128 /** 129 * Adds a block to the container. 130 * 131 * @param block the block ({@code null} permitted). 132 */ 133 public void add(Block block) { 134 add(block, null); 135 } 136 137 /** 138 * Adds a block to the container. 139 * 140 * @param block the block ({@code null} permitted). 141 * @param key the key ({@code null} permitted). 142 */ 143 public void add(Block block, Object key) { 144 this.blocks.add(block); 145 this.arrangement.add(block, key); 146 } 147 148 /** 149 * Clears all the blocks from the container. 150 */ 151 public void clear() { 152 this.blocks.clear(); 153 this.arrangement.clear(); 154 } 155 156 /** 157 * Arranges the contents of the block, within the given constraints, and 158 * returns the block size. 159 * 160 * @param g2 the graphics device. 161 * @param constraint the constraint ({@code null} not permitted). 162 * 163 * @return The block size (in Java2D units, never {@code null}). 164 */ 165 @Override 166 public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { 167 return this.arrangement.arrange(this, g2, constraint); 168 } 169 170 /** 171 * Draws the container and all the blocks within it. 172 * 173 * @param g2 the graphics device. 174 * @param area the area. 175 */ 176 @Override 177 public void draw(Graphics2D g2, Rectangle2D area) { 178 draw(g2, area, null); 179 } 180 181 /** 182 * Draws the block within the specified area. 183 * 184 * @param g2 the graphics device. 185 * @param area the area. 186 * @param params passed on to blocks within the container 187 * ({@code null} permitted). 188 * 189 * @return An instance of {@link EntityBlockResult}, or {@code null}. 190 */ 191 @Override 192 public Object draw(Graphics2D g2, Rectangle2D area, Object params) { 193 // check if we need to collect chart entities from the container 194 EntityBlockParams ebp; 195 StandardEntityCollection sec = null; 196 if (params instanceof EntityBlockParams) { 197 ebp = (EntityBlockParams) params; 198 if (ebp.getGenerateEntities()) { 199 sec = new StandardEntityCollection(); 200 } 201 } 202 Rectangle2D contentArea = (Rectangle2D) area.clone(); 203 contentArea = trimMargin(contentArea); 204 drawBorder(g2, contentArea); 205 contentArea = trimBorder(contentArea); 206 contentArea = trimPadding(contentArea); 207 Iterator iterator = this.blocks.iterator(); 208 while (iterator.hasNext()) { 209 Block block = (Block) iterator.next(); 210 Rectangle2D bounds = block.getBounds(); 211 Rectangle2D drawArea = new Rectangle2D.Double(bounds.getX() 212 + area.getX(), bounds.getY() + area.getY(), 213 bounds.getWidth(), bounds.getHeight()); 214 Object r = block.draw(g2, drawArea, params); 215 if (sec != null) { 216 if (r instanceof EntityBlockResult) { 217 EntityBlockResult ebr = (EntityBlockResult) r; 218 EntityCollection ec = ebr.getEntityCollection(); 219 sec.addAll(ec); 220 } 221 } 222 } 223 BlockResult result = null; 224 if (sec != null) { 225 result = new BlockResult(); 226 result.setEntityCollection(sec); 227 } 228 return result; 229 } 230 231 /** 232 * Tests this container for equality with an arbitrary object. 233 * 234 * @param obj the object ({@code null} permitted). 235 * 236 * @return A boolean. 237 */ 238 @Override 239 public boolean equals(Object obj) { 240 if (obj == this) { 241 return true; 242 } 243 if (!(obj instanceof BlockContainer)) { 244 return false; 245 } 246 BlockContainer that = (BlockContainer) obj; 247 248 // fix the "equals not symmetric" problem 249 if (!that.canEqual(this)) { 250 return false; 251 } 252 // compare fields in this class 253 if (!Objects.equals(this.arrangement, that.arrangement)) { 254 return false; 255 } 256 if (!Objects.equals(this.blocks, that.blocks)) { 257 return false; 258 } 259 return super.equals(obj); 260 } 261 262 /** 263 * Ensures symmetry between super/subclass implementations of equals. For 264 * more detail, see http://jqno.nl/equalsverifier/manual/inheritance. 265 * 266 * @param other Object 267 * 268 * @return true ONLY if the parameter is THIS class type 269 */ 270 @Override 271 public boolean canEqual(Object other) { 272 // Solves Problem: equals not symmetric 273 return (other instanceof BlockContainer); 274 } 275 276 @Override 277 public int hashCode() { 278 int hash = super.hashCode(); // equals calls superclass function, so hashCode must also 279 hash = 79 * hash + Objects.hashCode(this.blocks); 280 hash = 79 * hash + Objects.hashCode(this.arrangement); 281 return hash; 282 } 283 284 /** 285 * Returns a clone of the container. 286 * 287 * @return A clone. 288 * 289 * @throws CloneNotSupportedException if there is a problem cloning. 290 */ 291 @Override 292 public Object clone() throws CloneNotSupportedException { 293 BlockContainer clone = (BlockContainer) super.clone(); 294 // TODO : complete this 295 return clone; 296 } 297 298}