1. /*
  2. * @(#)BasicTextAreaUI.java 1.60 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.plaf.basic;
  11. import java.beans.*;
  12. import java.awt.*;
  13. import java.awt.event.KeyEvent;
  14. import java.awt.event.InputEvent;
  15. import javax.swing.*;
  16. import javax.swing.event.DocumentEvent;
  17. import javax.swing.text.*;
  18. import javax.swing.plaf.*;
  19. /**
  20. * Provides the look and feel for a plain text editor. In this
  21. * implementation the default UI is extended to act as a simple
  22. * view factory.
  23. * <p>
  24. * <strong>Warning:</strong>
  25. * Serialized objects of this class will not be compatible with
  26. * future Swing releases. The current serialization support is appropriate
  27. * for short term storage or RMI between applications running the same
  28. * version of Swing. A future release of Swing will provide support for
  29. * long term persistence.
  30. *
  31. * @author Timothy Prinzing
  32. * @version 1.60 02/02/00
  33. */
  34. public class BasicTextAreaUI extends BasicTextUI {
  35. /**
  36. * Creates a UI for a JTextArea.
  37. *
  38. * @param ta a text area
  39. * @return the UI
  40. */
  41. public static ComponentUI createUI(JComponent ta) {
  42. return new BasicTextAreaUI();
  43. }
  44. /**
  45. * Constructs a new BasicTextAreaUI object.
  46. */
  47. public BasicTextAreaUI() {
  48. super();
  49. }
  50. /**
  51. * Fetches the name used as a key to look up properties through the
  52. * UIManager. This is used as a prefix to all the standard
  53. * text properties.
  54. *
  55. * @return the name ("TextArea")
  56. */
  57. protected String getPropertyPrefix() {
  58. return "TextArea";
  59. }
  60. /**
  61. * This method gets called when a bound property is changed
  62. * on the associated JTextComponent. This is a hook
  63. * which UI implementations may change to reflect how the
  64. * UI displays bound properties of JTextComponent subclasses.
  65. * This is implemented to rebuild the View when the
  66. * <em>WrapLine</em> or the <em>WrapStyleWord</em> property changes.
  67. *
  68. * @param evt the property change event
  69. */
  70. protected void propertyChange(PropertyChangeEvent evt) {
  71. if (evt.getPropertyName().equals("lineWrap") ||
  72. evt.getPropertyName().equals("wrapStyleWord")) {
  73. // rebuild the view
  74. modelChanged();
  75. }
  76. // I18N views need to update themselves when the font changes.
  77. // This is a brute force way of doing that. A better way would be to
  78. // notify the views that the font has changed and let them react
  79. // accordingly.
  80. if ("font".equals(evt.getPropertyName())) {
  81. Document doc = editor.getDocument();
  82. Object flag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
  83. if( Boolean.TRUE.equals(flag) )
  84. modelChanged();
  85. }
  86. }
  87. /**
  88. * Creates the view for an element. Returns a WrappedPlainView or
  89. * PlainView.
  90. *
  91. * @param elem the element
  92. * @return the view
  93. */
  94. public View create(Element elem) {
  95. Document doc = elem.getDocument();
  96. Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
  97. if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
  98. // build a view that support bidi
  99. return createI18N(elem);
  100. } else {
  101. JTextComponent c = getComponent();
  102. if (c instanceof JTextArea) {
  103. JTextArea area = (JTextArea) c;
  104. View v;
  105. if (area.getLineWrap()) {
  106. v = new WrappedPlainView(elem, area.getWrapStyleWord());
  107. } else {
  108. v = new PlainView(elem);
  109. }
  110. return v;
  111. }
  112. }
  113. return null;
  114. }
  115. View createI18N(Element elem) {
  116. String kind = elem.getName();
  117. if (kind != null) {
  118. if (kind.equals(AbstractDocument.ContentElementName)) {
  119. return new PlainParagraph(elem);
  120. } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
  121. return new BoxView(elem, View.Y_AXIS);
  122. }
  123. }
  124. return null;
  125. }
  126. /**
  127. * Paragraph for representing plain-text lines that support
  128. * bidirectional text.
  129. */
  130. static class PlainParagraph extends ParagraphView {
  131. PlainParagraph(Element elem) {
  132. super(elem);
  133. layoutPool = new LogicalView(elem);
  134. layoutPool.setParent(this);
  135. }
  136. public void setParent(View parent) {
  137. super.setParent(parent);
  138. setPropertiesFromAttributes();
  139. }
  140. protected void setPropertiesFromAttributes() {
  141. Component c = getContainer();
  142. if ((c != null) && (! c.getComponentOrientation().isLeftToRight())) {
  143. setJustification(StyleConstants.ALIGN_RIGHT);
  144. } else {
  145. setJustification(StyleConstants.ALIGN_LEFT);
  146. }
  147. }
  148. /**
  149. * Fetch the constraining span to flow against for
  150. * the given child index.
  151. */
  152. public int getFlowSpan(int index) {
  153. Component c = getContainer();
  154. if (c instanceof JTextArea) {
  155. JTextArea area = (JTextArea) c;
  156. if (! area.getLineWrap()) {
  157. // no limit if unwrapped
  158. return Integer.MAX_VALUE;
  159. }
  160. }
  161. return super.getFlowSpan(index);
  162. }
  163. protected SizeRequirements calculateMinorAxisRequirements(int axis,
  164. SizeRequirements r) {
  165. SizeRequirements req = super.calculateMinorAxisRequirements(axis, r);
  166. Component c = getContainer();
  167. if (c instanceof JTextArea) {
  168. JTextArea area = (JTextArea) c;
  169. if (! area.getLineWrap()) {
  170. // min is pref if unwrapped
  171. req.minimum = req.preferred;
  172. } else {
  173. req.minimum = 0;
  174. req.preferred = getWidth();
  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. }