PageRenderTime 41ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

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

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