1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.text; 26 27 import java.io.*; 28 import java.awt.*; 29 import java.awt.event.ActionEvent; 30 import java.beans.PropertyChangeEvent; 31 import java.beans.PropertyChangeListener; 32 import javax.swing.event.*; 33 import javax.swing.Action; 34 import javax.swing.JEditorPane; 35 import javax.swing.KeyStroke; 36 import javax.swing.UIManager; 37 38 /** 39 * This is the set of things needed by a text component 40 * to be a reasonably functioning editor for some <em>type</em> 41 * of text document. This implementation provides a default 42 * implementation which treats text as styled text and 43 * provides a minimal set of actions for editing styled text. 44 * 45 * @author Timothy Prinzing 46 */ 47 public class StyledEditorKit extends DefaultEditorKit { 48 49 /** 50 * Creates a new EditorKit used for styled documents. 51 */ 52 public StyledEditorKit() { 53 createInputAttributeUpdated(); 54 createInputAttributes(); 55 } 56 57 /** 58 * Gets the input attributes for the pane. When 59 * the caret moves and there is no selection, the 60 * input attributes are automatically mutated to 61 * reflect the character attributes of the current 62 * caret location. The styled editing actions 63 * use the input attributes to carry out their 64 * actions. 65 * 66 * @return the attribute set 67 */ 68 public MutableAttributeSet getInputAttributes() { 69 return inputAttributes; 70 } 71 72 /** 73 * Fetches the element representing the current 74 * run of character attributes for the caret. 75 * 76 * @return the element 77 */ 78 public Element getCharacterAttributeRun() { 79 return currentRun; 80 } 81 82 // --- EditorKit methods --------------------------- 83 84 /** 85 * Fetches the command list for the editor. This is 86 * the list of commands supported by the superclass 87 * augmented by the collection of commands defined 88 * locally for style operations. 89 * 90 * @return the command list 91 */ 92 public Action[] getActions() { 93 return TextAction.augmentList(super.getActions(), StyledEditorKit.defaultActions); 94 } 95 96 /** 97 * Creates an uninitialized text storage model 98 * that is appropriate for this type of editor. 99 * 100 * @return the model 101 */ 102 public Document createDefaultDocument() { 103 return new DefaultStyledDocument(); 104 } 105 106 /** 107 * Called when the kit is being installed into 108 * a JEditorPane. 109 * 110 * @param c the JEditorPane 111 */ 112 public void install(JEditorPane c) { 113 c.addCaretListener(inputAttributeUpdater); 114 c.addPropertyChangeListener(inputAttributeUpdater); 115 Caret caret = c.getCaret(); 116 if (caret != null) { 117 inputAttributeUpdater.updateInputAttributes 118 (caret.getDot(), caret.getMark(), c); 119 } 120 } 121 122 /** 123 * Called when the kit is being removed from the 124 * JEditorPane. This is used to unregister any 125 * listeners that were attached. 126 * 127 * @param c the JEditorPane 128 */ 129 public void deinstall(JEditorPane c) { 130 c.removeCaretListener(inputAttributeUpdater); 131 c.removePropertyChangeListener(inputAttributeUpdater); 132 133 // remove references to current document so it can be collected. 134 currentRun = null; 135 currentParagraph = null; 136 } 137 138 /** 139 * Fetches a factory that is suitable for producing 140 * views of any models that are produced by this 141 * kit. This is implemented to return View implementations 142 * for the following kinds of elements: 143 * <ul> 144 * <li>AbstractDocument.ContentElementName 145 * <li>AbstractDocument.ParagraphElementName 146 * <li>AbstractDocument.SectionElementName 147 * <li>StyleConstants.ComponentElementName 148 * <li>StyleConstants.IconElementName 149 * </ul> 150 * 151 * @return the factory 152 */ 153 public ViewFactory getViewFactory() { 154 return defaultFactory; 155 } 156 157 /** 158 * Creates a copy of the editor kit. 159 * 160 * @return the copy 161 */ 162 public Object clone() { 163 StyledEditorKit o = (StyledEditorKit)super.clone(); 164 o.currentRun = o.currentParagraph = null; 165 o.createInputAttributeUpdated(); 166 o.createInputAttributes(); 167 return o; 168 } 169 170 /** 171 * Creates the AttributeSet used for the selection. 172 */ 173 private void createInputAttributes() { 174 inputAttributes = new SimpleAttributeSet() { 175 public AttributeSet getResolveParent() { 176 return (currentParagraph != null) ? 177 currentParagraph.getAttributes() : null; 178 } 179 180 public Object clone() { 181 return new SimpleAttributeSet(this); 182 } 183 }; 184 } 185 186 /** 187 * Creates a new <code>AttributeTracker</code>. 188 */ 189 private void createInputAttributeUpdated() { 190 inputAttributeUpdater = new AttributeTracker(); 191 } 192 193 194 private static final ViewFactory defaultFactory = new StyledViewFactory(); 195 196 Element currentRun; 197 Element currentParagraph; 198 199 /** 200 * This is the set of attributes used to store the 201 * input attributes. 202 */ 203 MutableAttributeSet inputAttributes; 204 205 /** 206 * This listener will be attached to the caret of 207 * the text component that the EditorKit gets installed 208 * into. This should keep the input attributes updated 209 * for use by the styled actions. 210 */ 211 private AttributeTracker inputAttributeUpdater; 212 213 /** 214 * Tracks caret movement and keeps the input attributes set 215 * to reflect the current set of attribute definitions at the 216 * caret position. 217 * <p>This implements PropertyChangeListener to update the 218 * input attributes when the Document changes, as if the Document 219 * changes the attributes will almost certainly change. 220 */ 221 class AttributeTracker implements CaretListener, PropertyChangeListener, Serializable { 222 223 /** 224 * Updates the attributes. <code>dot</code> and <code>mark</code> 225 * mark give the positions of the selection in <code>c</code>. 226 */ 227 void updateInputAttributes(int dot, int mark, JTextComponent c) { 228 // EditorKit might not have installed the StyledDocument yet. 229 Document aDoc = c.getDocument(); 230 if (!(aDoc instanceof StyledDocument)) { 231 return ; 232 } 233 int start = Math.min(dot, mark); 234 // record current character attributes. 235 StyledDocument doc = (StyledDocument)aDoc; 236 // If nothing is selected, get the attributes from the character 237 // before the start of the selection, otherwise get the attributes 238 // from the character element at the start of the selection. 239 Element run; 240 currentParagraph = doc.getParagraphElement(start); 241 if (currentParagraph.getStartOffset() == start || dot != mark) { 242 // Get the attributes from the character at the selection 243 // if in a different paragrah! 244 run = doc.getCharacterElement(start); 245 } 246 else { 247 run = doc.getCharacterElement(Math.max(start-1, 0)); 248 } 249 if (run != currentRun) { 250 /* 251 * PENDING(prinz) All attributes that represent a single 252 * glyph position and can't be inserted into should be 253 * removed from the input attributes... this requires 254 * mixing in an interface to indicate that condition. 255 * When we can add things again this logic needs to be 256 * improved!! 257 */ 258 currentRun = run; 259 createInputAttributes(currentRun, getInputAttributes()); 260 } 261 } 262 263 public void propertyChange(PropertyChangeEvent evt) { 264 Object newValue = evt.getNewValue(); 265 Object source = evt.getSource(); 266 267 if ((source instanceof JTextComponent) && 268 (newValue instanceof Document)) { 269 // New document will have changed selection to 0,0. 270 updateInputAttributes(0, 0, (JTextComponent)source); 271 } 272 } 273 274 public void caretUpdate(CaretEvent e) { 275 updateInputAttributes(e.getDot(), e.getMark(), 276 (JTextComponent)e.getSource()); 277 } 278 } 279 280 /** 281 * Copies the key/values in <code>element</code>s AttributeSet into 282 * <code>set</code>. This does not copy component, icon, or element 283 * names attributes. Subclasses may wish to refine what is and what 284 * isn't copied here. But be sure to first remove all the attributes that 285 * are in <code>set</code>.<p> 286 * This is called anytime the caret moves over a different location. 287 * 288 */ 289 protected void createInputAttributes(Element element, 290 MutableAttributeSet set) { 291 if (element.getAttributes().getAttributeCount() > 0 292 || element.getEndOffset() - element.getStartOffset() > 1 293 || element.getEndOffset() < element.getDocument().getLength()) { 294 set.removeAttributes(set); 295 set.addAttributes(element.getAttributes()); 296 set.removeAttribute(StyleConstants.ComponentAttribute); 297 set.removeAttribute(StyleConstants.IconAttribute); 298 set.removeAttribute(AbstractDocument.ElementNameAttribute); 299 set.removeAttribute(StyleConstants.ComposedTextAttribute); 300 } 301 } 302 303 // ---- default ViewFactory implementation --------------------- 304 305 static class StyledViewFactory implements ViewFactory { 306 307 public View create(Element elem) { 308 String kind = elem.getName(); 309 if (kind != null) { 310 if (kind.equals(AbstractDocument.ContentElementName)) { 311 return new LabelView(elem); 312 } else if (kind.equals(AbstractDocument.ParagraphElementName)) { 313 return new ParagraphView(elem); 314 } else if (kind.equals(AbstractDocument.SectionElementName)) { 315 return new BoxView(elem, View.Y_AXIS); 316 } else if (kind.equals(StyleConstants.ComponentElementName)) { 317 return new ComponentView(elem); 318 } else if (kind.equals(StyleConstants.IconElementName)) { 319 return new IconView(elem); 320 } 321 } 322 323 // default to text display 324 return new LabelView(elem); 325 } 326 327 } 328 329 // --- Action implementations --------------------------------- 330 331 private static final Action[] defaultActions = { 332 new FontFamilyAction("font-family-SansSerif", "SansSerif"), 333 new FontFamilyAction("font-family-Monospaced", "Monospaced"), 334 new FontFamilyAction("font-family-Serif", "Serif"), 335 new FontSizeAction("font-size-8", 8), 336 new FontSizeAction("font-size-10", 10), 337 new FontSizeAction("font-size-12", 12), 338 new FontSizeAction("font-size-14", 14), 339 new FontSizeAction("font-size-16", 16), 340 new FontSizeAction("font-size-18", 18), 341 new FontSizeAction("font-size-24", 24), 342 new FontSizeAction("font-size-36", 36), 343 new FontSizeAction("font-size-48", 48), 344 new AlignmentAction("left-justify", StyleConstants.ALIGN_LEFT), 345 new AlignmentAction("center-justify", StyleConstants.ALIGN_CENTER), 346 new AlignmentAction("right-justify", StyleConstants.ALIGN_RIGHT), 347 new BoldAction(), 348 new ItalicAction(), 349 new StyledInsertBreakAction(), 350 new UnderlineAction() 351 }; 352 353 /** 354 * An action that assumes it's being fired on a JEditorPane 355 * with a StyledEditorKit (or subclass) installed. This has 356 * some convenience methods for causing character or paragraph 357 * level attribute changes. The convenience methods will 358 * throw an IllegalArgumentException if the assumption of 359 * a StyledDocument, a JEditorPane, or a StyledEditorKit 360 * fail to be true. 361 * <p> 362 * The component that gets acted upon by the action 363 * will be the source of the ActionEvent if the source 364 * can be narrowed to a JEditorPane type. If the source 365 * can't be narrowed, the most recently focused text 366 * component is changed. If neither of these are the 367 * case, the action cannot be performed. 368 * <p> 369 * <strong>Warning:</strong> 370 * Serialized objects of this class will not be compatible with 371 * future Swing releases. The current serialization support is 372 * appropriate for short term storage or RMI between applications running 373 * the same version of Swing. As of 1.4, support for long term storage 374 * of all JavaBeans™ 375 * has been added to the <code>java.beans</code> package. 376 * Please see {@link java.beans.XMLEncoder}. 377 */ 378 public abstract static class StyledTextAction extends TextAction { 379 380 /** 381 * Creates a new StyledTextAction from a string action name. 382 * 383 * @param nm the name of the action 384 */ 385 public StyledTextAction(String nm) { 386 super(nm); 387 } 388 389 /** 390 * Gets the target editor for an action. 391 * 392 * @param e the action event 393 * @return the editor 394 */ 395 protected final JEditorPane getEditor(ActionEvent e) { 396 JTextComponent tcomp = getTextComponent(e); 397 if (tcomp instanceof JEditorPane) { 398 return (JEditorPane) tcomp; 399 } 400 return null; 401 } 402 403 /** 404 * Gets the document associated with an editor pane. 405 * 406 * @param e the editor 407 * @return the document 408 * @exception IllegalArgumentException for the wrong document type 409 */ 410 protected final StyledDocument getStyledDocument(JEditorPane e) { 411 Document d = e.getDocument(); 412 if (d instanceof StyledDocument) { 413 return (StyledDocument) d; 414 } 415 throw new IllegalArgumentException("document must be StyledDocument"); 416 } 417 418 /** 419 * Gets the editor kit associated with an editor pane. 420 * 421 * @param e the editor pane 422 * @return the kit 423 * @exception IllegalArgumentException for the wrong document type 424 */ 425 protected final StyledEditorKit getStyledEditorKit(JEditorPane e) { 426 EditorKit k = e.getEditorKit(); 427 if (k instanceof StyledEditorKit) { 428 return (StyledEditorKit) k; 429 } 430 throw new IllegalArgumentException("EditorKit must be StyledEditorKit"); 431 } 432 433 /** 434 * Applies the given attributes to character 435 * content. If there is a selection, the attributes 436 * are applied to the selection range. If there 437 * is no selection, the attributes are applied to 438 * the input attribute set which defines the attributes 439 * for any new text that gets inserted. 440 * 441 * @param editor the editor 442 * @param attr the attributes 443 * @param replace if true, then replace the existing attributes first 444 */ 445 protected final void setCharacterAttributes(JEditorPane editor, 446 AttributeSet attr, boolean replace) { 447 int p0 = editor.getSelectionStart(); 448 int p1 = editor.getSelectionEnd(); 449 if (p0 != p1) { 450 StyledDocument doc = getStyledDocument(editor); 451 doc.setCharacterAttributes(p0, p1 - p0, attr, replace); 452 } 453 StyledEditorKit k = getStyledEditorKit(editor); 454 MutableAttributeSet inputAttributes = k.getInputAttributes(); 455 if (replace) { 456 inputAttributes.removeAttributes(inputAttributes); 457 } 458 inputAttributes.addAttributes(attr); 459 } 460 461 /** 462 * Applies the given attributes to paragraphs. If 463 * there is a selection, the attributes are applied 464 * to the paragraphs that intersect the selection. 465 * if there is no selection, the attributes are applied 466 * to the paragraph at the current caret position. 467 * 468 * @param editor the editor 469 * @param attr the attributes 470 * @param replace if true, replace the existing attributes first 471 */ 472 protected final void setParagraphAttributes(JEditorPane editor, 473 AttributeSet attr, boolean replace) { 474 int p0 = editor.getSelectionStart(); 475 int p1 = editor.getSelectionEnd(); 476 StyledDocument doc = getStyledDocument(editor); 477 doc.setParagraphAttributes(p0, p1 - p0, attr, replace); 478 } 479 480 } 481 482 /** 483 * An action to set the font family in the associated 484 * JEditorPane. This will use the family specified as 485 * the command string on the ActionEvent if there is one, 486 * otherwise the family that was initialized with will be used. 487 * <p> 488 * <strong>Warning:</strong> 489 * Serialized objects of this class will not be compatible with 490 * future Swing releases. The current serialization support is 491 * appropriate for short term storage or RMI between applications running 492 * the same version of Swing. As of 1.4, support for long term storage 493 * of all JavaBeans™ 494 * has been added to the <code>java.beans</code> package. 495 * Please see {@link java.beans.XMLEncoder}. 496 */ 497 public static class FontFamilyAction extends StyledTextAction { 498 499 /** 500 * Creates a new FontFamilyAction. 501 * 502 * @param nm the action name 503 * @param family the font family 504 */ 505 public FontFamilyAction(String nm, String family) { 506 super(nm); 507 this.family = family; 508 } 509 510 /** 511 * Sets the font family. 512 * 513 * @param e the event 514 */ 515 public void actionPerformed(ActionEvent e) { 516 JEditorPane editor = getEditor(e); 517 if (editor != null) { 518 String family = this.family; 519 if ((e != null) && (e.getSource() == editor)) { 520 String s = e.getActionCommand(); 521 if (s != null) { 522 family = s; 523 } 524 } 525 if (family != null) { 526 MutableAttributeSet attr = new SimpleAttributeSet(); 527 StyleConstants.setFontFamily(attr, family); 528 setCharacterAttributes(editor, attr, false); 529 } else { 530 UIManager.getLookAndFeel().provideErrorFeedback(editor); 531 } 532 } 533 } 534 535 private String family; 536 } 537 538 /** 539 * An action to set the font size in the associated 540 * JEditorPane. This will use the size specified as 541 * the command string on the ActionEvent if there is one, 542 * otherwise the size that was initialized with will be used. 543 * <p> 544 * <strong>Warning:</strong> 545 * Serialized objects of this class will not be compatible with 546 * future Swing releases. The current serialization support is 547 * appropriate for short term storage or RMI between applications running 548 * the same version of Swing. As of 1.4, support for long term storage 549 * of all JavaBeans™ 550 * has been added to the <code>java.beans</code> package. 551 * Please see {@link java.beans.XMLEncoder}. 552 */ 553 public static class FontSizeAction extends StyledTextAction { 554 555 /** 556 * Creates a new FontSizeAction. 557 * 558 * @param nm the action name 559 * @param size the font size 560 */ 561 public FontSizeAction(String nm, int size) { 562 super(nm); 563 this.size = size; 564 } 565 566 /** 567 * Sets the font size. 568 * 569 * @param e the action event 570 */ 571 public void actionPerformed(ActionEvent e) { 572 JEditorPane editor = getEditor(e); 573 if (editor != null) { 574 int size = this.size; 575 if ((e != null) && (e.getSource() == editor)) { 576 String s = e.getActionCommand(); 577 try { 578 size = Integer.parseInt(s, 10); 579 } catch (NumberFormatException nfe) { 580 } 581 } 582 if (size != 0) { 583 MutableAttributeSet attr = new SimpleAttributeSet(); 584 StyleConstants.setFontSize(attr, size); 585 setCharacterAttributes(editor, attr, false); 586 } else { 587 UIManager.getLookAndFeel().provideErrorFeedback(editor); 588 } 589 } 590 } 591 592 private int size; 593 } 594 595 /** 596 * An action to set foreground color. This sets the 597 * <code>StyleConstants.Foreground</code> attribute for the 598 * currently selected range of the target JEditorPane. 599 * This is done by calling 600 * <code>StyledDocument.setCharacterAttributes</code> 601 * on the styled document associated with the target 602 * JEditorPane. 603 * <p> 604 * If the target text component is specified as the 605 * source of the ActionEvent and there is a command string, 606 * the command string will be interpreted as the foreground 607 * color. It will be interpreted by called 608 * <code>Color.decode</code>, and should therefore be 609 * legal input for that method. 610 * <p> 611 * <strong>Warning:</strong> 612 * Serialized objects of this class will not be compatible with 613 * future Swing releases. The current serialization support is 614 * appropriate for short term storage or RMI between applications running 615 * the same version of Swing. As of 1.4, support for long term storage 616 * of all JavaBeans™ 617 * has been added to the <code>java.beans</code> package. 618 * Please see {@link java.beans.XMLEncoder}. 619 */ 620 public static class ForegroundAction extends StyledTextAction { 621 622 /** 623 * Creates a new ForegroundAction. 624 * 625 * @param nm the action name 626 * @param fg the foreground color 627 */ 628 public ForegroundAction(String nm, Color fg) { 629 super(nm); 630 this.fg = fg; 631 } 632 633 /** 634 * Sets the foreground color. 635 * 636 * @param e the action event 637 */ 638 public void actionPerformed(ActionEvent e) { 639 JEditorPane editor = getEditor(e); 640 if (editor != null) { 641 Color fg = this.fg; 642 if ((e != null) && (e.getSource() == editor)) { 643 String s = e.getActionCommand(); 644 try { 645 fg = Color.decode(s); 646 } catch (NumberFormatException nfe) { 647 } 648 } 649 if (fg != null) { 650 MutableAttributeSet attr = new SimpleAttributeSet(); 651 StyleConstants.setForeground(attr, fg); 652 setCharacterAttributes(editor, attr, false); 653 } else { 654 UIManager.getLookAndFeel().provideErrorFeedback(editor); 655 } 656 } 657 } 658 659 private Color fg; 660 } 661 662 /** 663 * An action to set paragraph alignment. This sets the 664 * <code>StyleConstants.Alignment</code> attribute for the 665 * currently selected range of the target JEditorPane. 666 * This is done by calling 667 * <code>StyledDocument.setParagraphAttributes</code> 668 * on the styled document associated with the target 669 * JEditorPane. 670 * <p> 671 * If the target text component is specified as the 672 * source of the ActionEvent and there is a command string, 673 * the command string will be interpreted as an integer 674 * that should be one of the legal values for the 675 * <code>StyleConstants.Alignment</code> attribute. 676 * <p> 677 * <strong>Warning:</strong> 678 * Serialized objects of this class will not be compatible with 679 * future Swing releases. The current serialization support is 680 * appropriate for short term storage or RMI between applications running 681 * the same version of Swing. As of 1.4, support for long term storage 682 * of all JavaBeans™ 683 * has been added to the <code>java.beans</code> package. 684 * Please see {@link java.beans.XMLEncoder}. 685 */ 686 public static class AlignmentAction extends StyledTextAction { 687 688 /** 689 * Creates a new AlignmentAction. 690 * 691 * @param nm the action name 692 * @param a the alignment >= 0 693 */ 694 public AlignmentAction(String nm, int a) { 695 super(nm); 696 this.a = a; 697 } 698 699 /** 700 * Sets the alignment. 701 * 702 * @param e the action event 703 */ 704 public void actionPerformed(ActionEvent e) { 705 JEditorPane editor = getEditor(e); 706 if (editor != null) { 707 int a = this.a; 708 if ((e != null) && (e.getSource() == editor)) { 709 String s = e.getActionCommand(); 710 try { 711 a = Integer.parseInt(s, 10); 712 } catch (NumberFormatException nfe) { 713 } 714 } 715 MutableAttributeSet attr = new SimpleAttributeSet(); 716 StyleConstants.setAlignment(attr, a); 717 setParagraphAttributes(editor, attr, false); 718 } 719 } 720 721 private int a; 722 } 723 724 /** 725 * An action to toggle the bold attribute. 726 * <p> 727 * <strong>Warning:</strong> 728 * Serialized objects of this class will not be compatible with 729 * future Swing releases. The current serialization support is 730 * appropriate for short term storage or RMI between applications running 731 * the same version of Swing. As of 1.4, support for long term storage 732 * of all JavaBeans™ 733 * has been added to the <code>java.beans</code> package. 734 * Please see {@link java.beans.XMLEncoder}. 735 */ 736 public static class BoldAction extends StyledTextAction { 737 738 /** 739 * Constructs a new BoldAction. 740 */ 741 public BoldAction() { 742 super("font-bold"); 743 } 744 745 /** 746 * Toggles the bold attribute. 747 * 748 * @param e the action event 749 */ 750 public void actionPerformed(ActionEvent e) { 751 JEditorPane editor = getEditor(e); 752 if (editor != null) { 753 StyledEditorKit kit = getStyledEditorKit(editor); 754 MutableAttributeSet attr = kit.getInputAttributes(); 755 boolean bold = (StyleConstants.isBold(attr)) ? false : true; 756 SimpleAttributeSet sas = new SimpleAttributeSet(); 757 StyleConstants.setBold(sas, bold); 758 setCharacterAttributes(editor, sas, false); 759 } 760 } 761 } 762 763 /** 764 * An action to toggle the italic attribute. 765 * <p> 766 * <strong>Warning:</strong> 767 * Serialized objects of this class will not be compatible with 768 * future Swing releases. The current serialization support is 769 * appropriate for short term storage or RMI between applications running 770 * the same version of Swing. As of 1.4, support for long term storage 771 * of all JavaBeans™ 772 * has been added to the <code>java.beans</code> package. 773 * Please see {@link java.beans.XMLEncoder}. 774 */ 775 public static class ItalicAction extends StyledTextAction { 776 777 /** 778 * Constructs a new ItalicAction. 779 */ 780 public ItalicAction() { 781 super("font-italic"); 782 } 783 784 /** 785 * Toggles the italic attribute. 786 * 787 * @param e the action event 788 */ 789 public void actionPerformed(ActionEvent e) { 790 JEditorPane editor = getEditor(e); 791 if (editor != null) { 792 StyledEditorKit kit = getStyledEditorKit(editor); 793 MutableAttributeSet attr = kit.getInputAttributes(); 794 boolean italic = (StyleConstants.isItalic(attr)) ? false : true; 795 SimpleAttributeSet sas = new SimpleAttributeSet(); 796 StyleConstants.setItalic(sas, italic); 797 setCharacterAttributes(editor, sas, false); 798 } 799 } 800 } 801 802 /** 803 * An action to toggle the underline attribute. 804 * <p> 805 * <strong>Warning:</strong> 806 * Serialized objects of this class will not be compatible with 807 * future Swing releases. The current serialization support is 808 * appropriate for short term storage or RMI between applications running 809 * the same version of Swing. As of 1.4, support for long term storage 810 * of all JavaBeans™ 811 * has been added to the <code>java.beans</code> package. 812 * Please see {@link java.beans.XMLEncoder}. 813 */ 814 public static class UnderlineAction extends StyledTextAction { 815 816 /** 817 * Constructs a new UnderlineAction. 818 */ 819 public UnderlineAction() { 820 super("font-underline"); 821 } 822 823 /** 824 * Toggles the Underline attribute. 825 * 826 * @param e the action event 827 */ 828 public void actionPerformed(ActionEvent e) { 829 JEditorPane editor = getEditor(e); 830 if (editor != null) { 831 StyledEditorKit kit = getStyledEditorKit(editor); 832 MutableAttributeSet attr = kit.getInputAttributes(); 833 boolean underline = (StyleConstants.isUnderline(attr)) ? false : true; 834 SimpleAttributeSet sas = new SimpleAttributeSet(); 835 StyleConstants.setUnderline(sas, underline); 836 setCharacterAttributes(editor, sas, false); 837 } 838 } 839 } 840 841 842 /** 843 * StyledInsertBreakAction has similar behavior to that of 844 * <code>DefaultEditorKit.InsertBreakAction</code>. That is when 845 * its <code>actionPerformed</code> method is invoked, a newline 846 * is inserted. Beyond that, this will reset the input attributes to 847 * what they were before the newline was inserted. 848 */ 849 static class StyledInsertBreakAction extends StyledTextAction { 850 private SimpleAttributeSet tempSet; 851 852 StyledInsertBreakAction() { 853 super(insertBreakAction); 854 } 855 856 public void actionPerformed(ActionEvent e) { 857 JEditorPane target = getEditor(e); 858 859 if (target != null) { 860 if ((!target.isEditable()) || (!target.isEnabled())) { 861 UIManager.getLookAndFeel().provideErrorFeedback(target); 862 return; 863 } 864 StyledEditorKit sek = getStyledEditorKit(target); 865 866 if (tempSet != null) { 867 tempSet.removeAttributes(tempSet); 868 } 869 else { 870 tempSet = new SimpleAttributeSet(); 871 } 872 tempSet.addAttributes(sek.getInputAttributes()); 873 target.replaceSelection("\n"); 874 875 MutableAttributeSet ia = sek.getInputAttributes(); 876 877 ia.removeAttributes(ia); 878 ia.addAttributes(tempSet); 879 tempSet.removeAttributes(tempSet); 880 } 881 else { 882 // See if we are in a JTextComponent. 883 JTextComponent text = getTextComponent(e); 884 885 if (text != null) { 886 if ((!text.isEditable()) || (!text.isEnabled())) { 887 UIManager.getLookAndFeel().provideErrorFeedback(target); 888 return; 889 } 890 text.replaceSelection("\n"); 891 } 892 } 893 } 894 } 895 }