PageRenderTime 36ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-1-pre5/org/gjt/sp/jedit/gui/CompleteWord.java

#
Java | 471 lines | 342 code | 66 blank | 63 comment | 68 complexity | a0af526a8374657bf570ebb5c096a4f0 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * CompleteWord.java - Complete word dialog
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2001 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.jedit.gui;
  23. //{{{ Imports
  24. import javax.swing.*;
  25. import javax.swing.event.*;
  26. import java.awt.*;
  27. import java.awt.event.*;
  28. import java.util.Vector;
  29. import org.gjt.sp.jedit.syntax.*;
  30. import org.gjt.sp.jedit.textarea.*;
  31. import org.gjt.sp.jedit.*;
  32. //}}}
  33. public class CompleteWord extends JWindow
  34. {
  35. //{{{ completeWord() method
  36. public static void completeWord(View view)
  37. {
  38. JEditTextArea textArea = view.getTextArea();
  39. Buffer buffer = view.getBuffer();
  40. int caretLine = textArea.getCaretLine();
  41. int caret = textArea.getCaretPosition();
  42. if(!buffer.isEditable())
  43. {
  44. textArea.getToolkit().beep();
  45. return;
  46. }
  47. KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
  48. String noWordSep = getNonAlphaNumericWordChars(buffer,keywordMap,caret);
  49. String word = getWordToComplete(buffer,caretLine,caret,noWordSep);
  50. if(word == null)
  51. {
  52. textArea.getToolkit().beep();
  53. return;
  54. }
  55. Vector completions = getCompletions(buffer,word,keywordMap,
  56. noWordSep,caret);
  57. if(completions.size() == 0
  58. || (completions.size() == 1 &&
  59. ((Completion)completions.get(0)).text.equals(word)))
  60. {
  61. textArea.getToolkit().beep();
  62. }
  63. //{{{ if there is only one competion, insert in buffer
  64. else if(completions.size() == 1)
  65. {
  66. textArea.setSelectedText(completions
  67. .elementAt(0).toString()
  68. .substring(word.length()));
  69. } //}}}
  70. //{{{ show popup if > 1
  71. else
  72. {
  73. textArea.scrollToCaret(false);
  74. Point location = textArea.offsetToXY(caret - word.length());
  75. location.y += textArea.getPainter().getFontMetrics()
  76. .getHeight();
  77. SwingUtilities.convertPointToScreen(location,
  78. textArea.getPainter());
  79. new CompleteWord(view,word,completions,location);
  80. } //}}}
  81. } //}}}
  82. //{{{ CompleteWord constructor
  83. public CompleteWord(View view, String word, Vector completions, Point location)
  84. {
  85. super(view);
  86. setContentPane(new JPanel(new BorderLayout())
  87. {
  88. /**
  89. * Returns if this component can be traversed by pressing the
  90. * Tab key. This returns false.
  91. */
  92. public boolean isManagingFocus()
  93. {
  94. return false;
  95. }
  96. /**
  97. * Makes the tab key work in Java 1.4.
  98. */
  99. public boolean getFocusTraversalKeysEnabled()
  100. {
  101. return false;
  102. }
  103. });
  104. this.view = view;
  105. this.textArea = view.getTextArea();
  106. this.buffer = view.getBuffer();
  107. this.word = word;
  108. words = new JList(completions);
  109. words.setFont(UIManager.getFont("TextArea.font"));
  110. words.setVisibleRowCount(Math.min(completions.size(),8));
  111. words.addMouseListener(new MouseHandler());
  112. words.setSelectedIndex(0);
  113. words.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  114. words.setCellRenderer(new Renderer());
  115. // stupid scrollbar policy is an attempt to work around
  116. // bugs people have been seeing with IBM's JDK -- 7 Sep 2000
  117. JScrollPane scroller = new JScrollPane(words,
  118. JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
  119. JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
  120. getContentPane().add(scroller, BorderLayout.CENTER);
  121. GUIUtilities.requestFocus(this,words);
  122. pack();
  123. setLocation(location);
  124. show();
  125. KeyHandler keyHandler = new KeyHandler();
  126. addKeyListener(keyHandler);
  127. words.addKeyListener(keyHandler);
  128. view.setKeyEventInterceptor(keyHandler);
  129. } //}}}
  130. //{{{ dispose() method
  131. public void dispose()
  132. {
  133. view.setKeyEventInterceptor(null);
  134. super.dispose();
  135. SwingUtilities.invokeLater(new Runnable()
  136. {
  137. public void run()
  138. {
  139. textArea.requestFocus();
  140. }
  141. });
  142. } //}}}
  143. //{{{ Private members
  144. //{{{ getNonAlphaNumericWordChars() method
  145. private static String getNonAlphaNumericWordChars(Buffer buffer,
  146. KeywordMap keywordMap, int caret)
  147. {
  148. // figure out what constitutes a word character and what
  149. // doesn't
  150. String noWordSep = buffer.getStringProperty("noWordSep");
  151. if(noWordSep == null)
  152. noWordSep = "";
  153. if(keywordMap != null)
  154. {
  155. String keywordNoWordSep = keywordMap.getNonAlphaNumericChars();
  156. if(keywordNoWordSep != null)
  157. noWordSep = noWordSep + keywordNoWordSep;
  158. }
  159. return noWordSep;
  160. } //}}}
  161. //{{{ getWordToComplete() method
  162. private static String getWordToComplete(Buffer buffer, int caretLine,
  163. int caret, String noWordSep)
  164. {
  165. String line = buffer.getLineText(caretLine);
  166. int dot = caret - buffer.getLineStartOffset(caretLine);
  167. if(dot == 0)
  168. return null;
  169. char ch = line.charAt(dot-1);
  170. if(!Character.isLetterOrDigit(ch)
  171. && noWordSep.indexOf(ch) == -1)
  172. {
  173. // attempting to expand non-word char
  174. return null;
  175. }
  176. int wordStart = TextUtilities.findWordStart(line,dot-1,noWordSep);
  177. String word = line.substring(wordStart,dot);
  178. if(word.length() == 0)
  179. return null;
  180. return word;
  181. } //}}}
  182. //{{{ getCompletions() method
  183. private static Vector getCompletions(Buffer buffer, String word,
  184. KeywordMap keywordMap, String noWordSep, int caret)
  185. {
  186. Vector completions = new Vector();
  187. int wordLen = word.length();
  188. //{{{ try to find matching keywords
  189. if(keywordMap != null)
  190. {
  191. String[] keywords = keywordMap.getKeywords();
  192. for(int i = 0; i < keywords.length; i++)
  193. {
  194. String _keyword = keywords[i];
  195. if(_keyword.regionMatches(keywordMap.getIgnoreCase(),
  196. 0,word,0,wordLen))
  197. {
  198. Completion keyword = new Completion(_keyword,true);
  199. if(completions.indexOf(keyword) == -1)
  200. completions.addElement(keyword);
  201. }
  202. }
  203. } //}}}
  204. //{{{ loop through all lines of current buffer
  205. for(int i = 0; i < buffer.getLineCount(); i++)
  206. {
  207. String line = buffer.getLineText(i);
  208. int start = buffer.getLineStartOffset(i);
  209. // check for match at start of line
  210. if(line.startsWith(word) && caret != start + word.length())
  211. {
  212. String _word = completeWord(line,0,noWordSep);
  213. Completion comp = new Completion(_word,false);
  214. // remove duplicates
  215. if(completions.indexOf(comp) == -1)
  216. completions.addElement(comp);
  217. }
  218. // check for match inside line
  219. int len = line.length() - word.length();
  220. for(int j = 0; j < len; j++)
  221. {
  222. char c = line.charAt(j);
  223. if(!Character.isLetterOrDigit(c) && noWordSep.indexOf(c) == -1)
  224. {
  225. if(line.regionMatches(j + 1,word,0,wordLen)
  226. && caret != start + j + word.length() + 1)
  227. {
  228. String _word = completeWord(line,j + 1,noWordSep);
  229. Completion comp = new Completion(_word,false);
  230. // remove duplicates
  231. if(completions.indexOf(comp) == -1)
  232. completions.addElement(comp);
  233. }
  234. }
  235. }
  236. } //}}}
  237. // sort completion list
  238. MiscUtilities.quicksort(completions,new MiscUtilities.StringICaseCompare());
  239. return completions;
  240. } //}}}
  241. //{{{ completeWord() method
  242. private static String completeWord(String line, int offset, String noWordSep)
  243. {
  244. // '+ 1' so that findWordEnd() doesn't pick up the space at the start
  245. int wordEnd = TextUtilities.findWordEnd(line,offset + 1,noWordSep);
  246. return line.substring(offset,wordEnd);
  247. } //}}}
  248. //{{{ Instance variables
  249. private View view;
  250. private JEditTextArea textArea;
  251. private Buffer buffer;
  252. private String word;
  253. private JList words;
  254. //}}}
  255. //{{{ insertSelected() method
  256. private void insertSelected()
  257. {
  258. textArea.setSelectedText(words.getSelectedValue().toString()
  259. .substring(word.length()));
  260. dispose();
  261. } //}}}
  262. //}}}
  263. //{{{ Completion class
  264. static class Completion
  265. {
  266. String text;
  267. boolean keyword;
  268. Completion(String text, boolean keyword)
  269. {
  270. this.text = text;
  271. this.keyword = keyword;
  272. }
  273. public String toString()
  274. {
  275. return text;
  276. }
  277. public boolean equals(Object obj)
  278. {
  279. if(obj instanceof Completion)
  280. return ((Completion)obj).text.equals(text);
  281. else
  282. return false;
  283. }
  284. } //}}}
  285. //{{{ Renderer class
  286. static class Renderer extends DefaultListCellRenderer
  287. {
  288. public Component getListCellRendererComponent(JList list, Object value,
  289. int index, boolean isSelected, boolean cellHasFocus)
  290. {
  291. super.getListCellRendererComponent(list,value,index,
  292. isSelected,cellHasFocus);
  293. Completion comp = (Completion)value;
  294. if(comp.keyword)
  295. setFont(list.getFont().deriveFont(Font.BOLD));
  296. else
  297. setFont(list.getFont());
  298. return this;
  299. }
  300. } //}}}
  301. //{{{ KeyHandler class
  302. class KeyHandler extends KeyAdapter
  303. {
  304. //{{{ keyPressed() method
  305. public void keyPressed(KeyEvent evt)
  306. {
  307. switch(evt.getKeyCode())
  308. {
  309. case KeyEvent.VK_TAB:
  310. case KeyEvent.VK_ENTER:
  311. insertSelected();
  312. evt.consume();
  313. break;
  314. case KeyEvent.VK_ESCAPE:
  315. dispose();
  316. evt.consume();
  317. break;
  318. case KeyEvent.VK_UP:
  319. int selected = words.getSelectedIndex();
  320. if(selected == 0)
  321. selected = words.getModel().getSize() - 1;
  322. else if(getFocusOwner() == words)
  323. return;
  324. else
  325. selected = selected - 1;
  326. words.setSelectedIndex(selected);
  327. words.ensureIndexIsVisible(selected);
  328. evt.consume();
  329. break;
  330. case KeyEvent.VK_DOWN:
  331. /* int */ selected = words.getSelectedIndex();
  332. if(selected == words.getModel().getSize() - 1)
  333. selected = 0;
  334. else if(getFocusOwner() == words)
  335. return;
  336. else
  337. selected = selected + 1;
  338. words.setSelectedIndex(selected);
  339. words.ensureIndexIsVisible(selected);
  340. evt.consume();
  341. break;
  342. case KeyEvent.VK_BACK_SPACE:
  343. if(word.length() == 1)
  344. {
  345. textArea.backspace();
  346. evt.consume();
  347. dispose();
  348. }
  349. else
  350. {
  351. word = word.substring(0,word.length() - 1);
  352. textArea.backspace();
  353. int caret = textArea.getCaretPosition();
  354. KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
  355. String noWordSep = getNonAlphaNumericWordChars(buffer,keywordMap,caret);
  356. Vector completions = getCompletions(buffer,word,
  357. keywordMap,noWordSep,caret);
  358. if(completions.size() == 0)
  359. dispose();
  360. words.setListData(completions);
  361. words.setSelectedIndex(0);
  362. evt.consume();
  363. }
  364. break;
  365. default:
  366. if(evt.isActionKey())
  367. {
  368. dispose();
  369. view.processKeyEvent(evt);
  370. }
  371. break;
  372. }
  373. } //}}}
  374. //{{{ keyTyped() method
  375. public void keyTyped(KeyEvent evt)
  376. {
  377. char ch = evt.getKeyChar();
  378. evt = KeyEventWorkaround.processKeyEvent(evt);
  379. if(evt == null)
  380. return;
  381. else if(ch != '\b')
  382. {
  383. word = word + ch;
  384. textArea.userInput(ch);
  385. int caret = textArea.getCaretPosition();
  386. KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
  387. String noWordSep = getNonAlphaNumericWordChars(buffer,keywordMap,caret);
  388. Vector completions = getCompletions(buffer,word,keywordMap,
  389. noWordSep,caret);
  390. if(completions.size() == 0)
  391. dispose();
  392. words.setListData(completions);
  393. words.setSelectedIndex(0);
  394. }
  395. } //}}}
  396. } //}}}
  397. //{{{ MouseHandler class
  398. class MouseHandler extends MouseAdapter
  399. {
  400. public void mouseClicked(MouseEvent evt)
  401. {
  402. insertSelected();
  403. }
  404. } //}}}
  405. }