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