PageRenderTime 64ms CodeModel.GetById 25ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

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

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