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