Frames | No Frames |
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: }