TextFragment.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /* ========================================================================
  2. * JCommon : a free general purpose class library for the Java(tm) platform
  3. * ========================================================================
  4. *
  5. * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
  6. *
  7. * Project Info: http://www.jfree.org/jcommon/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. * TextFragment.java
  29. * -----------------
  30. * (C) Copyright 2003-2013, by Object Refinery Limited and Contributors.
  31. *
  32. * Original Author: David Gilbert (for Object Refinery Limited);
  33. * Contributor(s): -;
  34. *
  35. * $Id: TextFragment.java,v 1.13 2007/03/16 10:25:58 mungady Exp $
  36. *
  37. * Changes
  38. * -------
  39. * 07-Nov-2003 : Version 1 (DG);
  40. * 25-Nov-2003 : Fixed bug in the dimension calculation (DG);
  41. * 22-Dec-2003 : Added workaround for Java bug 4245442 (DG);
  42. * 29-Jan-2004 : Added paint attribute (DG);
  43. * 22-Mar-2004 : Added equals() method and implemented Serializable (DG);
  44. * 01-Apr-2004 : Changed java.awt.geom.Dimension2D to org.jfree.ui.Size2D
  45. * because of JDK bug 4976448 which persists on JDK 1.3.1 (DG);
  46. * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities
  47. * --> TextUtilities (DG);
  48. * 16-Mar-2007 : Fixed serialization for GradientPaint (DG);
  49. * 01-Sep-2013 : Take into account all TextAnchor offsets (DG);
  50. *
  51. */
  52. package org.jfree.text;
  53. import java.awt.Color;
  54. import java.awt.Font;
  55. import java.awt.FontMetrics;
  56. import java.awt.Graphics2D;
  57. import java.awt.Paint;
  58. import java.awt.font.LineMetrics;
  59. import java.awt.geom.Rectangle2D;
  60. import java.io.IOException;
  61. import java.io.ObjectInputStream;
  62. import java.io.ObjectOutputStream;
  63. import java.io.Serializable;
  64. import org.jfree.io.SerialUtilities;
  65. import org.jfree.ui.Size2D;
  66. import org.jfree.ui.TextAnchor;
  67. import org.jfree.util.Log;
  68. import org.jfree.util.LogContext;
  69. /**
  70. * A text item, with an associated font, that fits on a single line (see
  71. * {@link TextLine}). Instances of the class are immutable.
  72. */
  73. public class TextFragment implements Serializable {
  74. /** For serialization. */
  75. private static final long serialVersionUID = 4465945952903143262L;
  76. /** The default font. */
  77. public static final Font DEFAULT_FONT = new Font("Serif", Font.PLAIN, 12);
  78. /** The default text color. */
  79. public static final Paint DEFAULT_PAINT = Color.black;
  80. /** The text. */
  81. private String text;
  82. /** The font. */
  83. private Font font;
  84. /** The text color. */
  85. private transient Paint paint;
  86. /**
  87. * The baseline offset (can be used to simulate subscripts and
  88. * superscripts).
  89. */
  90. private float baselineOffset;
  91. /** Access to logging facilities. */
  92. protected static final LogContext logger = Log.createContext(
  93. TextFragment.class);
  94. /**
  95. * Creates a new text fragment.
  96. *
  97. * @param text the text (<code>null</code> not permitted).
  98. */
  99. public TextFragment(final String text) {
  100. this(text, DEFAULT_FONT, DEFAULT_PAINT);
  101. }
  102. /**
  103. * Creates a new text fragment.
  104. *
  105. * @param text the text (<code>null</code> not permitted).
  106. * @param font the font (<code>null</code> not permitted).
  107. */
  108. public TextFragment(final String text, final Font font) {
  109. this(text, font, DEFAULT_PAINT);
  110. }
  111. /**
  112. * Creates a new text fragment.
  113. *
  114. * @param text the text (<code>null</code> not permitted).
  115. * @param font the font (<code>null</code> not permitted).
  116. * @param paint the text color (<code>null</code> not permitted).
  117. */
  118. public TextFragment(final String text, final Font font, final Paint paint) {
  119. this(text, font, paint, 0.0f);
  120. }
  121. /**
  122. * Creates a new text fragment.
  123. *
  124. * @param text the text (<code>null</code> not permitted).
  125. * @param font the font (<code>null</code> not permitted).
  126. * @param paint the text color (<code>null</code> not permitted).
  127. * @param baselineOffset the baseline offset.
  128. */
  129. public TextFragment(final String text, final Font font, final Paint paint,
  130. final float baselineOffset) {
  131. if (text == null) {
  132. throw new IllegalArgumentException("Null 'text' argument.");
  133. }
  134. if (font == null) {
  135. throw new IllegalArgumentException("Null 'font' argument.");
  136. }
  137. if (paint == null) {
  138. throw new IllegalArgumentException("Null 'paint' argument.");
  139. }
  140. this.text = text;
  141. this.font = font;
  142. this.paint = paint;
  143. this.baselineOffset = baselineOffset;
  144. }
  145. /**
  146. * Returns the text.
  147. *
  148. * @return The text (possibly <code>null</code>).
  149. */
  150. public String getText() {
  151. return this.text;
  152. }
  153. /**
  154. * Returns the font.
  155. *
  156. * @return The font (never <code>null</code>).
  157. */
  158. public Font getFont() {
  159. return this.font;
  160. }
  161. /**
  162. * Returns the text paint.
  163. *
  164. * @return The text paint (never <code>null</code>).
  165. */
  166. public Paint getPaint() {
  167. return this.paint;
  168. }
  169. /**
  170. * Returns the baseline offset.
  171. *
  172. * @return The baseline offset.
  173. */
  174. public float getBaselineOffset() {
  175. return this.baselineOffset;
  176. }
  177. /**
  178. * Draws the text fragment.
  179. *
  180. * @param g2 the graphics device.
  181. * @param anchorX the x-coordinate of the anchor point.
  182. * @param anchorY the y-coordinate of the anchor point.
  183. * @param anchor the location of the text that is aligned to the anchor
  184. * point.
  185. * @param rotateX the x-coordinate of the rotation point.
  186. * @param rotateY the y-coordinate of the rotation point.
  187. * @param angle the angle.
  188. */
  189. public void draw(final Graphics2D g2, final float anchorX,
  190. final float anchorY, final TextAnchor anchor,
  191. final float rotateX, final float rotateY,
  192. final double angle) {
  193. g2.setFont(this.font);
  194. g2.setPaint(this.paint);
  195. TextUtilities.drawRotatedString(this.text, g2, anchorX, anchorY
  196. + this.baselineOffset, anchor, angle, rotateX, rotateY);
  197. }
  198. /**
  199. * Calculates the dimensions of the text fragment.
  200. *
  201. * @param g2 the graphics device.
  202. *
  203. * @return The width and height of the text.
  204. */
  205. public Size2D calculateDimensions(final Graphics2D g2) {
  206. final FontMetrics fm = g2.getFontMetrics(this.font);
  207. final Rectangle2D bounds = TextUtilities.getTextBounds(this.text, g2,
  208. fm);
  209. final Size2D result = new Size2D(bounds.getWidth(), bounds.getHeight());
  210. return result;
  211. }
  212. /**
  213. * Calculates the vertical offset between the baseline and the specified
  214. * text anchor.
  215. *
  216. * @param g2 the graphics device.
  217. * @param anchor the anchor.
  218. *
  219. * @return the offset.
  220. */
  221. public float calculateBaselineOffset(Graphics2D g2, TextAnchor anchor) {
  222. float result = 0.0f;
  223. final FontMetrics fm = g2.getFontMetrics(this.font);
  224. final LineMetrics lm = fm.getLineMetrics("ABCxyz", g2);
  225. if (anchor.isTop()) {
  226. result = lm.getAscent();
  227. }
  228. else if (anchor.isHalfAscent()) {
  229. result = lm.getAscent() / 2.0f;
  230. }
  231. else if (anchor.isVerticalCenter()) {
  232. result = lm.getAscent() / 2.0f - lm.getDescent() / 2.0f;
  233. }
  234. else if (anchor.isBottom()) {
  235. result = -lm.getDescent() - lm.getLeading();
  236. }
  237. return result;
  238. }
  239. /**
  240. * Tests this instance for equality with an arbitrary object.
  241. *
  242. * @param obj the object to test against (<code>null</code> permitted).
  243. *
  244. * @return A boolean.
  245. */
  246. public boolean equals(final Object obj) {
  247. if (obj == null) {
  248. return false;
  249. }
  250. if (obj == this) {
  251. return true;
  252. }
  253. if (obj instanceof TextFragment) {
  254. final TextFragment tf = (TextFragment) obj;
  255. if (!this.text.equals(tf.text)) {
  256. return false;
  257. }
  258. if (!this.font.equals(tf.font)) {
  259. return false;
  260. }
  261. if (!this.paint.equals(tf.paint)) {
  262. return false;
  263. }
  264. return true;
  265. }
  266. return false;
  267. }
  268. /**
  269. * Returns a hash code for this object.
  270. *
  271. * @return A hash code.
  272. */
  273. public int hashCode() {
  274. int result;
  275. result = (this.text != null ? this.text.hashCode() : 0);
  276. result = 29 * result + (this.font != null ? this.font.hashCode() : 0);
  277. result = 29 * result + (this.paint != null ? this.paint.hashCode() : 0);
  278. return result;
  279. }
  280. /**
  281. * Provides serialization support.
  282. *
  283. * @param stream the output stream.
  284. *
  285. * @throws IOException if there is an I/O error.
  286. */
  287. private void writeObject(final ObjectOutputStream stream)
  288. throws IOException {
  289. stream.defaultWriteObject();
  290. SerialUtilities.writePaint(this.paint, stream);
  291. }
  292. /**
  293. * Provides serialization support.
  294. *
  295. * @param stream the input stream.
  296. *
  297. * @throws IOException if there is an I/O error.
  298. * @throws ClassNotFoundException if there is a classpath problem.
  299. */
  300. private void readObject(final ObjectInputStream stream)
  301. throws IOException, ClassNotFoundException {
  302. stream.defaultReadObject();
  303. this.paint = SerialUtilities.readPaint(stream);
  304. }
  305. }