Multiple Views
[jalview.git] / src / jalview / gui / TreePanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.gui;\r
20 \r
21 import jalview.analysis.*;\r
22 \r
23 import jalview.datamodel.*;\r
24 \r
25 import jalview.io.*;\r
26 \r
27 import jalview.jbgui.*;\r
28 \r
29 import org.jibble.epsgraphics.*;\r
30 \r
31 import java.awt.*;\r
32 import java.awt.event.*;\r
33 import java.awt.image.*;\r
34 \r
35 import java.io.*;\r
36 \r
37 import java.util.*;\r
38 \r
39 import javax.imageio.*;\r
40 \r
41 import java.beans.PropertyChangeEvent;\r
42 \r
43 \r
44 /**\r
45  * DOCUMENT ME!\r
46  *\r
47  * @author $author$\r
48  * @version $Revision$\r
49  */\r
50 public class TreePanel extends GTreePanel\r
51 {\r
52     String type;\r
53     String pwtype;\r
54     TreeCanvas treeCanvas;\r
55     NJTree tree;\r
56     AlignViewport av;\r
57 \r
58     /**\r
59      * Creates a new TreePanel object.\r
60      *\r
61      * @param av DOCUMENT ME!\r
62      * @param seqVector DOCUMENT ME!\r
63      * @param type DOCUMENT ME!\r
64      * @param pwtype DOCUMENT ME!\r
65      * @param s DOCUMENT ME!\r
66      * @param e DOCUMENT ME!\r
67      */\r
68     public TreePanel(AlignmentPanel ap, String type, String pwtype)\r
69     {\r
70       super();\r
71       initTreePanel(ap, type, pwtype, null);\r
72 \r
73       // We know this tree has distances. JBPNote TODO: prolly should add this as a userdefined default\r
74       // showDistances(true);\r
75     }\r
76 \r
77     /**\r
78      * Creates a new TreePanel object.\r
79      *\r
80      * @param av DOCUMENT ME!\r
81      * @param seqVector DOCUMENT ME!\r
82      * @param newtree DOCUMENT ME!\r
83      * @param type DOCUMENT ME!\r
84      * @param pwtype DOCUMENT ME!\r
85      */\r
86     public TreePanel(AlignmentPanel ap,\r
87                      String type,\r
88                      String pwtype,\r
89                      NewickFile newtree)\r
90     {\r
91       super();\r
92       initTreePanel(ap, type, pwtype, newtree);\r
93     }\r
94 \r
95     public AlignmentI getAlignment()\r
96     {\r
97       return treeCanvas.av.getAlignment();\r
98     }\r
99 \r
100 \r
101     void initTreePanel(AlignmentPanel ap, String type,  String pwtype,\r
102                        NewickFile newTree)\r
103     {\r
104 \r
105       av = ap.av;\r
106       this.type = type;\r
107       this.pwtype = pwtype;\r
108 \r
109       treeCanvas = new TreeCanvas(ap, scrollPane);\r
110       scrollPane.setViewportView(treeCanvas);\r
111 \r
112       av.addPropertyChangeListener(new java.beans.PropertyChangeListener()\r
113       {\r
114         public void propertyChange(PropertyChangeEvent evt)\r
115         {\r
116           if (evt.getPropertyName().equals("alignment"))\r
117           {\r
118             if(tree==null)\r
119               System.out.println("tree is null");\r
120             if(evt.getNewValue()==null)\r
121               System.out.println("new value is null");\r
122 \r
123             tree.UpdatePlaceHolders( (Vector) evt.getNewValue());\r
124 \r
125             repaint();\r
126           }\r
127         }\r
128       });\r
129 \r
130       this.av = av;\r
131 \r
132 \r
133       TreeLoader tl = new TreeLoader(newTree);\r
134       tl.start();\r
135 \r
136     }\r
137 \r
138     class TreeLoader extends Thread\r
139     {\r
140       NewickFile newtree;\r
141       jalview.datamodel.AlignmentView odata=null;\r
142       public TreeLoader(NewickFile newtree)\r
143       {\r
144         this.newtree = newtree;\r
145         if (newtree != null)\r
146         {\r
147           // Must be outside run(), as Jalview2XML tries to\r
148           // update distance/bootstrap visibility at the same time\r
149           showBootstrap(newtree.HasBootstrap());\r
150           showDistances(newtree.HasDistances());\r
151         }\r
152       }\r
153 \r
154       public void run()\r
155       {\r
156 \r
157         if(newtree!=null)\r
158         {\r
159           if (odata==null) {\r
160             tree = new NJTree(av.alignment.getSequencesArray(),\r
161                               newtree);\r
162           } else {\r
163             tree = new NJTree(av.alignment.getSequencesArray(), odata, newtree);\r
164           }\r
165           if (!tree.hasOriginalSequenceData())\r
166             allowOriginalSeqData(false);\r
167         }\r
168         else\r
169         {\r
170           int start, end;\r
171           SequenceI [] seqs;\r
172           AlignmentView seqStrings = av.getAlignmentView(av.getSelectionGroup()!=null);\r
173           if(av.getSelectionGroup()==null)\r
174           {\r
175             start = 0;\r
176             end = av.alignment.getWidth();\r
177             seqs = av.alignment.getSequencesArray();\r
178           }\r
179           else\r
180           {\r
181             start = av.getSelectionGroup().getStartRes();\r
182             end = av.getSelectionGroup().getEndRes()+1;\r
183             seqs = av.getSelectionGroup().getSequencesInOrder(av.alignment);\r
184           }\r
185 \r
186           tree = new NJTree(seqs, seqStrings, type, pwtype, start, end);\r
187           showDistances(true);\r
188         }\r
189 \r
190 \r
191         tree.reCount(tree.getTopNode());\r
192         tree.findHeight(tree.getTopNode());\r
193         treeCanvas.setTree(tree);\r
194         treeCanvas.repaint();\r
195         av.setCurrentTree(tree);\r
196 \r
197       }\r
198     }\r
199 \r
200     public void showDistances(boolean b)\r
201     {\r
202       treeCanvas.setShowDistances(b);\r
203       distanceMenu.setSelected(b);\r
204     }\r
205 \r
206     public void showBootstrap(boolean b)\r
207     {\r
208       treeCanvas.setShowBootstrap(b);\r
209       bootstrapMenu.setSelected(b);\r
210     }\r
211 \r
212     public void showPlaceholders(boolean b)\r
213     {\r
214       placeholdersMenu.setState(b);\r
215       treeCanvas.setMarkPlaceholders(b);\r
216     }\r
217 \r
218     private void allowOriginalSeqData(boolean b) {\r
219       originalSeqData.setVisible(b);\r
220     }\r
221 \r
222 \r
223 \r
224     /**\r
225      * DOCUMENT ME!\r
226      *\r
227      * @return DOCUMENT ME!\r
228      */\r
229     public NJTree getTree()\r
230     {\r
231         return tree;\r
232     }\r
233 \r
234 \r
235     /**\r
236      * DOCUMENT ME!\r
237      *\r
238      * @param e DOCUMENT ME!\r
239      */\r
240     public void textbox_actionPerformed(ActionEvent e)\r
241     {\r
242         CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
243 \r
244         StringBuffer buffer = new StringBuffer();\r
245 \r
246         if (type.equals("AV"))\r
247         {\r
248             buffer.append("Average distance tree using ");\r
249         }\r
250         else\r
251         {\r
252             buffer.append("Neighbour joining tree using ");\r
253         }\r
254 \r
255         if (pwtype.equals("BL"))\r
256         {\r
257             buffer.append("BLOSUM62");\r
258         }\r
259         else\r
260         {\r
261             buffer.append("PID");\r
262         }\r
263 \r
264         Desktop.addInternalFrame(cap, buffer.toString(), 500, 100);\r
265 \r
266         jalview.io.NewickFile fout = new jalview.io.NewickFile(tree.getTopNode());\r
267         cap.setText(fout.print(tree.isHasBootstrap(), tree.isHasDistances(), tree.isHasRootDistance()));\r
268     }\r
269 \r
270     /**\r
271      * DOCUMENT ME!\r
272      *\r
273      * @param e DOCUMENT ME!\r
274      */\r
275     public void saveAsNewick_actionPerformed(ActionEvent e)\r
276     {\r
277         JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(\r
278                     "LAST_DIRECTORY"));\r
279         chooser.setFileView(new JalviewFileView());\r
280         chooser.setDialogTitle("Save tree as newick file");\r
281         chooser.setToolTipText("Save");\r
282 \r
283         int value = chooser.showSaveDialog(null);\r
284 \r
285         if (value == JalviewFileChooser.APPROVE_OPTION)\r
286         {\r
287             String choice = chooser.getSelectedFile().getPath();\r
288             jalview.bin.Cache.setProperty("LAST_DIRECTORY",\r
289                 chooser.getSelectedFile().getParent());\r
290 \r
291             try\r
292             {\r
293                 jalview.io.NewickFile fout = new jalview.io.NewickFile(tree.getTopNode());\r
294                 String output = fout.print(tree.isHasBootstrap(), tree.isHasDistances(), tree.isHasRootDistance());\r
295                 java.io.PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(\r
296                             choice));\r
297                 out.println(output);\r
298                 out.close();\r
299             }\r
300             catch (Exception ex)\r
301             {\r
302                 ex.printStackTrace();\r
303             }\r
304         }\r
305     }\r
306 \r
307     /**\r
308      * DOCUMENT ME!\r
309      *\r
310      * @param e DOCUMENT ME!\r
311      */\r
312     public void printMenu_actionPerformed(ActionEvent e)\r
313     {\r
314         //Putting in a thread avoids Swing painting problems\r
315         treeCanvas.startPrinting();\r
316     }\r
317 \r
318 \r
319     public void originalSeqData_actionPerformed(ActionEvent e)\r
320     {\r
321       if (!tree.hasOriginalSequenceData())\r
322       {\r
323         jalview.bin.Cache.log.info("Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");\r
324         return;\r
325       }\r
326       // decide if av alignment is sufficiently different to original data to warrant a new window to be created\r
327       // create new alignmnt window with hidden regions (unhiding hidden regions yields unaligned seqs)\r
328       // or create a selection box around columns in alignment view\r
329       // test Alignment(SeqCigar[])\r
330       Object[] alAndColsel = tree.seqData.getAlignmentAndColumnSelection(av.\r
331           getGapCharacter());\r
332 \r
333 \r
334       if (alAndColsel != null && alAndColsel[0]!=null)\r
335        {\r
336          // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);\r
337 \r
338          Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);\r
339          Alignment dataset = av.getAlignment().getDataset();\r
340          if (dataset != null)\r
341          {\r
342            al.setDataset(dataset);\r
343          }\r
344 \r
345          if (true)\r
346          {\r
347            // make a new frame!\r
348            AlignFrame af = new AlignFrame(al, (ColumnSelection) alAndColsel[1],\r
349                                            AlignFrame.DEFAULT_WIDTH,\r
350                                            AlignFrame.DEFAULT_HEIGHT\r
351 );\r
352 \r
353            //>>>This is a fix for the moment, until a better solution is found!!<<<\r
354            // af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());\r
355 \r
356        //           af.addSortByOrderMenuItem(ServiceName + " Ordering",\r
357        //                                     msaorder);\r
358 \r
359            Desktop.addInternalFrame(af, "Original Data for " + this.title,\r
360                                     AlignFrame.DEFAULT_WIDTH,\r
361                                     AlignFrame.DEFAULT_HEIGHT);\r
362          }\r
363        }\r
364     }\r
365 \r
366 \r
367     /**\r
368      * DOCUMENT ME!\r
369      *\r
370      * @param e DOCUMENT ME!\r
371      */\r
372     public void fitToWindow_actionPerformed(ActionEvent e)\r
373     {\r
374         treeCanvas.fitToWindow = fitToWindow.isSelected();\r
375         repaint();\r
376     }\r
377 \r
378     /**\r
379      * DOCUMENT ME!\r
380      *\r
381      * @param e DOCUMENT ME!\r
382      */\r
383     public void font_actionPerformed(ActionEvent e)\r
384     {\r
385         if (treeCanvas == null)\r
386         {\r
387             return;\r
388         }\r
389 \r
390         new FontChooser(this);\r
391     }\r
392 \r
393     public Font getTreeFont()\r
394     {\r
395         return treeCanvas.font;\r
396     }\r
397 \r
398     public void setTreeFont(Font font)\r
399     {\r
400       if(treeCanvas!=null)\r
401       treeCanvas.setFont(font);\r
402     }\r
403 \r
404     /**\r
405      * DOCUMENT ME!\r
406      *\r
407      * @param e DOCUMENT ME!\r
408      */\r
409     public void distanceMenu_actionPerformed(ActionEvent e)\r
410     {\r
411         treeCanvas.setShowDistances(distanceMenu.isSelected());\r
412     }\r
413 \r
414     /**\r
415      * DOCUMENT ME!\r
416      *\r
417      * @param e DOCUMENT ME!\r
418      */\r
419     public void bootstrapMenu_actionPerformed(ActionEvent e)\r
420     {\r
421         treeCanvas.setShowBootstrap(bootstrapMenu.isSelected());\r
422     }\r
423 \r
424     /**\r
425      * DOCUMENT ME!\r
426      *\r
427      * @param e DOCUMENT ME!\r
428      */\r
429     public void placeholdersMenu_actionPerformed(ActionEvent e)\r
430     {\r
431         treeCanvas.setMarkPlaceholders(placeholdersMenu.isSelected());\r
432     }\r
433 \r
434     /**\r
435      * DOCUMENT ME!\r
436      *\r
437      * @param e DOCUMENT ME!\r
438      */\r
439     public void epsTree_actionPerformed(ActionEvent e)\r
440     {\r
441       boolean accurateText = true;\r
442 \r
443       String renderStyle = jalview.bin.Cache.getDefault("EPS_RENDERING",\r
444           "Prompt each time");\r
445 \r
446     // If we need to prompt, and if the GUI is visible then\r
447     // Prompt for EPS rendering style\r
448       if (renderStyle.equalsIgnoreCase("Prompt each time")\r
449           && !\r
450           (System.getProperty("java.awt.headless") != null\r
451            && System.getProperty("java.awt.headless").equals("true")))\r
452       {\r
453         EPSOptions eps = new EPSOptions();\r
454         renderStyle = eps.getValue();\r
455 \r
456         if (renderStyle==null || eps.cancelled)\r
457           return;\r
458 \r
459 \r
460       }\r
461 \r
462       if (renderStyle.equalsIgnoreCase("text"))\r
463       {\r
464         accurateText = false;\r
465       }\r
466 \r
467         int width = treeCanvas.getWidth();\r
468         int height = treeCanvas.getHeight();\r
469 \r
470         try\r
471         {\r
472             jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(jalview.bin.Cache.getProperty(\r
473                         "LAST_DIRECTORY"), new String[] { "eps" },\r
474                     new String[] { "Encapsulated Postscript" },\r
475                     "Encapsulated Postscript");\r
476             chooser.setFileView(new jalview.io.JalviewFileView());\r
477             chooser.setDialogTitle("Create EPS file from tree");\r
478             chooser.setToolTipText("Save");\r
479 \r
480             int value = chooser.showSaveDialog(this);\r
481 \r
482             if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)\r
483             {\r
484                 return;\r
485             }\r
486 \r
487             jalview.bin.Cache.setProperty("LAST_DIRECTORY",\r
488                                           chooser.getSelectedFile().getParent());\r
489 \r
490             FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());\r
491             EpsGraphics2D pg = new EpsGraphics2D("Tree", out, 0, 0, width,\r
492                                                  height);\r
493 \r
494             pg.setAccurateTextMode(accurateText);\r
495 \r
496             treeCanvas.draw(pg, width, height);\r
497 \r
498             pg.flush();\r
499             pg.close();\r
500         }\r
501         catch (Exception ex)\r
502         {\r
503             ex.printStackTrace();\r
504         }\r
505     }\r
506 \r
507     /**\r
508      * DOCUMENT ME!\r
509      *\r
510      * @param e DOCUMENT ME!\r
511      */\r
512     public void pngTree_actionPerformed(ActionEvent e)\r
513     {\r
514         int width = treeCanvas.getWidth();\r
515         int height = treeCanvas.getHeight();\r
516 \r
517         try\r
518         {\r
519             jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(jalview.bin.Cache.getProperty(\r
520                         "LAST_DIRECTORY"), new String[] { "png" },\r
521                     new String[] { "Portable network graphics" },\r
522                     "Portable network graphics");\r
523 \r
524             chooser.setFileView(new jalview.io.JalviewFileView());\r
525             chooser.setDialogTitle("Create PNG image from tree");\r
526             chooser.setToolTipText("Save");\r
527 \r
528             int value = chooser.showSaveDialog(this);\r
529 \r
530             if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)\r
531             {\r
532                 return;\r
533             }\r
534 \r
535             jalview.bin.Cache.setProperty("LAST_DIRECTORY",\r
536                 chooser.getSelectedFile().getParent());\r
537 \r
538             FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());\r
539 \r
540             BufferedImage bi = new BufferedImage(width, height,\r
541                     BufferedImage.TYPE_INT_RGB);\r
542             Graphics png = bi.getGraphics();\r
543 \r
544             treeCanvas.draw(png, width, height);\r
545 \r
546             ImageIO.write(bi, "png", out);\r
547             out.close();\r
548         }\r
549         catch (Exception ex)\r
550         {\r
551             ex.printStackTrace();\r
552         }\r
553     }\r
554 }\r