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

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/gui/HistoryTextField.java

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