blob: d841344a052e7b9f8d03fcfca811b53e121cb8a3 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing.text;
26
27import java.io.*;
28import java.awt.*;
29import java.awt.event.ActionEvent;
30import java.beans.PropertyChangeEvent;
31import java.beans.PropertyChangeListener;
32import javax.swing.event.*;
33import javax.swing.Action;
34import javax.swing.JEditorPane;
35import javax.swing.KeyStroke;
36import 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 */
47public 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(), this.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<sup><font size="-2">TM</font></sup>
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<sup><font size="-2">TM</font></sup>
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<sup><font size="-2">TM</font></sup>
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<sup><font size="-2">TM</font></sup>
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<sup><font size="-2">TM</font></sup>
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<sup><font size="-2">TM</font></sup>
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<sup><font size="-2">TM</font></sup>
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<sup><font size="-2">TM</font></sup>
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}