JAL-1632 refactored NJTree constructor to include SimilarityParams
[jalview.git] / src / jalview / gui / TreePanel.java
index d8253db..857e77c 100755 (executable)
@@ -1,39 +1,68 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
- * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  * Jalview is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License 
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
- * 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
  * Jalview is distributed in the hope that it will be useful, but 
  * WITHOUT ANY WARRANTY; without even the implied warranty 
  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
  * PURPOSE.  See the GNU General Public License for more details.
  * 
- * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
  */
 package jalview.gui;
 
-import java.beans.*;
-import java.io.*;
-import java.util.*;
-import javax.imageio.*;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.image.*;
-import javax.swing.*;
-
-import org.jibble.epsgraphics.*;
-import jalview.analysis.*;
+import jalview.analysis.AlignmentSorter;
+import jalview.analysis.NJTree;
+import jalview.analysis.scoremodels.ScoreModels;
+import jalview.analysis.scoremodels.SimilarityParams;
+import jalview.api.analysis.ScoreModelI;
+import jalview.api.analysis.ViewBasedAnalysisI;
+import jalview.bin.Cache;
 import jalview.commands.CommandI;
 import jalview.commands.OrderCommand;
-import jalview.datamodel.*;
-import jalview.io.*;
-import jalview.jbgui.*;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.BinaryNode;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.NodeTransformI;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.SequenceNode;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.io.NewickFile;
+import jalview.jbgui.GTreePanel;
+import jalview.util.ImageMaker;
+import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
+
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java.beans.PropertyChangeEvent;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+import javax.swing.ButtonGroup;
+import javax.swing.JMenuItem;
+import javax.swing.JRadioButtonMenuItem;
+
+import org.jibble.epsgraphics.EpsGraphics2D;
 
 /**
  * DOCUMENT ME!
@@ -79,27 +108,6 @@ public class TreePanel extends GTreePanel
     // showDistances(true);
   }
 
-  /**
-   * Creates a new TreePanel object.
-   * 
-   * @param av
-   *          DOCUMENT ME!
-   * @param seqVector
-   *          DOCUMENT ME!
-   * @param newtree
-   *          DOCUMENT ME!
-   * @param type
-   *          DOCUMENT ME!
-   * @param pwtype
-   *          DOCUMENT ME!
-   */
-  public TreePanel(AlignmentPanel ap, String type, String pwtype,
-          NewickFile newtree)
-  {
-    super();
-    initTreePanel(ap, type, pwtype, newtree, null);
-  }
-
   public TreePanel(AlignmentPanel av, String type, String pwtype,
           NewickFile newtree, AlignmentView inputData)
   {
@@ -112,7 +120,7 @@ public class TreePanel extends GTreePanel
     return treeCanvas.av.getAlignment();
   }
 
-  public AlignViewport getViewPort()
+  public AlignmentViewport getViewPort()
   {
     return treeCanvas.av;
   }
@@ -134,6 +142,7 @@ public class TreePanel extends GTreePanel
 
     av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
     {
+      @Override
       public void propertyChange(PropertyChangeEvent evt)
       {
         if (evt.getPropertyName().equals("alignment"))
@@ -152,7 +161,7 @@ public class TreePanel extends GTreePanel
                     .println("new alignment sequences vector value is null");
           }
 
-          tree.UpdatePlaceHolders((Vector) evt.getNewValue());
+          tree.updatePlaceHolders((List<SequenceI>) evt.getNewValue());
           treeCanvas.nameHash.clear(); // reset the mapping between canvas
           // rectangles and leafnodes
           repaint();
@@ -169,6 +178,7 @@ public class TreePanel extends GTreePanel
 
   }
 
+  @Override
   public void viewMenu_menuSelected()
   {
     buildAssociatedViewMenu();
@@ -204,6 +214,7 @@ public class TreePanel extends GTreePanel
       buttonGroup.add(item);
       item.addActionListener(new ActionListener()
       {
+        @Override
         public void actionPerformed(ActionEvent evt)
         {
           treeCanvas.applyToAllViews = false;
@@ -216,11 +227,13 @@ public class TreePanel extends GTreePanel
       associateLeavesMenu.add(item);
     }
 
-    final JRadioButtonMenuItem itemf = new JRadioButtonMenuItem("All Views");
+    final JRadioButtonMenuItem itemf = new JRadioButtonMenuItem(
+            MessageManager.getString("label.all_views"));
     buttonGroup.add(itemf);
     itemf.setSelected(treeCanvas.applyToAllViews);
     itemf.addActionListener(new ActionListener()
     {
+      @Override
       public void actionPerformed(ActionEvent evt)
       {
         treeCanvas.applyToAllViews = itemf.isSelected();
@@ -248,6 +261,7 @@ public class TreePanel extends GTreePanel
       }
     }
 
+    @Override
     public void run()
     {
 
@@ -255,11 +269,11 @@ public class TreePanel extends GTreePanel
       {
         if (odata == null)
         {
-          tree = new NJTree(av.alignment.getSequencesArray(), newtree);
+          tree = new NJTree(av.getAlignment().getSequencesArray(), newtree);
         }
         else
         {
-          tree = new NJTree(av.alignment.getSequencesArray(), odata,
+          tree = new NJTree(av.getAlignment().getSequencesArray(), odata,
                   newtree);
         }
         if (!tree.hasOriginalSequenceData())
@@ -271,22 +285,24 @@ public class TreePanel extends GTreePanel
       {
         int start, end;
         SequenceI[] seqs;
-        AlignmentView seqStrings = av.getAlignmentView(av
-                .getSelectionGroup() != null);
-        if (av.getSelectionGroup() == null)
+        boolean selview = av.getSelectionGroup() != null
+                && av.getSelectionGroup().getSize() > 1;
+        AlignmentView seqStrings = av.getAlignmentView(selview);
+        if (!selview)
         {
           start = 0;
-          end = av.alignment.getWidth();
-          seqs = av.alignment.getSequencesArray();
+          end = av.getAlignment().getWidth();
+          seqs = av.getAlignment().getSequencesArray();
         }
         else
         {
           start = av.getSelectionGroup().getStartRes();
           end = av.getSelectionGroup().getEndRes() + 1;
-          seqs = av.getSelectionGroup().getSequencesInOrder(av.alignment);
+          seqs = av.getSelectionGroup().getSequencesInOrder(
+                  av.getAlignment());
         }
-
-        tree = new NJTree(seqs, seqStrings, type, pwtype, start, end);
+        ScoreModelI sm = configureScoreModel(pwtype);
+        tree = new NJTree(av, type, sm, SimilarityParams.Jalview);
         showDistances(true);
       }
 
@@ -297,7 +313,7 @@ public class TreePanel extends GTreePanel
       av.setCurrentTree(tree);
       if (av.getSortByTree())
       {
-        sortByTree_actionPerformed(null);
+        sortByTree_actionPerformed();
       }
     }
   }
@@ -341,37 +357,19 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void textbox_actionPerformed(ActionEvent e)
   {
     CutAndPasteTransfer cap = new CutAndPasteTransfer();
 
-    StringBuffer buffer = new StringBuffer();
-
-    if (type.equals("AV"))
-    {
-      buffer.append("Average distance tree using ");
-    }
-    else
-    {
-      buffer.append("Neighbour joining tree using ");
-    }
-
-    if (pwtype.equals("BL"))
-    {
-      buffer.append("BLOSUM62");
-    }
-    else
-    {
-      buffer.append("PID");
-    }
+    String newTitle = getPanelTitle(type, pwtype);
 
-    jalview.io.NewickFile fout = new jalview.io.NewickFile(
-            tree.getTopNode());
+    NewickFile fout = new NewickFile(tree.getTopNode());
     try
     {
-      cap.setText(fout.print(tree.isHasBootstrap(), tree.isHasDistances(),
-              tree.isHasRootDistance()));
-      Desktop.addInternalFrame(cap, buffer.toString(), 500, 100);
+      cap.setText(fout.print(tree.hasBootstrap(), tree.hasDistances(),
+              tree.hasRootDistance()));
+      Desktop.addInternalFrame(cap, newTitle, 500, 100);
     } catch (OutOfMemoryError oom)
     {
       new OOMWarning("generating newick tree file", oom);
@@ -386,13 +384,15 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void saveAsNewick_actionPerformed(ActionEvent e)
   {
     JalviewFileChooser chooser = new JalviewFileChooser(
             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle("Save tree as newick file");
-    chooser.setToolTipText("Save");
+    chooser.setDialogTitle(MessageManager
+            .getString("label.save_tree_as_newick"));
+    chooser.setToolTipText(MessageManager.getString("action.save"));
 
     int value = chooser.showSaveDialog(null);
 
@@ -406,8 +406,8 @@ public class TreePanel extends GTreePanel
       {
         jalview.io.NewickFile fout = new jalview.io.NewickFile(
                 tree.getTopNode());
-        String output = fout.print(tree.isHasBootstrap(),
-                tree.isHasDistances(), tree.isHasRootDistance());
+        String output = fout.print(tree.hasBootstrap(),
+                tree.hasDistances(), tree.hasRootDistance());
         java.io.PrintWriter out = new java.io.PrintWriter(
                 new java.io.FileWriter(choice));
         out.println(output);
@@ -425,12 +425,14 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void printMenu_actionPerformed(ActionEvent e)
   {
     // Putting in a thread avoids Swing painting problems
     treeCanvas.startPrinting();
   }
 
+  @Override
   public void originalSeqData_actionPerformed(ActionEvent e)
   {
     if (!tree.hasOriginalSequenceData())
@@ -462,8 +464,8 @@ public class TreePanel extends GTreePanel
     {
       // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);
 
-      Alignment al = new Alignment((SequenceI[]) alAndColsel[0]);
-      Alignment dataset = (av != null && av.getAlignment() != null) ? av
+      AlignmentI al = new Alignment((SequenceI[]) alAndColsel[0]);
+      AlignmentI dataset = (av != null && av.getAlignment() != null) ? av
               .getAlignment().getDataset() : null;
       if (dataset != null)
       {
@@ -484,8 +486,10 @@ public class TreePanel extends GTreePanel
         // af.addSortByOrderMenuItem(ServiceName + " Ordering",
         // msaorder);
 
-        Desktop.addInternalFrame(af, "Original Data for " + this.title,
-                AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+        Desktop.addInternalFrame(af, MessageManager.formatMessage(
+                "label.original_data_for_params",
+                new Object[] { this.title }), AlignFrame.DEFAULT_WIDTH,
+                AlignFrame.DEFAULT_HEIGHT);
       }
     }
   }
@@ -496,6 +500,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void fitToWindow_actionPerformed(ActionEvent e)
   {
     treeCanvas.fitToWindow = fitToWindow.isSelected();
@@ -507,80 +512,86 @@ public class TreePanel extends GTreePanel
    * 
    * @param e
    */
-  public void sortByTree_actionPerformed(ActionEvent e)
+  @Override
+  public void sortByTree_actionPerformed()
   {
-    
+
     if (treeCanvas.applyToAllViews)
     {
       final ArrayList<CommandI> commands = new ArrayList<CommandI>();
-      for (AlignmentPanel ap: PaintRefresher.getAssociatedPanels(av
+      for (AlignmentPanel ap : PaintRefresher.getAssociatedPanels(av
               .getSequenceSetId()))
       {
         commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
       }
       av.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
       {
-        
+
         @Override
         public void undoCommand(AlignmentI[] views)
         {
-          for (CommandI tsort:commands)
+          for (CommandI tsort : commands)
           {
             tsort.undoCommand(views);
-          }          
+          }
         }
-        
+
         @Override
         public int getSize()
         {
           return commands.size();
         }
-        
+
         @Override
         public String getDescription()
         {
           return "Tree Sort (many views)";
         }
-        
+
         @Override
         public void doCommand(AlignmentI[] views)
         {
 
-          for (CommandI tsort:commands)
+          for (CommandI tsort : commands)
           {
             tsort.doCommand(views);
-          }          
+          }
         }
       });
-      for (AlignmentPanel ap: PaintRefresher.getAssociatedPanels(av
+      for (AlignmentPanel ap : PaintRefresher.getAssociatedPanels(av
               .getSequenceSetId()))
       {
         // ensure all the alignFrames refresh their GI after adding an undo item
         ap.alignFrame.updateEditMenuBar();
       }
-    } else {
-      treeCanvas.ap.alignFrame.addHistoryItem(sortAlignmentIn(treeCanvas.ap));
+    }
+    else
+    {
+      treeCanvas.ap.alignFrame
+              .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
     }
 
   }
+
   public CommandI sortAlignmentIn(AlignmentPanel ap)
   {
-    AlignViewport av = ap.av;
+    AlignmentViewport av = ap.av;
     SequenceI[] oldOrder = av.getAlignment().getSequencesArray();
     AlignmentSorter.sortByTree(av.getAlignment(), tree);
     CommandI undo;
-    undo=new OrderCommand("Tree Sort", oldOrder,
-          av.alignment);
+    undo = new OrderCommand("Tree Sort", oldOrder, av.getAlignment());
 
-    ap.paintAlignment(true);    
+    ap.paintAlignment(true);
     return undo;
   }
+
   /**
    * DOCUMENT ME!
    * 
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void font_actionPerformed(ActionEvent e)
   {
     if (treeCanvas == null)
@@ -610,6 +621,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void distanceMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setShowDistances(distanceMenu.isSelected());
@@ -621,6 +633,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void bootstrapMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setShowBootstrap(bootstrapMenu.isSelected());
@@ -632,6 +645,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void placeholdersMenu_actionPerformed(ActionEvent e)
   {
     treeCanvas.setMarkPlaceholders(placeholdersMenu.isSelected());
@@ -643,6 +657,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void epsTree_actionPerformed(ActionEvent e)
   {
     boolean accurateText = true;
@@ -676,23 +691,22 @@ public class TreePanel extends GTreePanel
 
     try
     {
-      jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
-              jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
-              { "eps" }, new String[]
-              { "Encapsulated Postscript" }, "Encapsulated Postscript");
-      chooser.setFileView(new jalview.io.JalviewFileView());
-      chooser.setDialogTitle("Create EPS file from tree");
-      chooser.setToolTipText("Save");
+      JalviewFileChooser chooser = new JalviewFileChooser(
+              ImageMaker.EPS_EXTENSION, ImageMaker.EPS_EXTENSION);
+      chooser.setFileView(new JalviewFileView());
+      chooser.setDialogTitle(MessageManager
+              .getString("label.create_eps_from_tree"));
+      chooser.setToolTipText(MessageManager.getString("action.save"));
 
       int value = chooser.showSaveDialog(this);
 
-      if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)
+      if (value != JalviewFileChooser.APPROVE_OPTION)
       {
         return;
       }
 
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
-              .getSelectedFile().getParent());
+      Cache.setProperty("LAST_DIRECTORY", chooser.getSelectedFile()
+              .getParent());
 
       FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());
       EpsGraphics2D pg = new EpsGraphics2D("Tree", out, 0, 0, width, height);
@@ -715,6 +729,7 @@ public class TreePanel extends GTreePanel
    * @param e
    *          DOCUMENT ME!
    */
+  @Override
   public void pngTree_actionPerformed(ActionEvent e)
   {
     int width = treeCanvas.getWidth();
@@ -722,14 +737,13 @@ public class TreePanel extends GTreePanel
 
     try
     {
-      jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
-              jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
-              { "png" }, new String[]
-              { "Portable network graphics" }, "Portable network graphics");
+      JalviewFileChooser chooser = new JalviewFileChooser(
+              ImageMaker.PNG_EXTENSION, ImageMaker.PNG_DESCRIPTION);
 
       chooser.setFileView(new jalview.io.JalviewFileView());
-      chooser.setDialogTitle("Create PNG image from tree");
-      chooser.setToolTipText("Save");
+      chooser.setDialogTitle(MessageManager
+              .getString("label.create_png_from_tree"));
+      chooser.setToolTipText(MessageManager.getString("action.save"));
 
       int value = chooser.showSaveDialog(this);
 
@@ -770,6 +784,7 @@ public class TreePanel extends GTreePanel
     tree.applyToNodes(new NodeTransformI()
     {
 
+      @Override
       public void transform(BinaryNode node)
       {
         if (node instanceof SequenceNode
@@ -782,8 +797,8 @@ public class TreePanel extends GTreePanel
           {
             // search dbrefs, features and annotation
             DBRefEntry[] refs = jalview.util.DBRefUtils.selectRefs(
-                    sq.getDBRef(), new String[]
-                    { labelClass.toUpperCase() });
+                    sq.getDBRefs(),
+                    new String[] { labelClass.toUpperCase() });
             if (refs != null)
             {
               for (int i = 0; i < refs.length; i++)
@@ -827,4 +842,68 @@ public class TreePanel extends GTreePanel
       }
     });
   }
+
+  /**
+   * Formats a localised title for the tree panel, like
+   * <p>
+   * Neighbour Joining Using BLOSUM62
+   * <p>
+   * For a tree loaded from file, just uses the file name
+   * 
+   * @param treeType
+   *          NJ or AV or FromFile
+   * @param modelOrFileName
+   * @return
+   */
+  public static String getPanelTitle(String treeType, String modelOrFileName)
+  {
+    if (NJTree.FROM_FILE.equals(treeType))
+    {
+      return modelOrFileName;
+    }
+
+    /*
+     * i18n description of Neighbour Joining or Average Distance method
+     */
+    String treecalcnm = MessageManager.getString("label.tree_calc_"
+            + treeType.toLowerCase());
+
+    /*
+     * i18n description (if any) of score model used
+     */
+    String smn = MessageManager.getStringOrReturn("label.score_model_",
+            modelOrFileName);
+
+    /*
+     * put them together as <method> Using <model>
+     */
+    final String ttl = MessageManager.formatMessage("label.treecalc_title",
+            treecalcnm, smn);
+    return ttl;
+  }
+
+  /**
+   * Gets the score model for the given name. If the score model is one that
+   * requires to get state data from the current view, allow it to do so
+   * 
+   * @param sm
+   * @return
+   */
+  protected ScoreModelI configureScoreModel(String modelName)
+  {
+    ScoreModelI sm = ScoreModels.getInstance().forName(modelName);
+    if (sm instanceof ViewBasedAnalysisI)
+    {
+      try
+      {
+        sm = sm.getClass().newInstance();
+        ((ViewBasedAnalysisI) sm).configureFromAlignmentView(treeCanvas.ap);
+      } catch (Exception q)
+      {
+        Cache.log.error("Couldn't create a scoremodel instance for "
+                + sm.getName());
+      }
+    }
+    return sm;
+  }
 }