PageRenderTime 133ms CodeModel.GetById 20ms RepoModel.GetById 2ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/gui/ActionBar.java

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