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