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