41b7d480cb9c4e97cd76d848d4ca020fd65a3692
[jalview.git] / src / jalview / gui / TreeChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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 jalview.analysis.NJTree;
24 import jalview.analysis.scoremodels.ScoreMatrix;
25 import jalview.analysis.scoremodels.ScoreModels;
26 import jalview.analysis.scoremodels.SimilarityParams;
27 import jalview.api.analysis.DistanceScoreModelI;
28 import jalview.api.analysis.ScoreModelI;
29 import jalview.api.analysis.SimilarityParamsI;
30 import jalview.util.MessageManager;
31
32 import java.awt.Color;
33 import java.awt.FlowLayout;
34 import java.awt.Font;
35 import java.awt.GridLayout;
36 import java.awt.event.ActionEvent;
37 import java.awt.event.ItemEvent;
38 import java.awt.event.ItemListener;
39 import java.beans.PropertyVetoException;
40
41 import javax.swing.ButtonGroup;
42 import javax.swing.JButton;
43 import javax.swing.JCheckBox;
44 import javax.swing.JComboBox;
45 import javax.swing.JInternalFrame;
46 import javax.swing.JLabel;
47 import javax.swing.JLayeredPane;
48 import javax.swing.JPanel;
49 import javax.swing.JRadioButton;
50
51 /**
52  * A dialog to allow a user to select and action Tree calculation options
53  */
54 public class TreeChooser extends JPanel
55 {
56   private static final Font VERDANA_11PT = new Font("Verdana", 0, 11);
57
58   AlignFrame af;
59
60   JRadioButton pca;
61
62   JRadioButton tree;
63
64   JRadioButton neighbourJoining;
65
66   JRadioButton averageDistance;
67
68   JComboBox<String> modelNames;
69
70   private JInternalFrame frame;
71
72   private ButtonGroup treeTypes;
73
74   private JCheckBox includeGaps;
75
76   private JCheckBox matchGaps;
77
78   private JCheckBox includeGappedColumns;
79
80   private JCheckBox shorterSequence;
81
82   /**
83    * Constructor
84    * 
85    * @param af
86    */
87   public TreeChooser(AlignFrame alignFrame)
88   {
89     this.af = alignFrame;
90     init();
91   }
92
93   /**
94    * Lays out the panel and adds it to the desktop
95    */
96   void init()
97   {
98     frame = new JInternalFrame();
99     frame.setContentPane(this);
100     this.setBackground(Color.white);
101
102     /*
103      * Layout consists of 5 panels:
104      * - first with choice of Tree or PCA
105      * - second with choice of tree method NJ or AV
106      * - third with choice of score model
107      * - fourth with score model parameter options
108      * - fifth with OK and Cancel
109      */
110     tree = new JRadioButton(MessageManager.getString("label.tree"));
111     tree.setOpaque(false);
112     pca = new JRadioButton(
113             MessageManager.getString("label.principal_component_analysis"));
114     pca.setOpaque(false);
115     neighbourJoining = new JRadioButton(
116             MessageManager.getString("label.tree_calc_nj"));
117     averageDistance = new JRadioButton(
118             MessageManager.getString("label.tree_calc_av"));
119     ItemListener listener = new ItemListener()
120     {
121       @Override
122       public void itemStateChanged(ItemEvent e)
123       {
124         neighbourJoining.setEnabled(tree.isSelected());
125         averageDistance.setEnabled(tree.isSelected());
126       }
127     };
128     pca.addItemListener(listener);
129     tree.addItemListener(listener);
130     ButtonGroup calcTypes = new ButtonGroup();
131     calcTypes.add(pca);
132     calcTypes.add(tree);
133     JPanel calcChoicePanel = new JPanel();
134     calcChoicePanel.setOpaque(false);
135     tree.setSelected(true);
136     calcChoicePanel.add(tree);
137     calcChoicePanel.add(pca);
138
139     neighbourJoining.setOpaque(false);
140     treeTypes = new ButtonGroup();
141     treeTypes.add(neighbourJoining);
142     treeTypes.add(averageDistance);
143     neighbourJoining.setSelected(true);
144     JPanel treeChoicePanel = new JPanel();
145     treeChoicePanel.setOpaque(false);
146     treeChoicePanel.add(neighbourJoining);
147     treeChoicePanel.add(averageDistance);
148
149     /*
150      * score model drop-down
151      */
152     modelNames = new JComboBox<String>();
153     ScoreModels scoreModels = ScoreModels.getInstance();
154     for (ScoreModelI sm : scoreModels.getModels())
155     {
156       boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
157       if (sm.isDNA() && nucleotide || sm.isProtein() && !nucleotide)
158       {
159         modelNames.addItem(sm.getName());
160       }
161     }
162     modelNames.addItemListener(new ItemListener()
163     {
164
165       @Override
166       public void itemStateChanged(ItemEvent e)
167       {
168         if (e.getStateChange() == ItemEvent.SELECTED)
169         {
170           scoreModelChanged((String) e.getItem());
171         }
172       }
173     });
174     JPanel scoreModelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
175     scoreModelPanel.setOpaque(false);
176     scoreModelPanel.add(modelNames, FlowLayout.LEFT);
177
178     /*
179      * score model parameters
180      */
181     JPanel paramsPanel = new JPanel(new GridLayout(5, 1));
182     paramsPanel.setOpaque(false);
183     includeGaps = new JCheckBox("Include gaps");
184     matchGaps = new JCheckBox("Match gaps");
185     includeGappedColumns = new JCheckBox("Include gapped columns");
186     shorterSequence = new JCheckBox("Match on shorter sequence");
187     paramsPanel.add(new JLabel("Pairwise sequence scoring options"));
188     paramsPanel.add(includeGaps);
189     paramsPanel.add(matchGaps);
190     paramsPanel.add(includeGappedColumns);
191     paramsPanel.add(shorterSequence);
192     // configure initial state of options
193     scoreModelChanged(modelNames.getItemAt(0));
194
195     /*
196      * OK / Cancel buttons
197      */
198     JButton ok = new JButton(MessageManager.getString("action.ok"));
199     ok.setFont(VERDANA_11PT);
200     ok.addActionListener(new java.awt.event.ActionListener()
201     {
202       @Override
203       public void actionPerformed(ActionEvent e)
204       {
205         ok_actionPerformed(e);
206       }
207     });
208     JButton cancel = new JButton(MessageManager.getString("action.cancel"));
209     cancel.setFont(VERDANA_11PT);
210     cancel.addActionListener(new java.awt.event.ActionListener()
211     {
212       @Override
213       public void actionPerformed(ActionEvent e)
214       {
215         cancel_actionPerformed(e);
216       }
217     });
218     JPanel actionPanel = new JPanel();
219     actionPanel.setOpaque(false);
220     actionPanel.add(ok);
221     actionPanel.add(cancel);
222
223     this.add(calcChoicePanel);
224     this.add(treeChoicePanel);
225     this.add(scoreModelPanel);
226     this.add(paramsPanel);
227     this.add(actionPanel);
228
229     Desktop.addInternalFrame(frame,
230             MessageManager.getString("label.choose_tree"), 400, 400, false);
231
232     frame.setLayer(JLayeredPane.PALETTE_LAYER);
233   }
234
235   /**
236    * Action on selection of score model
237    * 
238    * @param item
239    */
240   protected void scoreModelChanged(String modelName)
241   {
242     /*
243      * enable/disable options appropriate to score model
244      * NB this is temporary - will get score models to provide
245      * their own parameters
246      */
247     includeGaps.setEnabled(true);
248     matchGaps.setEnabled(true);
249     includeGappedColumns.setEnabled(true);
250     shorterSequence.setEnabled(true);
251
252     ScoreModelI sm = ScoreModels.getInstance().forName(modelName);
253     if (sm instanceof DistanceScoreModelI)
254     {
255       matchGaps.setEnabled(false);
256       includeGappedColumns.setEnabled(false);
257       shorterSequence.setEnabled(false);
258     }
259     if (sm instanceof ScoreMatrix)
260     {
261       matchGaps.setEnabled(false);
262     }
263     if (tree.isSelected())
264     {
265       // ?? tree requires specific parameter settings??
266       includeGaps.setSelected(true);
267       includeGaps.setEnabled(false);
268       matchGaps.setSelected(true);
269       includeGappedColumns.setSelected(true);
270       includeGappedColumns.setEnabled(false);
271       shorterSequence.setSelected(false);
272       shorterSequence.setEnabled(false);
273     }
274   }
275
276   /**
277    * Open and calculate the selected tree on 'OK'
278    * 
279    * @param e
280    */
281   protected void ok_actionPerformed(ActionEvent e)
282   {
283     ScoreModelI sm = ScoreModels.getInstance().forName(
284             modelNames.getSelectedItem().toString());
285     SimilarityParamsI params = getSimilarityParameters();
286
287     if (pca.isSelected())
288     {
289       AlignViewport viewport = af.getViewport();
290       if (((viewport.getSelectionGroup() != null)
291               && (viewport.getSelectionGroup().getSize() < 4) && (viewport
292               .getSelectionGroup().getSize() > 0))
293               || (viewport.getAlignment().getHeight() < 4))
294       {
295         JvOptionPane
296                 .showInternalMessageDialog(
297                         this,
298                         MessageManager
299                                 .getString("label.principal_component_analysis_must_take_least_four_input_sequences"),
300                         MessageManager
301                                 .getString("label.sequence_selection_insufficient"),
302                         JvOptionPane.WARNING_MESSAGE);
303         return;
304       }
305       new PCAPanel(af.alignPanel, sm, params);
306     }
307     else
308     {
309       String treeType = neighbourJoining.isSelected() ? NJTree.NEIGHBOUR_JOINING
310               : NJTree.AVERAGE_DISTANCE;
311       af.newTreePanel(treeType, sm, params);
312     }
313
314     // closeFrame();
315   }
316
317   /**
318    * 
319    */
320   protected void closeFrame()
321   {
322     try
323     {
324       frame.setClosed(true);
325     } catch (PropertyVetoException ex)
326     {
327     }
328   }
329
330   private SimilarityParamsI getSimilarityParameters()
331   {
332     SimilarityParamsI params = new SimilarityParams(
333             includeGappedColumns.isSelected(), matchGaps.isSelected(),
334             includeGaps.isSelected(), shorterSequence.isSelected());
335     return params;
336   }
337
338   /**
339    * Closes dialog on cancel
340    * 
341    * @param e
342    */
343   protected void cancel_actionPerformed(ActionEvent e)
344   {
345     try
346     {
347       frame.setClosed(true);
348     } catch (Exception ex)
349     {
350     }
351   }
352 }