Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.gui

File TreePanel.java

 

Coverage histogram

../../img/srcFileCovDistChart3.png
47% of files have more coverage

Code metrics

58
204
41
2
817
556
79
0.39
4.98
20.5
1.93

Classes

Class Line # Actions
TreePanel 77 184 72 201
0.2583025725.8%
TreePanel.TreeLoader 272 20 7 11
0.6562565.6%
 

Contributing tests

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