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