JAL-3161 limit tooltip and status updates to visible columns
[jalview.git] / src / jalview / appletgui / TreePanel.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.appletgui;
22
23 import jalview.analysis.AverageDistanceTree;
24 import jalview.analysis.NJTree;
25 import jalview.analysis.TreeBuilder;
26 import jalview.analysis.TreeModel;
27 import jalview.analysis.scoremodels.ScoreModels;
28 import jalview.analysis.scoremodels.SimilarityParams;
29 import jalview.api.analysis.ScoreModelI;
30 import jalview.datamodel.Alignment;
31 import jalview.datamodel.HiddenColumns;
32 import jalview.datamodel.SequenceI;
33 import jalview.io.NewickFile;
34 import jalview.util.MessageManager;
35
36 import java.awt.BorderLayout;
37 import java.awt.CheckboxMenuItem;
38 import java.awt.Color;
39 import java.awt.Menu;
40 import java.awt.MenuBar;
41 import java.awt.MenuItem;
42 import java.awt.ScrollPane;
43 import java.awt.event.ActionEvent;
44 import java.awt.event.ActionListener;
45 import java.awt.event.ItemEvent;
46 import java.awt.event.ItemListener;
47
48 public class TreePanel extends EmbmenuFrame
49         implements ActionListener, ItemListener
50 {
51   SequenceI[] seq;
52
53   String type;
54
55   String pwtype;
56
57   int start;
58
59   int end;
60
61   TreeCanvas treeCanvas;
62
63   TreeModel tree;
64
65   AlignmentPanel ap;
66
67   AlignViewport av;
68
69   public TreeModel getTree()
70   {
71     return tree;
72   }
73
74   @Override
75   public void finalize() throws Throwable
76   {
77     ap = null;
78     av = null;
79     super.finalize();
80   }
81
82   /**
83    * Creates a new TreePanel object.
84    */
85   public TreePanel(AlignmentPanel alignPanel, String type, String pwtype)
86   {
87     try
88     {
89       jbInit();
90       this.setMenuBar(jMenuBar1);
91     } catch (Exception ex)
92     {
93       ex.printStackTrace();
94     }
95
96     initTreePanel(alignPanel, type, pwtype, null);
97   }
98
99   /**
100    * Creates a new TreePanel object.
101    * 
102    */
103   public TreePanel(AlignmentPanel ap, String type, String pwtype,
104           NewickFile newtree)
105   {
106     try
107     {
108       jbInit();
109       this.setMenuBar(jMenuBar1);
110     } catch (Exception e)
111     {
112       e.printStackTrace();
113     }
114
115     initTreePanel(ap, type, pwtype, newtree);
116   }
117
118   void initTreePanel(AlignmentPanel ap, String type, String pwtype,
119           NewickFile newTree)
120   {
121
122     this.ap = ap;
123     this.av = ap.av;
124     this.type = type;
125     this.pwtype = pwtype;
126
127     treeCanvas = new TreeCanvas(ap, scrollPane);
128     TreeLoader tl = new TreeLoader(newTree);
129     tl.start();
130     embedMenuIfNeeded(treeCanvas);
131     scrollPane.add(treeCanvas, BorderLayout.CENTER);
132   }
133
134   void showOriginalData()
135   {
136     // decide if av alignment is sufficiently different to original data to
137     // warrant a new window to be created
138     // create new alignmnt window with hidden regions (unhiding hidden regions
139     // yields unaligned seqs)
140     // or create a selection box around columns in alignment view
141     // test Alignment(SeqCigar[])
142     if (tree.getOriginalData() != null)
143     {
144       char gc = '-';
145       try
146       {
147         // we try to get the associated view's gap character
148         // but this may fail if the view was closed...
149         gc = av.getGapCharacter();
150       } catch (Exception ex)
151       {
152       }
153
154       Object[] alAndColsel = tree.getOriginalData()
155               .getAlignmentAndHiddenColumns(gc);
156
157       if (alAndColsel != null && alAndColsel[0] != null)
158       {
159         Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
160         AlignFrame af = new AlignFrame(al, av.applet,
161                 "Original Data for Tree", false);
162
163         af.viewport.getAlignment()
164                 .setHiddenColumns((HiddenColumns) alAndColsel[1]);
165       }
166     }
167     else
168     {
169       System.out.println("Original Tree Data not available");
170     }
171   }
172
173   class TreeLoader extends Thread
174   {
175     NewickFile newtree;
176
177     jalview.datamodel.AlignmentView odata = null;
178
179     public TreeLoader(NewickFile newtree)
180     {
181       this.newtree = newtree;
182     }
183
184     @Override
185     public void run()
186     {
187       if (newtree != null)
188       {
189         tree = new TreeModel(av.getAlignment().getSequencesArray(), odata,
190                 newtree);
191       }
192       else
193       {
194         ScoreModelI sm1 = ScoreModels.getInstance().getScoreModel(pwtype,
195                 treeCanvas.ap);
196         ScoreModelI sm = sm1;
197         TreeBuilder njtree = type.equals(TreeBuilder.NEIGHBOUR_JOINING)
198                 ? new NJTree(av, sm, SimilarityParams.Jalview)
199                 : new AverageDistanceTree(av, sm, SimilarityParams.Jalview);
200         tree = new TreeModel(njtree);
201       }
202
203       tree.reCount(tree.getTopNode());
204       tree.findHeight(tree.getTopNode());
205       treeCanvas.setTree(tree);
206       if (newtree != null)
207       {
208         // Set default view, paying lip service to any overriding tree view
209         // parameter settings
210         boolean showDist = newtree.HasDistances()
211                 && av.applet.getDefaultParameter("showTreeDistances",
212                         newtree.HasDistances());
213         boolean showBoots = newtree.HasBootstrap()
214                 && av.applet.getDefaultParameter("showTreeBootstraps",
215                         newtree.HasBootstrap());
216         distanceMenu.setState(showDist);
217         bootstrapMenu.setState(showBoots);
218         treeCanvas.setShowBootstrap(showBoots);
219         treeCanvas.setShowDistances(showDist);
220         treeCanvas.setMarkPlaceholders(av.applet
221                 .getDefaultParameter("showUnlinkedTreeNodes", false));
222       }
223
224       treeCanvas.repaint();
225
226       av.setCurrentTree(tree);
227
228     }
229   }
230
231   @Override
232   public void actionPerformed(ActionEvent evt)
233   {
234     if (evt.getSource() == newickOutput)
235     {
236       newickOutput_actionPerformed();
237     }
238     else if (evt.getSource() == fontSize)
239     {
240       fontSize_actionPerformed();
241     }
242     else if (evt.getSource() == inputData)
243     {
244       showOriginalData();
245     }
246   }
247
248   @Override
249   public void itemStateChanged(ItemEvent evt)
250   {
251     if (evt.getSource() == fitToWindow)
252     {
253       treeCanvas.fitToWindow = fitToWindow.getState();
254     }
255
256     else if (evt.getSource() == distanceMenu)
257     {
258       treeCanvas.setShowDistances(distanceMenu.getState());
259     }
260
261     else if (evt.getSource() == bootstrapMenu)
262     {
263       treeCanvas.setShowBootstrap(bootstrapMenu.getState());
264     }
265
266     else if (evt.getSource() == placeholdersMenu)
267     {
268       treeCanvas.setMarkPlaceholders(placeholdersMenu.getState());
269     }
270
271     treeCanvas.repaint();
272   }
273
274   public void newickOutput_actionPerformed()
275   {
276     jalview.io.NewickFile fout = new jalview.io.NewickFile(
277             tree.getTopNode());
278     String output = fout.print(false, true);
279     CutAndPasteTransfer cap = new CutAndPasteTransfer(false, null);
280     cap.setText(output);
281     java.awt.Frame frame = new java.awt.Frame();
282     frame.add(cap);
283     jalview.bin.JalviewLite.addFrame(frame, type + " " + pwtype, 500, 100);
284   }
285
286   public java.awt.Font getTreeFont()
287   {
288     return treeCanvas.font;
289   }
290
291   public void setTreeFont(java.awt.Font font)
292   {
293     treeCanvas.font = font;
294     treeCanvas.repaint();
295   }
296
297   protected void fontSize_actionPerformed()
298   {
299     if (treeCanvas == null)
300     {
301       return;
302     }
303
304     new FontChooser(this);
305   }
306
307   BorderLayout borderLayout1 = new BorderLayout();
308
309   protected ScrollPane scrollPane = new ScrollPane();
310
311   MenuBar jMenuBar1 = new MenuBar();
312
313   Menu jMenu2 = new Menu();
314
315   protected MenuItem fontSize = new MenuItem();
316
317   protected CheckboxMenuItem bootstrapMenu = new CheckboxMenuItem();
318
319   protected CheckboxMenuItem distanceMenu = new CheckboxMenuItem();
320
321   protected CheckboxMenuItem placeholdersMenu = new CheckboxMenuItem();
322
323   protected CheckboxMenuItem fitToWindow = new CheckboxMenuItem();
324
325   Menu fileMenu = new Menu();
326
327   MenuItem newickOutput = new MenuItem();
328
329   MenuItem inputData = new MenuItem();
330
331   private void jbInit() throws Exception
332   {
333     setLayout(borderLayout1);
334     this.setBackground(Color.white);
335     this.setFont(new java.awt.Font("Verdana", 0, 12));
336     jMenu2.setLabel(MessageManager.getString("action.view"));
337     fontSize.setLabel(MessageManager.getString("action.font"));
338     fontSize.addActionListener(this);
339     bootstrapMenu.setLabel(
340             MessageManager.getString("label.show_bootstrap_values"));
341     bootstrapMenu.addItemListener(this);
342     distanceMenu.setLabel(MessageManager.getString("label.show_distances"));
343     distanceMenu.addItemListener(this);
344     placeholdersMenu.setLabel(
345             MessageManager.getString("label.mark_unassociated_leaves"));
346     placeholdersMenu.addItemListener(this);
347     fitToWindow.setState(true);
348     fitToWindow.setLabel(MessageManager.getString("label.fit_to_window"));
349     fitToWindow.addItemListener(this);
350     fileMenu.setLabel(MessageManager.getString("action.file"));
351     newickOutput.setLabel(MessageManager.getString("label.newick_format"));
352     newickOutput.addActionListener(this);
353     inputData.setLabel(MessageManager.getString("label.input_data"));
354
355     add(scrollPane, BorderLayout.CENTER);
356     jMenuBar1.add(fileMenu);
357     jMenuBar1.add(jMenu2);
358     jMenu2.add(fitToWindow);
359     jMenu2.add(fontSize);
360     jMenu2.add(distanceMenu);
361     jMenu2.add(bootstrapMenu);
362     jMenu2.add(placeholdersMenu);
363     fileMenu.add(newickOutput);
364     fileMenu.add(inputData);
365     inputData.addActionListener(this);
366   }
367
368 }