Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/jext/search/FindReplace.java


1   /*
2    * 03/01/2002 - 19:53:59
3    *
4    * FindReplace.java - The Jext's find dialog
5    * Copyright (C) 1998-2001 Romain Guy
6    * romain.guy@jext.org
7    * www.jext.org
8    *
9    * This program is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU General Public License
11   * as published by the Free Software Foundation; either version 2
12   * of the License, or any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   *
19   * You should have received a copy of the GNU General Public License
20   * along with this program; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22   */
23  
24  package org.jext.search;
25  
26  import gnu.regexp.*;
27  
28  import java.awt.*;
29  import java.awt.event.*;
30  
31  import javax.swing.*;
32  
33  import org.jext.*;
34  import org.jext.gui.*;
35  
36  /**
37   * The <code>FindReplace</code> class is a component which displays
38   * a dialog for either finding either replacing text. It provides
39   * two combo lists, which holds latest patterns, and many buttons
40   * or check boxes for options.
41   * @author Romain Guy
42   */
43  
44  public class FindReplace extends JDialog implements ActionListener
45  {
46    // Constant declarations
47    /** Defines a search only dialog */
48    public static final int SEARCH = 1;
49    /** Defines a search and replace dialog */
50    public static final int REPLACE = 2;
51  
52    // Private declarations
53    private int type;
54    private JextFrame parent;
55    private JComboBox fieldSearch;
56    private JComboBox fieldReplace;
57    private JTextField fieldSearchEditor, fieldReplaceEditor, script;
58    private JextHighlightButton btnFind, btnReplace, btnReplaceAll, btnCancel;
59    private JextCheckBox checkIgnoreCase, saveStates, useRegexp, allFiles, scripted;
60  
61    // This method is used to easily build the GridBagLayout
62  
63    private void buildConstraints(GridBagConstraints agbc, int agx, int agy, int agw, int agh,
64                                  int awx, int awy)
65    {
66      agbc.gridx = agx;
67      agbc.gridy = agy;
68      agbc.gridwidth = agw;
69      agbc.gridheight = agh;
70      agbc.weightx = awx;
71      agbc.weighty = awy;
72      agbc.insets = new Insets(2, 2, 2, 2);
73    }
74  
75    /**
76     * Constructs a new find dialog according to the specified
77     * type of dialog requested. The dialog can be either a
78     * FIND dialog, either a REPLACE dialog. In both cases, components
79     * displayed remain the sames, but the ones specific to replace
80     * feature are grayed out.
81     * @param parent The window holder
82     * @param type The type of the dialog: <code>FindReplace.FIND</code>
83     *             or <code>FindReplace.REPLACE</code>
84     * @param modal Displays dialog as a modal window if true
85     */
86  
87    public FindReplace(JextFrame parent, int type, boolean modal)
88    {
89      super(parent, type == REPLACE ? Jext.getProperty("replace.title") :
90                                      Jext.getProperty("find.title"), modal);
91      this.parent = parent;
92      this.type = type;
93  
94      fieldSearch = new JComboBox();
95      fieldSearch.setRenderer(new ModifiedCellRenderer());
96      fieldSearch.setEditable(true);
97      fieldReplace = new JComboBox();
98      fieldReplace.setRenderer(new ModifiedCellRenderer());
99      fieldReplace.setEditable(true);
100     KeyHandler handler = new KeyHandler();
101     fieldSearchEditor = (JTextField) fieldSearch.getEditor().getEditorComponent();
102     fieldSearchEditor.addKeyListener(handler);
103     fieldReplaceEditor = (JTextField) fieldReplace.getEditor().getEditorComponent();
104     fieldReplaceEditor.addKeyListener(handler);
105 
106     GridBagLayout gridbag = new GridBagLayout();
107     GridBagConstraints constraints = new GridBagConstraints();
108     getContentPane().setLayout(gridbag);
109     ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
110 
111     JLabel findLabel = new JLabel(Jext.getProperty("find.label"));
112     buildConstraints(constraints, 0, 0, 1, 1, 25, 50);
113     constraints.anchor = GridBagConstraints.WEST;
114     gridbag.setConstraints(findLabel, constraints);
115     getContentPane().add(findLabel);
116 
117     buildConstraints(constraints, 1, 0, 1, 1, 25, 50);
118     constraints.fill = GridBagConstraints.HORIZONTAL;
119     constraints.anchor = GridBagConstraints.CENTER;
120     gridbag.setConstraints(fieldSearch, constraints);
121     getContentPane().add(fieldSearch);
122 
123     btnFind = new JextHighlightButton(Jext.getProperty("find.button"));
124     btnFind.setToolTipText(Jext.getProperty("find.tip"));
125     btnFind.setMnemonic(Jext.getProperty("find.mnemonic").charAt(0));
126     btnFind.addActionListener(this);
127     buildConstraints(constraints, 2, 0, 1, 1, 25, 50);
128     constraints.anchor = GridBagConstraints.CENTER;
129     gridbag.setConstraints(btnFind, constraints);
130     getContentPane().add(btnFind);
131     getRootPane().setDefaultButton(btnFind);
132 
133     btnCancel = new JextHighlightButton(Jext.getProperty("general.cancel.button"));
134     btnCancel.setMnemonic(Jext.getProperty("general.cancel.mnemonic").charAt(0));
135     btnCancel.addActionListener(this);
136     buildConstraints(constraints, 3, 0, 1, 1, 25, 50);
137     constraints.anchor = GridBagConstraints.CENTER;
138     gridbag.setConstraints(btnCancel, constraints);
139     getContentPane().add(btnCancel);
140 
141     JLabel replaceLabel = new JLabel(Jext.getProperty("replace.label"));
142     buildConstraints(constraints, 0, 1, 1, 1, 25, 50);
143     constraints.anchor = GridBagConstraints.WEST;
144     gridbag.setConstraints(replaceLabel, constraints);
145     getContentPane().add(replaceLabel);
146 
147 // patch added by gandalf march 25 2003
148     if (type != REPLACE)
149       replaceLabel.setEnabled(false);
150 // patch added by gandalf march 25 2003
151 
152     buildConstraints(constraints, 1, 1, 1, 1, 25, 50);
153     constraints.fill = GridBagConstraints.HORIZONTAL;
154     constraints.anchor = GridBagConstraints.CENTER;
155     gridbag.setConstraints(fieldReplace, constraints);
156     getContentPane().add(fieldReplace);
157 
158     if (type != REPLACE)
159       fieldReplace.setEnabled(false);
160     btnReplace = new JextHighlightButton(Jext.getProperty("replace.button"));
161     btnReplace.setToolTipText(Jext.getProperty("replace.tip"));
162     btnReplace.setMnemonic(Jext.getProperty("replace.mnemonic").charAt(0));
163     if (type != REPLACE)
164       btnReplace.setEnabled(false);
165     btnReplace.addActionListener(this);
166     buildConstraints(constraints, 2, 1, 1, 1, 25, 50);
167     constraints.anchor = GridBagConstraints.CENTER;
168     gridbag.setConstraints(btnReplace, constraints);
169     getContentPane().add(btnReplace);
170 
171     btnReplaceAll = new JextHighlightButton(Jext.getProperty("replace.all.button"));
172     btnReplaceAll.setToolTipText(Jext.getProperty("replace.all.tip"));
173     btnReplaceAll.setMnemonic(Jext.getProperty("replace.all.mnemonic").charAt(0));
174     if (type != REPLACE)
175       btnReplaceAll.setEnabled(false);
176     btnReplaceAll.addActionListener(this);
177     buildConstraints(constraints, 3, 1, 1, 1, 25, 50);
178     constraints.anchor = GridBagConstraints.CENTER;
179     gridbag.setConstraints(btnReplaceAll, constraints);
180     getContentPane().add(btnReplaceAll);
181 
182     scripted = new JextCheckBox(Jext.getProperty("replace.script"), Search.getPythonScript());
183     if (type != REPLACE)
184       scripted.setEnabled(false);
185     else
186     {
187       fieldReplace.setEnabled(!scripted.isSelected());
188       scripted.addActionListener(this);
189     }
190     buildConstraints(constraints, 0, 2, 1, 1, 50, 50);
191     constraints.anchor = GridBagConstraints.WEST;
192     gridbag.setConstraints(scripted, constraints);
193     getContentPane().add(scripted);
194 
195     script = new JTextField();
196     if (type != REPLACE)
197       script.setEnabled(false);
198     else
199       script.setEnabled(scripted.isSelected());
200     script.setText(Search.getPythonScriptString());
201     buildConstraints(constraints, 1, 2, 1, 1, 50, 50);
202     constraints.anchor = GridBagConstraints.CENTER;
203     gridbag.setConstraints(script, constraints);
204     getContentPane().add(script);
205 
206     checkIgnoreCase = new JextCheckBox(Jext.getProperty("find.ignorecase.label"), Search.getIgnoreCase());
207     buildConstraints(constraints, 0, 3, 1, 1, 25, 50);
208     constraints.anchor = GridBagConstraints.WEST;
209     gridbag.setConstraints(checkIgnoreCase, constraints);
210     getContentPane().add(checkIgnoreCase);
211 
212     JPanel cPane = new JPanel();
213     saveStates = new JextCheckBox(Jext.getProperty("find.savevalues.label"),
214                                Jext.getBooleanProperty("savestates"));
215     allFiles = new JextCheckBox(Jext.getProperty("find.allFiles.label"),
216                              Jext.getBooleanProperty("allfiles"));
217     cPane.add(saveStates);
218     cPane.add(allFiles);
219 
220     buildConstraints(constraints, 1, 3, 1, 1, 25, 50);
221     constraints.anchor = GridBagConstraints.WEST;
222     gridbag.setConstraints(cPane, constraints);
223     getContentPane().add(cPane);
224 
225     useRegexp = new JextCheckBox(Jext.getProperty("find.useregexp.label"), Search.getRegexp());
226     buildConstraints(constraints, 2, 3, 2, 1, 50, 50);
227     constraints.anchor = GridBagConstraints.WEST;
228     gridbag.setConstraints(useRegexp, constraints);
229     getContentPane().add(useRegexp);
230 
231     load();
232 
233     setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
234     addKeyListener(new AbstractDisposer(this));
235     addWindowListener(new WindowAdapter()
236     {
237       public void windowClosing(WindowEvent e)
238       {
239         exit();
240       }
241     });
242 
243     FontMetrics fm = getFontMetrics(getFont());
244     fieldSearch.setPreferredSize(new Dimension(18 * fm.charWidth('m'),
245                                  (int) fieldSearch.getPreferredSize().height));
246     fieldReplace.setPreferredSize(new Dimension(18 * fm.charWidth('m'),
247                                   (int) fieldReplace.getPreferredSize().height));
248 
249     pack();
250     setResizable(false);
251     Utilities.centerComponentChild(parent, this);
252 
253 //patch by MJB 8/1/2002    
254   btnFind.addKeyListener(handler);
255   btnReplace.addKeyListener(handler);
256   btnReplaceAll.addKeyListener(handler);
257   btnCancel.addKeyListener(handler);
258   checkIgnoreCase.addKeyListener(handler);
259   saveStates.addKeyListener(handler);
260   useRegexp.addKeyListener(handler);
261   allFiles.addKeyListener(handler);
262   scripted.addKeyListener(handler);
263   script.addKeyListener(handler);
264 //end MJB patch
265     
266     show();
267   }
268 
269   // load the search and replace histories from user
270   // properties. It also selects latest pattern from
271   // the list.
272 
273   private void load()
274   {
275     String s;
276     for (int i = 0; i < 25; i++)
277     {
278       s = Jext.getProperty("search.history." + i);
279       if (s != null)
280         fieldSearch.addItem(s);
281       else
282         break;
283     }
284 
285     JextTextArea textArea = parent.getTextArea();
286     if (!Jext.getBooleanProperty("use.selection"))
287     {
288       s = Search.getFindPattern();
289       if (s != null)
290       {
291         addSearchHistory(s);
292         fieldSearch.setSelectedItem(s);
293       }
294     } else if ((s = textArea.getSelectedText()) != null) {
295 
296       char c = '\0';
297       StringBuffer buf = new StringBuffer(s.length());
298 out:  for (int i = 0; i < s.length(); i++)
299       {
300         switch (c = s.charAt(i))
301         {
302           case '\n':
303             break out;
304           default:
305             buf.append(c);
306         }
307       }
308 
309       s = buf.toString();
310       addSearchHistory(s);
311       fieldSearch.setSelectedItem(s);
312     }
313 
314     if (type == REPLACE)
315     {
316       for (int i = 0; i < 25; i++)
317       {
318         s = Jext.getProperty("replace.history." + i);
319         if (s != null)
320           fieldReplace.addItem(s);
321         else
322           break;
323       }
324 
325       s = Search.getReplacePattern();
326       if (s != null)
327       {
328         addReplaceHistory(s);
329         fieldReplace.setSelectedItem(s);
330       }
331     }
332 
333     // selects contents
334     fieldSearchEditor.selectAll();
335   }
336 
337   // exits the dialog after having saved the search and
338   // replace histories.
339 
340   private void exit()
341   {
342     if (saveStates.isSelected())
343     {
344       for (int i = 0; i < fieldSearch.getItemCount(); i++)
345         Jext.setProperty("search.history." + i, (String) fieldSearch.getItemAt(i));
346       for (int i = fieldSearch.getItemCount(); i < 25; i++)
347         Jext.unsetProperty("search.history." + i);
348 
349       if (type == REPLACE)
350       {
351         for (int i = 0; i < fieldReplace.getItemCount(); i++)
352           Jext.setProperty("replace.history." + i, (String) fieldReplace.getItemAt(i));
353         for (int i = fieldReplace.getItemCount(); i < 25; i++)
354           Jext.unsetProperty("replace.history." + i);
355       }
356     }
357 
358     Jext.setProperty("savestates", (saveStates.isSelected() ? "on" : "off"));
359     Jext.setProperty("allfiles", (allFiles.isSelected() ? "on" : "off"));
360 
361 // patch added by gandalf march 25 2003
362     Search.setIgnoreCase(checkIgnoreCase.isSelected() ? true : false);
363     Search.setRegexp(useRegexp.isSelected() ? true : false);
364 // patch added by gandalf march 25 2003
365 
366     dispose();
367   }
368 
369   // adds current search pattern in the search history list
370 
371   private void addSearchHistory()
372   {
373     addSearchHistory(fieldSearchEditor.getText());
374   }
375 
376   // adds a pattern in the search history list
377   // the pattern to be added is specified by the param c
378 
379   private void addSearchHistory(String c)
380   {
381     if (c == null)
382       return;
383 
384     for (int i = 0; i < fieldSearch.getItemCount(); i++)
385     {
386       if (((String) fieldSearch.getItemAt(i)).equals(c))
387         return;
388     }
389 
390     fieldSearch.insertItemAt(c, 0);
391     if (fieldSearch.getItemCount() > 25)
392     {
393       //for (int i = 24; i < fieldSearch.getItemCount(); i++)
394 
395 // patch added by gandalf march 25 2003
396       for (int i = 25; i < fieldSearch.getItemCount();)
397 // patch added by gandalf march 25 2003
398           fieldSearch.removeItemAt(i);
399     }
400 
401     //Search.setFindPattern(fieldSearchEditor.getText());
402     fieldSearchEditor.setText((String) fieldSearch.getItemAt(0));
403   }
404 
405   // adds current replace pattern in the replace history list
406 
407   private void addReplaceHistory()
408   {
409     addReplaceHistory(fieldReplaceEditor.getText());
410   }
411 
412   // adds a pattern in the replace history list
413   // the pattern to be added is given by the param c
414 
415   private void addReplaceHistory(String c)
416   {
417     if (c == null)
418       return;
419 
420     for (int i = 0; i < fieldReplace.getItemCount(); i++)
421     {
422       if (((String) fieldReplace.getItemAt(i)).equals(c))
423         return;
424     }
425 
426     fieldReplace.insertItemAt(c, 0);
427     if (fieldReplace.getItemCount() > 25)
428     {
429       //for (int i = 24; i < fieldReplace.getItemCount(); i++)
430 
431 // patch added by gandalf march 25 2003
432       for (int i = 25; i < fieldReplace.getItemCount();)
433 // patch added by gandalf march 25 2003
434         fieldReplace.removeItemAt(i);
435     }
436 
437     //Search.setReplacePattern(fieldReplaceEditor.getText());
438     fieldReplaceEditor.setText((String) fieldReplace.getItemAt(0));
439   }
440 
441   // Catch the action performed and then look for its source
442   // According to the source object we call appropriate methods
443 
444   public void actionPerformed(ActionEvent evt)
445   {
446     Object source = evt.getSource();
447     if (source == btnCancel)
448       exit();
449     else if (source == btnFind)
450       doFind();
451     else if (source == btnReplace)
452       doReplace();
453     else if (source == btnReplaceAll)
454       doReplaceAll();
455     else if (source == scripted)
456     {
457       script.setEnabled(scripted.isSelected());
458       fieldReplace.setEnabled(!scripted.isSelected());
459     }
460   }
461 
462   private void setSettings()
463   {
464     Search.setFindPattern(fieldSearchEditor.getText());
465     Search.setIgnoreCase(checkIgnoreCase.isSelected());
466     Search.setRegexp(useRegexp.isSelected());
467     if (type == REPLACE)
468     {
469       Search.setReplacePattern(fieldReplaceEditor.getText());
470       Search.setPythonScript(scripted.isSelected());
471       Search.setPythonScriptString(script.getText());
472     }
473   }
474 
475   // replace all the occurences of search pattern by
476   // the replace one. If 'All Files' is checked, this is
477   // done in all the opened file in the component 'parent'
478 
479   private void doReplaceAll()
480   {
481     Utilities.setCursorOnWait(this, true);
482     addReplaceHistory();
483     addSearchHistory();
484 
485     try
486     {
487 
488       if (allFiles.isSelected())
489       {
490         parent.setBatchMode(true);
491 
492         JextTextArea textArea;
493         JextTextArea[] areas = parent.getTextAreas();
494 
495         for (int i = 0; i < areas.length; i ++)
496         {
497           textArea = areas[i];
498           setSettings();
499           Search.replaceAll(textArea, 0,  textArea.getLength());
500         }
501 
502         parent.setBatchMode(false);
503       } else  {
504         JextTextArea textArea = parent.getTextArea();
505         setSettings();
506         if (Search.replaceAll(textArea, 0, textArea.getLength()) == 0)
507         {
508           Utilities.beep();
509         }
510       }
511 
512     } catch (Exception e) {
513       // nothing
514     } finally {
515      Utilities.setCursorOnWait(this, false);
516     }
517   }
518 
519   // replaces specified search pattern by the replace one.
520   // this is done only if a match is found.
521 
522   private void doReplace()
523   {
524     Utilities.setCursorOnWait(this, true);
525     addReplaceHistory();
526     addSearchHistory();
527 
528     try
529     {
530 
531       JextTextArea textArea = parent.getTextArea();
532       setSettings();
533 
534       if (!Search.replace(textArea))
535       {
536         Utilities.beep();
537       } else
538         find(textArea);
539 
540     } catch (Exception e) {
541       // nothing
542     } finally {
543       Utilities.setCursorOnWait(this, false);
544     }
545   }
546 
547   // finds the next occurence of current search pattern
548   // the search is done in current text area
549 
550   private void doFind()
551   {
552     Utilities.setCursorOnWait(this, true);
553 
554     addSearchHistory();
555     find(parent.getTextArea());
556 
557     Utilities.setCursorOnWait(this, false);
558   }
559 
560   // finds the next occurence of the search pattern in a
561   // a given text area. if match is not found, and if user
562   // don't ask to start over from beginning, then the method
563   // calls itself by specifying next opened text area.
564 
565   private void find(JextTextArea textArea)
566   {
567     setSettings();
568 
569     try
570     {
571       if (!Search.find(textArea, textArea.getCaretPosition()))
572       {
573         String[] args = { textArea.getName() };
574         int response = JOptionPane.showConfirmDialog(null,
575                        Jext.getProperty("find.matchnotfound", args),
576                        Jext.getProperty("find.title"),
577                        (allFiles.isSelected() ?
578                         JOptionPane.YES_NO_CANCEL_OPTION : JOptionPane.YES_NO_OPTION),
579                        JOptionPane.QUESTION_MESSAGE);
580 
581         switch (response)
582         {
583           case JOptionPane.YES_OPTION:
584             textArea.setCaretPosition(0);
585             find(textArea);
586             break;
587           case JOptionPane.NO_OPTION:
588             if (allFiles.isSelected())
589             {
590               JextTabbedPane pane = parent.getTabbedPane();
591               int index = pane.indexOfComponent(textArea);
592 
593               Component c = null;
594               while (c == null && !(c instanceof JextTextArea))
595               {
596                 index++;
597                 if (index == pane.getTabCount())
598                   index = 0;
599                 c = pane.getComponentAt(index);
600               }
601 
602               JextTextArea area = (JextTextArea) c;
603               if (area != textArea)
604                 find(area);
605             }
606             break;
607           case JOptionPane.CANCEL_OPTION:
608             return;
609         }
610       }
611     } catch (Exception e) { }
612   }
613 
614   class KeyHandler extends KeyAdapter
615   {
616     public void keyPressed(KeyEvent evt)
617     {
618       switch (evt.getKeyCode())
619       {
620         case KeyEvent.VK_ENTER:
621           if (evt.getSource() == fieldSearchEditor)
622             doFind();
623           else if (evt.getSource() == fieldReplaceEditor)
624             doReplace();
625           break;
626         case KeyEvent.VK_ESCAPE:
627           exit();
628       }
629     }
630   }
631 
632   /***************************************************************************
633   Patch
634      -> Memory management improvements : it may help the garbage collector.
635      -> Author : Julien Ponge (julien@izforge.com)
636      -> Date : 23, May 2001
637   ***************************************************************************/
638   protected void finalize() throws Throwable
639   {
640     super.finalize();
641 
642     parent = null;
643     fieldSearch = null;
644     fieldReplace = null;
645     fieldSearchEditor = null;
646     fieldReplaceEditor = null;
647     btnFind = null;
648     btnReplace = null;
649     btnReplaceAll = null;
650     btnCancel = null;
651     checkIgnoreCase = null;
652     saveStates = null;
653     useRegexp = null;
654     allFiles = null;
655   }
656   // End of patch
657 }
658 
659 // End of FindReplace.java