PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/gui/GrabKeyDialog.java

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