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