1. /*
  2. * @(#)StyledEditorKit.java 1.33 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.text;
  11. import java.io.*;
  12. import java.awt.*;
  13. import java.awt.event.ActionEvent;
  14. import java.beans.PropertyChangeEvent;
  15. import java.beans.PropertyChangeListener;
  16. import javax.swing.event.*;
  17. import javax.swing.Action;
  18. import javax.swing.JEditorPane;
  19. import javax.swing.KeyStroke;
  20. /**
  21. * This is the set of things needed by a text component
  22. * to be a reasonably functioning editor for some <em>type</em>
  23. * of text document. This implementation provides a default
  24. * implementation which treats text as styled text and
  25. * provides a minimal set of actions for editing styled text.
  26. *
  27. * @author Timothy Prinzing
  28. * @version 1.33 02/02/00
  29. */
  30. public class StyledEditorKit extends DefaultEditorKit {
  31. /**
  32. * Gets the input attributes for the pane. When
  33. * the caret moves and there is no selection, the
  34. * input attributes are automatically mutated to
  35. * reflect the character attributes of the current
  36. * caret location. The styled editing actions
  37. * use the input attributes to carry out their
  38. * actions.
  39. *
  40. * @return the attribute set
  41. */
  42. public MutableAttributeSet getInputAttributes() {
  43. return inputAttributes;
  44. }
  45. /**
  46. * Fetches the element representing the current
  47. * run of character attributes for the caret.
  48. *
  49. * @return the element
  50. */
  51. public Element getCharacterAttributeRun() {
  52. return currentRun;
  53. }
  54. // --- EditorKit methods ---------------------------
  55. /**
  56. * Create a copy of the editor kit. This
  57. * allows an implementation to serve as a prototype
  58. * for others, so that they can be quickly created.
  59. *
  60. * @return the copy
  61. */
  62. public Object clone() {
  63. return new StyledEditorKit();
  64. }
  65. /**
  66. * Fetches the command list for the editor. This is
  67. * the list of commands supported by the superclass
  68. * augmented by the collection of commands defined
  69. * locally for style operations.
  70. *
  71. * @return the command list
  72. */
  73. public Action[] getActions() {
  74. return TextAction.augmentList(super.getActions(), this.defaultActions);
  75. }
  76. /**
  77. * Creates an uninitialized text storage model
  78. * that is appropriate for this type of editor.
  79. *
  80. * @return the model
  81. */
  82. public Document createDefaultDocument() {
  83. return new DefaultStyledDocument();
  84. }
  85. /**
  86. * Called when the kit is being installed into
  87. * a JEditorPane.
  88. *
  89. * @param c the JEditorPane
  90. */
  91. public void install(JEditorPane c) {
  92. c.addCaretListener(inputAttributeUpdater);
  93. c.addPropertyChangeListener(inputAttributeUpdater);
  94. Caret caret = c.getCaret();
  95. if (caret != null) {
  96. inputAttributeUpdater.updateInputAttributes
  97. (caret.getDot(), caret.getMark(), c);
  98. }
  99. }
  100. /**
  101. * Called when the kit is being removed from the
  102. * JEditorPane. This is used to unregister any
  103. * listeners that were attached.
  104. *
  105. * @param c the JEditorPane
  106. */
  107. public void deinstall(JEditorPane c) {
  108. c.removeCaretListener(inputAttributeUpdater);
  109. c.removePropertyChangeListener(inputAttributeUpdater);
  110. // remove references to current document so it can be collected.
  111. currentRun = null;
  112. currentParagraph = null;
  113. }
  114. /**
  115. * Fetches a factory that is suitable for producing
  116. * views of any models that are produced by this
  117. * kit. This is implemented to return View implementations
  118. * for the following kinds of elements:
  119. * <ul>
  120. * <li>AbstractDocument.ContentElementName
  121. * <li>AbstractDocument.ParagraphElementName
  122. * <li>AbstractDocument.SectionElementName
  123. * <li>StyleConstants.ComponentElementName
  124. * <li>StyleConstants.IconElementName
  125. * </ul>
  126. *
  127. * @return the factory
  128. */
  129. public ViewFactory getViewFactory() {
  130. return defaultFactory;
  131. }
  132. private static final ViewFactory defaultFactory = new StyledViewFactory();
  133. Element currentRun;
  134. Element currentParagraph;
  135. /**
  136. * This is the set of attributes used to store the
  137. * input attributes.
  138. */
  139. MutableAttributeSet inputAttributes = new SimpleAttributeSet() {
  140. public AttributeSet getResolveParent() {
  141. return (currentParagraph != null) ? currentParagraph.getAttributes() : null;
  142. }
  143. public Object clone() {
  144. return new SimpleAttributeSet(this);
  145. }
  146. };
  147. /**
  148. * This listener will be attached to the caret of
  149. * the text component that the EditorKit gets installed
  150. * into. This should keep the input attributes updated
  151. * for use by the styled actions.
  152. */
  153. private AttributeTracker inputAttributeUpdater = new AttributeTracker();
  154. /**
  155. * Tracks caret movement and keeps the input attributes set
  156. * to reflect the current set of attribute definitions at the
  157. * caret position.
  158. * <p>This implements PropertyChangeListener to update the
  159. * input attributes when the Document changes, as if the Document
  160. * changes the attributes will almost certainly change.
  161. */
  162. class AttributeTracker implements CaretListener, PropertyChangeListener, Serializable {
  163. /**
  164. * Updates the attributes. <code>dot</code> and <code>mark</code>
  165. * mark give the positions of the selection in <code>c</code>.
  166. */
  167. void updateInputAttributes(int dot, int mark, JTextComponent c) {
  168. // EditorKit might not have installed the StyledDocument yet.
  169. Document aDoc = c.getDocument();
  170. if (!(aDoc instanceof StyledDocument)) {
  171. return ;
  172. }
  173. int start = Math.min(dot, mark);
  174. // record current character attributes.
  175. StyledDocument doc = (StyledDocument)aDoc;
  176. // If nothing is selected, get the attributes from the character
  177. // before the start of the selection, otherwise get the attributes
  178. // from the character element at the start of the selection.
  179. Element run;
  180. currentParagraph = doc.getParagraphElement(start);
  181. if (currentParagraph.getStartOffset() == start || dot != mark) {
  182. // Get the attributes from the character at the selection
  183. // if in a different paragrah!
  184. run = doc.getCharacterElement(start);
  185. }
  186. else {
  187. run = doc.getCharacterElement(Math.max(start-1, 0));
  188. }
  189. if (run != currentRun) {
  190. /*
  191. * PENDING(prinz) All attributes that represent a single
  192. * glyph position and can't be inserted into should be
  193. * removed from the input attributes... this requires
  194. * mixing in an interface to indicate that condition.
  195. * When we can add things again this logic needs to be
  196. * improved!!
  197. */
  198. currentRun = run;
  199. createInputAttributes(currentRun, getInputAttributes());
  200. }
  201. }
  202. public void propertyChange(PropertyChangeEvent evt) {
  203. Object newValue = evt.getNewValue();
  204. Object source = evt.getSource();
  205. if ((source instanceof JTextComponent) &&
  206. (newValue instanceof Document)) {
  207. // New document will have changed selection to 0,0.
  208. updateInputAttributes(0, 0, (JTextComponent)source);
  209. }
  210. }
  211. public void caretUpdate(CaretEvent e) {
  212. updateInputAttributes(e.getDot(), e.getMark(),
  213. (JTextComponent)e.getSource());
  214. }
  215. }
  216. /**
  217. * Copies the key/values in <code>element</code>s AttributeSet into
  218. * <code>set</code>. This does not copy component, icon, or element
  219. * names attributes. Subclasses may wish to refine what is and what
  220. * isn't copied here. But be sure to first remove all the attributes that
  221. * are in <code>set</code>.<p>
  222. * This is called anytime the caret moves over a different location.
  223. *
  224. */
  225. protected void createInputAttributes(Element element,
  226. MutableAttributeSet set) {
  227. set.removeAttributes(set);
  228. set.addAttributes(element.getAttributes());
  229. set.removeAttribute(StyleConstants.ComponentAttribute);
  230. set.removeAttribute(StyleConstants.IconAttribute);
  231. set.removeAttribute(AbstractDocument.ElementNameAttribute);
  232. set.removeAttribute(StyleConstants.ComposedTextAttribute);
  233. }
  234. // ---- default ViewFactory implementation ---------------------
  235. static class StyledViewFactory implements ViewFactory {
  236. public View create(Element elem) {
  237. String kind = elem.getName();
  238. if (kind != null) {
  239. if (kind.equals(AbstractDocument.ContentElementName)) {
  240. return new LabelView(elem);
  241. } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
  242. return new ParagraphView(elem);
  243. } else if (kind.equals(AbstractDocument.SectionElementName)) {
  244. return new BoxView(elem, View.Y_AXIS);
  245. } else if (kind.equals(StyleConstants.ComponentElementName)) {
  246. return new ComponentView(elem);
  247. } else if (kind.equals(StyleConstants.IconElementName)) {
  248. return new IconView(elem);
  249. }
  250. }
  251. // default to text display
  252. return new LabelView(elem);
  253. }
  254. }
  255. // --- Action implementations ---------------------------------
  256. private static final Action[] defaultActions = {
  257. new FontFamilyAction("font-family-SansSerif", "SansSerif"),
  258. new FontFamilyAction("font-family-Monospaced", "Monospaced"),
  259. new FontFamilyAction("font-family-Serif", "Serif"),
  260. new FontSizeAction("font-size-8", 8),
  261. new FontSizeAction("font-size-10", 10),
  262. new FontSizeAction("font-size-12", 12),
  263. new FontSizeAction("font-size-14", 14),
  264. new FontSizeAction("font-size-16", 16),
  265. new FontSizeAction("font-size-18", 18),
  266. new FontSizeAction("font-size-24", 24),
  267. new FontSizeAction("font-size-36", 36),
  268. new FontSizeAction("font-size-48", 48),
  269. new AlignmentAction("left-justify", StyleConstants.ALIGN_LEFT),
  270. new AlignmentAction("center-justify", StyleConstants.ALIGN_CENTER),
  271. new AlignmentAction("right-justify", StyleConstants.ALIGN_RIGHT),
  272. new BoldAction(),
  273. new ItalicAction(),
  274. new UnderlineAction()
  275. };
  276. /**
  277. * An action that assumes it's being fired on a JEditorPane
  278. * with a StyledEditorKit (or subclass) installed. This has
  279. * some convenience methods for causing character or paragraph
  280. * level attribute changes. The convenience methods will
  281. * throw an IllegalArgumentException if the assumption of
  282. * a StyledDocument, a JEditorPane, or a StyledEditorKit
  283. * fail to be true.
  284. * <p>
  285. * The component that gets acted upon by the action
  286. * will be the source of the ActionEvent if the source
  287. * can be narrowed to a JEditorPane type. If the source
  288. * can't be narrowed, the most recently focused text
  289. * component is changed. If neither of these are the
  290. * case, the action cannot be performed.
  291. * <p>
  292. * <strong>Warning:</strong>
  293. * Serialized objects of this class will not be compatible with
  294. * future Swing releases. The current serialization support is appropriate
  295. * for short term storage or RMI between applications running the same
  296. * version of Swing. A future release of Swing will provide support for
  297. * long term persistence.
  298. */
  299. public abstract static class StyledTextAction extends TextAction {
  300. /**
  301. * Creates a new StyledTextAction from a string action name.
  302. *
  303. * @param nm the name of the action
  304. */
  305. public StyledTextAction(String nm) {
  306. super(nm);
  307. }
  308. /**
  309. * Gets the target editor for an action.
  310. *
  311. * @param e the action event
  312. * @return the editor
  313. */
  314. protected final JEditorPane getEditor(ActionEvent e) {
  315. JTextComponent tcomp = getTextComponent(e);
  316. if (tcomp instanceof JEditorPane) {
  317. return (JEditorPane) tcomp;
  318. }
  319. return null;
  320. }
  321. /**
  322. * Gets the document associated with an editor pane.
  323. *
  324. * @param e the editor
  325. * @return the document
  326. * @exception IllegalArgumentException for the wrong document type
  327. */
  328. protected final StyledDocument getStyledDocument(JEditorPane e) {
  329. Document d = e.getDocument();
  330. if (d instanceof StyledDocument) {
  331. return (StyledDocument) d;
  332. }
  333. throw new IllegalArgumentException("document must be StyledDocument");
  334. }
  335. /**
  336. * Gets the editor kit associated with an editor pane.
  337. *
  338. * @param e the editor pane
  339. * @return the kit
  340. * @exception IllegalArgumentException for the wrong document type
  341. */
  342. protected final StyledEditorKit getStyledEditorKit(JEditorPane e) {
  343. EditorKit k = e.getEditorKit();
  344. if (k instanceof StyledEditorKit) {
  345. return (StyledEditorKit) k;
  346. }
  347. throw new IllegalArgumentException("EditorKit must be StyledEditorKit");
  348. }
  349. /**
  350. * Applies the given attributes to character
  351. * content. If there is a selection, the attributes
  352. * are applied to the selection range. If there
  353. * is no selection, the attributes are applied to
  354. * the input attribute set which defines the attributes
  355. * for any new text that gets inserted.
  356. *
  357. * @param editor the editor
  358. * @param attr the attributes
  359. * @param replace if true, then replace the existing attributes first
  360. */
  361. protected final void setCharacterAttributes(JEditorPane editor,
  362. AttributeSet attr, boolean replace) {
  363. int p0 = editor.getSelectionStart();
  364. int p1 = editor.getSelectionEnd();
  365. if (p0 != p1) {
  366. StyledDocument doc = getStyledDocument(editor);
  367. doc.setCharacterAttributes(p0, p1 - p0, attr, replace);
  368. }
  369. StyledEditorKit k = getStyledEditorKit(editor);
  370. MutableAttributeSet inputAttributes = k.getInputAttributes();
  371. if (replace) {
  372. inputAttributes.removeAttributes(inputAttributes);
  373. }
  374. inputAttributes.addAttributes(attr);
  375. }
  376. /**
  377. * Applies the given attributes to paragraphs. If
  378. * there is a selection, the attributes are applied
  379. * to the paragraphs that intersect the selection.
  380. * if there is no selection, the attributes are applied
  381. * to the paragraph at the current caret position.
  382. *
  383. * @param editor the editor
  384. * @param attr the attributes
  385. * @param replace if true, replace the existing attributes first
  386. */
  387. protected final void setParagraphAttributes(JEditorPane editor,
  388. AttributeSet attr, boolean replace) {
  389. int p0 = editor.getSelectionStart();
  390. int p1 = editor.getSelectionEnd();
  391. StyledDocument doc = getStyledDocument(editor);
  392. doc.setParagraphAttributes(p0, p1 - p0, attr, replace);
  393. }
  394. }
  395. /**
  396. * An action to set the font family in the associated
  397. * JEditorPane. This will use the family specified as
  398. * the command string on the ActionEvent if there is one,
  399. * otherwise the family that was initialized with will be used.
  400. * <p>
  401. * <strong>Warning:</strong>
  402. * Serialized objects of this class will not be compatible with
  403. * future Swing releases. The current serialization support is appropriate
  404. * for short term storage or RMI between applications running the same
  405. * version of Swing. A future release of Swing will provide support for
  406. * long term persistence.
  407. */
  408. public static class FontFamilyAction extends StyledTextAction {
  409. /**
  410. * Creates a new FontFamilyAction.
  411. *
  412. * @param nm the action name
  413. * @param family the font family
  414. */
  415. public FontFamilyAction(String nm, String family) {
  416. super(nm);
  417. this.family = family;
  418. }
  419. /**
  420. * Sets the font family.
  421. *
  422. * @param e the event
  423. */
  424. public void actionPerformed(ActionEvent e) {
  425. JEditorPane editor = getEditor(e);
  426. if (editor != null) {
  427. String family = this.family;
  428. if ((e != null) && (e.getSource() == editor)) {
  429. String s = e.getActionCommand();
  430. if (s != null) {
  431. family = s;
  432. }
  433. }
  434. if (family != null) {
  435. MutableAttributeSet attr = new SimpleAttributeSet();
  436. StyleConstants.setFontFamily(attr, family);
  437. setCharacterAttributes(editor, attr, false);
  438. } else {
  439. Toolkit.getDefaultToolkit().beep();
  440. }
  441. }
  442. }
  443. private String family;
  444. }
  445. /**
  446. * An action to set the font size in the associated
  447. * JEditorPane. This will use the size specified as
  448. * the command string on the ActionEvent if there is one,
  449. * otherwise the size that was initialized with will be used.
  450. * <p>
  451. * <strong>Warning:</strong>
  452. * Serialized objects of this class will not be compatible with
  453. * future Swing releases. The current serialization support is appropriate
  454. * for short term storage or RMI between applications running the same
  455. * version of Swing. A future release of Swing will provide support for
  456. * long term persistence.
  457. */
  458. public static class FontSizeAction extends StyledTextAction {
  459. /**
  460. * Creates a new FontSizeAction.
  461. *
  462. * @param nm the action name
  463. * @param size the font size
  464. */
  465. public FontSizeAction(String nm, int size) {
  466. super(nm);
  467. this.size = size;
  468. }
  469. /**
  470. * Sets the font size.
  471. *
  472. * @param e the action event
  473. */
  474. public void actionPerformed(ActionEvent e) {
  475. JEditorPane editor = getEditor(e);
  476. if (editor != null) {
  477. int size = this.size;
  478. if ((e != null) && (e.getSource() == editor)) {
  479. String s = e.getActionCommand();
  480. try {
  481. size = Integer.parseInt(s, 10);
  482. } catch (NumberFormatException nfe) {
  483. }
  484. }
  485. if (size != 0) {
  486. MutableAttributeSet attr = new SimpleAttributeSet();
  487. StyleConstants.setFontSize(attr, size);
  488. setCharacterAttributes(editor, attr, false);
  489. } else {
  490. Toolkit.getDefaultToolkit().beep();
  491. }
  492. }
  493. }
  494. private int size;
  495. }
  496. /**
  497. * An action to set foreground color. This sets the
  498. * <code>StyleConstants.Foreground</code> attribute for the
  499. * currently selected range of the target JEditorPane.
  500. * This is done by calling
  501. * <code>StyledDocument.setCharacterAttributes</code>
  502. * on the styled document associated with the target
  503. * JEditorPane.
  504. * <p>
  505. * If the target text component is specified as the
  506. * source of the ActionEvent and there is a command string,
  507. * the command string will be interpreted as the foreground
  508. * color. It will be interpreted by called
  509. * <code>Color.decode</code>, and should therefore be
  510. * legal input for that method.
  511. * <p>
  512. * <strong>Warning:</strong>
  513. * Serialized objects of this class will not be compatible with
  514. * future Swing releases. The current serialization support is appropriate
  515. * for short term storage or RMI between applications running the same
  516. * version of Swing. A future release of Swing will provide support for
  517. * long term persistence.
  518. */
  519. public static class ForegroundAction extends StyledTextAction {
  520. /**
  521. * Creates a new ForegroundAction.
  522. *
  523. * @param nm the action name
  524. * @param fg the foreground color
  525. */
  526. public ForegroundAction(String nm, Color fg) {
  527. super(nm);
  528. this.fg = fg;
  529. }
  530. /**
  531. * Sets the foreground color.
  532. *
  533. * @param e the action event
  534. */
  535. public void actionPerformed(ActionEvent e) {
  536. JEditorPane editor = getEditor(e);
  537. if (editor != null) {
  538. Color fg = this.fg;
  539. if ((e != null) && (e.getSource() == editor)) {
  540. String s = e.getActionCommand();
  541. try {
  542. fg = Color.decode(s);
  543. } catch (NumberFormatException nfe) {
  544. }
  545. }
  546. if (fg != null) {
  547. MutableAttributeSet attr = new SimpleAttributeSet();
  548. StyleConstants.setForeground(attr, fg);
  549. setCharacterAttributes(editor, attr, false);
  550. } else {
  551. Toolkit.getDefaultToolkit().beep();
  552. }
  553. }
  554. }
  555. private Color fg;
  556. }
  557. /**
  558. * An action to set paragraph alignment. This sets the
  559. * <code>StyleConstants.Alignment</code> attribute for the
  560. * currently selected range of the target JEditorPane.
  561. * This is done by calling
  562. * <code>StyledDocument.setParagraphAttributes</code>
  563. * on the styled document associated with the target
  564. * JEditorPane.
  565. * <p>
  566. * If the target text component is specified as the
  567. * source of the ActionEvent and there is a command string,
  568. * the command string will be interpreted as an integer
  569. * that should be one of the legal values for the
  570. * <code>StyleConstants.Alignment</code> attribute.
  571. * <p>
  572. * <strong>Warning:</strong>
  573. * Serialized objects of this class will not be compatible with
  574. * future Swing releases. The current serialization support is appropriate
  575. * for short term storage or RMI between applications running the same
  576. * version of Swing. A future release of Swing will provide support for
  577. * long term persistence.
  578. */
  579. public static class AlignmentAction extends StyledTextAction {
  580. /**
  581. * Creates a new AlignmentAction.
  582. *
  583. * @param nm the action name
  584. * @param a the alignment >= 0
  585. */
  586. public AlignmentAction(String nm, int a) {
  587. super(nm);
  588. this.a = a;
  589. }
  590. /**
  591. * Sets the alignment.
  592. *
  593. * @param e the action event
  594. */
  595. public void actionPerformed(ActionEvent e) {
  596. JEditorPane editor = getEditor(e);
  597. if (editor != null) {
  598. int a = this.a;
  599. if ((e != null) && (e.getSource() == editor)) {
  600. String s = e.getActionCommand();
  601. try {
  602. a = Integer.parseInt(s, 10);
  603. } catch (NumberFormatException nfe) {
  604. }
  605. }
  606. MutableAttributeSet attr = new SimpleAttributeSet();
  607. StyleConstants.setAlignment(attr, a);
  608. setParagraphAttributes(editor, attr, false);
  609. }
  610. }
  611. private int a;
  612. }
  613. /**
  614. * An action to toggle the bold attribute.
  615. * <p>
  616. * <strong>Warning:</strong>
  617. * Serialized objects of this class will not be compatible with
  618. * future Swing releases. The current serialization support is appropriate
  619. * for short term storage or RMI between applications running the same
  620. * version of Swing. A future release of Swing will provide support for
  621. * long term persistence.
  622. */
  623. public static class BoldAction extends StyledTextAction {
  624. /**
  625. * Constructs a new BoldAction.
  626. */
  627. public BoldAction() {
  628. super("font-bold");
  629. }
  630. /**
  631. * Toggles the bold attribute.
  632. *
  633. * @param e the action event
  634. */
  635. public void actionPerformed(ActionEvent e) {
  636. JEditorPane editor = getEditor(e);
  637. if (editor != null) {
  638. StyledEditorKit kit = getStyledEditorKit(editor);
  639. MutableAttributeSet attr = kit.getInputAttributes();
  640. boolean bold = (StyleConstants.isBold(attr)) ? false : true;
  641. SimpleAttributeSet sas = new SimpleAttributeSet();
  642. StyleConstants.setBold(sas, bold);
  643. setCharacterAttributes(editor, sas, false);
  644. }
  645. }
  646. }
  647. /**
  648. * An action to toggle the italic attribute.
  649. * <p>
  650. * <strong>Warning:</strong>
  651. * Serialized objects of this class will not be compatible with
  652. * future Swing releases. The current serialization support is appropriate
  653. * for short term storage or RMI between applications running the same
  654. * version of Swing. A future release of Swing will provide support for
  655. * long term persistence.
  656. */
  657. public static class ItalicAction extends StyledTextAction {
  658. /**
  659. * Constructs a new ItalicAction.
  660. */
  661. public ItalicAction() {
  662. super("font-italic");
  663. }
  664. /**
  665. * Toggles the italic attribute.
  666. *
  667. * @param e the action event
  668. */
  669. public void actionPerformed(ActionEvent e) {
  670. JEditorPane editor = getEditor(e);
  671. if (editor != null) {
  672. StyledEditorKit kit = getStyledEditorKit(editor);
  673. MutableAttributeSet attr = kit.getInputAttributes();
  674. boolean italic = (StyleConstants.isItalic(attr)) ? false : true;
  675. SimpleAttributeSet sas = new SimpleAttributeSet();
  676. StyleConstants.setItalic(sas, italic);
  677. setCharacterAttributes(editor, sas, false);
  678. }
  679. }
  680. }
  681. /**
  682. * An action to toggle the underline attribute.
  683. * <p>
  684. * <strong>Warning:</strong>
  685. * Serialized objects of this class will not be compatible with
  686. * future Swing releases. The current serialization support is appropriate
  687. * for short term storage or RMI between applications running the same
  688. * version of Swing. A future release of Swing will provide support for
  689. * long term persistence.
  690. */
  691. public static class UnderlineAction extends StyledTextAction {
  692. /**
  693. * Constructs a new UnderlineAction.
  694. */
  695. public UnderlineAction() {
  696. super("font-underline");
  697. }
  698. /**
  699. * Toggles the Underline attribute.
  700. *
  701. * @param e the action event
  702. */
  703. public void actionPerformed(ActionEvent e) {
  704. JEditorPane editor = getEditor(e);
  705. if (editor != null) {
  706. StyledEditorKit kit = getStyledEditorKit(editor);
  707. MutableAttributeSet attr = kit.getInputAttributes();
  708. boolean underline = (StyleConstants.isUnderline(attr)) ? false : true;
  709. SimpleAttributeSet sas = new SimpleAttributeSet();
  710. StyleConstants.setUnderline(sas, underline);
  711. setCharacterAttributes(editor, sas, false);
  712. }
  713. }
  714. }
  715. }