PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-1-pre5/org/gjt/sp/jedit/gui/GrabKeyDialog.java

#
Java | 550 lines | 358 code | 68 blank | 124 comment | 99 complexity | 745a33b1a7c54d0638229ecd0ad751fb 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. * GrabKeyDialog.java - Grabs keys from the keyboard
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2001, 2002 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 javax.swing.border.*;
  25. import javax.swing.*;
  26. import java.awt.event.*;
  27. import java.awt.*;
  28. import java.lang.reflect.Field;
  29. import java.util.*;
  30. import org.gjt.sp.jedit.*;
  31. import org.gjt.sp.util.Log;
  32. //}}}
  33. /**
  34. * A dialog for getting shortcut keys.
  35. */
  36. public class GrabKeyDialog extends JDialog
  37. {
  38. //{{{ keyboardTest() method
  39. public static void keyboardTest(View view)
  40. {
  41. Buffer buffer = jEdit.newFile(view);
  42. new GrabKeyDialog(view,null,null,buffer);
  43. } //}}}
  44. //{{{ GrabKeyDialog constructor
  45. /**
  46. * Create and show a new modal dialog.
  47. *
  48. * @param comp center dialog on this component.
  49. * @param binding the action/macro that should get a binding.
  50. * @param allBindings all other key bindings.
  51. */
  52. public GrabKeyDialog(Component comp, KeyBinding binding,
  53. Vector allBindings)
  54. {
  55. this(comp,binding,allBindings,null);
  56. } //}}}
  57. //{{{ GrabKeyDialog constructor
  58. /**
  59. * Create and show a new modal dialog.
  60. *
  61. * @param comp center dialog on this component.
  62. * @param debugBuffer debug info will be dumped to this buffer
  63. * (may be null)
  64. */
  65. public GrabKeyDialog(Component comp, Buffer debugBuffer)
  66. {
  67. this(comp,null,null,debugBuffer);
  68. } //}}}
  69. //{{{ GrabKeyDialog constructor
  70. /**
  71. * Create and show a new modal dialog.
  72. *
  73. * @param comp center dialog on this component.
  74. * @param binding the action/macro that should get a binding.
  75. * @param allBindings all other key bindings.
  76. * @param debugBuffer debug info will be dumped to this buffer
  77. * (may be null)
  78. */
  79. public GrabKeyDialog(Component comp, KeyBinding binding,
  80. Vector allBindings, Buffer debugBuffer)
  81. {
  82. super(JOptionPane.getFrameForComponent(comp),
  83. jEdit.getProperty("grab-key.title"),true);
  84. this.binding = binding;
  85. this.allBindings = allBindings;
  86. this.debugBuffer = debugBuffer;
  87. enableEvents(AWTEvent.KEY_EVENT_MASK);
  88. // create a panel with a BoxLayout. Can't use Box here
  89. // because Box doesn't have setBorder().
  90. JPanel content = new JPanel(new GridLayout(0,1,0,6))
  91. {
  92. /**
  93. * Returns if this component can be traversed by pressing the
  94. * Tab key. This returns false.
  95. */
  96. public boolean isManagingFocus()
  97. {
  98. return false;
  99. }
  100. /**
  101. * Makes the tab key work in Java 1.4.
  102. * @since jEdit 3.2pre4
  103. */
  104. public boolean getFocusTraversalKeysEnabled()
  105. {
  106. return false;
  107. }
  108. };
  109. content.setBorder(new EmptyBorder(12,12,12,12));
  110. setContentPane(content);
  111. JLabel label = new JLabel(
  112. debugBuffer == null ? jEdit.getProperty(
  113. "grab-key.caption",new String[] { binding.label })
  114. : jEdit.getProperty("grab-key.keyboard-test"));
  115. Box input = Box.createHorizontalBox();
  116. shortcut = new InputPane();
  117. input.add(shortcut);
  118. input.add(Box.createHorizontalStrut(12));
  119. clear = new JButton(jEdit.getProperty("grab-key.clear"));
  120. clear.addActionListener(new ActionHandler());
  121. input.add(clear);
  122. assignedTo = new JLabel();
  123. if(debugBuffer == null)
  124. updateAssignedTo(null);
  125. Box buttons = Box.createHorizontalBox();
  126. buttons.add(Box.createGlue());
  127. if(debugBuffer == null)
  128. {
  129. ok = new JButton(jEdit.getProperty("common.ok"));
  130. ok.addActionListener(new ActionHandler());
  131. buttons.add(ok);
  132. buttons.add(Box.createHorizontalStrut(12));
  133. if(binding.isAssigned()) {
  134. // show "remove" button
  135. remove = new JButton(jEdit.getProperty("grab-key.remove"));
  136. remove.addActionListener(new ActionHandler());
  137. buttons.add(remove);
  138. buttons.add(Box.createHorizontalStrut(12));
  139. }
  140. }
  141. cancel = new JButton(jEdit.getProperty("common.cancel"));
  142. cancel.addActionListener(new ActionHandler());
  143. buttons.add(cancel);
  144. buttons.add(Box.createGlue());
  145. content.add(label);
  146. content.add(input);
  147. if(debugBuffer == null)
  148. content.add(assignedTo);
  149. content.add(buttons);
  150. setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  151. pack();
  152. setLocationRelativeTo(comp);
  153. setResizable(false);
  154. show();
  155. } //}}}
  156. //{{{ getShortcut() method
  157. /**
  158. * Returns the shortcut, or null if the current shortcut should be
  159. * removed or the dialog either has been cancelled. Use isOK()
  160. * to determine if the latter is true.
  161. */
  162. public String getShortcut()
  163. {
  164. if(isOK)
  165. return shortcut.getText();
  166. else
  167. return null;
  168. } //}}}
  169. //{{{ isOK() method
  170. /**
  171. * Returns true, if the dialog has not been cancelled.
  172. * @since jEdit 3.2pre9
  173. */
  174. public boolean isOK()
  175. {
  176. return isOK;
  177. } //}}}
  178. //{{{ isManagingFocus() method
  179. /**
  180. * Returns if this component can be traversed by pressing the
  181. * Tab key. This returns false.
  182. */
  183. public boolean isManagingFocus()
  184. {
  185. return false;
  186. } //}}}
  187. //{{{ getFocusTraversalKeysEnabled() method
  188. /**
  189. * Makes the tab key work in Java 1.4.
  190. * @since jEdit 3.2pre4
  191. */
  192. public boolean getFocusTraversalKeysEnabled()
  193. {
  194. return false;
  195. } //}}}
  196. //{{{ processKeyEvent() method
  197. protected void processKeyEvent(KeyEvent evt)
  198. {
  199. shortcut.processKeyEvent(evt);
  200. } //}}}
  201. //{{{ Private members
  202. //{{{ Instance variables
  203. private InputPane shortcut; // this is a bad hack
  204. private JLabel assignedTo;
  205. private JButton ok;
  206. private JButton remove;
  207. private JButton cancel;
  208. private JButton clear;
  209. private boolean isOK;
  210. private KeyBinding binding;
  211. private Vector allBindings;
  212. private Buffer debugBuffer;
  213. //}}}
  214. //{{{ getSymbolicName() method
  215. private String getSymbolicName(int keyCode)
  216. {
  217. if(keyCode == KeyEvent.VK_UNDEFINED)
  218. return null;
  219. /* else if(keyCode == KeyEvent.VK_OPEN_BRACKET)
  220. return "[";
  221. else if(keyCode == KeyEvent.VK_CLOSE_BRACKET)
  222. return "]"; */
  223. if(keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z)
  224. return String.valueOf(Character.toLowerCase((char)keyCode));
  225. try
  226. {
  227. Field[] fields = KeyEvent.class.getFields();
  228. for(int i = 0; i < fields.length; i++)
  229. {
  230. Field field = fields[i];
  231. String name = field.getName();
  232. if(name.startsWith("VK_")
  233. && field.getInt(null) == keyCode)
  234. {
  235. return name.substring(3);
  236. }
  237. }
  238. }
  239. catch(Exception e)
  240. {
  241. Log.log(Log.ERROR,this,e);
  242. }
  243. return null;
  244. } //}}}
  245. //{{{ updateAssignedTo() method
  246. private void updateAssignedTo(String shortcut)
  247. {
  248. String text = jEdit.getProperty("grab-key.assigned-to.none");
  249. KeyBinding kb = getKeyBinding(shortcut);
  250. if(kb != null)
  251. if(kb.isPrefix)
  252. text = jEdit.getProperty(
  253. "grab-key.assigned-to.prefix",
  254. new String[] { shortcut });
  255. else
  256. text = kb.label;
  257. if(ok != null)
  258. ok.setEnabled(kb == null || !kb.isPrefix);
  259. assignedTo.setText(
  260. jEdit.getProperty("grab-key.assigned-to",
  261. new String[] { text }));
  262. } //}}}
  263. //{{{ getKeyBinding() method
  264. private KeyBinding getKeyBinding(String shortcut)
  265. {
  266. if(shortcut == null || shortcut.length() == 0)
  267. return null;
  268. String spacedShortcut = shortcut + " ";
  269. Enumeration enum = allBindings.elements();
  270. while(enum.hasMoreElements())
  271. {
  272. KeyBinding kb = (KeyBinding)enum.nextElement();
  273. if(!kb.isAssigned())
  274. continue;
  275. String spacedKbShortcut = kb.shortcut + " ";
  276. // eg, trying to bind C+n C+p if C+n already bound
  277. if(spacedShortcut.startsWith(spacedKbShortcut))
  278. return kb;
  279. // eg, trying to bind C+e if C+e is a prefix
  280. if(spacedKbShortcut.startsWith(spacedShortcut))
  281. {
  282. // create a temporary (synthetic) prefix
  283. // KeyBinding, that won't be saved
  284. return new KeyBinding(kb.name,kb.label,
  285. shortcut,true);
  286. }
  287. }
  288. return null;
  289. } //}}}
  290. //}}}
  291. //{{{ KeyBinding class
  292. /**
  293. * A jEdit action or macro with its two possible shortcuts.
  294. * @since jEdit 3.2pre8
  295. */
  296. public static class KeyBinding
  297. {
  298. public KeyBinding(String name, String label,
  299. String shortcut, boolean isPrefix)
  300. {
  301. this.name = name;
  302. this.label = label;
  303. this.shortcut = shortcut;
  304. this.isPrefix = isPrefix;
  305. }
  306. public String name;
  307. public String label;
  308. public String shortcut;
  309. public boolean isPrefix;
  310. public boolean isAssigned()
  311. {
  312. return shortcut != null && shortcut.length() > 0;
  313. }
  314. } //}}}
  315. //{{{ InputPane class
  316. class InputPane extends JTextField
  317. {
  318. //{{{ getFocusTraversalKeysEnabled() method
  319. /**
  320. * Makes the tab key work in Java 1.4.
  321. * @since jEdit 3.2pre4
  322. */
  323. public boolean getFocusTraversalKeysEnabled()
  324. {
  325. return false;
  326. } //}}}
  327. //{{{ processKeyEvent() method
  328. protected void processKeyEvent(KeyEvent _evt)
  329. {
  330. KeyEvent evt = KeyEventWorkaround.processKeyEvent(_evt);
  331. if(evt == null)
  332. {
  333. if(debugBuffer != null)
  334. {
  335. debugBuffer.insert(debugBuffer.getLength(),
  336. "Event " + _evt + " filtered\n");
  337. }
  338. return;
  339. }
  340. else
  341. {
  342. if(debugBuffer != null)
  343. {
  344. debugBuffer.insert(debugBuffer.getLength(),
  345. "Event " + _evt + " passed\n");
  346. }
  347. }
  348. evt.consume();
  349. StringBuffer keyString = new StringBuffer(getText());
  350. if(getDocument().getLength() != 0)
  351. keyString.append(' ');
  352. if(evt.getID() == KeyEvent.KEY_TYPED)
  353. {
  354. if(!Character.isLetterOrDigit(evt.getKeyChar()))
  355. return;
  356. keyString.append(evt.getKeyChar());
  357. }
  358. else if(evt.getID() == KeyEvent.KEY_PRESSED)
  359. {
  360. String modifiers = DefaultInputHandler
  361. .getModifierString(evt);
  362. if(modifiers.length() != 0)
  363. {
  364. keyString.append(modifiers);
  365. keyString.append('+');
  366. }
  367. int keyCode = evt.getKeyCode();
  368. if(((keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z)
  369. || (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9))
  370. && modifiers.length() == 0)
  371. {
  372. // will be handled by KEY_TYPED
  373. return;
  374. }
  375. String symbolicName = getSymbolicName(keyCode);
  376. if(symbolicName == null)
  377. return;
  378. keyString.append(symbolicName);
  379. }
  380. else if(evt.getID() == KeyEvent.KEY_RELEASED)
  381. return;
  382. setText(keyString.toString());
  383. if(debugBuffer == null)
  384. updateAssignedTo(keyString.toString());
  385. } //}}}
  386. } //}}}
  387. //{{{ ActionHandler class
  388. class ActionHandler implements ActionListener
  389. {
  390. //{{{ actionPerformed() method
  391. public void actionPerformed(ActionEvent evt)
  392. {
  393. if(evt.getSource() == ok)
  394. {
  395. if(canClose())
  396. dispose();
  397. }
  398. else if(evt.getSource() == remove)
  399. {
  400. shortcut.setText(null);
  401. isOK = true;
  402. dispose();
  403. }
  404. else if(evt.getSource() == cancel)
  405. dispose();
  406. else if(evt.getSource() == clear)
  407. {
  408. shortcut.setText(null);
  409. if(debugBuffer == null)
  410. updateAssignedTo(null);
  411. }
  412. } //}}}
  413. //{{{ canClose() method
  414. private boolean canClose()
  415. {
  416. String shortcutString = shortcut.getText();
  417. if(shortcutString.length() == 0
  418. && binding.isAssigned())
  419. {
  420. // ask whether to remove the old shortcut
  421. int answer = GUIUtilities.confirm(
  422. GrabKeyDialog.this,
  423. "grab-key.remove-ask",
  424. null,
  425. JOptionPane.YES_NO_CANCEL_OPTION,
  426. JOptionPane.QUESTION_MESSAGE);
  427. if(answer == JOptionPane.YES_OPTION)
  428. {
  429. shortcut.setText(null);
  430. isOK = true;
  431. }
  432. else if(answer == JOptionPane.CANCEL_OPTION)
  433. return false;
  434. return true;
  435. }
  436. // check whether this shortcut already exists
  437. KeyBinding other = getKeyBinding(shortcutString);
  438. if(other == null || other == binding)
  439. {
  440. isOK = true;
  441. return true;
  442. }
  443. // check whether the other shortcut is the alt. shortcut
  444. if(other.name == binding.name)
  445. {
  446. // we don't need two identical shortcuts
  447. GUIUtilities.error(GrabKeyDialog.this,
  448. "grab-key.duplicate-alt-shortcut",
  449. null);
  450. return false;
  451. }
  452. // check whether shortcut is a prefix to others
  453. if(other.isPrefix)
  454. {
  455. // can't override prefix shortcuts
  456. GUIUtilities.error(GrabKeyDialog.this,
  457. "grab-key.prefix-shortcut",
  458. null);
  459. return false;
  460. }
  461. // ask whether to override that other shortcut
  462. int answer = GUIUtilities.confirm(GrabKeyDialog.this,
  463. "grab-key.duplicate-shortcut",
  464. new Object[] { other.label },
  465. JOptionPane.YES_NO_CANCEL_OPTION,
  466. JOptionPane.QUESTION_MESSAGE);
  467. if(answer == JOptionPane.YES_OPTION)
  468. {
  469. if(other.shortcut != null
  470. && shortcutString.startsWith(other.shortcut))
  471. {
  472. other.shortcut = null;
  473. }
  474. isOK = true;
  475. return true;
  476. }
  477. else if(answer == JOptionPane.CANCEL_OPTION)
  478. return false;
  479. return true;
  480. } //}}}
  481. } //}}}
  482. }