TextLine.java 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. * TextLine.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: TextLine.java,v 1.13 2007/11/02 17:50:35 taqua Exp $
  36. *
  37. * Changes
  38. * -------
  39. * 07-Nov-2003 : Version 1 (DG);
  40. * 22-Dec-2003 : Added workaround for Java bug 4245442 (DG);
  41. * 29-Jan-2004 : Added new constructor (DG);
  42. * 22-Mar-2004 : Added equals() method and implemented Serializable (DG);
  43. * 01-Apr-2004 : Changed java.awt.geom.Dimension2D to org.jfree.ui.Size2D
  44. * because of JDK bug 4976448 which persists on JDK 1.3.1 (DG);
  45. * 03-Sep-2004 : Added a method to remove a fragment (DG);
  46. * 08-Jul-2005 : Fixed bug in calculateBaselineOffset() (DG);
  47. * 01-Sep-2013 : Updated draw() method to take into account the textAnchor (DG);
  48. *
  49. */
  50. package org.jfree.text;
  51. import java.awt.Font;
  52. import java.awt.Graphics2D;
  53. import java.awt.Paint;
  54. import java.io.Serializable;
  55. import java.util.Iterator;
  56. import java.util.List;
  57. import org.jfree.ui.Size2D;
  58. import org.jfree.ui.TextAnchor;
  59. /**
  60. * A sequence of {@link TextFragment} objects that together form a line of
  61. * text. A sequence of text lines is managed by the {@link TextBlock} class.
  62. *
  63. * @author David Gilbert
  64. */
  65. public class TextLine implements Serializable {
  66. /** For serialization. */
  67. private static final long serialVersionUID = 7100085690160465444L;
  68. /** Storage for the text fragments that make up the line. */
  69. private List fragments;
  70. /**
  71. * Creates a new empty line.
  72. */
  73. public TextLine() {
  74. this.fragments = new java.util.ArrayList();
  75. }
  76. /**
  77. * Creates a new text line using the default font.
  78. *
  79. * @param text the text (<code>null</code> not permitted).
  80. */
  81. public TextLine(final String text) {
  82. this(text, TextFragment.DEFAULT_FONT);
  83. }
  84. /**
  85. * Creates a new text line.
  86. *
  87. * @param text the text (<code>null</code> not permitted).
  88. * @param font the text font (<code>null</code> not permitted).
  89. */
  90. public TextLine(final String text, final Font font) {
  91. this.fragments = new java.util.ArrayList();
  92. final TextFragment fragment = new TextFragment(text, font);
  93. this.fragments.add(fragment);
  94. }
  95. /**
  96. * Creates a new text line.
  97. *
  98. * @param text the text (<code>null</code> not permitted).
  99. * @param font the text font (<code>null</code> not permitted).
  100. * @param paint the text color (<code>null</code> not permitted).
  101. */
  102. public TextLine(final String text, final Font font, final Paint paint) {
  103. if (text == null) {
  104. throw new IllegalArgumentException("Null 'text' argument.");
  105. }
  106. if (font == null) {
  107. throw new IllegalArgumentException("Null 'font' argument.");
  108. }
  109. if (paint == null) {
  110. throw new IllegalArgumentException("Null 'paint' argument.");
  111. }
  112. this.fragments = new java.util.ArrayList();
  113. final TextFragment fragment = new TextFragment(text, font, paint);
  114. this.fragments.add(fragment);
  115. }
  116. /**
  117. * Adds a text fragment to the text line.
  118. *
  119. * @param fragment the text fragment (<code>null</code> not permitted).
  120. */
  121. public void addFragment(final TextFragment fragment) {
  122. this.fragments.add(fragment);
  123. }
  124. /**
  125. * Removes a fragment from the line.
  126. *
  127. * @param fragment the fragment to remove.
  128. */
  129. public void removeFragment(final TextFragment fragment) {
  130. this.fragments.remove(fragment);
  131. }
  132. /**
  133. * Draws the text line.
  134. *
  135. * @param g2 the graphics device.
  136. * @param anchorX the x-coordinate for the anchor point.
  137. * @param anchorY the y-coordinate for the anchor point.
  138. * @param anchor the point on the text line that is aligned to the anchor
  139. * point.
  140. * @param rotateX the x-coordinate for the rotation point.
  141. * @param rotateY the y-coordinate for the rotation point.
  142. * @param angle the rotation angle (in radians).
  143. */
  144. public void draw(Graphics2D g2, float anchorX, float anchorY,
  145. TextAnchor anchor, float rotateX, float rotateY, double angle) {
  146. Size2D dim = calculateDimensions(g2);
  147. float xAdj = 0.0f;
  148. if (anchor.isHorizontalCenter()) {
  149. xAdj = (float) -dim.getWidth() / 2.0f;
  150. }
  151. else if (anchor.isRight()) {
  152. xAdj = (float) -dim.getWidth();
  153. }
  154. float x = anchorX + xAdj;
  155. final float yOffset = calculateBaselineOffset(g2, anchor);
  156. final Iterator iterator = this.fragments.iterator();
  157. while (iterator.hasNext()) {
  158. final TextFragment fragment = (TextFragment) iterator.next();
  159. final Size2D d = fragment.calculateDimensions(g2);
  160. fragment.draw(g2, x, anchorY + yOffset, TextAnchor.BASELINE_LEFT,
  161. rotateX, rotateY, angle);
  162. x = x + (float) d.getWidth();
  163. }
  164. }
  165. /**
  166. * Calculates the width and height of the text line.
  167. *
  168. * @param g2 the graphics device.
  169. *
  170. * @return The width and height.
  171. */
  172. public Size2D calculateDimensions(final Graphics2D g2) {
  173. double width = 0.0;
  174. double height = 0.0;
  175. final Iterator iterator = this.fragments.iterator();
  176. while (iterator.hasNext()) {
  177. final TextFragment fragment = (TextFragment) iterator.next();
  178. final Size2D dimension = fragment.calculateDimensions(g2);
  179. width = width + dimension.getWidth();
  180. height = Math.max(height, dimension.getHeight());
  181. }
  182. return new Size2D(width, height);
  183. }
  184. /**
  185. * Returns the first text fragment in the line.
  186. *
  187. * @return The first text fragment in the line.
  188. */
  189. public TextFragment getFirstTextFragment() {
  190. TextFragment result = null;
  191. if (this.fragments.size() > 0) {
  192. result = (TextFragment) this.fragments.get(0);
  193. }
  194. return result;
  195. }
  196. /**
  197. * Returns the last text fragment in the line.
  198. *
  199. * @return The last text fragment in the line.
  200. */
  201. public TextFragment getLastTextFragment() {
  202. TextFragment result = null;
  203. if (this.fragments.size() > 0) {
  204. result = (TextFragment) this.fragments.get(this.fragments.size()
  205. - 1);
  206. }
  207. return result;
  208. }
  209. /**
  210. * Calculate the offsets required to translate from the specified anchor
  211. * position to the left baseline position.
  212. *
  213. * @param g2 the graphics device.
  214. * @param anchor the anchor position.
  215. *
  216. * @return The offsets.
  217. */
  218. private float calculateBaselineOffset(final Graphics2D g2,
  219. final TextAnchor anchor) {
  220. float result = 0.0f;
  221. Iterator iterator = this.fragments.iterator();
  222. while (iterator.hasNext()) {
  223. TextFragment fragment = (TextFragment) iterator.next();
  224. result = Math.max(result,
  225. fragment.calculateBaselineOffset(g2, anchor));
  226. }
  227. return result;
  228. }
  229. /**
  230. * Tests this object for equality with an arbitrary object.
  231. *
  232. * @param obj the object to test against (<code>null</code> permitted).
  233. *
  234. * @return A boolean.
  235. */
  236. public boolean equals(final Object obj) {
  237. if (obj == null) {
  238. return false;
  239. }
  240. if (obj == this) {
  241. return true;
  242. }
  243. if (obj instanceof TextLine) {
  244. final TextLine line = (TextLine) obj;
  245. return this.fragments.equals(line.fragments);
  246. }
  247. return false;
  248. }
  249. /**
  250. * Returns a hash code for this object.
  251. *
  252. * @return A hash code.
  253. */
  254. public int hashCode() {
  255. return (this.fragments != null ? this.fragments.hashCode() : 0);
  256. }
  257. }