PageRenderTime 132ms CodeModel.GetById 97ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 576 lines | 445 code | 59 blank | 72 comment | 100 complexity | 836bdba11eeeaea202fad27e4218b557 MD5 | raw file
  1/*
  2 * ActionBar.java - For invoking actions directly
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2003 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 bsh.NameSpace;
 27import java.awt.event.*;
 28import java.awt.*;
 29import java.util.ArrayList;
 30import java.util.Arrays;
 31import javax.swing.event.*;
 32import javax.swing.*;
 33import org.gjt.sp.jedit.*;
 34//}}}
 35
 36/**
 37 * Action invocation bar.
 38 */
 39public class ActionBar extends JPanel
 40{
 41	//{{{ ActionBar constructor
 42	public ActionBar(final View view, boolean temp)
 43	{
 44		setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
 45
 46		this.view = view;
 47		this.temp = temp;
 48
 49		add(Box.createHorizontalStrut(2));
 50
 51		JLabel label = new JLabel(jEdit.getProperty("view.action.prompt"));
 52		add(label);
 53		add(Box.createHorizontalStrut(12));
 54		add(action = new ActionTextField());
 55		action.setEnterAddsToHistory(false);
 56		Dimension max = action.getPreferredSize();
 57		max.width = Integer.MAX_VALUE;
 58		action.setMaximumSize(max);
 59		action.addActionListener(new ActionHandler());
 60		action.getDocument().addDocumentListener(new DocumentHandler());
 61
 62		if(temp)
 63		{
 64			close = new RolloverButton(GUIUtilities.loadIcon("closebox.gif"));
 65			close.addActionListener(new ActionHandler());
 66			close.setToolTipText(jEdit.getProperty(
 67				"view.action.close-tooltip"));
 68			add(close);
 69		}
 70
 71		// if 'temp' is true, hide search bar after user is done with it
 72		this.temp = temp;
 73	} //}}}
 74
 75	//{{{ getField() method
 76	public HistoryTextField getField()
 77	{
 78		return action;
 79	} //}}}
 80
 81	//{{{ goToActionBar() method
 82	public void goToActionBar()
 83	{
 84		repeatCount = view.getInputHandler().getRepeatCount();
 85		action.setText(null);
 86		action.requestFocus();
 87	} //}}}
 88
 89	//{{{ actionListChanged()
 90	/**
 91	 * Called when plugins are added or removed to notify the action bar
 92	 * that the action list has changed.
 93	 * @since jEdit 4.2pre2
 94	 */
 95	public void actionListChanged()
 96	{
 97		actions = null;
 98	} //}}}
 99
100	//{{{ Private members
101
102	private static NameSpace namespace = new NameSpace(
103		BeanShell.getNameSpace(),"action bar namespace");
104
105	//{{{ Instance variables
106	private View view;
107	private boolean temp;
108	private int repeatCount;
109	private HistoryTextField action;
110	private CompletionPopup popup;
111	private RolloverButton close;
112	private String[] actions;
113	//}}}
114
115	//{{{ initActions() method
116	private void initActions()
117	{
118		if(actions != null)
119			return;
120
121		actions = jEdit.getActionNames();
122		Arrays.sort(actions,new MiscUtilities.StringICaseCompare());
123	} //}}}
124
125	//{{{ invoke() method
126	private void invoke()
127	{
128		String cmd;
129		if(popup != null)
130			cmd = popup.list.getSelectedValue().toString();
131		else
132		{
133			cmd = action.getText().trim();
134			int index = cmd.indexOf('=');
135			if(index != -1)
136			{
137				action.addCurrentToHistory();
138				String propName = cmd.substring(0,index).trim();
139				String propValue = cmd.substring(index + 1).trim();
140				String code;
141				/* construct a BeanShell snippet instead of
142				 * invoking directly so that user can record
143				 * property changes in macros. */
144				if(propName.startsWith("buffer."))
145				{
146					if(propName.equals("buffer.mode"))
147					{
148						code = "buffer.setMode(\""
149							+ MiscUtilities.charsToEscapes(
150							propValue) + "\");";
151					}
152					else
153					{
154						code = "buffer.setStringProperty(\""
155							+ MiscUtilities.charsToEscapes(
156							propName.substring("buffer.".length())
157							) + "\",\""
158							+ MiscUtilities.charsToEscapes(
159							propValue) + "\");";
160					}
161
162					code = code + "\nbuffer.propertiesChanged();";
163				}
164				else if(propName.startsWith("!buffer."))
165				{
166					code = "jEdit.setProperty(\""
167						+ MiscUtilities.charsToEscapes(
168						propName.substring(1)) + "\",\""
169						+ MiscUtilities.charsToEscapes(
170						propValue) + "\");\n"
171						+ "jEdit.propertiesChanged();";
172				}
173				else
174				{
175					code = "jEdit.setProperty(\""
176						+ MiscUtilities.charsToEscapes(
177						propName) + "\",\""
178						+ MiscUtilities.charsToEscapes(
179						propValue) + "\");\n"
180						+ "jEdit.propertiesChanged();"
181						+ "EditBus.send(new DockableWindowUpdate(wm,"
182						+ "DockableWindowUpdate."
183						+ "PROPERTIES_CHANGED,null));";
184				}
185
186				Macros.Recorder recorder = view.getMacroRecorder();
187				if(recorder != null)
188					recorder.record(code);
189				BeanShell.eval(view,namespace,code);
190				cmd = null;
191			}
192			else if(cmd.length() != 0)
193			{
194				String[] completions = getCompletions(cmd);
195				if(completions.length != 0)
196				{
197					cmd = completions[0];
198				}
199			}
200			else
201				cmd = null;
202		}
203
204		if(popup != null)
205		{
206			popup.dispose();
207			popup = null;
208		}
209
210		final String finalCmd = cmd;
211		final EditAction act = (finalCmd == null ? null : jEdit.getAction(finalCmd));
212		if(temp)
213			view.removeToolBar(ActionBar.this);
214
215		SwingUtilities.invokeLater(new Runnable()
216		{
217			public void run()
218			{
219				view.getTextArea().requestFocus();
220				if(act == null)
221				{
222					if(finalCmd != null)
223					{
224						view.getStatus().setMessageAndClear(
225							jEdit.getProperty(
226							"view.action.no-completions"));
227					}
228				}
229				else
230				{
231					view.getInputHandler().setRepeatCount(repeatCount);
232					view.getInputHandler().invokeAction(act);
233				}
234			}
235		});
236	} //}}}
237
238	//{{{ getCompletions() method
239	private String[] getCompletions(String str)
240	{
241		initActions();
242
243		str = str.toLowerCase();
244		ArrayList returnValue = new ArrayList(actions.length);
245		for(int i = 0; i < actions.length; i++)
246		{
247			if(actions[i].toLowerCase().indexOf(str) != -1)
248				returnValue.add(actions[i]);
249		}
250
251		return (String[])returnValue.toArray(new String[returnValue.size()]);
252	} //}}}
253
254	//{{{ complete() method
255	private void complete(boolean insertLongestPrefix)
256	{
257		String text = action.getText().trim();
258		String[] completions = getCompletions(text);
259		if(completions.length == 1)
260		{
261			if(insertLongestPrefix)
262				action.setText(completions[0]);
263		}
264		else if(completions.length != 0)
265		{
266			if(insertLongestPrefix)
267			{
268				String prefix = MiscUtilities.getLongestPrefix(
269					completions,true);
270				if(prefix.indexOf(text) != -1)
271					action.setText(prefix);
272			}
273
274			if(popup != null)
275				popup.setModel(completions);
276			else
277				popup = new CompletionPopup(completions);
278			return;
279		}
280
281		if(popup != null)
282		{
283			popup.dispose();
284			popup = null;
285		}
286	} //}}}
287
288	//}}}
289
290	//{{{ Inner classes
291
292	//{{{ ActionHandler class
293	class ActionHandler implements ActionListener
294	{
295		public void actionPerformed(ActionEvent evt)
296		{
297			if(evt.getSource() == close)
298				view.removeToolBar(ActionBar.this);
299			else
300				invoke();
301		}
302	} //}}}
303
304	//{{{ DocumentHandler class
305	class DocumentHandler implements DocumentListener
306	{
307		//{{{ insertUpdate() method
308		public void insertUpdate(DocumentEvent evt)
309		{
310			if(popup != null)
311				complete(false);
312		} //}}}
313
314		//{{{ removeUpdate() method
315		public void removeUpdate(DocumentEvent evt)
316		{
317			if(popup != null)
318				complete(false);
319		} //}}}
320
321		//{{{ changedUpdate() method
322		public void changedUpdate(DocumentEvent evt) {}
323		//}}}
324	} //}}}
325
326	//{{{ ActionTextField class
327	class ActionTextField extends HistoryTextField
328	{
329		boolean repeat;
330		boolean nonDigit;
331
332		ActionTextField()
333		{
334			super("action");
335			setSelectAllOnFocus(true);
336		}
337
338		public boolean isManagingFocus()
339		{
340			return false;
341		}
342
343		public boolean getFocusTraversalKeysEnabled()
344		{
345			return false;
346		}
347
348		public void processKeyEvent(KeyEvent evt)
349		{
350			evt = KeyEventWorkaround.processKeyEvent(evt);
351			if(evt == null)
352				return;
353
354			switch(evt.getID())
355			{
356			case KeyEvent.KEY_TYPED:
357				char ch = evt.getKeyChar();
358				if(!nonDigit && Character.isDigit(ch))
359				{
360					super.processKeyEvent(evt);
361					repeat = true;
362					repeatCount = Integer.parseInt(action.getText());
363				}
364				else
365				{
366					nonDigit = true;
367					if(repeat)
368						passToView(evt);
369					else
370						super.processKeyEvent(evt);
371				}
372				break;
373			case KeyEvent.KEY_PRESSED:
374				int keyCode = evt.getKeyCode();
375				if(evt.isActionKey()
376					|| evt.isControlDown()
377					|| evt.isAltDown()
378					|| evt.isMetaDown()
379					|| keyCode == KeyEvent.VK_BACK_SPACE
380					|| keyCode == KeyEvent.VK_DELETE
381					|| keyCode == KeyEvent.VK_ENTER
382					|| keyCode == KeyEvent.VK_TAB
383					|| keyCode == KeyEvent.VK_ESCAPE)
384				{
385					nonDigit = true;
386					if(repeat)
387					{
388						passToView(evt);
389						break;
390					}
391					else if(keyCode == KeyEvent.VK_TAB)
392					{
393						complete(true);
394						evt.consume();
395					}
396					else if(keyCode == KeyEvent.VK_ESCAPE)
397					{
398						evt.consume();
399						if(popup != null)
400						{
401							popup.dispose();
402							popup = null;
403							action.requestFocus();
404						}
405						else
406						{
407							if(temp)
408								view.removeToolBar(ActionBar.this);
409							view.getEditPane().focusOnTextArea();
410						}
411						break;
412					}
413					else if((keyCode == KeyEvent.VK_UP
414						|| keyCode == KeyEvent.VK_DOWN)
415						&& popup != null)
416					{
417						popup.list.processKeyEvent(evt);
418						break;
419					}
420				}
421				super.processKeyEvent(evt);
422				break;
423			}
424		}
425
426		private void passToView(final KeyEvent evt)
427		{
428			if(temp)
429				view.removeToolBar(ActionBar.this);
430			SwingUtilities.invokeLater(new Runnable()
431			{
432				public void run()
433				{
434					view.getTextArea().requestFocus();
435					view.getInputHandler().setRepeatCount(repeatCount);
436					view.getInputHandler().processKeyEvent(evt);
437				}
438			});
439		}
440
441		public void addNotify()
442		{
443			super.addNotify();
444			repeat = nonDigit = false;
445		}
446	} //}}}
447
448	//{{{ CompletionPopup class
449	class CompletionPopup extends JWindow
450	{
451		CompletionList list;
452
453		//{{{ CompletionPopup constructor
454		CompletionPopup(String[] actions)
455		{
456			super(view);
457
458			setContentPane(new JPanel(new BorderLayout())
459			{
460				/**
461				 * Returns if this component can be traversed by pressing the
462				 * Tab key. This returns false.
463				 */
464				public boolean isManagingFocus()
465				{
466					return false;
467				}
468
469				/**
470				 * Makes the tab key work in Java 1.4.
471				 */
472				public boolean getFocusTraversalKeysEnabled()
473				{
474					return false;
475				}
476			});
477
478			list = new CompletionList(actions);
479			list.setVisibleRowCount(8);
480			list.addMouseListener(new MouseHandler());
481			list.setSelectedIndex(0);
482			list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
483
484			// stupid scrollbar policy is an attempt to work around
485			// bugs people have been seeing with IBM's JDK -- 7 Sep 2000
486			JScrollPane scroller = new JScrollPane(list,
487				JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
488				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
489
490			getContentPane().add(scroller, BorderLayout.CENTER);
491
492			GUIUtilities.requestFocus(this,list);
493
494			pack();
495			Point p = new Point(0,-getHeight());
496			SwingUtilities.convertPointToScreen(p,action);
497			setLocation(p);
498			show();
499
500			KeyHandler keyHandler = new KeyHandler();
501			addKeyListener(keyHandler);
502			list.addKeyListener(keyHandler);
503		} //}}}
504
505		//{{{ setModel() method
506		void setModel(String[] actions)
507		{
508			list.setListData(actions);
509			list.setSelectedIndex(0);
510		} //}}}
511
512		//{{{ MouseHandler class
513		class MouseHandler extends MouseAdapter
514		{
515			public void mouseClicked(MouseEvent evt)
516			{
517				invoke();
518			}
519		} //}}}
520
521		//{{{ CompletionList class
522		class CompletionList extends JList
523		{
524			CompletionList(Object[] data)
525			{
526				super(data);
527			}
528
529			// we need this public not protected
530			public void processKeyEvent(KeyEvent evt)
531			{
532				super.processKeyEvent(evt);
533			}
534		} //}}}
535
536		//{{{ KeyHandler class
537		class KeyHandler extends KeyAdapter
538		{
539			public void keyTyped(KeyEvent evt)
540			{
541				action.processKeyEvent(evt);
542			}
543
544			public void keyPressed(KeyEvent evt)
545			{
546				int keyCode = evt.getKeyCode();
547				if(keyCode == KeyEvent.VK_ESCAPE)
548					action.processKeyEvent(evt);
549				else if(keyCode == KeyEvent.VK_ENTER)
550					invoke();
551				else if(keyCode == KeyEvent.VK_UP)
552				{
553					int selected = list.getSelectedIndex();
554					if(selected == 0)
555					{
556						list.setSelectedIndex(
557							list.getModel().getSize()
558							- 1);
559						evt.consume();
560					}
561				}
562				else if(keyCode == KeyEvent.VK_DOWN)
563				{
564					int selected = list.getSelectedIndex();
565					if(selected == list.getModel().getSize() - 1)
566					{
567						list.setSelectedIndex(0);
568						evt.consume();
569					}
570				}
571			}
572		} //}}}
573	} //}}}
574
575	//}}}
576}