001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, 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 * ImageTitle.java 029 * --------------- 030 * (C) Copyright 2000-2008, by David Berry and Contributors; 031 * 032 * Original Author: David Berry; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * 035 * Changes (from 18-Sep-2001) 036 * -------------------------- 037 * 18-Sep-2001 : Added standard header (DG); 038 * 07-Nov-2001 : Separated the JCommon Class Library classes, JFreeChart now 039 * requires jcommon.jar (DG); 040 * 09-Jan-2002 : Updated Javadoc comments (DG); 041 * 07-Feb-2002 : Changed blank space around title from Insets --> Spacer, to 042 * allow for relative or absolute spacing (DG); 043 * 25-Jun-2002 : Updated import statements (DG); 044 * 23-Sep-2002 : Fixed errors reported by Checkstyle (DG); 045 * 26-Nov-2002 : Added method for drawing images at left or right (DG); 046 * 22-Sep-2003 : Added checks that the Image can never be null (TM). 047 * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0 048 * release (DG); 049 * 02-Feb-2005 : Changed padding mechanism for all titles (DG); 050 * 20-Apr-2005 : Added new draw() method (DG); 051 * ------------- JFREECHART 1.0.x --------------------------------------------- 052 * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG); 053 * 11-Apr-2008 : Added arrange() method override to account for margin, border 054 * and padding (DG); 055 * 21-Apr-2008 : Added equals() method override (DG); 056 * 057 */ 058 059 package org.jfree.chart.title; 060 061 import java.awt.Graphics2D; 062 import java.awt.Image; 063 import java.awt.geom.Rectangle2D; 064 065 import org.jfree.chart.block.RectangleConstraint; 066 import org.jfree.chart.event.TitleChangeEvent; 067 import org.jfree.ui.HorizontalAlignment; 068 import org.jfree.ui.RectangleEdge; 069 import org.jfree.ui.RectangleInsets; 070 import org.jfree.ui.Size2D; 071 import org.jfree.ui.VerticalAlignment; 072 import org.jfree.util.ObjectUtilities; 073 074 /** 075 * A chart title that displays an image. This is useful, for example, if you 076 * have an image of your corporate logo and want to use as a footnote or part 077 * of a title in a chart you create. 078 * <P> 079 * ImageTitle needs an image passed to it in the constructor. For ImageTitle 080 * to work, you must have already loaded this image from its source (disk or 081 * URL). It is recommended you use something like 082 * Toolkit.getDefaultToolkit().getImage() to get the image. Then, use 083 * MediaTracker or some other message to make sure the image is fully loaded 084 * from disk. 085 * <P> 086 * SPECIAL NOTE: this class fails to serialize, so if you are 087 * relying on your charts to be serializable, please avoid using this class. 088 */ 089 public class ImageTitle extends Title { 090 091 /** The title image. */ 092 private Image image; 093 094 /** 095 * Creates a new image title. 096 * 097 * @param image the image (<code>null</code> not permitted). 098 */ 099 public ImageTitle(Image image) { 100 this(image, image.getHeight(null), image.getWidth(null), 101 Title.DEFAULT_POSITION, Title.DEFAULT_HORIZONTAL_ALIGNMENT, 102 Title.DEFAULT_VERTICAL_ALIGNMENT, Title.DEFAULT_PADDING); 103 } 104 105 /** 106 * Creates a new image title. 107 * 108 * @param image the image (<code>null</code> not permitted). 109 * @param position the title position. 110 * @param horizontalAlignment the horizontal alignment. 111 * @param verticalAlignment the vertical alignment. 112 */ 113 public ImageTitle(Image image, RectangleEdge position, 114 HorizontalAlignment horizontalAlignment, 115 VerticalAlignment verticalAlignment) { 116 117 this(image, image.getHeight(null), image.getWidth(null), 118 position, horizontalAlignment, verticalAlignment, 119 Title.DEFAULT_PADDING); 120 } 121 122 /** 123 * Creates a new image title with the given image scaled to the given 124 * width and height in the given location. 125 * 126 * @param image the image (<code>null</code> not permitted). 127 * @param height the height used to draw the image. 128 * @param width the width used to draw the image. 129 * @param position the title position. 130 * @param horizontalAlignment the horizontal alignment. 131 * @param verticalAlignment the vertical alignment. 132 * @param padding the amount of space to leave around the outside of the 133 * title. 134 */ 135 public ImageTitle(Image image, int height, int width, 136 RectangleEdge position, 137 HorizontalAlignment horizontalAlignment, 138 VerticalAlignment verticalAlignment, 139 RectangleInsets padding) { 140 141 super(position, horizontalAlignment, verticalAlignment, padding); 142 if (image == null) { 143 throw new NullPointerException("Null 'image' argument."); 144 } 145 this.image = image; 146 setHeight(height); 147 setWidth(width); 148 149 } 150 151 /** 152 * Returns the image for the title. 153 * 154 * @return The image for the title (never <code>null</code>). 155 */ 156 public Image getImage() { 157 return this.image; 158 } 159 160 /** 161 * Sets the image for the title and notifies registered listeners that the 162 * title has been modified. 163 * 164 * @param image the new image (<code>null</code> not permitted). 165 */ 166 public void setImage(Image image) { 167 if (image == null) { 168 throw new NullPointerException("Null 'image' argument."); 169 } 170 this.image = image; 171 notifyListeners(new TitleChangeEvent(this)); 172 } 173 174 /** 175 * Arranges the contents of the block, within the given constraints, and 176 * returns the block size. 177 * 178 * @param g2 the graphics device. 179 * @param constraint the constraint (<code>null</code> not permitted). 180 * 181 * @return The block size (in Java2D units, never <code>null</code>). 182 */ 183 public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { 184 Size2D s = new Size2D(this.image.getWidth(null), 185 this.image.getHeight(null)); 186 return new Size2D(calculateTotalWidth(s.getWidth()), 187 calculateTotalHeight(s.getHeight())); 188 } 189 190 /** 191 * Draws the title on a Java 2D graphics device (such as the screen or a 192 * printer). 193 * 194 * @param g2 the graphics device. 195 * @param area the area allocated for the title. 196 */ 197 public void draw(Graphics2D g2, Rectangle2D area) { 198 RectangleEdge position = getPosition(); 199 if (position == RectangleEdge.TOP || position == RectangleEdge.BOTTOM) { 200 drawHorizontal(g2, area); 201 } 202 else if (position == RectangleEdge.LEFT 203 || position == RectangleEdge.RIGHT) { 204 drawVertical(g2, area); 205 } 206 else { 207 throw new RuntimeException("Invalid title position."); 208 } 209 } 210 211 /** 212 * Draws the title on a Java 2D graphics device (such as the screen or a 213 * printer). 214 * 215 * @param g2 the graphics device. 216 * @param chartArea the area within which the title (and plot) should be 217 * drawn. 218 * 219 * @return The size of the area used by the title. 220 */ 221 protected Size2D drawHorizontal(Graphics2D g2, Rectangle2D chartArea) { 222 223 double startY = 0.0; 224 double topSpace = 0.0; 225 double bottomSpace = 0.0; 226 double leftSpace = 0.0; 227 double rightSpace = 0.0; 228 229 double w = getWidth(); 230 double h = getHeight(); 231 RectangleInsets padding = getPadding(); 232 topSpace = padding.calculateTopOutset(h); 233 bottomSpace = padding.calculateBottomOutset(h); 234 leftSpace = padding.calculateLeftOutset(w); 235 rightSpace = padding.calculateRightOutset(w); 236 237 if (getPosition() == RectangleEdge.TOP) { 238 startY = chartArea.getY() + topSpace; 239 } 240 else { 241 startY = chartArea.getY() + chartArea.getHeight() - bottomSpace - h; 242 } 243 244 // what is our alignment? 245 HorizontalAlignment horizontalAlignment = getHorizontalAlignment(); 246 double startX = 0.0; 247 if (horizontalAlignment == HorizontalAlignment.CENTER) { 248 startX = chartArea.getX() + leftSpace + chartArea.getWidth() / 2.0 249 - w / 2.0; 250 } 251 else if (horizontalAlignment == HorizontalAlignment.LEFT) { 252 startX = chartArea.getX() + leftSpace; 253 } 254 else if (horizontalAlignment == HorizontalAlignment.RIGHT) { 255 startX = chartArea.getX() + chartArea.getWidth() - rightSpace - w; 256 } 257 g2.drawImage(this.image, (int) startX, (int) startY, (int) w, (int) h, 258 null); 259 260 return new Size2D(chartArea.getWidth() + leftSpace + rightSpace, 261 h + topSpace + bottomSpace); 262 263 } 264 265 /** 266 * Draws the title on a Java 2D graphics device (such as the screen or a 267 * printer). 268 * 269 * @param g2 the graphics device. 270 * @param chartArea the area within which the title (and plot) should be 271 * drawn. 272 * 273 * @return The size of the area used by the title. 274 */ 275 protected Size2D drawVertical(Graphics2D g2, Rectangle2D chartArea) { 276 277 double startX = 0.0; 278 double topSpace = 0.0; 279 double bottomSpace = 0.0; 280 double leftSpace = 0.0; 281 double rightSpace = 0.0; 282 283 double w = getWidth(); 284 double h = getHeight(); 285 286 RectangleInsets padding = getPadding(); 287 if (padding != null) { 288 topSpace = padding.calculateTopOutset(h); 289 bottomSpace = padding.calculateBottomOutset(h); 290 leftSpace = padding.calculateLeftOutset(w); 291 rightSpace = padding.calculateRightOutset(w); 292 } 293 294 if (getPosition() == RectangleEdge.LEFT) { 295 startX = chartArea.getX() + leftSpace; 296 } 297 else { 298 startX = chartArea.getMaxX() - rightSpace - w; 299 } 300 301 // what is our alignment? 302 VerticalAlignment alignment = getVerticalAlignment(); 303 double startY = 0.0; 304 if (alignment == VerticalAlignment.CENTER) { 305 startY = chartArea.getMinY() + topSpace 306 + chartArea.getHeight() / 2.0 - h / 2.0; 307 } 308 else if (alignment == VerticalAlignment.TOP) { 309 startY = chartArea.getMinY() + topSpace; 310 } 311 else if (alignment == VerticalAlignment.BOTTOM) { 312 startY = chartArea.getMaxY() - bottomSpace - h; 313 } 314 315 g2.drawImage(this.image, (int) startX, (int) startY, (int) w, (int) h, 316 null); 317 318 return new Size2D(chartArea.getWidth() + leftSpace + rightSpace, 319 h + topSpace + bottomSpace); 320 321 } 322 323 /** 324 * Draws the block within the specified area. 325 * 326 * @param g2 the graphics device. 327 * @param area the area. 328 * @param params ignored (<code>null</code> permitted). 329 * 330 * @return Always <code>null</code>. 331 */ 332 public Object draw(Graphics2D g2, Rectangle2D area, Object params) { 333 draw(g2, area); 334 return null; 335 } 336 337 /** 338 * Tests this <code>ImageTitle</code> for equality with an arbitrary 339 * object. Returns <code>true</code> if: 340 * <ul> 341 * <li><code>obj</code> is an instance of <code>ImageTitle</code>; 342 * <li><code>obj</code> references the same image as this 343 * <code>ImageTitle</code>; 344 * <li><code>super.equals(obj)<code> returns <code>true</code>; 345 * </ul> 346 * 347 * @param obj the object (<code>null</code> permitted). 348 * 349 * @return A boolean. 350 */ 351 public boolean equals(Object obj) { 352 if (obj == this) { 353 return true; 354 } 355 if (!(obj instanceof ImageTitle)) { 356 return false; 357 } 358 ImageTitle that = (ImageTitle) obj; 359 if (!ObjectUtilities.equal(this.image, that.image)) { 360 return false; 361 } 362 return super.equals(obj); 363 } 364 365 }