1. /*
  2. * @(#)HRuleView.java 1.27 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.text.html;
  11. import java.awt.*;
  12. import javax.swing.BorderFactory;
  13. import javax.swing.border.*;
  14. import javax.swing.event.DocumentEvent;
  15. import javax.swing.text.*;
  16. import java.util.Enumeration;
  17. import java.lang.Integer;
  18. /**
  19. * A view implementation to display an html horizontal
  20. * rule.
  21. *
  22. * @author Timothy Prinzing
  23. * @author Sara Swanson
  24. * @version 1.27 02/02/00
  25. */
  26. class HRuleView extends View {
  27. /**
  28. * Creates a new view that represents an <hr> element.
  29. *
  30. * @param elem the element to create a view for
  31. */
  32. public HRuleView(Element elem) {
  33. super(elem);
  34. setPropertiesFromAttributes();
  35. }
  36. /**
  37. * Update any cached values that come from attributes.
  38. */
  39. protected void setPropertiesFromAttributes() {
  40. StyleSheet sheet = ((HTMLDocument)getDocument()).getStyleSheet();
  41. AttributeSet eAttr = getElement().getAttributes();
  42. attr = sheet.getViewAttributes(this);
  43. alignment = StyleConstants.ALIGN_LEFT;
  44. size = 0;
  45. noshade = null;
  46. widthValue = null;
  47. // Get the width/height
  48. Enumeration attributes = attr.getAttributeNames();
  49. while (attributes.hasMoreElements()) {
  50. Object key = attributes.nextElement();
  51. }
  52. if (attr != null) {
  53. alignment = StyleConstants.getAlignment(attr);
  54. noshade = (String)eAttr.getAttribute("noshade");
  55. Object value = attr.getAttribute("size");
  56. if (value != null && (value instanceof String))
  57. size = Integer.parseInt((String)value);
  58. value = attr.getAttribute(CSS.Attribute.WIDTH);
  59. if (value != null && (value instanceof CSS.LengthValue)) {
  60. widthValue = (CSS.LengthValue)value;
  61. }
  62. topMargin = getLength(CSS.Attribute.MARGIN_TOP, attr);
  63. bottomMargin = getLength(CSS.Attribute.MARGIN_BOTTOM, attr);
  64. leftMargin = getLength(CSS.Attribute.MARGIN_LEFT, attr);
  65. rightMargin = getLength(CSS.Attribute.MARGIN_RIGHT, attr);
  66. }
  67. else {
  68. topMargin = bottomMargin = leftMargin = rightMargin = 0;
  69. }
  70. if (bevel == null) {
  71. bevel = BorderFactory.createLoweredBevelBorder();
  72. }
  73. }
  74. // This will be removed and centralized at some point, need to unify this
  75. // and avoid private classes.
  76. private float getLength(CSS.Attribute key, AttributeSet a) {
  77. CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
  78. float len = (lv != null) ? lv.getValue() : 0;
  79. return len;
  80. }
  81. // --- View methods ---------------------------------------------
  82. /**
  83. * Paints the view.
  84. *
  85. * @param g the graphics context
  86. * @param a the allocation region for the view
  87. * @see View#paint
  88. */
  89. public void paint(Graphics g, Shape a) {
  90. Rectangle alloc = a.getBounds();
  91. int x = 0;
  92. int y = alloc.y + SPACE_ABOVE + (int)topMargin;
  93. int width = alloc.width - (int)(leftMargin + rightMargin);
  94. if (widthValue != null) {
  95. width = (int)widthValue.getValue((float)width);
  96. }
  97. int height = alloc.height - (SPACE_ABOVE + SPACE_BELOW +
  98. (int)topMargin + (int)bottomMargin);
  99. if (size > 0)
  100. height = size;
  101. // Align the rule horizontally.
  102. switch (alignment) {
  103. case StyleConstants.ALIGN_CENTER:
  104. x = alloc.x + (alloc.width / 2) - (width / 2);
  105. break;
  106. case StyleConstants.ALIGN_RIGHT:
  107. x = alloc.x + alloc.width - width - (int)rightMargin;
  108. break;
  109. case StyleConstants.ALIGN_LEFT:
  110. default:
  111. x = alloc.x + (int)leftMargin;
  112. break;
  113. }
  114. // Paint either a shaded rule or a solid line.
  115. if (noshade == HTML.NULL_ATTRIBUTE_VALUE)
  116. g.fillRect(x, y, width, height);
  117. else
  118. bevel.paintBorder(getContainer(), g, x, y, width, height);
  119. }
  120. /**
  121. * Calculates the desired shape of the rule... this is
  122. * basically the preferred size of the border.
  123. *
  124. * @param axis may be either X_AXIS or Y_AXIS
  125. * @return the desired span
  126. * @see View#getPreferredSpan
  127. */
  128. public float getPreferredSpan(int axis) {
  129. Insets i = bevel.getBorderInsets(getContainer());
  130. switch (axis) {
  131. case View.X_AXIS:
  132. return i.left + i.right;
  133. case View.Y_AXIS:
  134. if (size > 0) {
  135. return size + SPACE_ABOVE + SPACE_BELOW + topMargin +
  136. bottomMargin;
  137. } else {
  138. if (noshade == HTML.NULL_ATTRIBUTE_VALUE) {
  139. return 1 + SPACE_ABOVE + SPACE_BELOW + topMargin +
  140. bottomMargin;
  141. } else {
  142. return i.top + i.bottom + SPACE_ABOVE + SPACE_BELOW +
  143. topMargin + bottomMargin;
  144. }
  145. }
  146. default:
  147. throw new IllegalArgumentException("Invalid axis: " + axis);
  148. }
  149. }
  150. /**
  151. * Gets the resize weight for the axis.
  152. * The rule is: rigid vertically and flexible horizontally.
  153. *
  154. * @param axis may be either X_AXIS or Y_AXIS
  155. * @return the weight
  156. */
  157. public int getResizeWeight(int axis) {
  158. if (axis == View.X_AXIS) {
  159. return 1;
  160. } else if (axis == View.Y_AXIS) {
  161. return 0;
  162. } else {
  163. return 0;
  164. }
  165. }
  166. /**
  167. * Determines how attractive a break opportunity in
  168. * this view is. This is implemented to request a forced break.
  169. *
  170. * @param axis may be either View.X_AXIS or View.Y_AXIS
  171. * @param pos the potential location of the start of the
  172. * broken view (greater than or equal to zero).
  173. * This may be useful for calculating tab
  174. * positions.
  175. * @param len specifies the relative length from <em>pos</em>
  176. * where a potential break is desired. The value must be greater
  177. * than or equal to zero.
  178. * @return the weight, which should be a value between
  179. * ForcedBreakWeight and BadBreakWeight.
  180. */
  181. public int getBreakWeight(int axis, float pos, float len) {
  182. if (axis == X_AXIS) {
  183. return ForcedBreakWeight;
  184. }
  185. return BadBreakWeight;
  186. }
  187. public View breakView(int axis, int offset, float pos, float len) {
  188. return null;
  189. }
  190. /**
  191. * Provides a mapping from the document model coordinate space
  192. * to the coordinate space of the view mapped to it.
  193. *
  194. * @param pos the position to convert
  195. * @param a the allocated region to render into
  196. * @return the bounding box of the given position
  197. * @exception BadLocationException if the given position does not
  198. * represent a valid location in the associated document
  199. * @see View#modelToView
  200. */
  201. public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
  202. int p0 = getStartOffset();
  203. int p1 = getEndOffset();
  204. if ((pos >= p0) && (pos <= p1)) {
  205. Rectangle r = a.getBounds();
  206. if (pos == p1) {
  207. r.x += r.width;
  208. }
  209. r.width = 0;
  210. return r;
  211. }
  212. return null;
  213. }
  214. /**
  215. * Provides a mapping from the view coordinate space to the logical
  216. * coordinate space of the model.
  217. *
  218. * @param x the X coordinate
  219. * @param y the Y coordinate
  220. * @param a the allocated region to render into
  221. * @return the location within the model that best represents the
  222. * given point of view
  223. * @see View#viewToModel
  224. */
  225. public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
  226. Rectangle alloc = (Rectangle) a;
  227. if (x < alloc.x + (alloc.width / 2)) {
  228. bias[0] = Position.Bias.Forward;
  229. return getStartOffset();
  230. }
  231. bias[0] = Position.Bias.Backward;
  232. return getEndOffset();
  233. }
  234. /**
  235. * Fetches the attributes to use when rendering. This is
  236. * implemented to multiplex the attributes specified in the
  237. * model with a StyleSheet.
  238. */
  239. public AttributeSet getAttributes() {
  240. return attr;
  241. }
  242. public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  243. super.changedUpdate(changes, a, f);
  244. int pos = changes.getOffset();
  245. if (pos <= getStartOffset() && (pos + changes.getLength()) >=
  246. getEndOffset()) {
  247. setPropertiesFromAttributes();
  248. }
  249. }
  250. // --- variables ------------------------------------------------
  251. private Border bevel;
  252. private float topMargin;
  253. private float bottomMargin;
  254. private float leftMargin;
  255. private float rightMargin;
  256. private int alignment = StyleConstants.ALIGN_LEFT;
  257. private String noshade = null;
  258. private int size = 0;
  259. private CSS.LengthValue widthValue;
  260. private static final int SPACE_ABOVE = 3;
  261. private static final int SPACE_BELOW = 3;
  262. /** View Attributes. */
  263. private AttributeSet attr;
  264. }