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