PageRenderTime 192ms CodeModel.GetById 174ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/gui/HistoryTextField.java

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