Source for javax.swing.text.DefaultEditorKit

   1: /* DefaultEditorKit.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.Point;
  42: import java.awt.Toolkit;
  43: import java.awt.event.ActionEvent;
  44: 
  45: import java.io.BufferedReader;
  46: import java.io.IOException;
  47: import java.io.InputStream;
  48: import java.io.InputStreamReader;
  49: import java.io.OutputStream;
  50: import java.io.OutputStreamWriter;
  51: import java.io.Reader;
  52: import java.io.Writer;
  53: 
  54: import javax.swing.Action;
  55: 
  56: /**
  57:  * The default implementation of {@link EditorKit}. This <code>EditorKit</code>
  58:  * a plain text <code>Document</code> and several commands that together
  59:  * make up a basic editor, like cut / copy + paste.
  60:  *
  61:  * @author original author unknown
  62:  * @author Roman Kennke (roman@kennke.org)
  63:  */
  64: public class DefaultEditorKit extends EditorKit
  65: {
  66:   static class SelectionPreviousWordAction
  67:       extends TextAction
  68:   {
  69:     SelectionPreviousWordAction()
  70:     {
  71:       super(selectionPreviousWordAction);
  72:     }
  73: 
  74:     public void actionPerformed(ActionEvent event)
  75:     {
  76:       try
  77:         {
  78:           JTextComponent t = getTextComponent(event);
  79:       
  80:           if (t != null)
  81:             {
  82:               int offs = Utilities.getPreviousWord(t, t.getCaretPosition());
  83:       
  84:               Caret c = t.getCaret();
  85:               c.moveDot(offs);
  86:               c.setMagicCaretPosition(t.modelToView(offs).getLocation());
  87:             }
  88:         }
  89:       catch(BadLocationException ble)
  90:         {
  91:           // Can't happen.
  92:         }
  93:     }
  94:   }
  95: 
  96:   static class SelectionNextWordAction
  97:       extends TextAction
  98:   {
  99:     SelectionNextWordAction()
 100:     {
 101:       super(selectionNextWordAction);
 102:     }
 103: 
 104:     public void actionPerformed(ActionEvent event)
 105:     {
 106:       try
 107:         {
 108:           JTextComponent t = getTextComponent(event);
 109:       
 110:           if (t != null)
 111:             {
 112:               int offs = Utilities.getNextWord(t, t.getCaretPosition());
 113:       
 114:               Caret c = t.getCaret();
 115:               c.moveDot(offs);
 116:               c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 117:             }
 118:         }
 119:       catch(BadLocationException ble)
 120:         {
 121:           // Can't happen.
 122:         }
 123:     }
 124:   }
 125: 
 126:   static class PreviousWordAction
 127:       extends TextAction
 128:   {
 129:     PreviousWordAction()
 130:     {
 131:       super(previousWordAction);
 132:     }
 133: 
 134:     public void actionPerformed(ActionEvent event)
 135:     {
 136:       try
 137:         {
 138:           JTextComponent t = getTextComponent(event);
 139:       
 140:           if (t != null)
 141:             {
 142:               int offs = Utilities.getPreviousWord(t, t.getCaretPosition());
 143:       
 144:               Caret c = t.getCaret();
 145:               c.setDot(offs);
 146:               c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 147:             }
 148:         }
 149:       catch(BadLocationException ble)
 150:         {
 151:           // Can't happen.
 152:         }
 153:     }
 154:   }
 155: 
 156:   static class NextWordAction
 157:       extends TextAction
 158:   {
 159:     NextWordAction()
 160:     {
 161:       super(nextWordAction);
 162:     }
 163: 
 164:     public void actionPerformed(ActionEvent event)
 165:     {
 166:       try
 167:         {
 168:           JTextComponent t = getTextComponent(event);
 169:       
 170:           if (t != null)
 171:             {
 172:               int offs = Utilities.getNextWord(t, t.getCaretPosition());
 173:       
 174:               Caret c = t.getCaret();
 175:               c.setDot(offs);
 176:               c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 177:             }
 178:         }
 179:       catch(BadLocationException ble)
 180:         {
 181:           // Can't happen.
 182:         }
 183:     }
 184:   }
 185: 
 186:   static class SelectAllAction
 187:       extends TextAction
 188:   {
 189:     SelectAllAction()
 190:     {
 191:       super(selectAllAction);
 192:     }
 193: 
 194:     public void actionPerformed(ActionEvent event)
 195:     {
 196:       JTextComponent t = getTextComponent(event);
 197:       int offs = t.getDocument().getLength();
 198:       Caret c = t.getCaret();
 199:       c.setDot(0);
 200:       c.moveDot(offs);
 201:       
 202:       try
 203:       {   
 204:         c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 205:       }
 206:     catch(BadLocationException ble)
 207:       {
 208:         // Can't happen.
 209:       }
 210:     }
 211:   }
 212: 
 213:   static class SelectionBeginAction
 214:       extends TextAction
 215:   {
 216:     SelectionBeginAction()
 217:     {
 218:       super(selectionBeginAction);
 219:     }
 220: 
 221:     public void actionPerformed(ActionEvent event)
 222:     {
 223:       JTextComponent t = getTextComponent(event);
 224:       Caret c = t.getCaret();
 225:       c.moveDot(0);
 226:       try
 227:         {   
 228:           c.setMagicCaretPosition(t.modelToView(0).getLocation());
 229:         }
 230:       catch(BadLocationException ble)
 231:         {
 232:           // Can't happen.
 233:         }
 234:     }
 235:   }
 236: 
 237:   static class SelectionEndAction
 238:       extends TextAction
 239:   {
 240:     SelectionEndAction()
 241:     {
 242:       super(selectionEndAction);
 243:     }
 244: 
 245:     public void actionPerformed(ActionEvent event)
 246:     {
 247:       JTextComponent t = getTextComponent(event);
 248:       int offs = t.getDocument().getLength();
 249:       Caret c = t.getCaret();
 250:       c.moveDot(offs);
 251:       try
 252:         {   
 253:           c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 254:         }
 255:       catch(BadLocationException ble)
 256:         {
 257:           // Can't happen.
 258:         }
 259:     }
 260:   }
 261: 
 262:   static class SelectionEndLineAction
 263:       extends TextAction
 264:   {
 265:     SelectionEndLineAction()
 266:     {
 267:       super(selectionEndLineAction);
 268:     }
 269: 
 270:     public void actionPerformed(ActionEvent event)
 271:     {
 272:       JTextComponent t = getTextComponent(event);
 273:      try
 274:      {
 275:        Point p = t.modelToView(t.getCaret().getDot()).getLocation();
 276:        int cur = t.getCaretPosition();
 277:        int y = p.y;
 278:        int length = t.getDocument().getLength();
 279:        while (y == p.y && cur < length)
 280:          y = t.modelToView(++cur).getLocation().y;
 281:        if (cur != length)
 282:          cur--;
 283:     
 284:        Caret c = t.getCaret();
 285:        c.moveDot(cur);
 286:        c.setMagicCaretPosition(t.modelToView(cur).getLocation());
 287:      }
 288:      catch (BadLocationException ble)
 289:      {
 290:        // Nothing to do here
 291:      }
 292:     }
 293:   }
 294: 
 295:   static class SelectionBeginLineAction
 296:       extends TextAction
 297:   {
 298:     SelectionBeginLineAction()
 299:     {
 300:       super(selectionBeginLineAction);
 301:     }
 302: 
 303:     public void actionPerformed(ActionEvent event)
 304:     {
 305:       JTextComponent t = getTextComponent(event);
 306:       
 307:       try
 308:       {
 309:         // TODO: There is a more efficent solution, but
 310:         // viewToModel doesn't work properly.
 311:         Point p = t.modelToView(t.getCaret().getDot()).getLocation();
 312:         
 313:         int cur = t.getCaretPosition();
 314:         int y = p.y;
 315:         
 316:         while (y == p.y && cur > 0)
 317:           y = t.modelToView(--cur).getLocation().y;
 318:         if (cur != 0)
 319:           cur++;
 320:         
 321:         Caret c = t.getCaret();
 322:         c.moveDot(cur);
 323:         c.setMagicCaretPosition(t.modelToView(cur).getLocation());
 324:       }
 325:       catch (BadLocationException ble)
 326:       {
 327:         // Do nothing here.
 328:       }
 329:     }
 330:   }
 331: 
 332:   static class SelectionDownAction
 333:       extends TextAction
 334:   {
 335:     SelectionDownAction()
 336:     {
 337:       super(selectionDownAction);
 338:     }
 339: 
 340:     public void actionPerformed(ActionEvent event)
 341:     {
 342:       JTextComponent t = getTextComponent(event);
 343:       try
 344:         {
 345:           if (t != null)
 346:             {
 347:               Caret c = t.getCaret();
 348:               // The magic caret position may be null when the caret
 349:               // has not moved yet.
 350:               Point mcp = c.getMagicCaretPosition();
 351:               int x = (mcp != null) ? mcp.x : 0;
 352:               int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x);
 353:               
 354:               if (pos > -1)
 355:                 t.moveCaretPosition(pos);
 356:             }
 357:         }
 358:       catch(BadLocationException ble) 
 359:         {
 360:           // FIXME: Swallowing allowed?
 361:         }
 362:     }
 363:   }
 364: 
 365:   static class SelectionUpAction
 366:       extends TextAction
 367:   {
 368:     SelectionUpAction()
 369:     {
 370:       super(selectionUpAction);
 371:     }
 372: 
 373:     public void actionPerformed(ActionEvent event)
 374:     {
 375:       JTextComponent t = getTextComponent(event);
 376:       try
 377:         {
 378:           if (t != null)
 379:             {
 380:               Caret c = t.getCaret();
 381:               // The magic caret position may be null when the caret
 382:               // has not moved yet.
 383:               Point mcp = c.getMagicCaretPosition();
 384:               int x = (mcp != null) ? mcp.x : 0;
 385:               int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x);
 386:               
 387:               if (pos > -1)
 388:                 t.moveCaretPosition(pos);
 389:             }
 390:         }
 391:       catch(BadLocationException ble) 
 392:         {
 393:           // FIXME: Swallowing allowed?
 394:         }
 395:     }
 396:   }
 397: 
 398:   static class SelectionForwardAction
 399:       extends TextAction
 400:   {
 401:     SelectionForwardAction()
 402:     {
 403:       super(selectionForwardAction);
 404:     }
 405: 
 406:     public void actionPerformed(ActionEvent event)
 407:     {
 408:       JTextComponent t = getTextComponent(event);
 409:       if (t != null)
 410:         {
 411:           int offs = t.getCaretPosition() + 1;
 412:           
 413:           if(offs <= t.getDocument().getLength())
 414:             {
 415:               Caret c = t.getCaret();
 416:               c.moveDot(offs);
 417:               try
 418:                 {
 419:                   c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 420:                 }
 421:               catch(BadLocationException ble)
 422:               {
 423:                 // Can't happen.
 424:               }
 425:             }
 426:         }
 427:     }
 428:   }
 429: 
 430:   static class SelectionBackwardAction
 431:       extends TextAction
 432:   {
 433:     SelectionBackwardAction()
 434:     {
 435:       super(selectionBackwardAction);
 436:     }
 437: 
 438:     public void actionPerformed(ActionEvent event)
 439:     {
 440:       JTextComponent t = getTextComponent(event);
 441:       if (t != null)
 442:         {
 443:       int offs = t.getCaretPosition() - 1;
 444:       
 445:       if(offs >= 0)
 446:         {
 447:           Caret c = t.getCaret();
 448:           c.moveDot(offs);
 449:           try
 450:             {
 451:               c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 452:             }
 453:           catch(BadLocationException ble)
 454:           {
 455:             // Can't happen.
 456:           }
 457:         }
 458:         }
 459:     }
 460:   }
 461: 
 462:   static class DownAction
 463:       extends TextAction
 464:   {
 465:     DownAction()
 466:     {
 467:       super(downAction);
 468:     }
 469: 
 470:     public void actionPerformed(ActionEvent event)
 471:     {
 472:       JTextComponent t = getTextComponent(event);
 473:       try
 474:         {
 475:           if (t != null)
 476:             {
 477:               Caret c = t.getCaret();
 478:               // The magic caret position may be null when the caret
 479:               // has not moved yet.
 480:               Point mcp = c.getMagicCaretPosition();
 481:               int x = (mcp != null) ? mcp.x : 0;
 482:               int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x);
 483:               
 484:               if (pos > -1)
 485:                 t.setCaretPosition(pos);
 486:             }
 487:         }
 488:       catch(BadLocationException ble) 
 489:         {
 490:           // FIXME: Swallowing allowed?
 491:         }
 492:     }
 493:   }
 494: 
 495:   static class UpAction
 496:       extends TextAction
 497:   {
 498:     UpAction()
 499:     {
 500:       super(upAction);
 501:     }
 502: 
 503:     public void actionPerformed(ActionEvent event)
 504:     {
 505:       JTextComponent t = getTextComponent(event);
 506:       try
 507:         {
 508:           if (t != null)
 509:             {
 510:               Caret c = t.getCaret();
 511:               // The magic caret position may be null when the caret
 512:               // has not moved yet.
 513:               Point mcp = c.getMagicCaretPosition();
 514:               int x = (mcp != null) ? mcp.x : 0;
 515:               int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x);
 516:               
 517:               if (pos > -1)
 518:                 t.setCaretPosition(pos);
 519:             }
 520:         }
 521:       catch(BadLocationException ble) 
 522:         {
 523:           // FIXME: Swallowing allowed?
 524:         }
 525:     }
 526:   }
 527: 
 528:   static class ForwardAction
 529:       extends TextAction
 530:   {
 531:     ForwardAction()
 532:     {
 533:       super(forwardAction);
 534:     }
 535: 
 536:     public void actionPerformed(ActionEvent event)
 537:     {
 538:       JTextComponent t = getTextComponent(event);
 539:       if (t != null)
 540:         {
 541:           int offs = t.getCaretPosition() + 1;
 542:           if (offs <= t.getDocument().getLength())
 543:             {
 544:               Caret c = t.getCaret();
 545:               c.setDot(offs);
 546:               
 547:               try
 548:                 {
 549:                   c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 550:                 }
 551:               catch (BadLocationException ble)
 552:                 {
 553:                   // Should not happen.
 554:                 }
 555:             }
 556:         }
 557:       
 558:     }
 559:   }
 560: 
 561:   static class BackwardAction
 562:       extends TextAction
 563:   {
 564:     BackwardAction()
 565:     {
 566:       super(backwardAction);
 567:     }
 568: 
 569:     public void actionPerformed(ActionEvent event)
 570:     {
 571:       JTextComponent t = getTextComponent(event);
 572:       if (t != null)
 573:         {
 574:           int offs = t.getCaretPosition() - 1;
 575:           if (offs >= 0)
 576:             {
 577:               Caret c = t.getCaret();
 578:               c.setDot(offs);
 579:               
 580:               try
 581:                 {
 582:                   c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 583:                 }
 584:               catch (BadLocationException ble)
 585:                 {
 586:                   // Should not happen.
 587:                 }
 588:             }
 589:         }
 590:     }
 591:   }
 592: 
 593:   static class DeletePrevCharAction
 594:       extends TextAction
 595:   {
 596:     DeletePrevCharAction()
 597:     {
 598:       super(deletePrevCharAction);
 599:     }
 600: 
 601:     public void actionPerformed(ActionEvent event)
 602:     {
 603:       JTextComponent t = getTextComponent(event);
 604:       if (t != null)
 605:         {
 606:           try
 607:             {
 608:               int pos = t.getSelectionStart();
 609:               int len = t.getSelectionEnd() - pos;
 610:               
 611:               if (len > 0)
 612:                   t.getDocument().remove(pos, len);
 613:               else if (pos > 0)
 614:                 {
 615:                   pos--;
 616:                   t.getDocument().remove(pos, 1);
 617:                   Caret c = t.getCaret();
 618:                   c.setDot(pos);
 619:                   c.setMagicCaretPosition(t.modelToView(pos).getLocation());
 620:                 }
 621:             }
 622:           catch (BadLocationException e)
 623:             {
 624:               // FIXME: we're not authorized to throw this.. swallow it?
 625:             }
 626:         }
 627:     }
 628:   }
 629: 
 630:   static class DeleteNextCharAction
 631:       extends TextAction
 632:   {
 633:     DeleteNextCharAction()
 634:     {
 635:       super(deleteNextCharAction);
 636:     }
 637: 
 638:     public void actionPerformed(ActionEvent event)
 639:     {
 640:       JTextComponent t = getTextComponent(event);
 641:       if (t != null)
 642:         {
 643:           try
 644:             {
 645:               int pos = t.getSelectionStart();
 646:               int len = t.getSelectionEnd() - pos;
 647:               
 648:               if (len > 0)
 649:                   t.getDocument().remove(pos, len);
 650:               else if (pos < t.getDocument().getLength())
 651:                   t.getDocument().remove(pos, 1);
 652:     
 653:               Caret c = t.getCaret();
 654:               c.setDot(pos);
 655:               c.setMagicCaretPosition(t.modelToView(pos).getLocation());
 656:             }
 657:           catch (BadLocationException e)
 658:             {
 659:               // FIXME: we're not authorized to throw this.. swallow it?
 660:             }
 661:         }
 662:     }
 663:   }
 664: 
 665:   static class EndLineAction
 666:       extends TextAction
 667:   {
 668:     EndLineAction()
 669:     {
 670:       super(endLineAction);
 671:     }
 672: 
 673:     public void actionPerformed(ActionEvent event)
 674:     {
 675:       JTextComponent t = getTextComponent(event);
 676:       try
 677:      {
 678:        int offs = Utilities.getRowEnd(t, t.getCaretPosition());
 679:        
 680:        if (offs > -1)
 681:          {
 682:            Caret c = t.getCaret();
 683:            c.setDot(offs);
 684:            c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 685:          }
 686:      }
 687:      catch (BadLocationException ble)
 688:      {
 689:        // Nothing to do here
 690:      }
 691:     }
 692:   }
 693: 
 694:   static class BeginLineAction
 695:       extends TextAction
 696:   {
 697:     BeginLineAction()
 698:     {
 699:       super(beginLineAction);
 700:     }
 701: 
 702:     public void actionPerformed(ActionEvent event)
 703:     {
 704:       JTextComponent t = getTextComponent(event);
 705:       try
 706:       {
 707:         int offs = Utilities.getRowStart(t, t.getCaretPosition());
 708:         
 709:         if (offs > -1)
 710:           {
 711:             Caret c = t.getCaret();
 712:             c.setDot(offs);
 713:             c.setMagicCaretPosition(t.modelToView(offs).getLocation());
 714:           }
 715:       }
 716:       catch (BadLocationException ble)
 717:       {
 718:         // Do nothing here.
 719:       }
 720:     }
 721:   }
 722: 
 723:   /**
 724:    * Creates a beep on the PC speaker.
 725:    *
 726:    * @see Toolkit#beep()
 727:    */
 728:   public static class BeepAction extends TextAction
 729:   {
 730:     /**
 731:      * Creates a new <code>BeepAction</code>.
 732:      */
 733:     public BeepAction()
 734:     {
 735:       super(beepAction);
 736:     }
 737: 
 738:     /**
 739:      * Performs the <code>Action</code>.
 740:      *
 741:      * @param event the action event describing the user action
 742:      */
 743:     public void actionPerformed(ActionEvent event)
 744:     {
 745:       Toolkit.getDefaultToolkit().beep();
 746:     }
 747:   }
 748: 
 749:   /**
 750:    * Copies the selected content into the system clipboard.
 751:    *
 752:    * @see Toolkit#getSystemClipboard()
 753:    * @see CutAction
 754:    * @see PasteAction
 755:    */
 756:   public static class CopyAction extends TextAction
 757:   {
 758: 
 759:     /**
 760:      * Create a new <code>CopyAction</code>.
 761:      */
 762:     public CopyAction()
 763:     {
 764:       super(copyAction);
 765:     }
 766: 
 767:     /**
 768:      * Performs the <code>Action</code>.
 769:      *
 770:      * @param event the action event describing the user action
 771:      */
 772:     public void actionPerformed(ActionEvent event)
 773:     {
 774:       getTextComponent(event).copy();
 775:     }
 776:   }
 777: 
 778: 
 779:   /**
 780:    * Copies the selected content into the system clipboard and deletes the
 781:    * selection.
 782:    *
 783:    * @see Toolkit#getSystemClipboard()
 784:    * @see CopyAction
 785:    * @see PasteAction
 786:    */
 787:   public static class CutAction extends TextAction
 788:   {
 789: 
 790:     /**
 791:      * Create a new <code>CutAction</code>.
 792:      */
 793:     public CutAction()
 794:     {
 795:       super(cutAction);
 796:     }
 797: 
 798:     /**
 799:      * Performs the <code>Action</code>.
 800:      *
 801:      * @param event the action event describing the user action
 802:      */
 803:     public void actionPerformed(ActionEvent event)
 804:     {
 805:       getTextComponent(event).cut();
 806:     }
 807:   }
 808: 
 809:   /**
 810:    * Copies content from the system clipboard into the editor.
 811:    *
 812:    * @see Toolkit#getSystemClipboard()
 813:    * @see CopyAction
 814:    * @see CutAction
 815:    */
 816:   public static class PasteAction extends TextAction
 817:   {
 818: 
 819:     /**
 820:      * Create a new <code>PasteAction</code>.
 821:      */
 822:     public PasteAction()
 823:     {
 824:       super(pasteAction);
 825:     }
 826: 
 827:     /**
 828:      * Performs the <code>Action</code>.
 829:      *
 830:      * @param event the action event describing the user action
 831:      */
 832:     public void actionPerformed(ActionEvent event)
 833:     {
 834:       getTextComponent(event).paste();
 835:     }
 836:   }
 837: 
 838:   /**
 839:    * This action is executed as default action when a KEY_TYPED
 840:    * event is received and no keymap entry exists for that. The purpose
 841:    * of this action is to filter out a couple of characters. This includes
 842:    * the control characters and characters with the ALT-modifier.
 843:    * 
 844:    * If an event does not get filtered, it is inserted into the document
 845:    * of the text component. If there is some text selected in the text
 846:    * component, this text will be replaced.
 847:    */
 848:   public static class DefaultKeyTypedAction 
 849:     extends TextAction
 850:   {
 851: 
 852:     /**
 853:      * Creates a new <code>DefaultKeyTypedAction</code>.
 854:      */
 855:     public DefaultKeyTypedAction()
 856:     {
 857:       super(defaultKeyTypedAction);
 858:     }
 859: 
 860:     /**
 861:      * Performs the <code>Action</code>.
 862:      *
 863:      * @param event the action event describing the user action
 864:      */
 865:     public void actionPerformed(ActionEvent event)
 866:     {
 867:       // first we filter the following events:
 868:       // - control characters
 869:       // - key events with the ALT modifier (FIXME: filter that too!)
 870:       char c = event.getActionCommand().charAt(0);
 871:       if (Character.isISOControl(c))
 872:         return;
 873: 
 874:       JTextComponent t = getTextComponent(event);
 875:       if (t != null && t.isEnabled() && t.isEditable())
 876:         t.replaceSelection(event.getActionCommand());
 877:     }    
 878:   }
 879: 
 880:   /**
 881:    * This action inserts a newline character into the document
 882:    * of the text component. This is typically triggered by hitting
 883:    * ENTER on the keyboard.
 884:    */
 885:   public static class InsertBreakAction extends TextAction
 886:   {
 887: 
 888:     /**
 889:      * Creates a new <code>InsertBreakAction</code>.
 890:      */
 891:     public InsertBreakAction()
 892:     {
 893:       super(insertBreakAction);
 894:     }
 895: 
 896:     /**
 897:      * Performs the <code>Action</code>.
 898:      *
 899:      * @param event the action event describing the user action
 900:      */
 901:     public void actionPerformed(ActionEvent event)
 902:     {
 903:       JTextComponent t = getTextComponent(event);
 904:       t.replaceSelection("\n");
 905:     }
 906:   }
 907: 
 908:   /**
 909:    * Places content into the associated editor. If there currently is a
 910:    * selection, this selection is replaced.
 911:    */
 912:   // FIXME: Figure out what this Action is supposed to do. Obviously text
 913:   // that is entered by the user is inserted through DefaultKeyTypedAction.
 914:   public static class InsertContentAction extends TextAction
 915:   {
 916: 
 917:     /**
 918:      * Creates a new <code>InsertContentAction</code>.
 919:      */
 920:     public InsertContentAction()
 921:     {
 922:       super(insertContentAction);
 923:     }
 924: 
 925:     /**
 926:      * Performs the <code>Action</code>.
 927:      *
 928:      * @param event the action event describing the user action
 929:      */
 930:     public void actionPerformed(ActionEvent event)
 931:     {
 932:       // FIXME: Figure out what this Action is supposed to do. Obviously text
 933:       // that is entered by the user is inserted through DefaultKeyTypedAction.
 934:     }
 935:   }
 936: 
 937:   /**
 938:    * Inserts a TAB character into the text editor.
 939:    */
 940:   public static class InsertTabAction extends TextAction
 941:   {
 942: 
 943:     /**
 944:      * Creates a new <code>TabAction</code>.
 945:      */
 946:     public InsertTabAction()
 947:     {
 948:       super(insertTabAction);
 949:     }
 950: 
 951:     /**
 952:      * Performs the <code>Action</code>.
 953:      *
 954:      * @param event the action event describing the user action
 955:      */
 956:     public void actionPerformed(ActionEvent event)
 957:     {
 958:       JTextComponent t = getTextComponent(event);
 959:       t.replaceSelection("\t");
 960:     }
 961:   }
 962: 
 963:   /**
 964:    * The serial version of DefaultEditorKit.
 965:    */
 966:   private static final long serialVersionUID = 9017245433028523428L;
 967: 
 968:   /**
 969:    * The name of the <code>Action</code> that moves the caret one character
 970:    * backwards.
 971:    *
 972:    * @see #getActions()
 973:    */
 974:   public static final String backwardAction = "caret-backward";
 975: 
 976:   /**
 977:    * The name of the <code>Action</code> that creates a beep in the speaker.
 978:    *
 979:    * @see #getActions()
 980:    */
 981:   public static final String beepAction = "beep";
 982: 
 983:   /**
 984:    * The name of the <code>Action</code> that moves the caret to the beginning
 985:    * of the <code>Document</code>.
 986:    *
 987:    * @see #getActions()
 988:    */
 989:   public static final String beginAction = "caret-begin";
 990: 
 991:   /**
 992:    * The name of the <code>Action</code> that moves the caret to the beginning
 993:    * of the current line.
 994:    *
 995:    * @see #getActions()
 996:    */
 997:   public static final String beginLineAction = "caret-begin-line";
 998: 
 999:   /**
1000:    * The name of the <code>Action</code> that moves the caret to the beginning
1001:    * of the current paragraph.
1002:    *
1003:    * @see #getActions()
1004:    */
1005:   public static final String beginParagraphAction = "caret-begin-paragraph";
1006: 
1007:   /**
1008:    * The name of the <code>Action</code> that moves the caret to the beginning
1009:    * of the current word.
1010:    *
1011:    * @see #getActions()
1012:    */
1013:   public static final String beginWordAction = "caret-begin-word";
1014: 
1015:   /**
1016:    * The name of the <code>Action</code> that copies the selected content
1017:    * into the system clipboard.
1018:    *
1019:    * @see #getActions()
1020:    */
1021:   public static final String copyAction = "copy-to-clipboard";
1022: 
1023:   /**
1024:    * The name of the <code>Action</code> that copies the selected content
1025:    * into the system clipboard and removes the selection.
1026:    *
1027:    * @see #getActions()
1028:    */
1029:   public static final String cutAction = "cut-to-clipboard";
1030: 
1031:   /**
1032:    * The name of the <code>Action</code> that is performed by default if
1033:    * a key is typed and there is no keymap entry.
1034:    *
1035:    * @see #getActions()
1036:    */
1037:   public static final String defaultKeyTypedAction = "default-typed";
1038: 
1039:   /**
1040:    * The name of the <code>Action</code> that deletes the character that
1041:    * follows the current caret position.
1042:    *
1043:    * @see #getActions()
1044:    */
1045:   public static final String deleteNextCharAction = "delete-next";
1046: 
1047:   /**
1048:    * The name of the <code>Action</code> that deletes the character that
1049:    * precedes the current caret position.
1050:    *
1051:    * @see #getActions()
1052:    */
1053:   public static final String deletePrevCharAction = "delete-previous";
1054: 
1055:   /**
1056:    * The name of the <code>Action</code> that moves the caret one line down.
1057:    *
1058:    * @see #getActions()
1059:    */
1060:   public static final String downAction = "caret-down";
1061: 
1062:   /**
1063:    * The name of the <code>Action</code> that moves the caret to the end
1064:    * of the <code>Document</code>.
1065:    *
1066:    * @see #getActions()
1067:    */
1068:   public static final String endAction = "caret-end";
1069: 
1070:   /**
1071:    * The name of the <code>Action</code> that moves the caret to the end
1072:    * of the current line.
1073:    *
1074:    * @see #getActions()
1075:    */
1076:   public static final String endLineAction = "caret-end-line";
1077: 
1078:   /**
1079:    * When a document is read and an CRLF is encountered, then we add a property
1080:    * with this name and a value of &quot;\r\n&quot;.
1081:    */
1082:   public static final String EndOfLineStringProperty = "__EndOfLine__";
1083: 
1084:   /**
1085:    * The name of the <code>Action</code> that moves the caret to the end
1086:    * of the current paragraph.
1087:    *
1088:    * @see #getActions()
1089:    */
1090:   public static final String endParagraphAction = "caret-end-paragraph";
1091: 
1092:   /**
1093:    * The name of the <code>Action</code> that moves the caret to the end
1094:    * of the current word.
1095:    *
1096:    * @see #getActions()
1097:    */
1098:   public static final String endWordAction = "caret-end-word";
1099: 
1100:   /**
1101:    * The name of the <code>Action</code> that moves the caret one character
1102:    * forward.
1103:    *
1104:    * @see #getActions()
1105:    */
1106:   public static final String forwardAction = "caret-forward";
1107: 
1108:   /**
1109:    * The name of the <code>Action</code> that inserts a line break.
1110:    *
1111:    * @see #getActions()
1112:    */
1113:   public static final String insertBreakAction = "insert-break";
1114: 
1115:   /**
1116:    * The name of the <code>Action</code> that inserts some content.
1117:    *
1118:    * @see #getActions()
1119:    */
1120:   public static final String insertContentAction = "insert-content";
1121: 
1122:   /**
1123:    * The name of the <code>Action</code> that inserts a TAB.
1124:    *
1125:    * @see #getActions()
1126:    */
1127:   public static final String insertTabAction = "insert-tab";
1128: 
1129:   /**
1130:    * The name of the <code>Action</code> that moves the caret to the beginning
1131:    * of the next word.
1132:    *
1133:    * @see #getActions()
1134:    */
1135:   public static final String nextWordAction = "caret-next-word";
1136: 
1137:   /**
1138:    * The name of the <code>Action</code> that moves the caret one page down.
1139:    *
1140:    * @see #getActions()
1141:    */
1142:   public static final String pageDownAction = "page-down";
1143: 
1144:   /**
1145:    * The name of the <code>Action</code> that moves the caret one page up.
1146:    *
1147:    * @see #getActions()
1148:    */
1149:   public static final String pageUpAction = "page-up";
1150: 
1151:   /**
1152:    * The name of the <code>Action</code> that copies content from the system
1153:    * clipboard into the document.
1154:    *
1155:    * @see #getActions()
1156:    */
1157:   public static final String pasteAction = "paste-from-clipboard";
1158: 
1159:   /**
1160:    * The name of the <code>Action</code> that moves the caret to the beginning
1161:    * of the previous word.
1162:    *
1163:    * @see #getActions()
1164:    */
1165:   public static final String previousWordAction = "caret-previous-word";
1166: 
1167:   /**
1168:    * The name of the <code>Action</code> that sets the editor in read only
1169:    * mode.
1170:    *
1171:    * @see #getActions()
1172:    */
1173:   public static final String readOnlyAction = "set-read-only";
1174: 
1175:   /**
1176:    * The name of the <code>Action</code> that selects the whole document.
1177:    *
1178:    * @see #getActions()
1179:    */
1180:   public static final String selectAllAction = "select-all";
1181: 
1182:   /**
1183:    * The name of the <code>Action</code> that moves the caret one character
1184:    * backwards, possibly extending the current selection.
1185:    *
1186:    * @see #getActions()
1187:    */
1188:   public static final String selectionBackwardAction = "selection-backward";
1189: 
1190:   /**
1191:    * The name of the <code>Action</code> that moves the caret to the beginning
1192:    * of the document, possibly extending the current selection.
1193:    *
1194:    * @see #getActions()
1195:    */
1196:   public static final String selectionBeginAction = "selection-begin";
1197: 
1198:   /**
1199:    * The name of the <code>Action</code> that moves the caret to the beginning
1200:    * of the current line, possibly extending the current selection.
1201:    *
1202:    * @see #getActions()
1203:    */
1204:   public static final String selectionBeginLineAction = "selection-begin-line";
1205: 
1206:   /**
1207:    * The name of the <code>Action</code> that moves the caret to the beginning
1208:    * of the current paragraph, possibly extending the current selection.
1209:    *
1210:    * @see #getActions()
1211:    */
1212:   public static final String selectionBeginParagraphAction =
1213:     "selection-begin-paragraph";
1214: 
1215:   /**
1216:    * The name of the <code>Action</code> that moves the caret to the beginning
1217:    * of the current word, possibly extending the current selection.
1218:    *
1219:    * @see #getActions()
1220:    */
1221:   public static final String selectionBeginWordAction = "selection-begin-word";
1222: 
1223:   /**
1224:    * The name of the <code>Action</code> that moves the caret one line down,
1225:    * possibly extending the current selection.
1226:    *
1227:    * @see #getActions()
1228:    */
1229:   public static final String selectionDownAction = "selection-down";
1230: 
1231:   /**
1232:    * The name of the <code>Action</code> that moves the caret to the end
1233:    * of the document, possibly extending the current selection.
1234:    *
1235:    * @see #getActions()
1236:    */
1237:   public static final String selectionEndAction = "selection-end";
1238: 
1239:   /**
1240:    * The name of the <code>Action</code> that moves the caret to the end
1241:    * of the current line, possibly extending the current selection.
1242:    *
1243:    * @see #getActions()
1244:    */
1245:   public static final String selectionEndLineAction = "selection-end-line";
1246: 
1247:   /**
1248:    * The name of the <code>Action</code> that moves the caret to the end
1249:    * of the current paragraph, possibly extending the current selection.
1250:    *
1251:    * @see #getActions()
1252:    */
1253:   public static final String selectionEndParagraphAction =
1254:     "selection-end-paragraph";
1255: 
1256:   /**
1257:    * The name of the <code>Action</code> that moves the caret to the end
1258:    * of the current word, possibly extending the current selection.
1259:    *
1260:    * @see #getActions()
1261:    */
1262:   public static final String selectionEndWordAction = "selection-end-word";
1263: 
1264:   /**
1265:    * The name of the <code>Action</code> that moves the caret one character
1266:    * forwards, possibly extending the current selection.
1267:    *
1268:    * @see #getActions()
1269:    */
1270:   public static final String selectionForwardAction = "selection-forward";
1271: 
1272:   /**
1273:    * The name of the <code>Action</code> that moves the caret to the beginning
1274:    * of the next word, possibly extending the current selection.
1275:    *
1276:    * @see #getActions()
1277:    */
1278:   public static final String selectionNextWordAction = "selection-next-word";
1279: 
1280:   /**
1281:    * The name of the <code>Action</code> that moves the caret to the beginning
1282:    * of the previous word, possibly extending the current selection.
1283:    *
1284:    * @see #getActions()
1285:    */
1286:   public static final String selectionPreviousWordAction =
1287:     "selection-previous-word";
1288: 
1289:   /**
1290:    * The name of the <code>Action</code> that moves the caret one line up,
1291:    * possibly extending the current selection.
1292:    *
1293:    * @see #getActions()
1294:    */
1295:   public static final String selectionUpAction = "selection-up";
1296: 
1297:   /**
1298:    * The name of the <code>Action</code> that selects the line around the
1299:    * caret.
1300:    *
1301:    * @see #getActions()
1302:    */
1303:   public static final String selectLineAction = "select-line";
1304: 
1305:   /**
1306:    * The name of the <code>Action</code> that selects the paragraph around the
1307:    * caret.
1308:    *
1309:    * @see #getActions()
1310:    */
1311:   public static final String selectParagraphAction = "select-paragraph";
1312: 
1313:   /**
1314:    * The name of the <code>Action</code> that selects the word around the
1315:    * caret.
1316:    *
1317:    * @see #getActions()
1318:    */
1319:   public static final String selectWordAction = "select-word";
1320: 
1321:   /**
1322:    * The name of the <code>Action</code> that moves the caret one line up.
1323:    *
1324:    * @see #getActions()
1325:    */
1326:   public static final String upAction = "caret-up";
1327: 
1328:   /**
1329:    * The name of the <code>Action</code> that sets the editor in read-write
1330:    * mode.
1331:    *
1332:    * @see #getActions()
1333:    */
1334:   public static final String writableAction = "set-writable";
1335: 
1336:   /**
1337:    * Creates a new <code>DefaultEditorKit</code>.
1338:    */
1339:   public DefaultEditorKit()
1340:   {
1341:     // Nothing to do here.
1342:   }
1343: 
1344:   /**
1345:    * The <code>Action</code>s that are supported by the
1346:    * <code>DefaultEditorKit</code>.
1347:    */
1348:   // TODO: All these inner classes look ugly. Maybe work out a better way
1349:   // to handle this.
1350:   private static Action[] defaultActions = 
1351:   new Action[] {
1352:     // These classes are public because they are so in the RI.            
1353:     new BeepAction(),
1354:     new CopyAction(),
1355:     new CutAction(),
1356:     new DefaultKeyTypedAction(),
1357:     new InsertBreakAction(),
1358:     new InsertContentAction(),
1359:     new InsertTabAction(),
1360:     new PasteAction(),
1361:     
1362:     // These are (package-)private inner classes.
1363:     new DeleteNextCharAction(),
1364:     new DeletePrevCharAction(),
1365: 
1366:     new BeginLineAction(),
1367:     new SelectionBeginLineAction(),
1368:     
1369:     new EndLineAction(),
1370:     new SelectionEndLineAction(),
1371:     
1372:     new BackwardAction(),
1373:     new SelectionBackwardAction(),
1374: 
1375:     new ForwardAction(),
1376:     new SelectionForwardAction(),
1377:     
1378:     new UpAction(),
1379:     new SelectionUpAction(),
1380: 
1381:     new DownAction(),
1382:     new SelectionDownAction(),
1383:     
1384:     new NextWordAction(),
1385:     new SelectionNextWordAction(),
1386: 
1387:     new PreviousWordAction(),
1388:     new SelectionPreviousWordAction(),
1389: 
1390:     new SelectionBeginAction(),
1391:     new SelectionEndAction(),
1392:     new SelectAllAction(),
1393:   };
1394: 
1395:   /**
1396:    * Creates the <code>Caret</code> for this <code>EditorKit</code>. This
1397:    * returns a {@link DefaultCaret} in this case.
1398:    *
1399:    * @return the <code>Caret</code> for this <code>EditorKit</code>
1400:    */
1401:   public Caret createCaret()
1402:   {
1403:     return new DefaultCaret();
1404:   }
1405: 
1406:   /**
1407:    * Creates the default {@link Document} that this <code>EditorKit</code>
1408:    * supports. This is a {@link PlainDocument} in this case.
1409:    *
1410:    * @return the default {@link Document} that this <code>EditorKit</code>
1411:    *         supports
1412:    */
1413:   public Document createDefaultDocument()
1414:   {
1415:     return new PlainDocument();
1416:   }
1417: 
1418:   /**
1419:    * Returns the <code>Action</code>s supported by this <code>EditorKit</code>.
1420:    *
1421:    * @return the <code>Action</code>s supported by this <code>EditorKit</code>
1422:    */
1423:   public Action[] getActions()
1424:   {
1425:     return defaultActions;
1426:   }
1427: 
1428:   /**
1429:    * Returns the content type that this <code>EditorKit</code> supports.
1430:    * The <code>DefaultEditorKit</code> supports the content type
1431:    * <code>text/plain</code>.
1432:    *
1433:    * @return the content type that this <code>EditorKit</code> supports
1434:    */
1435:   public String getContentType()
1436:   {
1437:     return "text/plain";
1438:   }
1439: 
1440:   /**
1441:    * Returns a {@link ViewFactory} that is able to create {@link View}s for
1442:    * the <code>Element</code>s that are used in this <code>EditorKit</code>'s
1443:    * model. This returns null which lets the UI of the text component supply
1444:    * <code>View</code>s.
1445:    *
1446:    * @return a {@link ViewFactory} that is able to create {@link View}s for
1447:    *         the <code>Element</code>s that are used in this
1448:    *         <code>EditorKit</code>'s model
1449:    */
1450:   public ViewFactory getViewFactory()
1451:   {
1452:     return null;
1453:   }
1454: 
1455:   /**
1456:    * Reads a document of the supported content type from an {@link InputStream}
1457:    * into the actual {@link Document} object.
1458:    *
1459:    * @param in the stream from which to read the document
1460:    * @param document the document model into which the content is read
1461:    * @param offset the offset inside to document where the content is inserted
1462:    *
1463:    * @throws BadLocationException if <code>offset</code> is an invalid location
1464:    *         inside <code>document</code>
1465:    * @throws IOException if something goes wrong while reading from
1466:    *        <code>in</code>
1467:    */
1468:   public void read(InputStream in, Document document, int offset)
1469:     throws BadLocationException, IOException
1470:   {
1471:     read(new InputStreamReader(in), document, offset);
1472:   }
1473: 
1474:   /**
1475:    * Reads a document of the supported content type from a {@link Reader}
1476:    * into the actual {@link Document} object.
1477:    *
1478:    * @param in the reader from which to read the document
1479:    * @param document the document model into which the content is read
1480:    * @param offset the offset inside to document where the content is inserted
1481:    *
1482:    * @throws BadLocationException if <code>offset</code> is an invalid location
1483:    *         inside <code>document</code>
1484:    * @throws IOException if something goes wrong while reading from
1485:    *        <code>in</code>
1486:    */
1487:   public void read(Reader in, Document document, int offset)
1488:     throws BadLocationException, IOException
1489:   {
1490:     BufferedReader reader = new BufferedReader(in);
1491: 
1492:     String line;
1493:     StringBuffer content = new StringBuffer();
1494: 
1495:     while ((line = reader.readLine()) != null)
1496:       {
1497:     content.append(line);
1498:     content.append("\n");
1499:       }
1500:     
1501:     document.insertString(offset, content.substring(0, content.length() - 1),
1502:               SimpleAttributeSet.EMPTY);
1503:   }
1504: 
1505:   /**
1506:    * Writes the <code>Document</code> (or a fragment of the
1507:    * <code>Document</code>) to an {@link OutputStream} in the
1508:    * supported content type format.
1509:    *
1510:    * @param out the stream to write to
1511:    * @param document the document that should be written out
1512:    * @param offset the beginning offset from where to write
1513:    * @param len the length of the fragment to write
1514:    *
1515:    * @throws BadLocationException if <code>offset</code> or
1516:    *         <code>offset + len</code>is an invalid location inside
1517:    *         <code>document</code>
1518:    * @throws IOException if something goes wrong while writing to
1519:    *        <code>out</code>
1520:    */
1521:   public void write(OutputStream out, Document document, int offset, int len)
1522:     throws BadLocationException, IOException
1523:   {
1524:     write(new OutputStreamWriter(out), document, offset, len);
1525:   }
1526: 
1527:   /**
1528:    * Writes the <code>Document</code> (or a fragment of the
1529:    * <code>Document</code>) to a {@link Writer} in the
1530:    * supported content type format.
1531:    *
1532:    * @param out the writer to write to
1533:    * @param document the document that should be written out
1534:    * @param offset the beginning offset from where to write
1535:    * @param len the length of the fragment to write
1536:    *
1537:    * @throws BadLocationException if <code>offset</code> is an 
1538:    * invalid location inside <code>document</code>.
1539:    * @throws IOException if something goes wrong while writing to
1540:    *        <code>out</code>
1541:    */
1542:   public void write(Writer out, Document document, int offset, int len)
1543:       throws BadLocationException, IOException
1544:   {
1545:     // Throw a BLE if offset is invalid
1546:     if (offset < 0 || offset > document.getLength())
1547:       throw new BadLocationException("Tried to write to invalid location",
1548:                                      offset);
1549: 
1550:     // If they gave an overly large len, just adjust it
1551:     if (offset + len > document.getLength())
1552:       len = document.getLength() - offset;
1553: 
1554:     out.write(document.getText(offset, len));
1555:   }
1556: }