001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2014, 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 * [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 * ImageTitle.java 029 * --------------- 030 * (C) Copyright 2000-2014, 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 059package org.jfree.chart.title; 060 061import java.awt.Graphics2D; 062import java.awt.Image; 063import java.awt.geom.Rectangle2D; 064 065import org.jfree.chart.block.RectangleConstraint; 066import org.jfree.chart.event.TitleChangeEvent; 067import org.jfree.ui.HorizontalAlignment; 068import org.jfree.ui.RectangleEdge; 069import org.jfree.ui.RectangleInsets; 070import org.jfree.ui.Size2D; 071import org.jfree.ui.VerticalAlignment; 072import 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 */ 089public 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} 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} 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} 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}). 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} 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} not permitted). 180 * 181 * @return The block size (in Java2D units, never {@code null}). 182 */ 183 @Override 184 public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { 185 Size2D s = new Size2D(this.image.getWidth(null), 186 this.image.getHeight(null)); 187 return new Size2D(calculateTotalWidth(s.getWidth()), 188 calculateTotalHeight(s.getHeight())); 189 } 190 191 /** 192 * Draws the title on a Java 2D graphics device (such as the screen or a 193 * printer). 194 * 195 * @param g2 the graphics device. 196 * @param area the area allocated for the title. 197 */ 198 @Override 199 public void draw(Graphics2D g2, Rectangle2D area) { 200 RectangleEdge position = getPosition(); 201 if (position == RectangleEdge.TOP || position == RectangleEdge.BOTTOM) { 202 drawHorizontal(g2, area); 203 } 204 else if (position == RectangleEdge.LEFT 205 || position == RectangleEdge.RIGHT) { 206 drawVertical(g2, area); 207 } 208 else { 209 throw new RuntimeException("Invalid title position."); 210 } 211 } 212 213 /** 214 * Draws the title on a Java 2D graphics device (such as the screen or a 215 * printer). 216 * 217 * @param g2 the graphics device. 218 * @param chartArea the area within which the title (and plot) should be 219 * drawn. 220 * 221 * @return The size of the area used by the title. 222 */ 223 protected Size2D drawHorizontal(Graphics2D g2, Rectangle2D chartArea) { 224 double startY; 225 double topSpace; 226 double bottomSpace; 227 double leftSpace; 228 double rightSpace; 229 230 double w = getWidth(); 231 double h = getHeight(); 232 RectangleInsets padding = getPadding(); 233 topSpace = padding.calculateTopOutset(h); 234 bottomSpace = padding.calculateBottomOutset(h); 235 leftSpace = padding.calculateLeftOutset(w); 236 rightSpace = padding.calculateRightOutset(w); 237 238 if (getPosition() == RectangleEdge.TOP) { 239 startY = chartArea.getY() + topSpace; 240 } 241 else { 242 startY = chartArea.getY() + chartArea.getHeight() - bottomSpace - h; 243 } 244 245 // what is our alignment? 246 HorizontalAlignment horizontalAlignment = getHorizontalAlignment(); 247 double startX = 0.0; 248 if (horizontalAlignment == HorizontalAlignment.CENTER) { 249 startX = chartArea.getX() + leftSpace + chartArea.getWidth() / 2.0 250 - w / 2.0; 251 } 252 else if (horizontalAlignment == HorizontalAlignment.LEFT) { 253 startX = chartArea.getX() + leftSpace; 254 } 255 else if (horizontalAlignment == HorizontalAlignment.RIGHT) { 256 startX = chartArea.getX() + chartArea.getWidth() - rightSpace - w; 257 } 258 g2.drawImage(this.image, (int) startX, (int) startY, (int) w, (int) h, 259 null); 260 261 return new Size2D(chartArea.getWidth() + leftSpace + rightSpace, 262 h + topSpace + bottomSpace); 263 264 } 265 266 /** 267 * Draws the title on a Java 2D graphics device (such as the screen or a 268 * printer). 269 * 270 * @param g2 the graphics device. 271 * @param chartArea the area within which the title (and plot) should be 272 * drawn. 273 * 274 * @return The size of the area used by the title. 275 */ 276 protected Size2D drawVertical(Graphics2D g2, Rectangle2D chartArea) { 277 278 double startX; 279 double topSpace = 0.0; 280 double bottomSpace = 0.0; 281 double leftSpace = 0.0; 282 double rightSpace = 0.0; 283 284 double w = getWidth(); 285 double h = getHeight(); 286 287 RectangleInsets padding = getPadding(); 288 if (padding != null) { 289 topSpace = padding.calculateTopOutset(h); 290 bottomSpace = padding.calculateBottomOutset(h); 291 leftSpace = padding.calculateLeftOutset(w); 292 rightSpace = padding.calculateRightOutset(w); 293 } 294 295 if (getPosition() == RectangleEdge.LEFT) { 296 startX = chartArea.getX() + leftSpace; 297 } 298 else { 299 startX = chartArea.getMaxX() - rightSpace - w; 300 } 301 302 // what is our alignment? 303 VerticalAlignment alignment = getVerticalAlignment(); 304 double startY = 0.0; 305 if (alignment == VerticalAlignment.CENTER) { 306 startY = chartArea.getMinY() + topSpace 307 + chartArea.getHeight() / 2.0 - h / 2.0; 308 } 309 else if (alignment == VerticalAlignment.TOP) { 310 startY = chartArea.getMinY() + topSpace; 311 } 312 else if (alignment == VerticalAlignment.BOTTOM) { 313 startY = chartArea.getMaxY() - bottomSpace - h; 314 } 315 316 g2.drawImage(this.image, (int) startX, (int) startY, (int) w, (int) h, 317 null); 318 319 return new Size2D(chartArea.getWidth() + leftSpace + rightSpace, 320 h + topSpace + bottomSpace); 321 322 } 323 324 /** 325 * Draws the block within the specified area. 326 * 327 * @param g2 the graphics device. 328 * @param area the area. 329 * @param params ignored ({@code null} permitted). 330 * 331 * @return Always {@code null}. 332 */ 333 @Override 334 public Object draw(Graphics2D g2, Rectangle2D area, Object params) { 335 draw(g2, area); 336 return null; 337 } 338 339 /** 340 * Tests this {@code ImageTitle} for equality with an arbitrary 341 * object. Returns {@code true} if: 342 * <ul> 343 * <li>{@code obj} is an instance of {@code ImageTitle}; 344 * <li>{@code obj} references the same image as this 345 * {@code ImageTitle}; 346 * <li>{@code super.equals(obj)} returns {@code true}; 347 * </ul> 348 * 349 * @param obj the object ({@code null} permitted). 350 * 351 * @return A boolean. 352 */ 353 @Override 354 public boolean equals(Object obj) { 355 if (obj == this) { 356 return true; 357 } 358 if (!(obj instanceof ImageTitle)) { 359 return false; 360 } 361 ImageTitle that = (ImageTitle) obj; 362 if (!ObjectUtilities.equal(this.image, that.image)) { 363 return false; 364 } 365 return super.equals(obj); 366 } 367 368}