PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

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

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