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