KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > ui > FindReplacePanel


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.ui;
35
36 import java.awt.*;
37 import java.awt.event.*;
38
39 import javax.swing.*;
40 import javax.swing.event.*;
41 import javax.swing.text.*;
42 import java.awt.datatransfer.*;
43 import java.io.File JavaDoc;
44 import java.util.LinkedList JavaDoc;
45
46 import edu.rice.cs.drjava.DrJava;
47 import edu.rice.cs.drjava.config.*;
48 import edu.rice.cs.drjava.model.SingleDisplayModel;
49 import edu.rice.cs.drjava.model.OpenDefinitionsDocument;
50 import edu.rice.cs.drjava.model.FindReplaceMachine;
51 import edu.rice.cs.drjava.model.FindResult;
52 import edu.rice.cs.drjava.model.ClipboardHistoryModel;
53 import edu.rice.cs.drjava.model.DocumentRegion;
54 import edu.rice.cs.drjava.model.MovingDocumentRegion;
55 import edu.rice.cs.drjava.model.RegionManager;
56 import edu.rice.cs.drjava.model.FileMovedException;
57
58 import edu.rice.cs.util.swing.BorderlessScrollPane;
59 import edu.rice.cs.util.swing.Utilities;
60 import edu.rice.cs.util.text.AbstractDocumentInterface;
61 import edu.rice.cs.util.text.SwingDocument;
62 import edu.rice.cs.util.UnexpectedException;
63 import edu.rice.cs.util.Lambda;
64 import edu.rice.cs.util.StringOps;
65
66 /** The tabbed panel that handles requests for finding and replacing text.
67  * @version $Id: FindReplacePanel.java 4042 2006-11-22 17:36:03Z rcartwright $
68  */

69 class FindReplacePanel extends TabbedPanel implements ClipboardOwner {
70
71   private JButton _findNextButton;
72   private JButton _findPreviousButton;
73   private JButton _findAllButton;
74   private JButton _replaceButton;
75   private JButton _replaceFindNextButton;
76   private JButton _replaceFindPreviousButton;
77   private JButton _replaceAllButton;
78
79   private JTextPane _findField;
80   private JTextPane _replaceField;
81
82   private JLabel _findLabelBot; // Dynamically updated
83

84   private JCheckBox _ignoreCommentsAndStrings;
85   private JCheckBox _matchCase;
86   private JCheckBox _searchAllDocuments;
87   private JCheckBox _matchWholeWord;
88
89   private FindReplaceMachine _machine;
90   private SingleDisplayModel _model;
91   private DefinitionsPane _defPane = null;
92   private boolean _caretChanged;
93   
94   /** Listens for changes to the cursor position in order to reset the start position */
95   private CaretListener _caretListener = new CaretListener() {
96     public void caretUpdate(CaretEvent e) {
97       Utilities.invokeLater(new Runnable JavaDoc() {
98         public void run() {
99           _replaceAction.setEnabled(false);
100           _replaceFindNextAction.setEnabled(false);
101           _replaceFindPreviousAction.setEnabled(false);
102           _machine.positionChanged();
103           _caretChanged = true;
104         }
105       });
106     }
107   };
108   
109   /** The action performed when searching forwards */
110   private Action _findNextAction = new AbstractAction("Find Next") {
111     public void actionPerformed(ActionEvent e) { findNext(); }
112   };
113   
114   private Action _findPreviousAction = new AbstractAction("Find Previous") {
115     public void actionPerformed(ActionEvent e) { findPrevious(); }
116   };
117   
118   private Action _findAllAction = new AbstractAction("Find All") {
119     public void actionPerformed(final ActionEvent e) {
120       if (_findField.getText().length() > 0) {
121         String JavaDoc searchStr = _findField.getText();
122         String JavaDoc title = searchStr;
123         if (title.length() > 10) { title = title.substring(0,10) + "..."; }
124         title = "Find: " + title;
125         
126         final RegionManager<MovingDocumentRegion> rm = _model.createFindResultsManager();
127         final FindResultsPanel panel = _frame.createFindResultsPanel(rm, title);
128         
129         _updateMachine();
130         _machine.setFindWord(searchStr);
131         _machine.setReplaceWord(_replaceField.getText());
132         _frame.clearStatusMessage();
133         final OpenDefinitionsDocument startDoc = _defPane.getOpenDefDocument();
134         final LinkedList JavaDoc<FindResult> results = new LinkedList JavaDoc<FindResult>();
135         
136         _frame.hourglassOn();
137         try {
138           final int count = _machine.processAll(new Lambda<Void JavaDoc, FindResult>() {
139             public Void JavaDoc apply(final FindResult fr) {
140               results.add(fr);
141               return null;
142             }
143           });
144           
145           // list of documents that have been reverted in the process of "find all"
146
LinkedList JavaDoc<OpenDefinitionsDocument> reverted = new LinkedList JavaDoc<OpenDefinitionsDocument>();
147           
148           for (FindResult fr: results) {
149             if (reverted.contains(fr.getDocument())) {
150               // skipping document because we have previously noticed that it has been modified,
151
// i.e. the document is in the reverted list
152
continue;
153             }
154             
155             // get the original time stamp
156
long origts = fr.getDocument().getTimestamp();
157             
158             if (!_model.getActiveDocument().equals(fr.getDocument())) {
159               _model.setActiveDocument(fr.getDocument());
160             }
161             else _model.refreshActiveDocument();
162             
163             final OpenDefinitionsDocument doc = _defPane.getOpenDefDocument();
164             
165             // get the time stamp after making the document the active one
166
long newts = doc.getTimestamp();
167             if (newts!=origts) {
168               // timestamps changed, document has been modified, so all our FindResults
169
// may not apply anymore. we are going to discard all FindResults for this
170
// document.
171
// add thi document to the list of reverted documents
172
reverted.add(doc);
173               continue;
174             }
175             
176             final StringBuilder JavaDoc sb = new StringBuilder JavaDoc();
177             try {
178               int endSel = fr.getFoundOffset();
179               int startSel = endSel-_machine.getFindWord().length();
180               final Position startPos = doc.createPosition(startSel);
181               final Position endPos = doc.createPosition(endSel);
182               
183               // create excerpt string
184
int excerptEndSel = doc.getLineEndPos(endSel);
185               int excerptStartSel = doc.getLineStartPos(startSel);
186               int length = Math.min(120, excerptEndSel - excerptStartSel);
187               
188               // this highlights the actual region in red
189
int startRed = startSel - excerptStartSel;
190               int endRed = endSel - excerptStartSel;
191               String JavaDoc s = doc.getText(excerptStartSel, length);
192               
193               // change control characters and ones that may not be displayed to spaces
194
for(int i = 0; i < s.length(); ++i) {
195                 if ((s.charAt(i) < ' ') || (s.charAt(i) > 127)) { sb.append(' '); } else { sb.append(s.charAt(i)); }
196               }
197               s = sb.toString();
198               
199               // trim the front
200
for(int i = 0; i < s.length(); ++i) {
201                 if (! Character.isWhitespace(s.charAt(i))) break;
202                 --startRed;
203                 --endRed;
204               }
205               
206               // trim the end
207
s = s.trim();
208               
209               // bound startRed and endRed
210
if (startRed < 0) { startRed = 0; }
211               if (startRed > s.length()) { startRed = s.length(); }
212               if (endRed < startRed) { endRed = startRed; }
213               if (endRed > s.length()) { endRed = s.length(); }
214               
215               // create the excerpt string
216
sb.setLength(0);
217               sb.append(StringOps.encodeHTML(s.substring(0, startRed)));
218               sb.append("<font color=#ff0000>");
219               sb.append(StringOps.encodeHTML(s.substring(startRed, endRed)));
220               sb.append("</font>");
221               sb.append(StringOps.encodeHTML(s.substring(endRed)));
222               rm.addRegion(new MovingDocumentRegion(doc, doc.getFile(), startPos, endPos, sb.toString()));
223             }
224             catch (FileMovedException fme) {
225               throw new UnexpectedException(fme);
226             }
227             catch (BadLocationException ble) {
228               throw new UnexpectedException(ble);
229             }
230           }
231           
232           SwingUtilities.invokeLater(new Runnable JavaDoc() {
233             public void run() {
234               _model.setActiveDocument(startDoc);
235               Toolkit.getDefaultToolkit().beep();
236               _frame.setStatusMessage("Found " + count + " occurrence" + ((count == 1) ? "" : "s") + ".");
237               if (count>0) {
238                 _frame.showFindResultsPanel(panel);
239               }
240               else {
241                 panel.freeResources();
242               }
243             }
244           });
245         }
246         finally { _frame.hourglassOff(); }
247       }
248     }
249   };
250   
251   private Action _doFindAction = new AbstractAction("Do Find") {
252     public void actionPerformed(ActionEvent e) { _doFind(); }
253   };
254                                                             
255   private Action _replaceAction = new AbstractAction("Replace") {
256     public void actionPerformed(ActionEvent e) {
257       _updateMachine();
258       _machine.setFindWord(_findField.getText());
259       String JavaDoc replaceWord = _replaceField.getText();
260       _machine.setReplaceWord(replaceWord);
261       _frame.clearStatusMessage();
262
263       // replaces the occurrence at the current position
264
boolean replaced = _machine.replaceCurrent();
265       if (replaced) _selectReplacedItem(replaceWord.length());
266       _replaceAction.setEnabled(false);
267       _replaceFindNextAction.setEnabled(false);
268       _replaceFindPreviousAction.setEnabled(false);
269       _replaceButton.requestFocusInWindow();
270     }
271   };
272
273   private Action _replaceFindNextAction = new AbstractAction("Replace/Find Next") {
274     public void actionPerformed(ActionEvent e) {
275       if (getSearchBackwards() == true) {
276         _machine.positionChanged();
277         findNext();
278       }
279       _updateMachine();
280       _machine.setFindWord(_findField.getText());
281       String JavaDoc replaceWord = _replaceField.getText();
282       _machine.setReplaceWord(replaceWord);
283       _frame.clearStatusMessage(); // _message.setText(""); // JL
284

285       // replaces the occurrence at the current position
286
boolean replaced = _machine.replaceCurrent();
287       // and finds the next word
288
if (replaced) {
289         _selectReplacedItem(replaceWord.length());
290         findNext();
291         _replaceFindNextButton.requestFocusInWindow();
292       }
293       else {
294         _replaceAction.setEnabled(false);
295         _replaceFindNextAction.setEnabled(false);
296         _replaceFindPreviousAction.setEnabled(false);
297         Toolkit.getDefaultToolkit().beep();
298         _frame.setStatusMessage("Replace failed.");
299       }
300     }
301   };
302   
303   private Action _replaceFindPreviousAction = new AbstractAction("Replace/Find Previous") {
304     public void actionPerformed(ActionEvent e) {
305       if (getSearchBackwards() == false) {
306         _machine.positionChanged();
307         findPrevious();
308       }
309       _updateMachine();
310       _machine.setFindWord(_findField.getText());
311       String JavaDoc replaceWord = _replaceField.getText();
312       _machine.setReplaceWord(replaceWord);
313       _frame.clearStatusMessage();
314       
315       // replaces the occurrence at the current position
316
boolean replaced = _machine.replaceCurrent();
317       // and finds the previous word
318
if (replaced) {
319         _selectReplacedItem(replaceWord.length());
320         findPrevious();
321         _replaceFindPreviousButton.requestFocusInWindow();
322       }
323       else {
324         _replaceAction.setEnabled(false);
325         _replaceFindNextAction.setEnabled(false);
326         _replaceFindPreviousAction.setEnabled(false);
327         Toolkit.getDefaultToolkit().beep();
328         _frame.setStatusMessage("Replace failed.");
329       }
330     }
331   };
332
333   /** Replaces all occurences of the findfield text with that of the replacefield text both before and after the cursor
334    * without prompting for wrapping around the end of the document.
335    */

336   private Action _replaceAllAction = new AbstractAction("Replace All") {
337     public void actionPerformed(ActionEvent e) {
338       _updateMachine();
339       _machine.setFindWord(_findField.getText());
340       _machine.setReplaceWord(_replaceField.getText());
341       _frame.clearStatusMessage();
342       int count = _machine.replaceAll();
343       Toolkit.getDefaultToolkit().beep();
344       _frame.setStatusMessage("Replaced " + count + " occurrence" + ((count == 1) ? "" :
345                                                                            "s") + ".");
346       _replaceAction.setEnabled(false);
347       _replaceFindNextAction.setEnabled(false);
348       _replaceFindPreviousAction.setEnabled(false);
349     }
350   };
351   
352   // Inserts '\n' into a text field. (The default binding for "enter" is to insert
353
// the system-specific newline string (I think), which causes trouble when finding
354
// in files with different newline strings.)
355
// TODO: Standardize on \n in a post-processing step, rather than mucking around
356
// in the workings of a text editor field. (Notice, for example, that this
357
// doesn't correctly handle an 'enter' pressed while some text is selected.)
358
Action _standardNewlineAction = new TextAction("NewLine Action") {
359     public void actionPerformed(ActionEvent e) {
360       JTextComponent c = getTextComponent(e);
361       String JavaDoc text = c.getText();
362       int caretPos = c.getCaretPosition();
363       String JavaDoc textBeforeCaret = text.substring(0, caretPos);
364       String JavaDoc textAfterCaret = text.substring(caretPos);
365       c.setText(textBeforeCaret.concat("\n").concat(textAfterCaret));
366       c.setCaretPosition(caretPos+1);
367   }
368 };
369
370
371   /*private Action _closeAction = new AbstractAction("X") {
372    public void actionPerformed(ActionEvent e) {
373    // removeTab automatically calls show()
374    _close();
375    }
376    };*/

377     
378             
379   /** Standard Constructor.
380    * @param frame the overall enclosing window
381    * @param model the model containing the documents to search
382    */

383   public FindReplacePanel(MainFrame frame, SingleDisplayModel model) {
384     super(frame, "Find/Replace");
385     _model = model;
386     _machine = new FindReplaceMachine(_model, _model.getDocumentIterator());
387     _updateMachine();
388     
389     
390     /********* Button Initialization ********/
391     _findNextButton = new JButton(_findNextAction);
392     _findPreviousButton = new JButton(_findPreviousAction);
393     _findAllButton = new JButton(_findAllAction);
394     _replaceButton = new JButton(_replaceAction);
395     _replaceFindNextButton = new JButton(_replaceFindNextAction);
396     _replaceFindPreviousButton = new JButton(_replaceFindPreviousAction);
397     _replaceAllButton = new JButton(_replaceAllAction);
398
399     _replaceAction.setEnabled(false);
400     _replaceFindNextAction.setEnabled(false);
401     _replaceFindPreviousAction.setEnabled(false);
402
403     
404     /********* Find/Replace Field Initialization **********/
405     _findField = new JTextPane(new DefaultStyledDocument());
406     _replaceField = new JTextPane(new SwingDocument());
407     
408     // Ignore special treatment of 'tab' in text panes
409
int tabForward = KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS;
410     int tabBackward = KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS;
411     _findField.setFocusTraversalKeys(tabForward, null);
412     _replaceField.setFocusTraversalKeys(tabForward, null);
413     _findField.setFocusTraversalKeys(tabBackward, null);
414     _replaceField.setFocusTraversalKeys(tabBackward, null);
415     
416     // Define custom key bindings for 'enter' and 'tab'
417
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
418     KeyStroke ctrlEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Event.CTRL_MASK);
419     KeyStroke ctrlTab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, Event.CTRL_MASK);
420     InputMap findIM = _findField.getInputMap();
421     InputMap replaceIM = _replaceField.getInputMap();
422     findIM.put(enter, "Do Find");
423     findIM.put(ctrlEnter, "Insert Newline");
424     findIM.put(ctrlTab, "Insert Tab");
425     findIM.put(DrJava.getConfig().getSetting(OptionConstants.KEY_CUT), "Cut");
426     findIM.put(DrJava.getConfig().getSetting(OptionConstants.KEY_COPY), "Copy");
427     replaceIM.put(enter, "Insert Newline");
428     replaceIM.put(ctrlEnter, "Insert Newline");
429     replaceIM.put(ctrlTab, "Insert Tab");
430     replaceIM.put(DrJava.getConfig().getSetting(OptionConstants.KEY_CUT), "Cut");
431     replaceIM.put(DrJava.getConfig().getSetting(OptionConstants.KEY_COPY), "Copy");
432     
433     Action insertTabAction = new DefaultEditorKit.InsertTabAction();
434     ActionMap findAM = _findField.getActionMap();
435     ActionMap replaceAM = _replaceField.getActionMap();
436     findAM.put("Do Find", _doFindAction);
437     findAM.put("Insert Newline", _standardNewlineAction);
438     findAM.put("Insert Tab", insertTabAction);
439     findAM.put("Cut", cutAction);
440     findAM.put("Copy", copyAction);
441     replaceAM.put("Insert Newline", _standardNewlineAction);
442     replaceAM.put("Insert Tab", insertTabAction);
443     replaceAM.put("Cut", cutAction);
444     replaceAM.put("Copy", copyAction);
445     
446     // Setup color listeners.
447
new ForegroundColorListener(_findField);
448     new BackgroundColorListener(_findField);
449     new ForegroundColorListener(_replaceField);
450     new BackgroundColorListener(_replaceField);
451     Font font = DrJava.getConfig().getSetting(OptionConstants.FONT_MAIN);
452     setFieldFont(font);
453     
454     
455     /******** Label Initializations ********/
456     // Create the Structure for the replace label
457
JLabel _replaceLabelTop = new JLabel("Replace", SwingConstants.RIGHT);
458     JLabel _replaceLabelBot = new JLabel("With", SwingConstants.RIGHT);
459     
460     JPanel replaceLabelPanelTop = new JPanel(new BorderLayout(5,5));
461     JPanel replaceLabelPanelBot = new JPanel(new BorderLayout(5,5));
462     JPanel replaceLabelPanel = new JPanel(new GridLayout(2,1));
463     
464     replaceLabelPanelTop.add(_replaceLabelTop, BorderLayout.SOUTH);
465     replaceLabelPanelBot.add(_replaceLabelBot, BorderLayout.NORTH);
466     
467     replaceLabelPanel.add(replaceLabelPanelTop);
468     replaceLabelPanel.add(replaceLabelPanelBot);
469     
470     
471     // Create the stucture for the find label
472
JLabel _findLabelTop = new JLabel("Find", SwingConstants.RIGHT);
473     _findLabelBot = new JLabel("Next", SwingConstants.RIGHT);
474     
475     JPanel findLabelPanelTop = new JPanel(new BorderLayout(5,5));
476     JPanel findLabelPanelBot = new JPanel(new BorderLayout(5,5));
477     JPanel findLabelPanel = new JPanel(new GridLayout(2,1));
478     
479     findLabelPanelTop.add(_findLabelTop, BorderLayout.SOUTH);
480     findLabelPanelBot.add(_findLabelBot, BorderLayout.NORTH);
481     
482     findLabelPanel.add(findLabelPanelTop);
483     findLabelPanel.add(findLabelPanelBot);
484
485     
486     /******** Button Panel ********/
487     JPanel buttons = new JPanel();
488     buttons.setLayout(new GridLayout(1,0,5,0));
489     buttons.add(_findNextButton);
490     buttons.add(_findPreviousButton);
491     buttons.add(_findAllButton);
492     buttons.add(_replaceFindNextButton);
493     buttons.add(_replaceFindPreviousButton);
494     buttons.add(_replaceButton);
495     buttons.add(_replaceAllButton);
496    
497     
498     /******** Listeners for the right-hand check boxes ********/
499     boolean matchCaseSelected = DrJava.getConfig().getSetting(OptionConstants.FIND_MATCH_CASE);
500     _matchCase = new JCheckBox("Match Case", matchCaseSelected);
501     _machine.setMatchCase(matchCaseSelected);
502     _matchCase.addItemListener(new ItemListener() {
503       public void itemStateChanged(ItemEvent e) {
504         boolean isSelected = (e.getStateChange() == ItemEvent.SELECTED);
505         _machine.setMatchCase(isSelected);
506         DrJava.getConfig().setSetting(OptionConstants.FIND_MATCH_CASE, isSelected);
507         _findField.requestFocusInWindow();
508       }
509     });
510     
511     boolean searchAllSelected = DrJava.getConfig().getSetting(OptionConstants.FIND_ALL_DOCUMENTS);
512     _searchAllDocuments = new JCheckBox("Search All Documents", searchAllSelected);
513     _machine.setSearchAllDocuments(searchAllSelected);
514     _searchAllDocuments.addItemListener(new ItemListener() {
515       public void itemStateChanged(ItemEvent e) {
516         boolean isSelected = (e.getStateChange() == ItemEvent.SELECTED);
517         _machine.setSearchAllDocuments(isSelected);
518         DrJava.getConfig().setSetting(OptionConstants.FIND_ALL_DOCUMENTS, isSelected);
519         _findField.requestFocusInWindow();
520       }
521     });
522     
523     boolean matchWordSelected = DrJava.getConfig().getSetting(OptionConstants.FIND_WHOLE_WORD);
524     _matchWholeWord = new JCheckBox("Whole Word", matchWordSelected);
525     if (matchWordSelected) { _machine.setMatchWholeWord(); }
526     else { _machine.setFindAnyOccurrence(); }
527     _matchWholeWord.addItemListener(new ItemListener() {
528       public void itemStateChanged(ItemEvent e) {
529         boolean isSelected = (e.getStateChange() == ItemEvent.SELECTED);
530         if (isSelected) { _machine.setMatchWholeWord(); }
531         else { _machine.setFindAnyOccurrence(); }
532         DrJava.getConfig().setSetting(OptionConstants.FIND_WHOLE_WORD, isSelected);
533         _findField.requestFocusInWindow();
534       }
535     });
536     
537     boolean ignoreCommentsSelected = DrJava.getConfig().getSetting(OptionConstants.FIND_NO_COMMENTS_STRINGS);
538     _ignoreCommentsAndStrings = new JCheckBox("No Comments/Strings", ignoreCommentsSelected);
539     _machine.setIgnoreCommentsAndStrings(ignoreCommentsSelected);
540     _ignoreCommentsAndStrings.addItemListener(new ItemListener() {
541       public void itemStateChanged(ItemEvent e) {
542         boolean isSelected = (e.getStateChange() == ItemEvent.SELECTED);
543         _machine.setIgnoreCommentsAndStrings(isSelected);
544         DrJava.getConfig().setSetting(OptionConstants.FIND_NO_COMMENTS_STRINGS, isSelected);
545         _findField.requestFocusInWindow();
546       }
547     });
548     
549     // We choose not to preserve backwards searching between sessions
550
//_machine.setSearchBackwards(DrJava.getConfig().getSetting(OptionConstants.FIND_SEARCH_BACKWARDS));
551

552
553     /******** Initialize the panels containing the checkboxes ********/
554     this.removeAll(); // actually, override the behavior of TabbedPanel
555

556     // remake closePanel
557
_closePanel = new JPanel(new BorderLayout());
558     _closePanel.add(_closeButton, BorderLayout.NORTH);
559
560     JPanel _lowerCheckPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
561     _lowerCheckPanel.add(_matchWholeWord);
562     _lowerCheckPanel.add(_ignoreCommentsAndStrings);
563     _lowerCheckPanel.setMaximumSize(new Dimension(200, 40));
564
565     JPanel _matchCaseAndAllDocsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
566     _matchCase.setPreferredSize(_matchWholeWord.getPreferredSize());
567     _matchCaseAndAllDocsPanel.add(_matchCase);
568     _matchCaseAndAllDocsPanel.add(_searchAllDocuments);
569     _matchCaseAndAllDocsPanel.setMaximumSize(new Dimension(200, 40));
570
571     BorderlessScrollPane _findPane = new BorderlessScrollPane(_findField);
572     BorderlessScrollPane _replacePane = new BorderlessScrollPane(_replaceField);
573     _findPane.setHorizontalScrollBarPolicy(BorderlessScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
574     _replacePane.setHorizontalScrollBarPolicy(BorderlessScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
575     
576     JPanel findPanel = new JPanel(new BorderLayout(5,5));
577     findPanel.add(findLabelPanel, BorderLayout.WEST);
578     findPanel.add(_findPane, BorderLayout.CENTER);
579     
580     JPanel replacePanel = new JPanel(new BorderLayout(5,5));
581     replacePanel.add(replaceLabelPanel, BorderLayout.WEST);
582     replacePanel.add(_replacePane, BorderLayout.CENTER);
583         
584     /******** Set up the Panel containing the Text Fields ********/
585     JPanel leftPanel = new JPanel(new GridLayout(1,2,5,5));
586     leftPanel.add(findPanel);
587     leftPanel.add(replacePanel);
588
589     /******** Set up the Panel containing both rows of checkboxes ********/
590     GridBagLayout gbLayout = new GridBagLayout();
591     GridBagConstraints c = new GridBagConstraints();
592     JPanel emptyPanel = new JPanel();
593     JPanel optionsPanel = new JPanel(gbLayout);
594     optionsPanel.setLayout(gbLayout);
595     optionsPanel.add(_matchCaseAndAllDocsPanel);
596     optionsPanel.add(_lowerCheckPanel);
597     optionsPanel.add(emptyPanel);
598     
599     c.fill = GridBagConstraints.HORIZONTAL;
600     c.anchor = GridBagConstraints.NORTH;
601     c.gridwidth = GridBagConstraints.REMAINDER;
602     c.weightx = 1.0;
603     gbLayout.setConstraints(_matchCaseAndAllDocsPanel, c);
604     gbLayout.setConstraints(_lowerCheckPanel, c);
605     
606     c.fill = GridBagConstraints.BOTH;
607     c.anchor = GridBagConstraints.SOUTH;
608     c.gridheight = GridBagConstraints.REMAINDER;
609     c.weighty = 1.0;
610     
611     gbLayout.setConstraints(emptyPanel, c);
612
613     /******** Set up the Panel containing the two above main panels ********/
614     JPanel midPanel = new JPanel(new BorderLayout(5,5));
615     midPanel.add(leftPanel, BorderLayout.CENTER);
616     midPanel.add(optionsPanel, BorderLayout.EAST);
617     
618     
619     /******** Set up the Panel containing the midPanel and the closePanel ********/
620      JPanel _rightPanel = new JPanel(new BorderLayout(5, 5));
621     _rightPanel.add(midPanel, BorderLayout.CENTER);
622     _rightPanel.add(_closePanel, BorderLayout.EAST);
623     
624     JPanel newPanel = new JPanel();
625     newPanel.setLayout(new BoxLayout(newPanel, BoxLayout.Y_AXIS));
626     newPanel.add(_rightPanel);
627     newPanel.add(Box.createVerticalStrut(5));
628     newPanel.add(buttons);
629     newPanel.add(Box.createVerticalStrut(5));
630     
631     this.add(newPanel);
632     
633     /******** Document, Focus and Key Listeners ********/
634     
635     // DocumentListener that keeps track of changes in the find field.
636
_findField.getDocument().addDocumentListener(new DocumentListener() {
637       
638       /**If attributes in the find field have changed, gray out "Replace" & "Replace and Find Next" buttons.
639        * @param e the event caught by this listener
640        */

641       public void changedUpdate(DocumentEvent e) { _updateHelper(); }
642
643       /** If text has been changed in the find field, gray out "Replace" & "Replace and Find Next" buttons.
644        * @param e the event caught by this listener
645        */

646       public void insertUpdate(DocumentEvent e) { _updateHelper(); }
647       
648       /** If text has been changed in the find field, gray out "Replace" & "Replace and Find Next" buttons.
649        * @param e the event caught by this listener
650        */

651       public void removeUpdate(DocumentEvent e) { _updateHelper(); }
652       
653       private void _updateHelper() {
654         Utilities.invokeLater(new Runnable JavaDoc() {
655           public void run() {
656 // _machine.makeCurrentOffsetStart();
657
updateFirstDocInSearch();
658             _replaceAction.setEnabled(false);
659             _replaceFindNextAction.setEnabled(false);
660             _replaceFindPreviousAction.setEnabled(false);
661             _machine.positionChanged();
662             if (_findField.getText().equals("")) _replaceAllAction.setEnabled(false);
663             else _replaceAllAction.setEnabled(true);
664             updateUI();
665           }
666         });
667       }
668     });
669     
670   }
671     
672     
673
674   /** Focuses the find/replace dialog in the window, placing the focus on the _findField, and selecting all the text.*/
675   public boolean requestFocusInWindow() {
676     super.requestFocusInWindow();
677     _findField.selectAll();
678     return _findField.requestFocusInWindow();
679   }
680
681   /** Getter method for the _findField component */
682   JTextPane getFindField() { return _findField; }
683
684   /** Called when user the activates "find next" command. Package visibility to accommodate calls from MainFrame. */
685   void findNext() {
686     _machine.setSearchBackwards(false);
687     _findLabelBot.setText("Next");
688     _doFind();
689   }
690   
691   /** Called when user the activates "find previous" command. Package visibility to accommodate calls from MainFrame. */
692   void findPrevious() {
693     _machine.setSearchBackwards(true);
694     _findLabelBot.setText("Prev");
695     _doFind();
696   }
697   
698   /** Called from MainFrame in response to opening this or changes in the active document. */
699   void beginListeningTo(DefinitionsPane defPane) {
700     if (_defPane == null) {
701       // removed so it doesn't give the pane focus when switching documents
702
// requestFocusInWindow();
703
_displayed = true;
704       _defPane = defPane;
705       _defPane.addCaretListener(_caretListener);
706       _caretChanged = true;
707       
708       _updateMachine();
709       _machine.setFindWord(_findField.getText());
710       _machine.setReplaceWord(_replaceField.getText());
711       _frame.clearStatusMessage(); // _message.setText(""); // JL
712
if (! _machine.onMatch() || _findField.getText().equals("")) {
713         _replaceAction.setEnabled(false);
714         _replaceFindNextAction.setEnabled(false);
715         _replaceFindPreviousAction.setEnabled(false);
716       }
717       else {
718         _replaceAction.setEnabled(true);
719         _replaceFindNextAction.setEnabled(true);
720         _replaceFindPreviousAction.setEnabled(true);
721         _machine.setLastFindWord();
722       }
723
724       if (_findField.getText().equals("")) _replaceAllAction.setEnabled(false);
725       else _replaceAllAction.setEnabled(true);
726
727       _frame.clearStatusMessage();
728     }
729     else
730       throw new UnexpectedException(new RuntimeException JavaDoc("FindReplacePanel should not be listening to anything"));
731   }
732
733   /** Called from MainFrame upon closing this Dialog or changes in the active document. */
734   public void stopListening() {
735     if (_defPane != null) {
736       _defPane.removeCaretListener(_caretListener);
737       _defPane = null;
738       _displayed = false;
739       _frame.clearStatusMessage();
740     }
741   }
742
743   /** Abstracted out since this is called from find and replace/find. */
744   private void _doFind() {
745
746     if (_findField.getText().length() > 0) {
747       
748       _model.addToBrowserHistory();
749
750       _updateMachine();
751       _machine.setFindWord(_findField.getText());
752       _machine.setReplaceWord(_replaceField.getText());
753       _frame.clearStatusMessage(); // _message.setText(""); // JL
754
final boolean searchAll = _machine.getSearchAllDocuments();
755       
756       // FindResult contains the document that the result was found in, offset to the next occurrence of
757
// the string, and a flag indicating whether the end of the document was wrapped around while searching
758
// for the string.
759
FindResult fr = _machine.findNext();
760       OpenDefinitionsDocument doc = fr.getDocument();
761       OpenDefinitionsDocument matchDoc = _model.getODDForDocument(doc);
762       OpenDefinitionsDocument openDoc = _defPane.getOpenDefDocument();
763       
764       final int pos = fr.getFoundOffset();
765       
766       // If there actually *is* a match, then switch active documents. otherwise don't
767
if (searchAll) {
768          if (! matchDoc.equals(openDoc)) _model.setActiveDocument(matchDoc); // set active doc if matchDoc != openDoc
769
else _model.refreshActiveDocument(); // the unmodified active document may have been kicked out of the cache!
770
}
771      
772       if (fr.getWrapped() && ! searchAll) {
773         Toolkit.getDefaultToolkit().beep();
774         if (! _machine.getSearchBackwards()) _frame.setStatusMessage("Search wrapped to beginning.");
775         else _frame.setStatusMessage("Search wrapped to end.");
776       }
777       
778       if (fr.getAllDocsWrapped() && searchAll) {
779         Toolkit.getDefaultToolkit().beep();
780         _frame.setStatusMessage("Search wrapped around all documents.");
781       }
782       
783       if (pos >= 0) { // found a match
784
Caret c = _defPane.getCaret();
785         c.setDot(c.getDot());
786         _defPane.setCaretPosition(pos);
787         _caretChanged = true;
788         _updateMachine();
789         
790         // defer executing this code until after active document switch (if any) is complete
791
SwingUtilities.invokeLater(new Runnable JavaDoc() {
792           public void run() {
793             _selectFoundItem();
794             _replaceAction.setEnabled(true);
795             _replaceFindNextAction.setEnabled(true);
796             _replaceFindPreviousAction.setEnabled(true);
797             _machine.setLastFindWord();
798 // _model.addToBrowserHistory();
799
}});
800       }
801       // else the entire document was searched and no instance of the string
802
// was found. display at most 50 characters of the non-found string
803
else {
804         Toolkit.getDefaultToolkit().beep();
805         final StringBuilder JavaDoc statusMessage = new StringBuilder JavaDoc("Search text \"");
806         if (_machine.getFindWord().length() <= 50) statusMessage.append(_machine.getFindWord());
807         else statusMessage.append(_machine.getFindWord().substring(0, 49) + "...");
808         statusMessage.append("\" not found.");
809         _frame.setStatusMessage(statusMessage.toString());
810       }
811     }
812     
813     if (!DrJava.getConfig().getSetting(OptionConstants.FIND_REPLACE_FOCUS_IN_DEFPANE).booleanValue()) {
814       _findField.requestFocusInWindow();
815     }
816   }
817
818   protected void _close() {
819     _defPane.requestFocusInWindow();
820     if (_displayed) stopListening();
821     super._close();
822     //_frame.uninstallFindReplaceDialog(this);
823
}
824
825   public void setSearchBackwards(boolean b) { _machine.setSearchBackwards(b); }
826   public boolean getSearchBackwards() { return _machine.getSearchBackwards(); }
827
828   /** Sets the font of the find and replace fields to f. */
829   public void setFieldFont(Font f) {
830     _findField.setFont(f);
831     _replaceField.setFont(f);
832   }
833   
834   /** Updates the first document where the current all-document search began (called in two places: either when the
835    * _findField is updated, or when the user changes documents.
836    */

837   public void updateFirstDocInSearch() {
838     _machine.setFirstDoc(_model.getActiveDocument());
839   }
840
841 // private static Container wrap(JComponent comp) {
842
// Container stretcher = Box.createHorizontalBox();
843
// stretcher.add(comp);
844
// stretcher.add(Box.createHorizontalGlue());
845
// return stretcher;
846
// }
847
//
848
// /** Consider a parent container. Change its layout to GridBagLayout
849
// * with 2 columns, 2 rows. Consider them quadrants in a coordinate plain.
850
// * put the arguments in their corresponding quadrants, ignoring q3.
851
// */
852
// private static void hookComponents(Container parent, JComponent q1,
853
// JComponent q2, JComponent q4) {
854
// GridBagLayout gbl = new GridBagLayout();
855
// GridBagConstraints c = new GridBagConstraints();
856
// parent.setLayout(gbl);
857
// c.fill = c.BOTH;
858
// addComp(parent, q2, c, gbl, 0, 0, 0f, 0f, 1, 0);
859
// addComp(parent, q1, c, gbl, 0, 1, 1f, 0f, 1, 0);
860
// addComp(parent, new JPanel(), c, gbl, 1, 0, 1f, 1f, 2, 0);
861
// addComp(parent, new JPanel(), c, gbl, 2, 0, 0f, 0f, 1, 0);
862
// addComp(parent, q4, c, gbl, 2, 1, 1f, 0f, 1, 0);
863
// }
864

865 // private static void addComp(Container p, JComponent child,
866
// GridBagConstraints c, GridBagLayout gbl,
867
// int row, int col,
868
// float weightx, float weighty, int gridw,
869
// int ipady) {
870
// c.gridx = col; c.gridy = row;
871
// c.weightx = weightx; c.weighty = weighty;
872
// c.gridwidth = gridw;
873
// c.ipady = ipady;
874
// gbl.setConstraints(child,c);
875
// p.add(child);
876
// }
877

878   /** Sets appropriate variables in the FindReplaceMachine if the caret has been changed. */
879   private void _updateMachine() {
880     if (_caretChanged) {
881       OpenDefinitionsDocument doc = _model.getActiveDocument();
882       _machine.setDocument(doc);
883       if (_machine.getFirstDoc() == null) _machine.setFirstDoc(doc);
884 // _machine.setStart(_defPane.getCaretPosition());
885
_machine.setPosition(_defPane.getCaretPosition());
886       _caretChanged = false;
887     }
888   }
889
890 // /** Shows the dialog and sets the focus appropriately. */
891
// public void show() {
892
// //super.show();
893
// System.err.println("*** Called show ***");
894
//// if (!isVisible())
895
// _frame.installFindReplaceDialog(this);
896
// _updateMachine();
897
// _findField.requestFocusInWindow();
898
// _findField.selectAll();
899
// }
900

901   /** This method is used to select the item that has been inserted in a replacement. */
902   private void _selectReplacedItem(int length) {
903     int from, to;
904     to = _machine.getCurrentOffset();
905     if (_machine.getSearchBackwards()) from = to + length;
906     else from = to - length;
907     _selectFoundItem(from, to);
908   }
909
910
911   /** Calls _selectFoundItem(from, to) with reasonable defaults. */
912   private void _selectFoundItem() {
913     int position = _machine.getCurrentOffset();
914     int to, from;
915     to = position;
916     if (!_machine.getSearchBackwards()) from = position - _machine.getFindWord().length();
917     else from = position + _machine.getFindWord().length();
918     _selectFoundItem(from, to);
919   }
920
921   /** Will select the searched-for text. Originally highlighted the text, but we ran into problems
922    * with the document remove method changing the view to where the cursor was located, resulting in
923    * replace constantly jumping from the replaced text back to the cursor. There was a
924    * removePreviousHighlight method which was removed since selections are removed automatically upon
925    * a caret change.
926    */

927   private void _selectFoundItem(int from, int to) {
928     _defPane.centerViewOnOffset(from);
929     _defPane.select(from, to);
930
931     // Found this little statement that will show the selected text in _defPane without giving _defPane
932
// focus, allowing the user to hit enter repeatedly and change the document while finding next.
933
SwingUtilities.invokeLater(new Runnable JavaDoc() {
934       public void run() { _defPane.getCaret().setSelectionVisible(true); }
935     });
936 // _defPane.centerViewOnOffset(from);
937
}
938
939 // private void _close() { hide(); }
940

941 // public void hide() {
942
// System.err.println("*** Called hide ***");
943
// if (_open)
944
// _frame.uninstallFindReplaceDialog(this);
945
// //super.hide();
946
// }
947

948 // private ContinueCommand CONFIRM_CONTINUE = new ContinueCommand() {
949
// public boolean shouldContinue() {
950
// String text = "The search has reached the end of the document.\n" +
951
// "Continue searching from the start?";
952
// int rc = JOptionPane.showConfirmDialog(FindReplacePanel.this,
953
// text,
954
// "Continue search?",
955
// JOptionPane.YES_NO_OPTION);
956
//
957
// switch (rc) {
958
// case JOptionPane.YES_OPTION:
959
// return true;
960
// case JOptionPane.NO_OPTION:
961
// return false;
962
// default:
963
// throw new RuntimeException("Invalid rc: " + rc);
964
// }
965
//
966
// }
967
// };
968

969   /** We lost ownership of what we put in the clipboard. */
970   public void lostOwnership(Clipboard clipboard, Transferable contents) {
971     // ignore
972
}
973   
974   /** Default cut action. */
975   Action cutAction = new DefaultEditorKit.CutAction() {
976     public void actionPerformed(ActionEvent e) {
977       if (e.getSource() instanceof JTextComponent) {
978         JTextComponent tc = (JTextComponent)e.getSource();
979         if (tc.getSelectedText()!=null) {
980           super.actionPerformed(e);
981           String JavaDoc s = edu.rice.cs.util.swing.Utilities.getClipboardSelection(FindReplacePanel.this);
982           if ((s!=null) && (s.length()!=0)){ ClipboardHistoryModel.singleton().put(s); }
983         }
984       }
985     }
986   };
987   
988   /** Default copy action. */
989   Action copyAction = new DefaultEditorKit.CopyAction() {
990     public void actionPerformed(ActionEvent e) {
991       if (e.getSource() instanceof JTextComponent) {
992         JTextComponent tc = (JTextComponent)e.getSource();
993         if (tc.getSelectedText()!=null) {
994           super.actionPerformed(e);
995           String JavaDoc s = edu.rice.cs.util.swing.Utilities.getClipboardSelection(FindReplacePanel.this);
996           if ((s!=null) && (s.length()!=0)){ ClipboardHistoryModel.singleton().put(s); }
997         }
998       }
999     }
1000  };
1001  
1002  /***************** METHODS FOR TESTING PURPOSES ONLY ***********************/
1003  public DefinitionsPane getDefPane() { return _defPane; }
1004  public JButton getFindNextButton() {return _findNextButton; }
1005  
1006
1007}
1008
Popular Tags