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