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