package edu.princeton.toy; import java.awt.*; import java.awt.event.*; import edu.princeton.swing.*; import edu.princeton.swing.text.*; import edu.princeton.toy.lang.*; /** * TCommentingAutoCompleter is an subclass of TUncommentingAutoCompleter which will also * automatically update or add an autocomment when the user completes or modifies a command. * * @version 7.1 * @author btsang */ public class TCommentingAutoCompleter extends TUncommentingAutoCompleter { public TCommentingAutoCompleter() { } /** * The PHighlightedTextArea will pass all key events to its auto-completer before processing * the event for itself. * * @param comp The component which recieved the KeyEvent. * @param e The event which occurred. * @return True if the component should ignore the KeyEvent (because this method already * performed a special action associated with it). In either case, KeyListeners of the * component will still be informed of the event. */ public boolean interceptKeyEvent(PHighlightedTextArea comp, KeyEvent e) { // Allow the indenter+uncommenter to try to intercept the KeyEvent if (super.interceptKeyEvent(comp, e)) return true; // do not intercept if the user has pressed an action key // right and left arrows are an exception (they may have a meaning) if (e.isActionKey() && e.getKeyCode() != KeyEvent.VK_RIGHT && e.getKeyCode() != KeyEvent.VK_LEFT) return false; // do not intercept if the user is trying to do any keyboard shortcut // excluding the paste command. int mask; if (System.getProperty("os.name").startsWith("Mac")) mask = InputEvent.META_DOWN_MASK; else mask = InputEvent.CTRL_DOWN_MASK; if ((e.getModifiersEx() & mask) == mask) { if (e.getKeyChar() == 'c' || e.getKeyChar() == 'z' || e.getKeyChar() == 'o' || e.getKeyChar() == 'n' || e.getKeyChar() == 'q' || e.getKeyChar() == 's' || e.getKeyChar() == 'a' || e.getKeyChar() == 'e' || e.getKeyChar() == 'f' || e.getKeyChar() == 'y') { return false; } } // get the caret position int selectionDot = comp.getSelectionDot(); HighlightedDocument document = comp.getDocument(); Point coordinate = document.offsetToCoordinate(selectionDot); // get the current line int lineStartDot = selectionDot - coordinate.x; int lineEndDot = document.coordinateToOffset(Integer.MAX_VALUE, coordinate.y); String line = document.getText(lineStartDot, lineEndDot); int length = line.length(); // Check if the line already has an instruction + pseudocode or not boolean hasInstruction = false; if (length >= 8) hasInstruction = TWord.isCommand(line.substring(0, 8)); // Check if some text is selected (highlited) Point selStart = document.offsetToCoordinate(comp.getSelectionStart()); Point selEnd = document.offsetToCoordinate(comp.getSelectionEnd()); boolean hasSelection = (selStart.x != selEnd.x && selStart.y == selEnd.y) || (selStart.y != selEnd.y); boolean startIn = selStart.x >= 8 && selStart.x <= TProgramDocument.COMMENT_COLUMN; boolean startAfter = selStart.x > TProgramDocument.COMMENT_COLUMN; // skip over the pseudocode if the user hits left while being at the beginning of // the user comments column or hits right while being at the end of the instruction // column mask = InputEvent.SHIFT_DOWN_MASK; int mark; if (selectionDot == comp.getSelectionStart()) mark = comp.getSelectionEnd(); else mark = comp.getSelectionStart(); if (hasInstruction && coordinate.x == 8 && e.getKeyCode() == KeyEvent.VK_RIGHT && e.getID() == KeyEvent.KEY_PRESSED) { int newPos = selectionDot + TProgramDocument.COMMENT_COLUMN - 8; if ((e.getModifiersEx() & mask) == mask) comp.select(newPos, mark, newPos); else comp.select(newPos, newPos, newPos); return true; } else if (hasInstruction && coordinate.x == TProgramDocument.COMMENT_COLUMN && e.getKeyCode() == KeyEvent.VK_LEFT && e.getID() == KeyEvent.KEY_PRESSED) { int newPos = selectionDot - TProgramDocument.COMMENT_COLUMN + 8; if ((e.getModifiersEx() & mask) == mask) comp.select(newPos, mark, newPos); else comp.select(newPos, newPos, newPos); return true; } else if (e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_LEFT) return false; // Do nothing if the user is modifying the user-comments column. if ((startAfter) || (selStart.x == TProgramDocument.COMMENT_COLUMN && hasSelection) || (coordinate.x == TProgramDocument.COMMENT_COLUMN && e.getKeyCode() != KeyEvent.VK_BACK_SPACE && selStart.x >= coordinate.x)) { return false; } // Prevent the user from typing in the auto-comment column IF the line // begins with a valid instruction if (hasInstruction && startIn) { // Exclude the case when the user is trying to remove the last character // of an instruction. if (coordinate.x == 8 && (e.getKeyCode() == KeyEvent.VK_BACK_SPACE)) { return false; } else { if (canBeep(e)) java.awt.Toolkit.getDefaultToolkit().beep(); return true; } } // Prevent the user from typing in the instructions column if there is a // valid instruction. The user can only delete or replace the instruction, // but not add. if (hasInstruction && !hasSelection && coordinate.x < 8) { if (e.getKeyCode() != KeyEvent.VK_BACK_SPACE && e.getKeyChar() != '\n') { if (canBeep(e)) java.awt.Toolkit.getDefaultToolkit().beep(); return true; } } return false; } private boolean canBeep(KeyEvent e) { return e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() != KeyEvent.VK_SHIFT && e.getKeyCode() != KeyEvent.VK_CONTROL && e.getKeyCode() != KeyEvent.VK_META && e.getKeyCode() != KeyEvent.VK_ESCAPE; } }