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