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:   /**
  67:    * Creates a beep on the PC speaker.
  68:    *
  69:    * @see Toolkit#beep()
  70:    */
  71:   public static class BeepAction extends TextAction
  72:   {
  73:     /**
  74:      * Creates a new <code>BeepAction</code>.
  75:      */
  76:     public BeepAction()
  77:     {
  78:       super(beepAction);
  79:     }
  80: 
  81:     /**
  82:      * Performs the <code>Action</code>.
  83:      *
  84:      * @param event the action event describing the user action
  85:      */
  86:     public void actionPerformed(ActionEvent event)
  87:     {
  88:       Toolkit.getDefaultToolkit().beep();
  89:     }
  90:   }
  91: 
  92:   /**
  93:    * Copies the selected content into the system clipboard.
  94:    *
  95:    * @see Toolkit#getSystemClipboard()
  96:    * @see CutAction
  97:    * @see PasteAction
  98:    */
  99:   public static class CopyAction extends TextAction
 100:   {
 101: 
 102:     /**
 103:      * Create a new <code>CopyAction</code>.
 104:      */
 105:     public CopyAction()
 106:     {
 107:       super(copyAction);
 108:     }
 109: 
 110:     /**
 111:      * Performs the <code>Action</code>.
 112:      *
 113:      * @param event the action event describing the user action
 114:      */
 115:     public void actionPerformed(ActionEvent event)
 116:     {
 117:       getTextComponent(event).copy();
 118:     }
 119:   }
 120: 
 121: 
 122:   /**
 123:    * Copies the selected content into the system clipboard and deletes the
 124:    * selection.
 125:    *
 126:    * @see Toolkit#getSystemClipboard()
 127:    * @see CopyAction
 128:    * @see PasteAction
 129:    */
 130:   public static class CutAction extends TextAction
 131:   {
 132: 
 133:     /**
 134:      * Create a new <code>CutAction</code>.
 135:      */
 136:     public CutAction()
 137:     {
 138:       super(cutAction);
 139:     }
 140: 
 141:     /**
 142:      * Performs the <code>Action</code>.
 143:      *
 144:      * @param event the action event describing the user action
 145:      */
 146:     public void actionPerformed(ActionEvent event)
 147:     {
 148:       getTextComponent(event).cut();
 149:     }
 150:   }
 151: 
 152:   /**
 153:    * Copies content from the system clipboard into the editor.
 154:    *
 155:    * @see Toolkit#getSystemClipboard()
 156:    * @see CopyAction
 157:    * @see CutAction
 158:    */
 159:   public static class PasteAction extends TextAction
 160:   {
 161: 
 162:     /**
 163:      * Create a new <code>PasteAction</code>.
 164:      */
 165:     public PasteAction()
 166:     {
 167:       super(pasteAction);
 168:     }
 169: 
 170:     /**
 171:      * Performs the <code>Action</code>.
 172:      *
 173:      * @param event the action event describing the user action
 174:      */
 175:     public void actionPerformed(ActionEvent event)
 176:     {
 177:       getTextComponent(event).paste();
 178:     }
 179:   }
 180: 
 181:   /**
 182:    * This action is executed as default action when a KEY_TYPED
 183:    * event is received and no keymap entry exists for that. The purpose
 184:    * of this action is to filter out a couple of characters. This includes
 185:    * the control characters and characters with the ALT-modifier.
 186:    * 
 187:    * If an event does not get filtered, it is inserted into the document
 188:    * of the text component. If there is some text selected in the text
 189:    * component, this text will be replaced.
 190:    */
 191:   public static class DefaultKeyTypedAction 
 192:     extends TextAction
 193:   {
 194: 
 195:     /**
 196:      * Creates a new <code>DefaultKeyTypedAction</code>.
 197:      */
 198:     public DefaultKeyTypedAction()
 199:     {
 200:       super(defaultKeyTypedAction);
 201:     }
 202: 
 203:     /**
 204:      * Performs the <code>Action</code>.
 205:      *
 206:      * @param event the action event describing the user action
 207:      */
 208:     public void actionPerformed(ActionEvent event)
 209:     {
 210:       // first we filter the following events:
 211:       // - control characters
 212:       // - key events with the ALT modifier (FIXME: filter that too!)
 213:       char c = event.getActionCommand().charAt(0);
 214:       if (Character.isISOControl(c))
 215:         return;
 216: 
 217:       JTextComponent t = getTextComponent(event);
 218:       if (t != null && t.isEnabled() && t.isEditable())
 219:         t.replaceSelection(event.getActionCommand());
 220:     }    
 221:   }
 222: 
 223:   /**
 224:    * This action inserts a newline character into the document
 225:    * of the text component. This is typically triggered by hitting
 226:    * ENTER on the keyboard.
 227:    */
 228:   public static class InsertBreakAction extends TextAction
 229:   {
 230: 
 231:     /**
 232:      * Creates a new <code>InsertBreakAction</code>.
 233:      */
 234:     public InsertBreakAction()
 235:     {
 236:       super(insertBreakAction);
 237:     }
 238: 
 239:     /**
 240:      * Performs the <code>Action</code>.
 241:      *
 242:      * @param event the action event describing the user action
 243:      */
 244:     public void actionPerformed(ActionEvent event)
 245:     {
 246:       JTextComponent t = getTextComponent(event);
 247:       t.replaceSelection("\n");
 248:     }
 249:   }
 250: 
 251:   /**
 252:    * Places content into the associated editor. If there currently is a
 253:    * selection, this selection is replaced.
 254:    */
 255:   // FIXME: Figure out what this Action is supposed to do. Obviously text
 256:   // that is entered by the user is inserted through DefaultKeyTypedAction.
 257:   public static class InsertContentAction extends TextAction
 258:   {
 259: 
 260:     /**
 261:      * Creates a new <code>InsertContentAction</code>.
 262:      */
 263:     public InsertContentAction()
 264:     {
 265:       super(insertContentAction);
 266:     }
 267: 
 268:     /**
 269:      * Performs the <code>Action</code>.
 270:      *
 271:      * @param event the action event describing the user action
 272:      */
 273:     public void actionPerformed(ActionEvent event)
 274:     {
 275:       // FIXME: Figure out what this Action is supposed to do. Obviously text
 276:       // that is entered by the user is inserted through DefaultKeyTypedAction.
 277:     }
 278:   }
 279: 
 280:   /**
 281:    * Inserts a TAB character into the text editor.
 282:    */
 283:   public static class InsertTabAction extends TextAction
 284:   {
 285: 
 286:     /**
 287:      * Creates a new <code>TabAction</code>.
 288:      */
 289:     public InsertTabAction()
 290:     {
 291:       super(insertTabAction);
 292:     }
 293: 
 294:     /**
 295:      * Performs the <code>Action</code>.
 296:      *
 297:      * @param event the action event describing the user action
 298:      */
 299:     public void actionPerformed(ActionEvent event)
 300:     {
 301:       JTextComponent t = getTextComponent(event);
 302:       t.replaceSelection("\t");
 303:     }
 304:   }
 305: 
 306:   /**
 307:    * The serial version of DefaultEditorKit.
 308:    */
 309:   private static final long serialVersionUID = 9017245433028523428L;
 310: 
 311:   /**
 312:    * The name of the <code>Action</code> that moves the caret one character
 313:    * backwards.
 314:    *
 315:    * @see #getActions()
 316:    */
 317:   public static final String backwardAction = "caret-backward";
 318: 
 319:   /**
 320:    * The name of the <code>Action</code> that creates a beep in the speaker.
 321:    *
 322:    * @see #getActions()
 323:    */
 324:   public static final String beepAction = "beep";
 325: 
 326:   /**
 327:    * The name of the <code>Action</code> that moves the caret to the beginning
 328:    * of the <code>Document</code>.
 329:    *
 330:    * @see #getActions()
 331:    */
 332:   public static final String beginAction = "caret-begin";
 333: 
 334:   /**
 335:    * The name of the <code>Action</code> that moves the caret to the beginning
 336:    * of the current line.
 337:    *
 338:    * @see #getActions()
 339:    */
 340:   public static final String beginLineAction = "caret-begin-line";
 341: 
 342:   /**
 343:    * The name of the <code>Action</code> that moves the caret to the beginning
 344:    * of the current paragraph.
 345:    *
 346:    * @see #getActions()
 347:    */
 348:   public static final String beginParagraphAction = "caret-begin-paragraph";
 349: 
 350:   /**
 351:    * The name of the <code>Action</code> that moves the caret to the beginning
 352:    * of the current word.
 353:    *
 354:    * @see #getActions()
 355:    */
 356:   public static final String beginWordAction = "caret-begin-word";
 357: 
 358:   /**
 359:    * The name of the <code>Action</code> that copies the selected content
 360:    * into the system clipboard.
 361:    *
 362:    * @see #getActions()
 363:    */
 364:   public static final String copyAction = "copy-to-clipboard";
 365: 
 366:   /**
 367:    * The name of the <code>Action</code> that copies the selected content
 368:    * into the system clipboard and removes the selection.
 369:    *
 370:    * @see #getActions()
 371:    */
 372:   public static final String cutAction = "cut-to-clipboard";
 373: 
 374:   /**
 375:    * The name of the <code>Action</code> that is performed by default if
 376:    * a key is typed and there is no keymap entry.
 377:    *
 378:    * @see #getActions()
 379:    */
 380:   public static final String defaultKeyTypedAction = "default-typed";
 381: 
 382:   /**
 383:    * The name of the <code>Action</code> that deletes the character that
 384:    * follows the current caret position.
 385:    *
 386:    * @see #getActions()
 387:    */
 388:   public static final String deleteNextCharAction = "delete-next";
 389: 
 390:   /**
 391:    * The name of the <code>Action</code> that deletes the character that
 392:    * precedes the current caret position.
 393:    *
 394:    * @see #getActions()
 395:    */
 396:   public static final String deletePrevCharAction = "delete-previous";
 397: 
 398:   /**
 399:    * The name of the <code>Action</code> that moves the caret one line down.
 400:    *
 401:    * @see #getActions()
 402:    */
 403:   public static final String downAction = "caret-down";
 404: 
 405:   /**
 406:    * The name of the <code>Action</code> that moves the caret to the end
 407:    * of the <code>Document</code>.
 408:    *
 409:    * @see #getActions()
 410:    */
 411:   public static final String endAction = "caret-end";
 412: 
 413:   /**
 414:    * The name of the <code>Action</code> that moves the caret to the end
 415:    * of the current line.
 416:    *
 417:    * @see #getActions()
 418:    */
 419:   public static final String endLineAction = "caret-end-line";
 420: 
 421:   /**
 422:    * When a document is read and an CRLF is encountered, then we add a property
 423:    * with this name and a value of &quot;\r\n&quot;.
 424:    */
 425:   public static final String EndOfLineStringProperty = "__EndOfLine__";
 426: 
 427:   /**
 428:    * The name of the <code>Action</code> that moves the caret to the end
 429:    * of the current paragraph.
 430:    *
 431:    * @see #getActions()
 432:    */
 433:   public static final String endParagraphAction = "caret-end-paragraph";
 434: 
 435:   /**
 436:    * The name of the <code>Action</code> that moves the caret to the end
 437:    * of the current word.
 438:    *
 439:    * @see #getActions()
 440:    */
 441:   public static final String endWordAction = "caret-end-word";
 442: 
 443:   /**
 444:    * The name of the <code>Action</code> that moves the caret one character
 445:    * forward.
 446:    *
 447:    * @see #getActions()
 448:    */
 449:   public static final String forwardAction = "caret-forward";
 450: 
 451:   /**
 452:    * The name of the <code>Action</code> that inserts a line break.
 453:    *
 454:    * @see #getActions()
 455:    */
 456:   public static final String insertBreakAction = "insert-break";
 457: 
 458:   /**
 459:    * The name of the <code>Action</code> that inserts some content.
 460:    *
 461:    * @see #getActions()
 462:    */
 463:   public static final String insertContentAction = "insert-content";
 464: 
 465:   /**
 466:    * The name of the <code>Action</code> that inserts a TAB.
 467:    *
 468:    * @see #getActions()
 469:    */
 470:   public static final String insertTabAction = "insert-tab";
 471: 
 472:   /**
 473:    * The name of the <code>Action</code> that moves the caret to the beginning
 474:    * of the next word.
 475:    *
 476:    * @see #getActions()
 477:    */
 478:   public static final String nextWordAction = "caret-next-word";
 479: 
 480:   /**
 481:    * The name of the <code>Action</code> that moves the caret one page down.
 482:    *
 483:    * @see #getActions()
 484:    */
 485:   public static final String pageDownAction = "page-down";
 486: 
 487:   /**
 488:    * The name of the <code>Action</code> that moves the caret one page up.
 489:    *
 490:    * @see #getActions()
 491:    */
 492:   public static final String pageUpAction = "page-up";
 493: 
 494:   /**
 495:    * The name of the <code>Action</code> that copies content from the system
 496:    * clipboard into the document.
 497:    *
 498:    * @see #getActions()
 499:    */
 500:   public static final String pasteAction = "paste-from-clipboard";
 501: 
 502:   /**
 503:    * The name of the <code>Action</code> that moves the caret to the beginning
 504:    * of the previous word.
 505:    *
 506:    * @see #getActions()
 507:    */
 508:   public static final String previousWordAction = "caret-previous-word";
 509: 
 510:   /**
 511:    * The name of the <code>Action</code> that sets the editor in read only
 512:    * mode.
 513:    *
 514:    * @see #getActions()
 515:    */
 516:   public static final String readOnlyAction = "set-read-only";
 517: 
 518:   /**
 519:    * The name of the <code>Action</code> that selects the whole document.
 520:    *
 521:    * @see #getActions()
 522:    */
 523:   public static final String selectAllAction = "select-all";
 524: 
 525:   /**
 526:    * The name of the <code>Action</code> that moves the caret one character
 527:    * backwards, possibly extending the current selection.
 528:    *
 529:    * @see #getActions()
 530:    */
 531:   public static final String selectionBackwardAction = "selection-backward";
 532: 
 533:   /**
 534:    * The name of the <code>Action</code> that moves the caret to the beginning
 535:    * of the document, possibly extending the current selection.
 536:    *
 537:    * @see #getActions()
 538:    */
 539:   public static final String selectionBeginAction = "selection-begin";
 540: 
 541:   /**
 542:    * The name of the <code>Action</code> that moves the caret to the beginning
 543:    * of the current line, possibly extending the current selection.
 544:    *
 545:    * @see #getActions()
 546:    */
 547:   public static final String selectionBeginLineAction = "selection-begin-line";
 548: 
 549:   /**
 550:    * The name of the <code>Action</code> that moves the caret to the beginning
 551:    * of the current paragraph, possibly extending the current selection.
 552:    *
 553:    * @see #getActions()
 554:    */
 555:   public static final String selectionBeginParagraphAction =
 556:     "selection-begin-paragraph";
 557: 
 558:   /**
 559:    * The name of the <code>Action</code> that moves the caret to the beginning
 560:    * of the current word, possibly extending the current selection.
 561:    *
 562:    * @see #getActions()
 563:    */
 564:   public static final String selectionBeginWordAction = "selection-begin-word";
 565: 
 566:   /**
 567:    * The name of the <code>Action</code> that moves the caret one line down,
 568:    * possibly extending the current selection.
 569:    *
 570:    * @see #getActions()
 571:    */
 572:   public static final String selectionDownAction = "selection-down";
 573: 
 574:   /**
 575:    * The name of the <code>Action</code> that moves the caret to the end
 576:    * of the document, possibly extending the current selection.
 577:    *
 578:    * @see #getActions()
 579:    */
 580:   public static final String selectionEndAction = "selection-end";
 581: 
 582:   /**
 583:    * The name of the <code>Action</code> that moves the caret to the end
 584:    * of the current line, possibly extending the current selection.
 585:    *
 586:    * @see #getActions()
 587:    */
 588:   public static final String selectionEndLineAction = "selection-end-line";
 589: 
 590:   /**
 591:    * The name of the <code>Action</code> that moves the caret to the end
 592:    * of the current paragraph, possibly extending the current selection.
 593:    *
 594:    * @see #getActions()
 595:    */
 596:   public static final String selectionEndParagraphAction =
 597:     "selection-end-paragraph";
 598: 
 599:   /**
 600:    * The name of the <code>Action</code> that moves the caret to the end
 601:    * of the current word, possibly extending the current selection.
 602:    *
 603:    * @see #getActions()
 604:    */
 605:   public static final String selectionEndWordAction = "selection-end-word";
 606: 
 607:   /**
 608:    * The name of the <code>Action</code> that moves the caret one character
 609:    * forwards, possibly extending the current selection.
 610:    *
 611:    * @see #getActions()
 612:    */
 613:   public static final String selectionForwardAction = "selection-forward";
 614: 
 615:   /**
 616:    * The name of the <code>Action</code> that moves the caret to the beginning
 617:    * of the next word, possibly extending the current selection.
 618:    *
 619:    * @see #getActions()
 620:    */
 621:   public static final String selectionNextWordAction = "selection-next-word";
 622: 
 623:   /**
 624:    * The name of the <code>Action</code> that moves the caret to the beginning
 625:    * of the previous word, possibly extending the current selection.
 626:    *
 627:    * @see #getActions()
 628:    */
 629:   public static final String selectionPreviousWordAction =
 630:     "selection-previous-word";
 631: 
 632:   /**
 633:    * The name of the <code>Action</code> that moves the caret one line up,
 634:    * possibly extending the current selection.
 635:    *
 636:    * @see #getActions()
 637:    */
 638:   public static final String selectionUpAction = "selection-up";
 639: 
 640:   /**
 641:    * The name of the <code>Action</code> that selects the line around the
 642:    * caret.
 643:    *
 644:    * @see #getActions()
 645:    */
 646:   public static final String selectLineAction = "select-line";
 647: 
 648:   /**
 649:    * The name of the <code>Action</code> that selects the paragraph around the
 650:    * caret.
 651:    *
 652:    * @see #getActions()
 653:    */
 654:   public static final String selectParagraphAction = "select-paragraph";
 655: 
 656:   /**
 657:    * The name of the <code>Action</code> that selects the word around the
 658:    * caret.
 659:    *
 660:    * @see #getActions()
 661:    */
 662:   public static final String selectWordAction = "select-word";
 663: 
 664:   /**
 665:    * The name of the <code>Action</code> that moves the caret one line up.
 666:    *
 667:    * @see #getActions()
 668:    */
 669:   public static final String upAction = "caret-up";
 670: 
 671:   /**
 672:    * The name of the <code>Action</code> that sets the editor in read-write
 673:    * mode.
 674:    *
 675:    * @see #getActions()
 676:    */
 677:   public static final String writableAction = "set-writable";
 678: 
 679:   /**
 680:    * Creates a new <code>DefaultEditorKit</code>.
 681:    */
 682:   public DefaultEditorKit()
 683:   {
 684:     // Nothing to do here.
 685:   }
 686: 
 687:   /**
 688:    * The <code>Action</code>s that are supported by the
 689:    * <code>DefaultEditorKit</code>.
 690:    */
 691:   // TODO: All these inner classes look ugly. Maybe work out a better way
 692:   // to handle this.
 693:   private static Action[] defaultActions = 
 694:   new Action[] {
 695:     new BeepAction(),
 696:     new CopyAction(),
 697:     new CutAction(),
 698:     new DefaultKeyTypedAction(),
 699:     new InsertBreakAction(),
 700:     new InsertContentAction(),
 701:     new InsertTabAction(),
 702:     new PasteAction(),
 703:     new TextAction(beginLineAction)
 704:     {
 705:       public void actionPerformed(ActionEvent event)
 706:       {
 707:         JTextComponent t = getTextComponent(event);
 708:         try
 709:         {
 710:           // TODO: There is a more efficent solution, but
 711:           // viewToModel doesn't work properly.
 712:           Point p = t.modelToView(t.getCaret().getDot()).getLocation();
 713:           int cur = t.getCaretPosition();
 714:           int y = p.y;
 715:           while (y == p.y && cur > 0)
 716:             y = t.modelToView(--cur).getLocation().y;
 717:           if (cur != 0)
 718:             cur++;
 719:           t.setCaretPosition(cur);
 720:         }
 721:         catch (BadLocationException ble)
 722:         {
 723:           // Do nothing here.
 724:         }
 725:       }
 726:     },
 727:     new TextAction(endLineAction)
 728:     {
 729:       public void actionPerformed(ActionEvent event)
 730:       {
 731:         JTextComponent t = getTextComponent(event);
 732:        try
 733:        {
 734:          Point p = t.modelToView(t.getCaret().getDot()).getLocation();
 735:          int cur = t.getCaretPosition();
 736:          int y = p.y;
 737:          int length = t.getDocument().getLength();
 738:          while (y == p.y && cur < length)
 739:            y = t.modelToView(++cur).getLocation().y;
 740:          if (cur != length)
 741:            cur--;
 742:          t.setCaretPosition(cur);
 743:        }
 744:        catch (BadLocationException ble)
 745:        {
 746:          // Nothing to do here
 747:        }
 748:       }
 749:     },
 750:     new TextAction(deleteNextCharAction) 
 751:     { 
 752:       public void actionPerformed(ActionEvent event)
 753:       {
 754:         JTextComponent t = getTextComponent(event);
 755:         if (t != null)
 756:           {
 757:             try
 758:               {
 759:                 int pos = t.getCaret().getDot();
 760:                 if (pos < t.getDocument().getEndPosition().getOffset())
 761:                   {
 762:                     t.getDocument().remove(t.getCaret().getDot(), 1);
 763:                   }
 764:               }
 765:             catch (BadLocationException e)
 766:               {
 767:                 // FIXME: we're not authorized to throw this.. swallow it?
 768:               }
 769:           }
 770:       }
 771:     },
 772:     new TextAction(deletePrevCharAction) 
 773:     { 
 774:       public void actionPerformed(ActionEvent event)
 775:       {
 776:         JTextComponent t = getTextComponent(event);
 777:         if (t != null)
 778:           {
 779:             try
 780:               {
 781:                 int pos = t.getCaret().getDot();
 782:                 if (pos > t.getDocument().getStartPosition().getOffset())
 783:                   {
 784:                     t.getDocument().remove(pos - 1, 1);
 785:                     t.getCaret().setDot(pos - 1);
 786:                   }
 787:               }
 788:             catch (BadLocationException e)
 789:               {
 790:                 // FIXME: we're not authorized to throw this.. swallow it?
 791:               }
 792:           }
 793:       }
 794:     },
 795:     new TextAction(backwardAction) 
 796:     { 
 797:       public void actionPerformed(ActionEvent event)
 798:       {
 799:         JTextComponent t = getTextComponent(event);
 800:         if (t != null)
 801:           {
 802:             t.getCaret().setDot(Math.max(t.getCaret().getDot() - 1,
 803:                                          t.getDocument().getStartPosition().getOffset()));
 804:           }
 805:       }
 806:     },
 807:     new TextAction(forwardAction) 
 808:     { 
 809:       public void actionPerformed(ActionEvent event)
 810:       {
 811:         JTextComponent t = getTextComponent(event);
 812:         if (t != null)
 813:           {
 814:             t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1,
 815:                                          t.getDocument().getEndPosition().getOffset()));
 816:           }
 817:       }
 818:     },
 819:     new TextAction(selectionBackwardAction)
 820:     {
 821:       public void actionPerformed(ActionEvent event)
 822:       {
 823:     JTextComponent t = getTextComponent(event);
 824:     if (t != null)
 825:       {
 826:         t.getCaret().moveDot(Math.max(t.getCaret().getDot() - 1,
 827:                       t.getDocument().getStartPosition().getOffset()));
 828:       }
 829:       }
 830:     },
 831:     new TextAction(selectionForwardAction)
 832:     {
 833:       public void actionPerformed(ActionEvent event)
 834:       {
 835:         JTextComponent t = getTextComponent(event);
 836:         if (t != null)
 837:           {
 838:             t.getCaret().moveDot(Math.min(t.getCaret().getDot() + 1,
 839:                                           t.getDocument().getEndPosition().getOffset()));
 840:           }
 841:       }
 842:     },
 843:   };
 844: 
 845:   /**
 846:    * Creates the <code>Caret</code> for this <code>EditorKit</code>. This
 847:    * returns a {@link DefaultCaret} in this case.
 848:    *
 849:    * @return the <code>Caret</code> for this <code>EditorKit</code>
 850:    */
 851:   public Caret createCaret()
 852:   {
 853:     return new DefaultCaret();
 854:   }
 855: 
 856:   /**
 857:    * Creates the default {@link Document} that this <code>EditorKit</code>
 858:    * supports. This is a {@link PlainDocument} in this case.
 859:    *
 860:    * @return the default {@link Document} that this <code>EditorKit</code>
 861:    *         supports
 862:    */
 863:   public Document createDefaultDocument()
 864:   {
 865:     return new PlainDocument();
 866:   }
 867: 
 868:   /**
 869:    * Returns the <code>Action</code>s supported by this <code>EditorKit</code>.
 870:    *
 871:    * @return the <code>Action</code>s supported by this <code>EditorKit</code>
 872:    */
 873:   public Action[] getActions()
 874:   {
 875:     return defaultActions;
 876:   }
 877: 
 878:   /**
 879:    * Returns the content type that this <code>EditorKit</code> supports.
 880:    * The <code>DefaultEditorKit</code> supports the content type
 881:    * <code>text/plain</code>.
 882:    *
 883:    * @return the content type that this <code>EditorKit</code> supports
 884:    */
 885:   public String getContentType()
 886:   {
 887:     return "text/plain";
 888:   }
 889: 
 890:   /**
 891:    * Returns a {@link ViewFactory} that is able to create {@link View}s for
 892:    * the <code>Element</code>s that are used in this <code>EditorKit</code>'s
 893:    * model. This returns null which lets the UI of the text component supply
 894:    * <code>View</code>s.
 895:    *
 896:    * @return a {@link ViewFactory} that is able to create {@link View}s for
 897:    *         the <code>Element</code>s that are used in this
 898:    *         <code>EditorKit</code>'s model
 899:    */
 900:   public ViewFactory getViewFactory()
 901:   {
 902:     return null;
 903:   }
 904: 
 905:   /**
 906:    * Reads a document of the supported content type from an {@link InputStream}
 907:    * into the actual {@link Document} object.
 908:    *
 909:    * @param in the stream from which to read the document
 910:    * @param document the document model into which the content is read
 911:    * @param offset the offset inside to document where the content is inserted
 912:    *
 913:    * @throws BadLocationException if <code>offset</code> is an invalid location
 914:    *         inside <code>document</code>
 915:    * @throws IOException if something goes wrong while reading from
 916:    *        <code>in</code>
 917:    */
 918:   public void read(InputStream in, Document document, int offset)
 919:     throws BadLocationException, IOException
 920:   {
 921:     read(new InputStreamReader(in), document, offset);
 922:   }
 923: 
 924:   /**
 925:    * Reads a document of the supported content type from a {@link Reader}
 926:    * into the actual {@link Document} object.
 927:    *
 928:    * @param in the reader from which to read the document
 929:    * @param document the document model into which the content is read
 930:    * @param offset the offset inside to document where the content is inserted
 931:    *
 932:    * @throws BadLocationException if <code>offset</code> is an invalid location
 933:    *         inside <code>document</code>
 934:    * @throws IOException if something goes wrong while reading from
 935:    *        <code>in</code>
 936:    */
 937:   public void read(Reader in, Document document, int offset)
 938:     throws BadLocationException, IOException
 939:   {
 940:     BufferedReader reader = new BufferedReader(in);
 941: 
 942:     String line;
 943:     StringBuffer content = new StringBuffer();
 944: 
 945:     while ((line = reader.readLine()) != null)
 946:       {
 947:     content.append(line);
 948:     content.append("\n");
 949:       }
 950:     
 951:     document.insertString(offset, content.substring(0, content.length() - 1),
 952:               SimpleAttributeSet.EMPTY);
 953:   }
 954: 
 955:   /**
 956:    * Writes the <code>Document</code> (or a fragment of the
 957:    * <code>Document</code>) to an {@link OutputStream} in the
 958:    * supported content type format.
 959:    *
 960:    * @param out the stream to write to
 961:    * @param document the document that should be written out
 962:    * @param offset the beginning offset from where to write
 963:    * @param len the length of the fragment to write
 964:    *
 965:    * @throws BadLocationException if <code>offset</code> or
 966:    *         <code>offset + len</code>is an invalid location inside
 967:    *         <code>document</code>
 968:    * @throws IOException if something goes wrong while writing to
 969:    *        <code>out</code>
 970:    */
 971:   public void write(OutputStream out, Document document, int offset, int len)
 972:     throws BadLocationException, IOException
 973:   {
 974:     write(new OutputStreamWriter(out), document, offset, len);
 975:   }
 976: 
 977:   /**
 978:    * Writes the <code>Document</code> (or a fragment of the
 979:    * <code>Document</code>) to a {@link Writer} in the
 980:    * supported content type format.
 981:    *
 982:    * @param out the writer to write to
 983:    * @param document the document that should be written out
 984:    * @param offset the beginning offset from where to write
 985:    * @param len the length of the fragment to write
 986:    *
 987:    * @throws BadLocationException if <code>offset</code> is an 
 988:    * invalid location inside <code>document</code>.
 989:    * @throws IOException if something goes wrong while writing to
 990:    *        <code>out</code>
 991:    */
 992:   public void write(Writer out, Document document, int offset, int len)
 993:       throws BadLocationException, IOException
 994:   {
 995:     // Throw a BLE if offset is invalid
 996:     if (offset < 0 || offset > document.getLength())
 997:       throw new BadLocationException("Tried to write to invalid location",
 998:                                      offset);
 999: 
1000:     // If they gave an overly large len, just adjust it
1001:     if (offset + len > document.getLength())
1002:       len = document.getLength() - offset;
1003: 
1004:     out.write(document.getText(offset, len));
1005:   }
1006: }