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