1. /*
  2. * @(#)BasicEditorPaneUI.java 1.32 04/07/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.awt.*;
  9. import java.awt.event.*;
  10. import java.beans.*;
  11. import java.net.URL;
  12. import java.net.MalformedURLException;
  13. import javax.swing.*;
  14. import javax.swing.text.*;
  15. import javax.swing.text.html.*;
  16. import javax.swing.plaf.*;
  17. import javax.swing.border.*;
  18. /**
  19. * Provides the look and feel for a JEditorPane.
  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.32 07/23/04
  32. */
  33. public class BasicEditorPaneUI extends BasicTextUI {
  34. /**
  35. * Creates a UI for the JTextPane.
  36. *
  37. * @param c the JTextPane component
  38. * @return the UI
  39. */
  40. public static ComponentUI createUI(JComponent c) {
  41. return new BasicEditorPaneUI();
  42. }
  43. /**
  44. * Creates a new BasicEditorPaneUI.
  45. */
  46. public BasicEditorPaneUI() {
  47. super();
  48. }
  49. /**
  50. * Fetches the name used as a key to lookup properties through the
  51. * UIManager. This is used as a prefix to all the standard
  52. * text properties.
  53. *
  54. * @return the name ("EditorPane")
  55. */
  56. protected String getPropertyPrefix() {
  57. return "EditorPane";
  58. }
  59. /**
  60. *{@inheritDoc}
  61. *
  62. * @since 1.5
  63. */
  64. public void installUI(JComponent c) {
  65. super.installUI(c);
  66. updateDisplayProperties(c.getFont(),
  67. c.getForeground());
  68. }
  69. /**
  70. *{@inheritDoc}
  71. *
  72. * @since 1.5
  73. */
  74. public void uninstallUI(JComponent c) {
  75. cleanDisplayProperties();
  76. super.uninstallUI(c);
  77. }
  78. /**
  79. * Fetches the EditorKit for the UI. This is whatever is
  80. * currently set in the associated JEditorPane.
  81. *
  82. * @return the editor capabilities
  83. * @see TextUI#getEditorKit
  84. */
  85. public EditorKit getEditorKit(JTextComponent tc) {
  86. JEditorPane pane = (JEditorPane) getComponent();
  87. return pane.getEditorKit();
  88. }
  89. /**
  90. * Fetch an action map to use. The map for a JEditorPane
  91. * is not shared because it changes with the EditorKit.
  92. */
  93. ActionMap getActionMap() {
  94. ActionMap am = new ActionMapUIResource();
  95. am.put("requestFocus", new FocusAction());
  96. EditorKit editorKit = getEditorKit(getComponent());
  97. if (editorKit != null) {
  98. Action[] actions = editorKit.getActions();
  99. if (actions != null) {
  100. addActions(am, actions);
  101. }
  102. }
  103. am.put(TransferHandler.getCutAction().getValue(Action.NAME),
  104. TransferHandler.getCutAction());
  105. am.put(TransferHandler.getCopyAction().getValue(Action.NAME),
  106. TransferHandler.getCopyAction());
  107. am.put(TransferHandler.getPasteAction().getValue(Action.NAME),
  108. TransferHandler.getPasteAction());
  109. return am;
  110. }
  111. /**
  112. * This method gets called when a bound property is changed
  113. * on the associated JTextComponent. This is a hook
  114. * which UI implementations may change to reflect how the
  115. * UI displays bound properties of JTextComponent subclasses.
  116. * This is implemented to rebuild the ActionMap based upon an
  117. * EditorKit change.
  118. *
  119. * @param evt the property change event
  120. */
  121. protected void propertyChange(PropertyChangeEvent evt) {
  122. String name = evt.getPropertyName();
  123. if ("editorKit".equals(name)) {
  124. ActionMap map = SwingUtilities.getUIActionMap(getComponent());
  125. if (map != null) {
  126. Object oldValue = evt.getOldValue();
  127. if (oldValue instanceof EditorKit) {
  128. Action[] actions = ((EditorKit)oldValue).getActions();
  129. if (actions != null) {
  130. removeActions(map, actions);
  131. }
  132. }
  133. Object newValue = evt.getNewValue();
  134. if (newValue instanceof EditorKit) {
  135. Action[] actions = ((EditorKit)newValue).getActions();
  136. if (actions != null) {
  137. addActions(map, actions);
  138. }
  139. }
  140. }
  141. updateFocusTraversalKeys();
  142. } else if ("editable".equals(name)) {
  143. updateFocusTraversalKeys();
  144. } else if ("foreground".equals(name)
  145. || "font".equals(name)
  146. || "document".equals(name)
  147. || JEditorPane.W3C_LENGTH_UNITS.equals(name)
  148. || JEditorPane.HONOR_DISPLAY_PROPERTIES.equals(name)
  149. ) {
  150. JComponent c = getComponent();
  151. updateDisplayProperties(c.getFont(), c.getForeground());
  152. if ( JEditorPane.W3C_LENGTH_UNITS.equals(name)
  153. || JEditorPane.HONOR_DISPLAY_PROPERTIES.equals(name) ) {
  154. modelChanged();
  155. }
  156. if ("foreground".equals(name)) {
  157. Object honorDisplayPropertiesObject = c.
  158. getClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES);
  159. boolean honorDisplayProperties = false;
  160. if (honorDisplayPropertiesObject instanceof Boolean) {
  161. honorDisplayProperties =
  162. ((Boolean)honorDisplayPropertiesObject).booleanValue();
  163. }
  164. if (honorDisplayProperties) {
  165. modelChanged();
  166. }
  167. }
  168. }
  169. }
  170. void removeActions(ActionMap map, Action[] actions) {
  171. int n = actions.length;
  172. for (int i = 0; i < n; i++) {
  173. Action a = actions[i];
  174. map.remove(a.getValue(Action.NAME));
  175. }
  176. }
  177. void addActions(ActionMap map, Action[] actions) {
  178. int n = actions.length;
  179. for (int i = 0; i < n; i++) {
  180. Action a = actions[i];
  181. map.put(a.getValue(Action.NAME), a);
  182. }
  183. }
  184. void updateDisplayProperties(Font font, Color fg) {
  185. JComponent c = getComponent();
  186. Object honorDisplayPropertiesObject = c.
  187. getClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES);
  188. boolean honorDisplayProperties = false;
  189. Object w3cLengthUnitsObject = c.getClientProperty(JEditorPane.
  190. W3C_LENGTH_UNITS);
  191. boolean w3cLengthUnits = false;
  192. if (honorDisplayPropertiesObject instanceof Boolean) {
  193. honorDisplayProperties =
  194. ((Boolean)honorDisplayPropertiesObject).booleanValue();
  195. }
  196. if (w3cLengthUnitsObject instanceof Boolean) {
  197. w3cLengthUnits = ((Boolean)w3cLengthUnitsObject).booleanValue();
  198. }
  199. if (this instanceof BasicTextPaneUI
  200. || honorDisplayProperties) {
  201. //using equals because can not use UIResource for Boolean
  202. Document doc = getComponent().getDocument();
  203. if (doc instanceof StyledDocument) {
  204. if (doc instanceof HTMLDocument
  205. && honorDisplayProperties) {
  206. updateCSS(font, fg);
  207. } else {
  208. updateStyle(font, fg);
  209. }
  210. }
  211. } else {
  212. cleanDisplayProperties();
  213. }
  214. if ( w3cLengthUnits ) {
  215. Document doc = getComponent().getDocument();
  216. if (doc instanceof HTMLDocument) {
  217. StyleSheet documentStyleSheet =
  218. ((HTMLDocument)doc).getStyleSheet();
  219. documentStyleSheet.addRule("W3C_LENGTH_UNITS_ENABLE");
  220. }
  221. } else {
  222. Document doc = getComponent().getDocument();
  223. if (doc instanceof HTMLDocument) {
  224. StyleSheet documentStyleSheet =
  225. ((HTMLDocument)doc).getStyleSheet();
  226. documentStyleSheet.addRule("W3C_LENGTH_UNITS_DISABLE");
  227. }
  228. }
  229. }
  230. void cleanDisplayProperties() {
  231. Document document = getComponent().getDocument();
  232. if (document instanceof HTMLDocument) {
  233. StyleSheet documentStyleSheet =
  234. ((HTMLDocument)document).getStyleSheet();
  235. StyleSheet[] styleSheets = documentStyleSheet.getStyleSheets();
  236. if (styleSheets != null) {
  237. for (StyleSheet s : styleSheets) {
  238. if (s instanceof StyleSheetUIResource) {
  239. documentStyleSheet.removeStyleSheet(s);
  240. documentStyleSheet.addRule("BASE_SIZE_DISABLE");
  241. break;
  242. }
  243. }
  244. }
  245. }
  246. }
  247. static class StyleSheetUIResource extends StyleSheet implements UIResource {
  248. }
  249. private void updateCSS(Font font, Color fg) {
  250. JTextComponent component = getComponent();
  251. Document document = component.getDocument();
  252. if (document instanceof HTMLDocument) {
  253. StyleSheet styleSheet = new StyleSheetUIResource();
  254. StyleSheet documentStyleSheet =
  255. ((HTMLDocument)document).getStyleSheet();
  256. StyleSheet[] styleSheets = documentStyleSheet.getStyleSheets();
  257. if (styleSheets != null) {
  258. for (StyleSheet s : styleSheets) {
  259. if (s instanceof StyleSheetUIResource) {
  260. documentStyleSheet.removeStyleSheet(s);
  261. }
  262. }
  263. }
  264. String cssRule = com.sun.java.swing.
  265. SwingUtilities2.displayPropertiesToCSS(font,
  266. fg);
  267. styleSheet.addRule(cssRule);
  268. documentStyleSheet.addStyleSheet(styleSheet);
  269. documentStyleSheet.addRule("BASE_SIZE " +
  270. component.getFont().getSize());
  271. }
  272. }
  273. private void updateStyle(Font font, Color fg) {
  274. updateFont(font);
  275. updateForeground(fg);
  276. }
  277. /**
  278. * Update the color in the default style of the document.
  279. *
  280. * @param color the new color to use or null to remove the color attribute
  281. * from the document's style
  282. */
  283. private void updateForeground(Color color) {
  284. StyledDocument doc = (StyledDocument)getComponent().getDocument();
  285. Style style = doc.getStyle(StyleContext.DEFAULT_STYLE);
  286. if (style == null) {
  287. return;
  288. }
  289. if (color == null) {
  290. style.removeAttribute(StyleConstants.Foreground);
  291. } else {
  292. StyleConstants.setForeground(style, color);
  293. }
  294. }
  295. /**
  296. * Update the font in the default style of the document.
  297. *
  298. * @param font the new font to use or null to remove the font attribute
  299. * from the document's style
  300. */
  301. private void updateFont(Font font) {
  302. StyledDocument doc = (StyledDocument)getComponent().getDocument();
  303. Style style = doc.getStyle(StyleContext.DEFAULT_STYLE);
  304. if (style == null) {
  305. return;
  306. }
  307. if (font == null) {
  308. style.removeAttribute(StyleConstants.FontFamily);
  309. style.removeAttribute(StyleConstants.FontSize);
  310. style.removeAttribute(StyleConstants.Bold);
  311. style.removeAttribute(StyleConstants.Italic);
  312. } else {
  313. StyleConstants.setFontFamily(style, font.getName());
  314. StyleConstants.setFontSize(style, font.getSize());
  315. StyleConstants.setBold(style, font.isBold());
  316. StyleConstants.setItalic(style, font.isItalic());
  317. }
  318. }
  319. }