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