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
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
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);
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 }
|
27 import java.io.*;
28 import java.awt.*;
29 import java.awt.event.ActionEvent;
30 import java.beans.PropertyChangeEvent;
31 import java.beans.PropertyChangeListener;
32 import javax.swing.event.*;
33 import javax.swing.Action;
34 import javax.swing.JEditorPane;
35 import javax.swing.KeyStroke;
36 import javax.swing.UIManager;
37
38 /**
39 * This is the set of things needed by a text component
40 * to be a reasonably functioning editor for some <em>type</em>
41 * of text document. This implementation provides a default
42 * implementation which treats text as styled text and
43 * provides a minimal set of actions for editing styled text.
44 *
45 * @author Timothy Prinzing
46 */
47 @SuppressWarnings("serial") // Same-version serialization only
48 public class StyledEditorKit extends DefaultEditorKit {
49
50 /**
51 * Creates a new EditorKit used for styled documents.
52 */
53 public StyledEditorKit() {
54 createInputAttributeUpdated();
55 createInputAttributes();
56 }
57
58 /**
59 * Gets the input attributes for the pane. When
60 * the caret moves and there is no selection, the
61 * input attributes are automatically mutated to
62 * reflect the character attributes of the current
63 * caret location. The styled editing actions
64 * use the input attributes to carry out their
65 * actions.
66 *
67 * @return the attribute set
154 public ViewFactory getViewFactory() {
155 return defaultFactory;
156 }
157
158 /**
159 * Creates a copy of the editor kit.
160 *
161 * @return the copy
162 */
163 public Object clone() {
164 StyledEditorKit o = (StyledEditorKit)super.clone();
165 o.currentRun = o.currentParagraph = null;
166 o.createInputAttributeUpdated();
167 o.createInputAttributes();
168 return o;
169 }
170
171 /**
172 * Creates the AttributeSet used for the selection.
173 */
174 @SuppressWarnings("serial") // anonymous class
175 private void createInputAttributes() {
176 inputAttributes = new SimpleAttributeSet() {
177 public AttributeSet getResolveParent() {
178 return (currentParagraph != null) ?
179 currentParagraph.getAttributes() : null;
180 }
181
182 public Object clone() {
183 return new SimpleAttributeSet(this);
184 }
185 };
186 }
187
188 /**
189 * Creates a new <code>AttributeTracker</code>.
190 */
191 private void createInputAttributeUpdated() {
192 inputAttributeUpdater = new AttributeTracker();
193 }
194
203 * input attributes.
204 */
205 MutableAttributeSet inputAttributes;
206
207 /**
208 * This listener will be attached to the caret of
209 * the text component that the EditorKit gets installed
210 * into. This should keep the input attributes updated
211 * for use by the styled actions.
212 */
213 private AttributeTracker inputAttributeUpdater;
214
215 /**
216 * Tracks caret movement and keeps the input attributes set
217 * to reflect the current set of attribute definitions at the
218 * caret position.
219 * <p>This implements PropertyChangeListener to update the
220 * input attributes when the Document changes, as if the Document
221 * changes the attributes will almost certainly change.
222 */
223 @SuppressWarnings("serial") // JDK-implementation class
224 class AttributeTracker implements CaretListener, PropertyChangeListener, Serializable {
225
226 /**
227 * Updates the attributes. <code>dot</code> and <code>mark</code>
228 * mark give the positions of the selection in <code>c</code>.
229 */
230 void updateInputAttributes(int dot, int mark, JTextComponent c) {
231 // EditorKit might not have installed the StyledDocument yet.
232 Document aDoc = c.getDocument();
233 if (!(aDoc instanceof StyledDocument)) {
234 return ;
235 }
236 int start = Math.min(dot, mark);
237 // record current character attributes.
238 StyledDocument doc = (StyledDocument)aDoc;
239 // If nothing is selected, get the attributes from the character
240 // before the start of the selection, otherwise get the attributes
241 // from the character element at the start of the selection.
242 Element run;
243 currentParagraph = doc.getParagraphElement(start);
840 JEditorPane editor = getEditor(e);
841 if (editor != null) {
842 StyledEditorKit kit = getStyledEditorKit(editor);
843 MutableAttributeSet attr = kit.getInputAttributes();
844 boolean underline = (StyleConstants.isUnderline(attr)) ? false : true;
845 SimpleAttributeSet sas = new SimpleAttributeSet();
846 StyleConstants.setUnderline(sas, underline);
847 setCharacterAttributes(editor, sas, false);
848 }
849 }
850 }
851
852
853 /**
854 * StyledInsertBreakAction has similar behavior to that of
855 * <code>DefaultEditorKit.InsertBreakAction</code>. That is when
856 * its <code>actionPerformed</code> method is invoked, a newline
857 * is inserted. Beyond that, this will reset the input attributes to
858 * what they were before the newline was inserted.
859 */
860 @SuppressWarnings("serial") // Superclass is not serializable across versions
861 static class StyledInsertBreakAction extends StyledTextAction {
862 private SimpleAttributeSet tempSet;
863
864 StyledInsertBreakAction() {
865 super(insertBreakAction);
866 }
867
868 public void actionPerformed(ActionEvent e) {
869 JEditorPane target = getEditor(e);
870
871 if (target != null) {
872 if ((!target.isEditable()) || (!target.isEnabled())) {
873 UIManager.getLookAndFeel().provideErrorFeedback(target);
874 return;
875 }
876 StyledEditorKit sek = getStyledEditorKit(target);
877
878 if (tempSet != null) {
879 tempSet.removeAttributes(tempSet);
880 }
|