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