JAL-2016 FeatureSettingsI now FeatureSettingsModelI
[jalview.git] / src / jalview / gui / AlignFrame.java
index afa6847..5438ce8 100644 (file)
  */
 package jalview.gui;
 
-import jalview.analysis.AAFrequency;
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AlignmentUtils;
-import jalview.analysis.Conservation;
 import jalview.analysis.CrossRef;
 import jalview.analysis.Dna;
 import jalview.analysis.ParseProperties;
 import jalview.analysis.SequenceIdMatcher;
+import jalview.api.AlignExportSettingI;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsControllerI;
+import jalview.api.FeatureSettingsModelI;
 import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.ScoreModelI;
@@ -54,6 +54,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SeqCigar;
@@ -95,9 +96,11 @@ import jalview.schemes.ZappoColourScheme;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.SequenceFetcher;
 import jalview.ws.jws1.Discoverer;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.seqfetcher.ASequenceFetcher;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
 import java.awt.BorderLayout;
@@ -132,7 +135,6 @@ import java.util.Deque;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.List;
-import java.util.Set;
 import java.util.Vector;
 
 import javax.swing.JCheckBoxMenuItem;
@@ -242,7 +244,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     this(al, hiddenColumns, width, height, null);
   }
 
-
   /**
    * Create alignment frame for al with hiddenColumns, a specific width and
    * height, and specific sequenceId
@@ -287,7 +288,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     alignPanel = new AlignmentPanel(this, viewport);
 
-
     addAlignmentPanel(alignPanel, true);
     init();
   }
@@ -313,7 +313,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     init();
   }
 
-
   /**
    * Make a new AlignFrame from existing alignmentPanels
    * 
@@ -372,10 +371,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       setGUINucleotide(viewport.getAlignment().isNucleotide());
     }
 
+    this.alignPanel.av
+            .setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
+
     setMenusFromViewport(viewport);
     buildSortByAnnotationScoresMenu();
     buildTreeMenu();
-    
+
     if (viewport.getWrapAlignment())
     {
       wrapMenuItem_actionPerformed(null);
@@ -456,7 +458,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 }
               }
             });
-    formatMenu.add(vsel);
+    if (Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase()
+            .indexOf("devel") > -1
+            || Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase()
+                    .indexOf("test") > -1)
+    {
+      formatMenu.add(vsel);
+    }
 
   }
 
@@ -553,8 +561,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         case KeyEvent.VK_SPACE:
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().insertGapAtCursor(evt.isControlDown()
-                    || evt.isShiftDown() || evt.isAltDown());
+            alignPanel.getSeqPanel().insertGapAtCursor(
+                    evt.isControlDown() || evt.isShiftDown()
+                            || evt.isAltDown());
           }
           break;
 
@@ -577,8 +586,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.getSeqPanel().deleteGapAtCursor(evt.isControlDown()
-                    || evt.isShiftDown() || evt.isAltDown());
+            alignPanel.getSeqPanel().deleteGapAtCursor(
+                    evt.isControlDown() || evt.isShiftDown()
+                            || evt.isAltDown());
           }
 
           break;
@@ -626,8 +636,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         case KeyEvent.VK_F2:
           viewport.cursorMode = !viewport.cursorMode;
           statusBar.setText(MessageManager.formatMessage(
-                  "label.keyboard_editing_mode", new String[]
-                  { (viewport.cursorMode ? "on" : "off") }));
+                  "label.keyboard_editing_mode",
+                  new String[] { (viewport.cursorMode ? "on" : "off") }));
           if (viewport.cursorMode)
           {
             alignPanel.getSeqPanel().seqCanvas.cursorX = viewport.startRes;
@@ -795,7 +805,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       public void internalFrameClosed(
               javax.swing.event.InternalFrameEvent evt)
       {
-        System.out.println("deregistering discoverer listener");
+        // System.out.println("deregistering discoverer listener");
         Desktop.instance.removeJalviewPropertyChangeListener("services",
                 thisListener);
         closeMenuItem_actionPerformed(true);
@@ -821,6 +831,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void setGUINucleotide(boolean nucleotide)
   {
     showTranslation.setVisible(nucleotide);
+    showReverse.setVisible(nucleotide);
+    showReverseComplement.setVisible(nucleotide);
     conservationMenuItem.setEnabled(!nucleotide);
     modifyConservation.setEnabled(!nucleotide);
     showGroupConservation.setEnabled(!nucleotide);
@@ -838,6 +850,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * operation that affects the data in the current view (selection changed,
    * etc) to update the menus to reflect the new state.
    */
+  @Override
   public void setMenusForViewport()
   {
     setMenusFromViewport(viewport);
@@ -895,7 +908,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     rnahelicesColour.setEnabled(av.getAlignment().hasRNAStructure());
     rnahelicesColour
             .setSelected(av.getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);
-    setShowProductsEnabled();
+
+    showProducts.setEnabled(canShowProducts());
+
     updateEditMenuBar();
   }
 
@@ -951,7 +966,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void fetchSequence_actionPerformed(ActionEvent e)
   {
-    new SequenceFetcher(this);
+    new jalview.gui.SequenceFetcher(this);
   }
 
   @Override
@@ -1030,7 +1045,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void addFromText_actionPerformed(ActionEvent e)
   {
-    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
+    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport
+            .getAlignPanel());
   }
 
   @Override
@@ -1071,7 +1087,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             currentFileFormat, false);
 
     chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle(MessageManager.getString("label.save_alignment_to_file"));
+    chooser.setDialogTitle(MessageManager
+            .getString("label.save_alignment_to_file"));
     chooser.setToolTipText(MessageManager.getString("action.save"));
 
     int value = chooser.showSaveDialog(this);
@@ -1129,8 +1146,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       success = new Jalview2XML().saveAlignment(this, file, shortName);
 
       statusBar.setText(MessageManager.formatMessage(
-              "label.successfully_saved_to_file_in_format", new Object[]
-              { fileName, format }));
+              "label.successfully_saved_to_file_in_format", new Object[] {
+                  fileName, format }));
 
     }
     else
@@ -1146,14 +1163,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         return false;
       }
 
-      AlignmentExportData exportData = getAlignmentForExport(format, viewport);
+      AlignmentExportData exportData = getAlignmentForExport(format,
+              viewport, null);
       if (exportData.getSettings().isCancelled())
       {
         return false;
       }
       FormatAdapter f = new FormatAdapter(alignPanel,
               exportData.getSettings());
-      String output = f.formatSequences(format,
+      String output = f.formatSequences(
+              format,
               exportData.getAlignment(), // class cast exceptions will
               // occur in the distant future
               exportData.getOmitHidden(), exportData.getStartEndPostions(),
@@ -1176,8 +1195,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           this.setTitle(file);
           statusBar.setText(MessageManager.formatMessage(
                   "label.successfully_saved_to_file_in_format",
-                  new Object[]
-                  { fileName, format }));
+                  new Object[] { fileName, format }));
         } catch (Exception ex)
         {
           success = false;
@@ -1189,8 +1207,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (!success)
     {
       JOptionPane.showInternalMessageDialog(this, MessageManager
-              .formatMessage("label.couldnt_save_file", new Object[]
-              { fileName }), MessageManager
+              .formatMessage("label.couldnt_save_file",
+                      new Object[] { fileName }), MessageManager
               .getString("label.error_saving_file"),
               JOptionPane.WARNING_MESSAGE);
     }
@@ -1198,7 +1216,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return success;
   }
 
-
   private void warningMessage(String warning, String title)
   {
     if (new jalview.util.Platform().isHeadless())
@@ -1225,7 +1242,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
 
     AlignmentExportData exportData = getAlignmentForExport(
-            e.getActionCommand(), viewport);
+            e.getActionCommand(), viewport, null);
     if (exportData.getSettings().isCancelled())
     {
       return;
@@ -1235,14 +1252,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     try
     {
       cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
-              .formatSequences(
-              e.getActionCommand(),
- exportData.getAlignment(),
-              exportData.getOmitHidden(), exportData.getStartEndPostions(),
-              viewport.getColumnSelection()));
+              .formatSequences(e.getActionCommand(),
+                      exportData.getAlignment(),
+                      exportData.getOmitHidden(),
+                      exportData.getStartEndPostions(),
+                      viewport.getColumnSelection()));
       Desktop.addInternalFrame(cap, MessageManager.formatMessage(
-              "label.alignment_output_command", new Object[]
-              { e.getActionCommand() }), 600, 500);
+              "label.alignment_output_command",
+              new Object[] { e.getActionCommand() }), 600, 500);
     } catch (OutOfMemoryError oom)
     {
       new OOMWarning("Outputting alignment as " + e.getActionCommand(), oom);
@@ -1251,25 +1268,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   }
 
-  public static AlignmentExportData getAlignmentForExport(String exportFormat,
-          AlignViewportI viewport)
+  public static AlignmentExportData getAlignmentForExport(
+          String exportFormat, AlignViewportI viewport,
+          AlignExportSettingI exportSettings)
   {
     AlignmentI alignmentToExport = null;
+    AlignExportSettingI settings = exportSettings;
     String[] omitHidden = null;
     int[] alignmentStartEnd = new int[2];
 
     HiddenSequences hiddenSeqs = viewport.getAlignment()
             .getHiddenSequences();
 
-
     alignmentToExport = viewport.getAlignment();
-    alignmentStartEnd = new int[]
-    { 0, alignmentToExport.getWidth() - 1 };
+    alignmentStartEnd = new int[] { 0, alignmentToExport.getWidth() - 1 };
 
     boolean hasHiddenSeqs = hiddenSeqs.getSize() > 0;
-    AlignExportSettings settings = new AlignExportSettings(hasHiddenSeqs,
-            viewport.hasHiddenColumns(), exportFormat);
-    settings.isExportAnnotations();
+    if (settings == null)
+    {
+      settings = new AlignExportSettings(hasHiddenSeqs,
+              viewport.hasHiddenColumns(), exportFormat);
+    }
+    // settings.isExportAnnotations();
 
     if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns())
     {
@@ -1286,8 +1306,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       alignmentStartEnd = getStartEnd(alignmentStartEnd, viewport
               .getColumnSelection().getHiddenColumns());
     }
-    AlignmentExportData ed = new AlignmentExportData(alignmentToExport, omitHidden, alignmentStartEnd,
-            settings);
+    AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
+            omitHidden, alignmentStartEnd, settings);
     return ed;
   }
 
@@ -1297,19 +1317,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     int startPos = aligmentStartEnd[0];
     int endPos = aligmentStartEnd[1];
 
-    int[] lowestRange = new int[2];
-    int[] higestRange = new int[2];
+    int[] lowestRange = new int[] { -1, -1 };
+    int[] higestRange = new int[] { -1, -1 };
 
     for (int[] hiddenCol : hiddenCols)
     {
-      // System.out.println("comparing : " + hiddenCol[0] + "-" + hiddenCol[1]);
       lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
       higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
     }
-    // System.out.println("min : " + lowestRange[0] + "-" + lowestRange[1]);
-    // System.out.println("max : " + higestRange[0] + "-" + higestRange[1]);
 
-    if (lowestRange[0] == 0 && lowestRange[1] == 0)
+    if (lowestRange[0] == -1 && lowestRange[1] == -1)
     {
       startPos = aligmentStartEnd[0];
     }
@@ -1318,36 +1335,29 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       startPos = lowestRange[1] + 1;
     }
 
-    if (higestRange[0] == 0 && higestRange[1] == 0)
+    if (higestRange[0] == -1 && higestRange[1] == -1)
     {
       endPos = aligmentStartEnd[1];
     }
     else
     {
-      endPos = higestRange[0];
+      endPos = higestRange[0] - 1;
     }
 
-    // System.out.println("Export range : " + minPos + " - " + maxPos);
-    return new int[]
-    { startPos, endPos };
+    // System.out.println("Export range : " + startPos + " - " + endPos);
+    return new int[] { startPos, endPos };
   }
 
   public static void main(String[] args)
   {
     ArrayList<int[]> hiddenCols = new ArrayList<int[]>();
-    hiddenCols.add(new int[]
-    { 0, 4 });
-    hiddenCols.add(new int[]
-    { 6, 9 });
-    hiddenCols.add(new int[]
-    { 11, 12 });
-    hiddenCols.add(new int[]
-    { 33, 33 });
-    hiddenCols.add(new int[]
-    { 45, 50 });
-
-    int[] x = getStartEnd(new int[]
-    { 0, 50 }, hiddenCols);
+    hiddenCols.add(new int[] { 0, 0 });
+    hiddenCols.add(new int[] { 6, 9 });
+    hiddenCols.add(new int[] { 11, 12 });
+    hiddenCols.add(new int[] { 33, 33 });
+    hiddenCols.add(new int[] { 50, 50 });
+
+    int[] x = getStartEnd(new int[] { 0, 50 }, hiddenCols);
     // System.out.println("Export range : " + x[0] + " - " + x[1]);
   }
 
@@ -1366,9 +1376,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
-    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
+    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel, this);
     bjs.exportJalviewAlignmentAsBioJsHtmlFile();
   }
+
   public void createImageMap(File file, String image)
   {
     alignPanel.makePNGImageMap(file, image);
@@ -1398,10 +1409,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     alignPanel.makeEPS(f);
   }
 
+  @Override
   public void createSVG(File f)
   {
     alignPanel.makeSVG(f);
   }
+
   @Override
   public void pageSetup_actionPerformed(ActionEvent e)
   {
@@ -1545,8 +1558,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       undoMenuItem.setEnabled(true);
       CommandI command = viewport.getHistoryList().peek();
       undoMenuItem.setText(MessageManager.formatMessage(
-              "label.undo_command", new Object[]
-              { command.getDescription() }));
+              "label.undo_command",
+              new Object[] { command.getDescription() }));
     }
     else
     {
@@ -1560,8 +1573,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       CommandI command = viewport.getRedoList().peek();
       redoMenuItem.setText(MessageManager.formatMessage(
-              "label.redo_command", new Object[]
-              { command.getDescription() }));
+              "label.redo_command",
+              new Object[] { command.getDescription() }));
     }
     else
     {
@@ -1570,6 +1583,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
   }
 
+  @Override
   public void addHistoryItem(CommandI command)
   {
     if (command.getSize() > 0)
@@ -1603,8 +1617,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     if (viewport != null)
     {
-      return new AlignmentI[]
-      { viewport.getAlignment() };
+      return new AlignmentI[] { viewport.getAlignment() };
     }
     return null;
   }
@@ -1838,8 +1851,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     boolean appendHistoryItem = false;
     Deque<CommandI> historyList = viewport.getHistoryList();
     boolean inSplitFrame = getSplitViewContainer() != null;
-    if (!inSplitFrame && historyList != null
-            && historyList.size() > 0
+    if (!inSplitFrame && historyList != null && historyList.size() > 0
             && historyList.peek() instanceof SlideSequencesCommand)
     {
       appendHistoryItem = ssc
@@ -1910,17 +1922,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
         {
-          hiddenColumns.add(new int[]
-          { region[0] - hiddenOffset, region[1] - hiddenOffset });
+          hiddenColumns.add(new int[] { region[0] - hiddenOffset,
+              region[1] - hiddenOffset });
         }
       }
     }
 
-    Desktop.jalviewClipboard = new Object[]
-    { seqs, viewport.getAlignment().getDataset(), hiddenColumns };
+    Desktop.jalviewClipboard = new Object[] { seqs,
+        viewport.getAlignment().getDataset(), hiddenColumns };
     statusBar.setText(MessageManager.formatMessage(
-            "label.copied_sequences_to_clipboard", new Object[]
-            { Integer.valueOf(seqs.length).toString() }));
+            "label.copied_sequences_to_clipboard", new Object[] { Integer
+                    .valueOf(seqs.length).toString() }));
   }
 
   /**
@@ -1975,7 +1987,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           return;
         }
 
-        format = new IdentifyFile().Identify(str, "Paste");
+        format = new IdentifyFile().identify(str, "Paste");
 
       } catch (OutOfMemoryError er)
       {
@@ -2129,8 +2141,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         //
         addHistoryItem(new EditCommand(
                 MessageManager.getString("label.add_sequences"),
-                Action.PASTE,
-                sequences, 0, alignment.getWidth(), alignment));
+                Action.PASTE, sequences, 0, alignment.getWidth(), alignment));
       }
       // Add any annotations attached to sequences
       for (int i = 0; i < sequences.length; i++)
@@ -2248,7 +2259,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         // found!!<<<
         af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
                 .transferSettings(
-                        alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer());
+                        alignPanel.getSeqPanel().seqCanvas
+                                .getFeatureRenderer());
 
         // TODO: maintain provenance of an alignment, rather than just make the
         // title a concatenation of operations.
@@ -2307,7 +2319,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // found!!<<<
       af.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer()
               .transferSettings(
-                      alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer());
+                      alignPanel.getSeqPanel().seqCanvas
+                              .getFeatureRenderer());
 
       // TODO: maintain provenance of an alignment, rather than just make the
       // title a concatenation of operations.
@@ -2369,20 +2382,24 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
      */
     if (sg.getSize() == viewport.getAlignment().getHeight())
     {
-      int confirm = JOptionPane.showConfirmDialog(this,
-              MessageManager.getString("warn.delete_all"), // $NON-NLS-1$
-              MessageManager.getString("label.delete_all"), // $NON-NLS-1$
-              JOptionPane.OK_CANCEL_OPTION);
-
-      if (confirm == JOptionPane.CANCEL_OPTION
-              || confirm == JOptionPane.CLOSED_OPTION)
+      boolean isEntireAlignWidth = (((sg.getEndRes() - sg.getStartRes()) + 1) == viewport
+              .getAlignment().getWidth()) ? true : false;
+      if (isEntireAlignWidth)
       {
-        return;
+        int confirm = JOptionPane.showConfirmDialog(this,
+                MessageManager.getString("warn.delete_all"), // $NON-NLS-1$
+                MessageManager.getString("label.delete_all"), // $NON-NLS-1$
+                JOptionPane.OK_CANCEL_OPTION);
+
+        if (confirm == JOptionPane.CANCEL_OPTION
+                || confirm == JOptionPane.CLOSED_OPTION)
+        {
+          return;
+        }
       }
       viewport.getColumnSelection().removeElements(sg.getStartRes(),
               sg.getEndRes() + 1);
     }
-
     SequenceI[] cut = sg.getSequences()
             .toArray(new SequenceI[sg.getSize()]);
 
@@ -2537,7 +2554,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     ColumnSelection colSel = viewport.getColumnSelection();
     int column;
 
-    if (colSel.size() > 0)
+    if (!colSel.isEmpty())
     {
       if (trimLeft)
       {
@@ -2562,23 +2579,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       TrimRegionCommand trimRegion;
       if (trimLeft)
       {
-        trimRegion = new TrimRegionCommand("Remove Left",
-                TrimRegionCommand.TRIM_LEFT, seqs, column,
-                viewport.getAlignment(), viewport.getColumnSelection(),
-                viewport.getSelectionGroup());
+        trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
+                column, viewport.getAlignment());
         viewport.setStartRes(0);
       }
       else
       {
-        trimRegion = new TrimRegionCommand("Remove Right",
-                TrimRegionCommand.TRIM_RIGHT, seqs, column,
-                viewport.getAlignment(), viewport.getColumnSelection(),
-                viewport.getSelectionGroup());
+        trimRegion = new TrimRegionCommand("Remove Right", false, seqs,
+                column, viewport.getAlignment());
       }
 
       statusBar.setText(MessageManager.formatMessage(
-              "label.removed_columns", new String[]
-              { Integer.valueOf(trimRegion.getSize()).toString() }));
+              "label.removed_columns",
+              new String[] { Integer.valueOf(trimRegion.getSize())
+                      .toString() }));
 
       addHistoryItem(trimRegion);
 
@@ -2627,8 +2641,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     addHistoryItem(removeGapCols);
 
     statusBar.setText(MessageManager.formatMessage(
-            "label.removed_empty_columns", new Object[]
-            { Integer.valueOf(removeGapCols.getSize()).toString() }));
+            "label.removed_empty_columns",
+            new Object[] { Integer.valueOf(removeGapCols.getSize())
+                    .toString() }));
 
     // This is to maintain viewport position on first residue
     // of first sequence
@@ -2878,8 +2893,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.setShowJVSuffix(seqLimits.isSelected());
 
-    alignPanel.getIdPanel().getIdCanvas().setPreferredSize(alignPanel
-            .calculateIdWidth());
+    alignPanel.getIdPanel().getIdCanvas()
+            .setPreferredSize(alignPanel.calculateIdWidth());
     alignPanel.paintAlignment(true);
   }
 
@@ -2958,13 +2973,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.showAllHiddenColumns();
     repaint();
+    viewport.sendSelection();
   }
 
   @Override
   public void hideSelSequences_actionPerformed(ActionEvent e)
   {
     viewport.hideAllSelectedSeqs();
-//    alignPanel.paintAlignment(true);
+    // alignPanel.paintAlignment(true);
   }
 
   /**
@@ -3048,6 +3064,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void hideAllButSelection_actionPerformed(ActionEvent e)
   {
     toggleHiddenRegions(false, false);
+    viewport.sendSelection();
   }
 
   /*
@@ -3065,6 +3082,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.hideAllSelectedSeqs();
     viewport.hideSelectedColumns();
     alignPanel.paintAlignment(true);
+    viewport.sendSelection();
   }
 
   /*
@@ -3080,6 +3098,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.showAllHiddenColumns();
     viewport.showAllHiddenSeqs();
     alignPanel.paintAlignment(true);
+    viewport.sendSelection();
   }
 
   @Override
@@ -3087,6 +3106,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.hideSelectedColumns();
     alignPanel.paintAlignment(true);
+    viewport.sendSelection();
   }
 
   @Override
@@ -3269,14 +3289,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     StringBuffer contents = new AlignmentProperties(viewport.getAlignment())
             .formatAsHtml();
     editPane.setText(MessageManager.formatMessage("label.html_content",
-            new Object[]
-            { contents.toString() }));
+            new Object[] { contents.toString() }));
     JInternalFrame frame = new JInternalFrame();
     frame.getContentPane().add(new JScrollPane(editPane));
 
     Desktop.addInternalFrame(frame, MessageManager.formatMessage(
-            "label.alignment_properties", new Object[]
-            { getTitle() }), 500, 400);
+            "label.alignment_properties", new Object[] { getTitle() }),
+            500, 400);
   }
 
   /**
@@ -3297,8 +3316,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     OverviewPanel overview = new OverviewPanel(alignPanel);
     frame.setContentPane(overview);
     Desktop.addInternalFrame(frame, MessageManager.formatMessage(
-            "label.overview_params", new Object[]
-            { this.getTitle() }), frame.getWidth(), frame.getHeight());
+            "label.overview_params", new Object[] { this.getTitle() }),
+            frame.getWidth(), frame.getHeight());
     frame.pack();
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
@@ -3489,117 +3508,35 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param cs
    *          DOCUMENT ME!
    */
+  @Override
   public void changeColour(ColourSchemeI cs)
   {
-    // TODO: compare with applet and pull up to model method
-    int threshold = 0;
+    // TODO: pull up to controller method
 
     if (cs != null)
     {
+      // Make sure viewport is up to date w.r.t. any sliders
       if (viewport.getAbovePIDThreshold())
       {
-        threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
+        int threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
                 "Background");
-        cs.setThreshold(threshold, viewport.isIgnoreGapsConsensus());
-      }
-      else
-      {
-        cs.setThreshold(0, viewport.isIgnoreGapsConsensus());
+        viewport.setThreshold(threshold);
       }
 
       if (viewport.getConservationSelected())
       {
-
-        Alignment al = (Alignment) viewport.getAlignment();
-        Conservation c = new Conservation("All",
-                ResidueProperties.propHash, 3, al.getSequences(), 0,
-                al.getWidth() - 1);
-
-        c.calculate();
-        c.verdict(false, viewport.getConsPercGaps());
-
-        cs.setConservation(c);
-
         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
                 cs, "Background"));
       }
-      else
+      if (cs instanceof TCoffeeColourScheme)
       {
-        cs.setConservation(null);
+        tcoffeeColour.setEnabled(true);
+        tcoffeeColour.setSelected(true);
       }
-
-      cs.setConsensus(viewport.getSequenceConsensusHash());
     }
 
     viewport.setGlobalColourScheme(cs);
 
-    if (viewport.getColourAppliesToAllGroups())
-    {
-
-      for (SequenceGroup sg : viewport.getAlignment().getGroups())
-      {
-        if (cs == null)
-        {
-          sg.cs = null;
-          continue;
-        }
-
-        if (cs instanceof ClustalxColourScheme)
-        {
-          sg.cs = new ClustalxColourScheme(sg,
-                  viewport.getHiddenRepSequences());
-        }
-        else if (cs instanceof UserColourScheme)
-        {
-          sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
-        }
-        else
-        {
-          try
-          {
-            sg.cs = cs.getClass().newInstance();
-          } catch (Exception ex)
-          {
-          }
-        }
-
-        if (viewport.getAbovePIDThreshold()
-                || cs instanceof PIDColourScheme
-                || cs instanceof Blosum62ColourScheme)
-        {
-          sg.cs.setThreshold(threshold, viewport.isIgnoreGapsConsensus());
-
-          sg.cs.setConsensus(AAFrequency.calculate(
-                  sg.getSequences(viewport.getHiddenRepSequences()),
-                  sg.getStartRes(), sg.getEndRes() + 1));
-        }
-        else
-        {
-          sg.cs.setThreshold(0, viewport.isIgnoreGapsConsensus());
-        }
-
-        if (viewport.getConservationSelected())
-        {
-          Conservation c = new Conservation("Group",
-                  ResidueProperties.propHash, 3, sg.getSequences(viewport
-                          .getHiddenRepSequences()), sg.getStartRes(),
-                  sg.getEndRes() + 1);
-          c.calculate();
-          c.verdict(false, viewport.getConsPercGaps());
-          sg.cs.setConservation(c);
-        }
-        else
-        {
-          sg.cs.setConservation(null);
-        }
-      }
-    }
-
-    if (alignPanel.getOverviewPanel() != null)
-    {
-      alignPanel.getOverviewPanel().updateOverviewImage();
-    }
-
     alignPanel.paintAlignment(true);
   }
 
@@ -4106,7 +4043,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void addSortByOrderMenuItem(String title,
           final AlignmentOrder order)
   {
-    final JMenuItem item = new JMenuItem(MessageManager.formatMessage("action.by_title_param", new Object[]{title}));
+    final JMenuItem item = new JMenuItem(MessageManager.formatMessage(
+            "action.by_title_param", new Object[] { title }));
     sort.add(item);
     item.addActionListener(new java.awt.event.ActionListener()
     {
@@ -4225,8 +4163,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     calculateTree.removeAll();
     // build the calculate menu
 
-    for (final String type : new String[]
-    { "NJ", "AV" })
+    for (final String type : new String[] { "NJ", "AV" })
     {
       String treecalcnm = MessageManager.getString("label.tree_calc_"
               + type.toLowerCase());
@@ -4375,8 +4312,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
     if (!viewport.getAlignment().isAligned(false))
     {
-      seqs.setSequences(new SeqCigar[]
-      { seqs.getSequences()[0] });
+      seqs.setSequences(new SeqCigar[] { seqs.getSequences()[0] });
       // TODO: if seqs.getSequences().length>1 then should really have warned
       // user!
 
@@ -4534,8 +4470,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         final List<JMenuItem> legacyItems = new ArrayList<JMenuItem>();
         try
         {
-          System.err.println("Building ws menu again "
-                  + Thread.currentThread());
+          // System.err.println("Building ws menu again "
+          // + Thread.currentThread());
           // TODO: add support for context dependent disabling of services based
           // on
           // alignment and current selection
@@ -4722,67 +4658,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
   }
 
-  /*
-   * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
-   * chooser = new JalviewFileChooser(jalview.bin.Cache.
-   * getProperty("LAST_DIRECTORY"));
-   * 
-   * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
-   * to Vamsas file"); chooser.setToolTipText("Export");
-   * 
-   * int value = chooser.showSaveDialog(this);
-   * 
-   * if (value == JalviewFileChooser.APPROVE_OPTION) {
-   * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
-   * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
-   * chooser.getSelectedFile().getAbsolutePath(), this); } }
-   */
   /**
-   * prototype of an automatically enabled/disabled analysis function
+   * Searches selected sequences for xRef products and builds the Show
+   * Cross-References menu (formerly called Show Products)
    * 
+   * @return true if Show Cross-references menu should be enabled.
    */
-  protected void setShowProductsEnabled()
+  public boolean canShowProducts()
   {
     SequenceI[] selection = viewport.getSequenceSelection();
-    if (canShowProducts(selection, viewport.getSelectionGroup() != null,
-            viewport.getAlignment().getDataset()))
-    {
-      showProducts.setEnabled(true);
-
-    }
-    else
-    {
-      showProducts.setEnabled(false);
-    }
-  }
-
-  /**
-   * search selection for sequence xRef products and build the show products
-   * menu.
-   * 
-   * @param selection
-   * @param dataset
-   * @return true if showProducts menu should be enabled.
-   */
-  public boolean canShowProducts(SequenceI[] selection,
-          boolean isRegionSelection, Alignment dataset)
-  {
+    AlignmentI dataset = viewport.getAlignment().getDataset();
     boolean showp = false;
     try
     {
       showProducts.removeAll();
       final boolean dna = viewport.getAlignment().isNucleotide();
-      final Alignment ds = dataset;
       String[] ptypes = (selection == null || selection.length == 0) ? null
               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
-      // Object[] prods =
-      // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
-      // selection, dataset, true);
-      final SequenceI[] sel = selection;
+
       for (int t = 0; ptypes != null && t < ptypes.length; t++)
       {
         showp = true;
-        final boolean isRegSel = isRegionSelection;
         final AlignFrame af = this;
         final String source = ptypes[t];
         JMenuItem xtype = new JMenuItem(ptypes[t]);
@@ -4792,9 +4688,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           @Override
           public void actionPerformed(ActionEvent e)
           {
-            // TODO: new thread for this call with vis-delay
-            af.showProductsFor(af.viewport.getSequenceSelection(),
-                    isRegSel, dna, source);
+            showProductsFor(af.viewport.getSequenceSelection(), dna, source);
           }
 
         });
@@ -4805,15 +4699,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     } catch (Exception e)
     {
       jalview.bin.Cache.log
-              .warn("canTranslate threw an exception - please report to help@jalview.org",
+              .warn("canShowProducts threw an exception - please report to help@jalview.org",
                       e);
       return false;
     }
     return showp;
   }
 
-  protected void showProductsFor(final SequenceI[] sel,
-          final boolean isRegSel, final boolean dna, final String source)
+  protected void showProductsFor(final SequenceI[] sel, final boolean dna,
+          final String source)
   {
     Runnable foo = new Runnable()
     {
@@ -4823,51 +4717,48 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         final long sttime = System.currentTimeMillis();
         AlignFrame.this.setProgressBar(MessageManager.formatMessage(
-                "status.searching_for_sequences_from", new Object[]
-                { source }), sttime);
+                "status.searching_for_sequences_from",
+                new Object[] { source }), sttime);
         try
         {
-          // update our local dataset reference
-          Alignment ds = AlignFrame.this.getViewport().getAlignment()
-                  .getDataset();
-          Alignment prods = CrossRef
-                  .findXrefSequences(sel, dna, source, ds);
-          if (prods != null)
+          /*
+           * 'peer' sequences are any to add to this alignment, for example
+           * alternative protein products for my protein's gene
+           */
+          List<SequenceI> addedPeers = new ArrayList<SequenceI>();
+          AlignmentI alignment = AlignFrame.this.getViewport()
+                  .getAlignment();
+          Alignment xrefs = CrossRef.findXrefSequences(sel, dna, source,
+                  alignment, addedPeers);
+          if (xrefs != null)
           {
-            SequenceI[] sprods = new SequenceI[prods.getHeight()];
-            for (int s = 0; s < sprods.length; s++)
+            /*
+             * figure out colour scheme if any to apply to features
+             */
+            ASequenceFetcher sftch = new SequenceFetcher();
+            List<DbSourceProxy> proxies = sftch.getSourceProxy(source);
+            FeatureSettingsModelI featureColourScheme = null;
+            for (DbSourceProxy proxy : proxies)
             {
-              sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
-              if (ds.getSequences() == null
-                      || !ds.getSequences().contains(
-                              sprods[s].getDatasetSequence()))
+              FeatureSettingsModelI preferredColours = proxy
+                      .getFeatureColourScheme();
+              if (preferredColours != null)
               {
-                ds.addSequence(sprods[s].getDatasetSequence());
+                featureColourScheme = preferredColours;
+                break;
               }
-              sprods[s].updatePDBIds();
             }
-            Alignment al = new Alignment(sprods);
-            al.setDataset(ds);
+            Alignment al = makeCrossReferencesAlignment(
+                    alignment.getDataset(), xrefs);
 
-            /*
-             * Copy dna-to-protein mappings to new alignment
-             */
-            // TODO 1: no mappings are set up for EMBL product
-            // TODO 2: if they were, should add them to protein alignment, not
-            // dna
-            Set<AlignedCodonFrame> cf = prods.getCodonFrames();
-            for (AlignedCodonFrame acf : cf)
-            {
-              al.addCodonFrame(acf);
-            }
-            AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
+            AlignFrame newFrame = new AlignFrame(al, DEFAULT_WIDTH,
                     DEFAULT_HEIGHT);
-            String newtitle = "" + ((dna) ? "Proteins" : "Nucleotides")
-                    + " for " + ((isRegSel) ? "selected region of " : "")
-                    + getTitle();
-            naf.setTitle(newtitle);
+            String newtitle = String.format("%s %s %s",
+                    MessageManager.getString(dna ? "label.proteins"
+                            : "label.nucleotides"), MessageManager
+                            .getString("label.for"), getTitle());
+            newFrame.setTitle(newtitle);
 
-            // temporary flag until SplitFrame is released
             boolean asSplitFrame = Cache.getDefault(
                     Preferences.ENABLE_SPLIT_FRAME, true);
             if (asSplitFrame)
@@ -4879,36 +4770,106 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               AlignmentI copyAlignment = null;
               final SequenceI[] sequenceSelection = AlignFrame.this.viewport
                       .getSequenceSelection();
+              List<AlignedCodonFrame> cf = xrefs.getCodonFrames();
               if (dna)
               {
-                copyAlignment = AlignmentUtils.makeExonAlignment(
-                        sequenceSelection, cf);
+                copyAlignment = AlignmentUtils.makeCdsAlignment(
+                        sequenceSelection, cf, alignment);
+                if (copyAlignment.getHeight() == 0)
+                {
+                  System.err.println("Failed to make CDS alignment");
+                }
                 al.getCodonFrames().clear();
                 al.getCodonFrames().addAll(cf);
-                final StructureSelectionManager ssm = StructureSelectionManager
-                        .getStructureSelectionManager(Desktop.instance);
-                ssm.registerMappings(cf);
               }
               else
               {
                 copyAlignment = new Alignment(new Alignment(
                         sequenceSelection));
+                copyAlignment.getCodonFrames().addAll(cf);
+              }
+              copyAlignment.setGapCharacter(AlignFrame.this.viewport
+                      .getGapCharacter());
+              StructureSelectionManager ssm = StructureSelectionManager
+                      .getStructureSelectionManager(Desktop.instance);
+              ssm.registerMappings(cf);
+
+              /*
+               * add in any extra 'peer' sequences discovered
+               * (e.g. alternative protein products)
+               */
+              for (SequenceI peer : addedPeers)
+              {
+                copyAlignment.addSequence(peer);
+              }
+
+              if (copyAlignment.getHeight() > 0)
+              {
+                /*
+                 * align protein to dna
+                 */
+                // FIXME what if the dna is not aligned :-O
+                if (dna)
+                {
+                  al.alignAs(copyAlignment);
+                }
+                else
+                {
+                  /*
+                   * align cdna to protein - currently only if 
+                   * fetching and aligning Ensembl transcripts!
+                   */
+                  if (DBRefSource.ENSEMBL.equalsIgnoreCase(source))
+                  {
+                    copyAlignment.alignAs(al);
+                  }
+                }
+
+                AlignFrame copyThis = new AlignFrame(copyAlignment,
+                        AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+                copyThis.setTitle(AlignFrame.this.getTitle());
+
+                boolean showSequenceFeatures = viewport
+                        .isShowSequenceFeatures();
+                newFrame.setShowSeqFeatures(showSequenceFeatures);
+                copyThis.setShowSeqFeatures(showSequenceFeatures);
+                FeatureRenderer myFeatureStyling = alignPanel.getSeqPanel().seqCanvas
+                        .getFeatureRenderer();
+
+                /*
+                 * copy feature rendering settings to split frame
+                 */
+                newFrame.alignPanel.getSeqPanel().seqCanvas
+                        .getFeatureRenderer().transferSettings(
+                                myFeatureStyling);
+                copyThis.alignPanel.getSeqPanel().seqCanvas
+                        .getFeatureRenderer().transferSettings(
+                                myFeatureStyling);
+
+                /*
+                 * apply 'database source' feature configuration
+                 * if any was found
+                 */
+                // TODO is this the feature colouring for the original
+                // alignment or the fetched xrefs? either could be Ensembl
+                newFrame.getViewport().applyFeaturesStyle(
+                        featureColourScheme);
+                copyThis.getViewport().applyFeaturesStyle(
+                        featureColourScheme);
+
+                SplitFrame sf = new SplitFrame(dna ? copyThis : newFrame,
+                        dna ? newFrame : copyThis);
+                newFrame.setVisible(true);
+                copyThis.setVisible(true);
+                String linkedTitle = MessageManager
+                        .getString("label.linked_view_title");
+                Desktop.addInternalFrame(sf, linkedTitle, -1, -1);
+                sf.adjustDivider();
               }
-              AlignFrame copyThis = new AlignFrame(copyAlignment,
-                      AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
-              copyThis.setTitle(AlignFrame.this.getTitle());
-              // SplitFrame with dna above, protein below
-              SplitFrame sf = new SplitFrame(dna ? copyThis : naf,
-                      dna ? naf : copyThis);
-              naf.setVisible(true);
-              copyThis.setVisible(true);
-              String linkedTitle = MessageManager
-                      .getString("label.linked_view_title");
-              Desktop.addInternalFrame(sf, linkedTitle, -1, -1);
             }
             else
             {
-              Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
+              Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH,
                       DEFAULT_HEIGHT);
             }
           }
@@ -4931,9 +4892,36 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         }
         AlignFrame.this.setProgressBar(MessageManager.formatMessage(
                 "status.finished_searching_for_sequences_from",
-                new Object[]
-                { source }),
-                sttime);
+                new Object[] { source }), sttime);
+      }
+
+      /**
+       * Makes an alignment containing the given sequences; the sequences are
+       * added to the given alignment dataset, and the dataset is set on (shared
+       * by) the new alignment
+       * 
+       * @param dataset
+       * @param seqs
+       * @return
+       */
+      protected Alignment makeCrossReferencesAlignment(Alignment dataset,
+              Alignment seqs)
+      {
+        SequenceI[] sprods = new SequenceI[seqs.getHeight()];
+        for (int s = 0; s < sprods.length; s++)
+        {
+          sprods[s] = (seqs.getSequenceAt(s)).deriveSequence();
+          if (dataset.getSequences() == null
+                  || !dataset.getSequences().contains(
+                          sprods[s].getDatasetSequence()))
+          {
+            dataset.addSequence(sprods[s].getDatasetSequence());
+          }
+          sprods[s].updatePDBIds();
+        }
+        Alignment al = new Alignment(sprods);
+        al.setDataset(dataset);
+        return al;
       }
 
     };
@@ -4998,8 +4986,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
       af.setFileFormat(this.currentFileFormat);
       final String newTitle = MessageManager.formatMessage(
-              "label.translation_of_params", new Object[]
-              { this.getTitle() });
+              "label.translation_of_params",
+              new Object[] { this.getTitle() });
       af.setTitle(newTitle);
       if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
       {
@@ -5037,7 +5025,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     return avc.parseFeaturesFile(file, type,
             jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
-    
+
   }
 
   @Override
@@ -5052,8 +5040,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       showSeqFeatures.setSelected(true);
     }
 
-
   }
+
   @Override
   public void dragEnter(DropTargetDragEvent evt)
   {
@@ -5175,7 +5163,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               String type = null;
               try
               {
-                type = new IdentifyFile().Identify(file, protocol);
+                type = new IdentifyFile().identify(file, protocol);
               } catch (Exception ex)
               {
                 type = null;
@@ -5184,8 +5172,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               {
                 if (type.equalsIgnoreCase("PDB"))
                 {
-                  filesmatched.add(new Object[]
-                  { file, protocol, mtch });
+                  filesmatched.add(new Object[] { file, protocol, mtch });
                   continue;
                 }
               }
@@ -5204,10 +5191,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                   MessageManager
                                           .formatMessage(
                                                   "label.automatically_associate_pdb_files_with_sequences_same_name",
-                                                  new Object[]
-                                                  { Integer.valueOf(
-                                                          filesmatched
-                                                                  .size())
+                                                  new Object[] { Integer
+                                                          .valueOf(
+                                                                  filesmatched
+                                                                          .size())
                                                           .toString() }),
                                   MessageManager
                                           .getString("label.automatically_associate_pdb_files_by_name"),
@@ -5244,14 +5231,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                           "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
                           .showConfirmDialog(
                                   this,
-                                  "<html>"+MessageManager
-                                          .formatMessage(
-                                                  "label.ignore_unmatched_dropped_files_info",
-                                                  new Object[]
-                                                  { Integer.valueOf(
-                                                          filesnotmatched
-                                                                  .size())
-                                                          .toString() })+"</html>",
+                                  "<html>"
+                                          + MessageManager
+                                                  .formatMessage(
+                                                          "label.ignore_unmatched_dropped_files_info",
+                                                          new Object[] { Integer
+                                                                  .valueOf(
+                                                                          filesnotmatched
+                                                                                  .size())
+                                                                  .toString() })
+                                          + "</html>",
                                   MessageManager
                                           .getString("label.ignore_unmatched_dropped_files"),
                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
@@ -5273,7 +5262,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   /**
    * Attempt to load a "dropped" file or URL string: First by testing whether
-   * it's and Annotation file, then a JNet file, and finally a features file. If
+   * 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.
    * 
@@ -5287,15 +5276,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       if (protocol == null)
       {
-        protocol = jalview.io.FormatAdapter.checkProtocol(file);
+        protocol = FormatAdapter.checkProtocol(file);
       }
       // if the file isn't identified, or not positively identified as some
       // other filetype (PFAM is default unidentified alignment file type) then
       // try to parse as annotation.
       boolean isAnnotation = (format == null || format
               .equalsIgnoreCase("PFAM")) ? new AnnotationFile()
-              .annotateAlignmentView(viewport, file, protocol)
-              : false;
+              .annotateAlignmentView(viewport, file, protocol) : false;
 
       if (!isAnnotation)
       {
@@ -5349,7 +5337,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           // try to parse it as a features file
           if (format == null)
           {
-            format = new IdentifyFile().Identify(file, protocol);
+            format = new IdentifyFile().identify(file, protocol);
           }
           if (format.equalsIgnoreCase("JnetFile"))
           {
@@ -5365,42 +5353,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             viewport.setColumnSelection(cs);
             isAnnotation = true;
           }
-          else
+          else if (IdentifyFile.FeaturesFile.equals(format))
           {
-            /*
-             * if (format.equalsIgnoreCase("PDB")) {
-             * 
-             * String pdbfn = ""; // try to match up filename with sequence id
-             * try { if (protocol == jalview.io.FormatAdapter.FILE) { File fl =
-             * new File(file); pdbfn = fl.getName(); } else if (protocol ==
-             * jalview.io.FormatAdapter.URL) { URL url = new URL(file); pdbfn =
-             * url.getFile(); } } catch (Exception e) { } ; if (assocSeq ==
-             * null) { SequenceIdMatcher idm = new SequenceIdMatcher(viewport
-             * .getAlignment().getSequencesArray()); if (pdbfn.length() > 0) {
-             * // attempt to find a match in the alignment SequenceI mtch =
-             * idm.findIdMatch(pdbfn); int l = 0, c = pdbfn.indexOf("."); while
-             * (mtch == null && c != -1) { while ((c = pdbfn.indexOf(".", l)) >
-             * l) { l = c; } if (l > -1) { pdbfn = pdbfn.substring(0, l); } mtch
-             * = idm.findIdMatch(pdbfn); } if (mtch != null) { // try and
-             * associate // prompt ? PDBEntry pe = new AssociatePdbFileWithSeq()
-             * .associatePdbWithSeq(file, protocol, mtch, true); if (pe != null)
-             * { System.err.println("Associated file : " + file + " with " +
-             * mtch.getDisplayId(true)); alignPanel.paintAlignment(true); } } //
-             * TODO: maybe need to load as normal otherwise return; } }
-             */
-            // try to parse it as a features file
-            boolean isGroupsFile = parseFeaturesFile(file, protocol);
-            // if it wasn't a features file then we just treat it as a general
-            // alignment file to load into the current view.
-            if (!isGroupsFile)
-            {
-              new FileLoader().LoadFile(viewport, file, protocol, format);
-            }
-            else
+            if (parseFeaturesFile(file, protocol))
             {
               alignPanel.paintAlignment(true);
             }
           }
+          else
+          {
+            new FileLoader().LoadFile(viewport, file, protocol, format);
+          }
         }
       }
       if (isAnnotation)
@@ -5422,7 +5385,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       } catch (Exception x)
       {
       }
-      ;
       new OOMWarning(
               "loading data "
                       + (protocol != null ? (protocol.equals(FormatAdapter.PASTE) ? "from clipboard."
@@ -5609,8 +5571,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           @Override
           public void run()
           {
+            boolean isNuclueotide = alignPanel.alignFrame.getViewport()
+                    .getAlignment().isNucleotide();
             new jalview.ws.DBRefFetcher(alignPanel.av
-                    .getSequenceSelection(), alignPanel.alignFrame)
+                    .getSequenceSelection(), alignPanel.alignFrame, null,
+                    alignPanel.alignFrame.featureSettings, isNuclueotide)
                     .fetchDBRefs(false);
           }
         }).start();
@@ -5625,7 +5590,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       @Override
       public void run()
       {
-        final jalview.ws.SequenceFetcher sf = SequenceFetcher
+        final jalview.ws.SequenceFetcher sf = jalview.gui.SequenceFetcher
                 .getSequenceFetcherSingleton(me);
         javax.swing.SwingUtilities.invokeLater(new Runnable()
         {
@@ -5679,16 +5644,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       @Override
                       public void run()
                       {
+                        boolean isNuclueotide = alignPanel.alignFrame
+                                .getViewport().getAlignment()
+                                .isNucleotide();
                         new jalview.ws.DBRefFetcher(alignPanel.av
                                 .getSequenceSelection(),
-                                alignPanel.alignFrame, dassource)
-                                .fetchDBRefs(false);
+                                alignPanel.alignFrame, dassource,
+                                alignPanel.alignFrame.featureSettings,
+                                isNuclueotide).fetchDBRefs(false);
                       }
                     }).start();
                   }
 
                 });
-                fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager.formatMessage("label.fetch_retrieve_from", new Object[]{src.getDbName()})));
+                fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true,
+                        MessageManager.formatMessage(
+                                "label.fetch_retrieve_from",
+                                new Object[] { src.getDbName() })));
                 dfetch.add(fetchr);
                 comp++;
               }
@@ -5699,8 +5671,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 // fetch all entry
                 DbSourceProxy src = otherdb.get(0);
                 fetchr = new JMenuItem(MessageManager.formatMessage(
-                        "label.fetch_all_param", new Object[]
-                        { src.getDbSource() }));
+                        "label.fetch_all_param",
+                        new Object[] { src.getDbSource() }));
                 fetchr.addActionListener(new ActionListener()
                 {
                   @Override
@@ -5712,20 +5684,32 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       @Override
                       public void run()
                       {
+                        boolean isNuclueotide = alignPanel.alignFrame
+                                .getViewport().getAlignment()
+                                .isNucleotide();
                         new jalview.ws.DBRefFetcher(alignPanel.av
                                 .getSequenceSelection(),
-                                alignPanel.alignFrame, dassource)
-                                .fetchDBRefs(false);
+                                alignPanel.alignFrame, dassource,
+                                alignPanel.alignFrame.featureSettings,
+                                isNuclueotide).fetchDBRefs(false);
                       }
                     }).start();
                   }
                 });
 
-                fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager.formatMessage("label.fetch_retrieve_from_all_sources", new Object[]{Integer.valueOf(otherdb.size()).toString(), src.getDbSource(), src.getDbName()})));
+                fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true,
+                        MessageManager.formatMessage(
+                                "label.fetch_retrieve_from_all_sources",
+                                new Object[] {
+                                    Integer.valueOf(otherdb.size())
+                                            .toString(), src.getDbSource(),
+                                    src.getDbName() })));
                 dfetch.add(fetchr);
                 comp++;
                 // and then build the rest of the individual menus
-                ifetch = new JMenu(MessageManager.formatMessage("label.source_from_db_source", new Object[]{src.getDbSource()}));
+                ifetch = new JMenu(MessageManager.formatMessage(
+                        "label.source_from_db_source",
+                        new Object[] { src.getDbSource() }));
                 icomp = 0;
                 String imname = null;
                 int i = 0;
@@ -5738,11 +5722,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                           0, 10) + "..." : dbname;
                   if (imname == null)
                   {
-                    imname = MessageManager.formatMessage("label.from_msname", new Object[]{sname});
+                    imname = MessageManager.formatMessage(
+                            "label.from_msname", new Object[] { sname });
                   }
                   fetchr = new JMenuItem(msname);
-                  final DbSourceProxy[] dassrc =
-                  { sproxy };
+                  final DbSourceProxy[] dassrc = { sproxy };
                   fetchr.addActionListener(new ActionListener()
                   {
 
@@ -5755,17 +5739,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                         @Override
                         public void run()
                         {
+                          boolean isNuclueotide = alignPanel.alignFrame
+                                  .getViewport().getAlignment()
+                                  .isNucleotide();
                           new jalview.ws.DBRefFetcher(alignPanel.av
                                   .getSequenceSelection(),
-                                  alignPanel.alignFrame, dassrc)
-                                  .fetchDBRefs(false);
+                                  alignPanel.alignFrame, dassrc,
+                                  alignPanel.alignFrame.featureSettings,
+                                  isNuclueotide).fetchDBRefs(false);
                         }
                       }).start();
                     }
 
                   });
                   fetchr.setToolTipText("<html>"
-                          + MessageManager.formatMessage("label.fetch_retrieve_from", new Object[]{dbname}));
+                          + MessageManager.formatMessage(
+                                  "label.fetch_retrieve_from", new Object[]
+                                  { dbname }));
                   ifetch.add(fetchr);
                   ++i;
                   if (++icomp >= mcomp || i == (otherdb.size()))
@@ -5820,6 +5810,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.firePropertyChange("alignment", null, al);
   }
 
+  @Override
   public void setShowSeqFeatures(boolean b)
   {
     showSeqFeatures.setSelected(b);
@@ -5929,10 +5920,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       alignPanel.paintAlignment(true);
     }
   }
+
   public void clearAlignmentSeqRep()
   {
     // TODO refactor alignmentseqrep to controller
-    if (viewport.getAlignment().hasSeqrep()) {
+    if (viewport.getAlignment().hasSeqrep())
+    {
       viewport.getAlignment().setSeqrep(null);
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
@@ -5968,7 +5961,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (!viewport.getSequenceSetId().equals(
             alignmentPanel.av.getSequenceSetId()))
     {
-      throw new Error(MessageManager.getString("error.implementation_error_cannot_show_view_alignment_frame"));
+      throw new Error(
+              MessageManager
+                      .getString("error.implementation_error_cannot_show_view_alignment_frame"));
     }
     if (tabbedPane != null
             && tabbedPane.getTabCount() > 0
@@ -6031,8 +6026,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   public List<? extends AlignmentViewPanel> getAlignPanels()
   {
-    return alignPanels == null ? Arrays.asList(alignPanel)
-            : alignPanels;
+    return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels;
   }
 
   /**
@@ -6043,14 +6037,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     // TODO no longer a menu action - refactor as required
     final AlignmentI alignment = getViewport().getAlignment();
-    Set<AlignedCodonFrame> mappings = alignment.getCodonFrames();
+    List<AlignedCodonFrame> mappings = alignment.getCodonFrames();
     if (mappings == null)
     {
       return;
     }
     List<SequenceI> cdnaSeqs = new ArrayList<SequenceI>();
-    for (SequenceI aaSeq : alignment.getSequences()) {
-      for (AlignedCodonFrame acf : mappings) {
+    for (SequenceI aaSeq : alignment.getSequences())
+    {
+      for (AlignedCodonFrame acf : mappings)
+      {
         SequenceI dnaSeq = acf.getDnaForAaSeq(aaSeq.getDatasetSequence());
         if (dnaSeq != null)
         {
@@ -6078,8 +6074,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     String newtitle = "cDNA " + MessageManager.getString("label.for") + " "
             + this.title;
     Desktop.addInternalFrame(alignFrame, newtitle,
-            AlignFrame.DEFAULT_WIDTH,
-            AlignFrame.DEFAULT_HEIGHT);
+            AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
   }
 
   /**
@@ -6092,10 +6087,32 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void showComplement_actionPerformed(boolean show)
   {
     SplitContainerI sf = getSplitViewContainer();
-    if (sf != null) {
+    if (sf != null)
+    {
       sf.setComplementVisible(this, show);
     }
   }
+
+  /**
+   * Generate the reverse (optionally complemented) of the selected sequences,
+   * and add them to the alignment
+   */
+  @Override
+  protected void showReverse_actionPerformed(boolean complement)
+  {
+    AlignmentI al = null;
+    try
+    {
+      Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
+
+      al = dna.reverseCdna(complement);
+      viewport.addAlignment(al, "");
+    } catch (Exception ex)
+    {
+      System.err.println(ex.getMessage());
+      return;
+    }
+  }
 }
 
 class PrintThread extends Thread