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