Merge from mainline
[official-gcc.git] / libjava / classpath / javax / swing / text / StyledEditorKit.java
blobc4eef4463fb7160d189acf0e6545db8d5e004ed1
1 /* StyledEditorKit.java --
2 Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Color;
42 import java.awt.event.ActionEvent;
44 import javax.swing.Action;
45 import javax.swing.JEditorPane;
46 import javax.swing.event.CaretEvent;
47 import javax.swing.event.CaretListener;
49 /**
50 * An {@link EditorKit} that supports editing styled text.
52 * @author Andrew Selkirk
53 * @author Roman Kennke (roman@kennke.org)
55 public class StyledEditorKit extends DefaultEditorKit
57 /** The serialVersionUID. */
58 private static final long serialVersionUID = 7002391892985555948L;
60 /**
61 * Toggles the underline attribute for the selected text.
63 public static class UnderlineAction extends StyledEditorKit.StyledTextAction
65 /**
66 * Creates an instance of <code>UnderlineAction</code>.
68 public UnderlineAction()
70 super("font-underline");
73 /**
74 * Performs the action.
76 * @param event the <code>ActionEvent</code> that describes the action
78 public void actionPerformed(ActionEvent event)
80 JEditorPane editor = getEditor(event);
81 StyledDocument doc = getStyledDocument(editor);
82 Element el = doc.getCharacterElement(editor.getSelectionStart());
83 boolean isUnderline = StyleConstants.isUnderline(el.getAttributes());
84 SimpleAttributeSet atts = new SimpleAttributeSet();
85 StyleConstants.setUnderline(atts, ! isUnderline);
86 setCharacterAttributes(editor, atts, false);
90 /**
91 * Toggles the italic attribute for the selected text.
93 public static class ItalicAction extends StyledEditorKit.StyledTextAction
95 /**
96 * Creates an instance of <code>ItalicAction</code>.
98 public ItalicAction()
100 super("font-italic");
104 * Performs the action.
106 * @param event the <code>ActionEvent</code> that describes the action
108 public void actionPerformed(ActionEvent event)
110 JEditorPane editor = getEditor(event);
111 StyledDocument doc = getStyledDocument(editor);
112 Element el = doc.getCharacterElement(editor.getSelectionStart());
113 boolean isItalic = StyleConstants.isItalic(el.getAttributes());
114 SimpleAttributeSet atts = new SimpleAttributeSet();
115 StyleConstants.setItalic(atts, ! isItalic);
116 setCharacterAttributes(editor, atts, false);
121 * Toggles the bold attribute for the selected text.
123 public static class BoldAction extends StyledEditorKit.StyledTextAction
126 * Creates an instance of <code>BoldAction</code>.
128 public BoldAction()
130 super("font-bold");
134 * Performs the action.
136 * @param event the <code>ActionEvent</code> that describes the action
138 public void actionPerformed(ActionEvent event)
140 JEditorPane editor = getEditor(event);
141 StyledDocument doc = getStyledDocument(editor);
142 Element el = doc.getCharacterElement(editor.getSelectionStart());
143 boolean isBold = StyleConstants.isBold(el.getAttributes());
144 SimpleAttributeSet atts = new SimpleAttributeSet();
145 StyleConstants.setItalic(atts, ! isBold);
146 setCharacterAttributes(editor, atts, false);
151 * Sets the alignment attribute on the selected text.
153 public static class AlignmentAction extends StyledEditorKit.StyledTextAction
156 * The aligment to set.
158 private int a;
161 * Creates a new instance of <code>AlignmentAction</code> to set the
162 * alignment to <code>a</code>.
164 * @param nm the name of the Action
165 * @param a the alignment to set
167 public AlignmentAction(String nm, int a)
169 super(nm);
170 this.a = a;
174 * Performs the action.
176 * @param event the <code>ActionEvent</code> that describes the action
178 public void actionPerformed(ActionEvent event)
180 SimpleAttributeSet atts = new SimpleAttributeSet();
181 StyleConstants.setAlignment(atts, a);
182 setParagraphAttributes(getEditor(event), atts, false);
187 * Sets the foreground color attribute on the selected text.
189 public static class ForegroundAction extends StyledEditorKit.StyledTextAction
192 * The foreground color to set.
194 private Color fg;
197 * Creates a new instance of <code>ForegroundAction</code> to set the
198 * foreground color to <code>fg</code>.
200 * @param nm the name of the Action
201 * @param fg the foreground color to set
203 public ForegroundAction(String nm, Color fg)
205 super(nm);
206 this.fg = fg;
210 * Performs the action.
212 * @param event the <code>ActionEvent</code> that describes the action
214 public void actionPerformed(ActionEvent event)
216 SimpleAttributeSet atts = new SimpleAttributeSet();
217 StyleConstants.setForeground(atts, fg);
218 setCharacterAttributes(getEditor(event), atts, false);
223 * Sets the font size attribute on the selected text.
225 public static class FontSizeAction extends StyledEditorKit.StyledTextAction
228 * The font size to set.
230 private int size;
233 * Creates a new instance of <code>FontSizeAction</code> to set the
234 * font size to <code>size</code>.
236 * @param nm the name of the Action
237 * @param size the font size to set
239 public FontSizeAction(String nm, int size)
241 super(nm);
242 this.size = size;
246 * Performs the action.
248 * @param event the <code>ActionEvent</code> that describes the action
250 public void actionPerformed(ActionEvent event)
252 SimpleAttributeSet atts = new SimpleAttributeSet();
253 StyleConstants.setFontSize(atts, size);
254 setCharacterAttributes(getEditor(event), atts, false);
259 * Sets the font family attribute on the selected text.
261 public static class FontFamilyAction extends StyledEditorKit.StyledTextAction
264 * The font family to set.
266 private String family;
269 * Creates a new instance of <code>FontFamilyAction</code> to set the
270 * font family to <code>family</code>.
272 * @param nm the name of the Action
273 * @param family the font family to set
275 public FontFamilyAction(String nm, String family)
277 super(nm);
278 this.family = family;
282 * Performs the action.
284 * @param event the <code>ActionEvent</code> that describes the action
286 public void actionPerformed(ActionEvent event)
288 SimpleAttributeSet atts = new SimpleAttributeSet();
289 StyleConstants.setFontFamily(atts, family);
290 setCharacterAttributes(getEditor(event), atts, false);
295 * The abstract superclass of all styled TextActions. This class
296 * provides some useful methods to manipulate the text attributes.
298 public abstract static class StyledTextAction extends TextAction
301 * Creates a new instance of <code>StyledTextAction</code>.
303 * @param nm the name of the <code>StyledTextAction</code>
305 public StyledTextAction(String nm)
307 super(nm);
311 * Returns the <code>JEditorPane</code> component from which the
312 * <code>ActionEvent</code> originated.
314 * @param event the <code>ActionEvent</code>
315 * @return the <code>JEditorPane</code> component from which the
316 * <code>ActionEvent</code> originated
318 protected final JEditorPane getEditor(ActionEvent event)
320 return (JEditorPane) getTextComponent(event);
324 * Sets the specified character attributes on the currently selected
325 * text of <code>editor</code>. If <code>editor</code> does not have
326 * a selection, then the attributes are used as input attributes
327 * for newly inserted content.
329 * @param editor the <code>JEditorPane</code> component
330 * @param atts the text attributes to set
331 * @param replace if <code>true</code> the current attributes of the
332 * selection are replaces, otherwise they are merged
334 protected final void setCharacterAttributes(JEditorPane editor,
335 AttributeSet atts,
336 boolean replace)
338 Document doc = editor.getDocument();
339 if (doc instanceof StyledDocument)
341 StyledDocument styleDoc = (StyledDocument) editor.getDocument();
342 EditorKit kit = editor.getEditorKit();
343 if (!(kit instanceof StyledEditorKit))
345 StyledEditorKit styleKit = (StyledEditorKit) kit;
346 int start = editor.getSelectionStart();
347 int end = editor.getSelectionEnd();
348 int dot = editor.getCaret().getDot();
349 if (start == dot && end == dot)
351 // If there is no selection, then we only update the
352 // input attributes.
353 MutableAttributeSet inputAttributes =
354 styleKit.getInputAttributes();
355 inputAttributes.addAttributes(atts);
357 else
358 styleDoc.setCharacterAttributes(start, end, atts, replace);
360 else
361 throw new AssertionError("The EditorKit for StyledTextActions "
362 + "is expected to be a StyledEditorKit");
364 else
365 throw new AssertionError("The Document for StyledTextActions is "
366 + "expected to be a StyledDocument.");
370 * Returns the {@link StyledDocument} that is used by <code>editor</code>.
372 * @param editor the <code>JEditorPane</code> from which to get the
373 * <code>StyledDocument</code>
375 * @return the {@link StyledDocument} that is used by <code>editor</code>
377 protected final StyledDocument getStyledDocument(JEditorPane editor)
379 Document doc = editor.getDocument();
380 if (!(doc instanceof StyledDocument))
381 throw new AssertionError("The Document for StyledEditorKits is "
382 + "expected to be a StyledDocument.");
384 return (StyledDocument) doc;
388 * Returns the {@link StyledEditorKit} that is used by <code>editor</code>.
390 * @param editor the <code>JEditorPane</code> from which to get the
391 * <code>StyledEditorKit</code>
393 * @return the {@link StyledEditorKit} that is used by <code>editor</code>
395 protected final StyledEditorKit getStyledEditorKit(JEditorPane editor)
397 EditorKit kit = editor.getEditorKit();
398 if (!(kit instanceof StyledEditorKit))
399 throw new AssertionError("The EditorKit for StyledDocuments is "
400 + "expected to be a StyledEditorKit.");
402 return (StyledEditorKit) kit;
406 * Sets the specified character attributes on the paragraph that
407 * contains the currently selected
408 * text of <code>editor</code>. If <code>editor</code> does not have
409 * a selection, then the attributes are set on the paragraph that
410 * contains the current caret position.
412 * @param editor the <code>JEditorPane</code> component
413 * @param atts the text attributes to set
414 * @param replace if <code>true</code> the current attributes of the
415 * selection are replaces, otherwise they are merged
417 protected final void setParagraphAttributes(JEditorPane editor,
418 AttributeSet atts,
419 boolean replace)
421 Document doc = editor.getDocument();
422 if (doc instanceof StyledDocument)
424 StyledDocument styleDoc = (StyledDocument) editor.getDocument();
425 EditorKit kit = editor.getEditorKit();
426 if (!(kit instanceof StyledEditorKit))
428 StyledEditorKit styleKit = (StyledEditorKit) kit;
429 int start = editor.getSelectionStart();
430 int end = editor.getSelectionEnd();
431 int dot = editor.getCaret().getDot();
432 if (start == dot && end == dot)
434 // If there is no selection, then we only update the
435 // input attributes.
436 MutableAttributeSet inputAttributes =
437 styleKit.getInputAttributes();
438 inputAttributes.addAttributes(atts);
440 else
441 styleDoc.setParagraphAttributes(start, end, atts, replace);
443 else
444 throw new AssertionError("The EditorKit for StyledTextActions "
445 + "is expected to be a StyledEditorKit");
447 else
448 throw new AssertionError("The Document for StyledTextActions is "
449 + "expected to be a StyledDocument.");
454 * A {@link ViewFactory} that is able to create {@link View}s for
455 * the <code>Element</code>s that are supported by
456 * <code>StyledEditorKit</code>, namely the following types of Elements:
458 * <ul>
459 * <li>{@link AbstractDocument#ContentElementName}</li>
460 * <li>{@link AbstractDocument#ParagraphElementName}</li>
461 * <li>{@link AbstractDocument#SectionElementName}</li>
462 * <li>{@link StyleConstants#ComponentElementName}</li>
463 * <li>{@link StyleConstants#IconElementName}</li>
464 * </ul>
466 static class StyledViewFactory
467 implements ViewFactory
470 * Creates a {@link View} for the specified <code>Element</code>.
472 * @param element the <code>Element</code> to create a <code>View</code>
473 * for
474 * @return the <code>View</code> for the specified <code>Element</code>
475 * or <code>null</code> if the type of <code>element</code> is
476 * not supported
478 public View create(Element element)
480 String name = element.getName();
481 View view = null;
482 if (name.equals(AbstractDocument.ContentElementName))
483 view = new LabelView(element);
484 else if (name.equals(AbstractDocument.ParagraphElementName))
485 view = new ParagraphView(element);
486 else if (name.equals(AbstractDocument.SectionElementName))
487 view = new BoxView(element, View.Y_AXIS);
488 else if (name.equals(StyleConstants.ComponentElementName))
489 view = new ComponentView(element);
490 else if (name.equals(StyleConstants.IconElementName))
491 view = new IconView(element);
492 else
493 throw new AssertionError("Unknown Element type: "
494 + element.getClass().getName() + " : "
495 + name);
496 return view;
501 * Keeps track of the caret position and updates the currentRun
502 * <code>Element</code> and the <code>inputAttributes</code>.
504 class CaretTracker
505 implements CaretListener
508 * Notifies an update of the caret position.
510 * @param ev the event for the caret update
512 public void caretUpdate(CaretEvent ev)
514 Object source = ev.getSource();
515 if (!(source instanceof JTextComponent))
516 throw new AssertionError("CaretEvents are expected to come from a"
517 + "JTextComponent.");
519 JTextComponent text = (JTextComponent) source;
520 Document doc = text.getDocument();
521 if (!(doc instanceof StyledDocument))
522 throw new AssertionError("The Document used by StyledEditorKits is"
523 + "expected to be a StyledDocument");
525 StyledDocument styleDoc = (StyledDocument) doc;
526 currentRun = styleDoc.getCharacterElement(ev.getDot());
527 createInputAttributes(currentRun, inputAttributes);
532 * Stores the <code>Element</code> at the current caret position. This
533 * is updated by {@link CaretTracker}.
535 Element currentRun;
538 * The current input attributes. This is updated by {@link CaretTracker}.
540 MutableAttributeSet inputAttributes;
543 * The CaretTracker that keeps track of the current input attributes, and
544 * the current character run Element.
546 CaretTracker caretTracker;
549 * The ViewFactory for StyledEditorKits.
551 StyledViewFactory viewFactory;
554 * Creates a new instance of <code>StyledEditorKit</code>.
556 public StyledEditorKit()
558 inputAttributes = new SimpleAttributeSet();
562 * Creates an exact copy of this <code>StyledEditorKit</code>.
564 * @return an exact copy of this <code>StyledEditorKit</code>
566 public Object clone()
568 StyledEditorKit clone = (StyledEditorKit) super.clone();
569 // FIXME: Investigate which fields must be copied.
570 return clone;
574 * Returns the <code>Action</code>s supported by this {@link EditorKit}.
575 * This includes the {@link BoldAction}, {@link ItalicAction} and
576 * {@link UnderlineAction} as well as the <code>Action</code>s supported
577 * by {@link DefaultEditorKit}.
579 * The other <code>Action</code>s of <code>StyledEditorKit</code> are not
580 * returned here, since they require a parameter and thus custom
581 * instantiation.
583 * @return the <code>Action</code>s supported by this {@link EditorKit}
585 public Action[] getActions()
587 Action[] actions1 = super.getActions();
588 Action[] myActions = new Action[] {
589 new FontSizeAction("font-size-8", 8),
590 new FontSizeAction("font-size-10", 10),
591 new FontSizeAction("font-size-12", 12),
592 new FontSizeAction("font-size-14", 14),
593 new FontSizeAction("font-size-16", 16),
594 new FontSizeAction("font-size-18", 18),
595 new FontSizeAction("font-size-24", 24),
596 new FontSizeAction("font-size-36", 36),
597 new FontSizeAction("font-size-48", 48),
598 new FontFamilyAction("font-family-Serif", "Serif"),
599 new FontFamilyAction("font-family-Monospaced", "Monospaced"),
600 new FontFamilyAction("font-family-SansSerif", "SansSerif"),
601 new AlignmentAction("left-justify", StyleConstants.ALIGN_LEFT),
602 new AlignmentAction("center-justify", StyleConstants.ALIGN_CENTER),
603 new AlignmentAction("right-justify", StyleConstants.ALIGN_RIGHT),
604 new BoldAction(),
605 new ItalicAction(),
606 new UnderlineAction()
608 return TextAction.augmentList(actions1, myActions);
612 * Returns the current input attributes. These are automatically set on
613 * any newly inserted content, if not specified otherwise.
615 * @return the current input attributes
617 public MutableAttributeSet getInputAttributes()
619 return inputAttributes;
623 * Returns the {@link Element} that represents the character run at the
624 * current caret position.
626 * @return the {@link Element} that represents the character run at the
627 * current caret position
629 public Element getCharacterAttributeRun()
631 return currentRun;
635 * Creates the default {@link Document} supported by this
636 * <code>EditorKit</code>. This is an instance of
637 * {@link DefaultStyledDocument} in this case but may be overridden by
638 * subclasses.
640 * @return an instance of <code>DefaultStyledDocument</code>
642 public Document createDefaultDocument()
644 return new DefaultStyledDocument();
648 * Installs this <code>EditorKit</code> on the specified {@link JEditorPane}.
649 * This basically involves setting up required listeners on the
650 * <code>JEditorPane</code>.
652 * @param component the <code>JEditorPane</code> to install this
653 * <code>EditorKit</code> on
655 public void install(JEditorPane component)
657 CaretTracker tracker = new CaretTracker();
658 component.addCaretListener(tracker);
662 * Deinstalls this <code>EditorKit</code> from the specified
663 * {@link JEditorPane}. This basically involves removing all listeners from
664 * <code>JEditorPane</code> that have been set up by this
665 * <code>EditorKit</code>.
667 * @param component the <code>JEditorPane</code> from which to deinstall this
668 * <code>EditorKit</code>
670 public void deinstall(JEditorPane component)
672 CaretTracker t = caretTracker;
673 if (t != null)
674 component.removeCaretListener(t);
675 caretTracker = null;
679 * Returns a {@link ViewFactory} that is able to create {@link View}s
680 * for {@link Element}s that are supported by this <code>EditorKit</code>,
681 * namely the following types of <code>Element</code>s:
683 * <ul>
684 * <li>{@link AbstractDocument#ContentElementName}</li>
685 * <li>{@link AbstractDocument#ParagraphElementName}</li>
686 * <li>{@link AbstractDocument#SectionElementName}</li>
687 * <li>{@link StyleConstants#ComponentElementName}</li>
688 * <li>{@link StyleConstants#IconElementName}</li>
689 * </ul>
691 * @return a {@link ViewFactory} that is able to create {@link View}s
692 * for {@link Element}s that are supported by this <code>EditorKit</code>
694 public ViewFactory getViewFactory()
696 if (viewFactory == null)
697 viewFactory = new StyledViewFactory();
698 return viewFactory;
702 * Copies the text attributes from <code>element</code> to <code>set</code>.
703 * This is called everytime when the caret position changes to keep
704 * track of the current input attributes. The attributes in <code>set</code>
705 * are cleaned before adding the attributes of <code>element</code>.
707 * This method filters out attributes for element names, <code>Icon</code>s
708 * and <code>Component</code>s.
710 * @param element the <code>Element</code> from which to copy the text
711 * attributes
712 * @param set the inputAttributes to copy the attributes to
714 protected void createInputAttributes(Element element,
715 MutableAttributeSet set)
717 // FIXME: Filter out component, icon and element name attributes.
718 set.removeAttributes(set);
719 set.addAttributes(element.getAttributes());