JAL-2360 refactoring for JalviewColourScheme enum,
[jalview.git] / src / jalview / gui / AlignFrame.java
index e439696..9aed70d 100644 (file)
@@ -32,7 +32,6 @@ 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,7 +53,6 @@ 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;
@@ -65,10 +63,14 @@ import jalview.gui.ViewSelectionMenu.ViewSetProvider;
 import jalview.io.AlignmentProperties;
 import jalview.io.AnnotationFile;
 import jalview.io.BioJsHTMLOutput;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileFormatI;
 import jalview.io.FileLoader;
 import jalview.io.FormatAdapter;
 import jalview.io.HtmlSvgOutput;
 import jalview.io.IdentifyFile;
+import jalview.io.JPredFile;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
 import jalview.io.JnetAnnotationMaker;
@@ -85,7 +87,9 @@ import jalview.schemes.HydrophobicColourScheme;
 import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.PIDColourScheme;
 import jalview.schemes.PurinePyrimidineColourScheme;
+import jalview.schemes.RNAHelicesColour;
 import jalview.schemes.RNAHelicesColourChooser;
+import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.ResidueProperties;
 import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
@@ -93,12 +97,10 @@ import jalview.schemes.TaylorColourScheme;
 import jalview.schemes.TurnColourScheme;
 import jalview.schemes.UserColourScheme;
 import jalview.schemes.ZappoColourScheme;
-import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.ws.DBRefFetcher;
 import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
-import jalview.ws.SequenceFetcher;
 import jalview.ws.jws1.Discoverer;
 import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
@@ -125,13 +127,11 @@ import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.print.PageFormat;
 import java.awt.print.PrinterJob;
 import java.beans.PropertyChangeEvent;
 import java.io.File;
-import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -147,8 +147,6 @@ import javax.swing.JInternalFrame;
 import javax.swing.JLayeredPane;
 import javax.swing.JMenu;
 import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JRadioButtonMenuItem;
 import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
 
@@ -180,7 +178,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   /**
    * Last format used to load or save alignments in this window
    */
-  String currentFileFormat = null;
+  FileFormatI currentFileFormat = null;
 
   /**
    * Current filename for this alignment
@@ -474,7 +472,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       @Override
       public void focusGained(FocusEvent e)
       {
-        Desktop.setCurrentAlignFrame(AlignFrame.this);
+        Jalview.setCurrentAlignFrame(AlignFrame.this);
       }
     });
 
@@ -489,7 +487,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param format
    *          format of file
    */
-  public void setFileName(String file, String format)
+  public void setFileName(String file, FileFormatI format)
   {
     fileName = file;
     setFileFormat(format);
@@ -674,6 +672,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           toggleHiddenRegions(toggleSeqs, toggleCols);
           break;
         }
+        case KeyEvent.VK_B:
+        {
+          boolean toggleSel = evt.isControlDown() || evt.isMetaDown();
+          boolean modifyExisting = true; // always modify, don't clear
+                                         // evt.isShiftDown();
+          boolean invertHighlighted = evt.isAltDown();
+          avc.markHighlightedColumns(invertHighlighted, modifyExisting,
+                  toggleSel);
+          break;
+        }
         case KeyEvent.VK_PAGE_UP:
           if (viewport.getWrapAlignment())
           {
@@ -848,13 +856,40 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     conservationMenuItem.setEnabled(!nucleotide);
     modifyConservation.setEnabled(!nucleotide);
     showGroupConservation.setEnabled(!nucleotide);
+
+    /*
+     * enable / disable colour schemes
+     * - the old, simple way (based on the nucleotide flag), or
+     * - the new, generic way (interrogate the colour scheme)
+     */
+    AlignmentI al = getViewport().getAlignment();
+    clustalColour.setEnabled(!nucleotide);
+    zappoColour.setEnabled(!nucleotide);
+    taylorColour.setEnabled(!nucleotide);
+    hydrophobicityColour.setEnabled(!nucleotide);
+    helixColour.setEnabled(!nucleotide);
+    strandColour.setEnabled(!nucleotide);
+    turnColour.setEnabled(!nucleotide);
+    // buriedColour.setEnabled(!nucleotide);
+    // TODO make isApplicableTo static in ColourSchemeI in Java 8
+    buriedColour.setEnabled(new BuriedColourScheme().isApplicableTo(al));
     rnahelicesColour.setEnabled(nucleotide);
-    purinePyrimidineColour.setEnabled(nucleotide);
-    showComplementMenuItem.setText(MessageManager
-            .getString(nucleotide ? "label.protein" : "label.nucleotide"));
-    setColourSelected(jalview.bin.Cache.getDefault(
+    nucleotideColour.setEnabled(nucleotide);
+    // purinePyrimidineColour.setEnabled(nucleotide);
+    purinePyrimidineColour.setEnabled(new PurinePyrimidineColourScheme()
+            .isApplicableTo(al));
+    tcoffeeColour
+            .setEnabled(new TCoffeeColourScheme(al).isApplicableTo(al));
+    RNAInteractionColour.setEnabled(nucleotide);
+    showComplementMenuItem.setText(nucleotide ? MessageManager
+            .getString("label.protein") : MessageManager
+            .getString("label.nucleotide"));
+
+    String selectedColourScheme = Cache.getDefault(
             nucleotide ? Preferences.DEFAULT_COLOUR_NUC
-                    : Preferences.DEFAULT_COLOUR_PROT, "None"));
+                    : Preferences.DEFAULT_COLOUR_PROT,
+            ResidueColourScheme.NONE);
+    setColourSelected(selectedColourScheme);
   }
 
   /**
@@ -917,12 +952,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     autoCalculate.setSelected(av.autoCalculateConsensus);
     sortByTree.setSelected(av.sortByTree);
     listenToViewSelections.setSelected(av.followSelection);
-    rnahelicesColour.setEnabled(av.getAlignment().hasRNAStructure());
+    // rnahelicesColour.setEnabled(av.getAlignment().hasRNAStructure());
+    rnahelicesColour.setEnabled(new RNAHelicesColour(av.getAlignment())
+            .isApplicableTo(av.getAlignment()));
     rnahelicesColour
             .setSelected(av.getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);
 
     showProducts.setEnabled(canShowProducts());
-    setGroovyEnabled(Desktop.instance.getGroovyConsole() != null);
+    setGroovyEnabled(Desktop.getGroovyConsole() != null);
 
     updateEditMenuBar();
   }
@@ -1007,7 +1044,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // originating file's format
       // TODO: work out how to recover feature settings for correct view(s) when
       // file is reloaded.
-      if (currentFileFormat.equals("Jalview"))
+      if (FileFormat.Jalview.equals(currentFileFormat))
       {
         JInternalFrame[] frames = Desktop.desktop.getAllFrames();
         for (int i = 0; i < frames.length; i++)
@@ -1029,7 +1066,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         Desktop.instance.closeAssociatedWindows();
 
         FileLoader loader = new FileLoader();
-        String protocol = fileName.startsWith("http:") ? "URL" : "File";
+        DataSourceType protocol = fileName.startsWith("http:") ? DataSourceType.URL
+                : DataSourceType.FILE;
         loader.LoadFile(viewport, fileName, protocol, currentFileFormat);
       }
       else
@@ -1037,7 +1075,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         Rectangle bounds = this.getBounds();
 
         FileLoader loader = new FileLoader();
-        String protocol = fileName.startsWith("http:") ? "URL" : "File";
+        DataSourceType protocol = fileName.startsWith("http:") ? DataSourceType.URL
+                : DataSourceType.FILE;
         AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,
                 protocol, currentFileFormat);
 
@@ -1081,9 +1120,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void save_actionPerformed(ActionEvent e)
   {
-    if (fileName == null
-            || (currentFileFormat == null || !jalview.io.FormatAdapter
-                    .isValidIOFormat(currentFileFormat, true))
+    if (fileName == null || (currentFileFormat == null)
             || fileName.startsWith("http"))
     {
       saveAs_actionPerformed(null);
@@ -1103,11 +1140,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void saveAs_actionPerformed(ActionEvent e)
   {
-    JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
-            jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS,
-            jalview.io.AppletFormatAdapter.WRITABLE_FNAMES,
-            currentFileFormat, false);
+    String format = currentFileFormat == null ? null : currentFileFormat
+            .toString();
+    JalviewFileChooser chooser = JalviewFileChooser.forWrite(
+            Cache.getProperty("LAST_DIRECTORY"), format);
 
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(MessageManager
@@ -1121,14 +1157,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       currentFileFormat = chooser.getSelectedFormat();
       while (currentFileFormat == null)
       {
-        JOptionPane
+        JvOptionPane
                 .showInternalMessageDialog(
                         Desktop.desktop,
                         MessageManager
                                 .getString("label.select_file_format_before_saving"),
                         MessageManager
                                 .getString("label.file_format_not_specified"),
-                        JOptionPane.WARNING_MESSAGE);
+                        JvOptionPane.WARNING_MESSAGE);
         currentFileFormat = chooser.getSelectedFormat();
         value = chooser.showSaveDialog(this);
         if (value != JalviewFileChooser.APPROVE_OPTION)
@@ -1139,24 +1175,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       fileName = chooser.getSelectedFile().getPath();
 
-      jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",
-              currentFileFormat);
+      Cache.setProperty("DEFAULT_FILE_FORMAT",
+              currentFileFormat.toString());
 
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);
-      if (currentFileFormat.indexOf(" ") > -1)
-      {
-        currentFileFormat = currentFileFormat.substring(0,
-                currentFileFormat.indexOf(" "));
-      }
+      Cache.setProperty("LAST_DIRECTORY", fileName);
       saveAlignment(fileName, currentFileFormat);
     }
   }
 
-  public boolean saveAlignment(String file, String format)
+  public boolean saveAlignment(String file, FileFormatI format)
   {
     boolean success = true;
 
-    if (format.equalsIgnoreCase("Jalview"))
+    if (FileFormat.Jalview.equals(format))
     {
       String shortName = title;
 
@@ -1175,16 +1206,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     else
     {
-      if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
-      {
-        warningMessage("Cannot save file " + fileName + " using format "
-                + format, "Alignment output format not supported");
-        if (!Jalview.isHeadlessMode())
-        {
-          saveAs_actionPerformed(null);
-        }
-        return false;
-      }
+      // if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
+      // {
+      // warningMessage("Cannot save file " + fileName + " using format "
+      // + format, "Alignment output format not supported");
+      // if (!Jalview.isHeadlessMode())
+      // {
+      // saveAs_actionPerformed(null);
+      // }
+      // return false;
+      // }
 
       AlignmentExportData exportData = getAlignmentForExport(format,
               viewport, null);
@@ -1229,11 +1260,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (!success)
     {
-      JOptionPane.showInternalMessageDialog(this, MessageManager
+      JvOptionPane.showInternalMessageDialog(this, MessageManager
               .formatMessage("label.couldnt_save_file",
                       new Object[] { fileName }), MessageManager
               .getString("label.error_saving_file"),
-              JOptionPane.WARNING_MESSAGE);
+              JvOptionPane.WARNING_MESSAGE);
     }
 
     return success;
@@ -1248,8 +1279,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     else
     {
-      JOptionPane.showInternalMessageDialog(this, warning, title,
-              JOptionPane.WARNING_MESSAGE);
+      JvOptionPane.showInternalMessageDialog(this, warning, title,
+              JvOptionPane.WARNING_MESSAGE);
     }
     return;
   }
@@ -1264,8 +1295,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void outputText_actionPerformed(ActionEvent e)
   {
 
-    AlignmentExportData exportData = getAlignmentForExport(
-            e.getActionCommand(), viewport, null);
+    FileFormatI fileFormat = FileFormat.forName(e.getActionCommand());
+    AlignmentExportData exportData = getAlignmentForExport(fileFormat,
+            viewport, null);
     if (exportData.getSettings().isCancelled())
     {
       return;
@@ -1274,8 +1306,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     cap.setForInput(null);
     try
     {
+      FileFormatI format = fileFormat;
       cap.setText(new FormatAdapter(alignPanel, exportData.getSettings())
-              .formatSequences(e.getActionCommand(),
+              .formatSequences(format,
                       exportData.getAlignment(),
                       exportData.getOmitHidden(),
                       exportData.getStartEndPostions(),
@@ -1292,7 +1325,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   public static AlignmentExportData getAlignmentForExport(
-          String exportFormat, AlignViewportI viewport,
+          FileFormatI format, AlignViewportI viewport,
           AlignExportSettingI exportSettings)
   {
     AlignmentI alignmentToExport = null;
@@ -1308,13 +1341,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (settings == null)
     {
       settings = new AlignExportSettings(hasHiddenSeqs,
-              viewport.hasHiddenColumns(), exportFormat);
+              viewport.hasHiddenColumns(), format);
     }
     // settings.isExportAnnotations();
 
     if (viewport.hasHiddenColumns() && !settings.isExportHiddenColumns())
     {
-      omitHidden = viewport.getViewAsString(false);
+      omitHidden = viewport.getViewAsString(false,
+              settings.isExportHiddenSequences());
     }
 
     int[] alignmentStartEnd = new int[2];
@@ -1325,17 +1359,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     else
     {
       alignmentToExport = viewport.getAlignment();
-      alignmentStartEnd = viewport.getAlignment()
-              .getVisibleStartAndEndIndex(
-                      viewport
-              .getColumnSelection().getHiddenColumns());
     }
+    alignmentStartEnd = alignmentToExport
+            .getVisibleStartAndEndIndex(viewport.getColumnSelection()
+                    .getHiddenColumns());
     AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
             omitHidden, alignmentStartEnd, settings);
     return ed;
   }
 
-
   /**
    * DOCUMENT ME!
    * 
@@ -1345,14 +1377,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void htmlMenuItem_actionPerformed(ActionEvent e)
   {
-    new HtmlSvgOutput(null, alignPanel);
+    HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel);
+    htmlSVG.exportHTML(null);
   }
 
   @Override
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
-    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel, this);
-    bjs.exportJalviewAlignmentAsBioJsHtmlFile();
+    BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
+    bjs.exportHTML(null);
   }
 
   public void createImageMap(File file, String image)
@@ -1866,7 +1899,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       omitHidden = viewport.getViewAsString(true);
     }
 
-    String output = new FormatAdapter().formatSequences("Fasta", seqs,
+    String output = new FormatAdapter().formatSequences(FileFormat.Fasta,
+            seqs,
             omitHidden, null);
 
     StringSelection ss = new StringSelection(output);
@@ -1953,7 +1987,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         return;
       }
 
-      String str, format;
+      String str;
+      FileFormatI format;
       try
       {
         str = (String) contents.getTransferData(DataFlavor.stringFlavor);
@@ -1962,7 +1997,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           return;
         }
 
-        format = new IdentifyFile().identify(str, "Paste");
+        format = new IdentifyFile().identify(str, DataSourceType.PASTE);
 
       } catch (OutOfMemoryError er)
       {
@@ -1992,7 +2027,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       else
       {
         // parse the clipboard as an alignment.
-        alignment = new FormatAdapter().readFile(str, "Paste", format);
+        alignment = new FormatAdapter().readFile(str, DataSourceType.PASTE,
+                format);
         sequences = alignment.getSequencesArray();
       }
 
@@ -2361,13 +2397,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               .getAlignment().getWidth()) ? true : false;
       if (isEntireAlignWidth)
       {
-        int confirm = JOptionPane.showConfirmDialog(this,
+        int confirm = JvOptionPane.showConfirmDialog(this,
                 MessageManager.getString("warn.delete_all"), // $NON-NLS-1$
                 MessageManager.getString("label.delete_all"), // $NON-NLS-1$
-                JOptionPane.OK_CANCEL_OPTION);
+                JvOptionPane.OK_CANCEL_OPTION);
 
-        if (confirm == JOptionPane.CANCEL_OPTION
-                || confirm == JOptionPane.CLOSED_OPTION)
+        if (confirm == JvOptionPane.CANCEL_OPTION
+                || confirm == JvOptionPane.CLOSED_OPTION)
         {
           return;
         }
@@ -2436,7 +2472,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
     viewport.setSelectionGroup(sg);
     viewport.sendSelection();
-    alignPanel.paintAlignment(true);
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
+    alignPanel.paintAlignment(false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
   }
 
@@ -2459,7 +2498,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setSelectionGroup(null);
     alignPanel.getSeqPanel().seqCanvas.highlightSearchResults(null);
     alignPanel.getIdPanel().getIdCanvas().searchResults = null;
-    alignPanel.paintAlignment(true);
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
+    alignPanel.paintAlignment(false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2486,6 +2528,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
     }
+    // JAL-2034 - should delegate to
+    // alignPanel to decide if overview needs
+    // updating.
 
     alignPanel.paintAlignment(true);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
@@ -2833,7 +2878,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void expandViews_actionPerformed(ActionEvent e)
   {
-    Desktop.instance.explodeViews(this);
+    Desktop.explodeViews(this);
   }
 
   /**
@@ -2903,8 +2948,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setFollowHighlight(state);
     if (state)
     {
-      alignPanel.scrollToPosition(
-              alignPanel.getSeqPanel().seqCanvas.searchResults, false);
+      alignPanel.scrollToPosition(viewport.getSearchResults(), false);
     }
   }
 
@@ -2974,9 +3018,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // Hide everything by the current selection - this is a hack - we do the
       // invert and then hide
       // first check that there will be visible columns after the invert.
-      if ((viewport.getColumnSelection() != null
-              && viewport.getColumnSelection().getSelected() != null && viewport
-              .getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns()
               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
                       .getEndRes()))
       {
@@ -3004,8 +3046,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         hideSelSequences_actionPerformed(null);
         hide = true;
       }
-      else if (!(toggleCols && viewport.getColumnSelection().getSelected()
-              .size() > 0))
+      else if (!(toggleCols && viewport.hasSelectedColumns()))
       {
         showAllSeqs_actionPerformed(null);
       }
@@ -3013,7 +3054,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (toggleCols)
     {
-      if (viewport.getColumnSelection().getSelected().size() > 0)
+      if (viewport.hasSelectedColumns())
       {
         hideSelColumns_actionPerformed(null);
         if (!toggleSeqs)
@@ -3212,30 +3253,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * Set or clear 'Show Sequence Features'
-   * 
-   * @param evt
-   *          DOCUMENT ME!
-   */
-  @Override
-  public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
-  {
-    viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
-            .isSelected());
-    if (viewport.isShowSequenceFeaturesHeight())
-    {
-      // ensure we're actually displaying features
-      viewport.setShowSequenceFeatures(true);
-      showSeqFeatures.setSelected(true);
-    }
-    alignPanel.paintAlignment(true);
-    if (alignPanel.getOverviewPanel() != null)
-    {
-      alignPanel.getOverviewPanel().updateOverviewImage();
-    }
-  }
-
-  /**
    * Action on toggle of the 'Show annotations' menu item. This shows or hides
    * the annotations panel as a whole.
    * 
@@ -3309,7 +3326,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   @Override
-  public void textColour_actionPerformed(ActionEvent e)
+  public void textColour_actionPerformed()
   {
     new TextColourChooser().chooseColour(alignPanel, null);
   }
@@ -3321,7 +3338,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  protected void noColourmenuItem_actionPerformed(ActionEvent e)
+  protected void noColourmenuItem_actionPerformed()
   {
     changeColour(null);
   }
@@ -3333,7 +3350,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void clustalColour_actionPerformed(ActionEvent e)
+  public void clustalColour_actionPerformed()
   {
     changeColour(new ClustalxColourScheme(viewport.getAlignment(),
             viewport.getHiddenRepSequences()));
@@ -3346,7 +3363,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void zappoColour_actionPerformed(ActionEvent e)
+  public void zappoColour_actionPerformed()
   {
     changeColour(new ZappoColourScheme());
   }
@@ -3358,7 +3375,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void taylorColour_actionPerformed(ActionEvent e)
+  public void taylorColour_actionPerformed()
   {
     changeColour(new TaylorColourScheme());
   }
@@ -3370,7 +3387,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void hydrophobicityColour_actionPerformed(ActionEvent e)
+  public void hydrophobicityColour_actionPerformed()
   {
     changeColour(new HydrophobicColourScheme());
   }
@@ -3382,7 +3399,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void helixColour_actionPerformed(ActionEvent e)
+  public void helixColour_actionPerformed()
   {
     changeColour(new HelixColourScheme());
   }
@@ -3394,7 +3411,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void strandColour_actionPerformed(ActionEvent e)
+  public void strandColour_actionPerformed()
   {
     changeColour(new StrandColourScheme());
   }
@@ -3406,7 +3423,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void turnColour_actionPerformed(ActionEvent e)
+  public void turnColour_actionPerformed()
   {
     changeColour(new TurnColourScheme());
   }
@@ -3418,7 +3435,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void buriedColour_actionPerformed(ActionEvent e)
+  public void buriedColour_actionPerformed()
   {
     changeColour(new BuriedColourScheme());
   }
@@ -3430,25 +3447,25 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void nucleotideColour_actionPerformed(ActionEvent e)
+  public void nucleotideColour_actionPerformed()
   {
     changeColour(new NucleotideColourScheme());
   }
 
   @Override
-  public void purinePyrimidineColour_actionPerformed(ActionEvent e)
+  public void purinePyrimidineColour_actionPerformed()
   {
     changeColour(new PurinePyrimidineColourScheme());
   }
 
   /*
-   * public void covariationColour_actionPerformed(ActionEvent e) {
+   * public void covariationColour_actionPerformed() {
    * changeColour(new
    * CovariationColourScheme(viewport.getAlignment().getAlignmentAnnotation
    * ()[0])); }
    */
   @Override
-  public void annotationColour_actionPerformed(ActionEvent e)
+  public void annotationColour_actionPerformed()
   {
     new AnnotationColourChooser(viewport, alignPanel);
   }
@@ -3460,7 +3477,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   @Override
-  public void rnahelicesColour_actionPerformed(ActionEvent e)
+  public void rnahelicesColour_actionPerformed()
   {
     new RNAHelicesColourChooser(viewport, alignPanel);
   }
@@ -3468,11 +3485,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   /**
    * DOCUMENT ME!
    * 
-   * @param e
-   *          DOCUMENT ME!
    */
   @Override
-  protected void applyToAllGroups_actionPerformed(ActionEvent e)
+  protected void applyToAllGroups_actionPerformed()
   {
     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
   }
@@ -3522,7 +3537,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  protected void modifyPID_actionPerformed(ActionEvent e)
+  protected void modifyPID_actionPerformed()
   {
     if (viewport.getAbovePIDThreshold()
             && viewport.getGlobalColourScheme() != null)
@@ -3540,7 +3555,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  protected void modifyConservation_actionPerformed(ActionEvent e)
+  protected void modifyConservation_actionPerformed()
   {
     if (viewport.getConservationSelected()
             && viewport.getGlobalColourScheme() != null)
@@ -3558,7 +3573,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  protected void conservationMenuItem_actionPerformed(ActionEvent e)
+  protected void conservationMenuItem_actionPerformed()
   {
     viewport.setConservationSelected(conservationMenuItem.isSelected());
 
@@ -3567,7 +3582,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     changeColour(viewport.getGlobalColourScheme());
 
-    modifyConservation_actionPerformed(null);
+    modifyConservation_actionPerformed();
   }
 
   /**
@@ -3577,7 +3592,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void abovePIDThreshold_actionPerformed(ActionEvent e)
+  public void abovePIDThreshold_actionPerformed()
   {
     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
 
@@ -3586,7 +3601,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     changeColour(viewport.getGlobalColourScheme());
 
-    modifyPID_actionPerformed(null);
+    modifyPID_actionPerformed();
   }
 
   /**
@@ -3605,89 +3620,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     else
     {
-      UserColourScheme udc = (UserColourScheme) UserDefinedColours
+      UserColourScheme udc = UserDefinedColours
               .getUserColourSchemes().get(e.getActionCommand());
 
       changeColour(udc);
     }
   }
 
-  public void updateUserColourMenu()
-  {
-
-    Component[] menuItems = colourMenu.getMenuComponents();
-    int iSize = menuItems.length;
-    for (int i = 0; i < iSize; i++)
-    {
-      if (menuItems[i].getName() != null
-              && menuItems[i].getName().equals("USER_DEFINED"))
-      {
-        colourMenu.remove(menuItems[i]);
-        iSize--;
-      }
-    }
-    if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
-    {
-      java.util.Enumeration userColours = jalview.gui.UserDefinedColours
-              .getUserColourSchemes().keys();
-
-      while (userColours.hasMoreElements())
-      {
-        final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(
-                userColours.nextElement().toString());
-        radioItem.setName("USER_DEFINED");
-        radioItem.addMouseListener(new MouseAdapter()
-        {
-          @Override
-          public void mousePressed(MouseEvent evt)
-          {
-            if (evt.isControlDown()
-                    || SwingUtilities.isRightMouseButton(evt))
-            {
-              radioItem.removeActionListener(radioItem.getActionListeners()[0]);
-
-              int option = JOptionPane.showInternalConfirmDialog(
-                      jalview.gui.Desktop.desktop,
-                      MessageManager
-                              .getString("label.remove_from_default_list"),
-                      MessageManager
-                              .getString("label.remove_user_defined_colour"),
-                      JOptionPane.YES_NO_OPTION);
-              if (option == JOptionPane.YES_OPTION)
-              {
-                jalview.gui.UserDefinedColours
-                        .removeColourFromDefaults(radioItem.getText());
-                colourMenu.remove(radioItem);
-              }
-              else
-              {
-                radioItem.addActionListener(new ActionListener()
-                {
-                  @Override
-                  public void actionPerformed(ActionEvent evt)
-                  {
-                    userDefinedColour_actionPerformed(evt);
-                  }
-                });
-              }
-            }
-          }
-        });
-        radioItem.addActionListener(new ActionListener()
-        {
-          @Override
-          public void actionPerformed(ActionEvent evt)
-          {
-            userDefinedColour_actionPerformed(evt);
-          }
-        });
-
-        colourMenu.insert(radioItem, 15);
-        colours.add(radioItem);
-      }
-    }
-  }
-
   /**
    * DOCUMENT ME!
    * 
@@ -3695,7 +3634,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void PIDColour_actionPerformed(ActionEvent e)
+  public void PIDColour_actionPerformed()
   {
     changeColour(new PIDColourScheme());
   }
@@ -3707,7 +3646,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  public void BLOSUM62Colour_actionPerformed(ActionEvent e)
+  public void BLOSUM62Colour_actionPerformed()
   {
     changeColour(new Blosum62ColourScheme());
   }
@@ -3802,10 +3741,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if ((viewport.getSelectionGroup() == null)
             || (viewport.getSelectionGroup().getSize() < 2))
     {
-      JOptionPane.showInternalMessageDialog(this, MessageManager
+      JvOptionPane.showInternalMessageDialog(this, MessageManager
               .getString("label.you_must_select_least_two_sequences"),
               MessageManager.getString("label.invalid_selection"),
-              JOptionPane.WARNING_MESSAGE);
+              JvOptionPane.WARNING_MESSAGE);
     }
     else
     {
@@ -3831,14 +3770,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             .getSelectionGroup().getSize() > 0))
             || (viewport.getAlignment().getHeight() < 4))
     {
-      JOptionPane
+      JvOptionPane
               .showInternalMessageDialog(
                       this,
                       MessageManager
                               .getString("label.principal_component_analysis_must_take_least_four_input_sequences"),
                       MessageManager
                               .getString("label.sequence_selection_insufficient"),
-                      JOptionPane.WARNING_MESSAGE);
+                      JvOptionPane.WARNING_MESSAGE);
 
       return;
     }
@@ -3936,14 +3875,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       if (viewport.getSelectionGroup().getSize() < 3)
       {
-        JOptionPane
+        JvOptionPane
                 .showMessageDialog(
                         Desktop.desktop,
                         MessageManager
                                 .getString("label.you_need_more_two_sequences_selected_build_tree"),
                         MessageManager
                                 .getString("label.not_enough_sequences"),
-                        JOptionPane.WARNING_MESSAGE);
+                        JvOptionPane.WARNING_MESSAGE);
         return;
       }
 
@@ -3954,14 +3893,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         if (_s.getLength() < sg.getEndRes())
         {
-          JOptionPane
+          JvOptionPane
                   .showMessageDialog(
                           Desktop.desktop,
                           MessageManager
                                   .getString("label.selected_region_to_tree_may_only_contain_residues_or_gaps"),
                           MessageManager
                                   .getString("label.sequences_selection_not_aligned"),
-                          JOptionPane.WARNING_MESSAGE);
+                          JvOptionPane.WARNING_MESSAGE);
 
           return;
         }
@@ -3975,14 +3914,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // are the visible sequences aligned?
       if (!viewport.getAlignment().isAligned(false))
       {
-        JOptionPane
+        JvOptionPane
                 .showMessageDialog(
                         Desktop.desktop,
                         MessageManager
                                 .getString("label.sequences_must_be_aligned_before_creating_tree"),
                         MessageManager
                                 .getString("label.sequences_not_aligned"),
-                        JOptionPane.WARNING_MESSAGE);
+                        JvOptionPane.WARNING_MESSAGE);
 
         return;
       }
@@ -4247,11 +4186,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     else if (viewport.getSelectionGroup() != null
             && viewport.getSelectionGroup().getSize() == 1)
     {
-      int option = JOptionPane.showConfirmDialog(this,
+      int option = JvOptionPane.showConfirmDialog(this,
               MessageManager.getString("warn.oneseq_msainput_selection"),
               MessageManager.getString("label.invalid_selection"),
-              JOptionPane.OK_CANCEL_OPTION);
-      if (option == JOptionPane.OK_OPTION)
+              JvOptionPane.OK_CANCEL_OPTION);
+      if (option == JvOptionPane.OK_OPTION)
       {
         msa = viewport.getAlignmentView(false);
       }
@@ -4323,31 +4262,31 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       jalview.io.NewickFile fin = null;
       try
       {
-        fin = new jalview.io.NewickFile(choice, "File");
+        fin = new NewickFile(choice, DataSourceType.FILE);
         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
       } catch (Exception ex)
       {
-        JOptionPane
+        JvOptionPane
                 .showMessageDialog(
                         Desktop.desktop,
                         ex.getMessage(),
                         MessageManager
                                 .getString("label.problem_reading_tree_file"),
-                        JOptionPane.WARNING_MESSAGE);
+                        JvOptionPane.WARNING_MESSAGE);
         ex.printStackTrace();
       }
       if (fin != null && fin.hasWarningMessage())
       {
-        JOptionPane.showMessageDialog(Desktop.desktop, fin
+        JvOptionPane.showMessageDialog(Desktop.desktop, fin
                 .getWarningMessage(), MessageManager
                 .getString("label.possible_problem_with_tree_file"),
-                JOptionPane.WARNING_MESSAGE);
+                JvOptionPane.WARNING_MESSAGE);
       }
     }
   }
 
   @Override
-  protected void tcoffeeColorScheme_actionPerformed(ActionEvent e)
+  protected void tcoffeeColorScheme_actionPerformed()
   {
     changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
   }
@@ -4461,22 +4400,18 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           // object broker mechanism.
           final Vector<JMenu> wsmenu = new Vector<JMenu>();
           final IProgressIndicator af = me;
+
+          /*
+           * do not i18n these strings - they are hard-coded in class
+           * compbio.data.msa.Category, Jws2Discoverer.isRecalculable() and
+           * SequenceAnnotationWSClient.initSequenceAnnotationWSClient()
+           */
           final JMenu msawsmenu = new JMenu("Alignment");
           final JMenu secstrmenu = new JMenu(
                   "Secondary Structure Prediction");
           final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
           final JMenu analymenu = new JMenu("Analysis");
           final JMenu dismenu = new JMenu("Protein Disorder");
-          // final JMenu msawsmenu = new
-          // JMenu(MessageManager.getString("label.alignment"));
-          // final JMenu secstrmenu = new
-          // JMenu(MessageManager.getString("label.secondary_structure_prediction"));
-          // final JMenu seqsrchmenu = new
-          // JMenu(MessageManager.getString("label.sequence_database_search"));
-          // final JMenu analymenu = new
-          // JMenu(MessageManager.getString("label.analysis"));
-          // final JMenu dismenu = new
-          // JMenu(MessageManager.getString("label.protein_disorder"));
           // JAL-940 - only show secondary structure prediction services from
           // the legacy server
           if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
@@ -4636,38 +4571,45 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * Searches selected sequences for xRef products and builds the Show
-   * Cross-References menu (formerly called Show Products)
+   * Searches the alignment sequences for xRefs and builds the Show
+   * Cross-References menu (formerly called Show Products), with database
+   * sources for which cross-references are found (protein sources for a
+   * nucleotide alignment and vice versa)
    * 
-   * @return true if Show Cross-references menu should be enabled.
+   * @return true if Show Cross-references menu should be enabled
    */
   public boolean canShowProducts()
   {
-    SequenceI[] selection = viewport.getSequenceSelection();
+    SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
     AlignmentI dataset = viewport.getAlignment().getDataset();
+
+    showProducts.removeAll();
+    final boolean dna = viewport.getAlignment().isNucleotide();
+
+    if (seqs == null || seqs.length == 0)
+    {
+      // nothing to see here.
+      return false;
+    }
+
     boolean showp = false;
     try
     {
-      showProducts.removeAll();
-      final boolean dna = viewport.getAlignment().isNucleotide();
-      String[] ptypes = (selection == null || selection.length == 0) ? null
-              : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
+      List<String> ptypes = new CrossRef(seqs, dataset)
+              .findXrefSourcesForSequences(dna);
 
-      for (int t = 0; ptypes != null && t < ptypes.length; t++)
+      for (final String source : ptypes)
       {
         showp = true;
         final AlignFrame af = this;
-        final String source = ptypes[t];
-        JMenuItem xtype = new JMenuItem(ptypes[t]);
+        JMenuItem xtype = new JMenuItem(source);
         xtype.addActionListener(new ActionListener()
         {
-
           @Override
           public void actionPerformed(ActionEvent e)
           {
             showProductsFor(af.viewport.getSequenceSelection(), dna, source);
           }
-
         });
         showProducts.add(xtype);
       }
@@ -4675,7 +4617,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       showProducts.setEnabled(showp);
     } catch (Exception e)
     {
-      jalview.bin.Cache.log
+      Cache.log
               .warn("canShowProducts threw an exception - please report to help@jalview.org",
                       e);
       return false;
@@ -4683,228 +4625,22 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return showp;
   }
 
-  protected void showProductsFor(final SequenceI[] sel, final boolean dna,
-          final String source)
+  /**
+   * Finds and displays cross-references for the selected sequences (protein
+   * products for nucleotide sequences, dna coding sequences for peptides).
+   * 
+   * @param sel
+   *          the sequences to show cross-references for
+   * @param dna
+   *          true if from a nucleotide alignment (so showing proteins)
+   * @param source
+   *          the database to show cross-references for
+   */
+  protected void showProductsFor(final SequenceI[] sel,
+          final boolean _odna, final String source)
   {
-    Runnable foo = new Runnable()
-    {
-
-      @Override
-      public void run()
-      {
-        final long sttime = System.currentTimeMillis();
-        AlignFrame.this.setProgressBar(MessageManager.formatMessage(
-                "status.searching_for_sequences_from",
-                new Object[] { source }), sttime);
-        try
-        {
-          AlignmentI alignment = AlignFrame.this.getViewport()
-                  .getAlignment();
-          AlignmentI xrefs = CrossRef.findXrefSequences(sel, dna, source,
-                  alignment);
-          if (xrefs != null)
-          {
-            /*
-             * get display scheme (if any) to apply to features
-             */
-            FeatureSettingsModelI featureColourScheme = new SequenceFetcher()
-                    .getFeatureColourScheme(source);
-
-            AlignmentI al = makeCrossReferencesAlignment(
-                    alignment.getDataset(), xrefs);
-
-            AlignFrame newFrame = new AlignFrame(al, DEFAULT_WIDTH,
-                    DEFAULT_HEIGHT);
-            String newtitle = String.format("%s %s %s",
-                    MessageManager.getString(dna ? "label.proteins"
-                            : "label.nucleotides"), MessageManager
-                            .getString("label.for"), getTitle());
-            newFrame.setTitle(newtitle);
-
-            if (!Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
-            {
-              /*
-               * split frame display is turned off in preferences file
-               */
-              Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH,
-                      DEFAULT_HEIGHT);
-              return; // via finally clause
-            }
-
-            /*
-             * Make a copy of this alignment (sharing the same dataset
-             * sequences). If we are DNA, drop introns and update mappings
-             */
-            AlignmentI copyAlignment = null;
-            final SequenceI[] sequenceSelection = AlignFrame.this.viewport
-                    .getSequenceSelection();
-            List<AlignedCodonFrame> cf = xrefs.getCodonFrames();
-            boolean copyAlignmentIsAligned = false;
-            if (dna)
-            {
-              copyAlignment = AlignmentUtils.makeCdsAlignment(
-                      sequenceSelection, cf, alignment);
-              if (copyAlignment.getHeight() == 0)
-              {
-                System.err.println("Failed to make CDS alignment");
-              }
-              al.getCodonFrames().clear();
-              al.getCodonFrames().addAll(copyAlignment.getCodonFrames());
-
-              /*
-               * pending getting Embl transcripts to 'align', 
-               * we are only doing this for Ensembl
-               */
-              // TODO proper criteria for 'can align as cdna'
-              if (DBRefSource.ENSEMBL.equalsIgnoreCase(source)
-                      || AlignmentUtils.looksLikeEnsembl(alignment))
-              {
-                copyAlignment.alignAs(alignment);
-                copyAlignmentIsAligned = true;
-              }
-            }
-            else
-            {
-              copyAlignment = AlignmentUtils.makeCopyAlignment(
-                      sequenceSelection, xrefs.getSequencesArray());
-              copyAlignment.getCodonFrames().addAll(cf);
-            }
-            copyAlignment.setGapCharacter(AlignFrame.this.viewport
-                    .getGapCharacter());
-
-            StructureSelectionManager ssm = StructureSelectionManager
-                    .getStructureSelectionManager(Desktop.instance);
-            ssm.registerMappings(cf);
-
-            if (copyAlignment.getHeight() <= 0)
-            {
-              System.err.println("No Sequences generated for xRef type "
-                      + source);
-              return;
-            }
-            /*
-             * align protein to dna
-             */
-            if (dna && copyAlignmentIsAligned)
-            {
-              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();
-          }
-        } catch (Exception e)
-        {
-          Cache.log.error(
-                  "Exception when finding crossreferences", e);
-        } catch (OutOfMemoryError e)
-        {
-          new OOMWarning("whilst fetching crossreferences", e);
-        } catch (Throwable e)
-        {
-          Cache.log.error("Error when finding crossreferences",
-                  e);
-        } finally
-        {
-          AlignFrame.this.setProgressBar(MessageManager.formatMessage(
-                  "status.finished_searching_for_sequences_from",
-                  new Object[] { source }), sttime);
-        }
-      }
-
-      /**
-       * Makes an alignment containing the given sequences. If this is of the
-       * same type as the given dataset (nucleotide/protein), then the new
-       * alignment shares the same dataset, and its dataset sequences are added
-       * to it. Otherwise a new dataset sequence is created for the
-       * cross-references.
-       * 
-       * @param dataset
-       * @param seqs
-       * @return
-       */
-      protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset,
-              AlignmentI seqs)
-      {
-        boolean sameType = dataset.isNucleotide() == seqs.isNucleotide();
-
-        SequenceI[] sprods = new SequenceI[seqs.getHeight()];
-        for (int s = 0; s < sprods.length; s++)
-        {
-          sprods[s] = (seqs.getSequenceAt(s)).deriveSequence();
-          if (sameType)
-          {
-            if (dataset.getSequences() == null
-                    || !dataset.getSequences().contains(
-                            sprods[s].getDatasetSequence()))
-            {
-              dataset.addSequence(sprods[s].getDatasetSequence());
-            }
-          }
-          sprods[s].updatePDBIds();
-        }
-        Alignment al = new Alignment(sprods);
-        if (sameType)
-        {
-          al.setDataset((Alignment) dataset);
-        }
-        else
-        {
-          al.createDatasetAlignment();
-        }
-        return al;
-      }
-
-    };
-    Thread frunner = new Thread(foo);
-    frunner.start();
+    new Thread(CrossRefAction.showProductsFor(sel, _odna, source, this))
+            .start();
   }
 
   /**
@@ -4928,9 +4664,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               .getString("label.error_when_translating_sequences_submit_bug_report");
       final String errorTitle = MessageManager
               .getString("label.implementation_error")
-              + MessageManager.getString("translation_failed");
-      JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
-              JOptionPane.ERROR_MESSAGE);
+              + MessageManager.getString("label.translation_failed");
+      JvOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
+              JvOptionPane.ERROR_MESSAGE);
       return;
     }
     if (al == null || al.getHeight() == 0)
@@ -4939,8 +4675,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               .getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation");
       final String errorTitle = MessageManager
               .getString("label.translation_failed");
-      JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
-              JOptionPane.WARNING_MESSAGE);
+      JvOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
+              JvOptionPane.WARNING_MESSAGE);
     }
     else
     {
@@ -4966,11 +4702,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   /**
    * Set the file format
    * 
-   * @param fileFormat
+   * @param format
    */
-  public void setFileFormat(String fileFormat)
+  public void setFileFormat(FileFormatI format)
   {
-    this.currentFileFormat = fileFormat;
+    this.currentFileFormat = format;
   }
 
   /**
@@ -4978,14 +4714,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param file
    *          contents or path to retrieve file
-   * @param type
+   * @param sourceType
    *          access mode of file (see jalview.io.AlignFile)
    * @return true if features file was parsed correctly.
    */
-  public boolean parseFeaturesFile(String file, String type)
+  public boolean parseFeaturesFile(String file, DataSourceType sourceType)
   {
-    return avc.parseFeaturesFile(file, type,
-            jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
+    return avc.parseFeaturesFile(file, sourceType,
+            Cache.getDefault("RELAXEDSEQIDMATCHING", false));
 
   }
 
@@ -5026,50 +4762,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void drop(DropTargetDropEvent evt)
   {
+    // JAL-1552 - acceptDrop required before getTransferable call for
+    // Java's Transferable for native dnd
+    evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
-    java.util.List files = null;
+    List<String> files = new ArrayList<String>();
+    List<DataSourceType> protocols = new ArrayList<DataSourceType>();
 
     try
     {
-      DataFlavor uriListFlavor = new DataFlavor(
-              "text/uri-list;class=java.lang.String");
-      if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
-      {
-        // Works on Windows and MacOSX
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        files = (java.util.List) t
-                .getTransferData(DataFlavor.javaFileListFlavor);
-      }
-      else if (t.isDataFlavorSupported(uriListFlavor))
-      {
-        // This is used by Unix drag system
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
-        String data = (String) t.getTransferData(uriListFlavor);
-        files = new java.util.ArrayList(1);
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(
-                data, "\r\n"); st.hasMoreTokens();)
-        {
-          String s = st.nextToken();
-          if (s.startsWith("#"))
-          {
-            // the line is a comment (as per the RFC 2483)
-            continue;
-          }
-
-          java.net.URI uri = new java.net.URI(s);
-          // check to see if we can handle this kind of URI
-          if (uri.getScheme().toLowerCase().startsWith("http"))
-          {
-            files.add(uri.toString());
-          }
-          else
-          {
-            // otherwise preserve old behaviour: catch all for file objects
-            java.io.File file = new java.io.File(uri);
-            files.add(file.toString());
-          }
-        }
-      }
+      Desktop.transferFromDropTarget(files, protocols, evt, t);
     } catch (Exception e)
     {
       e.printStackTrace();
@@ -5091,13 +4793,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         {
           String file = files.get(i).toString();
           String pdbfn = "";
-          String protocol = FormatAdapter.checkProtocol(file);
-          if (protocol == jalview.io.FormatAdapter.FILE)
+          DataSourceType protocol = FormatAdapter.checkProtocol(file);
+          if (protocol == DataSourceType.FILE)
           {
             File fl = new File(file);
             pdbfn = fl.getName();
           }
-          else if (protocol == jalview.io.FormatAdapter.URL)
+          else if (protocol == DataSourceType.URL)
           {
             URL url = new URL(file);
             pdbfn = url.getFile();
@@ -5121,7 +4823,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             }
             if (mtch != null)
             {
-              String type = null;
+              FileFormatI type = null;
               try
               {
                 type = new IdentifyFile().identify(file, protocol);
@@ -5129,13 +4831,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               {
                 type = null;
               }
-              if (type != null)
+              if (type != null && type.isStructureFile())
               {
-                if (type.equalsIgnoreCase("PDB"))
-                {
-                  filesmatched.add(new Object[] { file, protocol, mtch });
-                  continue;
-                }
+                filesmatched.add(new Object[] { file, protocol, mtch });
+                continue;
               }
             }
             // File wasn't named like one of the sequences or wasn't a PDB file.
@@ -5146,20 +4845,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         if (filesmatched.size() > 0)
         {
           if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
-                  || JOptionPane
+                  || JvOptionPane
                           .showConfirmDialog(
                                   this,
                                   MessageManager
                                           .formatMessage(
-                                                  "label.automatically_associate_pdb_files_with_sequences_same_name",
+                                                  "label.automatically_associate_structure_files_with_sequences_same_name",
                                                   new Object[] { Integer
                                                           .valueOf(
                                                                   filesmatched
                                                                           .size())
                                                           .toString() }),
                                   MessageManager
-                                          .getString("label.automatically_associate_pdb_files_by_name"),
-                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
+                                          .getString("label.automatically_associate_structure_files_by_name"),
+                                  JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION)
 
           {
             for (Object[] fm : filesmatched)
@@ -5171,7 +4870,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               {
                 PDBEntry pe = new AssociatePdbFileWithSeq()
                         .associatePdbWithSeq((String) fm[0],
-                                (String) fm[1], toassoc, false,
+                                (DataSourceType) fm[1], toassoc, false,
                                 Desktop.instance);
                 if (pe != null)
                 {
@@ -5189,7 +4888,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         {
           if (assocfiles > 0
                   && (Cache.getDefault(
-                          "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
+                          "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JvOptionPane
                           .showConfirmDialog(
                                   this,
                                   "<html>"
@@ -5204,7 +4903,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                           + "</html>",
                                   MessageManager
                                           .getString("label.ignore_unmatched_dropped_files"),
-                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
+                                  JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION))
           {
             return;
           }
@@ -5230,21 +4929,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param file
    *          either a filename or a URL string.
    */
-  public void loadJalviewDataFile(String file, String protocol,
-          String format, SequenceI assocSeq)
+  public void loadJalviewDataFile(String file, DataSourceType sourceType,
+          FileFormatI format, SequenceI assocSeq)
   {
     try
     {
-      if (protocol == null)
+      if (sourceType == null)
       {
-        protocol = FormatAdapter.checkProtocol(file);
+        sourceType = 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;
+      boolean isAnnotation = (format == null || FileFormat.Pfam
+              .equals(format)) ? new AnnotationFile()
+              .annotateAlignmentView(viewport, file, sourceType) : false;
 
       if (!isAnnotation)
       {
@@ -5252,7 +4951,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         TCoffeeScoreFile tcf = null;
         try
         {
-          tcf = new TCoffeeScoreFile(file, protocol);
+          tcf = new TCoffeeScoreFile(file, sourceType);
           if (tcf.isValid())
           {
             if (tcf.annotateAlignment(viewport.getAlignment(), true))
@@ -5269,7 +4968,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             {
               // some problem - if no warning its probable that the ID matching
               // process didn't work
-              JOptionPane
+              JvOptionPane
                       .showMessageDialog(
                               Desktop.desktop,
                               tcf.getWarningMessage() == null ? MessageManager
@@ -5277,7 +4976,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                       : tcf.getWarningMessage(),
                               MessageManager
                                       .getString("label.problem_reading_tcoffee_score_file"),
-                              JOptionPane.WARNING_MESSAGE);
+                              JvOptionPane.WARNING_MESSAGE);
             }
           }
           else
@@ -5298,12 +4997,12 @@ 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, sourceType);
           }
-          if (format.equalsIgnoreCase("JnetFile"))
+          if (FileFormat.Jnet.equals(format))
           {
-            jalview.io.JPredFile predictions = new jalview.io.JPredFile(
-                    file, protocol);
+            JPredFile predictions = new JPredFile(
+                    file, sourceType);
             new JnetAnnotationMaker();
             JnetAnnotationMaker.add_annotation(predictions,
                     viewport.getAlignment(), 0, false);
@@ -5314,16 +5013,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             viewport.setColumnSelection(cs);
             isAnnotation = true;
           }
-          else if (IdentifyFile.FeaturesFile.equals(format))
+          // else if (IdentifyFile.FeaturesFile.equals(format))
+          else if (FileFormat.Features.equals(format))
           {
-            if (parseFeaturesFile(file, protocol))
+            if (parseFeaturesFile(file, sourceType))
             {
               alignPanel.paintAlignment(true);
             }
           }
           else
           {
-            new FileLoader().LoadFile(viewport, file, protocol, format);
+            new FileLoader().LoadFile(viewport, file, sourceType, format);
           }
         }
       }
@@ -5348,8 +5048,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       }
       new OOMWarning(
               "loading data "
-                      + (protocol != null ? (protocol.equals(FormatAdapter.PASTE) ? "from clipboard."
-                              : "using " + protocol + " from " + file)
+                      + (sourceType != null ? (sourceType == DataSourceType.PASTE ? "from clipboard."
+                              : "using " + sourceType + " from " + file)
                               : ".")
                       + (format != null ? "(parsing as '" + format
                               + "' file)" : ""), oom, Desktop.desktop);
@@ -5395,11 +5095,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void tabbedPane_mousePressed(MouseEvent e)
   {
-    if (SwingUtilities.isRightMouseButton(e))
+    if (e.isPopupTrigger())
     {
       String msg = MessageManager.getString("label.enter_view_name");
-      String reply = JOptionPane.showInternalInputDialog(this, msg, msg,
-              JOptionPane.QUESTION_MESSAGE);
+      String reply = JvOptionPane.showInternalInputDialog(this, msg, msg,
+              JvOptionPane.QUESTION_MESSAGE);
 
       if (reply != null)
       {
@@ -5544,8 +5244,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 AlignFrame.this.setMenusForViewport();
               }
             });
-            dbRefFetcher
-                    .fetchDBRefs(false);
+            dbRefFetcher.fetchDBRefs(false);
           }
         }).start();
 
@@ -5986,8 +5685,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void setAnnotationsVisibility(boolean visible,
           boolean forSequences, boolean forAlignment)
   {
-    for (AlignmentAnnotation aa : alignPanel.getAlignment()
-            .getAlignmentAnnotation())
+    AlignmentAnnotation[] anns = alignPanel.getAlignment()
+            .getAlignmentAnnotation();
+    if (anns == null)
+    {
+      return;
+    }
+    for (AlignmentAnnotation aa : anns)
     {
       /*
        * don't display non-positional annotations on an alignment
@@ -6067,7 +5771,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     AlignmentI cdna = new Alignment(cdnaSeqs.toArray(new SequenceI[cdnaSeqs
             .size()]));
-    AlignFrame alignFrame = new AlignFrame(cdna, AlignFrame.DEFAULT_WIDTH,
+    GAlignFrame alignFrame = new AlignFrame(cdna, AlignFrame.DEFAULT_WIDTH,
             AlignFrame.DEFAULT_HEIGHT);
     cdna.alignAs(alignment);
     String newtitle = "cDNA " + MessageManager.getString("label.for") + " "
@@ -6103,9 +5807,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     try
     {
       Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
-
       al = dna.reverseCdna(complement);
       viewport.addAlignment(al, "");
+      addHistoryItem(new EditCommand(
+              MessageManager.getString("label.add_sequences"),
+              Action.PASTE, al.getSequencesArray(), 0, al.getWidth(),
+              viewport.getAlignment()));
     } catch (Exception ex)
     {
       System.err.println(ex.getMessage());
@@ -6121,29 +5828,22 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void runGroovy_actionPerformed()
   {
-    Desktop.setCurrentAlignFrame(this);
-    Object console = Desktop.instance.getGroovyConsole();
+    Jalview.setCurrentAlignFrame(this);
+    groovy.ui.Console console = Desktop.getGroovyConsole();
     if (console != null)
     {
-      /*
-       * use reflection here to avoid compile-time dependency
-       * on Groovy libraries
-       */
       try
       {
-        Class<?> gcClass = getClass().getClassLoader().loadClass(
-                "groovy.ui.Console");
-        Method runScript = gcClass.getMethod("runScript");
-        runScript.invoke(console);
+        console.runScript();
       } catch (Exception ex)
       {
         System.err.println((ex.toString()));
-        JOptionPane
+        JvOptionPane
                 .showInternalMessageDialog(Desktop.desktop, MessageManager
                         .getString("label.couldnt_run_groovy_script"),
                         MessageManager
                                 .getString("label.groovy_support_failed"),
-                        JOptionPane.ERROR_MESSAGE);
+                        JvOptionPane.ERROR_MESSAGE);
       }
     }
     else
@@ -6151,6 +5851,42 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       System.err.println("Can't run Groovy script as console not found");
     }
   }
+
+  /**
+   * Hides columns containing (or not containing) a specified feature, provided
+   * that would not leave all columns hidden
+   * 
+   * @param featureType
+   * @param columnsContaining
+   * @return
+   */
+  public boolean hideFeatureColumns(String featureType,
+          boolean columnsContaining)
+  {
+    boolean notForHiding = avc.markColumnsContainingFeatures(
+            columnsContaining, false, false, featureType);
+    if (notForHiding)
+    {
+      if (avc.markColumnsContainingFeatures(!columnsContaining, false,
+              false, featureType))
+      {
+        getViewport().hideSelectedColumns();
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  protected void selectHighlightedColumns_actionPerformed(
+          ActionEvent actionEvent)
+  {
+    // include key modifier check in case user selects from menu
+    avc.markHighlightedColumns(
+            (actionEvent.getModifiers() & ActionEvent.ALT_MASK) != 0,
+            true,
+            (actionEvent.getModifiers() & (ActionEvent.META_MASK | ActionEvent.CTRL_MASK)) != 0);
+  }
 }
 
 class PrintThread extends Thread