1. /*
  2. * @(#)SynthTextFieldUI.java 1.4 03/03/17
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.gtk;
  8. import javax.swing.*;
  9. import javax.swing.text.*;
  10. import javax.swing.event.*;
  11. import javax.swing.plaf.*;
  12. import java.awt.*;
  13. import java.beans.PropertyChangeEvent;
  14. /**
  15. * Basis of a look and feel for a JTextField in the Synth
  16. * look and feel.
  17. * <p>
  18. * <strong>Warning:</strong>
  19. * Serialized objects of this class will not be compatible with
  20. * future Swing releases. The current serialization support is
  21. * appropriate for short term storage or RMI between applications running
  22. * the same version of Swing. As of 1.4, support for long term storage
  23. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  24. * has been added to the <code>java.beans</code> package.
  25. * Please see {@link java.beans.XMLEncoder}.
  26. *
  27. * @author Shannon Hickey
  28. * @version 1.4 03/17/03 (based on revision 1.90 of BasicTextFieldUI)
  29. */
  30. class SynthTextFieldUI extends SynthTextUI {
  31. /**
  32. * Creates a UI for a JTextField.
  33. *
  34. * @param c the text field
  35. * @return the UI
  36. */
  37. public static ComponentUI createUI(JComponent c) {
  38. return new SynthTextFieldUI();
  39. }
  40. public void installUI(JComponent c) {
  41. super.installUI(c);
  42. }
  43. /**
  44. * Fetches the name used as a key to lookup properties through the
  45. * UIManager. This is used as a prefix to all the standard
  46. * text properties.
  47. *
  48. * @return the name ("TextField")
  49. */
  50. protected String getPropertyPrefix() {
  51. return "TextField";
  52. }
  53. /**
  54. * Creates a view (FieldView) based on an element.
  55. *
  56. * @param elem the element
  57. * @return the view
  58. */
  59. public View create(Element elem) {
  60. Document doc = elem.getDocument();
  61. Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
  62. if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
  63. // To support bidirectional text, we build a more heavyweight
  64. // representation of the field.
  65. String kind = elem.getName();
  66. if (kind != null) {
  67. if (kind.equals(AbstractDocument.ContentElementName)) {
  68. return new GlyphView(elem);
  69. } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
  70. return new I18nFieldView(elem);
  71. }
  72. }
  73. // this shouldn't happen, should probably throw in this case.
  74. }
  75. return new FieldView(elem);
  76. }
  77. /**
  78. * A field view that support bidirectional text via the
  79. * support provided by ParagraphView.
  80. */
  81. static class I18nFieldView extends ParagraphView {
  82. I18nFieldView(Element elem) {
  83. super(elem);
  84. }
  85. /**
  86. * Fetch the constraining span to flow against for
  87. * the given child index. There is no limit for
  88. * a field since it scrolls, so this is implemented to
  89. * return <code>Integer.MAX_VALUE</code>.
  90. */
  91. public int getFlowSpan(int index) {
  92. return Integer.MAX_VALUE;
  93. }
  94. protected void setJustification(int j) {
  95. // Justification is done in adjustAllocation(), so disable
  96. // ParagraphView's justification handling by doing nothing here.
  97. }
  98. static boolean isLeftToRight( java.awt.Component c ) {
  99. return c.getComponentOrientation().isLeftToRight();
  100. }
  101. /**
  102. * Adjusts the allocation given to the view
  103. * to be a suitable allocation for a text field.
  104. * If the view has been allocated more than the
  105. * preferred span vertically, the allocation is
  106. * changed to be centered vertically. Horizontally
  107. * the view is adjusted according to the horizontal
  108. * alignment property set on the associated JTextField
  109. * (if that is the type of the hosting component).
  110. *
  111. * @param a the allocation given to the view, which may need
  112. * to be adjusted.
  113. * @return the allocation that the superclass should use.
  114. */
  115. Shape adjustAllocation(Shape a) {
  116. if (a != null) {
  117. Rectangle bounds = a.getBounds();
  118. int vspan = (int) getPreferredSpan(Y_AXIS);
  119. int hspan = (int) getPreferredSpan(X_AXIS);
  120. if (bounds.height != vspan) {
  121. int slop = bounds.height - vspan;
  122. bounds.y += slop / 2;
  123. bounds.height -= slop;
  124. }
  125. // horizontal adjustments
  126. Component c = getContainer();
  127. if (c instanceof JTextField) {
  128. JTextField field = (JTextField) c;
  129. BoundedRangeModel vis = field.getHorizontalVisibility();
  130. int max = Math.max(hspan, bounds.width);
  131. int value = vis.getValue();
  132. int extent = Math.min(max, bounds.width - 1);
  133. if ((value + extent) > max) {
  134. value = max - extent;
  135. }
  136. vis.setRangeProperties(value, extent, vis.getMinimum(),
  137. max, false);
  138. if (hspan < bounds.width) {
  139. // horizontally align the interior
  140. int slop = bounds.width - 1 - hspan;
  141. int align = ((JTextField)c).getHorizontalAlignment();
  142. if(isLeftToRight(c)) {
  143. if(align==LEADING) {
  144. align = LEFT;
  145. }
  146. else if(align==TRAILING) {
  147. align = RIGHT;
  148. }
  149. }
  150. else {
  151. if(align==LEADING) {
  152. align = RIGHT;
  153. }
  154. else if(align==TRAILING) {
  155. align = LEFT;
  156. }
  157. }
  158. switch (align) {
  159. case SwingConstants.CENTER:
  160. bounds.x += slop / 2;
  161. bounds.width -= slop;
  162. break;
  163. case SwingConstants.RIGHT:
  164. bounds.x += slop;
  165. bounds.width -= slop;
  166. break;
  167. }
  168. } else {
  169. // adjust the allocation to match the bounded range.
  170. bounds.width = hspan;
  171. bounds.x -= vis.getValue();
  172. }
  173. }
  174. return bounds;
  175. }
  176. return null;
  177. }
  178. /**
  179. * Update the visibility model with the associated JTextField
  180. * (if there is one) to reflect the current visibility as a
  181. * result of changes to the document model. The bounded
  182. * range properties are updated. If the view hasn't yet been
  183. * shown the extent will be zero and we just set it to be full
  184. * until determined otherwise.
  185. */
  186. void updateVisibilityModel() {
  187. Component c = getContainer();
  188. if (c instanceof JTextField) {
  189. JTextField field = (JTextField) c;
  190. BoundedRangeModel vis = field.getHorizontalVisibility();
  191. int hspan = (int) getPreferredSpan(X_AXIS);
  192. int extent = vis.getExtent();
  193. int maximum = Math.max(hspan, extent);
  194. extent = (extent == 0) ? maximum : extent;
  195. int value = maximum - extent;
  196. int oldValue = vis.getValue();
  197. if ((oldValue + extent) > maximum) {
  198. oldValue = maximum - extent;
  199. }
  200. value = Math.max(0, Math.min(value, oldValue));
  201. vis.setRangeProperties(value, extent, 0, maximum, false);
  202. }
  203. }
  204. // --- View methods -------------------------------------------
  205. /**
  206. * Renders using the given rendering surface and area on that surface.
  207. * The view may need to do layout and create child views to enable
  208. * itself to render into the given allocation.
  209. *
  210. * @param g the rendering surface to use
  211. * @param a the allocated region to render into
  212. *
  213. * @see View#paint
  214. */
  215. public void paint(Graphics g, Shape a) {
  216. Rectangle r = (Rectangle) a;
  217. g.clipRect(r.x, r.y, r.width, r.height);
  218. super.paint(g, adjustAllocation(a));
  219. }
  220. /**
  221. * Determines the resizability of the view along the
  222. * given axis. A value of 0 or less is not resizable.
  223. *
  224. * @param axis View.X_AXIS or View.Y_AXIS
  225. * @return the weight -> 1 for View.X_AXIS, else 0
  226. */
  227. public int getResizeWeight(int axis) {
  228. if (axis == View.X_AXIS) {
  229. return 1;
  230. }
  231. return 0;
  232. }
  233. /**
  234. * Provides a mapping from the document model coordinate space
  235. * to the coordinate space of the view mapped to it.
  236. *
  237. * @param pos the position to convert >= 0
  238. * @param a the allocated region to render into
  239. * @return the bounding box of the given position
  240. * @exception BadLocationException if the given position does not
  241. * represent a valid location in the associated document
  242. * @see View#modelToView
  243. */
  244. public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
  245. return super.modelToView(pos, adjustAllocation(a), b);
  246. }
  247. /**
  248. * Provides a mapping from the document model coordinate space
  249. * to the coordinate space of the view mapped to it.
  250. *
  251. * @param p0 the position to convert >= 0
  252. * @param b0 the bias toward the previous character or the
  253. * next character represented by p0, in case the
  254. * position is a boundary of two views.
  255. * @param p1 the position to convert >= 0
  256. * @param b1 the bias toward the previous character or the
  257. * next character represented by p1, in case the
  258. * position is a boundary of two views.
  259. * @param a the allocated region to render into
  260. * @return the bounding box of the given position is returned
  261. * @exception BadLocationException if the given position does
  262. * not represent a valid location in the associated document
  263. * @exception IllegalArgumentException for an invalid bias argument
  264. * @see View#viewToModel
  265. */
  266. public Shape modelToView(int p0, Position.Bias b0,
  267. int p1, Position.Bias b1, Shape a)
  268. throws BadLocationException
  269. {
  270. return super.modelToView(p0, b0, p1, b1, adjustAllocation(a));
  271. }
  272. /**
  273. * Provides a mapping from the view coordinate space to the logical
  274. * coordinate space of the model.
  275. *
  276. * @param fx the X coordinate >= 0.0f
  277. * @param fy the Y coordinate >= 0.0f
  278. * @param a the allocated region to render into
  279. * @return the location within the model that best represents the
  280. * given point in the view
  281. * @see View#viewToModel
  282. */
  283. public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
  284. return super.viewToModel(fx, fy, adjustAllocation(a), bias);
  285. }
  286. /**
  287. * Gives notification that something was inserted into the document
  288. * in a location that this view is responsible for.
  289. *
  290. * @param changes the change information from the associated document
  291. * @param a the current allocation of the view
  292. * @param f the factory to use to rebuild if the view has children
  293. * @see View#insertUpdate
  294. */
  295. public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  296. super.insertUpdate(changes, adjustAllocation(a), f);
  297. updateVisibilityModel();
  298. }
  299. /**
  300. * Gives notification that something was removed from the document
  301. * in a location that this view is responsible for.
  302. *
  303. * @param changes the change information from the associated document
  304. * @param a the current allocation of the view
  305. * @param f the factory to use to rebuild if the view has children
  306. * @see View#removeUpdate
  307. */
  308. public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
  309. super.removeUpdate(changes, adjustAllocation(a), f);
  310. updateVisibilityModel();
  311. }
  312. }
  313. }