View Javadoc

1   /*
2    * Fsgrep is a simple Java application which allows a user to
3    * search all files in a directory structure for lines matching
4    * a given pattern.  Its functionality is a combination of the
5    * Unix 'find' and 'grep' utilities.
6    * Visit [http://fsgrep.sourceforge.net/] for more information.
7    * 
8    * Copyright (C) 2003-2006 Murali Krishnan [murali_ca_us@users.sourceforge.net]
9    * 
10   * Fsgrep is free software; you can redistribute it and/or modify
11   * it under the terms of version 2 of the GNU General Public
12   * License as published by the Free Software Foundation.
13   * 
14   * Fsgrep 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 Fsgrep (see the file named LICENSE.txt); if not, write
21   * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22   * Boston, MA  02111-1307  USA
23   */
24  
25  package mk.fsgrep.gui;
26  
27  
28  import java.awt.BorderLayout;
29  import java.awt.Frame;
30  import java.awt.event.*;
31  import java.io.*;
32  import java.util.*;
33  
34  import javax.swing.*;
35  import javax.swing.border.*;
36  import javax.swing.event.HyperlinkEvent;
37  import javax.swing.event.HyperlinkEvent.EventType;
38  import javax.swing.event.HyperlinkListener;
39  
40  import mk.fsgrep.Fsgrep;
41  import mk.fsgrep.match.MatchResult;
42  import mk.fsgrep.util.ExternalEditor;
43  import mk.fsgrep.util.PersistentData;
44  import mk.fsgrep.util.TargetFile;
45  import mk.fsgrep.util.output.DialogOutput;
46  import mk.fsgrep.util.output.TextFieldOutput;
47  import mk.fsgrep.util.thread.RunCallback;
48  import mk.fsgrep.util.thread.ThreadRunner;
49  
50  
51  /***
52   * A separate frame that displays search results.
53   * 
54   * @author  Murali Krishnan
55   *
56   */
57  public class ResultDisplay extends JFrame implements ItemListener,RunCallback {
58  
59      //------------------------------------------------------------
60      //- Class Variables
61  
62      protected static final String LAST_SAVE = "last_save";
63  
64      private static final PersistentData pdata = PersistentData.getInstance();
65  
66  
67      //------------------------------------------------------------
68      //- Class Functions
69  
70  
71  
72      //------------------------------------------------------------
73      //- Instance Variables
74  
75      private App _app = null;
76      private JTextArea _textArea = null;
77      private HtmlTablePane _htmlPane = null;
78      private JTextArea _reportArea = null;
79      private JButton _buttonOk = new JButton("Hide");
80      private JButton _buttonRefine = new JButton("Refine");
81      private JButton _buttonReplace = new JButton("Replace");
82      private JTabbedPane tabbedPane = new JTabbedPane();
83      private JCheckBox _checkWrap = new JCheckBox("word wrap");
84      private JButton _buttonSave = new JButton("Save to File");
85      private TargetFile _lastSave = null;
86      private ThreadRunner _runner = null;
87      private List<MatchResult> vResults = new ArrayList<MatchResult>();
88  
89  
90      //------------------------------------------------------------
91      //- Constructors
92  
93      public ResultDisplay(App pApp) {
94          super("Results");
95  
96          _app = pApp;
97  
98          initialize();
99      }
100 
101 
102 
103     //------------------------------------------------------------
104     //- Accessors
105 
106     protected App getApp() {return _app;}
107     protected JTextArea getTextArea() {return _textArea;}
108     protected HtmlTablePane getHtmlPane() {return _htmlPane;}
109     protected JTextArea getReportArea() {return _reportArea;}
110     protected JButton getButtonOk() {return _buttonOk;}
111     protected JButton getButtonRefine() {return _buttonRefine;}
112     protected JButton getButtonReplace() {return _buttonReplace;}
113     protected JTabbedPane getTabbedPane() {return tabbedPane;}
114     protected JCheckBox getCheckWrap() {return _checkWrap;}
115     protected JButton getButtonSave() {return _buttonSave;}
116     protected TargetFile getLastSave() {return _lastSave;}
117     protected ThreadRunner getRunner() {return _runner;}
118 
119     protected List<MatchResult> getResults() {
120         return vResults;
121     }
122 
123 
124     //------------------------------------------------------------
125     //- Settors
126 
127     protected void setTextArea(JTextArea val) {_textArea=val;}
128     protected void setHtmlPane(HtmlTablePane val) {_htmlPane=val;}
129     protected void setReportArea(JTextArea val) {_reportArea=val;}
130     protected void setLastSave(TargetFile val) {_lastSave=val;}
131     protected void setRunner(ThreadRunner val) {_runner=val;}
132 
133 
134     //------------------------------------------------------------
135     //- Private/Protected Utility Functions
136 
137     protected void initialize() {
138         String lastSaveFilename = pdata.getProperty(LAST_SAVE);
139         if (lastSaveFilename != null) {
140             setLastSave(new TargetFile(lastSaveFilename));
141         }
142 
143         setRunner(new ThreadRunner("ExternalEdit", this));
144 
145         createComponents();
146         defineActions();
147         makeFrame();
148     }
149 
150 
151     protected void createComponents() {
152         setTextArea(new JTextArea("", 10, 60));
153         getTextArea().setEditable(false);
154         getTextArea().setWrapStyleWord(true);
155 
156         setReportArea(new JTextArea("", 10, 60));
157         getReportArea().setEditable(false);
158         getReportArea().setWrapStyleWord(true);
159 
160         setHtmlPane(new HtmlTablePane());
161     }
162 
163 
164     protected void defineActions() {
165         getButtonOk().addActionListener(new ActionListener() {
166                 public void actionPerformed (ActionEvent aEvent) {
167                     setVisible(false);
168                 }
169             });
170 
171         getButtonRefine().addActionListener(new ActionListener() {
172                 public void actionPerformed (ActionEvent aEvent) {
173                     String newPattern = JOptionPane.showInputDialog("New pattern");
174                     List<TargetFile> files = findMatchFiles();
175                     getApp().performRefinedSearch(newPattern, files);
176                 }
177             });
178 
179         getButtonReplace().addActionListener(new ActionListener() {
180                 @SuppressWarnings({"UnusedDeclaration"})
181                 public void actionPerformed (ActionEvent aEvent) {
182                     String replacement = JOptionPane.showInputDialog("Replace: ");
183                     List<TargetFile> files = findMatchFiles();
184                 }
185             });
186 
187         addWindowListener(new WindowAdapter() {
188                 public void windowActivated(WindowEvent e) {
189                     getButtonOk().grabFocus();
190                 }
191             });
192 
193         getButtonSave().addActionListener(new ActionListener() {
194                 public void actionPerformed(ActionEvent aEvent) {
195                     saveSearchResults();
196                 }
197             });
198 
199         getHtmlPane().addHyperlinkListener(new HyperlinkListener() {
200                 public void hyperlinkUpdate(HyperlinkEvent he) {
201                     if (EventType.ACTIVATED.equals(he.getEventType())) {
202                         if (ExternalEditor.getInstance().isDefined()) {
203                             handleExternalEdit(he.getDescription());
204                         } else {
205                             handleFileView(he.getDescription());
206                         }
207                     }
208                 }
209             });
210 
211         getCheckWrap().addItemListener(this);
212     }
213 
214 
215     protected void makeFrame() {
216         getContentPane().setLayout(new BorderLayout());
217 
218         JPanel buttonPanel = new JPanel();
219         {
220             buttonPanel.setLayout(new BorderLayout());
221 
222             List<JButton> list = new ArrayList<JButton>();
223             {
224                 if (Fsgrep.DEBUG) {
225                     list.add(getButtonReplace());
226                 }
227                 list.add(getButtonRefine());
228                 list.add(getButtonOk());
229             }
230             buttonPanel.add(App.wrapButtons(list), BorderLayout.EAST);
231         }
232 
233         getContentPane().add(makeResultPanel(), BorderLayout.CENTER);
234         getContentPane().add(buttonPanel, BorderLayout.SOUTH);
235 
236         pack();
237     }
238 
239 
240     protected JTabbedPane makeResultPanel() {
241         JTabbedPane result = getTabbedPane();
242 
243         Border border = BorderFactory.createTitledBorder("Search Results");
244         result.setBorder(border);
245 
246         {  // Formatted results
247             JPanel formatted = new JPanel(new BorderLayout());
248 
249             JScrollPane scrollPane = new JScrollPane();
250             scrollPane.setViewportView(getHtmlPane());
251 
252             formatted.add(scrollPane, BorderLayout.CENTER);
253 
254             result.add("formatted", formatted);
255         }
256 
257         {  // Live results
258             JPanel live = new JPanel(new BorderLayout());
259 
260             JScrollPane scrollPane = new JScrollPane();
261             scrollPane.setViewportView(getTextArea());
262 
263             JPanel controlPanel = new JPanel(new BorderLayout());
264             {
265                 controlPanel.add(getCheckWrap(), BorderLayout.WEST);
266                 controlPanel.add(getButtonSave(), BorderLayout.EAST);
267             }
268 
269             live.add(scrollPane, BorderLayout.CENTER);
270             live.add(controlPanel, BorderLayout.SOUTH);
271 
272             result.addTab("raw", live);
273         }
274 
275         {  // Search Statistics
276             result.add("statistics", getReportArea());
277         }
278 
279         return result;
280     }
281 
282 
283     //------------------------------------------------------------
284     //- Protected Action Handling
285 
286     protected void saveSearchResults() {
287         JFileChooser chooser = new JFileChooser();
288         chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
289         if (getLastSave() != null) {
290             chooser.setSelectedFile(getLastSave().getFile());
291         }
292 
293         int result = chooser.showDialog(this, "Select");
294         if (result == JFileChooser.APPROVE_OPTION) {
295             File selected = chooser.getSelectedFile();
296             // Query the user when replacing an existing file?
297             try {
298                 FileWriter writer = new FileWriter(selected);
299                 writer.write(getTextArea().getText());
300                 writer.close();
301             } catch (IOException ioe) {
302                 System.err.println("Could not save results to [" + selected + "]");
303                 ioe.printStackTrace();
304             }
305 
306             TargetFile targetFile = new TargetFile(selected);
307             String status = "Saved results to [" + targetFile + "].";
308             getApp().getFieldStatus().setText(status);
309 
310             setLastSave(targetFile);
311             pdata.setProperty(LAST_SAVE, getLastSave().getName());
312             pdata.store();
313         }
314     }
315 
316 
317     public void itemStateChanged(ItemEvent ie) {
318         Object source = ie.getItemSelectable();
319         boolean value = (ie.getStateChange() == ItemEvent.SELECTED);
320 
321         if (source == getCheckWrap()) {
322             getTextArea().setLineWrap(value);
323         }
324     }
325 
326 
327     public void handleFileView(String description) {
328         final MatchLink link = new MatchLink(description);
329 
330         FileViewer viewer = FileViewer.getInstance();
331         viewer.display(link.getFilename(), link.getLinenum());
332     }
333 
334 
335     public void handleExternalEdit(String description) {
336         // System.out.println("desc: " + description);
337         final MatchLink link = new MatchLink(description);
338         final ExternalEditor editor = ExternalEditor.getInstance();
339         final TextFieldOutput status = new TextFieldOutput(getApp().getFieldStatus());
340         final DialogOutput error = new DialogOutput(this);
341         Runnable runnable = new Runnable() {
342                 public void run() {
343                     editor.launch(link.getFilename(), link.getLinenum(), status, error);
344                 }
345             };
346 
347         getRunner().execute(runnable);
348     }
349 
350 
351     protected List<TargetFile> findMatchFiles() {
352         List<TargetFile> result = new ArrayList<TargetFile>();
353 
354         for (MatchResult match : getResults()) {
355             TargetFile file = match.toTargetFile();
356             result.add(file);
357         }
358 
359         return result;
360     }
361 
362 
363     //------------------------------------------------------------
364     //- Public Interface Functions
365 
366     public void clear() {
367         getResults().clear();
368         getHtmlPane().clear();
369         getTextArea().setText("");
370         getReportArea().setText("");
371     }
372 
373 
374     public void defineResults(List<MatchResult> list) {
375         getResults().clear();
376         getResults().addAll(list);
377 
378         StringBuffer buffer = new StringBuffer();
379         for (MatchResult result : list) {
380             buffer.append(result.toHtml());
381         }
382 
383         getHtmlPane().append(buffer.toString());
384     }
385 
386 
387     public void reshow() {
388         if (getState() == Frame.ICONIFIED) {
389             setState(Frame.NORMAL);
390         }
391 
392         // Even if it is already visible, this call will bring it to the front.
393         setVisible(true);
394     }
395 
396 
397     //------------------------------------------------------------
398     //- Class Interface Functions
399 
400     public void runFinished(ThreadRunner runner) {
401         // System.out.println("Finished edit.");
402     }
403 
404 
405     //------------------------------------------------------------
406     //- Inner Classes
407 
408     class MatchLink {
409         private String _filename = "";
410         private String _linenum = "1";
411 
412         protected MatchLink(String def) {
413             int index = def.indexOf("?");
414             if (index == -1) {
415                 _filename = def;
416             } else {
417                 _filename = def.substring(0, index);
418                 _linenum = def.substring(index+1);
419             }
420         }
421 
422         protected String getFilename() {return _filename;}
423         protected String getLinenum() {return _linenum;}
424 
425         public String toString() {
426             String result = "MatchLink[file(" + getFilename() + "), line(" + getLinenum() + ")]";
427 
428             return result;
429         }
430 
431     }
432 
433 
434 
435     //------------------------------------------------------------
436     //- Main
437 
438 
439 
440 }