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