PageRenderTime 91ms CodeModel.GetById 60ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/gui/ActionBar.java

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