PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 587 lines | 365 code | 71 blank | 151 comment | 78 complexity | facb0c67b739121bed988d2e77420370 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. * HistoryTextField.java - Text field with a history
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2000, 2001 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.*;
  25. import javax.swing.border.Border;
  26. import javax.swing.border.AbstractBorder;
  27. import javax.swing.border.CompoundBorder;
  28. import javax.swing.event.MouseInputAdapter;
  29. import java.awt.*;
  30. import java.awt.event.*;
  31. import org.gjt.sp.jedit.*;
  32. //}}}
  33. /**
  34. * Text field with an arrow-key accessable history.
  35. * @author Slava Pestov
  36. * @version $Id: HistoryTextField.java 4265 2002-06-18 06:56:00Z spestov $
  37. */
  38. public class HistoryTextField extends JTextField
  39. {
  40. //{{{ HistoryTextField constructor
  41. /**
  42. * Creates a new history text field.
  43. * @since jEdit 3.2pre5
  44. */
  45. public HistoryTextField()
  46. {
  47. this(null);
  48. } //}}}
  49. //{{{ HistoryTextField constructor
  50. /**
  51. * Creates a new history text field.
  52. * @param name The history model name
  53. */
  54. public HistoryTextField(String name)
  55. {
  56. this(name,false,true);
  57. } //}}}
  58. //{{{ HistoryTextField constructor
  59. /**
  60. * Creates a new history text field.
  61. * @param name The history model name
  62. * @param instantPopup If true, selecting a value from the history
  63. * popup will immediately fire an ActionEvent. If false, the user
  64. * will have to press 'Enter' first
  65. *
  66. * @since jEdit 2.2pre5
  67. */
  68. public HistoryTextField(String name, boolean instantPopups)
  69. {
  70. this(name,instantPopups,true);
  71. } //}}}
  72. //{{{ HistoryTextField constructor
  73. /**
  74. * Creates a new history text field.
  75. * @param name The history model name
  76. * @param instantPopups If true, selecting a value from the history
  77. * popup will immediately fire an ActionEvent. If false, the user
  78. * will have to press 'Enter' first
  79. * @param enterAddsToHistory If true, pressing the Enter key will
  80. * automatically add the currently entered text to the history.
  81. *
  82. * @since jEdit 2.6pre5
  83. */
  84. public HistoryTextField(String name, boolean instantPopups,
  85. boolean enterAddsToHistory)
  86. {
  87. setBorder(new CompoundBorder(getBorder(),new HistoryBorder()));
  88. if(name != null)
  89. historyModel = HistoryModel.getModel(name);
  90. MouseHandler mouseHandler = new MouseHandler();
  91. addMouseListener(mouseHandler);
  92. addMouseMotionListener(mouseHandler);
  93. this.instantPopups = instantPopups;
  94. this.enterAddsToHistory = enterAddsToHistory;
  95. index = -1;
  96. } //}}}
  97. //{{{ setInstantPopups() method
  98. /**
  99. * Sets if selecting a value from the popup should immediately fire
  100. * an ActionEvent.
  101. * @since jEdit 4.0pre3
  102. */
  103. public void setInstantPopups(boolean instantPopups)
  104. {
  105. this.instantPopups = instantPopups;
  106. } //}}}
  107. //{{{ getInstantPopups() method
  108. /**
  109. * Returns if selecting a value from the popup should immediately fire
  110. * an ActionEvent.
  111. * @since jEdit 4.0pre3
  112. */
  113. public boolean getInstantPopups()
  114. {
  115. return instantPopups;
  116. } //}}}
  117. //{{{ setEnterAddsToHistory() method
  118. /**
  119. * Sets if pressing Enter should automatically add the currently
  120. * entered text to the history.
  121. * @since jEdit 4.0pre3
  122. */
  123. public void setEnterAddsToHistory(boolean enterAddsToHistory)
  124. {
  125. this.enterAddsToHistory = enterAddsToHistory;
  126. } //}}}
  127. //{{{ getEnterAddsToHistory() method
  128. /**
  129. * Returns if pressing Enter should automatically add the currently
  130. * entered text to the history.
  131. * @since jEdit 4.0pre3
  132. */
  133. public boolean setEnterAddsToHistory()
  134. {
  135. return enterAddsToHistory;
  136. } //}}}
  137. //{{{ setSelectAllOnFocus() method
  138. /**
  139. * Sets if all text should be selected when the field gets focus.
  140. * @since jEdit 4.0pre3
  141. */
  142. public void setSelectAllOnFocus(boolean selectAllOnFocus)
  143. {
  144. this.selectAllOnFocus = selectAllOnFocus;
  145. } //}}}
  146. //{{{ getSelectAllOnFocus() method
  147. /**
  148. * Returns if all text should be selected when the field gets focus.
  149. * @since jEdit 4.0pre3
  150. */
  151. public boolean setSelectAllOnFocus()
  152. {
  153. return selectAllOnFocus;
  154. } //}}}
  155. //{{{ setModel() method
  156. /**
  157. * Sets the history list model.
  158. * @param name The model name
  159. * @since jEdit 2.3pre3
  160. */
  161. public void setModel(String name)
  162. {
  163. if(name == null)
  164. historyModel = null;
  165. else
  166. historyModel = HistoryModel.getModel(name);
  167. index = -1;
  168. repaint();
  169. } //}}}
  170. //{{{ addCurrentToHistory() method
  171. /**
  172. * Adds the currently entered item to the history.
  173. */
  174. public void addCurrentToHistory()
  175. {
  176. if(historyModel != null)
  177. historyModel.addItem(getText());
  178. index = 0;
  179. } //}}}
  180. //{{{ setText() method
  181. /**
  182. * Sets the displayed text.
  183. */
  184. public void setText(String text)
  185. {
  186. super.setText(text);
  187. index = -1;
  188. } //}}}
  189. //{{{ getModel() method
  190. /**
  191. * Returns the underlying history model.
  192. */
  193. public HistoryModel getModel()
  194. {
  195. return historyModel;
  196. } //}}}
  197. //{{{ fireActionPerformed() method
  198. /**
  199. * Fires an action event to all listeners. This is public so
  200. * that inner classes can access it.
  201. */
  202. public void fireActionPerformed()
  203. {
  204. super.fireActionPerformed();
  205. } //}}}
  206. //{{{ Protected members
  207. //{{{ processKeyEvent() method
  208. protected void processKeyEvent(KeyEvent evt)
  209. {
  210. if(!isEnabled())
  211. return;
  212. /*evt = KeyEventWorkaround.processKeyEvent(evt);
  213. if(evt == null)
  214. return;*/
  215. if(evt.getID() == KeyEvent.KEY_PRESSED)
  216. {
  217. if(evt.getKeyCode() == KeyEvent.VK_ENTER)
  218. {
  219. if(enterAddsToHistory)
  220. addCurrentToHistory();
  221. if(evt.getModifiers() == 0)
  222. {
  223. fireActionPerformed();
  224. evt.consume();
  225. }
  226. }
  227. else if(evt.getKeyCode() == KeyEvent.VK_UP)
  228. {
  229. if(evt.isShiftDown())
  230. doBackwardSearch();
  231. else
  232. historyPrevious();
  233. evt.consume();
  234. }
  235. else if(evt.getKeyCode() == KeyEvent.VK_DOWN)
  236. {
  237. if(evt.isShiftDown())
  238. doForwardSearch();
  239. else
  240. historyNext();
  241. evt.consume();
  242. }
  243. else if(evt.getKeyCode() == KeyEvent.VK_TAB
  244. && evt.isControlDown())
  245. {
  246. doBackwardSearch();
  247. evt.consume();
  248. }
  249. }
  250. if(!evt.isConsumed())
  251. super.processKeyEvent(evt);
  252. } //}}}
  253. //{{{ processMouseEvent() method
  254. protected void processMouseEvent(MouseEvent evt)
  255. {
  256. if(!isEnabled())
  257. return;
  258. switch(evt.getID())
  259. {
  260. case MouseEvent.MOUSE_PRESSED:
  261. Border border = getBorder();
  262. Insets insets = border.getBorderInsets(HistoryTextField.this);
  263. if(evt.getX() >= getWidth() - insets.right
  264. || GUIUtilities.isPopupTrigger(evt))
  265. {
  266. if(evt.isShiftDown())
  267. showPopupMenu(getText().substring(0,
  268. getSelectionStart()),0,getHeight());
  269. else
  270. showPopupMenu("",0,getHeight());
  271. }
  272. else
  273. super.processMouseEvent(evt);
  274. break;
  275. case MouseEvent.MOUSE_EXITED:
  276. setCursor(Cursor.getDefaultCursor());
  277. super.processMouseEvent(evt);
  278. break;
  279. default:
  280. super.processMouseEvent(evt);
  281. break;
  282. }
  283. } //}}}
  284. //}}}
  285. //{{{ Private members
  286. //{{{ Instance variables
  287. private HistoryModel historyModel;
  288. private JPopupMenu popup;
  289. private boolean instantPopups;
  290. private boolean enterAddsToHistory;
  291. private boolean selectAllOnFocus;
  292. private String current;
  293. private int index;
  294. //}}}
  295. //{{{ doBackwardSearch() method
  296. private void doBackwardSearch()
  297. {
  298. if(historyModel == null)
  299. return;
  300. if(getSelectionEnd() != getDocument().getLength())
  301. {
  302. setCaretPosition(getDocument().getLength());
  303. }
  304. String text = getText().substring(0,getSelectionStart());
  305. if(text == null)
  306. {
  307. historyPrevious();
  308. return;
  309. }
  310. for(int i = index + 1; i < historyModel.getSize(); i++)
  311. {
  312. String item = historyModel.getItem(i);
  313. if(item.startsWith(text))
  314. {
  315. replaceSelection(item.substring(text.length()));
  316. select(text.length(),getDocument().getLength());
  317. index = i;
  318. return;
  319. }
  320. }
  321. getToolkit().beep();
  322. } //}}}
  323. //{{{ doForwardSearch() method
  324. private void doForwardSearch()
  325. {
  326. if(historyModel == null)
  327. return;
  328. if(getSelectionEnd() != getDocument().getLength())
  329. {
  330. setCaretPosition(getDocument().getLength());
  331. }
  332. String text = getText().substring(0,getSelectionStart());
  333. if(text == null)
  334. {
  335. historyNext();
  336. return;
  337. }
  338. for(int i = index - 1; i >= 0; i--)
  339. {
  340. String item = historyModel.getItem(i);
  341. if(item.startsWith(text))
  342. {
  343. replaceSelection(item.substring(text.length()));
  344. select(text.length(),getDocument().getLength());
  345. index = i;
  346. return;
  347. }
  348. }
  349. getToolkit().beep();
  350. } //}}}
  351. //{{{ historyPrevious() method
  352. private void historyPrevious()
  353. {
  354. if(historyModel == null)
  355. return;
  356. if(index == historyModel.getSize() - 1)
  357. getToolkit().beep();
  358. else if(index == -1)
  359. {
  360. current = getText();
  361. setText(historyModel.getItem(0));
  362. index = 0;
  363. }
  364. else
  365. {
  366. // have to do this because setText() sets index to -1
  367. int newIndex = index + 1;
  368. setText(historyModel.getItem(newIndex));
  369. index = newIndex;
  370. }
  371. } //}}}
  372. //{{{ historyNext() method
  373. private void historyNext()
  374. {
  375. if(historyModel == null)
  376. return;
  377. if(index == -1)
  378. getToolkit().beep();
  379. else if(index == 0)
  380. setText(current);
  381. else
  382. {
  383. // have to do this because setText() sets index to -1
  384. int newIndex = index - 1;
  385. setText(historyModel.getItem(newIndex));
  386. index = newIndex;
  387. }
  388. } //}}}
  389. //{{{ showPopupMenu() method
  390. private void showPopupMenu(String text, int x, int y)
  391. {
  392. if(historyModel == null)
  393. return;
  394. requestFocus();
  395. if(popup != null && popup.isVisible())
  396. {
  397. popup.setVisible(false);
  398. return;
  399. }
  400. ActionHandler actionListener = new ActionHandler();
  401. popup = new JPopupMenu();
  402. JMenuItem caption = new JMenuItem(jEdit.getProperty(
  403. "history.caption"));
  404. caption.getModel().setEnabled(false);
  405. popup.add(caption);
  406. popup.addSeparator();
  407. for(int i = 0; i < historyModel.getSize(); i++)
  408. {
  409. String item = historyModel.getItem(i);
  410. if(item.startsWith(text))
  411. {
  412. JMenuItem menuItem = new JMenuItem(item);
  413. menuItem.setActionCommand(String.valueOf(i));
  414. menuItem.addActionListener(actionListener);
  415. popup.add(menuItem);
  416. }
  417. }
  418. GUIUtilities.showPopupMenu(popup,this,x,y,false);
  419. } //}}}
  420. //}}}
  421. //{{{ Inner classes
  422. //{{{ ActionHandler class
  423. class ActionHandler implements ActionListener
  424. {
  425. public void actionPerformed(ActionEvent evt)
  426. {
  427. int ind = Integer.parseInt(evt.getActionCommand());
  428. if(ind == -1)
  429. {
  430. if(index != -1)
  431. setText(current);
  432. }
  433. else
  434. {
  435. setText(historyModel.getItem(ind));
  436. index = ind;
  437. }
  438. if(instantPopups)
  439. {
  440. addCurrentToHistory();
  441. fireActionPerformed();
  442. }
  443. }
  444. } //}}}
  445. //{{{ MouseHandler class
  446. class MouseHandler extends MouseInputAdapter
  447. {
  448. boolean selectAll;
  449. //{{{ mousePressed() method
  450. public void mousePressed(MouseEvent evt)
  451. {
  452. selectAll = (!hasFocus() && selectAllOnFocus);
  453. } //}}}
  454. //{{{ mouseReleased() method
  455. public void mouseReleased(MouseEvent evt)
  456. {
  457. SwingUtilities.invokeLater(new Runnable()
  458. {
  459. public void run()
  460. {
  461. if(selectAll)
  462. selectAll();
  463. }
  464. });
  465. } //}}}
  466. //{{{ mouseMoved() method
  467. public void mouseMoved(MouseEvent evt)
  468. {
  469. Border border = getBorder();
  470. Insets insets = border.getBorderInsets(HistoryTextField.this);
  471. if(evt.getX() >= getWidth() - insets.right)
  472. setCursor(Cursor.getDefaultCursor());
  473. else
  474. setCursor(Cursor.getPredefinedCursor(
  475. Cursor.TEXT_CURSOR));
  476. } //}}}
  477. //{{{ mouseDragged() method
  478. public void mouseDragged(MouseEvent evt)
  479. {
  480. selectAll = false;
  481. } //}}}
  482. } //}}}
  483. //{{{ HistoryBorder class
  484. static class HistoryBorder extends AbstractBorder
  485. {
  486. static final int WIDTH = 16;
  487. public void paintBorder(Component c, Graphics g,
  488. int x, int y, int w, int h)
  489. {
  490. g.translate(x+w-WIDTH,y-1);
  491. //if(c.isEnabled())
  492. //{
  493. // // vertical separation line
  494. // g.setColor(UIManager.getColor("controlDkShadow"));
  495. // g.drawLine(0,0,0,h);
  496. //}
  497. // down arrow
  498. int w2 = WIDTH/2;
  499. int h2 = h/2;
  500. g.setColor(UIManager.getColor(c.isEnabled()
  501. && ((HistoryTextField)c).getModel() != null
  502. ? "Menu.foreground" : "Menu.disabledForeground"));
  503. g.drawLine(w2-5,h2-2,w2+4,h2-2);
  504. g.drawLine(w2-4,h2-1,w2+3,h2-1);
  505. g.drawLine(w2-3,h2 ,w2+2,h2 );
  506. g.drawLine(w2-2,h2+1,w2+1,h2+1);
  507. g.drawLine(w2-1,h2+2,w2 ,h2+2);
  508. g.translate(-(x+w-WIDTH),-(y-1));
  509. }
  510. public Insets getBorderInsets(Component c)
  511. {
  512. return new Insets(0,0,0,WIDTH);
  513. }
  514. } //}}}
  515. //}}}
  516. }