Source for javax.swing.text.JTextComponent

   1: /* JTextComponent.java --
   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.text;
  40: 
  41: import java.awt.AWTEvent;
  42: import java.awt.Color;
  43: import java.awt.Dimension;
  44: import java.awt.Insets;
  45: import java.awt.Point;
  46: import java.awt.Rectangle;
  47: import java.awt.datatransfer.Clipboard;
  48: import java.awt.datatransfer.DataFlavor;
  49: import java.awt.datatransfer.StringSelection;
  50: import java.awt.datatransfer.Transferable;
  51: import java.awt.datatransfer.UnsupportedFlavorException;
  52: import java.awt.event.ActionEvent;
  53: import java.awt.event.ActionListener;
  54: import java.awt.event.InputMethodListener;
  55: import java.awt.event.KeyEvent;
  56: import java.io.IOException;
  57: import java.io.Reader;
  58: import java.io.Writer;
  59: import java.util.Enumeration;
  60: import java.util.Hashtable;
  61: 
  62: import javax.accessibility.Accessible;
  63: import javax.accessibility.AccessibleContext;
  64: import javax.accessibility.AccessibleRole;
  65: import javax.accessibility.AccessibleStateSet;
  66: import javax.accessibility.AccessibleText;
  67: import javax.swing.Action;
  68: import javax.swing.ActionMap;
  69: import javax.swing.InputMap;
  70: import javax.swing.JComponent;
  71: import javax.swing.JViewport;
  72: import javax.swing.KeyStroke;
  73: import javax.swing.Scrollable;
  74: import javax.swing.SwingConstants;
  75: import javax.swing.Timer;
  76: import javax.swing.TransferHandler;
  77: import javax.swing.UIManager;
  78: import javax.swing.event.CaretEvent;
  79: import javax.swing.event.CaretListener;
  80: import javax.swing.event.DocumentEvent;
  81: import javax.swing.event.DocumentListener;
  82: import javax.swing.plaf.ActionMapUIResource;
  83: import javax.swing.plaf.InputMapUIResource;
  84: import javax.swing.plaf.TextUI;
  85: 
  86: public abstract class JTextComponent extends JComponent
  87:   implements Scrollable, Accessible
  88: {
  89:   /**
  90:    * AccessibleJTextComponent
  91:    */
  92:   public class AccessibleJTextComponent extends AccessibleJComponent
  93:     implements AccessibleText, CaretListener, DocumentListener
  94:   {
  95:     private static final long serialVersionUID = 7664188944091413696L;
  96: 
  97:     /**
  98:      * Constructor AccessibleJTextComponent
  99:      */
 100:     public AccessibleJTextComponent()
 101:     {
 102:     }
 103: 
 104:     /**
 105:      * getCaretPosition
 106:      * @return int
 107:      */
 108:     public int getCaretPosition()
 109:     {
 110:       return 0; // TODO
 111:     }
 112: 
 113:     /**
 114:      * getSelectedText
 115:      * @return String
 116:      */
 117:     public String getSelectedText()
 118:     {
 119:       return null; // TODO
 120:     }
 121: 
 122:     /**
 123:      * getSelectionStart
 124:      * @return int
 125:      */
 126:     public int getSelectionStart()
 127:     {
 128:       return 0; // TODO
 129:     }
 130: 
 131:     /**
 132:      * getSelectionEnd
 133:      * @return int
 134:      */
 135:     public int getSelectionEnd()
 136:     {
 137:       return 0; // TODO
 138:     }
 139: 
 140:     /**
 141:      * caretUpdate
 142:      * @param value0 TODO
 143:      */
 144:     public void caretUpdate(CaretEvent value0)
 145:     {
 146:       // TODO
 147:     }
 148: 
 149:     /**
 150:      * getAccessibleStateSet
 151:      * @return AccessibleStateSet
 152:      */
 153:     public AccessibleStateSet getAccessibleStateSet()
 154:     {
 155:       return null; // TODO
 156:     }
 157: 
 158:     /**
 159:      * getAccessibleRole
 160:      * @return AccessibleRole
 161:      */
 162:     public AccessibleRole getAccessibleRole()
 163:     {
 164:       return null; // TODO
 165:     }
 166: 
 167:     /**
 168:      * getAccessibleText
 169:      * @return AccessibleText
 170:      */
 171:     public AccessibleText getAccessibleText()
 172:     {
 173:       return null; // TODO
 174:     }
 175: 
 176:     /**
 177:      * insertUpdate
 178:      * @param value0 TODO
 179:      */
 180:     public void insertUpdate(DocumentEvent value0)
 181:     {
 182:       // TODO
 183:     }
 184: 
 185:     /**
 186:      * removeUpdate
 187:      * @param value0 TODO
 188:      */
 189:     public void removeUpdate(DocumentEvent value0)
 190:     {
 191:       // TODO
 192:     }
 193: 
 194:     /**
 195:      * changedUpdate
 196:      * @param value0 TODO
 197:      */
 198:     public void changedUpdate(DocumentEvent value0)
 199:     {
 200:       // TODO
 201:     }
 202: 
 203:     /**
 204:      * getIndexAtPoint
 205:      * @param value0 TODO
 206:      * @return int
 207:      */
 208:     public int getIndexAtPoint(Point value0)
 209:     {
 210:       return 0; // TODO
 211:     }
 212: 
 213:     /**
 214:      * getRootEditorRect
 215:      * @return Rectangle
 216:      */
 217:     Rectangle getRootEditorRect()
 218:     {
 219:       return null;
 220:     }
 221: 
 222:     /**
 223:      * getCharacterBounds
 224:      * @param value0 TODO
 225:      * @return Rectangle
 226:      */
 227:     public Rectangle getCharacterBounds(int value0)
 228:     {
 229:       return null; // TODO
 230:     }
 231: 
 232:     /**
 233:      * getCharCount
 234:      * @return int
 235:      */
 236:     public int getCharCount()
 237:     {
 238:       return 0; // TODO
 239:     }
 240: 
 241:     /**
 242:      * getCharacterAttribute
 243:      * @param value0 TODO
 244:      * @return AttributeSet
 245:      */
 246:     public AttributeSet getCharacterAttribute(int value0)
 247:     {
 248:       return null; // TODO
 249:     }
 250: 
 251:     /**
 252:      * getAtIndex
 253:      * @param value0 TODO
 254:      * @param value1 TODO
 255:      * @return String
 256:      */
 257:     public String getAtIndex(int value0, int value1)
 258:     {
 259:       return null; // TODO
 260:     }
 261: 
 262:     /**
 263:      * getAfterIndex
 264:      * @param value0 TODO
 265:      * @param value1 TODO
 266:      * @return String
 267:      */
 268:     public String getAfterIndex(int value0, int value1)
 269:     {
 270:       return null; // TODO
 271:     }
 272: 
 273:     /**
 274:      * getBeforeIndex
 275:      * @param value0 TODO
 276:      * @param value1 TODO
 277:      * @return String
 278:      */
 279:     public String getBeforeIndex(int value0, int value1)
 280:     {
 281:       return null; // TODO
 282:     }
 283:   }
 284: 
 285:   public static class KeyBinding
 286:   {
 287:     public KeyStroke key;
 288:     public String actionName;
 289: 
 290:     /**
 291:      * Creates a new <code>KeyBinding</code> instance.
 292:      *
 293:      * @param key a <code>KeyStroke</code> value
 294:      * @param actionName a <code>String</code> value
 295:      */
 296:     public KeyBinding(KeyStroke key, String actionName)
 297:     {
 298:       this.key = key;
 299:       this.actionName = actionName;
 300:     }
 301:   }
 302: 
 303:   /**
 304:    * The timer that lets the caret blink.
 305:    */
 306:   private class CaretBlinkTimer
 307:     extends Timer
 308:     implements ActionListener
 309:   {
 310:     /**
 311:      * Creates a new CaretBlinkTimer object with a default delay of 1 second.
 312:      */
 313:     public CaretBlinkTimer()
 314:     {
 315:       super(1000, null);
 316:       addActionListener(this);
 317:     }
 318: 
 319:     /**
 320:      * Lets the caret blink.
 321:      */
 322:     public void actionPerformed(ActionEvent ev)
 323:     {
 324:       Caret c = caret;
 325:       if (c != null)
 326:     c.setVisible(!c.isVisible());
 327:     }
 328: 
 329:     /**
 330:      * Updates the blink delay according to the current caret.
 331:      */
 332:     public void update()
 333:     {
 334:       stop();
 335:       Caret c = caret;
 336:       if (c != null)
 337:     {
 338:       setDelay(c.getBlinkRate());
 339:       if (editable)
 340:         start();
 341:       else
 342:         c.setVisible(false);
 343:     }
 344:     }
 345:   }
 346: 
 347:   /**
 348:    * According to <a
 349:    * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">this
 350:    * report</a>, a pair of private classes wraps a {@link
 351:    * javax.swing.text.Keymap} in the new {@link InputMap} / {@link
 352:    * ActionMap} interfaces, such that old Keymap-using code can make use of
 353:    * the new framework.
 354:    *
 355:    * <p>A little bit of experimentation with these classes reveals the following
 356:    * structure:
 357:    *
 358:    * <ul>
 359:    *
 360:    * <li>KeymapWrapper extends {@link InputMap} and holds a reference to
 361:    * the underlying {@link Keymap}.</li>
 362:    *
 363:    * <li>KeymapWrapper maps {@link KeyStroke} objects to {@link Action}
 364:    * objects, by delegation to the underlying {@link Keymap}.</li>
 365:    *
 366:    * <li>KeymapActionMap extends {@link ActionMap} also holds a reference to
 367:    * the underlying {@link Keymap} but only appears to use it for listing 
 368:    * its keys. </li>
 369:    *
 370:    * <li>KeymapActionMap maps all {@link Action} objects to
 371:    * <em>themselves</em>, whether they exist in the underlying {@link
 372:    * Keymap} or not, and passes other objects to the parent {@link
 373:    * ActionMap} for resolving.
 374:    *
 375:    * </ul>
 376:    */
 377: 
 378:   private class KeymapWrapper extends InputMap
 379:   {
 380:     Keymap map;
 381: 
 382:     public KeymapWrapper(Keymap k)
 383:     {
 384:       map = k;
 385:     }
 386: 
 387:     public int size()
 388:     {
 389:       return map.getBoundKeyStrokes().length + super.size();
 390:     }
 391: 
 392:     public Object get(KeyStroke ks)
 393:     {
 394:       Action mapped = null;
 395:       Keymap m = map;
 396:       while(mapped == null && m != null)
 397:         {
 398:           mapped = m.getAction(ks);
 399:           if (mapped == null && ks.getKeyEventType() == KeyEvent.KEY_TYPED)
 400:             mapped = m.getDefaultAction();
 401:           if (mapped == null)
 402:             m = m.getResolveParent();
 403:         }
 404: 
 405:       if (mapped == null)
 406:         return super.get(ks);
 407:       else
 408:         return mapped;
 409:     }
 410: 
 411:     public KeyStroke[] keys()
 412:     {
 413:       KeyStroke[] superKeys = super.keys();
 414:       KeyStroke[] mapKeys = map.getBoundKeyStrokes(); 
 415:       KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length];
 416:       for (int i = 0; i < superKeys.length; ++i)
 417:         bothKeys[i] = superKeys[i];
 418:       for (int i = 0; i < mapKeys.length; ++i)
 419:         bothKeys[i + superKeys.length] = mapKeys[i];
 420:       return bothKeys;
 421:     }
 422: 
 423:     public KeyStroke[] allKeys()
 424:     {
 425:       KeyStroke[] superKeys = super.allKeys();
 426:       KeyStroke[] mapKeys = map.getBoundKeyStrokes(); 
 427:       KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length];
 428:       for (int i = 0; i < superKeys.length; ++i)
 429:         bothKeys[i] = superKeys[i];
 430:       for (int i = 0; i < mapKeys.length; ++i)
 431:         bothKeys[i + superKeys.length] = mapKeys[i];
 432:       return bothKeys;
 433:     }
 434:   }
 435: 
 436:   private class KeymapActionMap extends ActionMap
 437:   {
 438:     Keymap map;
 439: 
 440:     public KeymapActionMap(Keymap k)
 441:     {
 442:       map = k;
 443:     }
 444: 
 445:     public Action get(Object cmd)
 446:     {
 447:       if (cmd instanceof Action)
 448:         return (Action) cmd;
 449:       else
 450:         return super.get(cmd);
 451:     }
 452: 
 453:     public int size()
 454:     {
 455:       return map.getBoundKeyStrokes().length + super.size();
 456:     }
 457: 
 458:     public Object[] keys() 
 459:     {
 460:       Object[] superKeys = super.keys();
 461:       Object[] mapKeys = map.getBoundKeyStrokes(); 
 462:       Object[] bothKeys = new Object[superKeys.length + mapKeys.length];
 463:       for (int i = 0; i < superKeys.length; ++i)
 464:         bothKeys[i] = superKeys[i];
 465:       for (int i = 0; i < mapKeys.length; ++i)
 466:         bothKeys[i + superKeys.length] = mapKeys[i];
 467:       return bothKeys;      
 468:     }
 469: 
 470:     public Object[] allKeys()
 471:     {
 472:       Object[] superKeys = super.allKeys();
 473:       Object[] mapKeys = map.getBoundKeyStrokes(); 
 474:       Object[] bothKeys = new Object[superKeys.length + mapKeys.length];
 475:       for (int i = 0; i < superKeys.length; ++i)
 476:         bothKeys[i] = superKeys[i];
 477:       for (int i = 0; i < mapKeys.length; ++i)
 478:         bothKeys[i + superKeys.length] = mapKeys[i];
 479:       return bothKeys;
 480:     }
 481: 
 482:   }
 483: 
 484:   static class DefaultKeymap implements Keymap
 485:   {
 486:     String name;
 487:     Keymap parent;
 488:     Hashtable map;
 489:     Action defaultAction;
 490: 
 491:     public DefaultKeymap(String name)
 492:     {
 493:       this.name = name;
 494:       this.map = new Hashtable();
 495:     }
 496: 
 497:     public void addActionForKeyStroke(KeyStroke key, Action a)
 498:     {
 499:       map.put(key, a);
 500:     }
 501: 
 502:     /**
 503:      * Looks up a KeyStroke either in the current map or the parent Keymap;
 504:      * does <em>not</em> return the default action if lookup fails.
 505:      *
 506:      * @param key The KeyStroke to look up an Action for.
 507:      *
 508:      * @return The mapping for <code>key</code>, or <code>null</code>
 509:      * if no mapping exists in this Keymap or any of its parents.
 510:      */
 511:     public Action getAction(KeyStroke key)
 512:     {
 513:       if (map.containsKey(key))
 514:         return (Action) map.get(key);
 515:       else if (parent != null)
 516:         return parent.getAction(key);
 517:       else
 518:         return null;
 519:     }
 520: 
 521:     public Action[] getBoundActions()
 522:     {
 523:       Action [] ret = new Action[map.size()];
 524:       Enumeration e = map.elements();
 525:       int i = 0;
 526:       while (e.hasMoreElements())
 527:         {
 528:           ret[i++] = (Action) e.nextElement();
 529:         }
 530:       return ret;
 531:     }
 532: 
 533:     public KeyStroke[] getBoundKeyStrokes()
 534:     {
 535:       KeyStroke [] ret = new KeyStroke[map.size()];
 536:       Enumeration e = map.keys();
 537:       int i = 0;
 538:       while (e.hasMoreElements())
 539:         {
 540:           ret[i++] = (KeyStroke) e.nextElement();
 541:         }
 542:       return ret;
 543:     }
 544: 
 545:     public Action getDefaultAction()
 546:     {
 547:       return defaultAction;
 548:     }
 549: 
 550:     public KeyStroke[] getKeyStrokesForAction(Action a)
 551:     {
 552:       int i = 0;
 553:       Enumeration e = map.keys();
 554:       while (e.hasMoreElements())
 555:         {
 556:           if (map.get(e.nextElement()).equals(a))
 557:             ++i;
 558:         }
 559:       KeyStroke [] ret = new KeyStroke[i];
 560:       i = 0;
 561:       e = map.keys();
 562:       while (e.hasMoreElements())
 563:         {          
 564:           KeyStroke k = (KeyStroke) e.nextElement();
 565:           if (map.get(k).equals(a))
 566:             ret[i++] = k;            
 567:         }
 568:       return ret;
 569:     }
 570: 
 571:     public String getName()
 572:     {
 573:       return name;
 574:     }
 575: 
 576:     public Keymap getResolveParent()
 577:     {
 578:       return parent;
 579:     }
 580: 
 581:     public boolean isLocallyDefined(KeyStroke key)
 582:     {
 583:       return map.containsKey(key);
 584:     }
 585: 
 586:     public void removeBindings()
 587:     {
 588:       map.clear();
 589:     }
 590: 
 591:     public void removeKeyStrokeBinding(KeyStroke key)
 592:     {
 593:       map.remove(key);
 594:     }
 595: 
 596:     public void setDefaultAction(Action a)
 597:     {
 598:       defaultAction = a;
 599:     }
 600: 
 601:     public void setResolveParent(Keymap p)
 602:     {
 603:       parent = p;
 604:     }
 605:   }
 606: 
 607:   class DefaultTransferHandler
 608:     extends TransferHandler
 609:   {
 610:     public boolean canImport(JComponent component, DataFlavor[] flavors)
 611:     {
 612:       JTextComponent textComponent = (JTextComponent) component;
 613:       
 614:       if (! (textComponent.isEnabled()
 615:          && textComponent.isEditable()
 616:          && flavors != null))
 617:         return false;
 618: 
 619:       for (int i = 0; i < flavors.length; ++i)
 620:     if (flavors[i].equals(DataFlavor.stringFlavor))
 621:        return true;
 622: 
 623:       return false;
 624:     }
 625:     
 626:     public void exportToClipboard(JComponent component, Clipboard clipboard,
 627:                   int action)
 628:     {
 629:       JTextComponent textComponent = (JTextComponent) component;
 630:       int start = textComponent.getSelectionStart();
 631:       int end = textComponent.getSelectionEnd();
 632: 
 633:       if (start == end)
 634:     return;
 635: 
 636:       try
 637:     {
 638:       // Copy text to clipboard.
 639:       String data = textComponent.getDocument().getText(start, end);
 640:       StringSelection selection = new StringSelection(data);
 641:       clipboard.setContents(selection, null);
 642: 
 643:       // Delete selected text on cut action.
 644:       if (action == MOVE)
 645:         doc.remove(start, end - start);
 646:     }
 647:       catch (BadLocationException e)
 648:     {
 649:       // Ignore this and do nothing.
 650:     }
 651:     }
 652:     
 653:     public int getSourceActions()
 654:     {
 655:       return NONE;
 656:     }
 657: 
 658:     public boolean importData(JComponent component, Transferable transferable)
 659:     {
 660:       DataFlavor flavor = null;
 661:       DataFlavor[] flavors = transferable.getTransferDataFlavors();
 662: 
 663:       if (flavors == null)
 664:     return false;
 665: 
 666:       for (int i = 0; i < flavors.length; ++i)
 667:     if (flavors[i].equals(DataFlavor.stringFlavor))
 668:        flavor = flavors[i];
 669:       
 670:       if (flavor == null)
 671:     return false;
 672: 
 673:       try
 674:     {
 675:       JTextComponent textComponent = (JTextComponent) component;
 676:       String data = (String) transferable.getTransferData(flavor);
 677:       textComponent.replaceSelection(data);
 678:       return true;
 679:     }
 680:       catch (IOException e)
 681:     {
 682:       // Ignored.
 683:     }
 684:       catch (UnsupportedFlavorException e)
 685:     {
 686:       // Ignored.
 687:     }
 688: 
 689:       return false;
 690:     }
 691:   }
 692: 
 693:   private static final long serialVersionUID = -8796518220218978795L;
 694:   
 695:   public static final String DEFAULT_KEYMAP = "default";
 696:   public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey";
 697:   
 698:   private static DefaultTransferHandler defaultTransferHandler;
 699:   private static Hashtable keymaps = new Hashtable();
 700:   private Keymap keymap;
 701:   private char focusAccelerator = '\0';
 702:   private NavigationFilter navigationFilter;
 703: 
 704:   private CaretBlinkTimer caretBlinkTimer;
 705: 
 706:   /**
 707:    * Get a Keymap from the global keymap table, by name.
 708:    *
 709:    * @param n The name of the Keymap to look up
 710:    *
 711:    * @return A Keymap associated with the provided name, or
 712:    * <code>null</code> if no such Keymap exists
 713:    *
 714:    * @see #addKeymap
 715:    * @see #removeKeymap
 716:    * @see #keymaps
 717:    */
 718:   public static Keymap getKeymap(String n)
 719:   {
 720:     return (Keymap) keymaps.get(n);
 721:   }
 722: 
 723:   /**
 724:    * Remove a Keymap from the global Keymap table, by name.
 725:    *
 726:    * @param n The name of the Keymap to remove
 727:    *
 728:    * @return The keymap removed from the global table
 729:    *
 730:    * @see #addKeymap
 731:    * @see #getKeymap()
 732:    * @see #keymaps
 733:    */  
 734:   public static Keymap removeKeymap(String n)
 735:   {
 736:     Keymap km = (Keymap) keymaps.get(n);
 737:     keymaps.remove(n);
 738:     return km;
 739:   }
 740: 
 741:   /**
 742:    * Create a new Keymap with a specific name and parent, and add the new
 743:    * Keymap to the global keymap table. The name may be <code>null</code>,
 744:    * in which case the new Keymap will <em>not</em> be added to the global
 745:    * Keymap table. The parent may also be <code>null</code>, which is
 746:    * harmless.
 747:    * 
 748:    * @param n The name of the new Keymap, or <code>null</code>
 749:    * @param parent The parent of the new Keymap, or <code>null</code>
 750:    *
 751:    * @return The newly created Keymap
 752:    *
 753:    * @see #removeKeymap
 754:    * @see #getKeymap()
 755:    * @see #keymaps
 756:    */
 757:   public static Keymap addKeymap(String n, Keymap parent)
 758:   {
 759:     Keymap k = new DefaultKeymap(n);
 760:     k.setResolveParent(parent);
 761:     if (n != null)
 762:       keymaps.put(n, k);
 763:     return k;
 764:   }
 765: 
 766:   /**
 767:    * Get the current Keymap of this component.
 768:    *
 769:    * @return The component's current Keymap
 770:    *
 771:    * @see #setKeymap
 772:    * @see #keymap
 773:    */
 774:   public Keymap getKeymap() 
 775:   {
 776:     return keymap;
 777:   }
 778: 
 779:   /**
 780:    * Set the current Keymap of this component, installing appropriate
 781:    * {@link KeymapWrapper} and {@link KeymapActionMap} objects in the
 782:    * {@link InputMap} and {@link ActionMap} parent chains, respectively,
 783:    * and fire a property change event with name <code>"keymap"</code>.
 784:    *
 785:    * @see #getKeymap()
 786:    * @see #keymap
 787:    */
 788:   public void setKeymap(Keymap k) 
 789:   {
 790: 
 791:     // phase 1: replace the KeymapWrapper entry in the InputMap chain.
 792:     // the goal here is to always maintain the following ordering:
 793:     //
 794:     //   [InputMap]? -> [KeymapWrapper]? -> [InputMapUIResource]*
 795:     // 
 796:     // that is to say, component-specific InputMaps need to remain children
 797:     // of Keymaps, and Keymaps need to remain children of UI-installed
 798:     // InputMaps (and the order of each group needs to be preserved, of
 799:     // course).
 800:     
 801:     KeymapWrapper kw = (k == null ? null : new KeymapWrapper(k));
 802:     InputMap childInputMap = getInputMap(JComponent.WHEN_FOCUSED);
 803:     if (childInputMap == null)
 804:       setInputMap(JComponent.WHEN_FOCUSED, kw);
 805:     else
 806:       {
 807:         while (childInputMap.getParent() != null 
 808:                && !(childInputMap.getParent() instanceof KeymapWrapper)
 809:                && !(childInputMap.getParent() instanceof InputMapUIResource))
 810:           childInputMap = childInputMap.getParent();
 811: 
 812:         // option 1: there is nobody to replace at the end of the chain
 813:         if (childInputMap.getParent() == null)
 814:           childInputMap.setParent(kw);
 815:         
 816:         // option 2: there is already a KeymapWrapper in the chain which
 817:         // needs replacing (possibly with its own parents, possibly without)
 818:         else if (childInputMap.getParent() instanceof KeymapWrapper)
 819:           {
 820:             if (kw == null)
 821:               childInputMap.setParent(childInputMap.getParent().getParent());
 822:             else
 823:               {
 824:                 kw.setParent(childInputMap.getParent().getParent());
 825:                 childInputMap.setParent(kw);
 826:               }
 827:           }
 828: 
 829:         // option 3: there is an InputMapUIResource in the chain, which marks
 830:         // the place where we need to stop and insert ourselves
 831:         else if (childInputMap.getParent() instanceof InputMapUIResource)
 832:           {
 833:             if (kw != null)
 834:               {
 835:                 kw.setParent(childInputMap.getParent());
 836:                 childInputMap.setParent(kw);
 837:               }
 838:           }
 839:       }
 840: 
 841:     // phase 2: replace the KeymapActionMap entry in the ActionMap chain
 842: 
 843:     KeymapActionMap kam = (k == null ? null : new KeymapActionMap(k));
 844:     ActionMap childActionMap = getActionMap();
 845:     if (childActionMap == null)
 846:       setActionMap(kam);
 847:     else
 848:       {
 849:         while (childActionMap.getParent() != null 
 850:                && !(childActionMap.getParent() instanceof KeymapActionMap)
 851:                && !(childActionMap.getParent() instanceof ActionMapUIResource))
 852:           childActionMap = childActionMap.getParent();
 853: 
 854:         // option 1: there is nobody to replace at the end of the chain
 855:         if (childActionMap.getParent() == null)
 856:           childActionMap.setParent(kam);
 857:         
 858:         // option 2: there is already a KeymapActionMap in the chain which
 859:         // needs replacing (possibly with its own parents, possibly without)
 860:         else if (childActionMap.getParent() instanceof KeymapActionMap)
 861:           {
 862:             if (kam == null)
 863:               childActionMap.setParent(childActionMap.getParent().getParent());
 864:             else
 865:               {
 866:                 kam.setParent(childActionMap.getParent().getParent());
 867:                 childActionMap.setParent(kam);
 868:               }
 869:           }
 870: 
 871:         // option 3: there is an ActionMapUIResource in the chain, which marks
 872:         // the place where we need to stop and insert ourselves
 873:         else if (childActionMap.getParent() instanceof ActionMapUIResource)
 874:           {
 875:             if (kam != null)
 876:               {
 877:                 kam.setParent(childActionMap.getParent());
 878:                 childActionMap.setParent(kam);
 879:               }
 880:           }
 881:       }
 882: 
 883:     // phase 3: update the explicit keymap field
 884: 
 885:     Keymap old = keymap;
 886:     keymap = k;
 887:     firePropertyChange("keymap", old, k);
 888:   }
 889: 
 890:   /**
 891:    * Resolves a set of bindings against a set of actions and inserts the
 892:    * results into a {@link Keymap}. Specifically, for each provided binding
 893:    * <code>b</code>, if there exists a provided action <code>a</code> such
 894:    * that <code>a.getValue(Action.NAME) == b.ActionName</code> then an
 895:    * entry is added to the Keymap mapping <code>b</code> to
 896:    * <code>a</code>.
 897:    *
 898:    * @param map The Keymap to add new mappings to
 899:    * @param bindings The set of bindings to add to the Keymap
 900:    * @param actions The set of actions to resolve binding names against
 901:    *
 902:    * @see Action#NAME
 903:    * @see Action#getValue
 904:    * @see KeyBinding#actionName
 905:    */
 906:   public static void loadKeymap(Keymap map, 
 907:                                 JTextComponent.KeyBinding[] bindings, 
 908:                                 Action[] actions)
 909:   {
 910:     Hashtable acts = new Hashtable(actions.length);
 911:     for (int i = 0; i < actions.length; ++i)
 912:       acts.put(actions[i].getValue(Action.NAME), actions[i]);
 913:     for (int i = 0; i < bindings.length; ++i)
 914:       if (acts.containsKey(bindings[i].actionName))
 915:         map.addActionForKeyStroke(bindings[i].key, (Action) acts.get(bindings[i].actionName));
 916:   }
 917: 
 918:   /**
 919:    * Returns the set of available Actions this component's associated
 920:    * editor can run.  Equivalent to calling
 921:    * <code>getUI().getEditorKit().getActions()</code>. This set of Actions
 922:    * is a reasonable value to provide as a parameter to {@link
 923:    * #loadKeymap}, when resolving a set of {@link KeyBinding} objects
 924:    * against this component.
 925:    *
 926:    * @return The set of available Actions on this component's {@link EditorKit}
 927:    *
 928:    * @see TextUI#getEditorKit
 929:    * @see EditorKit#getActions()
 930:    */
 931:   public Action[] getActions()
 932:   {
 933:     return getUI().getEditorKit(this).getActions();
 934:   }
 935:     
 936:   // These are package-private to avoid an accessor method.
 937:   Document doc;
 938:   Caret caret;
 939:   boolean editable;
 940:   
 941:   private Highlighter highlighter;
 942:   private Color caretColor;
 943:   private Color disabledTextColor;
 944:   private Color selectedTextColor;
 945:   private Color selectionColor;
 946:   private Insets margin;
 947:   private boolean dragEnabled;
 948: 
 949:   /**
 950:    * Creates a new <code>JTextComponent</code> instance.
 951:    */
 952:   public JTextComponent()
 953:   {
 954:     Keymap defkeymap = getKeymap(DEFAULT_KEYMAP);
 955:     boolean creatingKeymap = false;
 956:     if (defkeymap == null)
 957:       {
 958:         defkeymap = addKeymap(DEFAULT_KEYMAP, null);
 959:         defkeymap.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction());
 960:         creatingKeymap = true;
 961:       }
 962: 
 963:     caretBlinkTimer = new CaretBlinkTimer();
 964: 
 965:     setFocusable(true);
 966:     setEditable(true);
 967:     enableEvents(AWTEvent.KEY_EVENT_MASK);
 968:     updateUI();
 969:     
 970:     // need to do this after updateUI()
 971:     if (creatingKeymap)
 972:       loadKeymap(defkeymap, 
 973:                  new KeyBinding[] { 
 974:                    new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
 975:                                   DefaultEditorKit.backwardAction),
 976:                    new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
 977:                                   DefaultEditorKit.forwardAction),
 978:                    new KeyBinding(KeyStroke.getKeyStroke("typed \b"),
 979:                                   DefaultEditorKit.deletePrevCharAction),
 980:                    new KeyBinding(KeyStroke.getKeyStroke("typed \u007f"),
 981:                                   DefaultEditorKit.deleteNextCharAction)                   
 982:                  },
 983:                  getActions());
 984:   }
 985: 
 986:   public void setDocument(Document newDoc)
 987:   {
 988:     Document oldDoc = doc;
 989:     doc = newDoc;
 990:     firePropertyChange("document", oldDoc, newDoc);
 991:     revalidate();
 992:     repaint();
 993:   }
 994: 
 995:   public Document getDocument()
 996:   {
 997:     return doc;
 998:   }
 999: 
1000:   /**
1001:    * Get the <code>AccessibleContext</code> of this object.
1002:    *
1003:    * @return an <code>AccessibleContext</code> object
1004:    */
1005:   public AccessibleContext getAccessibleContext()
1006:   {
1007:     return null;
1008:   }
1009: 
1010:   public void setMargin(Insets m)
1011:   {
1012:     margin = m;
1013:   }
1014: 
1015:   public Insets getMargin()
1016:   {
1017:     return margin;
1018:   }
1019: 
1020:   public void setText(String text)
1021:   {
1022:     try
1023:       {
1024:     doc.remove(0, doc.getLength());
1025:     doc.insertString(0, text, null);
1026:       }
1027:     catch (BadLocationException e)
1028:       {
1029:     // This can never happen.
1030:       }
1031:   }
1032: 
1033:   /**
1034:    * Retrieves the current text in this text document.
1035:    *
1036:    * @return the text
1037:    *
1038:    * @exception NullPointerException if the underlaying document is null
1039:    */
1040:   public String getText()
1041:   {
1042:     if (doc == null)
1043:       return null;
1044: 
1045:     try
1046:       {
1047:     return doc.getText(0, doc.getLength());
1048:       }
1049:     catch (BadLocationException e)
1050:       {
1051:     // This should never happen.
1052:     return "";
1053:       }
1054:   }
1055: 
1056:   /**
1057:    * Retrieves a part of the current text in this document.
1058:    *
1059:    * @param offset the postion of the first character
1060:    * @param length the length of the text to retrieve
1061:    *
1062:    * @return the text
1063:    *
1064:    * @exception BadLocationException if arguments do not hold pre-conditions
1065:    */
1066:   public String getText(int offset, int length)
1067:     throws BadLocationException
1068:   {
1069:     return getDocument().getText(offset, length);
1070:   }
1071: 
1072:   /**
1073:    * Retrieves the currently selected text in this text document.
1074:    *
1075:    * @return the selected text
1076:    *
1077:    * @exception NullPointerException if the underlaying document is null
1078:    */
1079:   public String getSelectedText()
1080:   {
1081:     try
1082:       {
1083:     return doc.getText(getSelectionStart(), getSelectionEnd());
1084:       }
1085:     catch (BadLocationException e)
1086:       {
1087:     // This should never happen.
1088:     return null;
1089:       }
1090:   }
1091: 
1092:   /**
1093:    * Returns a string that specifies the name of the Look and Feel class
1094:    * that renders this component.
1095:    *
1096:    * @return the string "TextComponentUI"
1097:    */
1098:   public String getUIClassID()
1099:   {
1100:     return "TextComponentUI";
1101:   }
1102: 
1103:   /**
1104:    * Returns a string representation of this JTextComponent.
1105:    */
1106:   protected String paramString()
1107:   {
1108:     return "JTextComponent";
1109:   }
1110: 
1111:   /**
1112:    * This method returns the label's UI delegate.
1113:    *
1114:    * @return The label's UI delegate.
1115:    */
1116:   public TextUI getUI()
1117:   {
1118:     return (TextUI) ui;
1119:   }
1120: 
1121:   /**
1122:    * This method sets the label's UI delegate.
1123:    *
1124:    * @param newUI The label's UI delegate.
1125:    */
1126:   public void setUI(TextUI newUI)
1127:   {
1128:     super.setUI(newUI);
1129:   }
1130: 
1131:   /**
1132:    * This method resets the label's UI delegate to the default UI for the
1133:    * current look and feel.
1134:    */
1135:   public void updateUI()
1136:   {
1137:     setUI((TextUI) UIManager.getUI(this));
1138:   }
1139: 
1140:   public Dimension getPreferredScrollableViewportSize()
1141:   {
1142:     return getPreferredSize();
1143:   }
1144: 
1145:   public int getScrollableUnitIncrement(Rectangle visible, int orientation,
1146:                                         int direction)
1147:   {
1148:     // We return 1/10 of the visible area as documented in Sun's API docs.
1149:     if (orientation == SwingConstants.HORIZONTAL)
1150:       return visible.width / 10;
1151:     else if (orientation == SwingConstants.VERTICAL)
1152:       return visible.height / 10;
1153:     else
1154:       throw new IllegalArgumentException("orientation must be either "
1155:                                       + "javax.swing.SwingConstants.VERTICAL "
1156:                                       + "or "
1157:                                       + "javax.swing.SwingConstants.HORIZONTAL"
1158:                                          );
1159:   }
1160: 
1161:   public int getScrollableBlockIncrement(Rectangle visible, int orientation,
1162:                                          int direction)
1163:   {
1164:     // We return the whole visible area as documented in Sun's API docs.
1165:     if (orientation == SwingConstants.HORIZONTAL)
1166:       return visible.width;
1167:     else if (orientation == SwingConstants.VERTICAL)
1168:       return visible.height;
1169:     else
1170:       throw new IllegalArgumentException("orientation must be either "
1171:                                       + "javax.swing.SwingConstants.VERTICAL "
1172:                                       + "or "
1173:                                       + "javax.swing.SwingConstants.HORIZONTAL"
1174:                                          );
1175:   }
1176: 
1177:   /**
1178:    * Checks whether this text component it editable.
1179:    *
1180:    * @return true if editable, false otherwise
1181:    */
1182:   public boolean isEditable()
1183:   {
1184:     return editable;
1185:   }
1186: 
1187:   /**
1188:    * Enables/disabled this text component's editability.
1189:    *
1190:    * @param newValue true to make it editable, false otherwise.
1191:    */
1192:   public void setEditable(boolean newValue)
1193:   {
1194:     if (editable == newValue)
1195:       return;
1196: 
1197:     if (newValue == true)
1198:       caretBlinkTimer.start();
1199:     else
1200:       {
1201:         caretBlinkTimer.stop();
1202:         caret.setVisible(false);
1203:       }
1204: 
1205:     boolean oldValue = editable;
1206:     editable = newValue;
1207:     firePropertyChange("editable", oldValue, newValue);
1208:   }
1209: 
1210:   /**
1211:    * The <code>Caret</code> object used in this text component.
1212:    *
1213:    * @return the caret object
1214:    */
1215:   public Caret getCaret()
1216:   {
1217:     return caret;
1218:   }
1219: 
1220:   /**
1221:    * Sets a new <code>Caret</code> for this text component.
1222:    *
1223:    * @param newCaret the new <code>Caret</code> to set
1224:    */
1225:   public void setCaret(Caret newCaret)
1226:   {
1227:     if (caret != null)
1228:       caret.deinstall(this);
1229:     
1230:     Caret oldCaret = caret;
1231:     caret = newCaret;
1232: 
1233:     caretBlinkTimer.update();
1234: 
1235:     if (caret != null)
1236:       caret.install(this);
1237:     
1238:     firePropertyChange("caret", oldCaret, newCaret);
1239:   }
1240: 
1241:   public Color getCaretColor()
1242:   {
1243:     return caretColor;
1244:   }
1245: 
1246:   public void setCaretColor(Color newColor)
1247:   {
1248:     Color oldCaretColor = caretColor;
1249:     caretColor = newColor;
1250:     firePropertyChange("caretColor", oldCaretColor, newColor);
1251:   }
1252: 
1253:   public Color getDisabledTextColor()
1254:   {
1255:     return disabledTextColor;
1256:   }
1257: 
1258:   public void setDisabledTextColor(Color newColor)
1259:   {
1260:     Color oldColor = disabledTextColor;
1261:     disabledTextColor = newColor;
1262:     firePropertyChange("disabledTextColor", oldColor, newColor);
1263:   }
1264: 
1265:   public Color getSelectedTextColor()
1266:   {
1267:     return selectedTextColor;
1268:   }
1269: 
1270:   public void setSelectedTextColor(Color newColor)
1271:   {
1272:     Color oldColor = selectedTextColor;
1273:     selectedTextColor = newColor;
1274:     firePropertyChange("selectedTextColor", oldColor, newColor);
1275:   }
1276: 
1277:   public Color getSelectionColor()
1278:   {
1279:     return selectionColor;
1280:   }
1281: 
1282:   public void setSelectionColor(Color newColor)
1283:   {
1284:     Color oldColor = selectionColor;
1285:     selectionColor = newColor;
1286:     firePropertyChange("selectionColor", oldColor, newColor);
1287:   }
1288: 
1289:   /**
1290:    * Retrisves the current caret position.
1291:    *
1292:    * @return the current position
1293:    */
1294:   public int getCaretPosition()
1295:   {
1296:     return caret.getDot();
1297:   }
1298: 
1299:   /**
1300:    * Sets the caret to a new position.
1301:    *
1302:    * @param position the new position
1303:    */
1304:   public void setCaretPosition(int position)
1305:   {
1306:     if (doc == null)
1307:       return;
1308: 
1309:     if (position < 0 || position > doc.getLength())
1310:       throw new IllegalArgumentException();
1311: 
1312:     caret.setDot(position);
1313:   }
1314: 
1315:   /**
1316:    * Moves the caret to a given position. This selects the text between
1317:    * the old and the new position of the caret.
1318:    */
1319:   public void moveCaretPosition(int position)
1320:   {
1321:     if (doc == null)
1322:       return;
1323: 
1324:     if (position < 0 || position > doc.getLength())
1325:       throw new IllegalArgumentException();
1326: 
1327:     caret.moveDot(position);
1328:   }
1329: 
1330:   public Highlighter getHighlighter()
1331:   {
1332:     return highlighter;
1333:   }
1334: 
1335:   public void setHighlighter(Highlighter newHighlighter)
1336:   {
1337:     if (highlighter != null)
1338:       highlighter.deinstall(this);
1339:     
1340:     Highlighter oldHighlighter = highlighter;
1341:     highlighter = newHighlighter;
1342: 
1343:     if (highlighter != null)
1344:       highlighter.install(this);
1345:     
1346:     firePropertyChange("highlighter", oldHighlighter, newHighlighter);
1347:   }
1348: 
1349:   /**
1350:    * Returns the start postion of the currently selected text.
1351:    *
1352:    * @return the start postion
1353:    */
1354:   public int getSelectionStart()
1355:   {
1356:     return Math.min(caret.getDot(), caret.getMark());
1357:   }
1358: 
1359:   /**
1360:    * Selects the text from the given postion to the selection end position.
1361:    *
1362:    * @param start the start positon of the selected text.
1363:    */
1364:   public void setSelectionStart(int start)
1365:   {
1366:     select(start, getSelectionEnd());
1367:   }
1368: 
1369:   /**
1370:    * Returns the end postion of the currently selected text.
1371:    *
1372:    * @return the end postion
1373:    */
1374:   public int getSelectionEnd()
1375:   {
1376:     return Math.max(caret.getDot(), caret.getMark());
1377:   }
1378: 
1379:   /**
1380:    * Selects the text from the selection start postion to the given position.
1381:    *
1382:    * @param end the end positon of the selected text.
1383:    */
1384:   public void setSelectionEnd(int end)
1385:   {
1386:     select(getSelectionStart(), end);
1387:   }
1388: 
1389:   /**
1390:    * Selects a part of the content of the text component.
1391:    *
1392:    * @param start the start position of the selected text
1393:    * @param end the end position of the selected text
1394:    */
1395:   public void select(int start, int end)
1396:   {
1397:     int length = doc.getLength();
1398:     
1399:     start = Math.max(start, 0);
1400:     start = Math.min(start, length);
1401: 
1402:     end = Math.max(end, 0);
1403:     end = Math.min(end, length);
1404: 
1405:     setCaretPosition(start);
1406:     moveCaretPosition(end);
1407:   }
1408: 
1409:   /**
1410:    * Selects the whole content of the text component.
1411:    */
1412:   public void selectAll()
1413:   {
1414:     select(0, doc.getLength());
1415:   }
1416: 
1417:   public synchronized void replaceSelection(String content)
1418:   {
1419:     int dot = caret.getDot();
1420:     int mark = caret.getMark();
1421: 
1422:     // If content is empty delete selection.
1423:     if (content == null)
1424:       {
1425:     caret.setDot(dot);
1426:     return;
1427:       }
1428: 
1429:     try
1430:       {
1431:     int start = getSelectionStart();
1432:     int end = getSelectionEnd();
1433:     
1434:     // Remove selected text.
1435:     if (dot != mark)
1436:       doc.remove(start, end - start);
1437: 
1438:     // Insert new text.
1439:     doc.insertString(start, content, null);
1440: 
1441:     // Set dot to new position.
1442:     setCaretPosition(start + content.length());
1443:       }
1444:     catch (BadLocationException e)
1445:       {
1446:     // This should never happen.
1447:       }
1448:   }
1449: 
1450:   public boolean getScrollableTracksViewportHeight()
1451:   {
1452:     if (getParent() instanceof JViewport)
1453:       return ((JViewport) getParent()).getHeight() > getPreferredSize().height;
1454: 
1455:     return false;
1456:   }
1457: 
1458:   public boolean getScrollableTracksViewportWidth()
1459:   {
1460:     if (getParent() instanceof JViewport)
1461:       return ((JViewport) getParent()).getWidth() > getPreferredSize().width;
1462: 
1463:     return false;
1464:   }
1465: 
1466:   /**
1467:    * Adds a <code>CaretListener</code> object to this text component.
1468:    *
1469:    * @param listener the listener to add
1470:    */
1471:   public void addCaretListener(CaretListener listener)
1472:   {
1473:     listenerList.add(CaretListener.class, listener);
1474:   }
1475: 
1476:   /**
1477:    * Removed a <code>CaretListener</code> object from this text component.
1478:    *
1479:    * @param listener the listener to remove
1480:    */
1481:   public void removeCaretListener(CaretListener listener)
1482:   {
1483:     listenerList.remove(CaretListener.class, listener);
1484:   }
1485: 
1486:   /**
1487:    * Returns all added <code>CaretListener</code> objects.
1488:    *
1489:    * @return an array of listeners
1490:    */
1491:   public CaretListener[] getCaretListeners()
1492:   {
1493:     return (CaretListener[]) getListeners(CaretListener.class);
1494:   }
1495: 
1496:   /**
1497:    * Notifies all registered <code>CaretListener</code> objects that the caret
1498:    * was updated.
1499:    *
1500:    * @param event the event to send
1501:    */
1502:   protected void fireCaretUpdate(CaretEvent event)
1503:   {
1504:     CaretListener[] listeners = getCaretListeners();
1505: 
1506:     for (int index = 0; index < listeners.length; ++index)
1507:       listeners[index].caretUpdate(event);
1508:   }
1509: 
1510:   /**
1511:    * Adds an <code>InputListener</code> object to this text component.
1512:    *
1513:    * @param listener the listener to add
1514:    */
1515:   public void addInputMethodListener(InputMethodListener listener)
1516:   {
1517:     listenerList.add(InputMethodListener.class, listener);
1518:   }
1519: 
1520:   /**
1521:    * Removes an <code>InputListener</code> object from this text component.
1522:    *
1523:    * @param listener the listener to remove
1524:    */
1525:   public void removeInputMethodListener(InputMethodListener listener)
1526:   {
1527:     listenerList.remove(InputMethodListener.class, listener);
1528:   }
1529: 
1530:   /**
1531:    * Returns all added <code>InputMethodListener</code> objects.
1532:    *
1533:    * @return an array of listeners
1534:    */
1535:   public InputMethodListener[] getInputMethodListeners()
1536:   {
1537:     return (InputMethodListener[]) getListeners(InputMethodListener.class);
1538:   }
1539: 
1540:   public Rectangle modelToView(int position) throws BadLocationException
1541:   {
1542:     return getUI().modelToView(this, position);
1543:   }
1544: 
1545:   public boolean getDragEnabled()
1546:   {
1547:     return dragEnabled;
1548:   }
1549: 
1550:   public void setDragEnabled(boolean enabled)
1551:   {
1552:     dragEnabled = enabled;
1553:   }
1554: 
1555:   public int viewToModel(Point pt)
1556:   {
1557:     return getUI().viewToModel(this, pt);
1558:   }
1559: 
1560:   public void copy()
1561:   {
1562:     doTransferAction("copy", TransferHandler.getCopyAction());
1563:   }
1564: 
1565:   public void cut()
1566:   {
1567:     doTransferAction("cut", TransferHandler.getCutAction());
1568:   }
1569: 
1570:   public void paste()
1571:   {
1572:     doTransferAction("paste", TransferHandler.getPasteAction());
1573:   }
1574: 
1575:   private void doTransferAction(String name, Action action)
1576:   {
1577:     // Install default TransferHandler if none set.
1578:     if (getTransferHandler() == null)
1579:       {
1580:     if (defaultTransferHandler == null)
1581:       defaultTransferHandler = new DefaultTransferHandler();
1582:     
1583:     setTransferHandler(defaultTransferHandler);
1584:       }
1585: 
1586:     // Perform action.
1587:     ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
1588:                     action.getValue(Action.NAME).toString());
1589:     action.actionPerformed(event);
1590:   }
1591: 
1592:   public void setFocusAccelerator(char newKey)
1593:   {
1594:     if (focusAccelerator == newKey)
1595:       return;
1596: 
1597:     char oldKey = focusAccelerator;
1598:     focusAccelerator = newKey;
1599:     firePropertyChange(FOCUS_ACCELERATOR_KEY, oldKey, newKey);
1600:   }
1601:   
1602:   public char getFocusAccelerator()
1603:   {
1604:     return focusAccelerator;
1605:   }
1606: 
1607:   /**
1608:    * @since 1.4
1609:    */
1610:   public NavigationFilter getNavigationFilter()
1611:   {
1612:     return navigationFilter;
1613:   }
1614: 
1615:   /**
1616:    * @since 1.4
1617:    */
1618:   public void setNavigationFilter(NavigationFilter filter)
1619:   {
1620:     navigationFilter = filter;
1621:   }
1622:   
1623:   /**
1624:    * Read and set the content this component. If not overridden, the
1625:    * method reads the component content as a plain text.
1626:    *
1627:    * The second parameter of this method describes the input stream. It can
1628:    * be String, URL, File and so on. If not null, this object is added to
1629:    * the properties of the associated document under the key
1630:    * {@link Document#StreamDescriptionProperty}.
1631:    *
1632:    * @param input an input stream to read from.
1633:    * @param streamDescription an object, describing the stream.
1634:    *
1635:    * @throws IOException if the reader throws it.
1636:    *
1637:    * @see #getDocument()
1638:    * @see Document#getProperty(Object)
1639:    */
1640:   public void read(Reader input, Object streamDescription)
1641:             throws IOException
1642:   {
1643:     if (streamDescription != null)
1644:       {
1645:         Document d = getDocument();
1646:         if (d != null)
1647:           d.putProperty(Document.StreamDescriptionProperty, streamDescription);
1648:       }
1649: 
1650:     StringBuffer b = new StringBuffer();
1651:     int c;
1652: 
1653:     // Read till -1 (EOF).
1654:     while ((c = input.read()) >= 0)
1655:       b.append((char) c);
1656: 
1657:     setText(b.toString());
1658:   }
1659: 
1660:   /**
1661:    * Write the content of this component to the given stream. If not
1662:    * overridden, the method writes the component content as a plain text.
1663:    *
1664:    * @param output the writer to write into.
1665:    *
1666:    * @throws IOException if the writer throws it.
1667:    */
1668:   public void write(Writer output)
1669:              throws IOException
1670:   {
1671:     output.write(getText());
1672:   }  
1673: }