Clover icon

Coverage Report

  1. Project Clover database Wed Nov 13 2024 16:12:26 GMT
  2. Package jalview.gui

File TreePanel.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
48% of files have more coverage

Code metrics

60
236
49
2
921
636
90
0.38
4.82
24.5
1.84

Classes

Class Line # Actions
TreePanel 84 216 83
0.322683732.3%
TreePanel.TreeLoader 353 20 7
0.7575%
 

Contributing tests

This file is covered by 10 tests. .

Source view

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 java.awt.Font;
24    import java.awt.Graphics;
25    import java.awt.event.ActionEvent;
26    import java.awt.event.ActionListener;
27    import java.awt.event.KeyAdapter;
28    import java.awt.event.KeyEvent;
29    import java.beans.PropertyChangeEvent;
30    import java.beans.PropertyChangeListener;
31    import java.io.File;
32    import java.io.FileOutputStream;
33    import java.util.ArrayList;
34    import java.util.List;
35    import java.util.Locale;
36   
37    import javax.swing.ButtonGroup;
38    import javax.swing.JMenuItem;
39    import javax.swing.JRadioButtonMenuItem;
40    import javax.swing.event.InternalFrameAdapter;
41    import javax.swing.event.InternalFrameEvent;
42   
43    import org.jibble.epsgraphics.EpsGraphics2D;
44   
45    import jalview.analysis.AlignmentSorter;
46    import jalview.analysis.AverageDistanceTree;
47    import jalview.analysis.NJTree;
48    import jalview.analysis.TreeBuilder;
49    import jalview.analysis.TreeModel;
50    import jalview.analysis.scoremodels.ScoreModels;
51    import jalview.api.analysis.ScoreModelI;
52    import jalview.api.analysis.SimilarityParamsI;
53    import jalview.bin.Cache;
54    import jalview.bin.Console;
55    import jalview.commands.CommandI;
56    import jalview.commands.OrderCommand;
57    import jalview.datamodel.Alignment;
58    import jalview.datamodel.AlignmentAnnotation;
59    import jalview.datamodel.AlignmentI;
60    import jalview.datamodel.AlignmentView;
61    import jalview.datamodel.BinaryNode;
62    import jalview.datamodel.DBRefEntry;
63    import jalview.datamodel.HiddenColumns;
64    import jalview.datamodel.NodeTransformI;
65    import jalview.datamodel.SequenceFeature;
66    import jalview.datamodel.SequenceI;
67    import jalview.datamodel.SequenceNode;
68    import jalview.gui.ImageExporter.ImageWriterI;
69    import jalview.io.JalviewFileChooser;
70    import jalview.io.JalviewFileView;
71    import jalview.io.NewickFile;
72    import jalview.io.exceptions.ImageOutputException;
73    import jalview.jbgui.GTreePanel;
74    import jalview.util.ImageMaker.TYPE;
75    import jalview.util.MessageManager;
76    import jalview.viewmodel.AlignmentViewport;
77   
78    /**
79    * DOCUMENT ME!
80    *
81    * @author $author$
82    * @version $Revision$
83    */
 
84    public class TreePanel extends GTreePanel
85    {
86    String treeType;
87   
88    String scoreModelName; // if tree computed
89   
90    String treeTitle; // if tree loaded
91   
92    SimilarityParamsI similarityParams;
93   
94    private TreeCanvas treeCanvas;
95   
96    TreeModel tree;
97   
98    private AlignViewport av;
99   
100    /**
101    * Creates a new TreePanel object.
102    *
103    * @param ap
104    * @param type
105    * @param modelName
106    * @param options
107    */
 
108  0 toggle public TreePanel(AlignmentPanel ap, String type, String modelName,
109    SimilarityParamsI options)
110    {
111  0 super();
112  0 this.setFrameIcon(null);
113  0 this.similarityParams = options;
114  0 initTreePanel(ap, type, modelName, null, null);
115   
116    // We know this tree has distances. JBPNote TODO: prolly should add this as
117    // a userdefined default
118    // showDistances(true);
119    }
120   
 
121  14 toggle public TreePanel(AlignmentPanel alignPanel, NewickFile newtree,
122    String theTitle, AlignmentView inputData)
123    {
124  14 super();
125  14 this.setFrameIcon(null);
126  14 this.treeTitle = theTitle;
127  14 initTreePanel(alignPanel, null, null, newtree, inputData);
128    }
129   
130    /**
131    * columnwise tree associated with positions in aa
132    *
133    * @param alignPanel
134    * @param fin
135    * @param title
136    * @param aa
137    */
 
138  0 toggle public TreePanel(AlignmentPanel alignPanel, NewickFile fin,
139    AlignmentAnnotation aa, String title)
140    {
141  0 super();
142  0 columnWise = true;
143  0 assocAnnotation = aa;
144  0 this.setFrameIcon(null);
145  0 this.treeTitle = title;
146  0 initTreePanel(alignPanel, null, null, fin, null);
147    }
148   
149    boolean columnWise = false;
150   
151    AlignmentAnnotation assocAnnotation = null;
152   
 
153  174 toggle public boolean isColumnWise()
154    {
155  174 return columnWise;
156    }
157   
 
158  14 toggle public AlignmentAnnotation getAssocAnnotation()
159    {
160  14 return assocAnnotation;
161    }
162   
 
163  0 toggle public AlignmentI getAlignment()
164    {
165  0 return getTreeCanvas().getViewport().getAlignment();
166    }
167   
 
168  0 toggle public AlignmentViewport getViewPort()
169    {
170    // @Mungo - Why don't we return our own viewport ???
171  0 return getTreeCanvas().getViewport();
172    }
173   
 
174  14 toggle void initTreePanel(AlignmentPanel ap, String type, String modelName,
175    NewickFile newTree, AlignmentView inputData)
176    {
177   
178  14 av = ap.av;
179  14 this.treeType = type;
180  14 this.scoreModelName = modelName;
181   
182  14 treeCanvas = new TreeCanvas(this, ap, scrollPane);
183  14 scrollPane.setViewportView(treeCanvas);
184   
185  14 if (columnWise)
186    {
187  0 bootstrapMenu.setVisible(false);
188  0 placeholdersMenu.setState(false);
189  0 placeholdersMenu.setVisible(false);
190  0 fitToWindow.setState(false);
191  0 sortAssocViews.setVisible(false);
192    }
193   
194  14 addKeyListener(new KeyAdapter()
195    {
 
196  0 toggle @Override
197    public void keyPressed(KeyEvent e)
198    {
199  0 switch (e.getKeyCode())
200    {
201  0 case 27: // escape
202  0 treeCanvas.clearSelectedLeaves();
203  0 e.consume();
204  0 break;
205   
206    }
207   
208    }
209    });
210  14 PaintRefresher.Register(this, ap.av.getSequenceSetId());
211   
212  14 buildAssociatedViewMenu();
213   
214  14 final PropertyChangeListener listener = addAlignmentListener();
215   
216    /*
217    * remove listener when window is closed, so that this
218    * panel can be garbage collected
219    */
220  14 addInternalFrameListener(new InternalFrameAdapter()
221    {
 
222  12 toggle @Override
223    public void internalFrameClosed(InternalFrameEvent evt)
224    {
225  12 if (av != null)
226    {
227  12 av.removePropertyChangeListener(listener);
228    }
229  12 releaseReferences();
230    }
231    });
232   
233  14 TreeLoader tl = new TreeLoader(newTree, inputData);
234  14 tl.start();
235   
236    }
237   
238    /**
239    * Ensure any potentially large object references are nulled
240    */
 
241  12 toggle public void releaseReferences()
242    {
243  12 this.tree = null;
244  12 this.treeCanvas.tree = null;
245  12 this.treeCanvas.nodeHash = null;
246  12 this.treeCanvas.nameHash = null;
247    }
248   
249    /**
250    * @return
251    */
 
252  14 toggle protected PropertyChangeListener addAlignmentListener()
253    {
254  14 final PropertyChangeListener listener = new PropertyChangeListener()
255    {
 
256  0 toggle @Override
257    public void propertyChange(PropertyChangeEvent evt)
258    {
259  0 if (evt.getPropertyName().equals("alignment"))
260    {
261  0 if (tree == null)
262    {
263  0 jalview.bin.Console.outPrintln("tree is null");
264    // TODO: deal with case when a change event is received whilst a
265    // tree is still being calculated - should save reference for
266    // processing message later.
267  0 return;
268    }
269  0 if (evt.getNewValue() == null)
270    {
271  0 jalview.bin.Console.outPrintln(
272    "new alignment sequences vector value is null");
273    }
274   
275  0 tree.updatePlaceHolders((List<SequenceI>) evt.getNewValue());
276  0 treeCanvas.nameHash.clear(); // reset the mapping between canvas
277    // rectangles and leafnodes
278  0 repaint();
279    }
280    }
281    };
282  14 av.addPropertyChangeListener(listener);
283  14 return listener;
284    }
285   
 
286  0 toggle @Override
287    public void viewMenu_menuSelected()
288    {
289  0 buildAssociatedViewMenu();
290    }
291   
 
292  14 toggle void buildAssociatedViewMenu()
293    {
294  14 AlignmentPanel[] aps = PaintRefresher
295    .getAssociatedPanels(av.getSequenceSetId());
296  14 if (aps.length == 1 && getTreeCanvas().getAssociatedPanel() == aps[0])
297    {
298  6 associateLeavesMenu.setVisible(false);
299  6 return;
300    }
301   
302  8 associateLeavesMenu.setVisible(true);
303   
304  8 if ((viewMenu
305    .getItem(viewMenu.getItemCount() - 2) instanceof JMenuItem))
306    {
307  8 viewMenu.insertSeparator(viewMenu.getItemCount() - 1);
308    }
309   
310  8 associateLeavesMenu.removeAll();
311   
312  8 JRadioButtonMenuItem item;
313  8 ButtonGroup buttonGroup = new ButtonGroup();
314  8 int i, iSize = aps.length;
315  8 final TreePanel thisTreePanel = this;
316  32 for (i = 0; i < iSize; i++)
317    {
318  24 final AlignmentPanel ap = aps[i];
319  24 item = new JRadioButtonMenuItem(ap.av.getViewName(),
320    ap == treeCanvas.getAssociatedPanel());
321  24 buttonGroup.add(item);
322  24 item.addActionListener(new ActionListener()
323    {
 
324  0 toggle @Override
325    public void actionPerformed(ActionEvent evt)
326    {
327  0 treeCanvas.applyToAllViews = false;
328  0 treeCanvas.setAssociatedPanel(ap);
329  0 treeCanvas.setViewport(ap.av);
330  0 PaintRefresher.Register(thisTreePanel, ap.av.getSequenceSetId());
331    }
332    });
333   
334  24 associateLeavesMenu.add(item);
335    }
336   
337  8 final JRadioButtonMenuItem itemf = new JRadioButtonMenuItem(
338    MessageManager.getString("label.all_views"));
339  8 buttonGroup.add(itemf);
340  8 itemf.setSelected(treeCanvas.applyToAllViews);
341  8 itemf.addActionListener(new ActionListener()
342    {
 
343  0 toggle @Override
344    public void actionPerformed(ActionEvent evt)
345    {
346  0 treeCanvas.applyToAllViews = itemf.isSelected();
347    }
348    });
349  8 associateLeavesMenu.add(itemf);
350   
351    }
352   
 
353    class TreeLoader extends Thread
354    {
355    private NewickFile newtree;
356   
357    private AlignmentView odata = null;
358   
 
359  14 toggle public TreeLoader(NewickFile newickFile, AlignmentView inputData)
360    {
361  14 this.newtree = newickFile;
362  14 this.odata = inputData;
363   
364  14 if (newickFile != null)
365    {
366    // Must be outside run(), as Jalview2XML tries to
367    // update distance/bootstrap visibility at the same time
368  14 showBootstrap(newickFile.HasBootstrap());
369  14 showDistances(newickFile.HasDistances());
370    }
371    }
372   
 
373  14 toggle @Override
374    public void run()
375    {
376   
377  14 if (newtree != null)
378    {
379  14 tree = new TreeModel(av.getAlignment().getSequencesArray(), odata,
380    newtree);
381  14 if (tree.getOriginalData() == null)
382    {
383  14 originalSeqData.setVisible(false);
384    }
385    }
386    else
387    {
388  0 ScoreModelI sm = ScoreModels.getInstance().getScoreModel(
389    scoreModelName, treeCanvas.getAssociatedPanel());
390  0 TreeBuilder njtree = treeType.equals(TreeBuilder.NEIGHBOUR_JOINING)
391    ? new NJTree(av, sm, similarityParams)
392    : new AverageDistanceTree(av, sm, similarityParams);
393  0 tree = new TreeModel(njtree);
394    // don't display distances for columnwise trees
395    }
396  14 showDistances(!columnWise);
397  14 tree.reCount(tree.getTopNode());
398  14 tree.findHeight(tree.getTopNode());
399  14 treeCanvas.setTree(tree);
400  14 treeCanvas.repaint();
401  14 av.setCurrentTree(tree);
402  14 if (av.getSortByTree())
403    {
404  1 sortByTree_actionPerformed();
405    }
406    }
407    }
408   
 
409  40 toggle public void showDistances(boolean b)
410    {
411  40 treeCanvas.setShowDistances(b);
412  40 distanceMenu.setSelected(b);
413    }
414   
 
415  26 toggle public void showBootstrap(boolean b)
416    {
417  26 treeCanvas.setShowBootstrap(b);
418  26 bootstrapMenu.setSelected(b);
419    }
420   
 
421  12 toggle public void showPlaceholders(boolean b)
422    {
423  12 placeholdersMenu.setState(b);
424  12 treeCanvas.setMarkPlaceholders(b);
425    }
426   
427    /**
428    * DOCUMENT ME!
429    *
430    * @return DOCUMENT ME!
431    */
 
432  22 toggle public TreeModel getTree()
433    {
434  22 return tree;
435    }
436   
437    /**
438    * DOCUMENT ME!
439    *
440    * @param e
441    * DOCUMENT ME!
442    */
 
443  0 toggle @Override
444    public void textbox_actionPerformed(ActionEvent e)
445    {
446  0 CutAndPasteTransfer cap = new CutAndPasteTransfer();
447   
448  0 String newTitle = getPanelTitle();
449   
450  0 NewickFile fout = new NewickFile(tree.getTopNode());
451  0 try
452    {
453  0 cap.setText(fout.print(tree.hasBootstrap(), tree.hasDistances(),
454    tree.hasRootDistance()));
455  0 Desktop.addInternalFrame(cap, newTitle, 500, 100);
456    } catch (OutOfMemoryError oom)
457    {
458  0 new OOMWarning("generating newick tree file", oom);
459  0 cap.dispose();
460    }
461   
462    }
463   
464    /**
465    * DOCUMENT ME!
466    *
467    * @param e
468    * DOCUMENT ME!
469    */
 
470  0 toggle @Override
471    public void saveAsNewick_actionPerformed(ActionEvent e)
472    {
473    // TODO: JAL-3048 save newick file for Jalview-JS
474  0 JalviewFileChooser chooser = new JalviewFileChooser(
475    Cache.getProperty("LAST_DIRECTORY"));
476  0 chooser.setFileView(new JalviewFileView());
477  0 chooser.setDialogTitle(
478    MessageManager.getString("label.save_tree_as_newick"));
479  0 chooser.setToolTipText(MessageManager.getString("action.save"));
480   
481  0 int value = chooser.showSaveDialog(null);
482   
483  0 if (value == JalviewFileChooser.APPROVE_OPTION)
484    {
485  0 String choice = chooser.getSelectedFile().getPath();
486  0 Cache.setProperty("LAST_DIRECTORY",
487    chooser.getSelectedFile().getParent());
488   
489  0 try
490    {
491  0 jalview.io.NewickFile fout = new jalview.io.NewickFile(
492    tree.getTopNode());
493  0 String output = fout.print(tree.hasBootstrap(), tree.hasDistances(),
494    tree.hasRootDistance());
495  0 java.io.PrintWriter out = new java.io.PrintWriter(
496    new java.io.FileWriter(choice));
497  0 out.println(output);
498  0 out.close();
499    } catch (Exception ex)
500    {
501  0 ex.printStackTrace();
502    }
503    }
504    }
505   
506    /**
507    * DOCUMENT ME!
508    *
509    * @param e
510    * DOCUMENT ME!
511    */
 
512  0 toggle @Override
513    public void printMenu_actionPerformed(ActionEvent e)
514    {
515    // Putting in a thread avoids Swing painting problems
516  0 treeCanvas.startPrinting();
517    }
518   
 
519  0 toggle @Override
520    public void originalSeqData_actionPerformed(ActionEvent e)
521    {
522  0 AlignmentView originalData = tree.getOriginalData();
523  0 if (originalData == null)
524    {
525  0 Console.info(
526    "Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
527  0 return;
528    }
529    // decide if av alignment is sufficiently different to original data to
530    // warrant a new window to be created
531    // create new alignmnt window with hidden regions (unhiding hidden regions
532    // yields unaligned seqs)
533    // or create a selection box around columns in alignment view
534    // test Alignment(SeqCigar[])
535  0 char gc = '-';
536  0 try
537    {
538    // we try to get the associated view's gap character
539    // but this may fail if the view was closed...
540  0 gc = av.getGapCharacter();
541   
542    } catch (Exception ex)
543    {
544    }
545   
546  0 Object[] alAndColsel = originalData.getAlignmentAndHiddenColumns(gc);
547   
548  0 if (alAndColsel != null && alAndColsel[0] != null)
549    {
550    // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);
551   
552  0 AlignmentI al = new Alignment((SequenceI[]) alAndColsel[0]);
553  0 AlignmentI dataset = (av != null && av.getAlignment() != null)
554    ? av.getAlignment().getDataset()
555    : null;
556  0 if (dataset != null)
557    {
558  0 al.setDataset(dataset);
559    }
560   
561  0 if (true)
562    {
563    // make a new frame!
564  0 AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
565    AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
566   
567    // >>>This is a fix for the moment, until a better solution is
568    // found!!<<<
569    // af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());
570   
571    // af.addSortByOrderMenuItem(ServiceName + " Ordering",
572    // msaorder);
573   
574  0 Desktop.addInternalFrame(af, MessageManager.formatMessage(
575    "label.original_data_for_params", new Object[]
576    { this.title }), AlignFrame.DEFAULT_WIDTH,
577    AlignFrame.DEFAULT_HEIGHT);
578    }
579    }
580    }
581   
582    /**
583    * DOCUMENT ME!
584    *
585    * @param e
586    * DOCUMENT ME!
587    */
 
588  12 toggle @Override
589    public void fitToWindow_actionPerformed(ActionEvent e)
590    {
591  12 treeCanvas.fitToWindow = fitToWindow.isSelected();
592  12 repaint();
593    }
594   
595    /**
596    * sort the associated alignment view by the current tree.
597    *
598    * @param e
599    */
 
600  1 toggle @Override
601    public void sortByTree_actionPerformed()
602    {
603   
604  1 if (treeCanvas.applyToAllViews)
605    {
606  0 final ArrayList<CommandI> commands = new ArrayList<>();
607  0 for (AlignmentPanel ap : PaintRefresher
608    .getAssociatedPanels(av.getSequenceSetId()))
609    {
610  0 commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
611    }
612  0 av.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
613    {
614   
 
615  0 toggle @Override
616    public void undoCommand(AlignmentI[] views)
617    {
618  0 for (CommandI tsort : commands)
619    {
620  0 tsort.undoCommand(views);
621    }
622    }
623   
 
624  0 toggle @Override
625    public int getSize()
626    {
627  0 return commands.size();
628    }
629   
 
630  0 toggle @Override
631    public String getDescription()
632    {
633  0 return "Tree Sort (many views)";
634    }
635   
 
636  0 toggle @Override
637    public void doCommand(AlignmentI[] views)
638    {
639   
640  0 for (CommandI tsort : commands)
641    {
642  0 tsort.doCommand(views);
643    }
644    }
645    });
646  0 for (AlignmentPanel ap : PaintRefresher
647    .getAssociatedPanels(av.getSequenceSetId()))
648    {
649    // ensure all the alignFrames refresh their GI after adding an undo item
650  0 ap.alignFrame.updateEditMenuBar();
651    }
652    }
653    else
654    {
655  1 treeCanvas.getAssociatedPanel().alignFrame.addHistoryItem(
656    sortAlignmentIn(treeCanvas.getAssociatedPanel()));
657    }
658   
659    }
660   
 
661  1 toggle public CommandI sortAlignmentIn(AlignmentPanel ap)
662    {
663    // TODO: move to alignment view controller
664  1 AlignmentViewport viewport = ap.av;
665  1 SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
666  1 AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
667  1 CommandI undo;
668  1 undo = new OrderCommand("Tree Sort", oldOrder, viewport.getAlignment());
669   
670  1 ap.paintAlignment(true, false);
671  1 return undo;
672    }
673   
674    /**
675    * DOCUMENT ME!
676    *
677    * @param e
678    * DOCUMENT ME!
679    */
 
680  0 toggle @Override
681    public void font_actionPerformed(ActionEvent e)
682    {
683  0 if (treeCanvas == null)
684    {
685  0 return;
686    }
687   
688  0 new FontChooser(this);
689    }
690   
 
691  12 toggle public Font getTreeFont()
692    {
693  12 return treeCanvas.font;
694    }
695   
 
696  12 toggle public void setTreeFont(Font f)
697    {
698  12 if (treeCanvas != null)
699    {
700  12 treeCanvas.setFont(f);
701    }
702    }
703   
704    /**
705    * DOCUMENT ME!
706    *
707    * @param e
708    * DOCUMENT ME!
709    */
 
710  0 toggle @Override
711    public void distanceMenu_actionPerformed(ActionEvent e)
712    {
713  0 treeCanvas.setShowDistances(distanceMenu.isSelected());
714    }
715   
716    /**
717    * DOCUMENT ME!
718    *
719    * @param e
720    * DOCUMENT ME!
721    */
 
722  0 toggle @Override
723    public void bootstrapMenu_actionPerformed(ActionEvent e)
724    {
725  0 treeCanvas.setShowBootstrap(bootstrapMenu.isSelected());
726    }
727   
728    /**
729    * DOCUMENT ME!
730    *
731    * @param e
732    * DOCUMENT ME!
733    */
 
734  0 toggle @Override
735    public void placeholdersMenu_actionPerformed(ActionEvent e)
736    {
737  0 treeCanvas.setMarkPlaceholders(placeholdersMenu.isSelected());
738    }
739   
740    /**
741    * Outputs the Tree in image format (currently EPS or PNG). The user is
742    * prompted for the file to save to, and for EPS (unless a preference is
743    * already set) for the choice of Text or Lineart for character rendering.
744    */
 
745  0 toggle @Override
746    public void writeTreeImage(TYPE imageFormat)
747    {
748  0 int width = treeCanvas.getWidth();
749  0 int height = treeCanvas.getHeight();
750  0 ImageWriterI writer = new ImageWriterI()
751    {
 
752  0 toggle @Override
753    public void exportImage(Graphics g) throws Exception
754    {
755  0 treeCanvas.draw(g, width, height);
756    }
757    };
758  0 String tree = MessageManager.getString("label.tree");
759  0 ImageExporter exporter = new ImageExporter(writer, null, imageFormat,
760    tree);
761  0 try
762    {
763  0 exporter.doExport(null, this, width, height,
764    tree.toLowerCase(Locale.ROOT));
765    } catch (ImageOutputException ioex)
766    {
767  0 Console.error(
768    "Unexpected error whilst writing " + imageFormat.toString(),
769    ioex);
770    }
771    }
772   
773    /**
774    * change node labels to the annotation referred to by labelClass TODO:
775    * promote to a datamodel modification that can be undone TODO: make argument
776    * one case of a generic transformation function ie { undoStep = apply(Tree,
777    * TransformFunction)};
778    *
779    * @param labelClass
780    */
 
781  0 toggle public void changeNames(final String labelClass)
782    {
783  0 tree.applyToNodes(new NodeTransformI()
784    {
785   
 
786  0 toggle @Override
787    public void transform(BinaryNode node)
788    {
789  0 if (node instanceof SequenceNode
790    && !((SequenceNode) node).isPlaceholder()
791    && !((SequenceNode) node).isDummy())
792    {
793  0 String newname = null;
794  0 SequenceI sq = (SequenceI) ((BinaryNode) node).element();
795  0 if (sq != null)
796    {
797    // search dbrefs, features and annotation
798  0 List<DBRefEntry> refs = jalview.util.DBRefUtils
799    .selectRefs(sq.getDBRefs(), new String[]
800    { labelClass.toUpperCase(Locale.ROOT) });
801  0 if (refs != null)
802    {
803  0 for (int i = 0, ni = refs.size(); i < ni; i++)
804    {
805  0 if (newname == null)
806    {
807  0 newname = new String(refs.get(i).getAccessionId());
808    }
809    else
810    {
811  0 newname += "; " + refs.get(i).getAccessionId();
812    }
813    }
814    }
815  0 if (newname == null)
816    {
817  0 List<SequenceFeature> features = sq.getFeatures()
818    .getPositionalFeatures(labelClass);
819  0 for (SequenceFeature feature : features)
820    {
821  0 if (newname == null)
822    {
823  0 newname = feature.getDescription();
824    }
825    else
826    {
827  0 newname = newname + "; " + feature.getDescription();
828    }
829    }
830    }
831    }
832  0 if (newname != null)
833    {
834    // String oldname = ((SequenceNode) node).getName();
835    // TODO : save oldname in the undo object for this modification.
836  0 ((BinaryNode) node).setName(newname);
837    }
838    }
839    }
840    });
841    }
842   
843    /**
844    * Formats a localised title for the tree panel, like
845    * <p>
846    * Neighbour Joining Using BLOSUM62
847    * <p>
848    * For a tree loaded from file, just uses the file name
849    *
850    * @return
851    */
 
852  0 toggle public String getPanelTitle()
853    {
854  0 if (treeTitle != null)
855    {
856  0 return treeTitle;
857    }
858   
859    /*
860    * i18n description of Neighbour Joining or Average Distance method
861    */
862  0 String treecalcnm = MessageManager.getString(
863    "label.tree_calc_" + treeType.toLowerCase(Locale.ROOT));
864   
865    /*
866    * short score model name (long description can be too long)
867    */
868  0 String smn = scoreModelName;
869   
870    /*
871    * put them together as <method> Using <model>
872    */
873  0 final String ttl = MessageManager.formatMessage("label.calc_title",
874    treecalcnm, smn);
875  0 return ttl;
876    }
877   
878    /**
879    * Builds an EPS image and writes it to the specified file.
880    *
881    * @param outFile
882    * @param textOption
883    * true for Text character rendering, false for Lineart
884    */
 
885  0 toggle protected void writeEpsFile(File outFile, boolean textOption)
886    {
887  0 try
888    {
889  0 int width = treeCanvas.getWidth();
890  0 int height = treeCanvas.getHeight();
891   
892  0 FileOutputStream out = new FileOutputStream(outFile);
893  0 EpsGraphics2D pg = new EpsGraphics2D("Tree", out, 0, 0, width,
894    height);
895  0 pg.setAccurateTextMode(!textOption);
896  0 treeCanvas.draw(pg, width, height);
897   
898  0 pg.flush();
899  0 pg.close();
900    } catch (Exception ex)
901    {
902  0 jalview.bin.Console.errPrintln("Error writing tree as EPS");
903  0 ex.printStackTrace();
904    }
905    }
906   
 
907  0 toggle public AlignViewport getViewport()
908    {
909  0 return av;
910    }
911   
 
912  0 toggle public void setViewport(AlignViewport av)
913    {
914  0 this.av = av;
915    }
916   
 
917  42 toggle public TreeCanvas getTreeCanvas()
918    {
919  42 return treeCanvas;
920    }
921    }