1. /*
  2. * @(#)JTextPane.java 1.67 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.event.ActionEvent;
  10. import java.io.ObjectOutputStream;
  11. import java.io.ObjectInputStream;
  12. import java.io.IOException;
  13. import javax.swing.text.*;
  14. import javax.swing.event.*;
  15. import javax.swing.plaf.*;
  16. /**
  17. * A text component that can be marked up with attributes that are
  18. * represented graphically. This component models paragraphs
  19. * that are composed of runs of character level attributes. Each
  20. * paragraph may have a logical style attached to it which contains
  21. * the default attributes to use if no overriden by attributes set
  22. * on the paragraph or character run. Components and images may
  23. * be embedded in the flow of text.
  24. * <p>
  25. * For the keyboard keys used by this component in the standard Look and
  26. * Feel (L&F) renditions, see the
  27. * <a href="doc-files/Key-Index.html#JTextPane">JTextPane</a> key assignments.
  28. * <p>
  29. * <strong>Warning:</strong>
  30. * Serialized objects of this class will not be compatible with
  31. * future Swing releases. The current serialization support is appropriate
  32. * for short term storage or RMI between applications running the same
  33. * version of Swing. A future release of Swing will provide support for
  34. * long term persistence.
  35. *
  36. * @author Timothy Prinzing
  37. * @version 1.67 11/29/01
  38. * @see text.StyledEditorKit
  39. */
  40. public class JTextPane extends JEditorPane {
  41. /**
  42. * Constructs a new JTextPane. A new instance of StyledEditorKit is
  43. * created and set, and the document model set to null.
  44. */
  45. public JTextPane() {
  46. super();
  47. setEditorKit(new StyledEditorKit());
  48. }
  49. /**
  50. * Constructs a new JTextPane, with a specified document model.
  51. * A new instance of text.StyledEditorKit is created and set.
  52. *
  53. * @param doc the document model
  54. */
  55. public JTextPane(StyledDocument doc) {
  56. this();
  57. setStyledDocument(doc);
  58. }
  59. /**
  60. * Returns the class ID for the UI.
  61. *
  62. * @return the ID ("TextPaneUI")
  63. * @see JComponent#getUIClassID
  64. * @see UIDefaults#getUI
  65. */
  66. public String getUIClassID() {
  67. return uiClassID;
  68. }
  69. /**
  70. * Associates the editor with a text document. This
  71. * must be a StyledDocument.
  72. *
  73. * @param doc the document to display/edit
  74. * @exception IllegalArgumentException if doc can't
  75. * be narrowed to a StyledDocument which is the
  76. * required type of model for this text component
  77. */
  78. public void setDocument(Document doc) {
  79. if (doc instanceof StyledDocument) {
  80. super.setDocument(doc);
  81. } else {
  82. throw new IllegalArgumentException("Model must be StyledDocument");
  83. }
  84. }
  85. /**
  86. * Associates the editor with a text document.
  87. * The currently registered factory is used to build a view for
  88. * the document, which gets displayed by the editor.
  89. *
  90. * @param doc the document to display/edit
  91. */
  92. public void setStyledDocument(StyledDocument doc) {
  93. super.setDocument(doc);
  94. }
  95. /**
  96. * Fetches the model associated with the editor.
  97. *
  98. * @return the model
  99. */
  100. public StyledDocument getStyledDocument() {
  101. return (StyledDocument) getDocument();
  102. }
  103. /**
  104. * Replaces the currently selected content with new content
  105. * represented by the given string. If there is no selection
  106. * this amounts to an insert of the given text. If there
  107. * is no replacement text this amounts to a removal of the
  108. * current selection. The replacement text will have the
  109. * attributes currently defined for input. If the document is not
  110. * editable, beep and return. Then if the document is null, do nothing.
  111. * If the content to insert is null or empty, ignore it.
  112. * <p>
  113. * This method is thread safe, although most Swing methods
  114. * are not. Please see
  115. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  116. * and Swing</A> for more information.
  117. *
  118. * @param content the content to replace the selection with
  119. */
  120. public void replaceSelection(String content) {
  121. if (! isEditable()) {
  122. getToolkit().beep();
  123. return;
  124. }
  125. Document doc = getStyledDocument();
  126. if (doc != null) {
  127. try {
  128. Caret caret = getCaret();
  129. int p0 = Math.min(caret.getDot(), caret.getMark());
  130. int p1 = Math.max(caret.getDot(), caret.getMark());
  131. if (p0 != p1) {
  132. doc.remove(p0, p1 - p0);
  133. }
  134. if (content != null && content.length() > 0) {
  135. doc.insertString(p0, content, getInputAttributes());
  136. }
  137. } catch (BadLocationException e) {
  138. getToolkit().beep();
  139. }
  140. }
  141. }
  142. /**
  143. * Inserts a component into the document as a replacement
  144. * for the currently selected content. If there is no
  145. * selection the component is effectively inserted at the
  146. * current position of the caret. This is represented in
  147. * the associated document as an attribute of one character
  148. * of content.
  149. *
  150. * @param c the component to insert
  151. */
  152. public void insertComponent(Component c) {
  153. MutableAttributeSet inputAttributes = getInputAttributes();
  154. inputAttributes.removeAttributes(inputAttributes);
  155. StyleConstants.setComponent(inputAttributes, c);
  156. replaceSelection(" ");
  157. inputAttributes.removeAttributes(inputAttributes);
  158. }
  159. /**
  160. * Inserts an icon into the document as a replacement
  161. * for the currently selected content. If there is no
  162. * selection the icon is effectively inserted at the
  163. * current position of the caret. This is represented in
  164. * the associated document as an attribute of one character
  165. * of content.
  166. * <p>
  167. * This method is thread safe, although most Swing methods
  168. * are not. Please see
  169. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  170. * and Swing</A> for more information.
  171. *
  172. * @param g the icon to insert
  173. * @see Icon
  174. */
  175. public void insertIcon(Icon g) {
  176. MutableAttributeSet inputAttributes = getInputAttributes();
  177. inputAttributes.removeAttributes(inputAttributes);
  178. StyleConstants.setIcon(inputAttributes, g);
  179. replaceSelection(" ");
  180. inputAttributes.removeAttributes(inputAttributes);
  181. }
  182. /**
  183. * Adds a new style into the logical style hierarchy. Style attributes
  184. * resolve from bottom up so an attribute specified in a child
  185. * will override an attribute specified in the parent.
  186. *
  187. * @param nm the name of the style (must be unique within the
  188. * collection of named styles). The name may be null if the style
  189. * is unnamed, but the caller is responsible
  190. * for managing the reference returned as an unnamed style can't
  191. * be fetched by name. An unnamed style may be useful for things
  192. * like character attribute overrides such as found in a style
  193. * run.
  194. * @param parent the parent style. This may be null if unspecified
  195. * attributes need not be resolved in some other style.
  196. * @return the new Style
  197. */
  198. public Style addStyle(String nm, Style parent) {
  199. StyledDocument doc = getStyledDocument();
  200. return doc.addStyle(nm, parent);
  201. }
  202. /**
  203. * Removes a named non-null style previously added to the document.
  204. *
  205. * @param nm the name of the style to remove
  206. */
  207. public void removeStyle(String nm) {
  208. StyledDocument doc = getStyledDocument();
  209. doc.removeStyle(nm);
  210. }
  211. /**
  212. * Fetches a named non-null style previously added.
  213. *
  214. * @param nm the name of the style
  215. * @return the style
  216. */
  217. public Style getStyle(String nm) {
  218. StyledDocument doc = getStyledDocument();
  219. return doc.getStyle(nm);
  220. }
  221. /**
  222. * Sets the logical style to use for the paragraph at the
  223. * current caret position. If attributes aren't explicitly set
  224. * for character and paragraph attributes they will resolve
  225. * through the logical style assigned to the paragraph, which
  226. * in term may resolve through some hierarchy completely
  227. * independant of the element hierarchy in the document.
  228. * <p>
  229. * This method is thread safe, although most Swing methods
  230. * are not. Please see
  231. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  232. * and Swing</A> for more information.
  233. *
  234. * @param s the logical style to assign to the paragraph, or null for
  235. * no style
  236. */
  237. public void setLogicalStyle(Style s) {
  238. StyledDocument doc = getStyledDocument();
  239. doc.setLogicalStyle(getCaretPosition(), s);
  240. }
  241. /**
  242. * Fetches the logical style assigned to the paragraph
  243. * represented by the current position of the caret, or null.
  244. *
  245. * @return the style
  246. */
  247. public Style getLogicalStyle() {
  248. StyledDocument doc = getStyledDocument();
  249. return doc.getLogicalStyle(getCaretPosition());
  250. }
  251. /**
  252. * Fetches the character attributes in effect at the
  253. * current location of the caret, or null.
  254. *
  255. * @return the attributes, or null
  256. */
  257. public AttributeSet getCharacterAttributes() {
  258. StyledDocument doc = getStyledDocument();
  259. Element run = doc.getCharacterElement(getCaretPosition());
  260. if (run != null) {
  261. return run.getAttributes();
  262. }
  263. return null;
  264. }
  265. /**
  266. * Applies the given attributes to character
  267. * content. If there is a selection, the attributes
  268. * are applied to the selection range. If there
  269. * is no selection, the attributes are applied to
  270. * the input attribute set which defines the attributes
  271. * for any new text that gets inserted.
  272. * <p>
  273. * This method is thread safe, although most Swing methods
  274. * are not. Please see
  275. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  276. * and Swing</A> for more information.
  277. *
  278. * @param attr the attributes
  279. * @param replace if true, then replace the existing attributes first
  280. */
  281. public void setCharacterAttributes(AttributeSet attr, boolean replace) {
  282. int p0 = getSelectionStart();
  283. int p1 = getSelectionEnd();
  284. if (p0 != p1) {
  285. StyledDocument doc = getStyledDocument();
  286. doc.setCharacterAttributes(p0, p1 - p0, attr, replace);
  287. } else {
  288. MutableAttributeSet inputAttributes = getInputAttributes();
  289. if (replace) {
  290. inputAttributes.removeAttributes(inputAttributes);
  291. }
  292. inputAttributes.addAttributes(attr);
  293. }
  294. }
  295. /**
  296. * Fetches the current paragraph attributes in effect
  297. * at the location of the caret, or null if none.
  298. *
  299. * @return the attributes
  300. */
  301. public AttributeSet getParagraphAttributes() {
  302. StyledDocument doc = getStyledDocument();
  303. Element paragraph = doc.getParagraphElement(getCaretPosition());
  304. if (paragraph != null) {
  305. return paragraph.getAttributes();
  306. }
  307. return null;
  308. }
  309. /**
  310. * Applies the given attributes to paragraphs. If
  311. * there is a selection, the attributes are applied
  312. * to the paragraphs that intersect the selection.
  313. * if there is no selection, the attributes are applied
  314. * to the paragraph at the current caret position.
  315. * <p>
  316. * This method is thread safe, although most Swing methods
  317. * are not. Please see
  318. * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
  319. * and Swing</A> for more information.
  320. *
  321. * @param attr the non-null attributes
  322. * @param replace if true, replace the existing attributes first
  323. */
  324. public void setParagraphAttributes(AttributeSet attr, boolean replace) {
  325. int p0 = getSelectionStart();
  326. int p1 = getSelectionEnd();
  327. StyledDocument doc = getStyledDocument();
  328. doc.setParagraphAttributes(p0, p1 - p0, attr, replace);
  329. }
  330. /**
  331. * Gets the input attributes for the pane.
  332. *
  333. * @return the attributes
  334. */
  335. public MutableAttributeSet getInputAttributes() {
  336. return getStyledEditorKit().getInputAttributes();
  337. }
  338. /**
  339. * Gets the editor kit.
  340. *
  341. * @return the editor kit.
  342. */
  343. protected final StyledEditorKit getStyledEditorKit() {
  344. return (StyledEditorKit) getEditorKit();
  345. }
  346. /**
  347. * @see #getUIClassID
  348. * @see #readObject
  349. */
  350. private static final String uiClassID = "TextPaneUI";
  351. /**
  352. * See readObject() and writeObject() in JComponent for more
  353. * information about serialization in Swing.
  354. */
  355. private void writeObject(ObjectOutputStream s) throws IOException {
  356. s.defaultWriteObject();
  357. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  358. ui.installUI(this);
  359. }
  360. }
  361. // --- JEditorPane ------------------------------------
  362. /**
  363. * Creates the EditorKit to use by default. This
  364. * is implemented to return text.StyledEditorKit.
  365. *
  366. * @return the editor kit
  367. */
  368. protected EditorKit createDefaultEditorKit() {
  369. return new StyledEditorKit();
  370. }
  371. /**
  372. * Sets the currently installed kit for handling
  373. * content. This is the bound property that
  374. * establishes the content type of the editor.
  375. *
  376. * @param kit the desired editor behavior.
  377. * @exception IllegalArgumentException if kit is not a text.StyledEditorKit
  378. */
  379. public final void setEditorKit(EditorKit kit) {
  380. if (kit instanceof StyledEditorKit) {
  381. super.setEditorKit(kit);
  382. } else {
  383. throw new IllegalArgumentException("Must be StyledEditorKit");
  384. }
  385. }
  386. // --- Scrollable ----------------------------------------
  387. /**
  388. * Returns true if a viewport should always force the width of this
  389. * Scrollable to match the width of the viewport.
  390. *
  391. * @return true if a viewport should force the Scrollables width to match its own.
  392. */
  393. public boolean getScrollableTracksViewportWidth() {
  394. return true;
  395. }
  396. /**
  397. * Returns a string representation of this JTextPane. This method
  398. * is intended to be used only for debugging purposes, and the
  399. * content and format of the returned string may vary between
  400. * implementations. The returned string may be empty but may not
  401. * be <code>null</code>.
  402. *
  403. * @return a string representation of this JTextPane.
  404. */
  405. protected String paramString() {
  406. return super.paramString();
  407. }
  408. }