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