1. /*
  2. * @(#)InlineView.java 1.25 04/03/05
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text.html;
  8. import java.awt.*;
  9. import java.text.BreakIterator;
  10. import javax.swing.event.DocumentEvent;
  11. import javax.swing.text.*;
  12. /**
  13. * Displays the <dfn>inline element</dfn> styles
  14. * based upon css attributes.
  15. *
  16. * @author Timothy Prinzing
  17. * @version 1.25 03/05/04
  18. */
  19. public class InlineView extends LabelView {
  20. /**
  21. * Constructs a new view wrapped on an element.
  22. *
  23. * @param elem the element
  24. */
  25. public InlineView(Element elem) {
  26. super(elem);
  27. StyleSheet sheet = getStyleSheet();
  28. attr = sheet.getViewAttributes(this);
  29. }
  30. /**
  31. * Gives notification that something was inserted into
  32. * the document in a location that this view is responsible for.
  33. * If either parameter is <code>null</code>, behavior of this method is
  34. * implementation dependent.
  35. *
  36. * @param e the change information from the associated document
  37. * @param a the current allocation of the view
  38. * @param f the factory to use to rebuild if the view has children
  39. * @since 1.5
  40. * @see View#insertUpdate
  41. */
  42. public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  43. super.insertUpdate(e, a, f);
  44. longestWordSpan = -1.0f;
  45. }
  46. /**
  47. * Gives notification that something was removed from the document
  48. * in a location that this view is responsible for.
  49. * If either parameter is <code>null</code>, behavior of this method is
  50. * implementation dependent.
  51. *
  52. * @param e the change information from the associated document
  53. * @param a the current allocation of the view
  54. * @param f the factory to use to rebuild if the view has children
  55. * @since 1.5
  56. * @see View#removeUpdate
  57. */
  58. public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  59. super.removeUpdate(e, a, f);
  60. longestWordSpan = -1.0f;
  61. }
  62. /**
  63. * Gives notification from the document that attributes were changed
  64. * in a location that this view is responsible for.
  65. *
  66. * @param e the change information from the associated document
  67. * @param a the current allocation of the view
  68. * @param f the factory to use to rebuild if the view has children
  69. * @see View#changedUpdate
  70. */
  71. public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  72. super.changedUpdate(e, a, f);
  73. StyleSheet sheet = getStyleSheet();
  74. attr = sheet.getViewAttributes(this);
  75. longestWordSpan = -1.0f;
  76. preferenceChanged(null, true, true);
  77. }
  78. /**
  79. * Fetches the attributes to use when rendering. This is
  80. * implemented to multiplex the attributes specified in the
  81. * model with a StyleSheet.
  82. */
  83. public AttributeSet getAttributes() {
  84. return attr;
  85. }
  86. /**
  87. * Determines how attractive a break opportunity in
  88. * this view is. This can be used for determining which
  89. * view is the most attractive to call <code>breakView</code>
  90. * on in the process of formatting. A view that represents
  91. * text that has whitespace in it might be more attractive
  92. * than a view that has no whitespace, for example. The
  93. * higher the weight, the more attractive the break. A
  94. * value equal to or lower than <code>BadBreakWeight</code>
  95. * should not be considered for a break. A value greater
  96. * than or equal to <code>ForcedBreakWeight</code> should
  97. * be broken.
  98. * <p>
  99. * This is implemented to provide the default behavior
  100. * of returning <code>BadBreakWeight</code> unless the length
  101. * is greater than the length of the view in which case the
  102. * entire view represents the fragment. Unless a view has
  103. * been written to support breaking behavior, it is not
  104. * attractive to try and break the view. An example of
  105. * a view that does support breaking is <code>LabelView</code>.
  106. * An example of a view that uses break weight is
  107. * <code>ParagraphView</code>.
  108. *
  109. * @param axis may be either View.X_AXIS or View.Y_AXIS
  110. * @param pos the potential location of the start of the
  111. * broken view >= 0. This may be useful for calculating tab
  112. * positions.
  113. * @param len specifies the relative length from <em>pos</em>
  114. * where a potential break is desired >= 0.
  115. * @return the weight, which should be a value between
  116. * ForcedBreakWeight and BadBreakWeight.
  117. * @see LabelView
  118. * @see ParagraphView
  119. * @see javax.swing.text.View#BadBreakWeight
  120. * @see javax.swing.text.View#GoodBreakWeight
  121. * @see javax.swing.text.View#ExcellentBreakWeight
  122. * @see javax.swing.text.View#ForcedBreakWeight
  123. */
  124. public int getBreakWeight(int axis, float pos, float len) {
  125. if (nowrap) {
  126. return BadBreakWeight;
  127. }
  128. return super.getBreakWeight(axis, pos, len);
  129. }
  130. /**
  131. * Tries to break this view on the given axis. Refer to
  132. * {@link javax.swing.text.View#breakView} for a complete
  133. * description of this method.
  134. * <p>Behavior of this method is unspecified in case <code>axis</code>
  135. * is neither <code>View.X_AXIS</code> nor <code>View.Y_AXIS</code>, and
  136. * in case <code>offset</code>, <code>pos</code>, or <code>len</code>
  137. * is null.
  138. *
  139. * @param axis may be either <code>View.X_AXIS</code> or
  140. * <code>View.Y_AXIS</code>
  141. * @param offset the location in the document model
  142. * that a broken fragment would occupy >= 0. This
  143. * would be the starting offset of the fragment
  144. * returned
  145. * @param pos the position along the axis that the
  146. * broken view would occupy >= 0. This may be useful for
  147. * things like tab calculations
  148. * @param len specifies the distance along the axis
  149. * where a potential break is desired >= 0
  150. * @return the fragment of the view that represents the
  151. * given span.
  152. * @since 1.5
  153. * @see javax.swing.text.View#breakView
  154. */
  155. public View breakView(int axis, int offset, float pos, float len) {
  156. InlineView view = (InlineView)super.breakView(axis, offset, pos, len);
  157. if (view != this) {
  158. view.longestWordSpan = -1;
  159. }
  160. return view;
  161. }
  162. /**
  163. * Fetch the span of the longest word in the view.
  164. */
  165. float getLongestWordSpan() {
  166. if (longestWordSpan < 0.0f) {
  167. longestWordSpan = calculateLongestWordSpan();
  168. }
  169. return longestWordSpan;
  170. }
  171. float calculateLongestWordSpan() {
  172. // find the longest word
  173. float span = 0;
  174. try {
  175. Document doc = getDocument();
  176. int p0 = getStartOffset();
  177. int p1 = getEndOffset();
  178. if (p1 > p0) {
  179. Segment segment = new Segment();
  180. doc.getText(p0, p1 - p0, segment);
  181. int word0 = p0;
  182. int word1 = p0;
  183. Container c = getContainer();
  184. BreakIterator words;
  185. if (c != null) {
  186. words = BreakIterator.getWordInstance(c.getLocale());
  187. } else {
  188. words = BreakIterator.getWordInstance();
  189. }
  190. words.setText(segment);
  191. int start = words.first();
  192. for (int end = words.next(); end != BreakIterator.DONE;
  193. start = end, end = words.next()) {
  194. // update longest word boundary
  195. if ((end - start) > (word1 - word0)) {
  196. word0 = start;
  197. word1 = end;
  198. }
  199. }
  200. // calculate the minimum
  201. if ((word1 - word0) > 0) {
  202. FontMetrics metrics = getFontMetrics();
  203. int offs = segment.offset + word0 - segment.getBeginIndex();
  204. span = metrics.charsWidth(segment.array, offs, word1 - word0);
  205. }
  206. }
  207. } catch (BadLocationException ble) {
  208. // If the text can't be retrieved, it can't influence the size.
  209. }
  210. return span;
  211. }
  212. /**
  213. * Set the cached properties from the attributes.
  214. */
  215. protected void setPropertiesFromAttributes() {
  216. super.setPropertiesFromAttributes();
  217. AttributeSet a = getAttributes();
  218. Object decor = a.getAttribute(CSS.Attribute.TEXT_DECORATION);
  219. boolean u = (decor != null) ?
  220. (decor.toString().indexOf("underline") >= 0) : false;
  221. setUnderline(u);
  222. boolean s = (decor != null) ?
  223. (decor.toString().indexOf("line-through") >= 0) : false;
  224. setStrikeThrough(s);
  225. Object vAlign = a.getAttribute(CSS.Attribute.VERTICAL_ALIGN);
  226. s = (vAlign != null) ? (vAlign.toString().indexOf("sup") >= 0) : false;
  227. setSuperscript(s);
  228. s = (vAlign != null) ? (vAlign.toString().indexOf("sub") >= 0) : false;
  229. setSubscript(s);
  230. Object whitespace = a.getAttribute(CSS.Attribute.WHITE_SPACE);
  231. if ((whitespace != null) && whitespace.equals("nowrap")) {
  232. nowrap = true;
  233. } else {
  234. nowrap = false;
  235. }
  236. HTMLDocument doc = (HTMLDocument)getDocument();
  237. // fetches background color from stylesheet if specified
  238. Color bg = doc.getBackground(a);
  239. if (bg != null) {
  240. setBackground(bg);
  241. }
  242. }
  243. protected StyleSheet getStyleSheet() {
  244. HTMLDocument doc = (HTMLDocument) getDocument();
  245. return doc.getStyleSheet();
  246. }
  247. private boolean nowrap;
  248. private AttributeSet attr;
  249. private float longestWordSpan = -1.0f;
  250. }