| 1 2 package org.objectweb.jac.aspects.gui.swing; 3 4 import java.awt.Color ; 5 import java.awt.Cursor ; 6 import java.awt.Dimension ; 7 import java.awt.Font ; 8 import java.awt.FontMetrics ; 9 import java.awt.Graphics ; 10 import java.awt.Rectangle ; 11 import java.awt.datatransfer.Clipboard ; 12 import java.awt.datatransfer.ClipboardOwner ; 13 import java.awt.datatransfer.DataFlavor ; 14 import java.awt.datatransfer.StringSelection ; 15 import java.awt.datatransfer.Transferable ; 16 import java.awt.event.FocusEvent ; 17 import java.awt.event.FocusListener ; 18 import java.awt.event.KeyEvent ; 19 import java.awt.event.KeyListener ; 20 import java.awt.event.MouseEvent ; 21 import java.awt.event.MouseListener ; 22 import java.awt.event.MouseMotionListener ; 23 import java.awt.event.TextEvent ; 24 import java.awt.event.TextListener ; 25 import java.io.BufferedInputStream ; 26 import java.io.BufferedReader ; 27 import java.io.File ; 28 import java.io.FileInputStream ; 29 import java.io.FileWriter ; 30 import java.io.IOException ; 31 import java.io.InputStreamReader ; 32 import java.io.PrintWriter ; 33 import java.util.HashSet ; 34 import java.util.Set ; 35 import java.util.Vector ; 36 import javax.swing.JPanel ; 37 import javax.swing.JScrollBar ; 38 import javax.swing.JScrollPane ; 39 import javax.swing.JViewport ; 40 import javax.swing.Scrollable ; 41 import javax.swing.SwingConstants ; 42 import javax.swing.event.CaretEvent ; 43 import javax.swing.event.CaretListener ; 44 import org.apache.log4j.Logger; 45 import org.objectweb.jac.util.Strings; 46 47 62 63 public class SHEditor extends JPanel 64 implements KeyListener , MouseListener , MouseMotionListener , 65 Scrollable , ClipboardOwner , FocusListener  66 { 67 static Logger logger = Logger.getLogger("gui.sheditor"); 68 static Logger loggerComp = Logger.getLogger("completion"); 69 static Logger loggerClip = Logger.getLogger("clipboard"); 70 71 private String text = ""; 72 private FontMetrics metrics; 73 int lineHeight; 75 private int caretPosition = 0; 76 private int selectionStart = 0; 77 private int selectionEnd = 0; 78 79 protected boolean isSelectionCompletion = false; 80 81 82 private int openPos = -1; 83 84 private int closePos = -1; 85 86 private int lineToMark = -1; 87 88 private boolean showCaret = true; 89 90 protected SHEditorConfig conf = new SHEditorConfig(); 91 public SHEditorConfig getConfig() { 92 return conf; 93 } 94 public void setConfig(SHEditorConfig conf) { 95 this.conf = conf; 96 } 97 98 public static final int DEFAULT = 0; 99 public static final int COMMENT = 1; 100 public static final int STRING = 2; 101 102 protected int syntaxUnderCaret; 103 public int getSyntaxUnderCaret() { 104 return syntaxUnderCaret; 105 } 106 107 private int mousePressPos = 0; 108 109 private Vector doneActions = new Vector (); 110 private Vector redoneActions = new Vector (); 111 112 private Rectangle car = new Rectangle (0, 0, 2, 0); 113 114 boolean changed = false; 115 116 private char separators[] = new char[] { 117 '\n', ' ', '.' , ',', '(', ')', '{', '}', '[', ']', '/', '-', '+', '*', 118 '<', '>', '=', ';', '"', '\'', '&', '|', '!' 119 }; 120 121 124 public void setWordSeparators(char[] separators) { 125 this.separators = separators; 126 } 127 128 131 public SHEditor() 132 { 133 super(); 134 135 setFont(new Font ("MonoSpaced", Font.PLAIN, 12)); 136 metrics = getFontMetrics(getFont()); 137 setCursor(new Cursor (Cursor.TEXT_CURSOR)); 138 addKeyListener(this); 139 addMouseListener(this); 140 addMouseMotionListener(this); 141 addFocusListener(this); 142 if (org.objectweb.jac.core.Jac.getMainJavaVersion().compareTo("1.4")>=0) { 143 setFocusTraversalKeysEnabled(false); 144 } 145 setBackground(Color.white); 146 } 147 148 152 public SHEditor(String txt) 153 { 154 this(); 155 text = txt; 156 } 157 158 162 public SHEditor(File file) 163 { 164 this(); 165 readFromFile(file); 166 } 167 168 Vector caretListeners = new Vector (); 169 176 public void addCaretListener(CaretListener listener) { 177 caretListeners.add(listener); 178 } 179 180 186 public void removeCaretListener(CaretListener listener) { 187 caretListeners.remove(listener); 188 } 189 190 protected void fireCaretUpdate() { 191 CaretEvent e = new MutableCaretEvent(this,caretPosition); 192 for (int i = caretListeners.size()-1; i>=0; i--) { 193 ((CaretListener )textListeners.get(i)).caretUpdate(e); 194 } 195 } 196 197 Vector textListeners = new Vector (); 198 199 206 public void addTextListener(TextListener listener) { 207 textListeners.add(listener); 208 } 209 210 216 public void removeTextListener(TextListener listener) { 217 textListeners.remove(listener); 218 } 219 220 protected void fireTextUpdate() { 221 TextEvent e = new TextEvent (this,TextEvent.TEXT_VALUE_CHANGED); 222 for (int i = textListeners.size()-1; i>=0; i--) { 223 ((TextListener )textListeners.get(i)).textValueChanged(e); 224 } 225 } 226 227 231 public String getText() 232 { 233 return text; 234 } 235 236 public void setText(String t) { 237 text=t; 238 fireTextUpdate(); 239 } 240 241 244 boolean eot() { 245 return caretPosition >= text.length(); 246 } 247 248 251 boolean endOfSelection() { 252 return caretPosition == selectionEnd; 253 } 254 255 258 boolean startOfSelection() { 259 return caretPosition == selectionStart; 260 } 261 262 266 public void setSelectionStart(int position) { 267 if (position>selectionEnd) { 268 int oldStart = selectionStart; 269 selectionStart = selectionEnd; 270 selectionEnd = position; 271 repaintChars(selectionStart,position); 272 } else { 273 repaintChars(selectionStart,position); 274 selectionStart = position; 275 } 276 } 277 278 282 public void setSelectionEnd(int position) { 283 if (position<selectionStart) { 284 int oldEnd = selectionEnd; 285 selectionEnd = selectionStart; 286 selectionStart = position; 287 repaintChars(selectionEnd,position); 288 } else { 289 repaintChars(selectionEnd,position); 290 selectionEnd = position; 291 } 292 } 293 294 299 public void setSelection(int start, int end) { 300 int oldStart = selectionStart; 301 int oldEnd = selectionEnd; 302 if (start<=end) { 303 selectionStart = start; 304 selectionEnd = end; 305 } else { 306 selectionStart = end; 307 selectionEnd = start; 308 } 309 repaintChars(oldStart,oldEnd); 310 repaintChars(selectionStart,selectionEnd); 311 } 312 313 317 void backwardMove(boolean select) { 318 if (select) { 319 if (caretPosition<selectionStart) 320 setSelectionStart(caretPosition); 321 else 322 setSelectionEnd(caretPosition); 323 } else { 324 resetSelection(); 325 } 326 } 327 328 332 void forwardMove(boolean select) { 333 if (select) { 334 if (caretPosition>selectionEnd) 335 setSelectionEnd(caretPosition); 336 else 337 setSelectionStart(caretPosition); 338 } else { 339 resetSelection(); 340 } 341 } 342 343 349 public void forwardChar(int n, boolean select) { 350 setCaretPosition(caretPosition + n); 351 forwardMove(select); 352 positionVisible(); 353 } 354 355 361 public void backwardChar(int n, boolean select) { 362 setCaretPosition(caretPosition - n); 363 backwardMove(select); 364 positionVisible(); 365 } 366 367 373 public void forwardWord(int n, boolean select) { 374 boolean endOfSelection = endOfSelection(); 375 int newPos = caretPosition; 376 while(!eot() && isDivider(text.charAt(newPos))) { 377 newPos++; 378 } 379 for (; n>0; n--) { 380 while(!eot() && !isDivider(text.charAt(newPos))) { 381 newPos++; 382 } 383 } 384 setCaretPosition(newPos); 385 forwardMove(select); 386 positionVisible(); 387 } 388 389 395 public void backwardWord(int n, boolean select) { 396 int newPos = caretPosition; 397 if (newPos>0) { 398 newPos--; 399 } 400 while (newPos>0 && isDivider(text.charAt(newPos))) { 401 newPos--; 402 } 403 for (; n>0; n--) { 404 while(newPos>0 && !isDivider(text.charAt(newPos))) { 405 newPos--; 406 } 407 } 408 if (!eot() && newPos>0) 409 newPos++; 410 setCaretPosition(newPos); 411 backwardMove(select); 412 positionVisible(); 413 } 414 415 421 public void nextLine(int n, boolean select) 422 { 423 boolean moved = false; 424 int newPos = caretPosition; 425 for (; n>0; n--) { 426 int posInLine = getPosInLine(newPos); 427 int nextLineStart = text.indexOf('\n', newPos); 428 if (nextLineStart != -1) 429 { 430 nextLineStart ++; 431 int i = 0; 432 while(i < posInLine && i + nextLineStart < text.length() && 433 text.charAt(i + nextLineStart) != '\n') 434 { 435 i ++; 436 } 437 if ((nextLineStart+i) >newPos) 438 moved = true; 439 newPos = nextLineStart + i; 440 } 441 } 442 if (moved) { 443 setCaretPosition(newPos); 444 forwardMove(select); 445 } 446 447 positionVisible(); 448 } 449 450 456 public void previousLine(int n, boolean select) 457 { 458 boolean moved = false; 459 int newPos = caretPosition; 460 for (; n>0; n--) { 461 int posInLine = getPosInLine(newPos); 462 int prevLineStart = 463 text.lastIndexOf('\n', newPos - posInLine - 2) + 1; 464 int i = 0; 465 while(i < posInLine && i + prevLineStart < text.length() && 466 text.charAt(i + prevLineStart) != '\n') 467 { 468 i ++; 469 } 470 if (prevLineStart+i<newPos) 471 moved = true; 472 newPos = prevLineStart+i; 473 } 474 if (moved) { 475 setCaretPosition(newPos); 476 backwardMove(select); 477 } 478 479 positionVisible(); 480 } 481 482 487 public void beginningOfText(boolean select) 488 { 489 setCaretPosition(0); 490 backwardMove(select); 491 positionVisible(); 492 } 493 494 495 500 public void endOfText(boolean select) 501 { 502 setCaretPosition(text.length()); 503 backwardMove(select); 504 positionVisible(); 505 } 506 507 512 public void beginningOfLine(boolean select) 513 { 514 int newPos = caretPosition; 515 if (getPosInLine(newPos) <= getWhiteAtLineStart(newPos)) { 516 newPos -= getPosInLine(newPos); 517 } else { 518 newPos -= 519 getPosInLine(newPos) - 520 getWhiteAtLineStart(newPos); 521 } 522 setCaretPosition(newPos); 523 backwardMove(select); 524 positionVisible(); 525 526 } 527 528 public void realBeginningOfLine(boolean select) 529 { 530 int newPos = caretPosition; 531 if (getPosInLine(newPos) <= getWhiteAtLineStart(newPos)) { 532 newPos -= getPosInLine(newPos); 533 } 534 setCaretPosition(newPos); 535 backwardMove(select); 536 positionVisible(); 537 } 538 539 544 public void endOfLine(boolean select) { 545 setCaretPosition(caretPosition + 546 getLineWidth(caretPosition) - getPosInLine(caretPosition)); 547 forwardMove(select); 548 positionVisible(); 549 } 550 551 555 public void gotoLine(int lineNumber) { 556 beginningOfText(false); 557 if (lineNumber>1) { 558 nextLine(lineNumber-1,false); 559 } 560 } 561 562 565 void resetSelection() { 566 int oldStart = selectionStart; 567 int oldEnd = selectionEnd; 568 selectionEnd = caretPosition; 569 selectionStart = caretPosition; 570 for (int p=oldStart; p<oldEnd; p++) 571 repaintCharAt(p); 572 } 573 574 577 void selectWord(int position) { 578 int oldStart = selectionStart; 579 int oldEnd = selectionEnd; 580 581 selectionEnd = caretPosition; 582 selectionStart = caretPosition; 583 while (selectionEnd<text.length() 584 && Character.isLetterOrDigit(text.charAt(selectionEnd))) { 585 selectionEnd++; 586 } 587 while (selectionStart>=0 && selectionStart<text.length() && 588 Character.isLetterOrDigit(text.charAt(selectionStart))) { 589 selectionStart--; 590 } 591 if (selectionStart>=0 && selectionStart<text.length() && 592 !Character.isLetterOrDigit(text.charAt(selectionStart))) 593 selectionStart++; 594 595 for (int p=oldStart; p<oldEnd; p++) 596 repaintCharAt(p); 597 } 598 599 CompletionEngine completionEngine; 600 601 public void setCompletionEngine(CompletionEngine ce) { 602 completionEngine = ce; 603 } 604 605 public CompletionEngine getCompletionEngine() { 606 return completionEngine; 607 } 608 609 void runCompletionEngine(int direction) { 610 611 if (completionEngine!=null) { 612 613 String writtenText = ""; 614 int pos; 615 if (selectionStart!=selectionEnd) { 616 pos = selectionStart; 617 } else { 618 pos = caretPosition; 619 } 620 int beginWritten = pos; 621 StringBuffer currentProposal = new StringBuffer (); 622 if (pos>0 && !isDivider(text.charAt(pos-1))) { 624 loggerComp.debug("written word found"); 625 beginWritten--; 626 while (beginWritten>0 && !isDivider(text.charAt(beginWritten-1))) { 628 beginWritten--; 629 } 630 writtenText = text.substring(beginWritten, pos); 631 if (selectionStart!=selectionEnd) { 632 currentProposal.append(writtenText); 633 } 634 } 635 636 currentProposal.append(text.substring(selectionStart, selectionEnd)); 637 int initPosition = caretPosition; 638 639 initPosition = selectionStart; 641 remove(selectionStart, selectionEnd - selectionStart); 642 resetSelection(); 643 isSelectionCompletion = true; 644 645 String proposedText = 646 completionEngine.getProposal( 647 text,beginWritten,writtenText, 648 currentProposal.toString(), 649 direction); 650 if (proposedText.length()>0) { 651 insertString(caretPosition,proposedText.substring(writtenText.length())); 652 } 653 654 setSelectionStart(initPosition); 655 setSelectionEnd(caretPosition); 656 657 } 658 } 659 660 KeyListener toolKeyListener; 661 public void toolDone() { 662 toolKeyListener = null; 663 } 664 665 668 public void keyPressed(KeyEvent e) 669 { 670 if (toolKeyListener!=null) { 671 toolKeyListener.keyPressed(e); 672 return; 673 } 674 if (e.isControlDown()) 675 { 676 switch (e.getKeyCode()) { 677 case KeyEvent.VK_C: 678 copy(); 679 break; 680 case KeyEvent.VK_V: 681 paste(); 682 break; 683 case KeyEvent.VK_X: 684 cut(); 685 break; 686 case KeyEvent.VK_Z: 687 undo(); 688 break; 689 case KeyEvent.VK_Y: 690 redo(); 691 break; 692 case KeyEvent.VK_S: 693 toolKeyListener = new SearchTool(this,caretPosition); 694 break; 695 case KeyEvent.VK_RIGHT: 696 forwardWord(1, e.isShiftDown()); 697 break; 698 case KeyEvent.VK_LEFT: 699 backwardWord(1, e.isShiftDown()); 700 break; 701 case KeyEvent.VK_HOME: 702 beginningOfText(e.isShiftDown()); 703 break; 704 case KeyEvent.VK_END: 705 endOfText(e.isShiftDown()); 706 break; 707 case KeyEvent.VK_SPACE: 708 runCompletionEngine( 709 e.isShiftDown()?CompletionEngine.BACKWARD:CompletionEngine.FORWARD); 710 break; 711 default: 712 } 713 } 714 else if ((e.getModifiers() & KeyEvent.ALT_MASK) > 0) 715 { 716 } 717 else if ((e.getModifiers() & KeyEvent.ALT_GRAPH_MASK) > 0) 718 { 719 } 720 else if (e.isShiftDown()) 721 { 722 switch (e.getKeyCode()) { 723 case KeyEvent.VK_LEFT: 724 backwardChar(1,e.isShiftDown()); 725 e.consume(); 726 break; 727 case KeyEvent.VK_RIGHT: 728 forwardChar(1,e.isShiftDown()); 729 e.consume(); 730 break; 731 case KeyEvent.VK_UP: 732 previousLine(1,e.isShiftDown()); 733 e.consume(); 734 break; 735 case KeyEvent.VK_DOWN: 736 nextLine(1,e.isShiftDown()); 737 e.consume(); 738 break; 739 case KeyEvent.VK_HOME: 740 beginningOfLine(e.isShiftDown()); 741 e.consume(); 742 break; 743 case KeyEvent.VK_END: 744 endOfLine(e.isShiftDown()); 745 e.consume(); 746 break; 747 case KeyEvent.VK_PAGE_UP: 748 previousLine(15,e.isShiftDown()); 749 e.consume(); 750 break; 751 case KeyEvent.VK_PAGE_DOWN: 752 nextLine(15,e.isShiftDown()); 753 e.consume(); 754 break; 755 case KeyEvent.VK_TAB: 756 { 757 if (selectionStart != selectionEnd) 758 { 759 int start = selectionStart; 760 int end = selectionEnd; 761 762 for(int pos = end; 763 pos >= start - getPosInLine(start) && pos >= 0; 764 pos--) 765 { 766 if (pos == 0 || text.charAt(pos - 1) == '\n') 767 { 768 for(int i=0; 769 i < conf.getTabWidth() && text.charAt(pos) == ' '; 770 i++) 771 { 772 remove(pos, 1); 773 end--; 774 } 775 } 776 } 777 setSelection(start,end); 778 } 779 else 780 { 781 } 782 e.consume(); 783 } 784 break; 785 default: 786 } 787 } 788 else 789 { 790 switch (e.getKeyCode()) { 791 case KeyEvent.VK_LEFT: 792 backwardChar(1,e.isShiftDown()); 793 e.consume(); 794 break; 795 case KeyEvent.VK_RIGHT: 796 forwardChar(1,e.isShiftDown()); 797 e.consume(); 798 break; 799 case KeyEvent.VK_UP: 800 previousLine(1,e.isShiftDown()); 801 e.consume(); 802 break; 803 case KeyEvent.VK_DOWN: 804 nextLine(1,e.isShiftDown()); 805 e.consume(); 806 break; 807 case KeyEvent.VK_TAB: 808 if (selectionStart == selectionEnd) 809 { 810 insertTab(caretPosition); 811 } 812 else 813 { 814 int start = selectionStart; 815 int end = selectionEnd; 816 817 for(int pos=end; 818 pos>=start-getPosInLine(start) && pos>=0; 819 pos--) 820
|