1. /*
  2. * @(#)BasicTextAreaUI.java 1.68 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.basic;
  8. import java.beans.*;
  9. import java.awt.*;
  10. import java.awt.event.KeyEvent;
  11. import java.awt.event.InputEvent;
  12. import javax.swing.*;
  13. import javax.swing.event.DocumentEvent;
  14. import javax.swing.text.*;
  15. import javax.swing.plaf.*;
  16. /**
  17. * Provides the look and feel for a plain text editor. In this
  18. * implementation the default UI is extended to act as a simple
  19. * view factory.
  20. * <p>
  21. * <strong>Warning:</strong>
  22. * Serialized objects of this class will not be compatible with
  23. * future Swing releases. The current serialization support is
  24. * appropriate for short term storage or RMI between applications running
  25. * the same version of Swing. As of 1.4, support for long term storage
  26. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  27. * has been added to the <code>java.beans</code> package.
  28. * Please see {@link java.beans.XMLEncoder}.
  29. *
  30. * @author Timothy Prinzing
  31. * @version 1.68 01/23/03
  32. */
  33. public class BasicTextAreaUI extends BasicTextUI {
  34. /**
  35. * Creates a UI for a JTextArea.
  36. *
  37. * @param ta a text area
  38. * @return the UI
  39. */
  40. public static ComponentUI createUI(JComponent ta) {
  41. return new BasicTextAreaUI();
  42. }
  43. /**
  44. * Constructs a new BasicTextAreaUI object.
  45. */
  46. public BasicTextAreaUI() {
  47. super();
  48. }
  49. /**
  50. * Fetches the name used as a key to look up properties through the
  51. * UIManager. This is used as a prefix to all the standard
  52. * text properties.
  53. *
  54. * @return the name ("TextArea")
  55. */
  56. protected String getPropertyPrefix() {
  57. return "TextArea";
  58. }
  59. /**
  60. * This method gets called when a bound property is changed
  61. * on the associated JTextComponent. This is a hook
  62. * which UI implementations may change to reflect how the
  63. * UI displays bound properties of JTextComponent subclasses.
  64. * This is implemented to rebuild the View when the
  65. * <em>WrapLine</em> or the <em>WrapStyleWord</em> property changes.
  66. *
  67. * @param evt the property change event
  68. */
  69. protected void propertyChange(PropertyChangeEvent evt) {
  70. if (evt.getPropertyName().equals("lineWrap") ||
  71. evt.getPropertyName().equals("wrapStyleWord") ||
  72. evt.getPropertyName().equals("tabSize")) {
  73. // rebuild the view
  74. modelChanged();
  75. } else if ("editable".equals(evt.getPropertyName())) {
  76. updateFocusTraversalKeys();
  77. }
  78. }
  79. /**
  80. * Creates the view for an element. Returns a WrappedPlainView or
  81. * PlainView.
  82. *
  83. * @param elem the element
  84. * @return the view
  85. */
  86. public View create(Element elem) {
  87. Document doc = elem.getDocument();
  88. Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
  89. if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
  90. // build a view that support bidi
  91. return createI18N(elem);
  92. } else {
  93. JTextComponent c = getComponent();
  94. if (c instanceof JTextArea) {
  95. JTextArea area = (JTextArea) c;
  96. View v;
  97. if (area.getLineWrap()) {
  98. v = new WrappedPlainView(elem, area.getWrapStyleWord());
  99. } else {
  100. v = new PlainView(elem);
  101. }
  102. return v;
  103. }
  104. }
  105. return null;
  106. }
  107. View createI18N(Element elem) {
  108. String kind = elem.getName();
  109. if (kind != null) {
  110. if (kind.equals(AbstractDocument.ContentElementName)) {
  111. return new PlainParagraph(elem);
  112. } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
  113. return new BoxView(elem, View.Y_AXIS);
  114. }
  115. }
  116. return null;
  117. }
  118. /**
  119. * Paragraph for representing plain-text lines that support
  120. * bidirectional text.
  121. */
  122. static class PlainParagraph extends ParagraphView {
  123. PlainParagraph(Element elem) {
  124. super(elem);
  125. layoutPool = new LogicalView(elem);
  126. layoutPool.setParent(this);
  127. }
  128. public void setParent(View parent) {
  129. super.setParent(parent);
  130. if (parent != null) {
  131. setPropertiesFromAttributes();
  132. }
  133. }
  134. protected void setPropertiesFromAttributes() {
  135. Component c = getContainer();
  136. if ((c != null) && (! c.getComponentOrientation().isLeftToRight())) {
  137. setJustification(StyleConstants.ALIGN_RIGHT);
  138. } else {
  139. setJustification(StyleConstants.ALIGN_LEFT);
  140. }
  141. }
  142. /**
  143. * Fetch the constraining span to flow against for
  144. * the given child index.
  145. */
  146. public int getFlowSpan(int index) {
  147. Component c = getContainer();
  148. if (c instanceof JTextArea) {
  149. JTextArea area = (JTextArea) c;
  150. if (! area.getLineWrap()) {
  151. // no limit if unwrapped
  152. return Integer.MAX_VALUE;
  153. }
  154. }
  155. return super.getFlowSpan(index);
  156. }
  157. protected SizeRequirements calculateMinorAxisRequirements(int axis,
  158. SizeRequirements r) {
  159. SizeRequirements req = super.calculateMinorAxisRequirements(axis, r);
  160. Component c = getContainer();
  161. if (c instanceof JTextArea) {
  162. JTextArea area = (JTextArea) c;
  163. if (! area.getLineWrap()) {
  164. // min is pref if unwrapped
  165. req.minimum = req.preferred;
  166. } else {
  167. req.minimum = 0;
  168. req.preferred = getWidth();
  169. if (req.preferred == Short.MAX_VALUE) {
  170. // We have been initially set to MAX_VALUE, but we
  171. // don't want this as our preferred. Short is used
  172. // here as FlowView returns it as the max size.
  173. req.preferred = 100;
  174. }
  175. }
  176. }
  177. return req;
  178. }
  179. /**
  180. * Sets the size of the view. If the size has changed, layout
  181. * is redone. The size is the full size of the view including
  182. * the inset areas.
  183. *
  184. * @param width the width >= 0
  185. * @param height the height >= 0
  186. */
  187. public void setSize(float width, float height) {
  188. if ((int) width != getWidth()) {
  189. preferenceChanged(null, true, true);
  190. }
  191. super.setSize(width, height);
  192. }
  193. /**
  194. * This class can be used to represent a logical view for
  195. * a flow. It keeps the children updated to reflect the state
  196. * of the model, gives the logical child views access to the
  197. * view hierarchy, and calculates a preferred span. It doesn't
  198. * do any rendering, layout, or model/view translation.
  199. */
  200. static class LogicalView extends CompositeView {
  201. LogicalView(Element elem) {
  202. super(elem);
  203. }
  204. protected int getViewIndexAtPosition(int pos) {
  205. Element elem = getElement();
  206. if (elem.getElementCount() > 0) {
  207. return elem.getElementIndex(pos);
  208. }
  209. return 0;
  210. }
  211. protected boolean updateChildren(DocumentEvent.ElementChange ec,
  212. DocumentEvent e, ViewFactory f) {
  213. return false;
  214. }
  215. protected void loadChildren(ViewFactory f) {
  216. Element elem = getElement();
  217. if (elem.getElementCount() > 0) {
  218. super.loadChildren(f);
  219. } else {
  220. View v = new GlyphView(elem);
  221. append(v);
  222. }
  223. }
  224. public float getPreferredSpan(int axis) {
  225. if( getViewCount() != 1 )
  226. throw new Error("One child view is assumed.");
  227. View v = getView(0);
  228. return v.getPreferredSpan(axis);
  229. }
  230. /**
  231. * Forward the DocumentEvent to the given child view. This
  232. * is implemented to reparent the child to the logical view
  233. * (the children may have been parented by a row in the flow
  234. * if they fit without breaking) and then execute the superclass
  235. * behavior.
  236. *
  237. * @param v the child view to forward the event to.
  238. * @param e the change information from the associated document
  239. * @param a the current allocation of the view
  240. * @param f the factory to use to rebuild if the view has children
  241. * @see #forwardUpdate
  242. * @since 1.3
  243. */
  244. protected void forwardUpdateToView(View v, DocumentEvent e,
  245. Shape a, ViewFactory f) {
  246. v.setParent(this);
  247. super.forwardUpdateToView(v, e, a, f);
  248. }
  249. // The following methods don't do anything useful, they
  250. // simply keep the class from being abstract.
  251. public void paint(Graphics g, Shape allocation) {
  252. }
  253. protected boolean isBefore(int x, int y, Rectangle alloc) {
  254. return false;
  255. }
  256. protected boolean isAfter(int x, int y, Rectangle alloc) {
  257. return false;
  258. }
  259. protected View getViewAtPoint(int x, int y, Rectangle alloc) {
  260. return null;
  261. }
  262. protected void childAllocation(int index, Rectangle a) {
  263. }
  264. }
  265. }
  266. }