Merge remote-tracking branch 'origin/develop' into features/JAL-2388hiddencolumnschanges
authorkiramt <k.mourao@dundee.ac.uk>
Fri, 5 May 2017 09:50:22 +0000 (10:50 +0100)
committerkiramt <k.mourao@dundee.ac.uk>
Fri, 5 May 2017 09:50:22 +0000 (10:50 +0100)
features/JAL-2388hiddencolumnschanges

Conflicts:
src/jalview/appletgui/TreePanel.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/TreePanel.java

17 files changed:
1  2 
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/PCAPanel.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/TreePanel.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/AnnotationColumnChooser.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/PCAPanel.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/TreePanel.java
src/jalview/structure/StructureSelectionManager.java

@@@ -22,6 -22,9 +22,9 @@@ package jalview.appletgui
  
  import jalview.analysis.AlignmentSorter;
  import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
+ import jalview.analysis.TreeBuilder;
+ import jalview.analysis.scoremodels.PIDModel;
+ import jalview.analysis.scoremodels.ScoreModels;
  import jalview.api.AlignViewControllerGuiI;
  import jalview.api.AlignViewControllerI;
  import jalview.api.AlignViewportI;
@@@ -43,7 -46,6 +46,7 @@@ import jalview.datamodel.AlignmentAnnot
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.AlignmentOrder;
  import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.Sequence;
  import jalview.datamodel.SequenceGroup;
@@@ -170,14 -172,14 +173,14 @@@ public class AlignFrame extends Embmenu
    }
  
    public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
 -          ColumnSelection columnSelection, JalviewLite applet,
 +          HiddenColumns hidden, JalviewLite applet,
            String title, boolean embedded)
    {
 -    this(al, hiddenSeqs, columnSelection, applet, title, embedded, true);
 +    this(al, hiddenSeqs, hidden, applet, title, embedded, true);
    }
  
    public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
 -          ColumnSelection columnSelection, JalviewLite applet,
 +          HiddenColumns hidden, JalviewLite applet,
            String title, boolean embedded, boolean addToDisplay)
    {
      if (applet != null)
      {
        viewport.hideSequence(hiddenSeqs);
      }
 -    if (columnSelection != null)
 +    if (hidden != null)
      {
 -      viewport.setColumnSelection(columnSelection);
 +      viewport.getAlignment().setHiddenColumns(hidden);
      }
      viewport.setScaleAboveWrapped(scaleAbove.getState());
  
      {
        copiedHiddenColumns = new Vector();
        int hiddenOffset = viewport.getSelectionGroup().getStartRes();
 -      for (int[] region : viewport.getColumnSelection().getHiddenColumns())
 +      for (int[] region : viewport.getAlignment().getHiddenColumns()
 +              .getListOfCols())
        {
          copiedHiddenColumns.addElement(new int[] {
              region[0] - hiddenOffset, region[1] - hiddenOffset });
    {
      SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
      AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
-             .getAlignment().getSequenceAt(0), null);
+             .getAlignment().getSequenceAt(0));
  
      addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
              viewport.getAlignment()));
  
    public void averageDistanceTreeMenuItem_actionPerformed()
    {
-     NewTreePanel("AV", "PID", "Average distance tree using PID");
+     newTreePanel(TreeBuilder.AVERAGE_DISTANCE, new PIDModel().getName(),
+             "Average distance tree using PID");
    }
  
    public void neighbourTreeMenuItem_actionPerformed()
    {
-     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
+     newTreePanel(TreeBuilder.NEIGHBOUR_JOINING, new PIDModel().getName(),
+             "Neighbour joining tree using PID");
    }
  
    protected void njTreeBlosumMenuItem_actionPerformed()
    {
-     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
+     newTreePanel(TreeBuilder.NEIGHBOUR_JOINING, ScoreModels.getInstance()
+             .getBlosum62().getName(),
+             "Neighbour joining tree using BLOSUM62");
    }
  
    protected void avTreeBlosumMenuItem_actionPerformed()
    {
-     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
+     newTreePanel(TreeBuilder.AVERAGE_DISTANCE, ScoreModels.getInstance()
+             .getBlosum62().getName(),
+             "Average distance tree using BLOSUM62");
    }
  
-   void NewTreePanel(String type, String pwType, String title)
+   void newTreePanel(String type, String pwType, String title)
    {
      // are the sequences aligned?
      if (!viewport.getAlignment().isAligned(false))
     * @param csel
     *          - columns to be selected on the alignment
     */
 -  public void select(SequenceGroup sel, ColumnSelection csel)
 +  public void select(SequenceGroup sel, ColumnSelection csel,
 +          HiddenColumns hidden)
    {
 -    alignPanel.seqPanel.selection(sel, csel, null);
 +    alignPanel.seqPanel.selection(sel, csel, hidden, null);
    }
  
    public void scrollTo(int row, int column)
   */
  package jalview.appletgui;
  
- import jalview.analysis.NJTree;
+ import jalview.analysis.TreeModel;
  import jalview.api.AlignViewportI;
  import jalview.api.FeatureSettingsModelI;
  import jalview.bin.JalviewLite;
  import jalview.commands.CommandI;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SearchResults;
  import jalview.datamodel.SearchResultsI;
  import jalview.datamodel.Sequence;
@@@ -53,7 -52,7 +53,7 @@@ public class AlignViewport extends Alig
  
    boolean validCharWidth = true;
  
-   NJTree currentTree = null;
+   TreeModel currentTree = null;
  
    public jalview.bin.JalviewLite applet;
  
      ranges.setEndSeq(height / getCharHeight());
    }
  
-   public void setCurrentTree(NJTree tree)
+   public void setCurrentTree(TreeModel tree)
    {
      currentTree = tree;
    }
  
-   public NJTree getCurrentTree()
+   public TreeModel getCurrentTree()
    {
      return currentTree;
    }
    {
      getStructureSelectionManager().sendSelection(
              new SequenceGroup(getSelectionGroup()),
 -            new ColumnSelection(getColumnSelection()), this);
 +            new ColumnSelection(getColumnSelection()),
 +            new HiddenColumns(getAlignment().getHiddenColumns()), this);
    }
  
    /**
@@@ -21,7 -21,7 +21,7 @@@
  package jalview.appletgui;
  
  import jalview.datamodel.AlignmentAnnotation;
 -import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.schemes.AnnotationColourGradient;
  import jalview.util.MessageManager;
  import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
@@@ -110,7 -110,7 +110,7 @@@ public class AnnotationColumnChooser ex
  
    private int actionOption = ACTION_OPTION_SELECT;
  
 -  private ColumnSelection oldColumnSelection;
 +  private HiddenColumns oldHiddenColumns;
  
    public AnnotationColumnChooser()
    {
      {
        return;
      }
 -    setOldColumnSelection(av.getColumnSelection());
 +    setOldHiddenColumns(av.getAlignment().getHiddenColumns());
      adjusting = true;
      Vector<String> list = new Vector<String>();
      int index = 1;
    @SuppressWarnings("unchecked")
    public void reset()
    {
 -    if (this.getOldColumnSelection() != null)
 +    if (this.getOldHiddenColumns() != null)
      {
        av.getColumnSelection().clear();
  
        if (av.getAnnotationColumnSelectionState() != null)
        {
 -        ColumnSelection oldSelection = av
 +        HiddenColumns oldHidden = av
                  .getAnnotationColumnSelectionState()
 -                .getOldColumnSelection();
 -        if (oldSelection != null && oldSelection.getHiddenColumns() != null
 -                && !oldSelection.getHiddenColumns().isEmpty())
 +                .getOldHiddenColumns();
 +        if (oldHidden != null && oldHidden.getListOfCols() != null
 +                && !oldHidden.getListOfCols().isEmpty())
          {
 -          for (Iterator<int[]> itr = oldSelection.getHiddenColumns()
 +          for (Iterator<int[]> itr = oldHidden.getListOfCols()
                    .iterator(); itr.hasNext();)
            {
              int positions[] = itr.next();
              av.hideColumns(positions[0], positions[1]);
            }
          }
 -        av.setColumnSelection(oldSelection);
 +        av.getAlignment().setHiddenColumns(oldHidden);
        }
        ap.paintAlignment(true);
      }
        // build filter params
        filterParams
                .setThresholdType(AnnotationFilterParameter.ThresholdType.NO_THRESHOLD);
-       if (getCurrentAnnotation().graph != AlignmentAnnotation.NO_GRAPH)
+       if (getCurrentAnnotation().isQuantitative())
        {
          filterParams
                  .setThresholdValue(getCurrentAnnotation().threshold.value);
      ap.paintAlignment(true);
    }
  
 -  public ColumnSelection getOldColumnSelection()
 +  public HiddenColumns getOldHiddenColumns()
    {
 -    return oldColumnSelection;
 +    return oldHiddenColumns;
    }
  
 -  public void setOldColumnSelection(ColumnSelection currentColumnSelection)
 +  public void setOldHiddenColumns(HiddenColumns currentHiddenColumns)
    {
 -    if (currentColumnSelection != null)
 +    if (currentHiddenColumns != null)
      {
 -      this.oldColumnSelection = new ColumnSelection(currentColumnSelection);
 +      this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns);
      }
    }
  
    {
      String currentView = AnnotationColumnChooser.NO_GRAPH_VIEW;
      if (av.getAlignment().getAlignmentAnnotation()[getAnnotations()
-             .getSelectedIndex()].graph != AlignmentAnnotation.NO_GRAPH)
+             .getSelectedIndex()].isQuantitative())
      {
        currentView = AnnotationColumnChooser.GRAPH_VIEW;
      }
   */
  package jalview.appletgui;
  
+ import jalview.analysis.scoremodels.ScoreModels;
+ import jalview.analysis.scoremodels.SimilarityParams;
+ import jalview.api.analysis.ScoreModelI;
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentView;
 -import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SeqCigar;
  import jalview.datamodel.SequenceI;
  import jalview.util.MessageManager;
@@@ -56,7 -59,7 +59,7 @@@ public class PCAPanel extends EmbmenuFr
  
    int top = 0;
  
-   public PCAPanel(AlignViewport av)
+   public PCAPanel(AlignViewport viewport)
    {
      try
      {
        zCombobox.addItem("dim " + i);
      }
  
-     this.av = av;
-     boolean selected = av.getSelectionGroup() != null
-             && av.getSelectionGroup().getSize() > 0;
-     AlignmentView seqstrings = av.getAlignmentView(selected);
-     boolean nucleotide = av.getAlignment().isNucleotide();
+     this.av = viewport;
+     boolean selected = viewport.getSelectionGroup() != null
+             && viewport.getSelectionGroup().getSize() > 0;
+     AlignmentView seqstrings = viewport.getAlignmentView(selected);
+     boolean nucleotide = viewport.getAlignment().isNucleotide();
      SequenceI[] seqs;
      if (!selected)
      {
-       seqs = av.getAlignment().getSequencesArray();
+       seqs = viewport.getAlignment().getSequencesArray();
      }
      else
      {
-       seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
+       seqs = viewport.getSelectionGroup().getSequencesInOrder(viewport.getAlignment());
      }
      SeqCigar sq[] = seqstrings.getSequences();
      int length = sq[0].getWidth();
          return;
        }
      }
-     pcaModel = new PCAModel(seqstrings, seqs, nucleotide);
  
-     rc = new RotatableCanvas(av);
+     ScoreModelI scoreModel = ScoreModels.getInstance().getDefaultModel(
+             !nucleotide);
+     pcaModel = new PCAModel(seqstrings, seqs, nucleotide, scoreModel,
+             SimilarityParams.SeqSpace);
+     rc = new RotatableCanvas(viewport);
      embedMenuIfNeeded(rc);
      add(rc, BorderLayout.CENTER);
  
        if (!pcaModel.isNucleotide())
        {
          pcaModel.setNucleotide(true);
+         ScoreModelI scoreModel = ScoreModels.getInstance().getDefaultModel(
+                 false);
+         pcaModel.setScoreModel(scoreModel);
          new Thread(this).start();
        }
      }
        if (pcaModel.isNucleotide())
        {
          pcaModel.setNucleotide(false);
+         ScoreModelI scoreModel = ScoreModels.getInstance().getDefaultModel(
+                 true);
+         pcaModel.setScoreModel(scoreModel);
          new Thread(this).start();
        }
      }
      }
      ;
      Object[] alAndColsel = pcaModel.getSeqtrings()
 -            .getAlignmentAndColumnSelection(gc);
 +            .getAlignmentAndHiddenColumns(gc);
  
      if (alAndColsel != null && alAndColsel[0] != null)
      {
        AlignFrame af = new AlignFrame(al, av.applet,
                "Original Data for PCA", false);
  
 -      af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
 +      af.viewport.getAlignment().setHiddenColumns(
 +              (HiddenColumns) alAndColsel[1]);
      }
    }
  
@@@ -25,7 -25,6 +25,7 @@@ import jalview.commands.EditCommand
  import jalview.commands.EditCommand.Action;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SearchResultMatchI;
  import jalview.datamodel.SearchResults;
  import jalview.datamodel.SearchResultsI;
@@@ -181,22 -180,19 +181,22 @@@ public class SeqPanel extends Panel imp
      seqCanvas.cursorX += dx;
      seqCanvas.cursorY += dy;
      if (av.hasHiddenColumns()
 -            && !av.getColumnSelection().isVisible(seqCanvas.cursorX))
 +            && !av.getAlignment().getHiddenColumns()
 +                    .isVisible(seqCanvas.cursorX))
      {
        int original = seqCanvas.cursorX - dx;
        int maxWidth = av.getAlignment().getWidth();
  
 -      while (!av.getColumnSelection().isVisible(seqCanvas.cursorX)
 +      while (!av.getAlignment().getHiddenColumns()
 +              .isVisible(seqCanvas.cursorX)
                && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
        {
          seqCanvas.cursorX += dx;
        }
  
        if (seqCanvas.cursorX >= maxWidth
 -              || !av.getColumnSelection().isVisible(seqCanvas.cursorX))
 +              || !av.getAlignment().getHiddenColumns()
 +                      .isVisible(seqCanvas.cursorX))
        {
          seqCanvas.cursorX = original;
        }
      else
      {
        ViewportRanges ranges = av.getRanges();
 +      HiddenColumns hidden = av.getAlignment().getHiddenColumns();
        while (seqCanvas.cursorY < ranges.getStartSeq())
        {
          ap.scrollUp(true);
        {
          ap.scrollUp(false);
        }
 -      while (seqCanvas.cursorX < av.getColumnSelection()
 -              .adjustForHiddenColumns(ranges.getStartRes()))
 +      while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(ranges
 +              .getStartRes()))
        {
  
          if (!ap.scrollRight(false))
            break;
          }
        }
 -      while (seqCanvas.cursorX > av.getColumnSelection()
 -              .adjustForHiddenColumns(ranges.getEndRes()))
 +      while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(ranges
 +              .getEndRes()))
        {
          if (!ap.scrollRight(true))
          {
        if (features != null && features.length > 0)
        {
          seqCanvas.getFeatureRenderer().amendFeatures(
-                 new SequenceI[] { sequence }, features, false, ap);
+                 new SequenceI[] { sequence }, features, false, ap, null);
  
          seqCanvas.highlightSearchResults(null);
        }
  
      if (av.hasHiddenColumns())
      {
 -      res = av.getColumnSelection().adjustForHiddenColumns(res);
 +      res = av.getAlignment().getHiddenColumns()
 +              .adjustForHiddenColumns(res);
      }
  
      return res;
      if (av.hasHiddenColumns())
      {
        fixedColumns = true;
 -      int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
 -      int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
 +      int y1 = av.getAlignment().getHiddenColumns()
 +              .getHiddenBoundaryLeft(startres);
 +      int y2 = av.getAlignment().getHiddenColumns()
 +              .getHiddenBoundaryRight(startres);
  
        if ((insertGap && startres > y1 && lastres < y1)
                || (!insertGap && startres < y2 && lastres > y2))
          {
            if (sg.getSize() == av.getAlignment().getHeight())
            {
 -            if ((av.hasHiddenColumns() && startres < av
 -                    .getColumnSelection().getHiddenBoundaryRight(startres)))
 +            if ((av.hasHiddenColumns() && startres < av.getAlignment()
 +                    .getHiddenColumns().getHiddenBoundaryRight(startres)))
              {
                endEditing();
                return;
     */
    @Override
    public void selection(SequenceGroup seqsel, ColumnSelection colsel,
 -          SelectionSource source)
 +          HiddenColumns hidden, SelectionSource source)
    {
      // TODO: fix this hack - source of messages is align viewport, but SeqPanel
      // handles selection messages...
       * Check for selection in a view of which this one is a dna/protein
       * complement.
       */
 -    if (selectionFromTranslation(seqsel, colsel, source))
 +    if (selectionFromTranslation(seqsel, colsel, hidden, source))
      {
        return;
      }
          }
          else
          {
 -          av.getColumnSelection().setElementsFrom(colsel);
 +          av.getColumnSelection().setElementsFrom(colsel,
 +                  av.getAlignment().getHiddenColumns());
          }
        }
        repaint |= av.isColSelChanged(true);
      }
      if (copycolsel
              && av.hasHiddenColumns()
 -            && (av.getColumnSelection() == null || av.getColumnSelection()
 -                    .getHiddenColumns() == null))
 +            && (av.getColumnSelection() == null || av.getAlignment()
 +                    .getHiddenColumns().getListOfCols() == null))
      {
        System.err.println("Bad things");
      }
     * @param source
     */
    protected boolean selectionFromTranslation(SequenceGroup seqsel,
 -          ColumnSelection colsel, SelectionSource source)
 +          ColumnSelection colsel, HiddenColumns hidden,
 +          SelectionSource source)
    {
      if (!(source instanceof AlignViewportI))
      {
      /*
       * Map column selection
       */
 -    ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
 -            av);
 +    // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
 +    // av);
 +    ColumnSelection cs = new ColumnSelection();
 +    HiddenColumns hs = new HiddenColumns();
 +    MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs);
      av.setColumnSelection(cs);
 +    av.getAlignment().setHiddenColumns(hs);
  
      ap.scalePanelHolder.repaint();
      ap.repaint();
   */
  package jalview.appletgui;
  
+ import jalview.analysis.AverageDistanceTree;
  import jalview.analysis.NJTree;
+ import jalview.analysis.TreeBuilder;
+ import jalview.analysis.TreeModel;
+ import jalview.analysis.scoremodels.ScoreModels;
+ import jalview.analysis.scoremodels.SimilarityParams;
  import jalview.api.analysis.ScoreModelI;
- import jalview.api.analysis.ViewBasedAnalysisI;
  import jalview.datamodel.Alignment;
- import jalview.datamodel.AlignmentView;
 -import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SequenceI;
  import jalview.io.NewickFile;
- import jalview.schemes.ResidueProperties;
  import jalview.util.MessageManager;
  
  import java.awt.BorderLayout;
@@@ -58,13 -60,13 +60,13 @@@ public class TreePanel extends EmbmenuF
  
    TreeCanvas treeCanvas;
  
-   NJTree tree;
+   TreeModel tree;
  
    AlignmentPanel ap;
  
    AlignViewport av;
  
-   public NJTree getTree()
+   public TreeModel getTree()
    {
      return tree;
    }
  
    /**
     * Creates a new TreePanel object.
-    * 
-    * @param av
-    *          DOCUMENT ME!
-    * @param seqVector
-    *          DOCUMENT ME!
-    * @param type
-    *          DOCUMENT ME!
-    * @param pwtype
-    *          DOCUMENT ME!
-    * @param s
-    *          DOCUMENT ME!
-    * @param e
-    *          DOCUMENT ME!
     */
-   public TreePanel(AlignmentPanel ap, String type, String pwtype)
+   public TreePanel(AlignmentPanel alignPanel, String type, String pwtype)
    {
      try
      {
        ex.printStackTrace();
      }
  
-     initTreePanel(ap, type, pwtype, null);
+     initTreePanel(alignPanel, type, pwtype, null);
    }
  
    /**
     * 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)
      // yields unaligned seqs)
      // or create a selection box around columns in alignment view
      // test Alignment(SeqCigar[])
-     if (tree.seqData != null)
+     if (tree.getOriginalData() != null)
      {
        char gc = '-';
        try
        } catch (Exception ex)
        {
        }
-       ;
-       Object[] alAndColsel = tree.seqData
+       Object[] alAndColsel = tree.getOriginalData()
 -              .getAlignmentAndColumnSelection(gc);
 +              .getAlignmentAndHiddenColumns(gc);
  
        if (alAndColsel != null && alAndColsel[0] != null)
        {
          AlignFrame af = new AlignFrame(al, av.applet,
                  "Original Data for Tree", false);
  
 -        af.viewport.setHiddenColumns((ColumnSelection) alAndColsel[1]);
 +        af.viewport.getAlignment().setHiddenColumns(
 +                (HiddenColumns) alAndColsel[1]);
        }
      }
      else
      {
        if (newtree != null)
        {
-         if (odata == null)
-         {
-           tree = new NJTree(av.getAlignment().getSequencesArray(), newtree);
-         }
-         else
-         {
-           tree = new NJTree(av.getAlignment().getSequencesArray(), odata,
-                   newtree);
-         }
+         tree = new TreeModel(av.getAlignment().getSequencesArray(), odata,
+                 newtree);
        }
        else
        {
-         int start, end;
-         SequenceI[] seqs;
-         boolean selview = av.getSelectionGroup() != null
-                 && av.getSelectionGroup().getSize() > 1;
-         AlignmentView seqStrings = av.getAlignmentView(selview);
-         if (!selview)
-         {
-           start = 0;
-           end = av.getAlignment().getWidth();
-           seqs = av.getAlignment().getSequencesArray();
-         }
-         else
-         {
-           start = av.getSelectionGroup().getStartRes();
-           end = av.getSelectionGroup().getEndRes() + 1;
-           seqs = av.getSelectionGroup().getSequencesInOrder(
-                   av.getAlignment());
-         }
-         ScoreModelI sm = ResidueProperties.getScoreModel(pwtype);
-         if (sm instanceof ViewBasedAnalysisI)
-         {
-           try
-           {
-             sm = sm.getClass().newInstance();
-             ((ViewBasedAnalysisI) sm)
-                     .configureFromAlignmentView(treeCanvas.ap);
-           } catch (Exception q)
-           {
-             System.err.println("Couldn't create a scoremodel instance for "
-                     + sm.getName());
-             q.printStackTrace();
-           }
-           tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
-         }
-         else
-         {
-           tree = new NJTree(seqs, seqStrings, type, pwtype, null, start,
-                   end);
-         }
+         ScoreModelI sm1 = ScoreModels.getInstance().getScoreModel(pwtype,
+                 treeCanvas.ap);
+         ScoreModelI sm = sm1;
+         TreeBuilder njtree = type.equals(TreeBuilder.NEIGHBOUR_JOINING) ? new NJTree(
+                 av, sm, SimilarityParams.Jalview)
+                 : new AverageDistanceTree(av, sm, SimilarityParams.Jalview);
+         tree = new TreeModel(njtree);
        }
  
        tree.reCount(tree.getTopNode());
   */
  package jalview.datamodel;
  
 +import jalview.analysis.Rna;
 +import jalview.analysis.SecStrConsensus.SimpleBP;
 +import jalview.analysis.WUSSParseException;
 +
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashMap;
@@@ -32,6 -28,10 +32,6 @@@ import java.util.List
  import java.util.Map;
  import java.util.Map.Entry;
  
 -import jalview.analysis.Rna;
 -import jalview.analysis.SecStrConsensus.SimpleBP;
 -import jalview.analysis.WUSSParseException;
 -
  /**
   * DOCUMENT ME!
   * 
@@@ -1150,14 -1150,14 +1150,14 @@@ public class AlignmentAnnotatio
     * @param colSel
     */
    public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation,
 -          ColumnSelection colSel)
 +          HiddenColumns hidden)
    {
      this(alignmentAnnotation);
      if (annotations == null)
      {
        return;
      }
 -    colSel.makeVisibleAnnotation(this);
 +    hidden.makeVisibleAnnotation(this);
    }
  
    public void setPadGaps(boolean padgaps, char gapchar)
    {
      return counter++;
    }
+   /**
+    * 
+    * @return true for rows that have a range of values in their annotation set
+    */
+   public boolean isQuantitative()
+   {
+     return graphMin < graphMax;
+   }
  }
@@@ -34,7 -34,7 +34,7 @@@ import jalview.api.AlignmentViewPanel
  import jalview.api.FeatureSettingsControllerI;
  import jalview.api.SplitContainerI;
  import jalview.api.ViewStyleI;
- import jalview.api.analysis.ScoreModelI;
+ import jalview.api.analysis.SimilarityParamsI;
  import jalview.bin.Cache;
  import jalview.bin.Jalview;
  import jalview.commands.CommandI;
@@@ -53,7 -53,6 +53,7 @@@ import jalview.datamodel.AlignmentI
  import jalview.datamodel.AlignmentOrder;
  import jalview.datamodel.AlignmentView;
  import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.HiddenSequences;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SeqCigar;
@@@ -70,6 -69,7 +70,7 @@@ import jalview.io.FileFormat
  import jalview.io.FileFormatI;
  import jalview.io.FileFormats;
  import jalview.io.FileLoader;
+ import jalview.io.FileParse;
  import jalview.io.FormatAdapter;
  import jalview.io.HtmlSvgOutput;
  import jalview.io.IdentifyFile;
@@@ -78,12 -78,12 +79,12 @@@ import jalview.io.JalviewFileChooser
  import jalview.io.JalviewFileView;
  import jalview.io.JnetAnnotationMaker;
  import jalview.io.NewickFile;
+ import jalview.io.ScoreMatrixFile;
  import jalview.io.TCoffeeScoreFile;
  import jalview.jbgui.GAlignFrame;
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemes;
  import jalview.schemes.ResidueColourScheme;
- import jalview.schemes.ResidueProperties;
  import jalview.schemes.TCoffeeColourScheme;
  import jalview.util.MessageManager;
  import jalview.viewmodel.AlignmentViewport;
@@@ -233,7 -233,7 +234,7 @@@ public class AlignFrame extends GAlignF
     * @param height
     *          height of frame.
     */
 -  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
 +  public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
            int width, int height)
    {
      this(al, hiddenColumns, width, height, null);
     * @param sequenceSetId
     *          (may be null)
     */
 -  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
 +  public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
            int width, int height, String sequenceSetId)
    {
      this(al, hiddenColumns, width, height, sequenceSetId, null);
     * @param viewId
     *          (may be null)
     */
 -  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
 +  public AlignFrame(AlignmentI al, HiddenColumns hiddenColumns,
            int width, int height, String sequenceSetId, String viewId)
    {
      setSize(width, height);
    }
  
    public AlignFrame(AlignmentI al, SequenceI[] hiddenSeqs,
 -          ColumnSelection hiddenColumns, int width, int height)
 +          HiddenColumns hiddenColumns, int width, int height)
    {
      setSize(width, height);
  
  
      setMenusFromViewport(viewport);
      buildSortByAnnotationScoresMenu();
-     buildTreeMenu();
+     calculateTree.addActionListener(new ActionListener()
+     {
+       @Override
+       public void actionPerformed(ActionEvent e)
+       {
+         openTreePcaDialog();
+       }
+     });
      buildColourMenu();
  
      if (Desktop.desktop != null)
                exportData.getAlignment(), // class cast exceptions will
                // occur in the distant future
                exportData.getOmitHidden(), exportData.getStartEndPostions(),
 -              f.getCacheSuffixDefault(format),
 -              viewport.getColumnSelection());
 +              f.getCacheSuffixDefault(format), viewport.getAlignment()
 +                      .getHiddenColumns());
  
        if (output == null)
        {
        cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
                .formatSequences(format, exportData.getAlignment(),
                        exportData.getOmitHidden(),
 -                      exportData.getStartEndPostions(),
 -                      viewport.getColumnSelection()));
 + exportData
 +                              .getStartEndPostions(), viewport
 +                              .getAlignment().getHiddenColumns()));
        Desktop.addInternalFrame(cap, MessageManager.formatMessage(
                "label.alignment_output_command",
                new Object[] { e.getActionCommand() }), 600, 500);
        alignmentToExport = viewport.getAlignment();
      }
      alignmentStartEnd = alignmentToExport
 -            .getVisibleStartAndEndIndex(viewport.getColumnSelection()
 -                    .getHiddenColumns());
 +            .getVisibleStartAndEndIndex(viewport.getAlignment()
 +                    .getHiddenColumns()
 +                    .getListOfCols());
      AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
              omitHidden, alignmentStartEnd, settings);
      return ed;
        hiddenColumns = new ArrayList<int[]>();
        int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport
                .getSelectionGroup().getEndRes();
 -      for (int[] region : viewport.getColumnSelection().getHiddenColumns())
 +      for (int[] region : viewport.getAlignment().getHiddenColumns()
 +              .getListOfCols())
        {
          if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
          {
    {
      SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
      AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
-             .getAlignment().getSequenceAt(0), null);
+             .getAlignment().getSequenceAt(0));
      addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
              viewport.getAlignment()));
      alignPanel.paintAlignment(true);
      }
    }
  
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   @Override
-   public void PCAMenuItem_actionPerformed(ActionEvent e)
-   {
-     if (((viewport.getSelectionGroup() != null)
-             && (viewport.getSelectionGroup().getSize() < 4) && (viewport
-             .getSelectionGroup().getSize() > 0))
-             || (viewport.getAlignment().getHeight() < 4))
-     {
-       JvOptionPane
-               .showInternalMessageDialog(
-                       this,
-                       MessageManager
-                               .getString("label.principal_component_analysis_must_take_least_four_input_sequences"),
-                       MessageManager
-                               .getString("label.sequence_selection_insufficient"),
-                       JvOptionPane.WARNING_MESSAGE);
-       return;
-     }
-     new PCAPanel(alignPanel);
-   }
    @Override
    public void autoCalculate_actionPerformed(ActionEvent e)
    {
    }
  
    /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   @Override
-   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
-   {
-     newTreePanel("AV", "PID", "Average distance tree using PID");
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   @Override
-   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
-   {
-     newTreePanel("NJ", "PID", "Neighbour joining tree using PID");
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   @Override
-   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
-   {
-     newTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   @Override
-   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
-   {
-     newTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
-   }
-   /**
-    * DOCUMENT ME!
+    * Constructs a tree panel and adds it to the desktop
     * 
     * @param type
-    *          DOCUMENT ME!
-    * @param pwType
-    *          DOCUMENT ME!
-    * @param title
-    *          DOCUMENT ME!
+    *          tree type (NJ or AV)
+    * @param modelName
+    *          name of score model used to compute the tree
+    * @param options
+    *          parameters for the distance or similarity calculation
     */
-   void newTreePanel(String type, String pwType, String title)
+   void newTreePanel(String type, String modelName, SimilarityParamsI options)
    {
+     String frameTitle = "";
      TreePanel tp;
  
+     boolean onSelection = false;
      if (viewport.getSelectionGroup() != null
              && viewport.getSelectionGroup().getSize() > 0)
      {
            return;
          }
        }
-       title = title + " on region";
-       tp = new TreePanel(alignPanel, type, pwType);
+       onSelection = true;
      }
      else
      {
-       // are the visible sequences aligned?
-       if (!viewport.getAlignment().isAligned(false))
-       {
-         JvOptionPane
-                 .showMessageDialog(
-                         Desktop.desktop,
-                         MessageManager
-                                 .getString("label.sequences_must_be_aligned_before_creating_tree"),
-                         MessageManager
-                                 .getString("label.sequences_not_aligned"),
-                         JvOptionPane.WARNING_MESSAGE);
-         return;
-       }
        if (viewport.getAlignment().getHeight() < 2)
        {
          return;
        }
-       tp = new TreePanel(alignPanel, type, pwType);
      }
  
-     title += " from ";
+     tp = new TreePanel(alignPanel, type, modelName, options);
+     frameTitle = tp.getPanelTitle() + (onSelection ? " on region" : "");
+     frameTitle += " from ";
  
      if (viewport.viewName != null)
      {
-       title += viewport.viewName + " of ";
+       frameTitle += viewport.viewName + " of ";
      }
  
-     title += this.title;
+     frameTitle += this.title;
  
-     Desktop.addInternalFrame(tp, title, 600, 500);
+     Desktop.addInternalFrame(tp, frameTitle, 600, 500);
    }
  
    /**
     * call. Listeners are added to remove the menu item when the treePanel is
     * closed, and adjust the tree leaf to sequence mapping when the alignment is
     * modified.
-    * 
-    * @param treePanel
-    *          Displayed tree window.
-    * @param title
-    *          SortBy menu item title.
     */
    @Override
-   public void buildTreeMenu()
+   public void buildTreeSortMenu()
    {
-     calculateTree.removeAll();
-     // build the calculate menu
-     for (final String type : new String[] { "NJ", "AV" })
-     {
-       String treecalcnm = MessageManager.getString("label.tree_calc_"
-               + type.toLowerCase());
-       for (final String pwtype : ResidueProperties.scoreMatrices.keySet())
-       {
-         JMenuItem tm = new JMenuItem();
-         ScoreModelI sm = ResidueProperties.scoreMatrices.get(pwtype);
-         if (sm.isDNA() == viewport.getAlignment().isNucleotide()
-                 || sm.isProtein() == !viewport.getAlignment()
-                         .isNucleotide())
-         {
-           String smn = MessageManager.getStringOrReturn(
-                   "label.score_model_", sm.getName());
-           final String title = MessageManager.formatMessage(
-                   "label.treecalc_title", treecalcnm, smn);
-           tm.setText(title);//
-           tm.addActionListener(new java.awt.event.ActionListener()
-           {
-             @Override
-             public void actionPerformed(ActionEvent e)
-             {
-               newTreePanel(type, pwtype, title);
-             }
-           });
-           calculateTree.add(tm);
-         }
-       }
-     }
      sortByTreeMenu.removeAll();
  
      List<Component> comps = PaintRefresher.components.get(viewport
  
      if (value == JalviewFileChooser.APPROVE_OPTION)
      {
-       String choice = chooser.getSelectedFile().getPath();
-       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
-       jalview.io.NewickFile fin = null;
+       String filePath = chooser.getSelectedFile().getPath();
+       Cache.setProperty("LAST_DIRECTORY", filePath);
+       NewickFile fin = null;
        try
        {
-         fin = new NewickFile(choice, DataSourceType.FILE);
-         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
+         fin = new NewickFile(filePath, DataSourceType.FILE);
+         viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
        } catch (Exception ex)
        {
          JvOptionPane
      }
    }
  
-   public TreePanel ShowNewickTree(NewickFile nf, String title)
-   {
-     return ShowNewickTree(nf, title, 600, 500, 4, 5);
-   }
-   public TreePanel ShowNewickTree(NewickFile nf, String title,
-           AlignmentView input)
+   public TreePanel showNewickTree(NewickFile nf, String treeTitle)
    {
-     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
+     return showNewickTree(nf, treeTitle, 600, 500, 4, 5);
    }
  
-   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
+   public TreePanel showNewickTree(NewickFile nf, String treeTitle, int w,
            int h, int x, int y)
    {
-     return ShowNewickTree(nf, title, null, w, h, x, y);
+     return showNewickTree(nf, treeTitle, null, w, h, x, y);
    }
  
    /**
-    * Add a treeviewer for the tree extracted from a newick file object to the
+    * Add a treeviewer for the tree extracted from a Newick file object to the
     * current alignment view
     * 
     * @param nf
     *          position
     * @return TreePanel handle
     */
-   public TreePanel ShowNewickTree(NewickFile nf, String title,
+   public TreePanel showNewickTree(NewickFile nf, String treeTitle,
            AlignmentView input, int w, int h, int x, int y)
    {
      TreePanel tp = null;
  
        if (nf.getTree() != null)
        {
-         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
+         tp = new TreePanel(alignPanel, nf, treeTitle, input);
  
          tp.setSize(w, h);
  
            tp.setLocation(x, y);
          }
  
-         Desktop.addInternalFrame(tp, title, w, h);
+         Desktop.addInternalFrame(tp, treeTitle, w, h);
        }
      } catch (Exception ex)
      {
    }
  
    /**
-    * Attempt to load a "dropped" file or URL string: First by testing whether
-    * it's an Annotation file, then a JNet file, and finally a features file. If
-    * all are false then the user may have dropped an alignment file onto this
-    * AlignFrame.
+    * Attempt to load a "dropped" file or URL string, by testing in turn for
+    * <ul>
+    * <li>an Annotation file</li>
+    * <li>a JNet file</li>
+    * <li>a features file</li>
+    * <li>else try to interpret as an alignment file</li>
+    * </ul>
     * 
     * @param file
     *          either a filename or a URL string.
            {
              format = new IdentifyFile().identify(file, sourceType);
            }
-           if (FileFormat.Jnet.equals(format))
+           if (FileFormat.ScoreMatrix == format)
+           {
+             ScoreMatrixFile sm = new ScoreMatrixFile(new FileParse(file,
+                     sourceType));
+             sm.parse();
+             // todo: i18n this message
+             statusBar
+                     .setText(MessageManager.formatMessage(
+                             "label.successfully_loaded_matrix",
+                             sm.getMatrixName()));
+           }
+           else if (FileFormat.Jnet.equals(format))
            {
              JPredFile predictions = new JPredFile(file, sourceType);
              new JnetAnnotationMaker();
                      viewport.getAlignment(), 0, false);
              SequenceI repseq = viewport.getAlignment().getSequenceAt(0);
              viewport.getAlignment().setSeqrep(repseq);
 -            ColumnSelection cs = new ColumnSelection();
 +            HiddenColumns cs = new HiddenColumns();
              cs.hideInsertionsFor(repseq);
 -            viewport.setColumnSelection(cs);
 +            viewport.getAlignment().setHiddenColumns(cs);
              isAnnotation = true;
            }
            // else if (IdentifyFile.FeaturesFile.equals(format))
      ColourSchemeI colourScheme = viewport.getGlobalColourScheme();
      ColourMenuHelper.setColourSelected(colourMenu, colourScheme);
    }
+   /**
+    * Open a dialog (if not already open) that allows the user to select and
+    * calculate PCA or Tree analysis
+    */
+   protected void openTreePcaDialog()
+   {
+     if (alignPanel.getCalculationDialog() == null)
+     {
+       new CalculationChooser(AlignFrame.this);
+     }
+   }
  }
  
  class PrintThread extends Thread
@@@ -22,7 -22,7 +22,7 @@@ package jalview.gui
  
  import jalview.analysis.AlignmentUtils;
  import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
- import jalview.analysis.NJTree;
+ import jalview.analysis.TreeModel;
  import jalview.api.AlignViewportI;
  import jalview.api.AlignmentViewPanel;
  import jalview.api.FeatureColourI;
@@@ -35,7 -35,6 +35,7 @@@ import jalview.datamodel.AlignedCodonFr
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SearchResults;
  import jalview.datamodel.SearchResultsI;
@@@ -77,7 -76,7 +77,7 @@@ public class AlignViewport extends Alig
  {
    Font font;
  
-   NJTree currentTree = null;
+   TreeModel currentTree = null;
  
    boolean cursorMode = false;
  
     * @param hiddenColumns
     *          ColumnSelection
     */
 -  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns)
 +  public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns)
    {
      setAlignment(al);
      if (hiddenColumns != null)
      {
 -      colSel = hiddenColumns;
 +      al.setHiddenColumns(hiddenColumns);
      }
      init();
    }
     * @param seqsetid
     *          (may be null)
     */
 -  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
 +  public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
            String seqsetid)
    {
      this(al, hiddenColumns, seqsetid, null);
     * @param viewid
     *          (may be null)
     */
 -  public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
 +  public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
            String seqsetid, String viewid)
    {
      sequenceSetID = seqsetid;
      setAlignment(al);
      if (hiddenColumns != null)
      {
 -      colSel = hiddenColumns;
 +      al.setHiddenColumns(hiddenColumns);
      }
      init();
    }
     * @param tree
     *          DOCUMENT ME!
     */
-   public void setCurrentTree(NJTree tree)
+   public void setCurrentTree(TreeModel tree)
    {
      currentTree = tree;
    }
     * 
     * @return DOCUMENT ME!
     */
-   public NJTree getCurrentTree()
+   public TreeModel getCurrentTree()
    {
      return currentTree;
    }
      {
        end = alignment.getWidth();
      }
 -    viscontigs = colSel.getVisibleContigs(start, end);
 +    viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end);
      return viscontigs;
    }
  
      jalview.structure.StructureSelectionManager
              .getStructureSelectionManager(Desktop.instance).sendSelection(
                      new SequenceGroup(getSelectionGroup()),
 -                    new ColumnSelection(getColumnSelection()), this);
 +                    new ColumnSelection(getColumnSelection()),
 +                    new HiddenColumns(getAlignment().getHiddenColumns()),
 +                    this);
    }
  
    /**
@@@ -25,7 -25,6 +25,7 @@@ import jalview.api.AlignViewportI
  import jalview.api.AlignmentViewPanel;
  import jalview.bin.Cache;
  import jalview.datamodel.AlignmentI;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SearchResultsI;
  import jalview.datamodel.SequenceFeature;
  import jalview.datamodel.SequenceGroup;
@@@ -107,6 -106,8 +107,8 @@@ public class AlignmentPanel extends GAl
  
    private PropertyChangeListener propertyChangeListener;
  
+   private CalculationChooser calculationDialog;
    /**
     * Creates a new AlignmentPanel object.
     * 
    {
      av.alignmentChanged(this);
  
+     if (getCalculationDialog() != null)
+     {
+       getCalculationDialog().validateCalcTypes();
+     }
      alignFrame.updateEditMenuBar();
  
      paintAlignment(true);
        }
        if (av.hasHiddenColumns())
        {
 -        start = av.getColumnSelection().findColumnPosition(start);
 -        end = av.getColumnSelection().findColumnPosition(end);
 +        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
 +        start = hidden.findColumnPosition(start);
 +        end = hidden.findColumnPosition(end);
          if (start == end)
          {
 -          if (!av.getColumnSelection().isVisible(r[0]))
 +          if (!hidden.isVisible(r[0]))
            {
              // don't scroll - position isn't visible
              return false;
      if (av.hasHiddenColumns())
      {
        // reset the width to exclude hidden columns
 -      width = av.getColumnSelection().findColumnPosition(width);
 +      width = av.getAlignment().getHiddenColumns()
 +              .findColumnPosition(width);
      }
  
      hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
  
        if (av.hasHiddenColumns())
        {
 -        maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
 +        maxwidth = av.getAlignment().getHiddenColumns()
 +                .findColumnPosition(maxwidth) - 1;
        }
  
        int canvasWidth = getSeqPanel().seqCanvas
      int maxwidth = av.getAlignment().getWidth();
      if (av.hasHiddenColumns())
      {
 -      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
 +      maxwidth = av.getAlignment().getHiddenColumns()
 +              .findColumnPosition(maxwidth) - 1;
      }
  
      int resWidth = getSeqPanel().seqCanvas.getWrappedCanvasWidth(pwidth
      int maxwidth = av.getAlignment().getWidth();
      if (av.hasHiddenColumns())
      {
 -      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth);
 +      maxwidth = av.getAlignment().getHiddenColumns()
 +              .findColumnPosition(maxwidth);
      }
  
      int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
      int maxwidth = av.getAlignment().getWidth();
      if (av.hasHiddenColumns())
      {
 -      maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
 +      maxwidth = av.getAlignment().getHiddenColumns()
 +              .findColumnPosition(maxwidth) - 1;
      }
  
      int height = ((maxwidth / chunkWidth) + 1) * cHeight;
      PaintRefresher.RemoveComponent(getIdPanel().getIdCanvas());
      PaintRefresher.RemoveComponent(this);
  
+     closeChildFrames();
      /*
       * try to ensure references are nulled
       */
    }
  
    /**
+    * Close any open dialogs that would be orphaned when this one is closed
+    */
+   protected void closeChildFrames()
+   {
+     if (calculationDialog != null)
+     {
+       calculationDialog.closeFrame();
+     }
+   }
+   /**
     * hides or shows dynamic annotation rows based on groups and av state flags
     */
    public void updateAnnotation()
        repaint();
      }
    }
+   /**
+    * Set the reference to the PCA/Tree chooser dialog for this panel. This
+    * reference should be nulled when the dialog is closed.
+    * 
+    * @param calculationChooser
+    */
+   public void setCalculationDialog(CalculationChooser calculationChooser)
+   {
+     calculationDialog = calculationChooser;
+   }
+   /**
+    * Returns the reference to the PCA/Tree chooser dialog for this panel (null
+    * if none is open)
+    */
+   public CalculationChooser getCalculationDialog()
+   {
+     return calculationDialog;
+   }
  }
@@@ -21,8 -21,7 +21,7 @@@
  
  package jalview.gui;
  
- import jalview.datamodel.AlignmentAnnotation;
 -import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.schemes.AnnotationColourGradient;
  import jalview.util.MessageManager;
  import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
@@@ -30,6 -29,7 +29,7 @@@
  import java.awt.BorderLayout;
  import java.awt.CardLayout;
  import java.awt.Color;
+ import java.awt.Dimension;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.ItemEvent;
@@@ -86,8 -86,12 +86,12 @@@ public class AnnotationColumnChooser ex
  
    private int actionOption = ACTION_OPTION_SELECT;
  
 -  private ColumnSelection oldColumnSelection;
 +  private HiddenColumns oldHiddenColumns;
  
+   protected int MIN_WIDTH = 420;
+   protected int MIN_HEIGHT = 430;
    public AnnotationColumnChooser(AlignViewport av, final AlignmentPanel ap)
    {
      super(av, ap);
      Desktop.addInternalFrame(frame,
              MessageManager.getString("label.select_by_annotation"), 520,
              215);
+     frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
  
      addSliderChangeListener();
      addSliderMouseListeners();
      {
        return;
      }
 -    setOldColumnSelection(av.getColumnSelection());
 +    setOldHiddenColumns(av.getAlignment().getHiddenColumns());
      adjusting = true;
  
      setAnnotations(new JComboBox<String>(getAnnotationItems(false)));
    @Override
    protected void reset()
    {
 -    if (this.getOldColumnSelection() != null)
 +    if (this.getOldHiddenColumns() != null)
      {
        av.getColumnSelection().clear();
  
        if (av.getAnnotationColumnSelectionState() != null)
        {
 -        ColumnSelection oldSelection = av
 +        HiddenColumns oldHidden = av
                  .getAnnotationColumnSelectionState()
 -                .getOldColumnSelection();
 -        if (oldSelection != null && oldSelection.getHiddenColumns() != null
 -                && !oldSelection.getHiddenColumns().isEmpty())
 +                .getOldHiddenColumns();
 +        if (oldHidden != null && oldHidden.getListOfCols() != null
 +                && !oldHidden.getListOfCols().isEmpty())
          {
 -          for (Iterator<int[]> itr = oldSelection.getHiddenColumns()
 +          for (Iterator<int[]> itr = oldHidden.getListOfCols()
                    .iterator(); itr.hasNext();)
            {
              int positions[] = itr.next();
              av.hideColumns(positions[0], positions[1]);
            }
          }
 -        av.setColumnSelection(oldSelection);
 +        av.getAlignment().setHiddenColumns(oldHidden);
        }
        ap.paintAlignment(true);
      }
        // build filter params
        filterParams
                .setThresholdType(AnnotationFilterParameter.ThresholdType.NO_THRESHOLD);
-       if (getCurrentAnnotation().graph != AlignmentAnnotation.NO_GRAPH)
+       if (getCurrentAnnotation().isQuantitative())
        {
          filterParams
                  .setThresholdValue(getCurrentAnnotation().threshold.value);
      ap.paintAlignment(true);
    }
  
 -
 -  public ColumnSelection getOldColumnSelection()
 +  public HiddenColumns getOldHiddenColumns()
    {
 -    return oldColumnSelection;
 +    return oldHiddenColumns;
    }
  
 -  public void setOldColumnSelection(ColumnSelection currentColumnSelection)
 +  public void setOldHiddenColumns(HiddenColumns currentHiddenColumns)
    {
 -    if (currentColumnSelection != null)
 +    if (currentHiddenColumns != null)
      {
 -      this.oldColumnSelection = new ColumnSelection(currentColumnSelection);
 +      this.oldHiddenColumns = new HiddenColumns(currentHiddenColumns);
      }
    }
  
    public void selectedAnnotationChanged()
    {
      String currentView = AnnotationColumnChooser.NO_GRAPH_VIEW;
-     if (av.getAlignment().getAlignmentAnnotation()[annmap[getAnnotations()
-             .getSelectedIndex()]].graph != AlignmentAnnotation.NO_GRAPH)
+     if (av.getAlignment()
+             .getAlignmentAnnotation()[annmap[getAnnotations()
+             .getSelectedIndex()]].isQuantitative())
      {
        currentView = AnnotationColumnChooser.GRAPH_VIEW;
      }
@@@ -1107,7 -1107,7 +1107,7 @@@ public class Jalview2XM
                Tree tree = new Tree();
                tree.setTitle(tp.getTitle());
                tree.setCurrentTree((av.currentTree == tp.getTree()));
-               tree.setNewick(tp.getTree().toString());
+               tree.setNewick(tp.getTree().print());
                tree.setThreshold(tp.treeCanvas.threshold);
  
                tree.setFitToWindow(tp.fitToWindow.getState());
  
        if (av.hasHiddenColumns())
        {
 -        if (av.getColumnSelection() == null
 -                || av.getColumnSelection().getHiddenColumns() == null)
 +        jalview.datamodel.HiddenColumns hidden = av.getAlignment()
 +                .getHiddenColumns();
 +        if (hidden == null || hidden.getListOfCols() == null)
          {
            warn("REPORT BUG: avoided null columnselection bug (DMAM reported). Please contact Jim about this.");
          }
          else
          {
 -          for (int c = 0; c < av.getColumnSelection().getHiddenColumns()
 +          for (int c = 0; c < hidden.getListOfCols()
                    .size(); c++)
            {
 -            int[] region = av.getColumnSelection().getHiddenColumns()
 +            int[] region = hidden.getListOfCols()
                      .get(c);
              HiddenColumns hc = new HiddenColumns();
              hc.setStart(region[0]);
          TreePanel tp = (TreePanel) retrieveExistingObj(tree.getId());
          if (tp == null)
          {
-           tp = af.ShowNewickTree(
+           tp = af.showNewickTree(
                    new jalview.io.NewickFile(tree.getNewick()),
                    tree.getTitle(), tree.getWidth(), tree.getHeight(),
                    tree.getXpos(), tree.getYpos());
   */
  package jalview.gui;
  
+ import jalview.analysis.scoremodels.ScoreModels;
+ import jalview.analysis.scoremodels.SimilarityParams;
+ import jalview.api.analysis.ScoreModelI;
+ import jalview.api.analysis.SimilarityParamsI;
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.AlignmentView;
 -import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
- import jalview.datamodel.SeqCigar;
  import jalview.datamodel.SequenceI;
  import jalview.jbgui.GPCAPanel;
- import jalview.schemes.ResidueProperties;
  import jalview.util.MessageManager;
  import jalview.viewmodel.AlignmentViewport;
  import jalview.viewmodel.PCAModel;
  
  import java.awt.BorderLayout;
  import java.awt.Color;
+ import java.awt.Dimension;
  import java.awt.Graphics;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
@@@ -70,29 -73,54 +73,54 @@@ public class PCAPanel extends GPCAPane
  
    PCAModel pcaModel;
  
+   private static final int MIN_WIDTH = 470;
+   private static final int MIN_HEIGHT = 250;
    int top = 0;
  
    /**
-    * Creates a new PCAPanel object.
+    * Creates a new PCAPanel object using default score model and parameters
     * 
-    * @param av
-    *          DOCUMENT ME!
-    * @param s
-    *          DOCUMENT ME!
+    * @param alignPanel
     */
-   public PCAPanel(AlignmentPanel ap)
+   public PCAPanel(AlignmentPanel alignPanel)
+   {
+     this(alignPanel, ScoreModels.getInstance()
+             .getDefaultModel(!alignPanel.av.getAlignment().isNucleotide())
+             .getName(), SimilarityParams.SeqSpace);
+   }
+   /**
+    * Constructor given sequence data, a similarity (or distance) score model
+    * name, and score calculation parameters
+    * 
+    * @param alignPanel
+    * @param modelName
+    * @param params
+    */
+   public PCAPanel(AlignmentPanel alignPanel, String modelName,
+           SimilarityParamsI params)
    {
      super();
-     this.av = ap.av;
-     this.ap = ap;
+     this.av = alignPanel.av;
+     this.ap = alignPanel;
+     boolean nucleotide = av.getAlignment().isNucleotide();
  
      progressBar = new ProgressBar(statusPanel, statusBar);
  
-     boolean sameLength = true;
+     addInternalFrameListener(new InternalFrameAdapter()
+     {
+       @Override
+       public void internalFrameClosed(InternalFrameEvent e)
+       {
+         close_actionPerformed();
+       }
+     });
      boolean selected = av.getSelectionGroup() != null
              && av.getSelectionGroup().getSize() > 0;
      AlignmentView seqstrings = av.getAlignmentView(selected);
-     boolean nucleotide = av.getAlignment().isNucleotide();
      SequenceI[] seqs;
      if (!selected)
      {
      {
        seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
      }
-     SeqCigar sq[] = seqstrings.getSequences();
-     int length = sq[0].getWidth();
-     for (int i = 0; i < seqs.length; i++)
-     {
-       if (sq[i].getWidth() != length)
-       {
-         sameLength = false;
-         break;
-       }
-     }
-     if (!sameLength)
-     {
-       JvOptionPane.showMessageDialog(Desktop.desktop,
-               MessageManager.getString("label.pca_sequences_not_aligned"),
-               MessageManager.getString("label.sequences_not_aligned"),
-               JvOptionPane.WARNING_MESSAGE);
  
-       return;
-     }
-     addInternalFrameListener(new InternalFrameAdapter()
-     {
-       @Override
-       public void internalFrameClosed(InternalFrameEvent e)
-       {
-         close_actionPerformed();
-       }
-     });
-     pcaModel = new PCAModel(seqstrings, seqs, nucleotide);
+     ScoreModelI scoreModel = ScoreModels.getInstance().getScoreModel(
+             modelName, ap);
+     pcaModel = new PCAModel(seqstrings, seqs, nucleotide, scoreModel,
+             params);
      PaintRefresher.Register(this, av.getSequenceSetId());
  
-     rc = new RotatableCanvas(ap);
+     rc = new RotatableCanvas(alignPanel);
      this.getContentPane().add(rc, BorderLayout.CENTER);
      Thread worker = new Thread(this);
      worker.start();
      pcaModel = null;
    }
  
+   /**
+    * Repopulate the options and actions under the score model menu when it is
+    * selected. Options will depend on whether 'nucleotide' or 'peptide'
+    * modelling is selected (and also possibly on whether any additional score
+    * models have been added).
+    */
    @Override
-   protected void scoreMatrix_menuSelected()
+   protected void scoreModel_menuSelected()
    {
-     scoreMatrixMenu.removeAll();
-     for (final String sm : ResidueProperties.scoreMatrices.keySet())
+     scoreModelMenu.removeAll();
+     for (final ScoreModelI sm : ScoreModels.getInstance().getModels())
      {
-       if (ResidueProperties.getScoreMatrix(sm) != null)
+       final String name = sm.getName();
+       JCheckBoxMenuItem jm = new JCheckBoxMenuItem(name);
+       /*
+        * if the score model doesn't provide a description, try to look one
+        * up in the text bundle, falling back on its name
+        */
+       String tooltip = sm.getDescription();
+       if (tooltip == null)
+       {
+         tooltip = MessageManager.getStringOrReturn("label.score_model_",
+                 name);
+       }
+       jm.setToolTipText(tooltip);
+       jm.setSelected(pcaModel.getScoreModelName().equals(name));
+       if ((pcaModel.isNucleotide() && sm.isDNA())
+               || (!pcaModel.isNucleotide() && sm.isProtein()))
        {
-         // create an entry for this score matrix for use in PCA
-         JCheckBoxMenuItem jm = new JCheckBoxMenuItem();
-         jm.setText(MessageManager.getStringOrReturn("label.score_model_",
-                 sm));
-         jm.setSelected(pcaModel.getScore_matrix().equals(sm));
-         if ((ResidueProperties.scoreMatrices.get(sm).isDNA() && ResidueProperties.scoreMatrices
-                 .get(sm).isProtein())
-                 || pcaModel.isNucleotide() == ResidueProperties.scoreMatrices
-                         .get(sm).isDNA())
+         jm.addActionListener(new ActionListener()
          {
-           final PCAPanel us = this;
-           jm.addActionListener(new ActionListener()
+           @Override
+           public void actionPerformed(ActionEvent e)
            {
-             @Override
-             public void actionPerformed(ActionEvent e)
+             if (!pcaModel.getScoreModelName().equals(name))
              {
-               if (!pcaModel.getScore_matrix().equals(sm))
-               {
-                 pcaModel.setScore_matrix(sm);
-                 Thread worker = new Thread(us);
-                 worker.start();
-               }
+               ScoreModelI sm2 = ScoreModels.getInstance().getScoreModel(
+                       name, ap);
+               pcaModel.setScoreModel(sm2);
+               Thread worker = new Thread(PCAPanel.this);
+               worker.start();
              }
-           });
-           scoreMatrixMenu.add(jm);
-         }
+           }
+         });
+         scoreModelMenu.add(jm);
        }
      }
    }
        // rc.invalidate();
        nuclSetting.setSelected(pcaModel.isNucleotide());
        protSetting.setSelected(!pcaModel.isNucleotide());
-       jvVersionSetting.setSelected(pcaModel.isJvCalcMode());
        top = pcaModel.getTop();
  
      } catch (OutOfMemoryError er)
        addKeyListener(rc);
        Desktop.addInternalFrame(this, MessageManager
                .getString("label.principal_component_analysis"), 475, 450);
+       this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
      }
    }
  
      if (!pcaModel.isNucleotide())
      {
        pcaModel.setNucleotide(true);
-       pcaModel.setScore_matrix("DNA");
+       pcaModel.setScoreModel(ScoreModels.getInstance().getDefaultModel(
+               false));
        Thread worker = new Thread(this);
        worker.start();
      }
      if (pcaModel.isNucleotide())
      {
        pcaModel.setNucleotide(false);
-       pcaModel.setScore_matrix("BLOSUM62");
+       pcaModel.setScoreModel(ScoreModels.getInstance()
+               .getDefaultModel(true));
        Thread worker = new Thread(this);
        worker.start();
      }
    }
  
-   @Override
-   protected void jvVersionSetting_actionPerfomed(ActionEvent arg0)
-   {
-     pcaModel.setJvCalcMode(jvVersionSetting.isSelected());
-     Thread worker = new Thread(this);
-     worker.start();
-   }
    /**
     * DOCUMENT ME!
     */
      }
      ;
      Object[] alAndColsel = pcaModel.getSeqtrings()
 -            .getAlignmentAndColumnSelection(gc);
 +            .getAlignmentAndHiddenColumns(gc);
  
      if (alAndColsel != null && alAndColsel[0] != null)
      {
        if (true)
        {
          // make a new frame!
 -        AlignFrame af = new AlignFrame(al,
 -                (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
 +        AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
 +                AlignFrame.DEFAULT_WIDTH,
                  AlignFrame.DEFAULT_HEIGHT);
  
          // >>>This is a fix for the moment, until a better solution is
@@@ -31,8 -31,8 +31,8 @@@ import jalview.commands.EditCommand.Act
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.Annotation;
 -import jalview.datamodel.ColumnSelection;
  import jalview.datamodel.DBRefEntry;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.Sequence;
  import jalview.datamodel.SequenceFeature;
@@@ -55,6 -55,7 +55,7 @@@ import jalview.util.UrlLink
  import java.awt.Color;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
+ import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Collections;
@@@ -1445,21 -1446,13 +1446,21 @@@ public class PopupMenu extends JPopupMe
    {
      if (sequence != null)
      {
 -      ColumnSelection cs = ap.av.getColumnSelection();
 -      if (cs == null)
 -      {
 -        cs = new ColumnSelection();
 +      /* ColumnSelection cs = ap.av.getColumnSelection();
 +       if (cs == null)
 +       {
 +         cs = new ColumnSelection();
 +       }
 +       cs.hideInsertionsFor(sequence);
 +       ap.av.setColumnSelection(cs);*/
 +
 +      HiddenColumns hidden = ap.av.getAlignment().getHiddenColumns();
 +      if (hidden == null)
 +      {
 +        hidden = new HiddenColumns();
        }
 -      cs.hideInsertionsFor(sequence);
 -      ap.av.setColumnSelection(cs);
 +      hidden.hideInsertionsFor(sequence);
 +      ap.av.getAlignment().setHiddenColumns(hidden);
      }
      refresh();
    }
        return;
      }
  
-     int rsize = 0, gSize = sg.getSize();
-     SequenceI[] rseqs, seqs = new SequenceI[gSize];
-     SequenceFeature[] tfeatures, features = new SequenceFeature[gSize];
+     List<SequenceI> seqs = new ArrayList<SequenceI>();
+     List<SequenceFeature> features = new ArrayList<SequenceFeature>();
  
+     /*
+      * assemble dataset sequences, and template new sequence features,
+      * for the amend features dialog
+      */
+     int gSize = sg.getSize();
      for (int i = 0; i < gSize; i++)
      {
        int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
        int end = sg.findEndRes(sg.getSequenceAt(i));
        if (start <= end)
        {
-         seqs[rsize] = sg.getSequenceAt(i).getDatasetSequence();
-         features[rsize] = new SequenceFeature(null, null, null, start, end,
-                 "Jalview");
-         rsize++;
+         seqs.add(sg.getSequenceAt(i).getDatasetSequence());
+         features.add(new SequenceFeature(null, null, null, start, end,
+                 "Jalview"));
        }
      }
-     rseqs = new SequenceI[rsize];
-     tfeatures = new SequenceFeature[rsize];
-     System.arraycopy(seqs, 0, rseqs, 0, rsize);
-     System.arraycopy(features, 0, tfeatures, 0, rsize);
-     features = tfeatures;
-     seqs = rseqs;
      if (ap.getSeqPanel().seqCanvas.getFeatureRenderer().amendFeatures(seqs,
-             features, true, ap))
+             features, true, ap, null))
      {
        ap.alignFrame.setShowSeqFeatures(true);
        ap.highlightSearchResults(null);
@@@ -27,7 -27,6 +27,7 @@@ import jalview.commands.EditCommand.Act
  import jalview.commands.EditCommand.Edit;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SearchResultMatchI;
  import jalview.datamodel.SearchResults;
  import jalview.datamodel.SearchResultsI;
@@@ -60,6 -59,7 +60,7 @@@ import java.awt.event.MouseMotionListen
  import java.awt.event.MouseWheelEvent;
  import java.awt.event.MouseWheelListener;
  import java.util.ArrayList;
+ import java.util.Collections;
  import java.util.List;
  
  import javax.swing.JPanel;
@@@ -233,8 -233,7 +234,8 @@@ public class SeqPanel extends JPanel im
  
      if (av.hasHiddenColumns())
      {
 -      res = av.getColumnSelection().adjustForHiddenColumns(res);
 +      res = av.getAlignment().getHiddenColumns()
 +              .adjustForHiddenColumns(res);
      }
  
      return res;
    {
      seqCanvas.cursorX += dx;
      seqCanvas.cursorY += dy;
 +
 +    HiddenColumns hidden = av.getAlignment().getHiddenColumns();
 +
      if (av.hasHiddenColumns()
 -            && !av.getColumnSelection().isVisible(seqCanvas.cursorX))
 + && !hidden.isVisible(seqCanvas.cursorX))
      {
        int original = seqCanvas.cursorX - dx;
        int maxWidth = av.getAlignment().getWidth();
  
 -      while (!av.getColumnSelection().isVisible(seqCanvas.cursorX)
 +      while (!hidden.isVisible(seqCanvas.cursorX)
                && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
        {
          seqCanvas.cursorX += dx;
        }
  
        if (seqCanvas.cursorX >= maxWidth
 -              || !av.getColumnSelection().isVisible(seqCanvas.cursorX))
 +              || !hidden.isVisible(seqCanvas.cursorX))
        {
          seqCanvas.cursorX = original;
        }
        }
        if (!av.getWrapAlignment())
        {
 -        while (seqCanvas.cursorX < av.getColumnSelection()
 -                .adjustForHiddenColumns(av.getRanges().getStartRes()))
 +        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
 +        while (seqCanvas.cursorX < hidden.adjustForHiddenColumns(av
 +                .getRanges().getStartRes()))
          {
            if (!ap.scrollRight(false))
            {
              break;
            }
          }
 -        while (seqCanvas.cursorX > av.getColumnSelection()
 -                .adjustForHiddenColumns(av.getRanges().getEndRes()))
 +        while (seqCanvas.cursorX > hidden.adjustForHiddenColumns(av
 +                .getRanges().getEndRes()))
          {
            if (!ap.scrollRight(true))
            {
      if (av.hasHiddenColumns())
      {
        fixedColumns = true;
 -      int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
 -      int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
 +      int y1 = av.getAlignment().getHiddenColumns()
 +              .getHiddenBoundaryLeft(startres);
 +      int y2 = av.getAlignment().getHiddenColumns()
 +              .getHiddenBoundaryRight(startres);
  
        if ((insertGap && startres > y1 && lastres < y1)
                || (!insertGap && startres < y2 && lastres > y2))
          {
            if (sg.getSize() == av.getAlignment().getHeight())
            {
 -            if ((av.hasHiddenColumns() && startres < av
 -                    .getColumnSelection().getHiddenBoundaryRight(startres)))
 +            if ((av.hasHiddenColumns() && startres < av.getAlignment()
 +                    .getHiddenColumns().getHiddenBoundaryRight(startres)))
              {
                endEditing();
                return;
      }
    }
  
+   /**
+    * Handler for double-click on a position with one or more sequence features.
+    * Opens the Amend Features dialog to allow feature details to be amended, or
+    * the feature deleted.
+    */
    @Override
    public void mouseClicked(MouseEvent evt)
    {
                .findFeaturesAtRes(sequence.getDatasetSequence(),
                        sequence.findPosition(findRes(evt)));
  
-       if (features != null && features.size() > 0)
+       if (!features.isEmpty())
        {
+         /*
+          * highlight the first feature at the position on the alignment
+          */
          SearchResultsI highlight = new SearchResults();
          highlight.addResult(sequence, features.get(0).getBegin(), features
                  .get(0).getEnd());
          seqCanvas.highlightSearchResults(highlight);
-       }
-       if (features != null && features.size() > 0)
-       {
-         seqCanvas.getFeatureRenderer().amendFeatures(
-                 new SequenceI[] { sequence },
-                 features.toArray(new SequenceFeature[features.size()]),
-                 false, ap);
  
+         /*
+          * open the Amend Features dialog; clear highlighting afterwards,
+          * whether changes were made or not
+          */
+         List<SequenceI> seqs = Collections.singletonList(sequence);
+         seqCanvas.getFeatureRenderer().amendFeatures(seqs, features, false,
+                 ap, null);
          seqCanvas.highlightSearchResults(null);
        }
      }
     * 
     * @param evt
     * @param res
-    * @param sequence
+    * @param sequences
     */
    void showPopupMenu(MouseEvent evt)
    {
     */
    @Override
    public void selection(SequenceGroup seqsel, ColumnSelection colsel,
 -          SelectionSource source)
 +          HiddenColumns hidden, SelectionSource source)
    {
      // TODO: fix this hack - source of messages is align viewport, but SeqPanel
      // handles selection messages...
      // shared between viewports.
      boolean iSentTheSelection = (av == source || (source instanceof AlignViewport && ((AlignmentViewport) source)
              .getSequenceSetId().equals(av.getSequenceSetId())));
-     if (iSentTheSelection || !av.followSelection)
+     if (iSentTheSelection)
      {
-       return;
+       // respond to our own event by updating dependent dialogs
+       if (ap.getCalculationDialog() != null)
+       {
+         ap.getCalculationDialog().validateCalcTypes();
+       }
+       // process further ?
+       if (!av.followSelection)
+       {
+         return;
+       }
      }
  
      /*
       * Check for selection in a view of which this one is a dna/protein
       * complement.
       */
 -    if (selectionFromTranslation(seqsel, colsel, source))
 +    if (selectionFromTranslation(seqsel, colsel, hidden, source))
      {
        return;
      }
          }
          else
          {
 -          av.getColumnSelection().setElementsFrom(colsel);
 +          av.getColumnSelection().setElementsFrom(colsel,
 +                  av.getAlignment().getHiddenColumns());
          }
        }
        av.isColSelChanged(true);
  
      if (copycolsel
              && av.hasHiddenColumns()
 -            && (av.getColumnSelection() == null || av.getColumnSelection()
 -                    .getHiddenColumns() == null))
 +            && (av.getAlignment().getHiddenColumns() == null || av
 +                    .getAlignment().getHiddenColumns().getListOfCols() == null))
      {
        System.err.println("Bad things");
      }
        PaintRefresher.Refresh(this, av.getSequenceSetId());
        // ap.paintAlignment(false);
      }
+     // lastly, update dependent dialogs
+     if (ap.getCalculationDialog() != null)
+     {
+       ap.getCalculationDialog().validateCalcTypes();
+     }
    }
  
    /**
     * @param source
     */
    protected boolean selectionFromTranslation(SequenceGroup seqsel,
 -          ColumnSelection colsel, SelectionSource source)
 +          ColumnSelection colsel, HiddenColumns hidden,
 +          SelectionSource source)
    {
      if (!(source instanceof AlignViewportI))
      {
      /*
       * Map column selection
       */
 -    ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
 -            av);
 +    // ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
 +    // av);
 +    ColumnSelection cs = new ColumnSelection();
 +    HiddenColumns hs = new HiddenColumns();
 +    MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs);
      av.setColumnSelection(cs);
 +    av.getAlignment().setHiddenColumns(hs);
  
+     // lastly, update any dependent dialogs
+     if (ap.getCalculationDialog() != null)
+     {
+       ap.getCalculationDialog().validateCalcTypes();
+     }
      PaintRefresher.Refresh(this, av.getSequenceSetId());
  
      return true;
  package jalview.gui;
  
  import jalview.analysis.AlignmentSorter;
+ import jalview.analysis.AverageDistanceTree;
  import jalview.analysis.NJTree;
+ import jalview.analysis.TreeBuilder;
+ import jalview.analysis.TreeModel;
+ import jalview.analysis.scoremodels.ScoreModels;
  import jalview.api.analysis.ScoreModelI;
- import jalview.api.analysis.ViewBasedAnalysisI;
+ import jalview.api.analysis.SimilarityParamsI;
  import jalview.bin.Cache;
  import jalview.commands.CommandI;
  import jalview.commands.OrderCommand;
@@@ -31,8 -35,8 +35,8 @@@ 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.HiddenColumns;
  import jalview.datamodel.NodeTransformI;
  import jalview.datamodel.SequenceFeature;
  import jalview.datamodel.SequenceI;
@@@ -41,7 -45,6 +45,6 @@@ import jalview.io.JalviewFileChooser
  import jalview.io.JalviewFileView;
  import jalview.io.NewickFile;
  import jalview.jbgui.GTreePanel;
- import jalview.schemes.ResidueProperties;
  import jalview.util.ImageMaker;
  import jalview.util.MessageManager;
  import jalview.viewmodel.AlignmentViewport;
@@@ -71,68 -74,46 +74,46 @@@ import org.jibble.epsgraphics.EpsGraphi
   */
  public class TreePanel extends GTreePanel
  {
-   String type;
+   String treeType;
  
-   String pwtype;
+   String scoreModelName; // if tree computed
+   String treeTitle; // if tree loaded
+   SimilarityParamsI similarityParams;
  
    TreeCanvas treeCanvas;
  
-   NJTree tree;
+   TreeModel tree;
  
    AlignViewport av;
  
    /**
     * Creates a new TreePanel object.
     * 
-    * @param av
-    *          DOCUMENT ME!
-    * @param seqVector
-    *          DOCUMENT ME!
+    * @param ap
     * @param type
-    *          DOCUMENT ME!
-    * @param pwtype
-    *          DOCUMENT ME!
-    * @param s
-    *          DOCUMENT ME!
-    * @param e
-    *          DOCUMENT ME!
+    * @param modelName
+    * @param options
     */
-   public TreePanel(AlignmentPanel ap, String type, String pwtype)
+   public TreePanel(AlignmentPanel ap, String type, String modelName,
+           SimilarityParamsI options)
    {
      super();
-     initTreePanel(ap, type, pwtype, null, null);
+     this.similarityParams = options;
+     initTreePanel(ap, type, modelName, null, null);
  
      // We know this tree has distances. JBPNote TODO: prolly should add this as
      // a userdefined default
      // 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)
+   public TreePanel(AlignmentPanel alignPanel, NewickFile newtree,
+           String theTitle, AlignmentView inputData)
    {
      super();
-     initTreePanel(av, type, pwtype, newtree, inputData);
+     this.treeTitle = theTitle;
+     initTreePanel(alignPanel, null, null, newtree, inputData);
    }
  
    public AlignmentI getAlignment()
      return treeCanvas.av;
    }
  
-   void initTreePanel(AlignmentPanel ap, String type, String pwtype,
+   void initTreePanel(AlignmentPanel ap, String type, String modelName,
            NewickFile newTree, AlignmentView inputData)
    {
  
      av = ap.av;
-     this.type = type;
-     this.pwtype = pwtype;
+     this.treeType = type;
+     this.scoreModelName = modelName;
  
      treeCanvas = new TreeCanvas(this, ap, scrollPane);
      scrollPane.setViewportView(treeCanvas);
                      .println("new alignment sequences vector value is null");
            }
  
-           tree.UpdatePlaceHolders((List<SequenceI>) evt.getNewValue());
+           tree.updatePlaceHolders((List<SequenceI>) evt.getNewValue());
            treeCanvas.nameHash.clear(); // reset the mapping between canvas
            // rectangles and leafnodes
            repaint();
        }
      });
  
-     TreeLoader tl = new TreeLoader(newTree);
-     if (inputData != null)
-     {
-       tl.odata = inputData;
-     }
+     TreeLoader tl = new TreeLoader(newTree, inputData);
      tl.start();
  
    }
  
    class TreeLoader extends Thread
    {
-     NewickFile newtree;
+     private NewickFile newtree;
  
-     jalview.datamodel.AlignmentView odata = null;
+     private AlignmentView odata = null;
  
-     public TreeLoader(NewickFile newtree)
+     public TreeLoader(NewickFile newickFile, AlignmentView inputData)
      {
-       this.newtree = newtree;
-       if (newtree != null)
+       this.newtree = newickFile;
+       this.odata = inputData;
+       if (newickFile != null)
        {
          // Must be outside run(), as Jalview2XML tries to
          // update distance/bootstrap visibility at the same time
-         showBootstrap(newtree.HasBootstrap());
-         showDistances(newtree.HasDistances());
+         showBootstrap(newickFile.HasBootstrap());
+         showDistances(newickFile.HasDistances());
        }
      }
  
  
        if (newtree != null)
        {
-         if (odata == null)
-         {
-           tree = new NJTree(av.getAlignment().getSequencesArray(), newtree);
-         }
-         else
+         tree = new TreeModel(av.getAlignment().getSequencesArray(), odata,
+                 newtree);
+         if (tree.getOriginalData() == null)
          {
-           tree = new NJTree(av.getAlignment().getSequencesArray(), odata,
-                   newtree);
-         }
-         if (!tree.hasOriginalSequenceData())
-         {
-           allowOriginalSeqData(false);
+           originalSeqData.setVisible(false);
          }
        }
        else
        {
-         int start, end;
-         SequenceI[] seqs;
-         boolean selview = av.getSelectionGroup() != null
-                 && av.getSelectionGroup().getSize() > 1;
-         AlignmentView seqStrings = av.getAlignmentView(selview);
-         if (!selview)
-         {
-           start = 0;
-           end = av.getAlignment().getWidth();
-           seqs = av.getAlignment().getSequencesArray();
-         }
-         else
-         {
-           start = av.getSelectionGroup().getStartRes();
-           end = av.getSelectionGroup().getEndRes() + 1;
-           seqs = av.getSelectionGroup().getSequencesInOrder(
-                   av.getAlignment());
-         }
-         ScoreModelI sm = ResidueProperties.getScoreModel(pwtype);
-         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());
-           }
-           tree = new NJTree(seqs, seqStrings, type, pwtype, sm, start, end);
-         }
-         else
-         {
-           tree = new NJTree(seqs, seqStrings, type, pwtype, null, start,
-                   end);
-         }
+         ScoreModelI sm = ScoreModels.getInstance().getScoreModel(
+                 scoreModelName, treeCanvas.ap);
+         TreeBuilder njtree = treeType.equals(TreeBuilder.NEIGHBOUR_JOINING) ? new NJTree(
+                 av, sm, similarityParams) : new AverageDistanceTree(av, sm,
+                 similarityParams);
+         tree = new TreeModel(njtree);
          showDistances(true);
        }
  
      treeCanvas.setMarkPlaceholders(b);
    }
  
-   private void allowOriginalSeqData(boolean b)
-   {
-     originalSeqData.setVisible(b);
-   }
    /**
     * DOCUMENT ME!
     * 
     * @return DOCUMENT ME!
     */
-   public NJTree getTree()
+   public TreeModel getTree()
    {
      return tree;
    }
    {
      CutAndPasteTransfer cap = new CutAndPasteTransfer();
  
-     StringBuffer buffer = new StringBuffer();
+     String newTitle = getPanelTitle();
  
-     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");
-     }
-     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);
        {
          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);
    @Override
    public void originalSeqData_actionPerformed(ActionEvent e)
    {
-     if (!tree.hasOriginalSequenceData())
+     AlignmentView originalData = tree.getOriginalData();
+     if (originalData == null)
      {
        jalview.bin.Cache.log
                .info("Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
      } catch (Exception ex)
      {
      }
-     ;
-     Object[] alAndColsel = tree.seqData.getAlignmentAndHiddenColumns(gc);
 -    Object[] alAndColsel = originalData
 -            .getAlignmentAndColumnSelection(gc);
++    Object[] alAndColsel = originalData.getAlignmentAndHiddenColumns(gc);
  
      if (alAndColsel != null && alAndColsel[0] != null)
      {
        if (true)
        {
          // make a new frame!
 -        AlignFrame af = new AlignFrame(al,
 -                (ColumnSelection) alAndColsel[1], AlignFrame.DEFAULT_WIDTH,
 +        AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
 +                AlignFrame.DEFAULT_WIDTH,
                  AlignFrame.DEFAULT_HEIGHT);
  
          // >>>This is a fix for the moment, until a better solution is
  
    public CommandI sortAlignmentIn(AlignmentPanel ap)
    {
-     AlignmentViewport av = ap.av;
-     SequenceI[] oldOrder = av.getAlignment().getSequencesArray();
-     AlignmentSorter.sortByTree(av.getAlignment(), tree);
+     AlignmentViewport viewport = ap.av;
+     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+     AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
      CommandI undo;
-     undo = new OrderCommand("Tree Sort", oldOrder, av.getAlignment());
+     undo = new OrderCommand("Tree Sort", oldOrder, viewport.getAlignment());
  
      ap.paintAlignment(true);
      return undo;
      return treeCanvas.font;
    }
  
-   public void setTreeFont(Font font)
+   public void setTreeFont(Font f)
    {
      if (treeCanvas != null)
      {
-       treeCanvas.setFont(font);
+       treeCanvas.setFont(f);
      }
    }
  
            }
            if (newname != null)
            {
-             String oldname = ((SequenceNode) node).getName();
-             // TODO : save in the undo object for this modification.
+             // String oldname = ((SequenceNode) node).getName();
+             // TODO : save oldname in the undo object for this modification.
              ((SequenceNode) node).setName(newname);
            }
          }
        }
      });
    }
+   /**
+    * 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
+    * @return
+    */
+   public String getPanelTitle()
+   {
+     if (treeTitle != null)
+     {
+       return treeTitle;
+     }
+     /*
+      * i18n description of Neighbour Joining or Average Distance method
+      */
+     String treecalcnm = MessageManager.getString("label.tree_calc_"
+             + treeType.toLowerCase());
+     /*
+      * short score model name (long description can be too long)
+      */
+     String smn = scoreModelName;
+     /*
+      * put them together as <method> Using <model>
+      */
+     final String ttl = MessageManager.formatMessage("label.treecalc_title",
+             treecalcnm, smn);
+     return ttl;
+   }
  }
@@@ -29,7 -29,6 +29,7 @@@ import jalview.datamodel.AlignedCodonFr
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.Annotation;
 +import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SearchResults;
  import jalview.datamodel.SearchResultsI;
@@@ -455,7 -454,7 +455,7 @@@ public class StructureSelectionManage
         * Attempt pairwise alignment of the sequence with each chain in the PDB,
         * and remember the highest scoring chain
         */
-       int max = -10;
+       float max = -10;
        AlignSeq maxAlignseq = null;
        String maxChainId = " ";
        PDBChain maxChain = null;
  
    public synchronized void sendSelection(
            jalview.datamodel.SequenceGroup selection,
 -          jalview.datamodel.ColumnSelection colsel, SelectionSource source)
 +          jalview.datamodel.ColumnSelection colsel, HiddenColumns hidden,
 +          SelectionSource source)
    {
      for (SelectionListener slis : sel_listeners)
      {
        if (slis != source)
        {
 -        slis.selection(selection, colsel, source);
 +        slis.selection(selection, colsel, hidden, source);
        }
      }
    }