/jEdit/tags/jedit-4-2-pre1/org/gjt/sp/jedit/search/SearchBar.java

# · Java · 426 lines · 304 code · 39 blank · 83 comment · 48 complexity · 9afdedac7291a4c6b5bf50f96f3963cb MD5 · raw file

  1. /*
  2. * SearchBar.java - Search & replace toolbar
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 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.search;
  23. //{{{ Imports
  24. import java.awt.event.*;
  25. import java.awt.*;
  26. import javax.swing.event.*;
  27. import javax.swing.*;
  28. import org.gjt.sp.jedit.*;
  29. import org.gjt.sp.jedit.gui.*;
  30. import org.gjt.sp.jedit.textarea.*;
  31. import org.gjt.sp.util.Log;
  32. //}}}
  33. /**
  34. * Incremental search tool bar.
  35. */
  36. public class SearchBar extends JPanel
  37. {
  38. //{{{ SearchBar constructor
  39. public SearchBar(final View view, boolean temp)
  40. {
  41. setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
  42. this.view = view;
  43. add(Box.createHorizontalStrut(2));
  44. JLabel label = new JLabel(jEdit.getProperty("view.search.find"));
  45. add(label);
  46. add(Box.createHorizontalStrut(12));
  47. add(find = new HistoryTextField("find"));
  48. find.setSelectAllOnFocus(true);
  49. Dimension max = find.getPreferredSize();
  50. max.width = Integer.MAX_VALUE;
  51. find.setMaximumSize(max);
  52. ActionHandler actionHandler = new ActionHandler();
  53. find.addKeyListener(new KeyHandler());
  54. find.addActionListener(actionHandler);
  55. find.getDocument().addDocumentListener(new DocumentHandler());
  56. Insets margin = new Insets(1,1,1,1);
  57. add(Box.createHorizontalStrut(12));
  58. add(ignoreCase = new JCheckBox(jEdit.getProperty(
  59. "search.case")));
  60. ignoreCase.addActionListener(actionHandler);
  61. ignoreCase.setMargin(margin);
  62. ignoreCase.setRequestFocusEnabled(false);
  63. add(Box.createHorizontalStrut(2));
  64. add(regexp = new JCheckBox(jEdit.getProperty(
  65. "search.regexp")));
  66. regexp.addActionListener(actionHandler);
  67. regexp.setMargin(margin);
  68. regexp.setRequestFocusEnabled(false);
  69. add(Box.createHorizontalStrut(2));
  70. add(hyperSearch = new JCheckBox(jEdit.getProperty(
  71. "search.hypersearch")));
  72. hyperSearch.addActionListener(actionHandler);
  73. hyperSearch.setMargin(margin);
  74. hyperSearch.setRequestFocusEnabled(false);
  75. update();
  76. //{{{ Create the timer used by incremental search
  77. timer = new Timer(0,new ActionListener()
  78. {
  79. public void actionPerformed(ActionEvent evt)
  80. {
  81. if(!incrementalSearch(searchStart,searchReverse))
  82. {
  83. if(!incrementalSearch(
  84. (searchReverse
  85. ? view.getBuffer().getLength()
  86. : 0),searchReverse))
  87. {
  88. // not found at all.
  89. view.getStatus().setMessageAndClear(
  90. jEdit.getProperty(
  91. "view.status.search-not-found"));
  92. }
  93. }
  94. }
  95. }); //}}}
  96. // if 'temp' is true, hide search bar after user is done with it
  97. this.temp = temp;
  98. } //}}}
  99. //{{{ getField() method
  100. public HistoryTextField getField()
  101. {
  102. return find;
  103. } //}}}
  104. //{{{ setHyperSearch() method
  105. public void setHyperSearch(boolean hyperSearch)
  106. {
  107. jEdit.setBooleanProperty("view.search.hypersearch.toggle",hyperSearch);
  108. this.hyperSearch.setSelected(hyperSearch);
  109. } //}}}
  110. //{{{ update() method
  111. public void update()
  112. {
  113. ignoreCase.setSelected(SearchAndReplace.getIgnoreCase());
  114. regexp.setSelected(SearchAndReplace.getRegexp());
  115. hyperSearch.setSelected(jEdit.getBooleanProperty(
  116. "view.search.hypersearch.toggle"));
  117. } //}}}
  118. //{{{ propertiesChanged() method
  119. public void propertiesChanged()
  120. {
  121. if(temp)
  122. {
  123. if(close == null)
  124. {
  125. close = new RolloverButton(GUIUtilities.loadIcon("closebox.gif"));
  126. close.addActionListener(new ActionHandler());
  127. close.setToolTipText(jEdit.getProperty(
  128. "view.search.close-tooltip"));
  129. }
  130. add(close);
  131. }
  132. else if(close != null)
  133. remove(close);
  134. } //}}}
  135. //{{{ Private members
  136. //{{{ Instance variables
  137. private View view;
  138. private HistoryTextField find;
  139. private JCheckBox ignoreCase, regexp, hyperSearch;
  140. private Timer timer;
  141. // close button only there if 'temp' is true
  142. private RolloverButton close;
  143. private int searchStart;
  144. private boolean searchReverse;
  145. private boolean temp;
  146. //}}}
  147. //{{{ find() method
  148. private void find(boolean reverse)
  149. {
  150. timer.stop();
  151. String text = find.getText();
  152. //{{{ If nothing entered, show search and replace dialog box
  153. if(text.length() == 0)
  154. {
  155. jEdit.setBooleanProperty("search.hypersearch.toggle",
  156. hyperSearch.isSelected());
  157. new SearchDialog(view,null);
  158. } //}}}
  159. //{{{ HyperSearch
  160. else if(hyperSearch.isSelected())
  161. {
  162. if(temp)
  163. {
  164. view.removeToolBar(SearchBar.this);
  165. }
  166. else
  167. find.setText(null);
  168. SearchAndReplace.setSearchString(text);
  169. SearchAndReplace.setSearchFileSet(new CurrentBufferSet());
  170. SearchAndReplace.hyperSearch(view);
  171. } //}}}
  172. //{{{ Incremental search
  173. else
  174. {
  175. // on enter, start search from end
  176. // of current match to find next one
  177. int start;
  178. JEditTextArea textArea = view.getTextArea();
  179. Selection s = textArea.getSelectionAtOffset(
  180. textArea.getCaretPosition());
  181. if(s == null)
  182. start = textArea.getCaretPosition();
  183. else if(reverse)
  184. start = s.getStart();
  185. else
  186. start = s.getEnd();
  187. if(!incrementalSearch(start,reverse))
  188. {
  189. // not found. start from
  190. // beginning
  191. if(!incrementalSearch(reverse
  192. ? view.getBuffer().getLength()
  193. : 0,reverse))
  194. {
  195. // not found at all.
  196. view.getStatus().setMessageAndClear(
  197. jEdit.getProperty(
  198. "view.status.search-not-found"));
  199. }
  200. else
  201. {
  202. // inform user search restarted
  203. view.getStatus().setMessageAndClear(
  204. jEdit.getProperty("view.status.auto-wrap"));
  205. // beep if beep property set
  206. if(jEdit.getBooleanProperty("search.beepOnSearchAutoWrap"))
  207. {
  208. getToolkit().beep();
  209. }
  210. }
  211. }
  212. } //}}}
  213. } //}}}
  214. //{{{ incrementalSearch() method
  215. private boolean incrementalSearch(int start, boolean reverse)
  216. {
  217. /* For example, if the current fileset is a directory,
  218. * C+g will find the next match within that fileset.
  219. * This can be annoying if you have just done an
  220. * incremental search and want the next occurrence
  221. * in the current buffer. */
  222. SearchAndReplace.setSearchFileSet(new CurrentBufferSet());
  223. SearchAndReplace.setSearchString(find.getText());
  224. SearchAndReplace.setReverseSearch(reverse);
  225. try
  226. {
  227. if(SearchAndReplace.find(view,view.getBuffer(),start,false,reverse))
  228. return true;
  229. }
  230. catch(Exception e)
  231. {
  232. Log.log(Log.DEBUG,this,e);
  233. // invalid regexp, ignore
  234. // return true to avoid annoying beeping while
  235. // typing a re
  236. return true;
  237. }
  238. return false;
  239. } //}}}
  240. //{{{ timerIncrementalSearch() method
  241. private void timerIncrementalSearch(int start, boolean reverse)
  242. {
  243. this.searchStart = start;
  244. this.searchReverse = reverse;
  245. timer.stop();
  246. timer.setRepeats(false);
  247. timer.setInitialDelay(150);
  248. timer.start();
  249. } //}}}
  250. //}}}
  251. //{{{ Inner classes
  252. //{{{ ActionHandler class
  253. class ActionHandler implements ActionListener
  254. {
  255. //{{{ actionPerformed() method
  256. public void actionPerformed(ActionEvent evt)
  257. {
  258. Object source = evt.getSource();
  259. if(source == find)
  260. find(false);
  261. else if(source == hyperSearch)
  262. {
  263. jEdit.setBooleanProperty("view.search.hypersearch.toggle",
  264. hyperSearch.isSelected());
  265. update();
  266. }
  267. else if(source == ignoreCase)
  268. {
  269. SearchAndReplace.setIgnoreCase(ignoreCase
  270. .isSelected());
  271. }
  272. else if(source == regexp)
  273. {
  274. SearchAndReplace.setRegexp(regexp
  275. .isSelected());
  276. }
  277. else if(source == close)
  278. {
  279. view.removeToolBar(SearchBar.this);
  280. view.getEditPane().focusOnTextArea();
  281. }
  282. } //}}}
  283. } //}}}
  284. //{{{ DocumentHandler class
  285. class DocumentHandler implements DocumentListener
  286. {
  287. //{{{ insertUpdate() method
  288. public void insertUpdate(DocumentEvent evt)
  289. {
  290. // on insert, start search from beginning of
  291. // current match. This will continue to highlight
  292. // the current match until another match is found
  293. if(!hyperSearch.isSelected())
  294. {
  295. int start;
  296. JEditTextArea textArea = view.getTextArea();
  297. Selection s = textArea.getSelectionAtOffset(
  298. textArea.getCaretPosition());
  299. if(s == null)
  300. start = textArea.getCaretPosition();
  301. else
  302. start = s.getStart();
  303. timerIncrementalSearch(start,false);
  304. }
  305. } //}}}
  306. //{{{ removeUpdate() method
  307. public void removeUpdate(DocumentEvent evt)
  308. {
  309. // on backspace, restart from beginning
  310. if(!hyperSearch.isSelected())
  311. {
  312. String text = find.getText();
  313. if(text.length() != 0)
  314. {
  315. // don't beep if not found.
  316. // subsequent beeps are very
  317. // annoying when backspacing an
  318. // invalid search string.
  319. if(regexp.isSelected())
  320. {
  321. // reverse regexp search
  322. // not supported yet, so
  323. // 'simulate' with restart
  324. timerIncrementalSearch(0,false);
  325. }
  326. else
  327. {
  328. int start;
  329. JEditTextArea textArea = view.getTextArea();
  330. Selection s = textArea.getSelectionAtOffset(
  331. textArea.getCaretPosition());
  332. if(s == null)
  333. start = textArea.getCaretPosition();
  334. else
  335. start = s.getStart();
  336. timerIncrementalSearch(start,true);
  337. }
  338. }
  339. }
  340. } //}}}
  341. //{{{ changedUpdate() method
  342. public void changedUpdate(DocumentEvent evt) {}
  343. //}}}
  344. } //}}}
  345. //{{{ KeyHandler class
  346. class KeyHandler extends KeyAdapter
  347. {
  348. public void keyPressed(KeyEvent evt)
  349. {
  350. switch(evt.getKeyCode())
  351. {
  352. case KeyEvent.VK_LEFT:
  353. case KeyEvent.VK_RIGHT:
  354. if(!hyperSearch.isSelected())
  355. {
  356. if(temp)
  357. {
  358. view.removeToolBar(SearchBar.this);
  359. }
  360. evt.consume();
  361. view.getEditPane().focusOnTextArea();
  362. view.getEditPane().getTextArea()
  363. .processKeyEvent(evt);
  364. }
  365. break;
  366. case KeyEvent.VK_ESCAPE:
  367. if(temp)
  368. {
  369. view.removeToolBar(SearchBar.this);
  370. }
  371. evt.consume();
  372. view.getEditPane().focusOnTextArea();
  373. break;
  374. case KeyEvent.VK_ENTER:
  375. if(evt.isShiftDown())
  376. {
  377. evt.consume();
  378. // reverse search with regexps not
  379. // supported yet
  380. find(regexp.isSelected() ? false : true);
  381. }
  382. break;
  383. }
  384. }
  385. } //}}}
  386. //}}}
  387. }