Source for javax.swing.JTextPane

   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: import java.io.IOException;
  43: import java.io.ObjectOutputStream;
  44: 
  45: import javax.swing.text.AttributeSet;
  46: import javax.swing.text.BadLocationException;
  47: import javax.swing.text.Caret;
  48: import javax.swing.text.Document;
  49: import javax.swing.text.EditorKit;
  50: import javax.swing.text.Element;
  51: import javax.swing.text.MutableAttributeSet;
  52: import javax.swing.text.SimpleAttributeSet;
  53: import javax.swing.text.Style;
  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 {@link #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: 
 156:     int dot = caret.getDot();
 157:     int mark = caret.getMark();
 158: 
 159:     // If content is empty delete selection.
 160:     if (content == null)
 161:       {
 162:     caret.setDot(dot);
 163:     return;
 164:       }
 165: 
 166:     try
 167:       {
 168:     int start = getSelectionStart();
 169:     int end = getSelectionEnd();
 170:     int contentLength = content.length();
 171: 
 172:     // Remove selected text.
 173:     if (dot != mark)
 174:       doc.remove(start, end - start);
 175: 
 176:     // Insert new text.
 177:     doc.insertString(start, content, null);
 178:     // Set attributes for inserted text
 179:     doc.setCharacterAttributes(start, contentLength, getInputAttributes(),
 180:                    true);
 181: 
 182:     // Set dot to new position.
 183:     setCaretPosition(start + contentLength);
 184:       }
 185:     catch (BadLocationException e)
 186:       {
 187:     throw new AssertionError
 188:       ("No BadLocationException should be thrown here");
 189:       }
 190:   }
 191: 
 192:   /**
 193:    * Inserts an AWT or Swing component into the text at the current caret
 194:    * position.
 195:    *
 196:    * @param component the component to be inserted
 197:    */
 198:   public void insertComponent(Component component)
 199:   {
 200:     // TODO: One space must be inserted here with attributes set to indicate
 201:     // that the component must be displayed here. Have to figure out the
 202:     // attributes.
 203:   }
 204: 
 205:   /**
 206:    * Inserts an <code>Icon</code> into the text at the current caret position.
 207:    *
 208:    * @param icon the <code>Icon</code> to be inserted
 209:    */
 210:   public void insertIcon(Icon icon)
 211:   {
 212:     // TODO: One space must be inserted here with attributes set to indicate
 213:     // that the icon must be displayed here. Have to figure out the
 214:     // attributes.
 215:   }
 216: 
 217:   /**
 218:    * Adds a style into the style hierarchy. Unspecified style attributes
 219:    * can be resolved in the <code>parent</code> style, if one is specified.
 220:    *
 221:    * While it is legal to add nameless styles (<code>nm == null</code),
 222:    * you must be aware that the client application is then responsible
 223:    * for managing the style hierarchy, since unnamed styles cannot be
 224:    * looked up by their name.
 225:    *
 226:    * @param nm the name of the style or <code>null</code> if the style should
 227:    *           be unnamed
 228:    * @param parent the parent in which unspecified style attributes are
 229:    *           resolved, or <code>null</code> if that is not necessary
 230:    *
 231:    * @return the newly created <code>Style</code>
 232:    */
 233:   public Style addStyle(String nm, Style parent)
 234:   {
 235:     return getStyledDocument().addStyle(nm, parent);
 236:   }
 237: 
 238:   /**
 239:    * Removes a named <code>Style</code> from the style hierarchy.
 240:    *
 241:    * @param nm the name of the <code>Style</code> to be removed
 242:    */
 243:   public void removeStyle(String nm)
 244:   {
 245:     getStyledDocument().removeStyle(nm);
 246:   }
 247: 
 248:   /**
 249:    * Looks up and returns a named <code>Style</code>.
 250:    *
 251:    * @param nm the name of the <code>Style</code>
 252:    *
 253:    * @return the found <code>Style</code> of <code>null</code> if no such
 254:    *         <code>Style</code> exists
 255:    */
 256:   public Style getStyle(String nm)
 257:   {
 258:     return getStyledDocument().getStyle(nm);
 259:   }
 260: 
 261:   /**
 262:    * Returns the logical style of the paragraph at the current caret position.
 263:    *
 264:    * @return the logical style of the paragraph at the current caret position
 265:    */
 266:   public Style getLogicalStyle()
 267:   {
 268:     return getStyledDocument().getLogicalStyle(getCaretPosition());
 269:   }
 270: 
 271:   /**
 272:    * Sets the logical style for the paragraph at the current caret position.
 273:    *
 274:    * @param style the style to set for the current paragraph
 275:    */
 276:   public void setLogicalStyle(Style style)
 277:   {
 278:     getStyledDocument().setLogicalStyle(getCaretPosition(), style);
 279:   }
 280: 
 281:   /**
 282:    * Returns the text attributes for the character at the current caret
 283:    * position.
 284:    *
 285:    * @return the text attributes for the character at the current caret
 286:    *         position
 287:    */
 288:   public AttributeSet getCharacterAttributes()
 289:   {
 290:     StyledDocument doc = getStyledDocument();
 291:     Element el = doc.getCharacterElement(getCaretPosition());
 292:     return el.getAttributes();
 293:   }
 294: 
 295:   /**
 296:    * Sets text attributes for the current selection. If there is no selection
 297:    * the text attributes are applied to newly inserted text
 298:    *
 299:    * @param attribute the text attributes to set
 300:    * @param replace if <code>true</code>, the attributes of the current
 301:    *     selection are overridden, otherwise they are merged
 302:    *
 303:    * @see {@link #getInputAttributes}
 304:    */
 305:   public void setCharacterAttributes(AttributeSet attribute,
 306:                                      boolean replace)
 307:   {
 308:     int dot = getCaret().getDot();
 309:     int start = getSelectionStart();
 310:     int end = getSelectionEnd();
 311:     if (start == dot && end == dot)
 312:       // There is no selection, update insertAttributes instead
 313:       {
 314:     MutableAttributeSet inputAttributes =
 315:       getStyledEditorKit().getInputAttributes();
 316:     inputAttributes.addAttributes(attribute);
 317:       }
 318:     else
 319:       getStyledDocument().setCharacterAttributes(start, end - start, attribute,
 320:                          replace);
 321:   }
 322: 
 323:   /**
 324:    * Returns the text attributes of the paragraph at the current caret
 325:    * position.
 326:    *
 327:    * @return the attributes of the paragraph at the current caret position
 328:    */
 329:   public AttributeSet getParagraphAttributes()
 330:   {
 331:     StyledDocument doc = getStyledDocument();
 332:     Element el = doc.getParagraphElement(getCaretPosition());
 333:     return el.getAttributes();
 334:   }
 335: 
 336:   /**
 337:    * Sets text attributes for the paragraph at the current selection.
 338:    * If there is no selection the text attributes are applied to
 339:    * the paragraph at the current caret position.
 340:    *
 341:    * @param attribute the text attributes to set
 342:    * @param replace if <code>true</code>, the attributes of the current
 343:    *     selection are overridden, otherwise they are merged
 344:    */
 345:   public void setParagraphAttributes(AttributeSet attribute,
 346:                                      boolean replace)
 347:   {
 348:     // TODO
 349:   }
 350: 
 351:   /**
 352:    * Returns the attributes that are applied to newly inserted text.
 353:    * This is a {@link MutableAttributeSet}, so you can easily modify these
 354:    * attributes.
 355:    *
 356:    * @return the attributes that are applied to newly inserted text
 357:    */
 358:   public MutableAttributeSet getInputAttributes()
 359:   {
 360:     return getStyledEditorKit().getInputAttributes();
 361:   }
 362: 
 363:   /**
 364:    * Returns the {@link StyledEditorKit} that is currently used by this
 365:    * <code>JTextPane</code>.
 366:    *
 367:    * @return the current <code>StyledEditorKit</code> of this
 368:    *         <code>JTextPane</code>
 369:    */
 370:   protected final StyledEditorKit getStyledEditorKit()
 371:   {
 372:     return (StyledEditorKit) getEditorKit();
 373:   }
 374: 
 375:   /**
 376:    * Creates the default {@link EditorKit} that is used in
 377:    * <code>JTextPane</code>s. This is an instance of {@link StyledEditorKit}.
 378:    *
 379:    * @return the default {@link EditorKit} that is used in
 380:    *         <code>JTextPane</code>s
 381:    */
 382:   protected EditorKit createDefaultEditorKit()
 383:   {
 384:     return new StyledEditorKit();
 385:   }
 386: 
 387:   /**
 388:    * Sets the {@link EditorKit} to use for this <code>JTextPane</code>.
 389:    * <code>JTextPane</code>s can only handle {@link StyledEditorKit}s,
 390:    * if client programs try to set a different type of <code>EditorKit</code>
 391:    * then an IllegalArgumentException is thrown
 392:    *
 393:    * @param editor the <code>EditorKit</code> to set
 394:    *
 395:    * @throws IllegalArgumentException if <code>editor</code> is no
 396:    *         <code>StyledEditorKit</code>
 397:    */
 398:   public final void setEditorKit(EditorKit editor)
 399:   {
 400:     if (!(editor instanceof StyledEditorKit))
 401:       throw new IllegalArgumentException
 402:         ("JTextPanes can only handle StyledEditorKits");
 403:     super.setEditorKit(editor);
 404:   }
 405: 
 406:   /**
 407:    * Returns a param string that can be used for debugging.
 408:    *
 409:    * @return a param string that can be used for debugging.
 410:    */
 411:   protected String paramString()
 412:   {
 413:     return super.paramString(); // TODO
 414:   }
 415: }