a2aebd4ca684dbd6561fb75f3226d9eabf82080e
[gcc.git] / libjava / classpath / javax / swing / JTextPane.java
1 /* JTextPane.java -- A powerful text widget supporting styled text
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38
39 package javax.swing;
40
41 import java.awt.Component;
42
43 import javax.swing.text.AttributeSet;
44 import javax.swing.text.BadLocationException;
45 import javax.swing.text.Caret;
46 import javax.swing.text.Document;
47 import javax.swing.text.EditorKit;
48 import javax.swing.text.Element;
49 import javax.swing.text.MutableAttributeSet;
50 import javax.swing.text.SimpleAttributeSet;
51 import javax.swing.text.Style;
52 import javax.swing.text.StyleConstants;
53 import javax.swing.text.StyledDocument;
54 import javax.swing.text.StyledEditorKit;
55
56 /**
57 * A powerful text component that supports styled content as well as
58 * embedding images and components. It is entirely based on a
59 * {@link StyledDocument} content model and a {@link StyledEditorKit}.
60 *
61 * @author Roman Kennke (roman@kennke.org)
62 * @author Andrew Selkirk
63 */
64 public class JTextPane
65 extends JEditorPane
66 {
67 /**
68 * Creates a new <code>JTextPane</code> with a <code>null</code> document.
69 */
70 public JTextPane()
71 {
72 super();
73 }
74
75 /**
76 * Creates a new <code>JTextPane</code> and sets the specified
77 * <code>document</code>.
78 *
79 * @param document the content model to use
80 */
81 public JTextPane(StyledDocument document)
82 {
83 this();
84 setStyledDocument(document);
85 }
86
87 /**
88 * Returns the UI class ID. This is <code>TextPaneUI</code>.
89 *
90 * @return <code>TextPaneUI</code>
91 */
92 public String getUIClassID()
93 {
94 return "TextPaneUI";
95 }
96
97 /**
98 * Sets the content model for this <code>JTextPane</code>.
99 * <code>JTextPane</code> can only be used with {@link StyledDocument}s,
100 * if you try to set a different type of <code>Document</code>, an
101 * <code>IllegalArgumentException</code> is thrown.
102 *
103 * @param document the content model to set
104 *
105 * @throws IllegalArgumentException if <code>document</code> is not an
106 * instance of <code>StyledDocument</code>
107 *
108 * @see #setStyledDocument
109 */
110 public void setDocument(Document document)
111 {
112 if (document != null && !(document instanceof StyledDocument))
113 throw new IllegalArgumentException
114 ("JTextPane can only handle StyledDocuments");
115
116 setStyledDocument((StyledDocument) document);
117 }
118
119 /**
120 * Returns the {@link StyledDocument} that is the content model for
121 * this <code>JTextPane</code>. This is a typed wrapper for
122 * {@link #getDocument()}.
123 *
124 * @return the content model of this <code>JTextPane</code>
125 */
126 public StyledDocument getStyledDocument()
127 {
128 return (StyledDocument) super.getDocument();
129 }
130
131 /**
132 * Sets the content model for this <code>JTextPane</code>.
133 *
134 * @param document the content model to set
135 */
136 public void setStyledDocument(StyledDocument document)
137 {
138 super.setDocument(document);
139 }
140
141 /**
142 * Replaces the currently selected text with the specified
143 * <code>content</code>. If there is no selected text, this results
144 * in a simple insertion at the current caret position. If there is
145 * no <code>content</code> specified, this results in the selection
146 * beeing deleted.
147 *
148 * @param content the text with which the selection is replaced
149 */
150 public void replaceSelection(String content)
151 {
152 Caret caret = getCaret();
153 StyledDocument doc = getStyledDocument();
154
155 int dot = caret.getDot();
156 int mark = caret.getMark();
157
158 // If content is empty delete selection.
159 if (content == null)
160 {
161 caret.setDot(dot);
162 return;
163 }
164
165 try
166 {
167 int start = getSelectionStart();
168 int end = getSelectionEnd();
169 int contentLength = content.length();
170
171 // Remove selected text.
172 if (dot != mark)
173 doc.remove(start, end - start);
174
175 // Insert new text.
176 doc.insertString(start, content, null);
177 // Set attributes for inserted text
178 doc.setCharacterAttributes(start, contentLength, getInputAttributes(),
179 true);
180
181 }
182 catch (BadLocationException e)
183 {
184 throw new AssertionError
185 ("No BadLocationException should be thrown here");
186 }
187 }
188
189 /**
190 * Inserts an AWT or Swing component into the text at the current caret
191 * position.
192 *
193 * @param component the component to be inserted
194 */
195 public void insertComponent(Component component)
196 {
197 SimpleAttributeSet atts = new SimpleAttributeSet();
198 atts.addAttribute(StyleConstants.ComponentAttribute, component);
199 atts.addAttribute(StyleConstants.NameAttribute,
200 StyleConstants.ComponentElementName);
201 try
202 {
203 getDocument().insertString(getCaret().getDot(), " ", atts);
204 }
205 catch (BadLocationException ex)
206 {
207 AssertionError err = new AssertionError("Unexpected bad location");
208 err.initCause(ex);
209 throw err;
210 }
211 }
212
213 /**
214 * Inserts an <code>Icon</code> into the text at the current caret position.
215 *
216 * @param icon the <code>Icon</code> to be inserted
217 */
218 public void insertIcon(Icon icon)
219 {
220 SimpleAttributeSet atts = new SimpleAttributeSet();
221 atts.addAttribute(StyleConstants.IconAttribute, icon);
222 atts.addAttribute(StyleConstants.NameAttribute,
223 StyleConstants.IconElementName);
224 try
225 {
226 getDocument().insertString(getCaret().getDot(), " ", atts);
227 }
228 catch (BadLocationException ex)
229 {
230 AssertionError err = new AssertionError("Unexpected bad location");
231 err.initCause(ex);
232 throw err;
233 }
234 }
235
236 /**
237 * Adds a style into the style hierarchy. Unspecified style attributes
238 * can be resolved in the <code>parent</code> style, if one is specified.
239 *
240 * While it is legal to add nameless styles (<code>nm == null</code),
241 * you must be aware that the client application is then responsible
242 * for managing the style hierarchy, since unnamed styles cannot be
243 * looked up by their name.
244 *
245 * @param nm the name of the style or <code>null</code> if the style should
246 * be unnamed
247 * @param parent the parent in which unspecified style attributes are
248 * resolved, or <code>null</code> if that is not necessary
249 *
250 * @return the newly created <code>Style</code>
251 */
252 public Style addStyle(String nm, Style parent)
253 {
254 return getStyledDocument().addStyle(nm, parent);
255 }
256
257 /**
258 * Removes a named <code>Style</code> from the style hierarchy.
259 *
260 * @param nm the name of the <code>Style</code> to be removed
261 */
262 public void removeStyle(String nm)
263 {
264 getStyledDocument().removeStyle(nm);
265 }
266
267 /**
268 * Looks up and returns a named <code>Style</code>.
269 *
270 * @param nm the name of the <code>Style</code>
271 *
272 * @return the found <code>Style</code> of <code>null</code> if no such
273 * <code>Style</code> exists
274 */
275 public Style getStyle(String nm)
276 {
277 return getStyledDocument().getStyle(nm);
278 }
279
280 /**
281 * Returns the logical style of the paragraph at the current caret position.
282 *
283 * @return the logical style of the paragraph at the current caret position
284 */
285 public Style getLogicalStyle()
286 {
287 return getStyledDocument().getLogicalStyle(getCaretPosition());
288 }
289
290 /**
291 * Sets the logical style for the paragraph at the current caret position.
292 *
293 * @param style the style to set for the current paragraph
294 */
295 public void setLogicalStyle(Style style)
296 {
297 getStyledDocument().setLogicalStyle(getCaretPosition(), style);
298 }
299
300 /**
301 * Returns the text attributes for the character at the current caret
302 * position.
303 *
304 * @return the text attributes for the character at the current caret
305 * position
306 */
307 public AttributeSet getCharacterAttributes()
308 {
309 StyledDocument doc = getStyledDocument();
310 Element el = doc.getCharacterElement(getCaretPosition());
311 return el.getAttributes();
312 }
313
314 /**
315 * Sets text attributes for the current selection. If there is no selection
316 * the text attributes are applied to newly inserted text
317 *
318 * @param attribute the text attributes to set
319 * @param replace if <code>true</code>, the attributes of the current
320 * selection are overridden, otherwise they are merged
321 *
322 * @see #getInputAttributes
323 */
324 public void setCharacterAttributes(AttributeSet attribute,
325 boolean replace)
326 {
327 int dot = getCaret().getDot();
328 int start = getSelectionStart();
329 int end = getSelectionEnd();
330 if (start == dot && end == dot)
331 // There is no selection, update insertAttributes instead
332 {
333 MutableAttributeSet inputAttributes =
334 getStyledEditorKit().getInputAttributes();
335 inputAttributes.addAttributes(attribute);
336 }
337 else
338 getStyledDocument().setCharacterAttributes(start, end - start, attribute,
339 replace);
340 }
341
342 /**
343 * Returns the text attributes of the paragraph at the current caret
344 * position.
345 *
346 * @return the attributes of the paragraph at the current caret position
347 */
348 public AttributeSet getParagraphAttributes()
349 {
350 StyledDocument doc = getStyledDocument();
351 Element el = doc.getParagraphElement(getCaretPosition());
352 return el.getAttributes();
353 }
354
355 /**
356 * Sets text attributes for the paragraph at the current selection.
357 * If there is no selection the text attributes are applied to
358 * the paragraph at the current caret position.
359 *
360 * @param attribute the text attributes to set
361 * @param replace if <code>true</code>, the attributes of the current
362 * selection are overridden, otherwise they are merged
363 */
364 public void setParagraphAttributes(AttributeSet attribute,
365 boolean replace)
366 {
367 // TODO
368 }
369
370 /**
371 * Returns the attributes that are applied to newly inserted text.
372 * This is a {@link MutableAttributeSet}, so you can easily modify these
373 * attributes.
374 *
375 * @return the attributes that are applied to newly inserted text
376 */
377 public MutableAttributeSet getInputAttributes()
378 {
379 return getStyledEditorKit().getInputAttributes();
380 }
381
382 /**
383 * Returns the {@link StyledEditorKit} that is currently used by this
384 * <code>JTextPane</code>.
385 *
386 * @return the current <code>StyledEditorKit</code> of this
387 * <code>JTextPane</code>
388 */
389 protected final StyledEditorKit getStyledEditorKit()
390 {
391 return (StyledEditorKit) getEditorKit();
392 }
393
394 /**
395 * Creates the default {@link EditorKit} that is used in
396 * <code>JTextPane</code>s. This is an instance of {@link StyledEditorKit}.
397 *
398 * @return the default {@link EditorKit} that is used in
399 * <code>JTextPane</code>s
400 */
401 protected EditorKit createDefaultEditorKit()
402 {
403 return new StyledEditorKit();
404 }
405
406 /**
407 * Sets the {@link EditorKit} to use for this <code>JTextPane</code>.
408 * <code>JTextPane</code>s can only handle {@link StyledEditorKit}s,
409 * if client programs try to set a different type of <code>EditorKit</code>
410 * then an IllegalArgumentException is thrown
411 *
412 * @param editor the <code>EditorKit</code> to set
413 *
414 * @throws IllegalArgumentException if <code>editor</code> is no
415 * <code>StyledEditorKit</code>
416 */
417 public final void setEditorKit(EditorKit editor)
418 {
419 if (!(editor instanceof StyledEditorKit))
420 throw new IllegalArgumentException
421 ("JTextPanes can only handle StyledEditorKits");
422 super.setEditorKit(editor);
423 }
424
425 /**
426 * Returns a param string that can be used for debugging.
427 *
428 * @return a param string that can be used for debugging.
429 */
430 protected String paramString()
431 {
432 return super.paramString(); // TODO
433 }
434 }