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: MutableAttributeSet inputAtts = getInputAttributes(); 218: inputAtts.removeAttributes(inputAtts); 219: StyleConstants.setIcon(inputAtts, icon); 220: replaceSelection(" "); 221: inputAtts.removeAttributes(inputAtts); 222: } 223: 224: /** 225: * Adds a style into the style hierarchy. Unspecified style attributes 226: * can be resolved in the <code>parent</code> style, if one is specified. 227: * 228: * While it is legal to add nameless styles (<code>nm == null</code), 229: * you must be aware that the client application is then responsible 230: * for managing the style hierarchy, since unnamed styles cannot be 231: * looked up by their name. 232: * 233: * @param nm the name of the style or <code>null</code> if the style should 234: * be unnamed 235: * @param parent the parent in which unspecified style attributes are 236: * resolved, or <code>null</code> if that is not necessary 237: * 238: * @return the newly created <code>Style</code> 239: */ 240: public Style addStyle(String nm, Style parent) 241: { 242: return getStyledDocument().addStyle(nm, parent); 243: } 244: 245: /** 246: * Removes a named <code>Style</code> from the style hierarchy. 247: * 248: * @param nm the name of the <code>Style</code> to be removed 249: */ 250: public void removeStyle(String nm) 251: { 252: getStyledDocument().removeStyle(nm); 253: } 254: 255: /** 256: * Looks up and returns a named <code>Style</code>. 257: * 258: * @param nm the name of the <code>Style</code> 259: * 260: * @return the found <code>Style</code> of <code>null</code> if no such 261: * <code>Style</code> exists 262: */ 263: public Style getStyle(String nm) 264: { 265: return getStyledDocument().getStyle(nm); 266: } 267: 268: /** 269: * Returns the logical style of the paragraph at the current caret position. 270: * 271: * @return the logical style of the paragraph at the current caret position 272: */ 273: public Style getLogicalStyle() 274: { 275: return getStyledDocument().getLogicalStyle(getCaretPosition()); 276: } 277: 278: /** 279: * Sets the logical style for the paragraph at the current caret position. 280: * 281: * @param style the style to set for the current paragraph 282: */ 283: public void setLogicalStyle(Style style) 284: { 285: getStyledDocument().setLogicalStyle(getCaretPosition(), style); 286: } 287: 288: /** 289: * Returns the text attributes for the character at the current caret 290: * position. 291: * 292: * @return the text attributes for the character at the current caret 293: * position 294: */ 295: public AttributeSet getCharacterAttributes() 296: { 297: StyledDocument doc = getStyledDocument(); 298: Element el = doc.getCharacterElement(getCaretPosition()); 299: return el.getAttributes(); 300: } 301: 302: /** 303: * Sets text attributes for the current selection. If there is no selection 304: * the text attributes are applied to newly inserted text 305: * 306: * @param attribute the text attributes to set 307: * @param replace if <code>true</code>, the attributes of the current 308: * selection are overridden, otherwise they are merged 309: * 310: * @see #getInputAttributes 311: */ 312: public void setCharacterAttributes(AttributeSet attribute, 313: boolean replace) 314: { 315: int dot = getCaret().getDot(); 316: int start = getSelectionStart(); 317: int end = getSelectionEnd(); 318: if (start == dot && end == dot) 319: // There is no selection, update insertAttributes instead 320: { 321: MutableAttributeSet inputAttributes = 322: getStyledEditorKit().getInputAttributes(); 323: if (replace) 324: inputAttributes.removeAttributes(inputAttributes); 325: inputAttributes.addAttributes(attribute); 326: } 327: else 328: getStyledDocument().setCharacterAttributes(start, end - start, attribute, 329: replace); 330: } 331: 332: /** 333: * Returns the text attributes of the paragraph at the current caret 334: * position. 335: * 336: * @return the attributes of the paragraph at the current caret position 337: */ 338: public AttributeSet getParagraphAttributes() 339: { 340: StyledDocument doc = getStyledDocument(); 341: Element el = doc.getParagraphElement(getCaretPosition()); 342: return el.getAttributes(); 343: } 344: 345: /** 346: * Sets text attributes for the paragraph at the current selection. 347: * If there is no selection the text attributes are applied to 348: * the paragraph at the current caret position. 349: * 350: * @param attribute the text attributes to set 351: * @param replace if <code>true</code>, the attributes of the current 352: * selection are overridden, otherwise they are merged 353: */ 354: public void setParagraphAttributes(AttributeSet attribute, 355: boolean replace) 356: { 357: // TODO 358: } 359: 360: /** 361: * Returns the attributes that are applied to newly inserted text. 362: * This is a {@link MutableAttributeSet}, so you can easily modify these 363: * attributes. 364: * 365: * @return the attributes that are applied to newly inserted text 366: */ 367: public MutableAttributeSet getInputAttributes() 368: { 369: return getStyledEditorKit().getInputAttributes(); 370: } 371: 372: /** 373: * Returns the {@link StyledEditorKit} that is currently used by this 374: * <code>JTextPane</code>. 375: * 376: * @return the current <code>StyledEditorKit</code> of this 377: * <code>JTextPane</code> 378: */ 379: protected final StyledEditorKit getStyledEditorKit() 380: { 381: return (StyledEditorKit) getEditorKit(); 382: } 383: 384: /** 385: * Creates the default {@link EditorKit} that is used in 386: * <code>JTextPane</code>s. This is an instance of {@link StyledEditorKit}. 387: * 388: * @return the default {@link EditorKit} that is used in 389: * <code>JTextPane</code>s 390: */ 391: protected EditorKit createDefaultEditorKit() 392: { 393: return new StyledEditorKit(); 394: } 395: 396: /** 397: * Sets the {@link EditorKit} to use for this <code>JTextPane</code>. 398: * <code>JTextPane</code>s can only handle {@link StyledEditorKit}s, 399: * if client programs try to set a different type of <code>EditorKit</code> 400: * then an IllegalArgumentException is thrown 401: * 402: * @param editor the <code>EditorKit</code> to set 403: * 404: * @throws IllegalArgumentException if <code>editor</code> is no 405: * <code>StyledEditorKit</code> 406: */ 407: public final void setEditorKit(EditorKit editor) 408: { 409: if (!(editor instanceof StyledEditorKit)) 410: throw new IllegalArgumentException 411: ("JTextPanes can only handle StyledEditorKits"); 412: super.setEditorKit(editor); 413: } 414: 415: /** 416: * Returns a param string that can be used for debugging. 417: * 418: * @return a param string that can be used for debugging. 419: */ 420: protected String paramString() 421: { 422: return super.paramString(); // TODO 423: } 424: }