1. /*
  2. * @(#)FieldView.java 1.18 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;
  11. import java.awt.*;
  12. import javax.swing.*;
  13. import javax.swing.event.*;
  14. /**
  15. * Extends the multi-line plain text view to be suitable
  16. * for a single-line editor view. If the view is
  17. * allocated extra space, the field must adjust for it.
  18. * If the hosting component is a JTextField, this view
  19. * will manage the ranges of the associated BoundedRangeModel
  20. * and will adjust the horizontal allocation to match the
  21. * current visibility settings of the JTextField.
  22. *
  23. * @author Timothy Prinzing
  24. * @version 1.18 02/02/00
  25. * @see View
  26. */
  27. public class FieldView extends PlainView {
  28. /**
  29. * Constructs a new FieldView wrapped on an element.
  30. *
  31. * @param elem the element
  32. */
  33. public FieldView(Element elem) {
  34. super(elem);
  35. }
  36. /**
  37. * Fetches the font metrics associated with the component hosting
  38. * this view.
  39. *
  40. * @return the metrics
  41. */
  42. protected FontMetrics getFontMetrics() {
  43. Component c = getContainer();
  44. return c.getFontMetrics(c.getFont());
  45. }
  46. /**
  47. * Adjusts the allocation given to the view
  48. * to be a suitable allocation for a text field.
  49. * If the view has been allocated more than the
  50. * preferred span vertically, the allocation is
  51. * changed to be centered vertically. Horizontally
  52. * the view is adjusted according to the horizontal
  53. * alignment property set on the associated JTextField
  54. * (if that is the type of the hosting component).
  55. *
  56. * @param a the allocation given to the view, which may need
  57. * to be adjusted.
  58. * @return the allocation that the superclass should use.
  59. */
  60. protected Shape adjustAllocation(Shape a) {
  61. if (a != null) {
  62. Rectangle bounds = a.getBounds();
  63. int vspan = (int) getPreferredSpan(Y_AXIS);
  64. int hspan = (int) getPreferredSpan(X_AXIS);
  65. if (bounds.height != vspan) {
  66. int slop = bounds.height - vspan;
  67. bounds.y += slop / 2;
  68. bounds.height -= slop;
  69. }
  70. // horizontal adjustments
  71. Component c = getContainer();
  72. if (c instanceof JTextField) {
  73. JTextField field = (JTextField) c;
  74. BoundedRangeModel vis = field.getHorizontalVisibility();
  75. int max = Math.max(hspan, bounds.width);
  76. int value = vis.getValue();
  77. int extent = Math.min(max, bounds.width - 1);
  78. if ((value + extent) > max) {
  79. value = max - extent;
  80. }
  81. vis.setRangeProperties(value, extent, vis.getMinimum(),
  82. max, false);
  83. if (hspan < bounds.width) {
  84. // horizontally align the interior
  85. int slop = bounds.width - 1 - hspan;
  86. int align = ((JTextField)c).getHorizontalAlignment();
  87. if(Utilities.isLeftToRight(c)) {
  88. if(align==LEADING) {
  89. align = LEFT;
  90. }
  91. else if(align==TRAILING) {
  92. align = RIGHT;
  93. }
  94. }
  95. else {
  96. if(align==LEADING) {
  97. align = RIGHT;
  98. }
  99. else if(align==TRAILING) {
  100. align = LEFT;
  101. }
  102. }
  103. switch (align) {
  104. case SwingConstants.CENTER:
  105. bounds.x += slop / 2;
  106. bounds.width -= slop;
  107. break;
  108. case SwingConstants.RIGHT:
  109. bounds.x += slop;
  110. bounds.width -= slop;
  111. break;
  112. }
  113. } else {
  114. // adjust the allocation to match the bounded range.
  115. bounds.width = hspan;
  116. bounds.x -= vis.getValue();
  117. }
  118. }
  119. return bounds;
  120. }
  121. return null;
  122. }
  123. /**
  124. * Update the visibility model with the associated JTextField
  125. * (if there is one) to reflect the current visibility as a
  126. * result of changes to the document model. The bounded
  127. * range properties are updated. If the view hasn't yet been
  128. * shown the extent will be zero and we just set it to be full
  129. * until determined otherwise.
  130. */
  131. void updateVisibilityModel() {
  132. Component c = getContainer();
  133. if (c instanceof JTextField) {
  134. JTextField field = (JTextField) c;
  135. BoundedRangeModel vis = field.getHorizontalVisibility();
  136. int hspan = (int) getPreferredSpan(X_AXIS);
  137. int extent = vis.getExtent();
  138. int maximum = Math.max(hspan, extent);
  139. extent = (extent == 0) ? maximum : extent;
  140. int value = maximum - extent;
  141. int oldValue = vis.getValue();
  142. if ((oldValue + extent) > maximum) {
  143. oldValue = maximum - extent;
  144. }
  145. value = Math.max(0, Math.min(value, oldValue));
  146. vis.setRangeProperties(value, extent, 0, maximum, false);
  147. }
  148. }
  149. // --- View methods -------------------------------------------
  150. /**
  151. * Renders using the given rendering surface and area on that surface.
  152. * The view may need to do layout and create child views to enable
  153. * itself to render into the given allocation.
  154. *
  155. * @param g the rendering surface to use
  156. * @param a the allocated region to render into
  157. *
  158. * @see View#paint
  159. */
  160. public void paint(Graphics g, Shape a) {
  161. Rectangle r = (Rectangle) a;
  162. g.clipRect(r.x, r.y, r.width, r.height);
  163. super.paint(g, a);
  164. }
  165. /**
  166. * Adjusts <code>a</code> based on the visible region and returns it.
  167. */
  168. Shape adjustPaintRegion(Shape a) {
  169. return adjustAllocation(a);
  170. }
  171. /**
  172. * Determines the preferred span for this view along an
  173. * axis.
  174. *
  175. * @param axis may be either View.X_AXIS or View.Y_AXIS
  176. * @returns the span the view would like to be rendered into >= 0.
  177. * Typically the view is told to render into the span
  178. * that is returned, although there is no guarantee.
  179. * The parent may choose to resize or break the view.
  180. */
  181. public float getPreferredSpan(int axis) {
  182. switch (axis) {
  183. case View.X_AXIS:
  184. Segment buff = getLineBuffer();
  185. Document doc = getDocument();
  186. int width;
  187. try {
  188. doc.getText(0, doc.getLength(), buff);
  189. width = Utilities.getTabbedTextWidth(buff, getFontMetrics(), 0, this, 0);
  190. } catch (BadLocationException bl) {
  191. width = 0;
  192. }
  193. return width;
  194. default:
  195. return super.getPreferredSpan(axis);
  196. }
  197. }
  198. /**
  199. * Determines the resizability of the view along the
  200. * given axis. A value of 0 or less is not resizable.
  201. *
  202. * @param axis View.X_AXIS or View.Y_AXIS
  203. * @return the weight -> 1 for View.X_AXIS, else 0
  204. */
  205. public int getResizeWeight(int axis) {
  206. if (axis == View.X_AXIS) {
  207. return 1;
  208. }
  209. return 0;
  210. }
  211. /**
  212. * Provides a mapping from the document model coordinate space
  213. * to the coordinate space of the view mapped to it.
  214. *
  215. * @param pos the position to convert >= 0
  216. * @param a the allocated region to render into
  217. * @return the bounding box of the given position
  218. * @exception BadLocationException if the given position does not
  219. * represent a valid location in the associated document
  220. * @see View#modelToView
  221. */
  222. public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
  223. return super.modelToView(pos, adjustAllocation(a), b);
  224. }
  225. /**
  226. * Provides a mapping from the view coordinate space to the logical
  227. * coordinate space of the model.
  228. *
  229. * @param fx the X coordinate >= 0.0f
  230. * @param fy the Y coordinate >= 0.0f
  231. * @param a the allocated region to render into
  232. * @return the location within the model that best represents the
  233. * given point in the view
  234. * @see View#viewToModel
  235. */
  236. public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
  237. return super.viewToModel(fx, fy, adjustAllocation(a), bias);
  238. }
  239. /**
  240. * Gives notification that something was inserted into the document
  241. * in a location that this view is responsible for.
  242. *
  243. * @param changes the change information from the associated document
  244. * @param a the current allocation of the view
  245. * @param f the factory to use to rebuild if the view has children
  246. * @see View#insertUpdate
  247. */
  248. public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  249. super.insertUpdate(changes, adjustAllocation(a), f);
  250. updateVisibilityModel();
  251. }
  252. /**
  253. * Gives notification that something was removed from the document
  254. * in a location that this view is responsible for.
  255. *
  256. * @param changes the change information from the associated document
  257. * @param a the current allocation of the view
  258. * @param f the factory to use to rebuild if the view has children
  259. * @see View#removeUpdate
  260. */
  261. public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  262. super.removeUpdate(changes, adjustAllocation(a), f);
  263. updateVisibilityModel();
  264. }
  265. }