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 @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 */ 292 protected void createInputAttributes(Element element, 293 MutableAttributeSet set) { 294 if (element.getAttributes().getAttributeCount() > 0 295 || element.getEndOffset() - element.getStartOffset() > 1 296 || element.getEndOffset() < element.getDocument().getLength()) { 297 set.removeAttributes(set); 298 set.addAttributes(element.getAttributes()); 299 set.removeAttribute(StyleConstants.ComponentAttribute); 300 set.removeAttribute(StyleConstants.IconAttribute); 301 set.removeAttribute(AbstractDocument.ElementNameAttribute); 302 set.removeAttribute(StyleConstants.ComposedTextAttribute); 303 } 304 } 305 306 // ---- default ViewFactory implementation --------------------- 307 308 static class StyledViewFactory implements ViewFactory { 309 310 public View create(Element elem) { 311 String kind = elem.getName(); 312 if (kind != null) { 313 if (kind.equals(AbstractDocument.ContentElementName)) { 314 return new LabelView(elem); 315 } else if (kind.equals(AbstractDocument.ParagraphElementName)) { 316 return new ParagraphView(elem); 317 } else if (kind.equals(AbstractDocument.SectionElementName)) { 318 return new BoxView(elem, View.Y_AXIS); 319 } else if (kind.equals(StyleConstants.ComponentElementName)) { 320 return new ComponentView(elem); 321 } else if (kind.equals(StyleConstants.IconElementName)) { 322 return new IconView(elem); 323 } 324 } 325 326 // default to text display 327 return new LabelView(elem); 328 } 329 330 } 331 332 // --- Action implementations --------------------------------- 333 334 private static final Action[] defaultActions = { 335 new FontFamilyAction("font-family-SansSerif", "SansSerif"), 336 new FontFamilyAction("font-family-Monospaced", "Monospaced"), 337 new FontFamilyAction("font-family-Serif", "Serif"), 338 new FontSizeAction("font-size-8", 8), 339 new FontSizeAction("font-size-10", 10), 340 new FontSizeAction("font-size-12", 12), 341 new FontSizeAction("font-size-14", 14), 342 new FontSizeAction("font-size-16", 16), 343 new FontSizeAction("font-size-18", 18), 344 new FontSizeAction("font-size-24", 24), 345 new FontSizeAction("font-size-36", 36), 346 new FontSizeAction("font-size-48", 48), 347 new AlignmentAction("left-justify", StyleConstants.ALIGN_LEFT), 348 new AlignmentAction("center-justify", StyleConstants.ALIGN_CENTER), 349 new AlignmentAction("right-justify", StyleConstants.ALIGN_RIGHT), 350 new BoldAction(), 351 new ItalicAction(), 352 new StyledInsertBreakAction(), 353 new UnderlineAction() 354 }; 355 356 /** 357 * An action that assumes it's being fired on a JEditorPane 358 * with a StyledEditorKit (or subclass) installed. This has 359 * some convenience methods for causing character or paragraph 360 * level attribute changes. The convenience methods will 361 * throw an IllegalArgumentException if the assumption of 362 * a StyledDocument, a JEditorPane, or a StyledEditorKit 363 * fail to be true. 364 * <p> 365 * The component that gets acted upon by the action 366 * will be the source of the ActionEvent if the source 367 * can be narrowed to a JEditorPane type. If the source 368 * can't be narrowed, the most recently focused text 369 * component is changed. If neither of these are the 370 * case, the action cannot be performed. 371 * <p> 372 * <strong>Warning:</strong> 373 * Serialized objects of this class will not be compatible with 374 * future Swing releases. The current serialization support is 375 * appropriate for short term storage or RMI between applications running 376 * the same version of Swing. As of 1.4, support for long term storage 377 * of all JavaBeans™ 378 * has been added to the <code>java.beans</code> package. 379 * Please see {@link java.beans.XMLEncoder}. 380 */ 381 @SuppressWarnings("serial") // Same-version serialization only 382 public abstract static class StyledTextAction extends TextAction { 383 384 /** 385 * Creates a new StyledTextAction from a string action name. 386 * 387 * @param nm the name of the action 388 */ 389 public StyledTextAction(String nm) { 390 super(nm); 391 } 392 393 /** 394 * Gets the target editor for an action. 395 * 396 * @param e the action event 397 * @return the editor 398 */ 399 protected final JEditorPane getEditor(ActionEvent e) { 400 JTextComponent tcomp = getTextComponent(e); 401 if (tcomp instanceof JEditorPane) { 402 return (JEditorPane) tcomp; 403 } 404 return null; 405 } 406 407 /** 408 * Gets the document associated with an editor pane. 409 * 410 * @param e the editor 411 * @return the document 412 * @exception IllegalArgumentException for the wrong document type 413 */ 414 protected final StyledDocument getStyledDocument(JEditorPane e) { 415 Document d = e.getDocument(); 416 if (d instanceof StyledDocument) { 417 return (StyledDocument) d; 418 } 419 throw new IllegalArgumentException("document must be StyledDocument"); 420 } 421 422 /** 423 * Gets the editor kit associated with an editor pane. 424 * 425 * @param e the editor pane 426 * @return the kit 427 * @exception IllegalArgumentException for the wrong document type 428 */ 429 protected final StyledEditorKit getStyledEditorKit(JEditorPane e) { 430 EditorKit k = e.getEditorKit(); 431 if (k instanceof StyledEditorKit) { 432 return (StyledEditorKit) k; 433 } 434 throw new IllegalArgumentException("EditorKit must be StyledEditorKit"); 435 } 436 437 /** 438 * Applies the given attributes to character 439 * content. If there is a selection, the attributes 440 * are applied to the selection range. If there 441 * is no selection, the attributes are applied to 442 * the input attribute set which defines the attributes 443 * for any new text that gets inserted. 444 * 445 * @param editor the editor 446 * @param attr the attributes 447 * @param replace if true, then replace the existing attributes first 448 */ 449 protected final void setCharacterAttributes(JEditorPane editor, 450 AttributeSet attr, boolean replace) { 451 int p0 = editor.getSelectionStart(); 452 int p1 = editor.getSelectionEnd(); 453 if (p0 != p1) { 454 StyledDocument doc = getStyledDocument(editor); 455 doc.setCharacterAttributes(p0, p1 - p0, attr, replace); 456 } 457 StyledEditorKit k = getStyledEditorKit(editor); 458 MutableAttributeSet inputAttributes = k.getInputAttributes(); 459 if (replace) { 460 inputAttributes.removeAttributes(inputAttributes); 461 } 462 inputAttributes.addAttributes(attr); 463 } 464 465 /** 466 * Applies the given attributes to paragraphs. If 467 * there is a selection, the attributes are applied 468 * to the paragraphs that intersect the selection. 469 * if there is no selection, the attributes are applied 470 * to the paragraph at the current caret position. 471 * 472 * @param editor the editor 473 * @param attr the attributes 474 * @param replace if true, replace the existing attributes first 475 */ 476 protected final void setParagraphAttributes(JEditorPane editor, 477 AttributeSet attr, boolean replace) { 478 int p0 = editor.getSelectionStart(); 479 int p1 = editor.getSelectionEnd(); 480 StyledDocument doc = getStyledDocument(editor); 481 doc.setParagraphAttributes(p0, p1 - p0, attr, replace); 482 } 483 484 } 485 486 /** 487 * An action to set the font family in the associated 488 * JEditorPane. This will use the family specified as 489 * the command string on the ActionEvent if there is one, 490 * otherwise the family that was initialized with will be used. 491 * <p> 492 * <strong>Warning:</strong> 493 * Serialized objects of this class will not be compatible with 494 * future Swing releases. The current serialization support is 495 * appropriate for short term storage or RMI between applications running 496 * the same version of Swing. As of 1.4, support for long term storage 497 * of all JavaBeans™ 498 * has been added to the <code>java.beans</code> package. 499 * Please see {@link java.beans.XMLEncoder}. 500 */ 501 @SuppressWarnings("serial") // Same-version serialization only 502 public static class FontFamilyAction extends StyledTextAction { 503 504 /** 505 * Creates a new FontFamilyAction. 506 * 507 * @param nm the action name 508 * @param family the font family 509 */ 510 public FontFamilyAction(String nm, String family) { 511 super(nm); 512 this.family = family; 513 } 514 515 /** 516 * Sets the font family. 517 * 518 * @param e the event 519 */ 520 public void actionPerformed(ActionEvent e) { 521 JEditorPane editor = getEditor(e); 522 if (editor != null) { 523 String family = this.family; 524 if ((e != null) && (e.getSource() == editor)) { 525 String s = e.getActionCommand(); 526 if (s != null) { 527 family = s; 528 } 529 } 530 if (family != null) { 531 MutableAttributeSet attr = new SimpleAttributeSet(); 532 StyleConstants.setFontFamily(attr, family); 533 setCharacterAttributes(editor, attr, false); 534 } else { 535 UIManager.getLookAndFeel().provideErrorFeedback(editor); 536 } 537 } 538 } 539 540 private String family; 541 } 542 543 /** 544 * An action to set the font size in the associated 545 * JEditorPane. This will use the size specified as 546 * the command string on the ActionEvent if there is one, 547 * otherwise the size that was initialized with will be used. 548 * <p> 549 * <strong>Warning:</strong> 550 * Serialized objects of this class will not be compatible with 551 * future Swing releases. The current serialization support is 552 * appropriate for short term storage or RMI between applications running 553 * the same version of Swing. As of 1.4, support for long term storage 554 * of all JavaBeans™ 555 * has been added to the <code>java.beans</code> package. 556 * Please see {@link java.beans.XMLEncoder}. 557 */ 558 @SuppressWarnings("serial") // Same-version serialization only 559 public static class FontSizeAction extends StyledTextAction { 560 561 /** 562 * Creates a new FontSizeAction. 563 * 564 * @param nm the action name 565 * @param size the font size 566 */ 567 public FontSizeAction(String nm, int size) { 568 super(nm); 569 this.size = size; 570 } 571 572 /** 573 * Sets the font size. 574 * 575 * @param e the action event 576 */ 577 public void actionPerformed(ActionEvent e) { 578 JEditorPane editor = getEditor(e); 579 if (editor != null) { 580 int size = this.size; 581 if ((e != null) && (e.getSource() == editor)) { 582 String s = e.getActionCommand(); 583 try { 584 size = Integer.parseInt(s, 10); 585 } catch (NumberFormatException nfe) { 586 } 587 } 588 if (size != 0) { 589 MutableAttributeSet attr = new SimpleAttributeSet(); 590 StyleConstants.setFontSize(attr, size); 591 setCharacterAttributes(editor, attr, false); 592 } else { 593 UIManager.getLookAndFeel().provideErrorFeedback(editor); 594 } 595 } 596 } 597 598 private int size; 599 } 600 601 /** 602 * An action to set foreground color. This sets the 603 * <code>StyleConstants.Foreground</code> attribute for the 604 * currently selected range of the target JEditorPane. 605 * This is done by calling 606 * <code>StyledDocument.setCharacterAttributes</code> 607 * on the styled document associated with the target 608 * JEditorPane. 609 * <p> 610 * If the target text component is specified as the 611 * source of the ActionEvent and there is a command string, 612 * the command string will be interpreted as the foreground 613 * color. It will be interpreted by called 614 * <code>Color.decode</code>, and should therefore be 615 * legal input for that method. 616 * <p> 617 * <strong>Warning:</strong> 618 * Serialized objects of this class will not be compatible with 619 * future Swing releases. The current serialization support is 620 * appropriate for short term storage or RMI between applications running 621 * the same version of Swing. As of 1.4, support for long term storage 622 * of all JavaBeans™ 623 * has been added to the <code>java.beans</code> package. 624 * Please see {@link java.beans.XMLEncoder}. 625 */ 626 @SuppressWarnings("serial") // Same-version serialization only 627 public static class ForegroundAction extends StyledTextAction { 628 629 /** 630 * Creates a new ForegroundAction. 631 * 632 * @param nm the action name 633 * @param fg the foreground color 634 */ 635 public ForegroundAction(String nm, Color fg) { 636 super(nm); 637 this.fg = fg; 638 } 639 640 /** 641 * Sets the foreground color. 642 * 643 * @param e the action event 644 */ 645 public void actionPerformed(ActionEvent e) { 646 JEditorPane editor = getEditor(e); 647 if (editor != null) { 648 Color fg = this.fg; 649 if ((e != null) && (e.getSource() == editor)) { 650 String s = e.getActionCommand(); 651 try { 652 fg = Color.decode(s); 653 } catch (NumberFormatException nfe) { 654 } 655 } 656 if (fg != null) { 657 MutableAttributeSet attr = new SimpleAttributeSet(); 658 StyleConstants.setForeground(attr, fg); 659 setCharacterAttributes(editor, attr, false); 660 } else { 661 UIManager.getLookAndFeel().provideErrorFeedback(editor); 662 } 663 } 664 } 665 666 private Color fg; 667 } 668 669 /** 670 * An action to set paragraph alignment. This sets the 671 * <code>StyleConstants.Alignment</code> attribute for the 672 * currently selected range of the target JEditorPane. 673 * This is done by calling 674 * <code>StyledDocument.setParagraphAttributes</code> 675 * on the styled document associated with the target 676 * JEditorPane. 677 * <p> 678 * If the target text component is specified as the 679 * source of the ActionEvent and there is a command string, 680 * the command string will be interpreted as an integer 681 * that should be one of the legal values for the 682 * <code>StyleConstants.Alignment</code> 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 687 * appropriate for short term storage or RMI between applications running 688 * the same version of Swing. As of 1.4, support for long term storage 689 * of all JavaBeans™ 690 * has been added to the <code>java.beans</code> package. 691 * Please see {@link java.beans.XMLEncoder}. 692 */ 693 @SuppressWarnings("serial") // Same-version serialization only 694 public static class AlignmentAction extends StyledTextAction { 695 696 /** 697 * Creates a new AlignmentAction. 698 * 699 * @param nm the action name 700 * @param a the alignment >= 0 701 */ 702 public AlignmentAction(String nm, int a) { 703 super(nm); 704 this.a = a; 705 } 706 707 /** 708 * Sets the alignment. 709 * 710 * @param e the action event 711 */ 712 public void actionPerformed(ActionEvent e) { 713 JEditorPane editor = getEditor(e); 714 if (editor != null) { 715 int a = this.a; 716 if ((e != null) && (e.getSource() == editor)) { 717 String s = e.getActionCommand(); 718 try { 719 a = Integer.parseInt(s, 10); 720 } catch (NumberFormatException nfe) { 721 } 722 } 723 MutableAttributeSet attr = new SimpleAttributeSet(); 724 StyleConstants.setAlignment(attr, a); 725 setParagraphAttributes(editor, attr, false); 726 } 727 } 728 729 private int a; 730 } 731 732 /** 733 * An action to toggle the bold attribute. 734 * <p> 735 * <strong>Warning:</strong> 736 * Serialized objects of this class will not be compatible with 737 * future Swing releases. The current serialization support is 738 * appropriate for short term storage or RMI between applications running 739 * the same version of Swing. As of 1.4, support for long term storage 740 * of all JavaBeans™ 741 * has been added to the <code>java.beans</code> package. 742 * Please see {@link java.beans.XMLEncoder}. 743 */ 744 @SuppressWarnings("serial") // Same-version serialization only 745 public static class BoldAction extends StyledTextAction { 746 747 /** 748 * Constructs a new BoldAction. 749 */ 750 public BoldAction() { 751 super("font-bold"); 752 } 753 754 /** 755 * Toggles the bold attribute. 756 * 757 * @param e the action event 758 */ 759 public void actionPerformed(ActionEvent e) { 760 JEditorPane editor = getEditor(e); 761 if (editor != null) { 762 StyledEditorKit kit = getStyledEditorKit(editor); 763 MutableAttributeSet attr = kit.getInputAttributes(); 764 boolean bold = (StyleConstants.isBold(attr)) ? false : true; 765 SimpleAttributeSet sas = new SimpleAttributeSet(); 766 StyleConstants.setBold(sas, bold); 767 setCharacterAttributes(editor, sas, false); 768 } 769 } 770 } 771 772 /** 773 * An action to toggle the italic attribute. 774 * <p> 775 * <strong>Warning:</strong> 776 * Serialized objects of this class will not be compatible with 777 * future Swing releases. The current serialization support is 778 * appropriate for short term storage or RMI between applications running 779 * the same version of Swing. As of 1.4, support for long term storage 780 * of all JavaBeans™ 781 * has been added to the <code>java.beans</code> package. 782 * Please see {@link java.beans.XMLEncoder}. 783 */ 784 @SuppressWarnings("serial") // Same-version serialization only 785 public static class ItalicAction extends StyledTextAction { 786 787 /** 788 * Constructs a new ItalicAction. 789 */ 790 public ItalicAction() { 791 super("font-italic"); 792 } 793 794 /** 795 * Toggles the italic attribute. 796 * 797 * @param e the action event 798 */ 799 public void actionPerformed(ActionEvent e) { 800 JEditorPane editor = getEditor(e); 801 if (editor != null) { 802 StyledEditorKit kit = getStyledEditorKit(editor); 803 MutableAttributeSet attr = kit.getInputAttributes(); 804 boolean italic = (StyleConstants.isItalic(attr)) ? false : true; 805 SimpleAttributeSet sas = new SimpleAttributeSet(); 806 StyleConstants.setItalic(sas, italic); 807 setCharacterAttributes(editor, sas, false); 808 } 809 } 810 } 811 812 /** 813 * An action to toggle the underline attribute. 814 * <p> 815 * <strong>Warning:</strong> 816 * Serialized objects of this class will not be compatible with 817 * future Swing releases. The current serialization support is 818 * appropriate for short term storage or RMI between applications running 819 * the same version of Swing. As of 1.4, support for long term storage 820 * of all JavaBeans™ 821 * has been added to the <code>java.beans</code> package. 822 * Please see {@link java.beans.XMLEncoder}. 823 */ 824 @SuppressWarnings("serial") // Same-version serialization only 825 public static class UnderlineAction extends StyledTextAction { 826 827 /** 828 * Constructs a new UnderlineAction. 829 */ 830 public UnderlineAction() { 831 super("font-underline"); 832 } 833 834 /** 835 * Toggles the Underline attribute. 836 * 837 * @param e the action event 838 */ 839 public void actionPerformed(ActionEvent e) { 840 JEditorPane editor = getEditor(e); 841 if (editor != null) { 842 StyledEditorKit kit = getStyledEditorKit(editor); 843 MutableAttributeSet attr = kit.getInputAttributes(); 844 boolean underline = (StyleConstants.isUnderline(attr)) ? false : true; 845 SimpleAttributeSet sas = new SimpleAttributeSet(); 846 StyleConstants.setUnderline(sas, underline); 847 setCharacterAttributes(editor, sas, false); 848 } 849 } 850 } 851 852 853 /** 854 * StyledInsertBreakAction has similar behavior to that of 855 * <code>DefaultEditorKit.InsertBreakAction</code>. That is when 856 * its <code>actionPerformed</code> method is invoked, a newline 857 * is inserted. Beyond that, this will reset the input attributes to 858 * what they were before the newline was inserted. 859 */ 860 @SuppressWarnings("serial") // Superclass is not serializable across versions 861 static class StyledInsertBreakAction extends StyledTextAction { 862 private SimpleAttributeSet tempSet; 863 864 StyledInsertBreakAction() { 865 super(insertBreakAction); 866 } 867 868 public void actionPerformed(ActionEvent e) { 869 JEditorPane target = getEditor(e); 870 871 if (target != null) { 872 if ((!target.isEditable()) || (!target.isEnabled())) { 873 UIManager.getLookAndFeel().provideErrorFeedback(target); 874 return; 875 } 876 StyledEditorKit sek = getStyledEditorKit(target); 877 878 if (tempSet != null) { 879 tempSet.removeAttributes(tempSet); 880 } 881 else { 882 tempSet = new SimpleAttributeSet(); 883 } 884 tempSet.addAttributes(sek.getInputAttributes()); 885 target.replaceSelection("\n"); 886 887 MutableAttributeSet ia = sek.getInputAttributes(); 888 889 ia.removeAttributes(ia); 890 ia.addAttributes(tempSet); 891 tempSet.removeAttributes(tempSet); 892 } 893 else { 894 // See if we are in a JTextComponent. 895 JTextComponent text = getTextComponent(e); 896 897 if (text != null) { 898 if ((!text.isEditable()) || (!text.isEnabled())) { 899 UIManager.getLookAndFeel().provideErrorFeedback(target); 900 return; 901 } 902 text.replaceSelection("\n"); 903 } 904 } 905 } 906 } 907 }