069c1f9a823eda567bede8394581a6a4989bb256
[jalview.git] / src / jalview / gui / Finder.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import java.util.*;
21
22 import java.awt.event.*;
23 import javax.swing.*;
24
25 import jalview.datamodel.*;
26 import jalview.jbgui.*;
27
28 /**
29  * DOCUMENT ME!
30  * 
31  * @author $author$
32  * @version $Revision$
33  */
34 public class Finder extends GFinder
35 {
36   AlignViewport av;
37
38   AlignmentPanel ap;
39
40   JInternalFrame frame;
41
42   int seqIndex = 0;
43
44   int resIndex = -1;
45
46   SearchResults searchResults;
47
48   /**
49    * Creates a new Finder object.
50    * 
51    * @param av
52    *          DOCUMENT ME!
53    * @param ap
54    *          DOCUMENT ME!
55    * @param f
56    *          DOCUMENT ME!
57    */
58   public Finder()
59   {
60     this(null, null);
61     focusfixed = false;
62   }
63
64   public Finder(AlignViewport viewport, AlignmentPanel alignPanel)
65   {
66     av = viewport;
67     ap = alignPanel;
68     focusfixed = true;
69     frame = new JInternalFrame();
70     frame.setContentPane(this);
71     frame.setLayer(JLayeredPane.PALETTE_LAYER);
72     Desktop.addInternalFrame(frame, "Find", 340, 110);
73
74     textfield.requestFocus();
75   }
76
77   /**
78    * DOCUMENT ME!
79    * 
80    * @param e
81    *          DOCUMENT ME!
82    */
83   public void findNext_actionPerformed(ActionEvent e)
84   {
85     if (getFocusedViewport())
86     {
87       doSearch(false);
88     }
89   }
90
91   /**
92    * DOCUMENT ME!
93    * 
94    * @param e
95    *          DOCUMENT ME!
96    */
97   public void findAll_actionPerformed(ActionEvent e)
98   {
99     if (getFocusedViewport())
100     {
101       resIndex = -1;
102       seqIndex = 0;
103       doSearch(true);
104     }
105   }
106
107   /**
108    * do we only search a given alignment view ?
109    */
110   private boolean focusfixed;
111
112   /**
113    * if !focusfixed and not in a desktop environment, checks that av and ap are
114    * valid. Otherwise, gets the topmost alignment window and sets av and ap
115    * accordingly
116    * 
117    * @return false if no alignment window was found
118    */
119   boolean getFocusedViewport()
120   {
121     if (focusfixed || Desktop.desktop == null)
122     {
123       if (ap != null && av != null)
124       {
125         return true;
126       }
127       // we aren't in a desktop environment, so give up now.
128       return false;
129     }
130     // now checks further down the window stack to fix bug
131     // https://mantis.lifesci.dundee.ac.uk/view.php?id=36008
132     JInternalFrame[] frames = Desktop.desktop.getAllFrames();
133     for (int f = 0; f < frames.length; f++)
134     {
135       JInternalFrame frame = frames[f];
136       if (frame != null && frame instanceof AlignFrame)
137       {
138         av = ((AlignFrame) frame).viewport;
139         ap = ((AlignFrame) frame).alignPanel;
140         return true;
141       }
142     }
143     return false;
144   }
145
146   /**
147    * DOCUMENT ME!
148    * 
149    * @param e
150    *          DOCUMENT ME!
151    */
152   public void createNewGroup_actionPerformed(ActionEvent e)
153   {
154     SequenceI[] seqs = new SequenceI[searchResults.getSize()];
155     SequenceFeature[] features = new SequenceFeature[searchResults
156             .getSize()];
157
158     for (int i = 0; i < searchResults.getSize(); i++)
159     {
160       seqs[i] = searchResults.getResultSequence(i).getDatasetSequence();
161
162       features[i] = new SequenceFeature(textfield.getText().trim(),
163               "Search Results", null, searchResults.getResultStart(i),
164               searchResults.getResultEnd(i), "Search Results");
165     }
166
167     if (ap.seqPanel.seqCanvas.getFeatureRenderer().amendFeatures(seqs,
168             features, true, ap))
169     {
170       ap.alignFrame.showSeqFeatures.setSelected(true);
171       av.setShowSequenceFeatures(true);
172       ap.highlightSearchResults(null);
173     }
174   }
175
176   /**
177    * incrementally search the alignment
178    * 
179    * @param findAll
180    *          true means find all results and raise a dialog box
181    */
182   void doSearch(boolean findAll)
183   {
184     createNewGroup.setEnabled(false);
185
186     String searchString = textfield.getText().trim();
187
188     if (searchString.length() < 1)
189     {
190       return;
191     }
192     // TODO: extend finder to match descriptions, features and annotation, and
193     // other stuff
194     // TODO: add switches to control what is searched - sequences, IDS,
195     // descriptions, features
196     jalview.analysis.Finder finder = new jalview.analysis.Finder(
197             av.getAlignment(), av.getSelectionGroup(), seqIndex, resIndex);
198     finder.setCaseSensitive(caseSensitive.isSelected());
199     finder.setFindAll(findAll);
200
201     finder.find(searchString); // returns true if anything was actually found
202
203     seqIndex = finder.getSeqIndex();
204     resIndex = finder.getResIndex();
205
206     searchResults = finder.getSearchResults(); // find(regex,
207     // caseSensitive.isSelected(), )
208     Vector idMatch = finder.getIdMatch();
209     boolean haveResults = false;
210     // set or reset the GUI
211     if ((idMatch.size() > 0))
212     {
213       haveResults = true;
214       ap.idPanel.highlightSearchResults(idMatch);
215     }
216     else
217     {
218       ap.idPanel.highlightSearchResults(null);
219     }
220
221     if (searchResults.getSize() > 0)
222     {
223       haveResults = true;
224       createNewGroup.setEnabled(true);
225     }
226     else
227     {
228       searchResults = null;
229     }
230
231     // if allResults is null, this effectively switches displaySearch flag in
232     // seqCanvas
233     ap.highlightSearchResults(searchResults);
234     // TODO: add enablers for 'SelectSequences' or 'SelectColumns' or
235     // 'SelectRegion' selection
236     if (!haveResults)
237     {
238       JOptionPane.showInternalMessageDialog(this, "Finished searching",
239               null, JOptionPane.INFORMATION_MESSAGE);
240       resIndex = -1;
241       seqIndex = 0;
242     }
243
244     if (findAll)
245     {
246       String message = (idMatch.size() > 0) ? "" + idMatch.size() + " IDs"
247               : "";
248       if (searchResults != null)
249       {
250         if (idMatch.size() > 0 && searchResults.getSize() > 0)
251         {
252           message += " and ";
253         }
254         message += searchResults.getSize() + " subsequence matches found.";
255       }
256       JOptionPane.showInternalMessageDialog(this, message, null,
257               JOptionPane.INFORMATION_MESSAGE);
258       resIndex = -1;
259       seqIndex = 0;
260     }
261
262   }
263 }