| 1 31 32 package org.antlr.works.completion; 33 34 import org.antlr.works.prefs.AWPrefs; 35 import org.antlr.works.stats.StatisticsAW; 36 import org.antlr.works.utils.OverlayObject; 37 import org.antlr.xjlib.appkit.frame.XJFrameInterface; 38 39 import javax.swing.*; 40 import javax.swing.border.BevelBorder ; 41 import javax.swing.text.BadLocationException ; 42 import javax.swing.text.Document ; 43 import javax.swing.text.JTextComponent ; 44 import java.awt.*; 45 import java.awt.event.*; 46 import java.util.LinkedList ; 47 import java.util.List ; 48 49 public class AutoCompletionMenu extends OverlayObject { 50 51 protected AutoCompletionMenuDelegate delegate; 52 53 protected DefaultListModel listModel; 54 protected JList list; 55 56 protected List <String > words; 57 60 protected static List <String > recentlyUsedWords = new LinkedList <String >(); 61 protected int maxWordLength; 62 63 protected int insertionStartIndex; 64 protected int insertionEndIndex; 65 66 protected int displayIndex; 67 68 public static int visibleMatchingRules = 15; 69 70 public AutoCompletionMenu(AutoCompletionMenuDelegate delegate, JTextComponent textComponent, XJFrameInterface frame) { 71 super(frame, textComponent); 72 this.delegate = delegate; 73 } 74 75 public boolean isVStyle() { 76 return AWPrefs.isVStyleAutoCompletion(); 77 } 78 79 public JTextComponent getTextComponent() { 80 return (JTextComponent )parentComponent; 81 } 82 83 public JComponent overlayCreateInterface() { 84 visibleMatchingRules = (isVStyle()?7:15); getTextComponent().addKeyListener(new MyKeyAdapter()); 86 87 listModel = new DefaultListModel(); 88 89 list = new JList(listModel) { 90 public int getVisibleRowCount() { 91 return Math.min(listModel.getSize(), visibleMatchingRules); 92 } 93 }; 94 list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 95 list.setBackground(new Color(235, 244, 254)); 96 list.addKeyListener(new MyKeyAdapter()); 97 list.setPrototypeCellValue("This is a rule name g"); 98 list.addMouseListener(new ListMouseAdapter()); 99 100 JScrollPane scrollPane = new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 101 scrollPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); 102 return scrollPane; 103 } 104 105 public boolean overlayWillDisplay() { 106 if (isVStyle()){ 107 int index = getTextComponent().getCaretPosition()+1; 110 String partialWord = ""; 111 setInsertionStartIndex(index); 112 setInsertionEndIndex(index); 113 114 List <String > matchingRules = delegate.autoCompletionMenuGetMatchingWordsForPartialWord(partialWord); 115 if(matchingRules.size() == 0) { return false; 117 } 118 119 list.setFont(new Font(AWPrefs.getEditorFont(), Font.PLAIN, 12)); 120 list.setAutoscrolls(true); 121 setDisplayIndex(index); 122 setWordLists(matchingRules, matchingRules); 123 delegate.autoCompletionMenuWillDisplay(); 124 selectMostRecentlyUsedWordPosition(partialWord, matchingRules.get(0)); 125 return true; 126 } else { 127 int position = getTextComponent().getCaretPosition(); 128 129 int index = getPartialWordBeginsAtPosition(position); 130 String partialWord = ""; 131 if(index < position) 132 partialWord = getTextComponent().getText().substring(index+1, position); 133 134 setInsertionStartIndex(index+1); 135 setInsertionEndIndex(position); 136 137 List <String > matchingRules = delegate.autoCompletionMenuGetMatchingWordsForPartialWord(partialWord); 138 if(matchingRules.size() == 0) { 139 return false; 140 } else if(matchingRules.size() == 1) { 141 completePartialWord(matchingRules.get(0)); 142 return false; 143 } 144 145 list.setFont(new Font(AWPrefs.getEditorFont(), Font.PLAIN, 12)); 146 list.setAutoscrolls(true); 147 setDisplayIndex(index+1); 148 setWordLists(matchingRules, matchingRules); 149 delegate.autoCompletionMenuWillDisplay(); 150 return true; 151 } 152 } 153 154 public KeyStroke overlayDisplayKeyStroke() { 155 if (isVStyle()) 156 return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0); else 158 return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_MASK); 159 } 160 161 public String overlayDisplayKeyStrokeMappingName() { 162 return "controlEspace"; 163 } 164 165 public void setWordLists(List <String > names, List <String > words) { 166 listModel.clear(); 167 for (String name : names) listModel.addElement(name); 168 169 this.words = words; 170 maxWordLength = 0; 171 for (String word : words) { 172 maxWordLength = Math.max(maxWordLength, word.length()); 173 } 174 } 175 176 public void setInsertionStartIndex(int startIndex) { 177 insertionStartIndex = startIndex; 178 } 179 180 public void setInsertionEndIndex(int endIndex) { 181 insertionEndIndex = endIndex; 182 } 183 184 public void setDisplayIndex(int index) { 185 this.displayIndex = index; 186 } 187 188 public static boolean isCharIdentifier(char c) { 189 return Character.isLetterOrDigit(c) || c == '_'; 190 } 191 192 private static boolean isAlphaNumericOr_(int keyCode) { 193 return (keyCode>=65 && keyCode <=90 || keyCode == 45); } 195 196 private static boolean isFunctionKey(int keyCode) { 197 return (keyCode >= 16 && keyCode <=18 || keyCode==20); 199 } 200 201 public int getPartialWordBeginsAtPosition(int pos) { 202 String t = getTextComponent().getText(); 203 int index = pos-1; 204 while((index>=0) && isCharIdentifier(t.charAt(index))) { 205 index--; 206 } 207 return index; 208 } 209 210 public void completePartialWord(String word) { 211 try { 212 Document doc = getTextComponent().getDocument(); 213 doc.remove(insertionStartIndex, insertionEndIndex-insertionStartIndex); 214 doc.insertString(insertionStartIndex, word, null); 215 } catch (BadLocationException e) { 216 e.printStackTrace(); 217 } 218 } 219 220 public void autoComplete() { 221 if(list.getSelectedIndex() >= 0){ 222 String partialWord = words.get(list.getSelectedIndex()); 223 if (isVStyle()) { 224 recentlyUsedWords.remove(partialWord); ((LinkedList )recentlyUsedWords).addFirst(partialWord); 226 } 227 completePartialWord(partialWord); 228 } 229 } 230 231 public void resize() { 232 Rectangle rect = null; 233 234 StatisticsAW.shared().recordEvent(StatisticsAW.EVENT_SHOW_AUTO_COMPLETION_MENU); 235 236 try { 237 rect = getTextComponent().getUI().modelToView(getTextComponent(), displayIndex); 238 } catch (BadLocationException e) { 239 e.printStackTrace(); 240 } 241 242 if(rect == null) 243 return; 244 245 Point p = SwingUtilities.convertPoint(getTextComponent(), new Point(rect.x, rect.y), parentFrame.getRootPane()); 246 int height = list.getFixedCellHeight(); 247 int size = listModel.size(); 248 if(size > 0) { 249 height = height*Math.min(visibleMatchingRules, size)+5; 250 content.setBounds(p.x - 3, p.y + rect.height, maxWordLength*8+50, height); 251 } 252 } 253 254 public void selectMostRecentlyUsedWordPosition(String partialWord, String firstWordInList){ 255 String mostRecentWord=""; 256 for (String recentlyUsedWord : recentlyUsedWords) { 257 if (recentlyUsedWord.toLowerCase().startsWith(partialWord) && words.contains(recentlyUsedWord)) { 258 mostRecentWord = recentlyUsedWord; 259 break; 260 } 261 } 262 263 if (mostRecentWord.length()>0){ 264 list.setSelectedValue(mostRecentWord,true); 265 } 266 else { 267 list.setSelectedValue(firstWordInList,true); 269 } 270 int selectedIndex = list.getSelectedIndex(); 273 int bottomIndex = Math.max(0,selectedIndex-1); 274 int topIndex = Math.min(words.size()-1, selectedIndex+2); 275 list.scrollRectToVisible(list.getCellBounds(bottomIndex, topIndex)); 276 } 277 278 public void updateAutoCompleteList() { 279 if(!content.isVisible()) 280 return; 281 282 int position = getTextComponent().getCaretPosition(); 283 int index = getPartialWordBeginsAtPosition(position); 284 String partialWord = ""; 285 if(index<position) 286 partialWord = getTextComponent().getText().substring(index+1, position); 287 288 List <String > matchingRules = delegate.autoCompletionMenuGetMatchingWordsForPartialWord(partialWord); 289 if(matchingRules == null || matchingRules.size() == 0) { 290 hide(); 291 } else { 292 setInsertionEndIndex(position); 293 if (!isVStyle()) setWordLists(matchingRules, matchingRules); 294 selectMostRecentlyUsedWordPosition(partialWord,matchingRules.get(0)); 295 resize(); 296 } 297 } 298 299 public class ListMouseAdapter extends MouseAdapter { 300 public void mouseReleased(MouseEvent e) { 301 if (e.isConsumed() || !content.isVisible()) 302 return; 303 autoComplete(); 304 content.setVisible(false); 305 parentComponent.requestFocusInWindow(); } 307 } 308 309 public class MyKeyAdapter extends KeyAdapter { 310 311 public void move(int delta) { 312 if(listModel.getSize() < 1) 313 return; 314 315 int current = list.getSelectedIndex(); 316 int index = Math.max(0, Math.min(listModel.getSize() - 1, current + delta)); 317 list.setSelectionInterval(index, index); 318 list.scrollRectToVisible(list.getCellBounds(index, index)); 319 } 320 321 public void keyPressed(KeyEvent e) { 322 if(e.isConsumed()) 323 return; 324 325 int keyCode = e.getKeyCode(); 326 if(!content.isVisible()) 327 return; 328 switch(keyCode) { 329 case KeyEvent.VK_LEFT: 330 case KeyEvent.VK_RIGHT: 331 content.setVisible(false); 332 break; 333 334 case KeyEvent.VK_BACK_SPACE: 335 int position = getTextComponent().getCaretPosition(); 336 int index = getPartialWordBeginsAtPosition(position); 337 if (position-1 <= index) 338 content.setVisible(false); 339 345 break; 346 case KeyEvent.VK_T: case KeyEvent.VK_F: if (!e.isControlDown()) break; 349 content.setVisible(false); break; 351 352 case KeyEvent.VK_ESCAPE: 353 content.setVisible(false); 355 e.consume(); 356 break; 357 358 case KeyEvent.VK_ENTER: 359 autoComplete(); 360 content.setVisible(false); 361 e.consume(); 362 break; 363 364 case KeyEvent.VK_DOWN: 365 move(1); 366 e.consume(); 367 break; 368 369 case KeyEvent.VK_UP: 370 move(-1); 371 e.consume(); 372 break; 373 374 case KeyEvent.VK_PAGE_DOWN: 375 if (isVStyle()) {content.setVisible(false);break;} move(list.getVisibleRowCount() - 1); 377 e.consume(); 378 break; 379 380 case KeyEvent.VK_PAGE_UP: 381 if (isVStyle()) {content.setVisible(false);break;} move(-(list.getVisibleRowCount() - 1)); 383 e.consume(); 384 break; 385 386 case KeyEvent.VK_HOME: 387 if (isVStyle()) {content.setVisible(false);break;} move(-listModel.getSize()); 389 e.consume(); 390 break; 391 392 case KeyEvent.VK_END: 393 if (isVStyle()) {content.setVisible(false);break;} move(listModel.getSize()); 395 e.consume(); 396 break; 397 398 default: if (!(isAlphaNumericOr_(keyCode) || isFunctionKey(keyCode)) ){ 400 System.out.println(keyCode); content.setVisible(false); 402 } 403 } 404 } 405 406 } 407 } 408 | Popular Tags |