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 gnu.java.lang.CPStringBuilder;
042    
043    import java.awt.Toolkit;
044    import java.awt.event.ActionEvent;
045    
046    import java.io.BufferedReader;
047    import java.io.IOException;
048    import java.io.InputStream;
049    import java.io.InputStreamReader;
050    import java.io.OutputStream;
051    import java.io.OutputStreamWriter;
052    import java.io.Reader;
053    import java.io.Writer;
054    
055    import javax.swing.Action;
056    import 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     */
067    public 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    }