1
2
3
4
5
6
7
8
9 package com.ochafik.swing.syntaxcoloring;
10 import java.awt.AWTEvent;
11 import java.awt.Component;
12 import java.awt.Container;
13 import java.awt.Dimension;
14 import java.awt.Font;
15 import java.awt.FontMetrics;
16 import java.awt.Insets;
17 import java.awt.LayoutManager;
18 import java.awt.Toolkit;
19 import java.awt.datatransfer.Clipboard;
20 import java.awt.datatransfer.DataFlavor;
21 import java.awt.datatransfer.StringSelection;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.awt.event.AdjustmentEvent;
25 import java.awt.event.AdjustmentListener;
26 import java.awt.event.ComponentAdapter;
27 import java.awt.event.ComponentEvent;
28 import java.awt.event.FocusEvent;
29 import java.awt.event.FocusListener;
30 import java.awt.event.InputEvent;
31 import java.awt.event.KeyEvent;
32 import java.awt.event.MouseAdapter;
33 import java.awt.event.MouseEvent;
34 import java.awt.event.MouseMotionListener;
35 import java.beans.PropertyChangeListener;
36 import java.beans.PropertyChangeSupport;
37 import java.util.Enumeration;
38 import java.util.Vector;
39
40 import javax.swing.Action;
41 import javax.swing.ActionMap;
42 import javax.swing.InputMap;
43 import javax.swing.JComponent;
44 import javax.swing.JOptionPane;
45 import javax.swing.JPopupMenu;
46 import javax.swing.JScrollBar;
47 import javax.swing.KeyStroke;
48 import javax.swing.SwingUtilities;
49 import javax.swing.Timer;
50 import javax.swing.event.CaretEvent;
51 import javax.swing.event.CaretListener;
52 import javax.swing.event.DocumentEvent;
53 import javax.swing.event.DocumentListener;
54 import javax.swing.event.EventListenerList;
55 import javax.swing.text.BadLocationException;
56 import javax.swing.text.Element;
57 import javax.swing.text.Segment;
58 import javax.swing.text.Utilities;
59 import javax.swing.undo.AbstractUndoableEdit;
60 import javax.swing.undo.CannotRedoException;
61 import javax.swing.undo.CannotUndoException;
62 import javax.swing.undo.UndoableEdit;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public class JEditTextArea extends JComponent
95 {
96
97
98
99
100
101 public static String LEFT_OF_SCROLLBAR = "los";
102
103
104
105
106 public JEditTextArea()
107 {
108 this(TextAreaDefaults.getDefaults());
109 }
110
111
112
113
114
115 public JEditTextArea(TextAreaDefaults defaults)
116 {
117 propertyChangeSupport=new PropertyChangeSupport(this);
118
119 enableEvents(AWTEvent.KEY_EVENT_MASK);
120
121
122 painter = new TextAreaPainter(this,defaults);
123 documentHandler = new DocumentHandler();
124 listenerList = new EventListenerList();
125 caretEvent = new MutableCaretEvent();
126 lineSegment = new Segment();
127 bracketLine = bracketPosition = -1;
128 blink = true;
129
130
131 setLayout(new ScrollLayout());
132 add(CENTER,painter);
133 add(RIGHT,vertical = new JScrollBar(JScrollBar.VERTICAL));
134 add(BOTTOM,horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
135
136
137 vertical.addAdjustmentListener(new AdjustHandler());
138 horizontal.addAdjustmentListener(new AdjustHandler());
139 painter.addComponentListener(new ComponentHandler());
140 painter.addMouseListener(new MouseHandler());
141 painter.addMouseMotionListener(new DragHandler());
142 addFocusListener(new FocusHandler());
143
144
145 setInputHandler(defaults.inputHandler);
146 setDocument(defaults.document);
147 editable = defaults.editable;
148 caretVisible = defaults.caretVisible;
149 caretBlinks = defaults.caretBlinks;
150 electricScroll = defaults.electricScroll;
151
152 popup = defaults.popup;
153
154
155 focusedComponent = this;
156 }
157
158
159
160
161
162 public final boolean isFocusable()
163 {
164 return true;
165 }
166
167
168
169
170 public final TextAreaPainter getPainter()
171 {
172 return painter;
173 }
174
175
176
177
178 public final InputHandler getInputHandler()
179 {
180 return inputHandler;
181 }
182
183
184
185
186
187 public void setInputHandler(InputHandler inputHandler)
188 {
189 this.inputHandler = inputHandler;
190 }
191
192
193
194
195 public final boolean isCaretBlinkEnabled()
196 {
197 return caretBlinks;
198 }
199
200
201
202
203
204 public void setCaretBlinkEnabled(boolean caretBlinks)
205 {
206 this.caretBlinks = caretBlinks;
207 if(!caretBlinks)
208 blink = false;
209
210 painter.invalidateSelectedLines();
211 }
212
213
214
215
216 public final boolean isCaretVisible()
217 {
218 return (!caretBlinks || blink) && caretVisible;
219 }
220
221
222
223
224
225
226 public void setCaretVisible(boolean caretVisible)
227 {
228 this.caretVisible = caretVisible;
229 blink = true;
230
231 painter.invalidateSelectedLines();
232 }
233
234
235
236
237 public final void blinkCaret()
238 {
239 if(caretBlinks)
240 {
241 blink = !blink;
242 painter.invalidateSelectedLines();
243 }
244 else
245 blink = true;
246 }
247
248
249
250
251
252 public final int getElectricScroll()
253 {
254 return electricScroll;
255 }
256
257
258
259
260
261
262
263 public final void setElectricScroll(int electricScroll)
264 {
265 this.electricScroll = electricScroll;
266 }
267
268
269
270
271
272
273 public void updateScrollBars()
274 {
275 if(vertical != null && visibleLines != 0)
276 {
277 vertical.setValues(firstLine,visibleLines,0,getLineCount());
278 vertical.setUnitIncrement(2);
279 vertical.setBlockIncrement(visibleLines);
280 }
281
282 int width = painter.getWidth();
283 if(horizontal != null && width != 0)
284 {
285 horizontal.setValues(-horizontalOffset,width,0,width * 5);
286 horizontal.setUnitIncrement(painter.getFontMetrics()
287 .charWidth('w'));
288 horizontal.setBlockIncrement(width / 2);
289 }
290 }
291
292
293
294
295 public final int getFirstLine()
296 {
297 return firstLine;
298 }
299
300
301
302
303
304 public void setFirstLine(int firstLine)
305 {
306 if(firstLine == this.firstLine)
307 return;
308 int oldFirstLine = this.firstLine;
309 this.firstLine = firstLine;
310 if(firstLine != vertical.getValue())
311 updateScrollBars();
312 painter.repaint();
313 }
314
315
316
317
318 public final int getVisibleLines()
319 {
320 return visibleLines;
321 }
322
323
324
325
326
327 public final void recalculateVisibleLines()
328 {
329 if(painter == null)
330 return;
331 int height = painter.getHeight();
332 int lineHeight = painter.getFontMetrics().getHeight();
333 int oldVisibleLines = visibleLines;
334 visibleLines = height / lineHeight;
335 updateScrollBars();
336 }
337
338
339
340
341 public final int getHorizontalOffset()
342 {
343 return horizontalOffset;
344 }
345
346
347
348
349
350
351 public void setHorizontalOffset(int horizontalOffset)
352 {
353 if(horizontalOffset == this.horizontalOffset)
354 return;
355 this.horizontalOffset = horizontalOffset;
356 if(horizontalOffset != horizontal.getValue())
357 updateScrollBars();
358 painter.repaint();
359 }
360
361
362
363
364
365
366
367
368 public boolean setOrigin(int firstLine, int horizontalOffset)
369 {
370 boolean changed = false;
371 int oldFirstLine = this.firstLine;
372
373 if(horizontalOffset != this.horizontalOffset)
374 {
375 this.horizontalOffset = horizontalOffset;
376 changed = true;
377 }
378
379 if(firstLine != this.firstLine)
380 {
381 this.firstLine = firstLine;
382 changed = true;
383 }
384
385 if(changed)
386 {
387 updateScrollBars();
388 painter.repaint();
389 }
390
391 return changed;
392 }
393
394
395
396
397
398
399
400 public boolean scrollToCaret()
401 {
402 int line = getCaretLine();
403 int lineStart = getLineStartOffset(line);
404 int offset = Math.max(0,Math.min(getLineLength(line) - 1,
405 getCaretPosition() - lineStart));
406
407 return scrollTo(line,offset);
408 }
409
410
411
412
413
414
415
416
417
418 public boolean scrollTo(int line, int offset)
419 {
420
421
422
423 if(visibleLines == 0)
424 {
425 setFirstLine(Math.max(0,line - electricScroll));
426 return true;
427 }
428
429 int newFirstLine = firstLine;
430 int newHorizontalOffset = horizontalOffset;
431
432 if(line < firstLine + electricScroll)
433 {
434 newFirstLine = Math.max(0,line - electricScroll);
435 }
436 else if(line + electricScroll >= firstLine + visibleLines)
437 {
438 newFirstLine = (line - visibleLines) + electricScroll + 1;
439 if(newFirstLine + visibleLines >= getLineCount())
440 newFirstLine = getLineCount() - visibleLines;
441 if(newFirstLine < 0)
442 newFirstLine = 0;
443 }
444
445 int x = _offsetToX(line,offset);
446 int width = painter.getFontMetrics().charWidth('w');
447
448 if(x < 0)
449 {
450 newHorizontalOffset = Math.min(0,horizontalOffset
451 - x + width + 5);
452 }
453 else if(x + width >= painter.getWidth())
454 {
455 newHorizontalOffset = horizontalOffset +
456 (painter.getWidth() - x) - width - 5;
457 }
458
459 return setOrigin(newFirstLine,newHorizontalOffset);
460 }
461
462
463
464
465
466 public int lineToY(int line)
467 {
468 FontMetrics fm = painter.getFontMetrics();
469 return (line - firstLine) * fm.getHeight()
470 - (fm.getLeading() + fm.getMaxDescent());
471 }
472 public int lineToBottomY(int line)
473 {
474 FontMetrics fm = painter.getFontMetrics();
475 return (line - firstLine) * fm.getHeight()
476 + (fm.getLeading()+ fm.getAscent()+ fm.getMaxDescent());
477 }
478
479
480
481
482
483 public int yToLine(int y)
484 {
485 FontMetrics fm = painter.getFontMetrics();
486 int height = fm.getHeight();
487 return Math.max(0,Math.min(getLineCount() - 1,
488 y / height + firstLine));
489 }
490
491
492
493
494
495
496
497 public final int offsetToX(int line, int offset)
498 {
499
500 painter.currentLineTokens = null;
501 return _offsetToX(line,offset);
502 }
503
504
505
506
507
508
509
510
511 public int _offsetToX(int line, int offset)
512 {
513 TokenMarker tokenMarker = getTokenMarker();
514
515
516 FontMetrics fm = painter.getFontMetrics();
517
518 getLineText(line,lineSegment);
519
520 int segmentOffset = lineSegment.offset;
521 int x = horizontalOffset;
522
523
524 if(tokenMarker == null)
525 {
526 lineSegment.count = offset;
527 return x + Utilities.getTabbedTextWidth(lineSegment,
528 fm,x,painter,0);
529 }
530
531
532 else
533 {
534 Token tokens;
535 if(painter.currentLineIndex == line
536 && painter.currentLineTokens != null)
537 tokens = painter.currentLineTokens;
538 else
539 {
540 painter.currentLineIndex = line;
541 tokens = painter.currentLineTokens
542 = tokenMarker.markTokens(lineSegment,line);
543 }
544
545 Toolkit toolkit = painter.getToolkit();
546 Font defaultFont = painter.getFont();
547 SyntaxStyle[] styles = painter.getStyles();
548
549 for(;;)
550 {
551 byte id = tokens.id;
552 if(id == Token.END)
553 {
554 return x;
555 }
556
557 if(id == Token.NULL)
558 fm = painter.getFontMetrics();
559 else
560 fm = styles[id].getFontMetrics(defaultFont);
561
562 int length = tokens.length;
563
564 if(offset + segmentOffset < lineSegment.offset + length)
565 {
566 lineSegment.count = offset - (lineSegment.offset - segmentOffset);
567 return x + Utilities.getTabbedTextWidth(
568 lineSegment,fm,x,painter,0);
569 }
570 else
571 {
572 lineSegment.count = length;
573 x += Utilities.getTabbedTextWidth(
574 lineSegment,fm,x,painter,0);
575 lineSegment.offset += length;
576 }
577 tokens = tokens.next;
578 }
579 }
580 }
581
582
583
584
585
586
587 public int xToOffset(int line, int x)
588 {
589 TokenMarker tokenMarker = getTokenMarker();
590
591
592 FontMetrics fm = painter.getFontMetrics();
593
594 getLineText(line,lineSegment);
595
596 char[] segmentArray = lineSegment.array;
597 int segmentOffset = lineSegment.offset;
598 int segmentCount = lineSegment.count;
599
600 int width = horizontalOffset;
601
602 if(tokenMarker == null)
603 {
604 for(int i = 0; i < segmentCount; i++)
605 {
606 char c = segmentArray[i + segmentOffset];
607 int charWidth;
608 if(c == '\t')
609 charWidth = (int)painter.nextTabStop(width,i)
610 - width;
611 else
612 charWidth = fm.charWidth(c);
613
614 if(painter.isBlockCaretEnabled())
615 {
616 if(x - charWidth <= width)
617 return i;
618 }
619 else
620 {
621 if(x - charWidth / 2 <= width)
622 return i;
623 }
624
625 width += charWidth;
626 }
627
628 return segmentCount;
629 }
630 else
631 {
632 Token tokens;
633 if(painter.currentLineIndex == line && painter
634 .currentLineTokens != null)
635 tokens = painter.currentLineTokens;
636 else
637 {
638 painter.currentLineIndex = line;
639 tokens = painter.currentLineTokens
640 = tokenMarker.markTokens(lineSegment,line);
641 }
642
643 int offset = 0;
644 Toolkit toolkit = painter.getToolkit();
645 Font defaultFont = painter.getFont();
646 SyntaxStyle[] styles = painter.getStyles();
647
648 for(;;)
649 {
650 byte id = tokens.id;
651 if(id == Token.END)
652 return offset;
653
654 if(id == Token.NULL)
655 fm = painter.getFontMetrics();
656 else
657 fm = styles[id].getFontMetrics(defaultFont);
658
659 int length = tokens.length;
660
661 for(int i = 0; i < length; i++)
662 {
663 char c = segmentArray[segmentOffset + offset + i];
664 int charWidth;
665 if(c == '\t')
666 charWidth = (int)painter.nextTabStop(width,offset + i)
667 - width;
668 else
669 charWidth = fm.charWidth(c);
670
671 if(painter.isBlockCaretEnabled())
672 {
673 if(x - charWidth <= width)
674 return offset + i;
675 }
676 else
677 {
678 if(x - charWidth / 2 <= width)
679 return offset + i;
680 }
681
682 width += charWidth;
683 }
684
685 offset += length;
686 tokens = tokens.next;
687 }
688 }
689 }
690
691
692
693
694
695
696 public int xyToOffset(int x, int y)
697 {
698 int line = yToLine(y);
699 int start = getLineStartOffset(line);
700 return start + xToOffset(line,x);
701 }
702
703
704
705
706 public final SyntaxDocument getDocument()
707 {
708 return document;
709 }
710
711
712
713
714
715 public void setDocument(SyntaxDocument document)
716 {
717 if(this.document == document)
718 return;
719 if(this.document != null)
720 this.document.removeDocumentListener(documentHandler);
721 this.document = document;
722
723 document.addDocumentListener(documentHandler);
724
725 select(0,0);
726 updateScrollBars();
727 painter.repaint();
728 }
729
730
731
732
733
734 public final TokenMarker getTokenMarker()
735 {
736 return document.getTokenMarker();
737 }
738
739
740
741
742
743
744 public final void setTokenMarker(TokenMarker tokenMarker)
745 {
746 document.setTokenMarker(tokenMarker);
747 }
748
749
750
751
752
753 public final int getDocumentLength()
754 {
755 return document.getLength();
756 }
757
758
759
760
761 public final int getLineCount()
762 {
763 return document.getDefaultRootElement().getElementCount();
764 }
765
766
767
768
769
770 public final int getLineOfOffset(int offset)
771 {
772 return document.getDefaultRootElement().getElementIndex(offset);
773 }
774
775
776
777
778
779
780
781 public int getLineStartOffset(int line)
782 {
783 Element lineElement = document.getDefaultRootElement()
784 .getElement(line);
785 if(lineElement == null)
786 return -1;
787 else
788 return lineElement.getStartOffset();
789 }
790
791
792
793
794
795
796
797 public int getLineEndOffset(int line)
798 {
799 Element lineElement = document.getDefaultRootElement()
800 .getElement(line);
801 if(lineElement == null)
802 return -1;
803 else
804 return lineElement.getEndOffset();
805 }
806
807
808
809
810
811 public int getLineLength(int line)
812 {
813 Element lineElement = document.getDefaultRootElement()
814 .getElement(line);
815 if(lineElement == null)
816 return -1;
817 else
818 return lineElement.getEndOffset()
819 - lineElement.getStartOffset() - 1;
820 }
821
822
823
824
825 public String getText()
826 {
827 try
828 {
829 return document.getText(0,document.getLength());
830 }
831 catch(BadLocationException bl)
832 {
833 bl.printStackTrace();
834 return null;
835 }
836 }
837
838
839
840
841 public void setText(String text)
842 {
843 try
844 {
845 document.beginCompoundEdit();
846 document.remove(0,document.getLength());
847 document.insertString(0,text,null);
848 }
849 catch(BadLocationException bl)
850 {
851 bl.printStackTrace();
852 }
853 finally
854 {
855 document.endCompoundEdit();
856 }
857 }
858
859
860
861
862
863
864
865 public final String getText(int start, int len)
866 {
867 try
868 {
869 return document.getText(start,len);
870 }
871 catch(BadLocationException bl)
872 {
873 bl.printStackTrace();
874 return null;
875 }
876 }
877
878
879
880
881
882
883
884
885 public final void getText(int start, int len, Segment segment)
886 {
887 try
888 {
889 document.getText(start,len,segment);
890 }
891 catch(BadLocationException bl)
892 {
893 bl.printStackTrace();
894 segment.offset = segment.count = 0;
895 }
896 }
897
898
899
900
901
902
903 public final String getLineText(int lineIndex)
904 {
905 int start = getLineStartOffset(lineIndex);
906 return getText(start,getLineEndOffset(lineIndex) - start - 1);
907 }
908
909
910
911
912
913
914 public final void getLineText(int lineIndex, Segment segment)
915 {
916 int start = getLineStartOffset(lineIndex);
917 getText(start,getLineEndOffset(lineIndex) - start - 1,segment);
918 }
919
920
921
922
923 public final int getSelectionStart()
924 {
925 return selectionStart;
926 }
927
928
929
930
931
932 public int getSelectionStart(int line)
933 {
934 if(line == selectionStartLine)
935 return selectionStart;
936 else if(rectSelect)
937 {
938 Element map = document.getDefaultRootElement();
939 int start = selectionStart - map.getElement(selectionStartLine)
940 .getStartOffset();
941
942 Element lineElement = map.getElement(line);
943 int lineStart = lineElement.getStartOffset();
944 int lineEnd = lineElement.getEndOffset() - 1;
945 return Math.min(lineEnd,lineStart + start);
946 }
947 else
948 return getLineStartOffset(line);
949 }
950
951
952
953
954 public final int getSelectionStartLine()
955 {
956 return selectionStartLine;
957 }
958
959
960
961
962
963
964
965 public final void setSelectionStart(int selectionStart)
966 {
967 select(selectionStart,selectionEnd);
968 }
969
970
971
972
973 public final int getSelectionEnd()
974 {
975 return selectionEnd;
976 }
977
978
979
980
981
982 public int getSelectionEnd(int line)
983 {
984 if(line == selectionEndLine)
985 return selectionEnd;
986 else if(rectSelect)
987 {
988 Element map = document.getDefaultRootElement();
989 int end = selectionEnd - map.getElement(selectionEndLine)
990 .getStartOffset();
991
992 Element lineElement = map.getElement(line);
993 int lineStart = lineElement.getStartOffset();
994 int lineEnd = lineElement.getEndOffset() - 1;
995 return Math.min(lineEnd,lineStart + end);
996 }
997 else
998 return getLineEndOffset(line) - 1;
999 }
1000
1001
1002
1003
1004 public final int getSelectionEndLine()
1005 {
1006 return selectionEndLine;
1007 }
1008
1009
1010
1011
1012
1013
1014
1015 public final void setSelectionEnd(int selectionEnd)
1016 {
1017 select(selectionStart,selectionEnd);
1018 }
1019
1020
1021
1022
1023
1024
1025 public final int getCaretPosition()
1026 {
1027 return (biasLeft ? selectionStart : selectionEnd);
1028 }
1029
1030
1031
1032
1033 public final int getCaretLine()
1034 {
1035 return (biasLeft ? selectionStartLine : selectionEndLine);
1036 }
1037
1038
1039
1040
1041
1042
1043 public final int getMarkPosition()
1044 {
1045 return (biasLeft ? selectionEnd : selectionStart);
1046 }
1047
1048
1049
1050
1051 public final int getMarkLine()
1052 {
1053 return (biasLeft ? selectionEndLine : selectionStartLine);
1054 }
1055
1056
1057
1058
1059
1060
1061
1062 public final void setCaretPosition(int caret)
1063 {
1064 select(caret,caret);
1065 }
1066
1067
1068
1069
1070 public final void selectAll()
1071 {
1072 select(0,getDocumentLength());
1073 }
1074
1075
1076
1077
1078 public final void selectNone()
1079 {
1080 select(getCaretPosition(),getCaretPosition());
1081 }
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 public void select(int start, int end)
1092 {
1093 int newStart, newEnd;
1094 boolean newBias;
1095 if(start <= end)
1096 {
1097 newStart = start;
1098 newEnd = end;
1099 newBias = false;
1100 }
1101 else
1102 {
1103 newStart = end;
1104 newEnd = start;
1105 newBias = true;
1106 }
1107
1108 if(newStart < 0 || newEnd > getDocumentLength())
1109 {
1110 throw new IllegalArgumentException("Bounds out of"
1111 + " range: " + newStart + "," +
1112 newEnd);
1113 }
1114
1115
1116
1117
1118 if(newStart != selectionStart || newEnd != selectionEnd
1119 || newBias != biasLeft)
1120 {
1121 int newStartLine = getLineOfOffset(newStart);
1122 int newEndLine = getLineOfOffset(newEnd);
1123
1124 if(painter.isBracketHighlightEnabled())
1125 {
1126 if(bracketLine != -1)
1127 painter.invalidateLine(bracketLine);
1128 updateBracketHighlight(end);
1129 if(bracketLine != -1)
1130 painter.invalidateLine(bracketLine);
1131 }
1132
1133 painter.invalidateLineRange(selectionStartLine,selectionEndLine);
1134 painter.invalidateLineRange(newStartLine,newEndLine);
1135
1136 document.addUndoableEdit(new CaretUndo(
1137 selectionStart,selectionEnd));
1138
1139 selectionStart = newStart;
1140 selectionEnd = newEnd;
1141 selectionStartLine = newStartLine;
1142 selectionEndLine = newEndLine;
1143 biasLeft = newBias;
1144
1145 fireCaretEvent();
1146 }
1147
1148
1149
1150 blink = true;
1151 caretTimer.restart();
1152
1153
1154 if(selectionStart == selectionEnd)
1155 rectSelect = false;
1156
1157
1158 magicCaret = -1;
1159
1160 scrollToCaret();
1161 }
1162
1163
1164
1165
1166 public final String getSelectedText()
1167 {
1168 if(selectionStart == selectionEnd)
1169 return null;
1170
1171 if(rectSelect)
1172 {
1173
1174
1175 Element map = document.getDefaultRootElement();
1176
1177 int start = selectionStart - map.getElement(selectionStartLine)
1178 .getStartOffset();
1179 int end = selectionEnd - map.getElement(selectionEndLine)
1180 .getStartOffset();
1181
1182
1183 if(end < start)
1184 {
1185 int tmp = end;
1186 end = start;
1187 start = tmp;
1188 }
1189
1190 StringBuffer buf = new StringBuffer();
1191 Segment seg = new Segment();
1192
1193 for(int i = selectionStartLine; i <= selectionEndLine; i++)
1194 {
1195 Element lineElement = map.getElement(i);
1196 int lineStart = lineElement.getStartOffset();
1197 int lineEnd = lineElement.getEndOffset() - 1;
1198 int lineLen = lineEnd - lineStart;
1199
1200 lineStart = Math.min(lineStart + start,lineEnd);
1201 lineLen = Math.min(end - start,lineEnd - lineStart);
1202
1203 getText(lineStart,lineLen,seg);
1204 buf.append(seg.array,seg.offset,seg.count);
1205
1206 if(i != selectionEndLine)
1207 buf.append('\n');
1208 }
1209
1210 return buf.toString();
1211 }
1212 else
1213 {
1214 return getText(selectionStart,
1215 selectionEnd - selectionStart);
1216 }
1217 }
1218
1219
1220
1221
1222
1223 public void setSelectedText(String selectedText)
1224 {
1225 if(!editable)
1226 {
1227 throw new InternalError("Text component"
1228 + " read only");
1229 }
1230
1231 document.beginCompoundEdit();
1232
1233 try
1234 {
1235 if(rectSelect)
1236 {
1237 Element map = document.getDefaultRootElement();
1238
1239 int start = selectionStart - map.getElement(selectionStartLine)
1240 .getStartOffset();
1241 int end = selectionEnd - map.getElement(selectionEndLine)
1242 .getStartOffset();
1243
1244
1245 if(end < start)
1246 {
1247 int tmp = end;
1248 end = start;
1249 start = tmp;
1250 }
1251
1252 int lastNewline = 0;
1253 int currNewline = 0;
1254
1255 for(int i = selectionStartLine; i <= selectionEndLine; i++)
1256 {
1257 Element lineElement = map.getElement(i);
1258 int lineStart = lineElement.getStartOffset();
1259 int lineEnd = lineElement.getEndOffset() - 1;
1260 int rectStart = Math.min(lineEnd,lineStart + start);
1261
1262 document.remove(rectStart,Math.min(lineEnd - rectStart,
1263 end - start));
1264
1265 if(selectedText == null)
1266 continue;
1267
1268 currNewline = selectedText.indexOf('\n',lastNewline);
1269 if(currNewline == -1)
1270 currNewline = selectedText.length();
1271
1272 document.insertString(rectStart,selectedText
1273 .substring(lastNewline,currNewline),null);
1274
1275 lastNewline = Math.min(selectedText.length(),
1276 currNewline + 1);
1277 }
1278
1279 if(selectedText != null &&
1280 currNewline != selectedText.length())
1281 {
1282 int offset = map.getElement(selectionEndLine)
1283 .getEndOffset() - 1;
1284 document.insertString(offset,"\n",null);
1285 document.insertString(offset + 1,selectedText
1286 .substring(currNewline + 1),null);
1287 }
1288 }
1289 else
1290 {
1291 document.remove(selectionStart,
1292 selectionEnd - selectionStart);
1293 if(selectedText != null)
1294 {
1295 document.insertString(selectionStart,
1296 selectedText,null);
1297 }
1298 }
1299 }
1300 catch(BadLocationException bl)
1301 {
1302 bl.printStackTrace();
1303 throw new InternalError("Cannot replace"
1304 + " selection");
1305 }
1306
1307
1308 finally
1309 {
1310 document.endCompoundEdit();
1311 }
1312
1313 setCaretPosition(selectionEnd);
1314 }
1315
1316
1317
1318
1319 public final boolean isEditable()
1320 {
1321 return editable;
1322 }
1323
1324
1325
1326
1327
1328
1329 public final void setEditable(boolean editable)
1330 {
1331 this.editable = editable;
1332 }
1333
1334
1335
1336
1337 public final JPopupMenu getRightClickPopup()
1338 {
1339 return popup;
1340 }
1341
1342
1343
1344
1345
1346 public final void setRightClickPopup(JPopupMenu popup)
1347 {
1348 this.popup = popup;
1349 }
1350
1351
1352
1353
1354
1355 public final int getMagicCaretPosition()
1356 {
1357 return magicCaret;
1358 }
1359
1360
1361
1362
1363
1364
1365 public final void setMagicCaretPosition(int magicCaret)
1366 {
1367 this.magicCaret = magicCaret;
1368 }
1369
1370
1371
1372
1373
1374
1375
1376
1377 public void overwriteSetSelectedText(String str)
1378 {
1379
1380 if(!overwrite || selectionStart != selectionEnd)
1381 {
1382 setSelectedText(str);
1383 return;
1384 }
1385
1386
1387
1388 int caret = getCaretPosition();
1389 int caretLineEnd = getLineEndOffset(getCaretLine());
1390 if(caretLineEnd - caret <= str.length())
1391 {
1392 setSelectedText(str);
1393 return;
1394 }
1395
1396 document.beginCompoundEdit();
1397
1398 try
1399 {
1400 document.remove(caret,str.length());
1401 document.insertString(caret,str,null);
1402 }
1403 catch(BadLocationException bl)
1404 {
1405 bl.printStackTrace();
1406 }
1407 finally
1408 {
1409 document.endCompoundEdit();
1410 }
1411 }
1412
1413
1414
1415
1416 public final boolean isOverwriteEnabled()
1417 {
1418 return overwrite;
1419 }
1420
1421
1422
1423
1424
1425
1426 public final void setOverwriteEnabled(boolean overwrite)
1427 {
1428 this.overwrite = overwrite;
1429 painter.invalidateSelectedLines();
1430 }
1431
1432
1433
1434
1435 public final boolean isSelectionRectangular()
1436 {
1437 return rectSelect;
1438 }
1439
1440
1441
1442
1443
1444
1445 public final void setSelectionRectangular(boolean rectSelect)
1446 {
1447 this.rectSelect = rectSelect;
1448 painter.invalidateSelectedLines();
1449 }
1450
1451
1452
1453
1454
1455 public final int getBracketPosition()
1456 {
1457 return bracketPosition;
1458 }
1459
1460
1461
1462
1463
1464 public final int getBracketLine()
1465 {
1466 return bracketLine;
1467 }
1468
1469
1470
1471
1472
1473 public final void addCaretListener(CaretListener listener)
1474 {
1475 listenerList.add(CaretListener.class,listener);
1476 }
1477
1478
1479
1480
1481
1482 public final void removeCaretListener(CaretListener listener)
1483 {
1484 listenerList.remove(CaretListener.class,listener);
1485 }
1486
1487
1488
1489
1490
1491 public void cut()
1492 {
1493 if(editable)
1494 {
1495 copy();
1496 setSelectedText("");
1497 }
1498 }
1499
1500
1501
1502
1503 public void copy()
1504 {
1505 if(selectionStart != selectionEnd)
1506 {
1507 Clipboard clipboard = getToolkit().getSystemClipboard();
1508
1509 String selection = getSelectedText();
1510
1511 int repeatCount = inputHandler.getRepeatCount();
1512 StringBuffer buf = new StringBuffer();
1513 for(int i = 0; i < repeatCount; i++)
1514 buf.append(selection);
1515
1516 clipboard.setContents(new StringSelection(buf.toString()),null);
1517 }
1518 }
1519
1520
1521
1522
1523 public void paste()
1524 {
1525 if(editable)
1526 {
1527 Clipboard clipboard = getToolkit().getSystemClipboard();
1528 try
1529 {
1530
1531
1532 String selection = ((String)clipboard
1533 .getContents(this).getTransferData(
1534 DataFlavor.stringFlavor))
1535 .replace('\r','\n');
1536
1537 int repeatCount = inputHandler.getRepeatCount();
1538 StringBuffer buf = new StringBuffer();
1539 for(int i = 0; i < repeatCount; i++)
1540 buf.append(selection);
1541 selection = buf.toString();
1542 setSelectedText(selection);
1543 }
1544 catch(Exception e)
1545 {
1546 getToolkit().beep();
1547 System.err.println("Clipboard does not"
1548 + " contain a string");
1549 }
1550 }
1551 }
1552
1553
1554
1555
1556
1557 public void removeNotify()
1558 {
1559 super.removeNotify();
1560 if(focusedComponent == this)
1561 focusedComponent = null;
1562 }
1563
1564
1565
1566
1567
1568
1569 public void processKeyEvent(KeyEvent evt)
1570 {
1571 if(inputHandler == null)
1572 return;
1573 switch(evt.getID())
1574 {
1575 case KeyEvent.KEY_TYPED:
1576 inputHandler.keyTyped(evt);
1577 break;
1578 case KeyEvent.KEY_PRESSED:
1579 inputHandler.keyPressed(evt);
1580 break;
1581 case KeyEvent.KEY_RELEASED:
1582 inputHandler.keyReleased(evt);
1583 break;
1584 }
1585 if (inputMap==null) inputMap=getInputMap();
1586 Object o=inputMap.get(KeyStroke.getKeyStrokeForEvent(evt));
1587 if (o!=null) {
1588 if (actionMap==null) actionMap=getActionMap();
1589 Object a=actionMap.get(o);
1590
1591 if (a!=null) ((Action)a).actionPerformed(new ActionEvent(this,ActionEvent.ACTION_PERFORMED,o.toString(),evt.getModifiers()));
1592 }
1593
1594 }
1595 InputMap inputMap;
1596 ActionMap actionMap;
1597
1598
1599
1600
1601
1602
1603
1604 protected static String CENTER = "center";
1605 protected static String RIGHT = "right";
1606 protected static String BOTTOM = "bottom";
1607
1608 protected static JEditTextArea focusedComponent;
1609 protected static Timer caretTimer;
1610
1611 protected TextAreaPainter painter;
1612
1613 protected JPopupMenu popup;
1614
1615 protected EventListenerList listenerList;
1616 protected MutableCaretEvent caretEvent;
1617
1618 protected boolean caretBlinks;
1619 protected boolean caretVisible;
1620 protected boolean blink;
1621
1622 protected boolean editable;
1623
1624 protected int firstLine;
1625 protected int visibleLines;
1626 protected int electricScroll;
1627
1628 protected int horizontalOffset;
1629
1630 protected JScrollBar vertical;
1631 protected JScrollBar horizontal;
1632 protected boolean scrollBarsInitialized;
1633
1634 protected InputHandler inputHandler;
1635 protected SyntaxDocument document;
1636 protected DocumentHandler documentHandler;
1637
1638 protected Segment lineSegment;
1639
1640 protected int selectionStart;
1641 protected int selectionStartLine;
1642 protected int selectionEnd;
1643 protected int selectionEndLine;
1644 protected boolean biasLeft;
1645
1646 protected int bracketPosition;
1647 protected int bracketLine;
1648
1649 protected int magicCaret;
1650 protected boolean overwrite;
1651 protected boolean rectSelect;
1652
1653 protected void fireCaretEvent()
1654 {
1655 Object[] listeners = listenerList.getListenerList();
1656 for(int i = listeners.length - 2; i >= 0; i--)
1657 {
1658 if(listeners[i] == CaretListener.class)
1659 {
1660 ((CaretListener)listeners[i+1]).caretUpdate(caretEvent);
1661 }
1662 }
1663 }
1664
1665 protected void updateBracketHighlight(int newCaretPosition)
1666 {
1667 if(newCaretPosition == 0)
1668 {
1669 bracketPosition = bracketLine = -1;
1670 return;
1671 }
1672
1673 try
1674 {
1675 int offset = TextUtilities.findMatchingBracket(
1676 document,newCaretPosition - 1);
1677 if(offset != -1)
1678 {
1679 bracketLine = getLineOfOffset(offset);
1680 bracketPosition = offset - getLineStartOffset(bracketLine);
1681 return;
1682 }
1683 }
1684 catch(BadLocationException bl)
1685 {
1686 bl.printStackTrace();
1687 }
1688
1689 bracketLine = bracketPosition = -1;
1690 }
1691
1692 protected void documentChanged(DocumentEvent evt)
1693 {
1694 DocumentEvent.ElementChange ch = evt.getChange(
1695 document.getDefaultRootElement());
1696
1697 int count;
1698 if(ch == null)
1699 count = 0;
1700 else
1701 count = ch.getChildrenAdded().length -
1702 ch.getChildrenRemoved().length;
1703
1704 int line = getLineOfOffset(evt.getOffset());
1705 if(count == 0)
1706 {
1707 painter.invalidateLine(line);
1708 }
1709
1710 else if(line < firstLine)
1711 {
1712 setFirstLine(firstLine + count);
1713 }
1714
1715 else
1716 {
1717 painter.invalidateLineRange(line,firstLine + visibleLines);
1718 updateScrollBars();
1719 }
1720 propertyChangeSupport.firePropertyChange(DOCUMENT_PROPERTY,null,null);
1721 }
1722 public static final String DOCUMENT_PROPERTY="doc";
1723 PropertyChangeSupport propertyChangeSupport;
1724 public void addDocumentChangeListener(PropertyChangeListener l) {
1725 propertyChangeSupport.addPropertyChangeListener(DOCUMENT_PROPERTY,l);
1726 }
1727 class ScrollLayout implements LayoutManager
1728 {
1729 public void addLayoutComponent(String name, Component comp)
1730 {
1731 if(name.equals(CENTER))
1732 center = comp;
1733 else if(name.equals(RIGHT))
1734 right = comp;
1735 else if(name.equals(BOTTOM))
1736 bottom = comp;
1737 else if(name.equals(LEFT_OF_SCROLLBAR))
1738 leftOfScrollBar.addElement(comp);
1739 }
1740
1741 public void removeLayoutComponent(Component comp)
1742 {
1743 if(center == comp)
1744 center = null;
1745 if(right == comp)
1746 right = null;
1747 if(bottom == comp)
1748 bottom = null;
1749 else
1750 leftOfScrollBar.removeElement(comp);
1751 }
1752
1753 public Dimension preferredLayoutSize(Container parent)
1754 {
1755 Dimension dim = new Dimension();
1756 Insets insets = getInsets();
1757 dim.width = insets.left + insets.right;
1758 dim.height = insets.top + insets.bottom;
1759
1760 Dimension centerPref = center.getPreferredSize();
1761 dim.width += centerPref.width;
1762 dim.height += centerPref.height;
1763 Dimension rightPref = right.getPreferredSize();
1764 dim.width += rightPref.width;
1765 Dimension bottomPref = bottom.getPreferredSize();
1766 dim.height += bottomPref.height;
1767
1768 return dim;
1769 }
1770
1771 public Dimension minimumLayoutSize(Container parent)
1772 {
1773 Dimension dim = new Dimension();
1774 Insets insets = getInsets();
1775 dim.width = insets.left + insets.right;
1776 dim.height = insets.top + insets.bottom;
1777
1778 Dimension centerPref = center.getMinimumSize();
1779 dim.width += centerPref.width;
1780 dim.height += centerPref.height;
1781 Dimension rightPref = right.getMinimumSize();
1782 dim.width += rightPref.width;
1783 Dimension bottomPref = bottom.getMinimumSize();
1784 dim.height += bottomPref.height;
1785
1786 return dim;
1787 }
1788
1789 public void layoutContainer(Container parent)
1790 {
1791 Dimension size = parent.getSize();
1792 Insets insets = parent.getInsets();
1793 int itop = insets.top;
1794 int ileft = insets.left;
1795 int ibottom = insets.bottom;
1796 int iright = insets.right;
1797
1798 int rightWidth = right.getPreferredSize().width;
1799 int bottomHeight = bottom.getPreferredSize().height;
1800 int centerWidth = size.width - rightWidth - ileft - iright;
1801 int centerHeight = size.height - bottomHeight - itop - ibottom;
1802
1803 center.setBounds(
1804 ileft,
1805 itop,
1806 centerWidth,
1807 centerHeight);
1808
1809 right.setBounds(
1810 ileft + centerWidth,
1811 itop,
1812 rightWidth,
1813 centerHeight);
1814
1815
1816 Enumeration status = leftOfScrollBar.elements();
1817 while(status.hasMoreElements())
1818 {
1819 Component comp = (Component)status.nextElement();
1820 Dimension dim = comp.getPreferredSize();
1821 comp.setBounds(ileft,
1822 itop + centerHeight,
1823 dim.width,
1824 bottomHeight);
1825 ileft += dim.width;
1826 }
1827
1828 bottom.setBounds(
1829 ileft,
1830 itop + centerHeight,
1831 size.width - rightWidth - ileft - iright,
1832 bottomHeight);
1833 }
1834
1835
1836 private Component center;
1837 private Component right;
1838 private Component bottom;
1839 private Vector leftOfScrollBar = new Vector();
1840 }
1841
1842 static class CaretBlinker implements ActionListener
1843 {
1844 public void actionPerformed(ActionEvent evt)
1845 {
1846 if(focusedComponent != null
1847 && focusedComponent.hasFocus())
1848 focusedComponent.blinkCaret();
1849 }
1850 }
1851
1852 class MutableCaretEvent extends CaretEvent
1853 {
1854 MutableCaretEvent()
1855 {
1856 super(JEditTextArea.this);
1857 }
1858
1859 public int getDot()
1860 {
1861 return getCaretPosition();
1862 }
1863
1864 public int getMark()
1865 {
1866 return getMarkPosition();
1867 }
1868 }
1869
1870 class AdjustHandler implements AdjustmentListener
1871 {
1872 public void adjustmentValueChanged(final AdjustmentEvent evt)
1873 {
1874 if(!scrollBarsInitialized)
1875 return;
1876
1877
1878
1879
1880 SwingUtilities.invokeLater(new Runnable() {
1881 public void run()
1882 {
1883 if(evt.getAdjustable() == vertical)
1884 setFirstLine(vertical.getValue());
1885 else
1886 setHorizontalOffset(-horizontal.getValue());
1887 }
1888 });
1889 }
1890 }
1891
1892 class ComponentHandler extends ComponentAdapter
1893 {
1894 public void componentResized(ComponentEvent evt)
1895 {
1896 recalculateVisibleLines();
1897 scrollBarsInitialized = true;
1898 }
1899 }
1900
1901 class DocumentHandler implements DocumentListener
1902 {
1903 public void insertUpdate(DocumentEvent evt)
1904 {
1905 documentChanged(evt);
1906
1907 int offset = evt.getOffset();
1908 int length = evt.getLength();
1909
1910 int newStart;
1911 int newEnd;
1912
1913 if(selectionStart > offset || (selectionStart
1914 == selectionEnd && selectionStart == offset))
1915 newStart = selectionStart + length;
1916 else
1917 newStart = selectionStart;
1918
1919 if(selectionEnd >= offset)
1920 newEnd = selectionEnd + length;
1921 else
1922 newEnd = selectionEnd;
1923
1924 select(newStart,newEnd);
1925 }
1926
1927 public void removeUpdate(DocumentEvent evt)
1928 {
1929 documentChanged(evt);
1930
1931 int offset = evt.getOffset();
1932 int length = evt.getLength();
1933
1934 int newStart;
1935 int newEnd;
1936
1937 if(selectionStart > offset)
1938 {
1939 if(selectionStart > offset + length)
1940 newStart = selectionStart - length;
1941 else
1942 newStart = offset;
1943 }
1944 else
1945 newStart = selectionStart;
1946
1947 if(selectionEnd > offset)
1948 {
1949 if(selectionEnd > offset + length)
1950 newEnd = selectionEnd - length;
1951 else
1952 newEnd = offset;
1953 }
1954 else
1955 newEnd = selectionEnd;
1956
1957 select(newStart,newEnd);
1958 }
1959
1960 public void changedUpdate(DocumentEvent evt)
1961 {
1962 JOptionPane.showMessageDialog(null, evt.getType()+ "");
1963 }
1964 }
1965
1966 class DragHandler implements MouseMotionListener
1967 {
1968 public void mouseDragged(MouseEvent evt)
1969 {
1970 if(popup != null && popup.isVisible())
1971 return;
1972
1973 setSelectionRectangular((evt.getModifiers()
1974 & InputEvent.CTRL_MASK) != 0);
1975 select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
1976 }
1977
1978 public void mouseMoved(MouseEvent evt) {}
1979 }
1980
1981 class FocusHandler implements FocusListener
1982 {
1983 public void focusGained(FocusEvent evt)
1984 {
1985 setCaretVisible(true);
1986 focusedComponent = JEditTextArea.this;
1987 }
1988
1989 public void focusLost(FocusEvent evt)
1990 {
1991 setCaretVisible(false);
1992 focusedComponent = null;
1993 }
1994 }
1995
1996 class MouseHandler extends MouseAdapter
1997 {
1998 public void mousePressed(MouseEvent evt)
1999 {
2000 requestFocus();
2001
2002
2003 setCaretVisible(true);
2004 focusedComponent = JEditTextArea.this;
2005
2006 if((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0
2007 && popup != null)
2008 {
2009 popup.show(painter,evt.getX(),evt.getY());
2010 return;
2011 }
2012
2013 int line = yToLine(evt.getY());
2014 int offset = xToOffset(line,evt.getX());
2015 int dot = getLineStartOffset(line) + offset;
2016
2017 switch(evt.getClickCount())
2018 {
2019 case 1:
2020 doSingleClick(evt,line,offset,dot);
2021 break;
2022 case 2:
2023
2024
2025 try
2026 {
2027 doDoubleClick(evt,line,offset,dot);
2028 }
2029 catch(BadLocationException bl)
2030 {
2031 bl.printStackTrace();
2032 }
2033 break;
2034 case 3:
2035 doTripleClick(evt,line,offset,dot);
2036 break;
2037 }
2038 }
2039
2040 private void doSingleClick(MouseEvent evt, int line,
2041 int offset, int dot)
2042 {
2043 if((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0)
2044 {
2045 rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
2046 select(getMarkPosition(),dot);
2047 }
2048 else
2049 setCaretPosition(dot);
2050 }
2051
2052 private void doDoubleClick(MouseEvent evt, int line,
2053 int offset, int dot) throws BadLocationException
2054 {
2055
2056 if(getLineLength(line) == 0)
2057 return;
2058
2059 try
2060 {
2061 int bracket = TextUtilities.findMatchingBracket(
2062 document,Math.max(0,dot - 1));
2063 if(bracket != -1)
2064 {
2065 int mark = getMarkPosition();
2066
2067 if(bracket > mark)
2068 {
2069 bracket++;
2070 mark--;
2071 }
2072 select(mark,bracket);
2073 return;
2074 }
2075 }
2076 catch(BadLocationException bl)
2077 {
2078 bl.printStackTrace();
2079 }
2080
2081
2082 String lineText = getLineText(line);
2083 char ch = lineText.charAt(Math.max(0,offset - 1));
2084
2085 String noWordSep = (String)document.getProperty("noWordSep");
2086 if(noWordSep == null)
2087 noWordSep = "";
2088
2089
2090
2091 boolean selectNoLetter = (!Character
2092 .isLetterOrDigit(ch)
2093 && noWordSep.indexOf(ch) == -1);
2094
2095 int wordStart = 0;
2096
2097 for(int i = offset - 1; i >= 0; i--)
2098 {
2099 ch = lineText.charAt(i);
2100 if(selectNoLetter ^ (!Character
2101 .isLetterOrDigit(ch) &&
2102 noWordSep.indexOf(ch) == -1))
2103 {
2104 wordStart = i + 1;
2105 break;
2106 }
2107 }
2108
2109 int wordEnd = lineText.length();
2110 for(int i = offset; i < lineText.length(); i++)
2111 {
2112 ch = lineText.charAt(i);
2113 if(selectNoLetter ^ (!Character
2114 .isLetterOrDigit(ch) &&
2115 noWordSep.indexOf(ch) == -1))
2116 {
2117 wordEnd = i;
2118 break;
2119 }
2120 }
2121
2122 int lineStart = getLineStartOffset(line);
2123 select(lineStart + wordStart,lineStart + wordEnd);
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134 }
2135
2136 private void doTripleClick(MouseEvent evt, int line,
2137 int offset, int dot)
2138 {
2139 select(getLineStartOffset(line),getLineEndOffset(line)-1);
2140 }
2141 }
2142
2143 class CaretUndo extends AbstractUndoableEdit
2144 {
2145 private int start;
2146 private int end;
2147
2148 CaretUndo(int start, int end)
2149 {
2150 this.start = start;
2151 this.end = end;
2152 }
2153
2154 public boolean isSignificant()
2155 {
2156 return false;
2157 }
2158
2159 public String getPresentationName()
2160 {
2161 return "caret move";
2162 }
2163
2164 public void undo() throws CannotUndoException
2165 {
2166 super.undo();
2167
2168 select(start,end);
2169 }
2170
2171 public void redo() throws CannotRedoException
2172 {
2173 super.redo();
2174
2175 select(start,end);
2176 }
2177
2178 public boolean addEdit(UndoableEdit edit)
2179 {
2180 if(edit instanceof CaretUndo)
2181 {
2182 CaretUndo cedit = (CaretUndo)edit;
2183 start = cedit.start;
2184 end = cedit.end;
2185 cedit.die();
2186
2187 return true;
2188 }
2189 else
2190 return false;
2191 }
2192 }
2193
2194 static
2195 {
2196 caretTimer = new Timer(500,new CaretBlinker());
2197 caretTimer.setInitialDelay(500);
2198 caretTimer.start();
2199 }
2200 }