1. /*
  2. * @(#)BlockView.java 1.25 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.util.Enumeration;
  12. import java.awt.*;
  13. import javax.swing.SizeRequirements;
  14. import javax.swing.border.*;
  15. import javax.swing.event.DocumentEvent;
  16. import javax.swing.text.*;
  17. /**
  18. * A view implementation to display a block (as a box)
  19. * with CSS specifications.
  20. *
  21. * @author Timothy Prinzing
  22. * @version 1.25 02/02/00
  23. */
  24. public class BlockView extends BoxView {
  25. /**
  26. * Creates a new view that represents an
  27. * html box. This can be used for a number
  28. * of elements.
  29. *
  30. * @param elem the element to create a view for
  31. * @param axis either View.X_AXIS or View.Y_AXIS
  32. */
  33. public BlockView(Element elem, int axis) {
  34. super(elem, axis);
  35. }
  36. /**
  37. * Establishes the parent view for this view. This is
  38. * guaranteed to be called before any other methods if the
  39. * parent view is functioning properly.
  40. * <p>
  41. * This is implemented
  42. * to forward to the superclass as well as call the
  43. * <a href="#setPropertiesFromAttributes">setPropertiesFromAttributes</a>
  44. * method to set the paragraph properties from the css
  45. * attributes. The call is made at this time to ensure
  46. * the ability to resolve upward through the parents
  47. * view attributes.
  48. *
  49. * @param parent the new parent, or null if the view is
  50. * being removed from a parent it was previously added
  51. * to
  52. */
  53. public void setParent(View parent) {
  54. super.setParent(parent);
  55. setPropertiesFromAttributes();
  56. }
  57. /**
  58. * Calculate the requirements of the block along the major
  59. * axis (i.e. the axis along with it tiles). This is implemented
  60. * to provide the superclass behavior and then adjust it if the
  61. * CSS width or height attribute is specified and applicable to
  62. * the axis.
  63. */
  64. protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
  65. if (r == null) {
  66. r = new SizeRequirements();
  67. }
  68. if (! spanSetFromAttributes(axis, r)) {
  69. r = super.calculateMajorAxisRequirements(axis, r);
  70. }
  71. return r;
  72. }
  73. /**
  74. * Calculate the requirements of the block along the minor
  75. * axis (i.e. the axis orthoginal to the axis along with it tiles).
  76. * This is implemented
  77. * to provide the superclass behavior and then adjust it if the
  78. * CSS width or height attribute is specified and applicable to
  79. * the axis.
  80. */
  81. protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
  82. if (r == null) {
  83. r = new SizeRequirements();
  84. }
  85. if (! spanSetFromAttributes(axis, r)) {
  86. /*
  87. * The requirements were not directly specified by attributes, so
  88. * compute the aggregate of the requirements of the children. The
  89. * children that have a percentage value specified will be treated
  90. * as completely stretchable since that child is not limited in any
  91. * way.
  92. */
  93. /*
  94. int min = 0;
  95. long pref = 0;
  96. int max = 0;
  97. int n = getViewCount();
  98. for (int i = 0; i < n; i++) {
  99. View v = getView(i);
  100. min = Math.max((int) v.getMinimumSpan(axis), min);
  101. pref = Math.max((int) v.getPreferredSpan(axis), pref);
  102. if (
  103. max = Math.max((int) v.getMaximumSpan(axis), max);
  104. }
  105. r.preferred = (int) pref;
  106. r.minimum = min;
  107. r.maximum = max;
  108. */
  109. r = super.calculateMinorAxisRequirements(axis, r);
  110. }
  111. /*
  112. * Set the alignment based upon the CSS properties if it is
  113. * specified. For X_AXIS this would be text-align, for
  114. * Y_AXIS this would be vertical-align.
  115. */
  116. if (axis == X_AXIS) {
  117. Object o = getAttributes().getAttribute(CSS.Attribute.TEXT_ALIGN);
  118. if (o != null) {
  119. String align = o.toString();
  120. if (align.equals("center")) {
  121. r.alignment = 0.5f;
  122. } else if (align.equals("right")) {
  123. r.alignment = 1.0f;
  124. } else {
  125. r.alignment = 0.0f;
  126. }
  127. }
  128. }
  129. // Y_AXIS TBD
  130. return r;
  131. }
  132. boolean isPercentage(int axis, AttributeSet a) {
  133. if (axis == X_AXIS) {
  134. if (cssWidth != null) {
  135. return cssWidth.isPercentage();
  136. }
  137. } else {
  138. if (cssHeight != null) {
  139. return cssHeight.isPercentage();
  140. }
  141. }
  142. return false;
  143. }
  144. /**
  145. * Adjust the given requirements to the CSS width or height if
  146. * it is specified along the applicable axis. Return true if the
  147. * size is exactly specified, false if the span is not specified
  148. * in an attribute or the size specified is a percentage.
  149. */
  150. boolean spanSetFromAttributes(int axis, SizeRequirements r) {
  151. if (axis == X_AXIS) {
  152. if ((cssWidth != null) && (! cssWidth.isPercentage())) {
  153. r.minimum = r.preferred = r.maximum = (int) cssWidth.getValue();
  154. return true;
  155. }
  156. } else {
  157. if ((cssHeight != null) && (! cssHeight.isPercentage())) {
  158. r.minimum = r.preferred = r.maximum = (int) cssHeight.getValue();
  159. return true;
  160. }
  161. }
  162. return false;
  163. }
  164. /**
  165. * Perform layout for the minor axis of the box (i.e. the
  166. * axis orthoginal to the axis that it represents). The results
  167. * of the layout should be placed in the given arrays which represent
  168. * the allocations to the children along the minor axis.
  169. *
  170. * @param targetSpan the total span given to the view, which
  171. * whould be used to layout the children.
  172. * @param axis the axis being layed out.
  173. * @param offsets the offsets from the origin of the view for
  174. * each of the child views. This is a return value and is
  175. * filled in by the implementation of this method.
  176. * @param spans the span of each child view. This is a return
  177. * value and is filled in by the implementation of this method.
  178. * @returns the offset and span for each child view in the
  179. * offsets and spans parameters.
  180. */
  181. protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  182. int n = getViewCount();
  183. Object key = (axis == X_AXIS) ? CSS.Attribute.WIDTH : CSS.Attribute.HEIGHT;
  184. for (int i = 0; i < n; i++) {
  185. View v = getView(i);
  186. int min = (int) v.getMinimumSpan(axis);
  187. int max = (int) v.getMaximumSpan(axis);
  188. // check for percentage span
  189. AttributeSet a = v.getAttributes();
  190. CSS.LengthValue lv = (CSS.LengthValue) a.getAttribute(key);
  191. if ((lv != null) && lv.isPercentage()) {
  192. // bound the span to the percentage specified
  193. min = (int) lv.getValue(targetSpan);
  194. max = min;
  195. }
  196. // assign the offset and span for the child
  197. if (max < targetSpan) {
  198. // can't make the child this wide, align it
  199. float align = v.getAlignment(axis);
  200. offsets[i] = (int) ((targetSpan - max) * align);
  201. spans[i] = max;
  202. } else {
  203. // make it the target width, or as small as it can get.
  204. offsets[i] = 0;
  205. spans[i] = Math.max(min, targetSpan);
  206. }
  207. }
  208. }
  209. /**
  210. * Renders using the given rendering surface and area on that
  211. * surface. This is implemented to delegate to the css box
  212. * painter to paint the border and background prior to the
  213. * interior.
  214. *
  215. * @param g the rendering surface to use
  216. * @param allocation the allocated region to render into
  217. * @see View#paint
  218. */
  219. public void paint(Graphics g, Shape allocation) {
  220. Rectangle a = (Rectangle) allocation;
  221. painter.paint(g, a.x, a.y, a.width, a.height, this);
  222. super.paint(g, a);
  223. }
  224. /**
  225. * Fetches the attributes to use when rendering. This is
  226. * implemented to multiplex the attributes specified in the
  227. * model with a StyleSheet.
  228. */
  229. public AttributeSet getAttributes() {
  230. if (attr == null) {
  231. StyleSheet sheet = getStyleSheet();
  232. attr = sheet.getViewAttributes(this);
  233. }
  234. return attr;
  235. }
  236. /**
  237. * Gets the resize weight.
  238. *
  239. * @param axis may be either X_AXIS or Y_AXIS
  240. * @return the weight
  241. * @exception IllegalArgumentException for an invalid axis
  242. */
  243. public int getResizeWeight(int axis) {
  244. switch (axis) {
  245. case View.X_AXIS:
  246. return 1;
  247. case View.Y_AXIS:
  248. return 0;
  249. default:
  250. throw new IllegalArgumentException("Invalid axis: " + axis);
  251. }
  252. }
  253. /**
  254. * Gets the alignment.
  255. *
  256. * @param axis may be either X_AXIS or Y_AXIS
  257. * @return the alignment
  258. */
  259. public float getAlignment(int axis) {
  260. switch (axis) {
  261. case View.X_AXIS:
  262. return 0;
  263. case View.Y_AXIS:
  264. if (getViewCount() == 0) {
  265. return 0;
  266. }
  267. float span = getPreferredSpan(View.Y_AXIS);
  268. View v = getView(0);
  269. float above = v.getPreferredSpan(View.Y_AXIS);
  270. float a = (((int)span) != 0) ? (above * v.getAlignment(View.Y_AXIS)) / span: 0;
  271. return a;
  272. default:
  273. throw new IllegalArgumentException("Invalid axis: " + axis);
  274. }
  275. }
  276. public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  277. super.changedUpdate(changes, a, f);
  278. int pos = changes.getOffset();
  279. if (pos <= getStartOffset() && (pos + changes.getLength()) >=
  280. getEndOffset()) {
  281. setPropertiesFromAttributes();
  282. }
  283. }
  284. /**
  285. * Update any cached values that come from attributes.
  286. */
  287. protected void setPropertiesFromAttributes() {
  288. // update attributes
  289. StyleSheet sheet = getStyleSheet();
  290. attr = sheet.getViewAttributes(this);
  291. // Reset the painter
  292. painter = sheet.getBoxPainter(attr);
  293. if (attr != null) {
  294. setInsets((short) painter.getInset(TOP, this),
  295. (short) painter.getInset(LEFT, this),
  296. (short) painter.getInset(BOTTOM, this),
  297. (short) painter.getInset(RIGHT, this));
  298. }
  299. // Get the width/height
  300. cssWidth = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.WIDTH);
  301. cssHeight = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.HEIGHT);
  302. }
  303. protected StyleSheet getStyleSheet() {
  304. HTMLDocument doc = (HTMLDocument) getDocument();
  305. return doc.getStyleSheet();
  306. }
  307. private AttributeSet attr;
  308. private StyleSheet.BoxPainter painter;
  309. private CSS.LengthValue cssWidth;
  310. private CSS.LengthValue cssHeight;
  311. }