Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/gjt/sp/jedit/gui/HistoryTextField.java


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  
23  package org.gjt.sp.jedit.gui;
24  
25  //{{{ Imports
26  import javax.swing.*;
27  import javax.swing.border.Border;
28  import javax.swing.border.AbstractBorder;
29  import javax.swing.border.CompoundBorder;
30  import javax.swing.event.MouseInputAdapter;
31  import java.awt.*;
32  import java.awt.event.*;
33  import 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,v 1.11 2003/11/12 00:24:11 spestov Exp $
40   */
41  public 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   //{{{ getModel() method
170   /**
171    * Returns the underlying history model.
172    */
173   public HistoryModel getModel()
174   {
175     return historyModel;
176   } //}}}
177 
178   //{{{ setModel() method
179   /**
180    * Sets the history list model.
181    * @param name The model name
182    * @since jEdit 2.3pre3
183    */
184   public void setModel(String name)
185   {
186     Border textFieldBorder = UIManager.getBorder("TextField.border");
187 
188     if(name == null)
189     {
190       historyModel = null;
191       if(textFieldBorder != null)
192         setBorder(textFieldBorder);
193     }
194     else
195     {
196       historyModel = HistoryModel.getModel(name);
197       if(textFieldBorder != null)
198       {
199         setBorder(new CompoundBorder(textFieldBorder,
200           new HistoryBorder()));
201       }
202     }
203     index = -1;
204     repaint();
205   } //}}}
206 
207   //{{{ addCurrentToHistory() method
208   /**
209    * Adds the currently entered item to the history.
210    */
211   public void addCurrentToHistory()
212   {
213     if(historyModel != null)
214       historyModel.addItem(getText());
215     index = 0;
216   } //}}}
217 
218   //{{{ setText() method
219   /**
220    * Sets the displayed text.
221    */
222   public void setText(String text)
223   {
224     super.setText(text);
225     index = -1;
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 }