blob: 69b94a30e42c62335eca27fbf336b548c8b56dee [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 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;
26
27import java.awt.*;
28import java.awt.event.ActionEvent;
29
30import java.io.ObjectOutputStream;
31import java.io.ObjectInputStream;
32import java.io.IOException;
33
34import javax.swing.text.*;
35import javax.swing.event.*;
36import javax.swing.plaf.*;
37
38/**
39 * A text component that can be marked up with attributes that are
40 * represented graphically.
41 * You can find how-to information and examples of using text panes in
42 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/text.html">Using Text Components</a>,
43 * a section in <em>The Java Tutorial.</em>
44 *
45 * <p>
46 * This component models paragraphs
47 * that are composed of runs of character level attributes. Each
48 * paragraph may have a logical style attached to it which contains
49 * the default attributes to use if not overridden by attributes set
50 * on the paragraph or character run. Components and images may
51 * be embedded in the flow of text.
52 * <p>
53 * <dl>
54 * <dt><b><font size=+1>Newlines</font></b>
55 * <dd>
56 * For a discussion on how newlines are handled, see
57 * <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>.
58 * </dl>
59 *
60 * <p>
61 * <strong>Warning:</strong> Swing is not thread safe. For more
62 * information see <a
63 * href="package-summary.html#threading">Swing's Threading
64 * Policy</a>.
65 * <p>
66 * <strong>Warning:</strong>
67 * Serialized objects of this class will not be compatible with
68 * future Swing releases. The current serialization support is
69 * appropriate for short term storage or RMI between applications running
70 * the same version of Swing. As of 1.4, support for long term storage
71 * of all JavaBeans<sup><font size="-2">TM</font></sup>
72 * has been added to the <code>java.beans</code> package.
73 * Please see {@link java.beans.XMLEncoder}.
74 *
75 * @beaninfo
76 * attribute: isContainer true
77 * description: A text component that can be marked up with attributes that are graphically represented.
78 *
79 * @author Timothy Prinzing
80 * @see javax.swing.text.StyledEditorKit
81 */
82public class JTextPane extends JEditorPane {
83
84 /**
85 * Creates a new <code>JTextPane</code>. A new instance of
86 * <code>StyledEditorKit</code> is
87 * created and set, and the document model set to <code>null</code>.
88 */
89 public JTextPane() {
90 super();
91 EditorKit editorKit = createDefaultEditorKit();
92 String contentType = editorKit.getContentType();
93 if (contentType != null
94 && getEditorKitClassNameForContentType(contentType) ==
95 defaultEditorKitMap.get(contentType)) {
96 setEditorKitForContentType(contentType, editorKit);
97 }
98 setEditorKit(editorKit);
99 }
100
101 /**
102 * Creates a new <code>JTextPane</code>, with a specified document model.
103 * A new instance of <code>javax.swing.text.StyledEditorKit</code>
104 * is created and set.
105 *
106 * @param doc the document model
107 */
108 public JTextPane(StyledDocument doc) {
109 this();
110 setStyledDocument(doc);
111 }
112
113 /**
114 * Returns the class ID for the UI.
115 *
116 * @return the string "TextPaneUI"
117 *
118 * @see JComponent#getUIClassID
119 * @see UIDefaults#getUI
120 */
121 public String getUIClassID() {
122 return uiClassID;
123 }
124
125 /**
126 * Associates the editor with a text document. This
127 * must be a <code>StyledDocument</code>.
128 *
129 * @param doc the document to display/edit
130 * @exception IllegalArgumentException if <code>doc</code> can't
131 * be narrowed to a <code>StyledDocument</code> which is the
132 * required type of model for this text component
133 */
134 public void setDocument(Document doc) {
135 if (doc instanceof StyledDocument) {
136 super.setDocument(doc);
137 } else {
138 throw new IllegalArgumentException("Model must be StyledDocument");
139 }
140 }
141
142 /**
143 * Associates the editor with a text document.
144 * The currently registered factory is used to build a view for
145 * the document, which gets displayed by the editor.
146 *
147 * @param doc the document to display/edit
148 */
149 public void setStyledDocument(StyledDocument doc) {
150 super.setDocument(doc);
151 }
152
153 /**
154 * Fetches the model associated with the editor.
155 *
156 * @return the model
157 */
158 public StyledDocument getStyledDocument() {
159 return (StyledDocument) getDocument();
160 }
161
162 /**
163 * Replaces the currently selected content with new content
164 * represented by the given string. If there is no selection
165 * this amounts to an insert of the given text. If there
166 * is no replacement text this amounts to a removal of the
167 * current selection. The replacement text will have the
168 * attributes currently defined for input at the point of
169 * insertion. If the document is not editable, beep and return.
170 * <p>
171 * This method is thread safe, although most Swing methods
172 * are not. Please see
173 * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
174 * to Use Threads</A> for more information.
175 *
176 * @param content the content to replace the selection with
177 */
178 public void replaceSelection(String content) {
179 replaceSelection(content, true);
180 }
181
182 private void replaceSelection(String content, boolean checkEditable) {
183 if (checkEditable && !isEditable()) {
184 UIManager.getLookAndFeel().provideErrorFeedback(JTextPane.this);
185 return;
186 }
187 Document doc = getStyledDocument();
188 if (doc != null) {
189 try {
190 Caret caret = getCaret();
191 int p0 = Math.min(caret.getDot(), caret.getMark());
192 int p1 = Math.max(caret.getDot(), caret.getMark());
193 AttributeSet attr = getInputAttributes().copyAttributes();
194 if (doc instanceof AbstractDocument) {
195 ((AbstractDocument)doc).replace(p0, p1 - p0, content,attr);
196 }
197 else {
198 if (p0 != p1) {
199 doc.remove(p0, p1 - p0);
200 }
201 if (content != null && content.length() > 0) {
202 doc.insertString(p0, content, attr);
203 }
204 }
205 } catch (BadLocationException e) {
206 UIManager.getLookAndFeel().provideErrorFeedback(JTextPane.this);
207 }
208 }
209 }
210
211 /**
212 * Inserts a component into the document as a replacement
213 * for the currently selected content. If there is no
214 * selection the component is effectively inserted at the
215 * current position of the caret. This is represented in
216 * the associated document as an attribute of one character
217 * of content.
218 * <p>
219 * The component given is the actual component used by the
220 * JTextPane. Since components cannot be a child of more than
221 * one container, this method should not be used in situations
222 * where the model is shared by text components.
223 * <p>
224 * The component is placed relative to the text baseline
225 * according to the value returned by
226 * <code>Component.getAlignmentY</code>. For Swing components
227 * this value can be conveniently set using the method
228 * <code>JComponent.setAlignmentY</code>. For example, setting
229 * a value of <code>0.75</code> will cause 75 percent of the
230 * component to be above the baseline, and 25 percent of the
231 * component to be below the baseline.
232 * <p>
233 * This method is thread safe, although most Swing methods
234 * are not. Please see
235 * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
236 * to Use Threads</A> for more information.
237 *
238 * @param c the component to insert
239 */
240 public void insertComponent(Component c) {
241 MutableAttributeSet inputAttributes = getInputAttributes();
242 inputAttributes.removeAttributes(inputAttributes);
243 StyleConstants.setComponent(inputAttributes, c);
244 replaceSelection(" ", false);
245 inputAttributes.removeAttributes(inputAttributes);
246 }
247
248 /**
249 * Inserts an icon into the document as a replacement
250 * for the currently selected content. If there is no
251 * selection the icon is effectively inserted at the
252 * current position of the caret. This is represented in
253 * the associated document as an attribute of one character
254 * of content.
255 * <p>
256 * This method is thread safe, although most Swing methods
257 * are not. Please see
258 * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
259 * to Use Threads</A> for more information.
260 *
261 * @param g the icon to insert
262 * @see Icon
263 */
264 public void insertIcon(Icon g) {
265 MutableAttributeSet inputAttributes = getInputAttributes();
266 inputAttributes.removeAttributes(inputAttributes);
267 StyleConstants.setIcon(inputAttributes, g);
268 replaceSelection(" ", false);
269 inputAttributes.removeAttributes(inputAttributes);
270 }
271
272 /**
273 * Adds a new style into the logical style hierarchy. Style attributes
274 * resolve from bottom up so an attribute specified in a child
275 * will override an attribute specified in the parent.
276 *
277 * @param nm the name of the style (must be unique within the
278 * collection of named styles). The name may be <code>null</code>
279 * if the style is unnamed, but the caller is responsible
280 * for managing the reference returned as an unnamed style can't
281 * be fetched by name. An unnamed style may be useful for things
282 * like character attribute overrides such as found in a style
283 * run.
284 * @param parent the parent style. This may be <code>null</code>
285 * if unspecified
286 * attributes need not be resolved in some other style.
287 * @return the new <code>Style</code>
288 */
289 public Style addStyle(String nm, Style parent) {
290 StyledDocument doc = getStyledDocument();
291 return doc.addStyle(nm, parent);
292 }
293
294 /**
295 * Removes a named non-<code>null</code> style previously added to
296 * the document.
297 *
298 * @param nm the name of the style to remove
299 */
300 public void removeStyle(String nm) {
301 StyledDocument doc = getStyledDocument();
302 doc.removeStyle(nm);
303 }
304
305 /**
306 * Fetches a named non-<code>null</code> style previously added.
307 *
308 * @param nm the name of the style
309 * @return the <code>Style</code>
310 */
311 public Style getStyle(String nm) {
312 StyledDocument doc = getStyledDocument();
313 return doc.getStyle(nm);
314 }
315
316 /**
317 * Sets the logical style to use for the paragraph at the
318 * current caret position. If attributes aren't explicitly set
319 * for character and paragraph attributes they will resolve
320 * through the logical style assigned to the paragraph, which
321 * in term may resolve through some hierarchy completely
322 * independent of the element hierarchy in the document.
323 * <p>
324 * This method is thread safe, although most Swing methods
325 * are not. Please see
326 * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
327 * to Use Threads</A> for more information.
328 *
329 * @param s the logical style to assign to the paragraph,
330 * or <code>null</code> for no style
331 */
332 public void setLogicalStyle(Style s) {
333 StyledDocument doc = getStyledDocument();
334 doc.setLogicalStyle(getCaretPosition(), s);
335 }
336
337 /**
338 * Fetches the logical style assigned to the paragraph represented
339 * by the current position of the caret, or <code>null</code>.
340 *
341 * @return the <code>Style</code>
342 */
343 public Style getLogicalStyle() {
344 StyledDocument doc = getStyledDocument();
345 return doc.getLogicalStyle(getCaretPosition());
346 }
347
348 /**
349 * Fetches the character attributes in effect at the
350 * current location of the caret, or <code>null</code>.
351 *
352 * @return the attributes, or <code>null</code>
353 */
354 public AttributeSet getCharacterAttributes() {
355 StyledDocument doc = getStyledDocument();
356 Element run = doc.getCharacterElement(getCaretPosition());
357 if (run != null) {
358 return run.getAttributes();
359 }
360 return null;
361 }
362
363 /**
364 * Applies the given attributes to character
365 * content. If there is a selection, the attributes
366 * are applied to the selection range. If there
367 * is no selection, the attributes are applied to
368 * the input attribute set which defines the attributes
369 * for any new text that gets inserted.
370 * <p>
371 * This method is thread safe, although most Swing methods
372 * are not. Please see
373 * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
374 * to Use Threads</A> for more information.
375 *
376 * @param attr the attributes
377 * @param replace if true, then replace the existing attributes first
378 */
379 public void setCharacterAttributes(AttributeSet attr, boolean replace) {
380 int p0 = getSelectionStart();
381 int p1 = getSelectionEnd();
382 if (p0 != p1) {
383 StyledDocument doc = getStyledDocument();
384 doc.setCharacterAttributes(p0, p1 - p0, attr, replace);
385 } else {
386 MutableAttributeSet inputAttributes = getInputAttributes();
387 if (replace) {
388 inputAttributes.removeAttributes(inputAttributes);
389 }
390 inputAttributes.addAttributes(attr);
391 }
392 }
393
394 /**
395 * Fetches the current paragraph attributes in effect
396 * at the location of the caret, or <code>null</code> if none.
397 *
398 * @return the attributes
399 */
400 public AttributeSet getParagraphAttributes() {
401 StyledDocument doc = getStyledDocument();
402 Element paragraph = doc.getParagraphElement(getCaretPosition());
403 if (paragraph != null) {
404 return paragraph.getAttributes();
405 }
406 return null;
407 }
408
409 /**
410 * Applies the given attributes to paragraphs. If
411 * there is a selection, the attributes are applied
412 * to the paragraphs that intersect the selection.
413 * If there is no selection, the attributes are applied
414 * to the paragraph at the current caret position.
415 * <p>
416 * This method is thread safe, although most Swing methods
417 * are not. Please see
418 * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
419 * to Use Threads</A> for more information.
420 *
421 * @param attr the non-<code>null</code> attributes
422 * @param replace if true, replace the existing attributes first
423 */
424 public void setParagraphAttributes(AttributeSet attr, boolean replace) {
425 int p0 = getSelectionStart();
426 int p1 = getSelectionEnd();
427 StyledDocument doc = getStyledDocument();
428 doc.setParagraphAttributes(p0, p1 - p0, attr, replace);
429 }
430
431 /**
432 * Gets the input attributes for the pane.
433 *
434 * @return the attributes
435 */
436 public MutableAttributeSet getInputAttributes() {
437 return getStyledEditorKit().getInputAttributes();
438 }
439
440 /**
441 * Gets the editor kit.
442 *
443 * @return the editor kit
444 */
445 protected final StyledEditorKit getStyledEditorKit() {
446 return (StyledEditorKit) getEditorKit();
447 }
448
449 /**
450 * @see #getUIClassID
451 * @see #readObject
452 */
453 private static final String uiClassID = "TextPaneUI";
454
455
456 /**
457 * See <code>readObject</code> and <code>writeObject</code> in
458 * <code>JComponent</code> for more
459 * information about serialization in Swing.
460 *
461 * @param s the output stream
462 */
463 private void writeObject(ObjectOutputStream s) throws IOException {
464 s.defaultWriteObject();
465 if (getUIClassID().equals(uiClassID)) {
466 byte count = JComponent.getWriteObjCounter(this);
467 JComponent.setWriteObjCounter(this, --count);
468 if (count == 0 && ui != null) {
469 ui.installUI(this);
470 }
471 }
472 }
473
474
475 // --- JEditorPane ------------------------------------
476
477 /**
478 * Creates the <code>EditorKit</code> to use by default. This
479 * is implemented to return <code>javax.swing.text.StyledEditorKit</code>.
480 *
481 * @return the editor kit
482 */
483 protected EditorKit createDefaultEditorKit() {
484 return new StyledEditorKit();
485 }
486
487 /**
488 * Sets the currently installed kit for handling
489 * content. This is the bound property that
490 * establishes the content type of the editor.
491 *
492 * @param kit the desired editor behavior
493 * @exception IllegalArgumentException if kit is not a
494 * <code>StyledEditorKit</code>
495 */
496 public final void setEditorKit(EditorKit kit) {
497 if (kit instanceof StyledEditorKit) {
498 super.setEditorKit(kit);
499 } else {
500 throw new IllegalArgumentException("Must be StyledEditorKit");
501 }
502 }
503
504 /**
505 * Returns a string representation of this <code>JTextPane</code>.
506 * This method
507 * is intended to be used only for debugging purposes, and the
508 * content and format of the returned string may vary between
509 * implementations. The returned string may be empty but may not
510 * be <code>null</code>.
511 *
512 * @return a string representation of this <code>JTextPane</code>
513 */
514 protected String paramString() {
515 return super.paramString();
516 }
517
518}