PageRenderTime 122ms CodeModel.GetById 32ms app.highlight 16ms RepoModel.GetById 70ms app.codeStats 0ms

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

#
Java | 453 lines | 331 code | 64 blank | 58 comment | 70 complexity | 1f97056a4bd245199bfdb640b4e6182e MD5 | raw file
  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
 23package org.gjt.sp.jedit.gui;
 24
 25//{{{ Imports
 26import javax.swing.*;
 27import javax.swing.event.*;
 28import java.awt.*;
 29import java.awt.event.*;
 30import java.util.Vector;
 31import org.gjt.sp.jedit.syntax.*;
 32import org.gjt.sp.jedit.textarea.*;
 33import org.gjt.sp.jedit.*;
 34//}}}
 35
 36public class CompleteWord extends JWindow
 37{
 38	//{{{ completeWord() method
 39	public static void completeWord(View view)
 40	{
 41		JEditTextArea textArea = view.getTextArea();
 42		Buffer buffer = view.getBuffer();
 43		int caretLine = textArea.getCaretLine();
 44		int caret = textArea.getCaretPosition();
 45
 46		if(!buffer.isEditable())
 47		{
 48			textArea.getToolkit().beep();
 49			return;
 50		}
 51
 52		KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
 53		String noWordSep = getNonAlphaNumericWordChars(buffer,keywordMap,caret);
 54		String word = getWordToComplete(buffer,caretLine,caret,noWordSep);
 55		if(word == null)
 56		{
 57			textArea.getToolkit().beep();
 58			return;
 59		}
 60
 61		Vector completions = getCompletions(buffer,word,keywordMap,
 62			noWordSep,caret);
 63
 64		if(completions.size() == 0)
 65			textArea.getToolkit().beep();
 66		//{{{ if there is only one competion, insert in buffer
 67		else if(completions.size() == 1)
 68		{
 69			textArea.setSelectedText(completions
 70				.elementAt(0).toString()
 71				.substring(word.length()));
 72		} //}}}
 73		//{{{ show popup if > 1
 74		else
 75		{
 76			Point location = textArea.offsetToXY(caret - word.length());
 77			location.y += textArea.getPainter().getFontMetrics()
 78				.getHeight();
 79
 80			SwingUtilities.convertPointToScreen(location,
 81				textArea.getPainter());
 82			new CompleteWord(view,word,completions,location);
 83		} //}}}
 84	} //}}}
 85
 86	//{{{ CompleteWord constructor
 87	public CompleteWord(View view, String word, Vector completions, Point location)
 88	{
 89		super(view);
 90
 91		this.view = view;
 92		this.textArea = view.getTextArea();
 93		this.buffer = view.getBuffer();
 94		this.word = word;
 95
 96		words = new JList(completions);
 97		words.setFont(UIManager.getFont("TextArea.font"));
 98
 99		words.setVisibleRowCount(Math.min(completions.size(),8));
100
101		words.addMouseListener(new MouseHandler());
102		words.setSelectedIndex(0);
103		words.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
104		words.setCellRenderer(new Renderer());
105
106		// stupid scrollbar policy is an attempt to work around
107		// bugs people have been seeing with IBM's JDK -- 7 Sep 2000
108		JScrollPane scroller = new JScrollPane(words,
109			JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
110			JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
111
112		getContentPane().add(scroller, BorderLayout.CENTER);
113
114		GUIUtilities.requestFocus(this,words);
115
116		pack();
117		setLocation(location);
118		show();
119
120		KeyHandler keyHandler = new KeyHandler();
121		addKeyListener(keyHandler);
122		words.addKeyListener(keyHandler);
123		view.setKeyEventInterceptor(keyHandler);
124	} //}}}
125
126	//{{{ dispose() method
127	public void dispose()
128	{
129		view.setKeyEventInterceptor(null);
130		super.dispose();
131		SwingUtilities.invokeLater(new Runnable()
132		{
133			public void run()
134			{
135				textArea.requestFocus();
136			}
137		});
138	} //}}}
139
140	//{{{ Private members
141
142	//{{{ getNonAlphaNumericWordChars() method
143	private static String getNonAlphaNumericWordChars(Buffer buffer,
144		KeywordMap keywordMap, int caret)
145	{
146		// figure out what constitutes a word character and what
147		// doesn't
148		String noWordSep = buffer.getStringProperty("noWordSep");
149		if(noWordSep == null)
150			noWordSep = "";
151		if(keywordMap != null)
152		{
153			String keywordNoWordSep = keywordMap.getNonAlphaNumericChars();
154			if(keywordNoWordSep != null)
155				noWordSep = noWordSep + keywordNoWordSep;
156		}
157
158		return noWordSep;
159	} //}}}
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
170		char ch = line.charAt(dot-1);
171		if(!Character.isLetterOrDigit(ch)
172			&& noWordSep.indexOf(ch) == -1)
173		{
174			// attempting to expand non-word char
175			return null;
176		}
177
178		int wordStart = TextUtilities.findWordStart(line,dot-1,noWordSep);
179		String word = line.substring(wordStart,dot);
180		if(word.length() == 0)
181			return null;
182
183		return word;
184	} //}}}
185
186	//{{{ getCompletions() method
187	private static Vector getCompletions(Buffer buffer, String word,
188		KeywordMap keywordMap, String noWordSep, int caret)
189	{
190		Vector completions = new Vector();
191
192		int wordLen = word.length();
193
194		//{{{ try to find matching keywords
195		if(keywordMap != null)
196		{
197			String[] keywords = keywordMap.getKeywords();
198			for(int i = 0; i < keywords.length; i++)
199			{
200				String _keyword = keywords[i];
201				if(_keyword.regionMatches(keywordMap.getIgnoreCase(),
202					0,word,0,wordLen))
203				{
204					Completion keyword = new Completion(_keyword,true);
205					if(completions.indexOf(keyword) == -1)
206						completions.addElement(keyword);
207				}
208			}
209		} //}}}
210
211		//{{{ loop through all lines of current buffer
212		for(int i = 0; i < buffer.getLineCount(); i++)
213		{
214			String line = buffer.getLineText(i);
215			int start = buffer.getLineStartOffset(i);
216
217			// check for match at start of line
218
219			if(line.startsWith(word) && caret != start + word.length())
220			{
221				String _word = completeWord(line,0,noWordSep);
222				if(_word.length() != wordLen)
223				{
224					Completion comp = new Completion(_word,false);
225
226					// remove duplicates
227					if(completions.indexOf(comp) == -1)
228						completions.addElement(comp);
229				}
230			}
231
232			// check for match inside line
233			int len = line.length() - word.length();
234			for(int j = 0; j < len; j++)
235			{
236				char c = line.charAt(j);
237				if(!Character.isLetterOrDigit(c) && noWordSep.indexOf(c) == -1)
238				{
239					if(line.regionMatches(j + 1,word,0,wordLen)
240						&& caret != start + j + word.length() + 1)
241					{
242						String _word = completeWord(line,j + 1,noWordSep);
243						if(_word.length() != wordLen)
244						{
245							Completion comp = new Completion(_word,false);
246
247							// remove duplicates
248							if(completions.indexOf(comp) == -1)
249								completions.addElement(comp);
250						}
251					}
252				}
253			}
254		} //}}}
255
256		// sort completion list
257		MiscUtilities.quicksort(completions,new MiscUtilities.StringICaseCompare());
258
259		return completions;
260	} //}}}
261
262	//{{{ completeWord() method
263	private static String completeWord(String line, int offset, String noWordSep)
264	{
265		// '+ 1' so that findWordEnd() doesn't pick up the space at the start
266		int wordEnd = TextUtilities.findWordEnd(line,offset + 1,noWordSep);
267		return line.substring(offset,wordEnd);
268	} //}}}
269
270	//{{{ Instance variables
271	private View view;
272	private JEditTextArea textArea;
273	private Buffer buffer;
274	private String word;
275	private JList words;
276	//}}}
277
278	//{{{ insertSelected() method
279	private void insertSelected()
280	{
281		textArea.setSelectedText(words.getSelectedValue().toString()
282			.substring(word.length()));
283		dispose();
284	} //}}}
285
286	//}}}
287
288	//{{{ Completion class
289	static class Completion
290	{
291		String text;
292		boolean keyword;
293
294		Completion(String text, boolean keyword)
295		{
296			this.text = text;
297			this.keyword = keyword;
298		}
299
300		public String toString()
301		{
302			return text;
303		}
304
305		public boolean equals(Object obj)
306		{
307			if(obj instanceof Completion)
308				return ((Completion)obj).text.equals(text);
309			else
310				return false;
311		}
312	} //}}}
313
314	//{{{ Renderer class
315	static class Renderer extends DefaultListCellRenderer
316	{
317		public Component getListCellRendererComponent(JList list, Object value,
318			int index, boolean isSelected, boolean cellHasFocus)
319		{
320			super.getListCellRendererComponent(list,value,index,
321				isSelected,cellHasFocus);
322
323			Completion comp = (Completion)value;
324			if(comp.keyword)
325				setFont(list.getFont().deriveFont(Font.BOLD));
326			else
327				setFont(list.getFont());
328
329			return this;
330		}
331	} //}}}
332
333	//{{{ KeyHandler class
334	class KeyHandler extends KeyAdapter
335	{
336		//{{{ keyPressed() method
337		public void keyPressed(KeyEvent evt)
338		{
339			switch(evt.getKeyCode())
340			{
341			// doesn't work in 1.4?
342			//case KeyEvent.VK_TAB:
343			case KeyEvent.VK_ENTER:
344				insertSelected();
345				evt.consume();
346				break;
347			case KeyEvent.VK_ESCAPE:
348				dispose();
349				evt.consume();
350				break;
351			case KeyEvent.VK_UP:
352				int selected = words.getSelectedIndex();
353
354				if(selected == 0)
355					selected = words.getModel().getSize() - 1;
356				else if(getFocusOwner() == words)
357					return;
358				else
359					selected = selected - 1;
360
361				words.setSelectedIndex(selected);
362				words.ensureIndexIsVisible(selected);
363
364				evt.consume();
365				break;
366			case KeyEvent.VK_DOWN:
367				/* int */ selected = words.getSelectedIndex();
368
369				if(selected == words.getModel().getSize() - 1)
370					selected = 0;
371				else if(getFocusOwner() == words)
372					return;
373				else
374					selected = selected + 1;
375
376				words.setSelectedIndex(selected);
377				words.ensureIndexIsVisible(selected);
378
379				evt.consume();
380				break;
381			case KeyEvent.VK_BACK_SPACE:
382				if(word.length() == 1)
383				{
384					textArea.backspace();
385					evt.consume();
386					dispose();
387				}
388				else
389				{
390					word = word.substring(0,word.length() - 1);
391					textArea.backspace();
392					int caret = textArea.getCaretPosition();
393					KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
394					String noWordSep = getNonAlphaNumericWordChars(buffer,keywordMap,caret);
395
396					Vector completions = getCompletions(buffer,word,
397						keywordMap,noWordSep,caret);
398
399					if(completions.size() == 0)
400						dispose();
401
402					words.setListData(completions);
403					words.setSelectedIndex(0);
404
405					evt.consume();
406				}
407				break;
408			default:
409				if(evt.isActionKey())
410				{
411					dispose();
412					view.processKeyEvent(evt);
413				}
414				break;
415			}
416		} //}}}
417
418		//{{{ keyTyped() method
419		public void keyTyped(KeyEvent evt)
420		{
421			char ch = evt.getKeyChar();
422			evt = KeyEventWorkaround.processKeyEvent(evt);
423			if(evt == null)
424				return;
425			else if(ch != '\b')
426			{
427				word = word + ch;
428				textArea.userInput(ch);
429				int caret = textArea.getCaretPosition();
430				KeywordMap keywordMap = buffer.getKeywordMapAtOffset(caret);
431				String noWordSep = getNonAlphaNumericWordChars(buffer,keywordMap,caret);
432
433				Vector completions = getCompletions(buffer,word,keywordMap,
434					noWordSep,caret);
435
436				if(completions.size() == 0)
437					dispose();
438
439				words.setListData(completions);
440				words.setSelectedIndex(0);
441			}
442		} //}}}
443	} //}}}
444
445	//{{{ MouseHandler class
446	class MouseHandler extends MouseAdapter
447	{
448		public void mouseClicked(MouseEvent evt)
449		{
450			insertSelected();
451		}
452	} //}}}
453}