PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

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

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