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