PageRenderTime 28ms CodeModel.GetById 9ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/gui/HistoryTextField.java

#
Java | 580 lines | 366 code | 67 blank | 147 comment | 80 complexity | 39d58a370fb55d4217ffb5280392cbea MD5 | raw file
  1/*
  2 * HistoryTextField.java - Text field with a history
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 1999, 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.border.Border;
 28import javax.swing.border.AbstractBorder;
 29import javax.swing.border.CompoundBorder;
 30import java.awt.*;
 31import java.awt.event.*;
 32import org.gjt.sp.jedit.*;
 33//}}}
 34
 35/**
 36 * Text field with an arrow-key accessable history.
 37 * @author Slava Pestov
 38 * @version $Id: HistoryTextField.java 3931 2001-12-02 11:40:51Z spestov $
 39 */
 40public class HistoryTextField extends JTextField
 41{
 42	//{{{ HistoryTextField constructor
 43	/**
 44	 * Creates a new history text field.
 45	 * @since jEdit 3.2pre5
 46	 */
 47	public HistoryTextField()
 48	{
 49		this(null);
 50	} //}}}
 51
 52	//{{{ HistoryTextField constructor
 53	/**
 54	 * Creates a new history text field.
 55	 * @param name The history model name
 56	 */
 57	public HistoryTextField(String name)
 58	{
 59		this(name,false,true);
 60	} //}}}
 61
 62	//{{{ HistoryTextField constructor
 63	/**
 64	 * Creates a new history text field.
 65	 * @param name The history model name
 66	 * @param instantPopup If true, selecting a value from the history
 67	 * popup will immediately fire an ActionEvent. If false, the user
 68	 * will have to press 'Enter' first
 69	 *
 70	 * @since jEdit 2.2pre5
 71	 */
 72	public HistoryTextField(String name, boolean instantPopups)
 73	{
 74		this(name,instantPopups,true);
 75	} //}}}
 76
 77	//{{{ HistoryTextField constructor
 78	/**
 79	 * Creates a new history text field.
 80	 * @param name The history model name
 81	 * @param instantPopups If true, selecting a value from the history
 82	 * popup will immediately fire an ActionEvent. If false, the user
 83	 * will have to press 'Enter' first
 84	 * @param enterAddsToHistory If true, pressing the Enter key will
 85	 * automatically add the currently entered text to the history.
 86	 *
 87	 * @since jEdit 2.6pre5
 88	 */
 89	public HistoryTextField(String name, boolean instantPopups,
 90		boolean enterAddsToHistory)
 91	{
 92		setBorder(new CompoundBorder(getBorder(),new HistoryBorder()));
 93
 94		if(name != null)
 95			historyModel = HistoryModel.getModel(name);
 96
 97		addMouseMotionListener(new MouseHandler());
 98		addFocusListener(new FocusHandler());
 99
100		this.instantPopups = instantPopups;
101		this.enterAddsToHistory = enterAddsToHistory;
102
103		index = -1;
104	} //}}}
105
106	//{{{ setInstantPopups() method
107	/**
108	 * Sets if selecting a value from the popup should immediately fire
109	 * an ActionEvent.
110	 * @since jEdit 4.0pre3
111	 */
112	public void setInstantPopups(boolean instantPopups)
113	{
114		this.instantPopups = instantPopups;
115	} //}}}
116
117	//{{{ getInstantPopups() method
118	/**
119	 * Returns if selecting a value from the popup should immediately fire
120	 * an ActionEvent.
121	 * @since jEdit 4.0pre3
122	 */
123	public boolean getInstantPopups()
124	{
125		return instantPopups;
126	} //}}}
127
128	//{{{ setEnterAddsToHistory() method
129	/**
130	 * Sets if pressing Enter should automatically add the currently
131	 * entered text to the history.
132	 * @since jEdit 4.0pre3
133	 */
134	public void setEnterAddsToHistory(boolean enterAddsToHistory)
135	{
136		this.enterAddsToHistory = enterAddsToHistory;
137	} //}}}
138
139	//{{{ getEnterAddsToHistory() method
140	/**
141	 * Returns if pressing Enter should automatically add the currently
142	 * entered text to the history.
143	 * @since jEdit 4.0pre3
144	 */
145	public boolean setEnterAddsToHistory()
146	{
147		return enterAddsToHistory;
148	} //}}}
149
150	//{{{ setSelectAllOnFocus() method
151	/**
152	 * Sets if all text should be selected when the field gets focus.
153	 * @since jEdit 4.0pre3
154	 */
155	public void setSelectAllOnFocus(boolean selectAllOnFocus)
156	{
157		this.selectAllOnFocus = selectAllOnFocus;
158	} //}}}
159
160	//{{{ getSelectAllOnFocus() method
161	/**
162	 * Returns if all text should be selected when the field gets focus.
163	 * @since jEdit 4.0pre3
164	 */
165	public boolean setSelectAllOnFocus()
166	{
167		return selectAllOnFocus;
168	} //}}}
169
170	//{{{ setModel() method
171	/**
172	 * Sets the history list model.
173	 * @param name The model name
174	 * @since jEdit 2.3pre3
175	 */
176	public void setModel(String name)
177	{
178		if(name == null)
179			historyModel = null;
180		else
181			historyModel = HistoryModel.getModel(name);
182		index = -1;
183		repaint();
184	} //}}}
185
186	//{{{ addCurrentToHistory() method
187	/**
188	 * Adds the currently entered item to the history.
189	 */
190	public void addCurrentToHistory()
191	{
192		if(historyModel != null)
193			historyModel.addItem(getText());
194		index = 0;
195	} //}}}
196
197	//{{{ setText() method
198	/**
199	 * Sets the displayed text.
200	 */
201	public void setText(String text)
202	{
203		super.setText(text);
204		index = -1;
205	} //}}}
206
207	//{{{ getModel() method
208	/**
209	 * Returns the underlying history model.
210	 */
211	public HistoryModel getModel()
212	{
213		return historyModel;
214	} //}}}
215
216	//{{{ fireActionPerformed() method
217	/**
218	 * Fires an action event to all listeners. This is public so
219	 * that inner classes can access it.
220	 */
221	public void fireActionPerformed()
222	{
223		super.fireActionPerformed();
224	} //}}}
225
226	//{{{ Protected members
227
228	//{{{ processKeyEvent() method
229	protected void processKeyEvent(KeyEvent evt)
230	{
231		if(!isEnabled())
232			return;
233
234		evt = KeyEventWorkaround.processKeyEvent(evt);
235		if(evt == null)
236			return;
237
238		if(evt.getID() == KeyEvent.KEY_PRESSED)
239		{
240			if(evt.getKeyCode() == KeyEvent.VK_ENTER)
241			{
242				if(enterAddsToHistory)
243					addCurrentToHistory();
244
245				if(evt.getModifiers() == 0)
246				{
247					fireActionPerformed();
248					evt.consume();
249				}
250			}
251			else if(evt.getKeyCode() == KeyEvent.VK_UP)
252			{
253				if(evt.isShiftDown())
254					doBackwardSearch();
255				else
256					historyPrevious();
257				evt.consume();
258			}
259			else if(evt.getKeyCode() == KeyEvent.VK_DOWN)
260			{
261				if(evt.isShiftDown())
262					doForwardSearch();
263				else
264					historyNext();
265				evt.consume();
266			}
267			else if(evt.getKeyCode() == KeyEvent.VK_TAB
268				&& evt.isControlDown())
269			{
270				doBackwardSearch();
271				evt.consume();
272			}
273		}
274
275		if(!evt.isConsumed())
276			super.processKeyEvent(evt);
277	} //}}}
278
279	//{{{ processMouseEvent() method
280	protected void processMouseEvent(MouseEvent evt)
281	{
282		if(!isEnabled())
283			return;
284
285		switch(evt.getID())
286		{
287		case MouseEvent.MOUSE_PRESSED:
288			Border border = getBorder();
289			Insets insets = border.getBorderInsets(HistoryTextField.this);
290
291			if(evt.getX() >= getWidth() - insets.right
292				|| GUIUtilities.isPopupTrigger(evt))
293			{
294				if(evt.isShiftDown())
295					showPopupMenu(getText().substring(0,
296						getSelectionStart()),0,getHeight());
297				else
298					showPopupMenu("",0,getHeight());
299			}
300			else
301				super.processMouseEvent(evt);
302
303			break;
304		case MouseEvent.MOUSE_EXITED:
305			setCursor(Cursor.getDefaultCursor());
306			super.processMouseEvent(evt);
307			break;
308		default:
309			super.processMouseEvent(evt);
310			break;
311		}
312	} //}}}
313
314	//}}}
315
316	//{{{ Private members
317
318	//{{{ Instance variables
319	private HistoryModel historyModel;
320	private JPopupMenu popup;
321	private boolean instantPopups;
322	private boolean enterAddsToHistory;
323	private boolean selectAllOnFocus;
324	private boolean focusClickFlag;
325	private String current;
326	private int index;
327	//}}}
328
329	//{{{ doBackwardSearch() method
330	private void doBackwardSearch()
331	{
332		if(historyModel == null)
333			return;
334
335		if(getSelectionEnd() != getDocument().getLength())
336		{
337			setCaretPosition(getDocument().getLength());
338		}
339
340		String text = getText().substring(0,getSelectionStart());
341		if(text == null)
342		{
343			historyPrevious();
344			return;
345		}
346
347		for(int i = index + 1; i < historyModel.getSize(); i++)
348		{
349			String item = historyModel.getItem(i);
350			if(item.startsWith(text))
351			{
352				replaceSelection(item.substring(text.length()));
353				select(text.length(),getDocument().getLength());
354				index = i;
355				return;
356			}
357		}
358
359		getToolkit().beep();
360	} //}}}
361
362	//{{{ doForwardSearch() method
363	private void doForwardSearch()
364	{
365		if(historyModel == null)
366			return;
367
368		if(getSelectionEnd() != getDocument().getLength())
369		{
370			setCaretPosition(getDocument().getLength());
371		}
372
373		String text = getText().substring(0,getSelectionStart());
374		if(text == null)
375		{
376			historyNext();
377			return;
378		}
379
380		for(int i = index - 1; i >= 0; i--)
381		{
382			String item = historyModel.getItem(i);
383			if(item.startsWith(text))
384			{
385				replaceSelection(item.substring(text.length()));
386				select(text.length(),getDocument().getLength());
387				index = i;
388				return;
389			}
390		}
391
392		getToolkit().beep();
393	} //}}}
394
395	//{{{ historyPrevious() method
396	private void historyPrevious()
397	{
398		if(historyModel == null)
399			return;
400
401		if(index == historyModel.getSize() - 1)
402			getToolkit().beep();
403		else if(index == -1)
404		{
405			current = getText();
406			setText(historyModel.getItem(0));
407			index = 0;
408		}
409		else
410		{
411			// have to do this because setText() sets index to -1
412			int newIndex = index + 1;
413			setText(historyModel.getItem(newIndex));
414			index = newIndex;
415		}
416	} //}}}
417
418	//{{{ historyNext() method
419	private void historyNext()
420	{
421		if(historyModel == null)
422			return;
423
424		if(index == -1)
425			getToolkit().beep();
426		else if(index == 0)
427			setText(current);
428		else
429		{
430			// have to do this because setText() sets index to -1
431			int newIndex = index - 1;
432			setText(historyModel.getItem(newIndex));
433			index = newIndex;
434		}
435	} //}}}
436
437	//{{{ showPopupMenu() method
438	private void showPopupMenu(String text, int x, int y)
439	{
440		if(historyModel == null)
441			return;
442
443		requestFocus();
444
445		if(popup != null && popup.isVisible())
446		{
447			popup.setVisible(false);
448			return;
449		}
450
451		ActionHandler actionListener = new ActionHandler();
452
453		popup = new JPopupMenu();
454		JMenuItem caption = new JMenuItem(jEdit.getProperty(
455			"history.caption"));
456		caption.getModel().setEnabled(false);
457 		popup.add(caption);
458 		popup.addSeparator();
459
460		for(int i = 0; i < historyModel.getSize(); i++)
461		{
462			String item = historyModel.getItem(i);
463			if(item.startsWith(text))
464			{
465				JMenuItem menuItem = new JMenuItem(item);
466				menuItem.setActionCommand(String.valueOf(i));
467				menuItem.addActionListener(actionListener);
468				popup.add(menuItem);
469			}
470		}
471
472		GUIUtilities.showPopupMenu(popup,this,x,y);
473	} //}}}
474
475	//}}}
476
477	//{{{ ActionHandler class
478	class ActionHandler implements ActionListener
479	{
480		public void actionPerformed(ActionEvent evt)
481		{
482			int ind = Integer.parseInt(evt.getActionCommand());
483			if(ind == -1)
484			{
485				if(index != -1)
486					setText(current);
487			}
488			else
489			{
490				setText(historyModel.getItem(ind));
491				index = ind;
492			}
493			if(instantPopups)
494			{
495				addCurrentToHistory();
496				fireActionPerformed();
497			}
498		}
499	} //}}}
500
501	//{{{ FocusHandler class
502	class FocusHandler extends FocusAdapter
503	{
504		public void focusGained(FocusEvent evt)
505		{
506			if(selectAllOnFocus)
507			{
508				selectAll();
509				focusClickFlag = true;
510			}
511		}
512	} //}}}
513
514	//{{{ MouseHandler class
515	class MouseHandler extends MouseMotionAdapter
516	{
517		//{{{ mouseMoved() method
518		public void mouseMoved(MouseEvent evt)
519		{
520			Border border = getBorder();
521			Insets insets = border.getBorderInsets(HistoryTextField.this);
522
523			if(evt.getX() >= getWidth() - insets.right)
524				setCursor(Cursor.getDefaultCursor());
525			else
526				setCursor(Cursor.getPredefinedCursor(
527					Cursor.TEXT_CURSOR));
528		} //}}}
529
530		//{{{ mouseDragged() method
531		public void mouseDragged(MouseEvent evt)
532		{
533			if(focusClickFlag)
534			{
535				// unselect if user starts dragging so they can
536				// more easily make a selection
537				setCaretPosition(getCaretPosition());
538				focusClickFlag = false;
539			}
540		} //}}}
541	} //}}}
542
543	//{{{ HistoryBorder class
544	static class HistoryBorder extends AbstractBorder
545	{
546		static final int WIDTH = 16;
547
548		public void paintBorder(Component c, Graphics g,
549			int x, int y, int w, int h)
550		{
551			g.translate(x+w-WIDTH,y-1);
552
553			//if(c.isEnabled())
554			//{
555			//	// vertical separation line
556			//	g.setColor(UIManager.getColor("controlDkShadow"));
557			//	g.drawLine(0,0,0,h);
558			//}
559
560			// down arrow
561			int w2 = WIDTH/2;
562			int h2 = h/2;
563			g.setColor(UIManager.getColor(c.isEnabled()
564				&& ((HistoryTextField)c).getModel() != null
565				? "Menu.foreground" : "Menu.disabledForeground"));
566			g.drawLine(w2-5,h2-2,w2+4,h2-2);
567			g.drawLine(w2-4,h2-1,w2+3,h2-1);
568			g.drawLine(w2-3,h2  ,w2+2,h2  );
569			g.drawLine(w2-2,h2+1,w2+1,h2+1);
570			g.drawLine(w2-1,h2+2,w2  ,h2+2);
571
572			g.translate(-(x+w-WIDTH),-(y-1));
573		}
574
575		public Insets getBorderInsets(Component c)
576		{
577			return new Insets(0,0,0,WIDTH);
578		}
579	} //}}}
580}