1. /*
  2. * @(#)TableView.java 1.13 01/11/29
  3. *
  4. * Copyright 2002 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 javax.swing.SizeRequirements;
  10. import javax.swing.event.DocumentEvent;
  11. import javax.swing.text.Element;
  12. import javax.swing.text.AttributeSet;
  13. import javax.swing.text.StyleConstants;
  14. import javax.swing.text.View;
  15. import javax.swing.text.ViewFactory;
  16. /**
  17. * HTML table view. Extends the basic table support to
  18. * provide html tables. This is primarily code to interpret
  19. * the html table attributes and css attributes and feed them
  20. * into the table formatting and rendering operations.
  21. *
  22. * @author Timothy Prinzing
  23. * @version 1.13 11/29/01
  24. */
  25. class TableView extends javax.swing.text.TableView {
  26. /**
  27. * Constructs a TableView for the given element.
  28. *
  29. * @param elem the element that this view is responsible for
  30. */
  31. public TableView(Element elem) {
  32. super(elem);
  33. StyleSheet sheet = getStyleSheet();
  34. attr = sheet.getViewAttributes(this);
  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. StyleSheet sheet = getStyleSheet();
  56. painter = sheet.getBoxPainter(attr);
  57. setPropertiesFromAttributes();
  58. }
  59. /**
  60. * Creates a new table row.
  61. *
  62. * @param elem an element
  63. * @return the row
  64. */
  65. protected TableRow createTableRow(Element elem) {
  66. // PENDING(prinz) need to add support for some of the other
  67. // elements, but for now just ignore anything that is not
  68. // a TR.
  69. Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
  70. if (o == HTML.Tag.TR) {
  71. return new RowView(elem);
  72. }
  73. return null;
  74. }
  75. protected StyleSheet getStyleSheet() {
  76. HTMLDocument doc = (HTMLDocument) getDocument();
  77. return doc.getStyleSheet();
  78. }
  79. /**
  80. * Update any cached values that come from attributes.
  81. */
  82. protected void setPropertiesFromAttributes() {
  83. if (attr != null) {
  84. setInsets((short) painter.getInset(TOP, this),
  85. (short) painter.getInset(LEFT, this),
  86. (short) painter.getInset(BOTTOM, this),
  87. (short) painter.getInset(RIGHT, this));
  88. }
  89. }
  90. /**
  91. * Calculate the requirements of the table along the minor
  92. * axis (i.e. the major axis of the rows).
  93. * This is implemented
  94. * to provide the superclass behavior and then adjust it if the
  95. * CSS width or height attribute is specified and applicable to
  96. * the axis.
  97. */
  98. protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
  99. SizeRequirements rr = super.calculateMinorAxisRequirements(axis, r);
  100. adjustSizeForCSS(axis, rr);
  101. return rr;
  102. }
  103. void adjustSizeForCSS(int axis, SizeRequirements r) {
  104. if (axis == X_AXIS) {
  105. Object widthValue = attr.getAttribute(CSS.Attribute.WIDTH);
  106. if (widthValue != null) {
  107. int width = (int) ((CSS.LengthValue)widthValue).getValue();
  108. r.minimum = r.preferred = width;
  109. r.maximum = Math.max(r.maximum, width);
  110. }
  111. } else {
  112. Object heightValue = attr.getAttribute(CSS.Attribute.HEIGHT);
  113. if (heightValue != null) {
  114. int height = (int) ((CSS.LengthValue)heightValue).getValue();
  115. r.minimum = r.preferred = height;
  116. r.maximum = Math.max(r.maximum, height);
  117. }
  118. }
  119. }
  120. /**
  121. * Fetch the ViewFactory to use for the table. This
  122. * is implemented to create a Factory that routes
  123. * build requests for row and cell elements to the
  124. * createTableRow and createTableCell methods, otherwise
  125. * it delegates to the given factory.
  126. */
  127. /*protected*/ ViewFactory createViewFactory(ViewFactory f) {
  128. return new TableFactory(f);
  129. }
  130. // --- View methods --------------------------------
  131. /**
  132. * Determines the maximum span for this view along an
  133. * axis. For an html table this is basically the
  134. * preferred size, as the table is not willing to
  135. * stretch beyond that.
  136. *
  137. * @param axis may be either View.X_AXIS or View.Y_AXIS
  138. * @returns the maximum span the view can be rendered into.
  139. * @see View#getPreferredSpan
  140. */
  141. public float getMaximumSpan(int axis) {
  142. return getPreferredSpan(axis);
  143. }
  144. /**
  145. * Fetches the attributes to use when rendering. This is
  146. * implemented to multiplex the attributes specified in the
  147. * model with a StyleSheet.
  148. */
  149. public AttributeSet getAttributes() {
  150. return attr;
  151. }
  152. /**
  153. * Renders using the given rendering surface and area on that
  154. * surface. This is implemented to delegate to the css box
  155. * painter to paint the border and background prior to the
  156. * interior.
  157. *
  158. * @param g the rendering surface to use
  159. * @param allocation the allocated region to render into
  160. * @see View#paint
  161. */
  162. public void paint(Graphics g, Shape allocation) {
  163. Rectangle a = (Rectangle) allocation;
  164. painter.paint(g, a.x, a.y, a.width, a.height, this);
  165. super.paint(g, a);
  166. }
  167. /**
  168. * Fetches the ViewFactory implementation that is feeding
  169. * the view hierarchy.
  170. * This replaces the ViewFactory with an implementation that
  171. * calls through to the createTableRow and createTableCell
  172. * methods. If the element given to the factory isn't a
  173. * table row or cell, the request is delegated to the factory
  174. * produced by the superclass behavior.
  175. *
  176. * @return the factory, null if none
  177. */
  178. public ViewFactory getViewFactory() {
  179. return createViewFactory(super.getViewFactory());
  180. }
  181. /**
  182. * Gives notification that something was inserted into
  183. * the document in a location that this view is responsible for.
  184. * This replaces the ViewFactory with an implementation that
  185. * calls through to the createTableRow and createTableCell
  186. * methods. If the element given to the factory isn't a
  187. * table row or cell, the request is delegated to the factory
  188. * passed as an argument.
  189. *
  190. * @param e the change information from the associated document
  191. * @param a the current allocation of the view
  192. * @param f the factory to use to rebuild if the view has children
  193. * @see View#insertUpdate
  194. */
  195. public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  196. super.insertUpdate(e, a, createViewFactory(f));
  197. }
  198. /**
  199. * Gives notification that something was removed from the document
  200. * in a location that this view is responsible for.
  201. * This replaces the ViewFactory with an implementation that
  202. * calls through to the createTableRow and createTableCell
  203. * methods. If the element given to the factory isn't a
  204. * table row or cell, the request is delegated to the factory
  205. * passed as an argument.
  206. *
  207. * @param e the change information from the associated document
  208. * @param a the current allocation of the view
  209. * @param f the factory to use to rebuild if the view has children
  210. * @see View#removeUpdate
  211. */
  212. public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  213. super.removeUpdate(e, a, createViewFactory(f));
  214. }
  215. /**
  216. * Gives notification from the document that attributes were changed
  217. * in a location that this view is responsible for.
  218. * This replaces the ViewFactory with an implementation that
  219. * calls through to the createTableRow and createTableCell
  220. * methods. If the element given to the factory isn't a
  221. * table row or cell, the request is delegated to the factory
  222. * passed as an argument.
  223. *
  224. * @param e the change information from the associated document
  225. * @param a the current allocation of the view
  226. * @param f the factory to use to rebuild if the view has children
  227. * @see View#changedUpdate
  228. */
  229. public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  230. super.changedUpdate(e, a, createViewFactory(f));
  231. }
  232. // --- variables ---------------------------------------
  233. private AttributeSet attr;
  234. private StyleSheet.BoxPainter painter;
  235. /**
  236. * An html row. This adds storage of the appropriate
  237. * css attributes to the superclass behavior.
  238. */
  239. class RowView extends javax.swing.text.TableView.TableRow {
  240. /**
  241. * Constructs a RowView for the given element.
  242. *
  243. * @param elem the element that this view is responsible for
  244. */
  245. public RowView(Element elem) {
  246. super(elem);
  247. StyleSheet sheet = getStyleSheet();
  248. attr = sheet.getViewAttributes(this);
  249. }
  250. /**
  251. * Fetches the attributes to use when rendering. This is
  252. * implemented to multiplex the attributes specified in the
  253. * model with a StyleSheet.
  254. */
  255. public AttributeSet getAttributes() {
  256. return attr;
  257. }
  258. protected StyleSheet getStyleSheet() {
  259. HTMLDocument doc = (HTMLDocument) getDocument();
  260. return doc.getStyleSheet();
  261. }
  262. public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  263. super.changedUpdate(e, a, createViewFactory(f));
  264. int pos = e.getOffset();
  265. if (pos <= getStartOffset() && (pos + e.getLength()) >=
  266. getEndOffset()) {
  267. attr = getStyleSheet().getViewAttributes(this);
  268. }
  269. }
  270. private AttributeSet attr;
  271. }
  272. /**
  273. * Default view of an html table cell. This needs to be moved
  274. * somewhere else.
  275. */
  276. static class CellView extends BlockView {
  277. /**
  278. * Constructs a TableCell for the given element.
  279. *
  280. * @param elem the element that this view is responsible for
  281. */
  282. public CellView(Element elem) {
  283. super(elem, Y_AXIS);
  284. }
  285. /**
  286. * Perform layout for the major axis of the box (i.e. the
  287. * axis that it represents). The results of the layout should
  288. * be placed in the given arrays which represent the allocations
  289. * to the children along the major axis. This is called by the
  290. * superclass to recalculate the positions of the child views
  291. * when the layout might have changed.
  292. * <p>
  293. * This is implemented to delegate to the superclass to
  294. * tile the children. If the target span is greater than
  295. * was needed, the offsets are adjusted to align the children
  296. * (i.e. position according to the html valign attribute).
  297. *
  298. * @param targetSpan the total span given to the view, which
  299. * whould be used to layout the children.
  300. * @param axis the axis being layed out.
  301. * @param offsets the offsets from the origin of the view for
  302. * each of the child views. This is a return value and is
  303. * filled in by the implementation of this method.
  304. * @param spans the span of each child view. This is a return
  305. * value and is filled in by the implementation of this method.
  306. * @returns the offset and span for each child view in the
  307. * offsets and spans parameters.
  308. */
  309. protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  310. super.layoutMajorAxis(targetSpan, axis, offsets, spans);
  311. // calculate usage
  312. int used = 0;
  313. int n = spans.length;
  314. for (int i = 0; i < n; i++) {
  315. used += spans[i];
  316. }
  317. // calculate adjustments
  318. int adjust = 0;
  319. if (used < targetSpan) {
  320. // PENDING(prinz) change to use the css alignment.
  321. String valign = (String) getElement().getAttributes().getAttribute(
  322. HTML.Attribute.VALIGN);
  323. if (valign == null) {
  324. AttributeSet rowAttr = getElement().getParentElement().getAttributes();
  325. valign = (String) rowAttr.getAttribute(HTML.Attribute.VALIGN);
  326. }
  327. if ((valign == null) || valign.equals("middle")) {
  328. adjust = (targetSpan - used) / 2;
  329. } else if (valign.equals("bottom")) {
  330. adjust = targetSpan - used;
  331. }
  332. }
  333. // make adjustments.
  334. if (adjust != 0) {
  335. for (int i = 0; i < n; i++) {
  336. offsets[i] += adjust;
  337. }
  338. }
  339. }
  340. /**
  341. * Calculate the requirements needed along the major axis.
  342. * This is called by the superclass whenever the requirements
  343. * need to be updated (i.e. a preferenceChanged was messaged
  344. * through this view).
  345. * <p>
  346. * This is implemented to delegate to the superclass, but
  347. * indicate the maximum size is very large (i.e. the cell
  348. * is willing to expend to occupy the full height of the row).
  349. *
  350. * @param axis the axis being layed out.
  351. * @param r the requirements to fill in. If null, a new one
  352. * should be allocated.
  353. */
  354. protected SizeRequirements calculateMajorAxisRequirements(int axis,
  355. SizeRequirements r) {
  356. SizeRequirements req = super.calculateMajorAxisRequirements(axis, r);
  357. req.maximum = Integer.MAX_VALUE;
  358. return req;
  359. }
  360. }
  361. class TableFactory implements ViewFactory {
  362. TableFactory(ViewFactory f) {
  363. this.f = f;
  364. }
  365. public View create(Element elem) {
  366. Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
  367. if (o instanceof HTML.Tag) {
  368. HTML.Tag kind = (HTML.Tag) o;
  369. if (kind == HTML.Tag.TR) {
  370. return createTableRow(elem);
  371. /*
  372. } else if ((kind == HTML.Tag.TD) || (kind == HTML.Tag.TH)) {
  373. return createTableCell(elem);
  374. */
  375. } else if (kind == HTML.Tag.CAPTION) {
  376. return new ParagraphView(elem);
  377. }
  378. }
  379. // default is to delegate to the normal factory
  380. return f.create(elem);
  381. }
  382. ViewFactory f;
  383. }
  384. }