001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2021, 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 * LabelBlock.java 029 * --------------- 030 * (C) Copyright 2004-2021, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Pierre-Marie Le Biot; 034 * 035 */ 036 037package org.jfree.chart.block; 038 039import java.awt.Color; 040import java.awt.Font; 041import java.awt.Graphics2D; 042import java.awt.Paint; 043import java.awt.Shape; 044import java.awt.geom.Point2D; 045import java.awt.geom.Rectangle2D; 046import java.io.IOException; 047import java.io.ObjectInputStream; 048import java.io.ObjectOutputStream; 049import java.util.Objects; 050 051import org.jfree.chart.entity.ChartEntity; 052import org.jfree.chart.entity.StandardEntityCollection; 053import org.jfree.chart.text.TextBlock; 054import org.jfree.chart.text.TextBlockAnchor; 055import org.jfree.chart.text.TextUtils; 056import org.jfree.chart.ui.RectangleAnchor; 057import org.jfree.chart.ui.Size2D; 058import org.jfree.chart.util.PaintUtils; 059import org.jfree.chart.util.Args; 060import org.jfree.chart.util.PublicCloneable; 061import org.jfree.chart.util.SerialUtils; 062 063/** 064 * A block containing a label. 065 */ 066public class LabelBlock extends AbstractBlock 067 implements Block, PublicCloneable { 068 069 /** For serialization. */ 070 static final long serialVersionUID = 249626098864178017L; 071 072 /** 073 * The text for the label - retained in case the label needs 074 * regenerating (for example, to change the font). 075 */ 076 private String text; 077 078 /** The label. */ 079 private TextBlock label; 080 081 /** The font. */ 082 private Font font; 083 084 /** The tool tip text (can be {@code null}). */ 085 private String toolTipText; 086 087 /** The URL text (can be {@code null}). */ 088 private String urlText; 089 090 /** The default color. */ 091 public static final Paint DEFAULT_PAINT = Color.BLACK; 092 093 /** The paint. */ 094 private transient Paint paint; 095 096 /** 097 * The content alignment point. 098 */ 099 private TextBlockAnchor contentAlignmentPoint; 100 101 /** 102 * The anchor point for the text. 103 */ 104 private RectangleAnchor textAnchor; 105 106 /** 107 * Creates a new label block. 108 * 109 * @param label the label ({@code null} not permitted). 110 */ 111 public LabelBlock(String label) { 112 this(label, new Font("SansSerif", Font.PLAIN, 10), DEFAULT_PAINT); 113 } 114 115 /** 116 * Creates a new label block. 117 * 118 * @param text the text for the label ({@code null} not permitted). 119 * @param font the font ({@code null} not permitted). 120 */ 121 public LabelBlock(String text, Font font) { 122 this(text, font, DEFAULT_PAINT); 123 } 124 125 /** 126 * Creates a new label block. 127 * 128 * @param text the text for the label ({@code null} not permitted). 129 * @param font the font ({@code null} not permitted). 130 * @param paint the paint ({@code null} not permitted). 131 */ 132 public LabelBlock(String text, Font font, Paint paint) { 133 this.text = text; 134 this.paint = paint; 135 this.label = TextUtils.createTextBlock(text, font, this.paint); 136 this.font = font; 137 this.toolTipText = null; 138 this.urlText = null; 139 this.contentAlignmentPoint = TextBlockAnchor.CENTER; 140 this.textAnchor = RectangleAnchor.CENTER; 141 } 142 143 /** 144 * Returns the font. 145 * 146 * @return The font (never {@code null}). 147 * 148 * @see #setFont(Font) 149 */ 150 public Font getFont() { 151 return this.font; 152 } 153 154 /** 155 * Sets the font and regenerates the label. 156 * 157 * @param font the font ({@code null} not permitted). 158 * 159 * @see #getFont() 160 */ 161 public void setFont(Font font) { 162 Args.nullNotPermitted(font, "font"); 163 this.font = font; 164 this.label = TextUtils.createTextBlock(this.text, font, this.paint); 165 } 166 167 /** 168 * Returns the paint. 169 * 170 * @return The paint (never {@code null}). 171 * 172 * @see #setPaint(Paint) 173 */ 174 public Paint getPaint() { 175 return this.paint; 176 } 177 178 /** 179 * Sets the paint and regenerates the label. 180 * 181 * @param paint the paint ({@code null} not permitted). 182 * 183 * @see #getPaint() 184 */ 185 public void setPaint(Paint paint) { 186 Args.nullNotPermitted(paint, "paint"); 187 this.paint = paint; 188 this.label = TextUtils.createTextBlock(this.text, this.font, 189 this.paint); 190 } 191 192 /** 193 * Returns the tool tip text. 194 * 195 * @return The tool tip text (possibly {@code null}). 196 * 197 * @see #setToolTipText(String) 198 */ 199 public String getToolTipText() { 200 return this.toolTipText; 201 } 202 203 /** 204 * Sets the tool tip text. 205 * 206 * @param text the text ({@code null} permitted). 207 * 208 * @see #getToolTipText() 209 */ 210 public void setToolTipText(String text) { 211 this.toolTipText = text; 212 } 213 214 /** 215 * Returns the URL text. 216 * 217 * @return The URL text (possibly {@code null}). 218 * 219 * @see #setURLText(String) 220 */ 221 public String getURLText() { 222 return this.urlText; 223 } 224 225 /** 226 * Sets the URL text. 227 * 228 * @param text the text ({@code null} permitted). 229 * 230 * @see #getURLText() 231 */ 232 public void setURLText(String text) { 233 this.urlText = text; 234 } 235 236 /** 237 * Returns the content alignment point. 238 * 239 * @return The content alignment point (never {@code null}). 240 */ 241 public TextBlockAnchor getContentAlignmentPoint() { 242 return this.contentAlignmentPoint; 243 } 244 245 /** 246 * Sets the content alignment point. 247 * 248 * @param anchor the anchor used to determine the alignment point (never 249 * {@code null}). 250 */ 251 public void setContentAlignmentPoint(TextBlockAnchor anchor) { 252 Args.nullNotPermitted(anchor, "anchor"); 253 this.contentAlignmentPoint = anchor; 254 } 255 256 /** 257 * Returns the text anchor (never {@code null}). 258 * 259 * @return The text anchor. 260 */ 261 public RectangleAnchor getTextAnchor() { 262 return this.textAnchor; 263 } 264 265 /** 266 * Sets the text anchor. 267 * 268 * @param anchor the anchor ({@code null} not permitted). 269 */ 270 public void setTextAnchor(RectangleAnchor anchor) { 271 this.textAnchor = anchor; 272 } 273 274 /** 275 * Arranges the contents of the block, within the given constraints, and 276 * returns the block size. 277 * 278 * @param g2 the graphics device. 279 * @param constraint the constraint ({@code null} not permitted). 280 * 281 * @return The block size (in Java2D units, never {@code null}). 282 */ 283 @Override 284 public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { 285 g2.setFont(this.font); 286 Size2D s = this.label.calculateDimensions(g2); 287 return new Size2D(calculateTotalWidth(s.getWidth()), 288 calculateTotalHeight(s.getHeight())); 289 } 290 291 /** 292 * Draws the block. 293 * 294 * @param g2 the graphics device. 295 * @param area the area. 296 */ 297 @Override 298 public void draw(Graphics2D g2, Rectangle2D area) { 299 draw(g2, area, null); 300 } 301 302 /** 303 * Draws the block within the specified area. 304 * 305 * @param g2 the graphics device. 306 * @param area the area. 307 * @param params ignored ({@code null} permitted). 308 * 309 * @return Always {@code null}. 310 */ 311 @Override 312 public Object draw(Graphics2D g2, Rectangle2D area, Object params) { 313 area = trimMargin(area); 314 drawBorder(g2, area); 315 area = trimBorder(area); 316 area = trimPadding(area); 317 318 // check if we need to collect chart entities from the container 319 EntityBlockParams ebp = null; 320 StandardEntityCollection sec = null; 321 Shape entityArea = null; 322 if (params instanceof EntityBlockParams) { 323 ebp = (EntityBlockParams) params; 324 if (ebp.getGenerateEntities()) { 325 sec = new StandardEntityCollection(); 326 entityArea = (Shape) area.clone(); 327 } 328 } 329 g2.setPaint(this.paint); 330 g2.setFont(this.font); 331 Point2D pt = this.textAnchor.getAnchorPoint(area); 332 this.label.draw(g2, (float) pt.getX(), (float) pt.getY(), 333 this.contentAlignmentPoint); 334 BlockResult result = null; 335 if (ebp != null && sec != null) { 336 if (this.toolTipText != null || this.urlText != null) { 337 ChartEntity entity = new ChartEntity(entityArea, 338 this.toolTipText, this.urlText); 339 sec.add(entity); 340 result = new BlockResult(); 341 result.setEntityCollection(sec); 342 } 343 } 344 return result; 345 } 346 347 /** 348 * Tests this {@code LabelBlock} for equality with an arbitrary object. 349 * 350 * @param obj the object ({@code null} permitted). 351 * 352 * @return A boolean. 353 */ 354 @Override 355 public boolean equals(Object obj) { 356 if (!(obj instanceof LabelBlock)) { 357 return false; 358 } 359 LabelBlock that = (LabelBlock) obj; 360 if (!this.text.equals(that.text)) { 361 return false; 362 } 363 if (!this.font.equals(that.font)) { 364 return false; 365 } 366 if (!PaintUtils.equal(this.paint, that.paint)) { 367 return false; 368 } 369 if (!Objects.equals(this.toolTipText, that.toolTipText)) { 370 return false; 371 } 372 if (!Objects.equals(this.urlText, that.urlText)) { 373 return false; 374 } 375 if (!this.contentAlignmentPoint.equals(that.contentAlignmentPoint)) { 376 return false; 377 } 378 if (!this.textAnchor.equals(that.textAnchor)) { 379 return false; 380 } 381 return super.equals(obj); 382 } 383 384 /** 385 * Returns a clone of this {@code LabelBlock} instance. 386 * 387 * @return A clone. 388 * 389 * @throws CloneNotSupportedException if there is a problem cloning. 390 */ 391 @Override 392 public Object clone() throws CloneNotSupportedException { 393 return super.clone(); 394 } 395 396 /** 397 * Provides serialization support. 398 * 399 * @param stream the output stream. 400 * 401 * @throws IOException if there is an I/O error. 402 */ 403 private void writeObject(ObjectOutputStream stream) throws IOException { 404 stream.defaultWriteObject(); 405 SerialUtils.writePaint(this.paint, stream); 406 } 407 408 /** 409 * Provides serialization support. 410 * 411 * @param stream the input stream. 412 * 413 * @throws IOException if there is an I/O error. 414 * @throws ClassNotFoundException if there is a classpath problem. 415 */ 416 private void readObject(ObjectInputStream stream) 417 throws IOException, ClassNotFoundException { 418 stream.defaultReadObject(); 419 this.paint = SerialUtils.readPaint(stream); 420 } 421 422}