1. /*
  2. * @(#)BasicTextAreaUI.java 1.68 03/01/23
  3. *
  4. * Copyright 2004 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. protected void installDefaults() {
  60. super.installDefaults();
  61. //the fix for 4785160 is undone
  62. }
  63. /**
  64. * This method gets called when a bound property is changed
  65. * on the associated JTextComponent. This is a hook
  66. * which UI implementations may change to reflect how the
  67. * UI displays bound properties of JTextComponent subclasses.
  68. * This is implemented to rebuild the View when the
  69. * <em>WrapLine</em> or the <em>WrapStyleWord</em> property changes.
  70. *
  71. * @param evt the property change event
  72. */
  73. protected void propertyChange(PropertyChangeEvent evt) {
  74. if (evt.getPropertyName().equals("lineWrap") ||
  75. evt.getPropertyName().equals("wrapStyleWord") ||
  76. evt.getPropertyName().equals("tabSize")) {
  77. // rebuild the view
  78. modelChanged();
  79. } else if ("editable".equals(evt.getPropertyName())) {
  80. updateFocusTraversalKeys();
  81. }
  82. }
  83. /**
  84. * The method is overridden to take into account caret width.
  85. *
  86. * @param c the editor component
  87. * @return the preferred size
  88. * @throws IllegalArgumentException if invalid value is passed
  89. *
  90. * @since 1.5
  91. */
  92. public Dimension getPreferredSize(JComponent c) {
  93. return super.getPreferredSize(c);
  94. //the fix for 4785160 is undone
  95. }
  96. /**
  97. * The method is overridden to take into account caret width.
  98. *
  99. * @param c the editor component
  100. * @return the minimum size
  101. * @throws IllegalArgumentException if invalid value is passed
  102. *
  103. * @since 1.5
  104. */
  105. public Dimension getMinimumSize(JComponent c) {
  106. return super.getMinimumSize(c);
  107. //the fix for 4785160 is undone
  108. }
  109. /**
  110. * Creates the view for an element. Returns a WrappedPlainView or
  111. * PlainView.
  112. *
  113. * @param elem the element
  114. * @return the view
  115. */
  116. public View create(Element elem) {
  117. Document doc = elem.getDocument();
  118. Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
  119. if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
  120. // build a view that support bidi
  121. return createI18N(elem);
  122. } else {
  123. JTextComponent c = getComponent();
  124. if (c instanceof JTextArea) {
  125. JTextArea area = (JTextArea) c;
  126. View v;
  127. if (area.getLineWrap()) {
  128. v = new WrappedPlainView(elem, area.getWrapStyleWord());
  129. } else {
  130. v = new PlainView(elem);
  131. }
  132. return v;
  133. }
  134. }
  135. return null;
  136. }
  137. View createI18N(Element elem) {
  138. String kind = elem.getName();
  139. if (kind != null) {
  140. if (kind.equals(AbstractDocument.ContentElementName)) {
  141. return new PlainParagraph(elem);
  142. } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
  143. return new BoxView(elem, View.Y_AXIS);
  144. }
  145. }
  146. return null;
  147. }
  148. /**
  149. * Paragraph for representing plain-text lines that support
  150. * bidirectional text.
  151. */
  152. static class PlainParagraph extends ParagraphView {
  153. PlainParagraph(Element elem) {
  154. super(elem);
  155. layoutPool = new LogicalView(elem);
  156. layoutPool.setParent(this);
  157. }
  158. public void setParent(View parent) {
  159. super.setParent(parent);
  160. if (parent != null) {
  161. setPropertiesFromAttributes();
  162. }
  163. }
  164. protected void setPropertiesFromAttributes() {
  165. Component c = getContainer();
  166. if ((c != null) && (! c.getComponentOrientation().isLeftToRight())) {
  167. setJustification(StyleConstants.ALIGN_RIGHT);
  168. } else {
  169. setJustification(StyleConstants.ALIGN_LEFT);
  170. }
  171. }
  172. /**
  173. * Fetch the constraining span to flow against for
  174. * the given child index.
  175. */
  176. public int getFlowSpan(int index) {
  177. Component c = getContainer();
  178. if (c instanceof JTextArea) {
  179. JTextArea area = (JTextArea) c;
  180. if (! area.getLineWrap()) {
  181. // no limit if unwrapped
  182. return Integer.MAX_VALUE;
  183. }
  184. }
  185. return super.getFlowSpan(index);
  186. }
  187. protected SizeRequirements calculateMinorAxisRequirements(int axis,
  188. SizeRequirements r) {
  189. SizeRequirements req = super.calculateMinorAxisRequirements(axis, r);
  190. Component c = getContainer();
  191. if (c instanceof JTextArea) {
  192. JTextArea area = (JTextArea) c;
  193. if (! area.getLineWrap()) {
  194. // min is pref if unwrapped
  195. req.minimum = req.preferred;
  196. } else {
  197. req.minimum = 0;
  198. req.preferred = getWidth();
  199. if (req.preferred == Short.MAX_VALUE) {
  200. // We have been initially set to MAX_VALUE, but we
  201. // don't want this as our preferred. Short is used
  202. // here as FlowView returns it as the max size.
  203. req.preferred = 100;
  204. }
  205. }
  206. }
  207. return req;
  208. }
  209. /**
  210. * Sets the size of the view. If the size has changed, layout
  211. * is redone. The size is the full size of the view including
  212. * the inset areas.
  213. *
  214. * @param width the width >= 0
  215. * @param height the height >= 0
  216. */
  217. public void setSize(float width, float height) {
  218. if ((int) width != getWidth()) {
  219. preferenceChanged(null, true, true);
  220. }
  221. super.setSize(width, height);
  222. }
  223. /**
  224. * This class can be used to represent a logical view for
  225. * a flow. It keeps the children updated to reflect the state
  226. * of the model, gives the logical child views access to the
  227. * view hierarchy, and calculates a preferred span. It doesn't
  228. * do any rendering, layout, or model/view translation.
  229. */
  230. static class LogicalView extends CompositeView {
  231. LogicalView(Element elem) {
  232. super(elem);
  233. }
  234. protected int getViewIndexAtPosition(int pos) {
  235. Element elem = getElement();
  236. if (elem.getElementCount() > 0) {
  237. return elem.getElementIndex(pos);
  238. }
  239. return 0;
  240. }
  241. protected boolean updateChildren(DocumentEvent.ElementChange ec,
  242. DocumentEvent e, ViewFactory f) {
  243. return false;
  244. }
  245. protected void loadChildren(ViewFactory f) {
  246. Element elem = getElement();
  247. if (elem.getElementCount() > 0) {
  248. super.loadChildren(f);
  249. } else {
  250. View v = new GlyphView(elem);
  251. append(v);
  252. }
  253. }
  254. public float getPreferredSpan(int axis) {
  255. if( getViewCount() != 1 )
  256. throw new Error("One child view is assumed.");
  257. View v = getView(0);
  258. return v.getPreferredSpan(axis);
  259. }
  260. /**
  261. * Forward the DocumentEvent to the given child view. This
  262. * is implemented to reparent the child to the logical view
  263. * (the children may have been parented by a row in the flow
  264. * if they fit without breaking) and then execute the superclass
  265. * behavior.
  266. *
  267. * @param v the child view to forward the event to.
  268. * @param e the change information from the associated document
  269. * @param a the current allocation of the view
  270. * @param f the factory to use to rebuild if the view has children
  271. * @see #forwardUpdate
  272. * @since 1.3
  273. */
  274. protected void forwardUpdateToView(View v, DocumentEvent e,
  275. Shape a, ViewFactory f) {
  276. v.setParent(this);
  277. super.forwardUpdateToView(v, e, a, f);
  278. }
  279. // The following methods don't do anything useful, they
  280. // simply keep the class from being abstract.
  281. public void paint(Graphics g, Shape allocation) {
  282. }
  283. protected boolean isBefore(int x, int y, Rectangle alloc) {
  284. return false;
  285. }
  286. protected boolean isAfter(int x, int y, Rectangle alloc) {
  287. return false;
  288. }
  289. protected View getViewAtPoint(int x, int y, Rectangle alloc) {
  290. return null;
  291. }
  292. protected void childAllocation(int index, Rectangle a) {
  293. }
  294. }
  295. }
  296. }