001 /*
002 * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025 package javax.swing.text;
026
027 import java.io.*;
028 import java.awt.*;
029 import java.awt.event.ActionEvent;
030 import java.beans.PropertyChangeEvent;
031 import java.beans.PropertyChangeListener;
032 import javax.swing.event.*;
033 import javax.swing.Action;
034 import javax.swing.JEditorPane;
035 import javax.swing.KeyStroke;
036 import javax.swing.UIManager;
037
038 /**
039 * This is the set of things needed by a text component
040 * to be a reasonably functioning editor for some <em>type</em>
041 * of text document. This implementation provides a default
042 * implementation which treats text as styled text and
043 * provides a minimal set of actions for editing styled text.
044 *
045 * @author Timothy Prinzing
046 * @version 1.52 05/05/07
047 */
048 public class StyledEditorKit extends DefaultEditorKit {
049
050 /**
051 * Creates a new EditorKit used for styled documents.
052 */
053 public StyledEditorKit() {
054 createInputAttributeUpdated();
055 createInputAttributes();
056 }
057
058 /**
059 * Gets the input attributes for the pane. When
060 * the caret moves and there is no selection, the
061 * input attributes are automatically mutated to
062 * reflect the character attributes of the current
063 * caret location. The styled editing actions
064 * use the input attributes to carry out their
065 * actions.
066 *
067 * @return the attribute set
068 */
069 public MutableAttributeSet getInputAttributes() {
070 return inputAttributes;
071 }
072
073 /**
074 * Fetches the element representing the current
075 * run of character attributes for the caret.
076 *
077 * @return the element
078 */
079 public Element getCharacterAttributeRun() {
080 return currentRun;
081 }
082
083 // --- EditorKit methods ---------------------------
084
085 /**
086 * Fetches the command list for the editor. This is
087 * the list of commands supported by the superclass
088 * augmented by the collection of commands defined
089 * locally for style operations.
090 *
091 * @return the command list
092 */
093 public Action[] getActions() {
094 return TextAction.augmentList(super .getActions(),
095 this .defaultActions);
096 }
097
098 /**
099 * Creates an uninitialized text storage model
100 * that is appropriate for this type of editor.
101 *
102 * @return the model
103 */
104 public Document createDefaultDocument() {
105 return new DefaultStyledDocument();
106 }
107
108 /**
109 * Called when the kit is being installed into
110 * a JEditorPane.
111 *
112 * @param c the JEditorPane
113 */
114 public void install(JEditorPane c) {
115 c.addCaretListener(inputAttributeUpdater);
116 c.addPropertyChangeListener(inputAttributeUpdater);
117 Caret caret = c.getCaret();
118 if (caret != null) {
119 inputAttributeUpdater.updateInputAttributes(caret.getDot(),
120 caret.getMark(), c);
121 }
122 }
123
124 /**
125 * Called when the kit is being removed from the
126 * JEditorPane. This is used to unregister any
127 * listeners that were attached.
128 *
129 * @param c the JEditorPane
130 */
131 public void deinstall(JEditorPane c) {
132 c.removeCaretListener(inputAttributeUpdater);
133 c.removePropertyChangeListener(inputAttributeUpdater);
134
135 // remove references to current document so it can be collected.
136 currentRun = null;
137 currentParagraph = null;
138 }
139
140 /**
141 * Fetches a factory that is suitable for producing
142 * views of any models that are produced by this
143 * kit. This is implemented to return View implementations
144 * for the following kinds of elements:
145 * <ul>
146 * <li>AbstractDocument.ContentElementName
147 * <li>AbstractDocument.ParagraphElementName
148 * <li>AbstractDocument.SectionElementName
149 * <li>StyleConstants.ComponentElementName
150 * <li>StyleConstants.IconElementName
151 * </ul>
152 *
153 * @return the factory
154 */
155 public ViewFactory getViewFactory() {
156 return defaultFactory;
157 }
158
159 /**
160 * Creates a copy of the editor kit.
161 *
162 * @return the copy
163 */
164 public Object clone() {
165 StyledEditorKit o = (StyledEditorKit) super .clone();
166 o.currentRun = o.currentParagraph = null;
167 o.createInputAttributeUpdated();
168 o.createInputAttributes();
169 return o;
170 }
171
172 /**
173 * Creates the AttributeSet used for the selection.
174 */
175 private void createInputAttributes() {
176 inputAttributes = new SimpleAttributeSet() {
177 public AttributeSet getResolveParent() {
178 return (currentParagraph != null) ? currentParagraph
179 .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 private static final ViewFactory defaultFactory = new StyledViewFactory();
196
197 Element currentRun;
198 Element currentParagraph;
199
200 /**
201 * This is the set of attributes used to store the
202 * input attributes.
203 */
204 MutableAttributeSet inputAttributes;
205
206 /**
207 * This listener will be attached to the caret of
208 * the text component that the EditorKit gets installed
209 * into. This should keep the input attributes updated
210 * for use by the styled actions.
211 */
212 private AttributeTracker inputAttributeUpdater;
213
214 /**
215 * Tracks caret movement and keeps the input attributes set
216 * to reflect the current set of attribute definitions at the
217 * caret position.
218 * <p>This implements PropertyChangeListener to update the
219 * input attributes when the Document changes, as if the Document
220 * changes the attributes will almost certainly change.
221 */
222 class AttributeTracker implements CaretListener,
223 PropertyChangeListener, Serializable {
224
225 /**
226 * Updates the attributes. <code>dot</code> and <code>mark</code>
227 * mark give the positions of the selection in <code>c</code>.
228 */
229 void updateInputAttributes(int dot, int mark, JTextComponent c) {
230 // EditorKit might not have installed the StyledDocument yet.
231 Document aDoc = c.getDocument();
232 if (!(aDoc instanceof StyledDocument)) {
233 return;
234 }
235 int start = Math.min(dot, mark);
236 // record current character attributes.
237 StyledDocument doc = (StyledDocument) aDoc;
238 // If nothing is selected, get the attributes from the character
239 // before the start of the selection, otherwise get the attributes
240 // from the character element at the start of the selection.
241 Element run;
242 currentParagraph = doc.getParagraphElement(start);
243 if (currentParagraph.getStartOffset() == start
244 || dot != mark) {
245 // Get the attributes from the character at the selection
246 // if in a different paragrah!
247 run = doc.getCharacterElement(start);
248 } else {
249 run = doc.getCharacterElement(Math.max(start - 1, 0));
250 }
251 if (run != currentRun) {
252 /*
253 * PENDING(prinz) All attributes that represent a single
254 * glyph position and can't be inserted into should be
255 * removed from the input attributes... this requires
256 * mixing in an interface to indicate that condition.
257 * When we can add things again this logic needs to be
258 * improved!!
259 */
260 currentRun = run;
261 createInputAttributes(currentRun, getInputAttributes());
262 }
263 }
264
265 public void propertyChange(PropertyChangeEvent evt) {
266 Object newValue = evt.getNewValue();
267 Object source = evt.getSource();
268
269 if ((source instanceof JTextComponent)
270 && (newValue instanceof Document)) {
271 // New document will have changed selection to 0,0.
272 updateInputAttributes(0, 0, (JTextComponent) source);
273 }
274 }
275
276 public void caretUpdate(CaretEvent e) {
277 updateInputAttributes(e.getDot(), e.getMark(),
278 (JTextComponent) e.getSource());
279 }
280 }
281
282 /**
283 * Copies the key/values in <code>element</code>s AttributeSet into
284 * <code>set</code>. This does not copy component, icon, or element
285 * names attributes. Subclasses may wish to refine what is and what
286 * isn't copied here. But be sure to first remove all the attributes that
287 * are in <code>set</code>.<p>
288 * This is called anytime the caret moves over a different location.
289 *
290 */
291 protected void createInputAttributes(Element element,
292 MutableAttributeSet set) {
293 if (element.getAttributes().getAttributeCount() > 0
294 || element.getEndOffset() - element.getStartOffset() > 1
295 || element.getEndOffset() < element.getDocument()
296 .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
316 .equals(AbstractDocument.ParagraphElementName)) {
317 return new ParagraphView(elem);
318 } else if (kind
319 .equals(AbstractDocument.SectionElementName)) {
320 return new BoxView(elem, View.Y_AXIS);
321 } else if (kind
322 .equals(StyleConstants.ComponentElementName)) {
323 return new ComponentView(elem);
324 } else if (kind.equals(StyleConstants.IconElementName)) {
325 return new IconView(elem);
326 }
327 }
328
329 // default to text display
330 return new LabelView(elem);
331 }
332
333 }
334
335 // --- Action implementations ---------------------------------
336
337 private static final Action[] defaultActions = {
338 new FontFamilyAction("font-family-SansSerif", "SansSerif"),
339 new FontFamilyAction("font-family-Monospaced", "Monospaced"),
340 new FontFamilyAction("font-family-Serif", "Serif"),
341 new FontSizeAction("font-size-8", 8),
342 new FontSizeAction("font-size-10", 10),
343 new FontSizeAction("font-size-12", 12),
344 new FontSizeAction("font-size-14", 14),
345 new FontSizeAction("font-size-16", 16),
346 new FontSizeAction("font-size-18", 18),
347 new FontSizeAction("font-size-24", 24),
348 new FontSizeAction("font-size-36", 36),
349 new FontSizeAction("font-size-48", 48),
350 new AlignmentAction("left-justify",
351 StyleConstants.ALIGN_LEFT),
352 new AlignmentAction("center-justify",
353 StyleConstants.ALIGN_CENTER),
354 new AlignmentAction("right-justify",
355 StyleConstants.ALIGN_RIGHT), new BoldAction(),
356 new ItalicAction(), new StyledInsertBreakAction(),
357 new UnderlineAction() };
358
359 /**
360 * An action that assumes it's being fired on a JEditorPane
361 * with a StyledEditorKit (or subclass) installed. This has
362 * some convenience methods for causing character or paragraph
363 * level attribute changes. The convenience methods will
364 * throw an IllegalArgumentException if the assumption of
365 * a StyledDocument, a JEditorPane, or a StyledEditorKit
366 * fail to be true.
367 * <p>
368 * The component that gets acted upon by the action
369 * will be the source of the ActionEvent if the source
370 * can be narrowed to a JEditorPane type. If the source
371 * can't be narrowed, the most recently focused text
372 * component is changed. If neither of these are the
373 * case, the action cannot be performed.
374 * <p>
375 * <strong>Warning:</strong>
376 * Serialized objects of this class will not be compatible with
377 * future Swing releases. The current serialization support is
378 * appropriate for short term storage or RMI between applications running
379 * the same version of Swing. As of 1.4, support for long term storage
380 * of all JavaBeans<sup><font size="-2">TM</font></sup>
381 * has been added to the <code>java.beans</code> package.
382 * Please see {@link java.beans.XMLEncoder}.
383 */
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(
422 "document must be StyledDocument");
423 }
424
425 /**
426 * Gets the editor kit associated with an editor pane.
427 *
428 * @param e the editor pane
429 * @return the kit
430 * @exception IllegalArgumentException for the wrong document type
431 */
432 protected final StyledEditorKit getStyledEditorKit(JEditorPane e) {
433 EditorKit k = e.getEditorKit();
434 if (k instanceof StyledEditorKit) {
435 return (StyledEditorKit) k;
436 }
437 throw new IllegalArgumentException(
438 "EditorKit must be StyledEditorKit");
439 }
440
441 /**
442 * Applies the given attributes to character
443 * content. If there is a selection, the attributes
444 * are applied to the selection range. If there
445 * is no selection, the attributes are applied to
446 * the input attribute set which defines the attributes
447 * for any new text that gets inserted.
448 *
449 * @param editor the editor
450 * @param attr the attributes
451 * @param replace if true, then replace the existing attributes first
452 */
453 protected final void setCharacterAttributes(JEditorPane editor,
454 AttributeSet attr, boolean replace) {
455 int p0 = editor.getSelectionStart();
456 int p1 = editor.getSelectionEnd();
457 if (p0 != p1) {
458 StyledDocument doc = getStyledDocument(editor);
459 doc.setCharacterAttributes(p0, p1 - p0, attr, replace);
460 }
461 StyledEditorKit k = getStyledEditorKit(editor);
462 MutableAttributeSet inputAttributes = k
463 .getInputAttributes();
464 if (replace) {
465 inputAttributes.removeAttributes(inputAttributes);
466 }
467 inputAttributes.addAttributes(attr);
468 }
469
470 /**
471 * Applies the given attributes to paragraphs. If
472 * there is a selection, the attributes are applied
473 * to the paragraphs that intersect the selection.
474 * if there is no selection, the attributes are applied
475 * to the paragraph at the current caret position.
476 *
477 * @param editor the editor
478 * @param attr the attributes
479 * @param replace if true, replace the existing attributes first
480 */
481 protected final void setParagraphAttributes(JEditorPane editor,
482 AttributeSet attr, boolean replace) {
483 int p0 = editor.getSelectionStart();
484 int p1 = editor.getSelectionEnd();
485 StyledDocument doc = getStyledDocument(editor);
486 doc.setParagraphAttributes(p0, p1 - p0, attr, replace);
487 }
488
489 }
490
491 /**
492 * An action to set the font family in the associated
493 * JEditorPane. This will use the family specified as
494 * the command string on the ActionEvent if there is one,
495 * otherwise the family that was initialized with will be used.
496 * <p>
497 * <strong>Warning:</strong>
498 * Serialized objects of this class will not be compatible with
499 * future Swing releases. The current serialization support is
500 * appropriate for short term storage or RMI between applications running
501 * the same version of Swing. As of 1.4, support for long term storage
502 * of all JavaBeans<sup><font size="-2">TM</font></sup>
503 * has been added to the <code>java.beans</code> package.
504 * Please see {@link java.beans.XMLEncoder}.
505 */
506 public static class FontFamilyAction extends StyledTextAction {
507
508 /**
509 * Creates a new FontFamilyAction.
510 *
511 * @param nm the action name
512 * @param family the font family
513 */
514 public FontFamilyAction(String nm, String family) {
515 super (nm);
516 this .family = family;
517 }
518
519 /**
520 * Sets the font family.
521 *
522 * @param e the event
523 */
524 public void actionPerformed(ActionEvent e) {
525 JEditorPane editor = getEditor(e);
526 if (editor != null) {
527 String family = this .family;
528 if ((e != null) && (e.getSource() == editor)) {
529 String s = e.getActionCommand();
530 if (s != null) {
531 family = s;
532 }
533 }
534 if (family != null) {
535 MutableAttributeSet attr = new SimpleAttributeSet();
536 StyleConstants.setFontFamily(attr, family);
537 setCharacterAttributes(editor, attr, false);
538 } else {
539 UIManager.getLookAndFeel().provideErrorFeedback(
540 editor);
541 }
542 }
543 }
544
545 private String family;
546 }
547
548 /**
549 * An action to set the font size in the associated
550 * JEditorPane. This will use the size specified as
551 * the command string on the ActionEvent if there is one,
552 * otherwise the size that was initialized with will be used.
553 * <p>
554 * <strong>Warning:</strong>
555 * Serialized objects of this class will not be compatible with
556 * future Swing releases. The current serialization support is
557 * appropriate for short term storage or RMI between applications running
558 * the same version of Swing. As of 1.4, support for long term storage
559 * of all JavaBeans<sup><font size="-2">TM</font></sup>
560 * has been added to the <code>java.beans</code> package.
561 * Please see {@link java.beans.XMLEncoder}.
562 */
563 public static class FontSizeAction extends StyledTextAction {
564
565 /**
566 * Creates a new FontSizeAction.
567 *
568 * @param nm the action name
569 * @param size the font size
570 */
571 public FontSizeAction(String nm, int size) {
572 super (nm);
573 this .size = size;
574 }
575
576 /**
577 * Sets the font size.
578 *
579 * @param e the action event
580 */
581 public void actionPerformed(ActionEvent e) {
582 JEditorPane editor = getEditor(e);
583 if (editor != null) {
584 int size = this .size;
585 if ((e != null) && (e.getSource() == editor)) {
586 String s = e.getActionCommand();
587 try {
588 size = Integer.parseInt(s, 10);
589 } catch (NumberFormatException nfe) {
590 }
591 }
592 if (size != 0) {
593 MutableAttributeSet attr = new SimpleAttributeSet();
594 StyleConstants.setFontSize(attr, size);
595 setCharacterAttributes(editor, attr, false);
596 } else {
597 UIManager.getLookAndFeel().provideErrorFeedback(
598 editor);
599 }
600 }
601 }
602
603 private int size;
604 }
605
606 /**
607 * An action to set foreground color. This sets the
608 * <code>StyleConstants.Foreground</code> attribute for the
609 * currently selected range of the target JEditorPane.
610 * This is done by calling
611 * <code>StyledDocument.setCharacterAttributes</code>
612 * on the styled document associated with the target
613 * JEditorPane.
614 * <p>
615 * If the target text component is specified as the
616 * source of the ActionEvent and there is a command string,
617 * the command string will be interpreted as the foreground
618 * color. It will be interpreted by called
619 * <code>Color.decode</code>, and should therefore be
620 * legal input for that method.
621 * <p>
622 * <strong>Warning:</strong>
623 * Serialized objects of this class will not be compatible with
624 * future Swing releases. The current serialization support is
625 * appropriate for short term storage or RMI between applications running
626 * the same version of Swing. As of 1.4, support for long term storage
627 * of all JavaBeans<sup><font size="-2">TM</font></sup>
628 * has been added to the <code>java.beans</code> package.
629 * Please see {@link java.beans.XMLEncoder}.
630 */
631 public static class ForegroundAction extends StyledTextAction {
632
633 /**
634 * Creates a new ForegroundAction.
635 *
636 * @param nm the action name
637 * @param fg the foreground color
638 */
639 public ForegroundAction(String nm, Color fg) {
640 super (nm);
641 this .fg = fg;
642 }
643
644 /**
645 * Sets the foreground color.
646 *
647 * @param e the action event
648 */
649 public void actionPerformed(ActionEvent e) {
650 JEditorPane editor = getEditor(e);
651 if (editor != null) {
652 Color fg = this .fg;
653 if ((e != null) && (e.getSource() == editor)) {
654 String s = e.getActionCommand();
655 try {
656 fg = Color.decode(s);
657 } catch (NumberFormatException nfe) {
658 }
659 }
660 if (fg != null) {
661 MutableAttributeSet attr = new SimpleAttributeSet();
662 StyleConstants.setForeground(attr, fg);
663 setCharacterAttributes(editor, attr, false);
664 } else {
665 UIManager.getLookAndFeel().provideErrorFeedback(
666 editor);
667 }
668 }
669 }
670
671 private Color fg;
672 }
673
674 /**
675 * An action to set paragraph alignment. This sets the
676 * <code>StyleConstants.Alignment</code> attribute for the
677 * currently selected range of the target JEditorPane.
678 * This is done by calling
679 * <code>StyledDocument.setParagraphAttributes</code>
680 * on the styled document associated with the target
681 * JEditorPane.
682 * <p>
683 * If the target text component is specified as the
684 * source of the ActionEvent and there is a command string,
685 * the command string will be interpreted as an integer
686 * that should be one of the legal values for the
687 * <code>StyleConstants.Alignment</code> attribute.
688 * <p>
689 * <strong>Warning:</strong>
690 * Serialized objects of this class will not be compatible with
691 * future Swing releases. The current serialization support is
692 * appropriate for short term storage or RMI between applications running
693 * the same version of Swing. As of 1.4, support for long term storage
694 * of all JavaBeans<sup><font size="-2">TM</font></sup>
695 * has been added to the <code>java.beans</code> package.
696 * Please see {@link java.beans.XMLEncoder}.
697 */
698 public static class AlignmentAction extends StyledTextAction {
699
700 /**
701 * Creates a new AlignmentAction.
702 *
703 * @param nm the action name
704 * @param a the alignment >= 0
705 */
706 public AlignmentAction(String nm, int a) {
707 super (nm);
708 this .a = a;
709 }
710
711 /**
712 * Sets the alignment.
713 *
714 * @param e the action event
715 */
716 public void actionPerformed(ActionEvent e) {
717 JEditorPane editor = getEditor(e);
718 if (editor != null) {
719 int a = this .a;
720 if ((e != null) && (e.getSource() == editor)) {
721 String s = e.getActionCommand();
722 try {
723 a = Integer.parseInt(s, 10);
724 } catch (NumberFormatException nfe) {
725 }
726 }
727 MutableAttributeSet attr = new SimpleAttributeSet();
728 StyleConstants.setAlignment(attr, a);
729 setParagraphAttributes(editor, attr, false);
730 }
731 }
732
733 private int a;
734 }
735
736 /**
737 * An action to toggle the bold attribute.
738 * <p>
739 * <strong>Warning:</strong>
740 * Serialized objects of this class will not be compatible with
741 * future Swing releases. The current serialization support is
742 * appropriate for short term storage or RMI between applications running
743 * the same version of Swing. As of 1.4, support for long term storage
744 * of all JavaBeans<sup><font size="-2">TM</font></sup>
745 * has been added to the <code>java.beans</code> package.
746 * Please see {@link java.beans.XMLEncoder}.
747 */
748 public static class BoldAction extends StyledTextAction {
749
750 /**
751 * Constructs a new BoldAction.
752 */
753 public BoldAction() {
754 super ("font-bold");
755 }
756
757 /**
758 * Toggles the bold attribute.
759 *
760 * @param e the action event
761 */
762 public void actionPerformed(ActionEvent e) {
763 JEditorPane editor = getEditor(e);
764 if (editor != null) {
765 StyledEditorKit kit = getStyledEditorKit(editor);
766 MutableAttributeSet attr = kit.getInputAttributes();
767 boolean bold = (StyleConstants.isBold(attr)) ? false
768 : true;
769 SimpleAttributeSet sas = new SimpleAttributeSet();
770 StyleConstants.setBold(sas, bold);
771 setCharacterAttributes(editor, sas, false);
772 }
773 }
774 }
775
776 /**
777 * An action to toggle the italic attribute.
778 * <p>
779 * <strong>Warning:</strong>
780 * Serialized objects of this class will not be compatible with
781 * future Swing releases. The current serialization support is
782 * appropriate for short term storage or RMI between applications running
783 * the same version of Swing. As of 1.4, support for long term storage
784 * of all JavaBeans<sup><font size="-2">TM</font></sup>
785 * has been added to the <code>java.beans</code> package.
786 * Please see {@link java.beans.XMLEncoder}.
787 */
788 public static class ItalicAction extends StyledTextAction {
789
790 /**
791 * Constructs a new ItalicAction.
792 */
793 public ItalicAction() {
794 super ("font-italic");
795 }
796
797 /**
798 * Toggles the italic attribute.
799 *
800 * @param e the action event
801 */
802 public void actionPerformed(ActionEvent e) {
803 JEditorPane editor = getEditor(e);
804 if (editor != null) {
805 StyledEditorKit kit = getStyledEditorKit(editor);
806 MutableAttributeSet attr = kit.getInputAttributes();
807 boolean italic = (StyleConstants.isItalic(attr)) ? false
808 : true;
809 SimpleAttributeSet sas = new SimpleAttributeSet();
810 StyleConstants.setItalic(sas, italic);
811 setCharacterAttributes(editor, sas, false);
812 }
813 }
814 }
815
816 /**
817 * An action to toggle the underline attribute.
818 * <p>
819 * <strong>Warning:</strong>
820 * Serialized objects of this class will not be compatible with
821 * future Swing releases. The current serialization support is
822 * appropriate for short term storage or RMI between applications running
823 * the same version of Swing. As of 1.4, support for long term storage
824 * of all JavaBeans<sup><font size="-2">TM</font></sup>
825 * has been added to the <code>java.beans</code> package.
826 * Please see {@link java.beans.XMLEncoder}.
827 */
828 public static class UnderlineAction extends StyledTextAction {
829
830 /**
831 * Constructs a new UnderlineAction.
832 */
833 public UnderlineAction() {
834 super ("font-underline");
835 }
836
837 /**
838 * Toggles the Underline attribute.
839 *
840 * @param e the action event
841 */
842 public void actionPerformed(ActionEvent e) {
843 JEditorPane editor = getEditor(e);
844 if (editor != null) {
845 StyledEditorKit kit = getStyledEditorKit(editor);
846 MutableAttributeSet attr = kit.getInputAttributes();
847 boolean underline = (StyleConstants.isUnderline(attr)) ? false
848 : true;
849 SimpleAttributeSet sas = new SimpleAttributeSet();
850 StyleConstants.setUnderline(sas, underline);
851 setCharacterAttributes(editor, sas, false);
852 }
853 }
854 }
855
856 /**
857 * StyledInsertBreakAction has similar behavior to that of
858 * <code>DefaultEditorKit.InsertBreakAction</code>. That is when
859 * its <code>actionPerformed</code> method is invoked, a newline
860 * is inserted. Beyond that, this will reset the input attributes to
861 * what they were before the newline was inserted.
862 */
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(
876 target);
877 return;
878 }
879 StyledEditorKit sek = getStyledEditorKit(target);
880
881 if (tempSet != null) {
882 tempSet.removeAttributes(tempSet);
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 } else {
895 // See if we are in a JTextComponent.
896 JTextComponent text = getTextComponent(e);
897
898 if (text != null) {
899 if ((!text.isEditable()) || (!text.isEnabled())) {
900 UIManager.getLookAndFeel()
901 .provideErrorFeedback(target);
902 return;
903 }
904 text.replaceSelection("\n");
905 }
906 }
907 }
908 }
909 }
|