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