JAL-1620 version bump and release notes
[jalview.git] / src / jalview / gui / AlignFrame.java
index 4c7ae80..216db0e 100644 (file)
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)\r
- * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle\r
- * \r
- * This file is part of Jalview.\r
- * \r
- * Jalview is free software: you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License \r
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
- *  \r
- * Jalview is distributed in the hope that it will be useful, but \r
- * WITHOUT ANY WARRANTY; without even the implied warranty \r
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
- * PURPOSE.  See the GNU General Public License for more details.\r
- * \r
- * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-package jalview.gui;\r
-\r
-import jalview.analysis.AAFrequency;\r
-import jalview.analysis.AlignmentSorter;\r
-import jalview.analysis.Conservation;\r
-import jalview.analysis.CrossRef;\r
-import jalview.analysis.NJTree;\r
-import jalview.analysis.ParseProperties;\r
-import jalview.analysis.SequenceIdMatcher;\r
-import jalview.api.AlignViewControllerI;\r
-import jalview.bin.Cache;\r
-import jalview.commands.CommandI;\r
-import jalview.commands.EditCommand;\r
-import jalview.commands.OrderCommand;\r
-import jalview.commands.RemoveGapColCommand;\r
-import jalview.commands.RemoveGapsCommand;\r
-import jalview.commands.SlideSequencesCommand;\r
-import jalview.commands.TrimRegionCommand;\r
-import jalview.datamodel.AlignedCodonFrame;\r
-import jalview.datamodel.Alignment;\r
-import jalview.datamodel.AlignmentAnnotation;\r
-import jalview.datamodel.AlignmentI;\r
-import jalview.datamodel.AlignmentOrder;\r
-import jalview.datamodel.AlignmentView;\r
-import jalview.datamodel.ColumnSelection;\r
-import jalview.datamodel.PDBEntry;\r
-import jalview.datamodel.SeqCigar;\r
-import jalview.datamodel.Sequence;\r
-import jalview.datamodel.SequenceGroup;\r
-import jalview.datamodel.SequenceI;\r
-import jalview.io.AlignmentProperties;\r
-import jalview.io.AnnotationFile;\r
-import jalview.io.FeaturesFile;\r
-import jalview.io.FileLoader;\r
-import jalview.io.FormatAdapter;\r
-import jalview.io.HTMLOutput;\r
-import jalview.io.IdentifyFile;\r
-import jalview.io.JalviewFileChooser;\r
-import jalview.io.JalviewFileView;\r
-import jalview.io.JnetAnnotationMaker;\r
-import jalview.io.NewickFile;\r
-import jalview.io.TCoffeeScoreFile;\r
-import jalview.jbgui.GAlignFrame;\r
-import jalview.schemes.Blosum62ColourScheme;\r
-import jalview.schemes.BuriedColourScheme;\r
-import jalview.schemes.ClustalxColourScheme;\r
-import jalview.schemes.ColourSchemeI;\r
-import jalview.schemes.ColourSchemeProperty;\r
-import jalview.schemes.HelixColourScheme;\r
-import jalview.schemes.HydrophobicColourScheme;\r
-import jalview.schemes.NucleotideColourScheme;\r
-import jalview.schemes.PIDColourScheme;\r
-import jalview.schemes.PurinePyrimidineColourScheme;\r
-import jalview.schemes.RNAHelicesColourChooser;\r
-import jalview.schemes.ResidueProperties;\r
-import jalview.schemes.StrandColourScheme;\r
-import jalview.schemes.TCoffeeColourScheme;\r
-import jalview.schemes.TaylorColourScheme;\r
-import jalview.schemes.TurnColourScheme;\r
-import jalview.schemes.UserColourScheme;\r
-import jalview.schemes.ZappoColourScheme;\r
-import jalview.util.MessageManager;\r
-import jalview.ws.jws1.Discoverer;\r
-import jalview.ws.jws2.Jws2Discoverer;\r
-import jalview.ws.jws2.jabaws2.Jws2Instance;\r
-import jalview.ws.seqfetcher.DbSourceProxy;\r
-\r
-import java.awt.BorderLayout;\r
-import java.awt.Color;\r
-import java.awt.Component;\r
-import java.awt.GridLayout;\r
-import java.awt.Rectangle;\r
-import java.awt.Toolkit;\r
-import java.awt.datatransfer.Clipboard;\r
-import java.awt.datatransfer.DataFlavor;\r
-import java.awt.datatransfer.StringSelection;\r
-import java.awt.datatransfer.Transferable;\r
-import java.awt.dnd.DnDConstants;\r
-import java.awt.dnd.DropTargetDragEvent;\r
-import java.awt.dnd.DropTargetDropEvent;\r
-import java.awt.dnd.DropTargetEvent;\r
-import java.awt.dnd.DropTargetListener;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.ActionListener;\r
-import java.awt.event.KeyAdapter;\r
-import java.awt.event.KeyEvent;\r
-import java.awt.event.MouseAdapter;\r
-import java.awt.event.MouseEvent;\r
-import java.awt.print.PageFormat;\r
-import java.awt.print.PrinterJob;\r
-import java.beans.PropertyChangeEvent;\r
-import java.io.File;\r
-import java.net.URL;\r
-import java.util.ArrayList;\r
-import java.util.Enumeration;\r
-import java.util.Hashtable;\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-import javax.swing.JButton;\r
-import javax.swing.JEditorPane;\r
-import javax.swing.JInternalFrame;\r
-import javax.swing.JLabel;\r
-import javax.swing.JLayeredPane;\r
-import javax.swing.JMenu;\r
-import javax.swing.JMenuItem;\r
-import javax.swing.JOptionPane;\r
-import javax.swing.JPanel;\r
-import javax.swing.JProgressBar;\r
-import javax.swing.JRadioButtonMenuItem;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.SwingUtilities;\r
-\r
-/**\r
- * DOCUMENT ME!\r
- * \r
- * @author $author$\r
- * @version $Revision$\r
- */\r
-public class AlignFrame extends GAlignFrame implements DropTargetListener,\r
-        IProgressIndicator\r
-{\r
-\r
-  /** DOCUMENT ME!! */\r
-  public static final int DEFAULT_WIDTH = 700;\r
-\r
-  /** DOCUMENT ME!! */\r
-  public static final int DEFAULT_HEIGHT = 500;\r
-\r
-  public AlignmentPanel alignPanel;\r
-\r
-  AlignViewport viewport;\r
\r
-  public AlignViewControllerI avc;\r
\r
-\r
-  Vector alignPanels = new Vector();\r
-\r
-  /**\r
-   * Last format used to load or save alignments in this window\r
-   */\r
-  String currentFileFormat = null;\r
-\r
-  /**\r
-   * Current filename for this alignment\r
-   */\r
-  String fileName = null;\r
-\r
-  /**\r
-   * Creates a new AlignFrame object with specific width and height.\r
-   * \r
-   * @param al\r
-   * @param width\r
-   * @param height\r
-   */\r
-  public AlignFrame(AlignmentI al, int width, int height)\r
-  {\r
-    this(al, null, width, height);\r
-  }\r
-\r
-  /**\r
-   * Creates a new AlignFrame object with specific width, height and\r
-   * sequenceSetId\r
-   * \r
-   * @param al\r
-   * @param width\r
-   * @param height\r
-   * @param sequenceSetId\r
-   */\r
-  public AlignFrame(AlignmentI al, int width, int height,\r
-          String sequenceSetId)\r
-  {\r
-    this(al, null, width, height, sequenceSetId);\r
-  }\r
-\r
-  /**\r
-   * Creates a new AlignFrame object with specific width, height and\r
-   * sequenceSetId\r
-   * \r
-   * @param al\r
-   * @param width\r
-   * @param height\r
-   * @param sequenceSetId\r
-   * @param viewId\r
-   */\r
-  public AlignFrame(AlignmentI al, int width, int height,\r
-          String sequenceSetId, String viewId)\r
-  {\r
-    this(al, null, width, height, sequenceSetId, viewId);\r
-  }\r
-\r
-  /**\r
-   * new alignment window with hidden columns\r
-   * \r
-   * @param al\r
-   *          AlignmentI\r
-   * @param hiddenColumns\r
-   *          ColumnSelection or null\r
-   * @param width\r
-   *          Width of alignment frame\r
-   * @param height\r
-   *          height of frame.\r
-   */\r
-  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,\r
-          int width, int height)\r
-  {\r
-    this(al, hiddenColumns, width, height, null);\r
-  }\r
-\r
-  /**\r
-   * Create alignment frame for al with hiddenColumns, a specific width and\r
-   * height, and specific sequenceId\r
-   * \r
-   * @param al\r
-   * @param hiddenColumns\r
-   * @param width\r
-   * @param height\r
-   * @param sequenceSetId\r
-   *          (may be null)\r
-   */\r
-  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,\r
-          int width, int height, String sequenceSetId)\r
-  {\r
-    this(al, hiddenColumns, width, height, sequenceSetId, null);\r
-  }\r
-\r
-  /**\r
-   * Create alignment frame for al with hiddenColumns, a specific width and\r
-   * height, and specific sequenceId\r
-   * \r
-   * @param al\r
-   * @param hiddenColumns\r
-   * @param width\r
-   * @param height\r
-   * @param sequenceSetId\r
-   *          (may be null)\r
-   * @param viewId\r
-   *          (may be null)\r
-   */\r
-  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,\r
-          int width, int height, String sequenceSetId, String viewId)\r
-  {\r
-    setSize(width, height);\r
-    viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId);\r
-\r
-    alignPanel = new AlignmentPanel(this, viewport);\r
-\r
-    if (al.getDataset() == null)\r
-    {\r
-      al.setDataset(null);\r
-    }\r
-\r
-    addAlignmentPanel(alignPanel, true);\r
-    init();\r
-  }\r
-\r
-  /**\r
-   * Make a new AlignFrame from exisiting alignmentPanels\r
-   * \r
-   * @param ap\r
-   *          AlignmentPanel\r
-   * @param av\r
-   *          AlignViewport\r
-   */\r
-  public AlignFrame(AlignmentPanel ap)\r
-  {\r
-    viewport = ap.av;\r
-    alignPanel = ap;\r
-    addAlignmentPanel(ap, false);\r
-    init();\r
-  }\r
-\r
-  /**\r
-   * initalise the alignframe from the underlying viewport data and the\r
-   * configurations\r
-   */\r
-  void init()\r
-  {\r
-    avc = new jalview.controller.AlignViewController(viewport, alignPanel);\r
-    if (viewport.getAlignmentConservationAnnotation() == null)\r
-    {\r
-      BLOSUM62Colour.setEnabled(false);\r
-      conservationMenuItem.setEnabled(false);\r
-      modifyConservation.setEnabled(false);\r
-      // PIDColour.setEnabled(false);\r
-      // abovePIDThreshold.setEnabled(false);\r
-      // modifyPID.setEnabled(false);\r
-    }\r
-\r
-    String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT",\r
-            "No sort");\r
-\r
-    if (sortby.equals("Id"))\r
-    {\r
-      sortIDMenuItem_actionPerformed(null);\r
-    }\r
-    else if (sortby.equals("Pairwise Identity"))\r
-    {\r
-      sortPairwiseMenuItem_actionPerformed(null);\r
-    }\r
-\r
-    if (Desktop.desktop != null)\r
-    {\r
-      this.setDropTarget(new java.awt.dnd.DropTarget(this, this));\r
-      addServiceListeners();\r
-      setGUINucleotide(viewport.getAlignment().isNucleotide());\r
-    }\r
-\r
-    setMenusFromViewport(viewport);\r
-    buildSortByAnnotationScoresMenu();\r
-    if (viewport.wrapAlignment)\r
-    {\r
-      wrapMenuItem_actionPerformed(null);\r
-    }\r
-\r
-    if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false))\r
-    {\r
-      this.overviewMenuItem_actionPerformed(null);\r
-    }\r
-\r
-    addKeyListener();\r
-    \r
-  }\r
-\r
-  /**\r
-   * Change the filename and format for the alignment, and enable the 'reload'\r
-   * button functionality.\r
-   * \r
-   * @param file\r
-   *          valid filename\r
-   * @param format\r
-   *          format of file\r
-   */\r
-  public void setFileName(String file, String format)\r
-  {\r
-    fileName = file;\r
-    currentFileFormat = format;\r
-    reload.setEnabled(true);\r
-  }\r
-\r
-  void addKeyListener()\r
-  {\r
-    addKeyListener(new KeyAdapter()\r
-    {\r
-      @Override\r
-      public void keyPressed(KeyEvent evt)\r
-      {\r
-        if (viewport.cursorMode\r
-                && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt\r
-                        .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt\r
-                        .getKeyCode() <= KeyEvent.VK_NUMPAD9))\r
-                && Character.isDigit(evt.getKeyChar()))\r
-          alignPanel.seqPanel.numberPressed(evt.getKeyChar());\r
-\r
-        switch (evt.getKeyCode())\r
-        {\r
-\r
-        case 27: // escape key\r
-          deselectAllSequenceMenuItem_actionPerformed(null);\r
-\r
-          break;\r
-\r
-        case KeyEvent.VK_DOWN:\r
-          if (evt.isAltDown() || !viewport.cursorMode)\r
-            moveSelectedSequences(false);\r
-          if (viewport.cursorMode)\r
-            alignPanel.seqPanel.moveCursor(0, 1);\r
-          break;\r
-\r
-        case KeyEvent.VK_UP:\r
-          if (evt.isAltDown() || !viewport.cursorMode)\r
-            moveSelectedSequences(true);\r
-          if (viewport.cursorMode)\r
-            alignPanel.seqPanel.moveCursor(0, -1);\r
-\r
-          break;\r
-\r
-        case KeyEvent.VK_LEFT:\r
-          if (evt.isAltDown() || !viewport.cursorMode)\r
-            slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());\r
-          else\r
-            alignPanel.seqPanel.moveCursor(-1, 0);\r
-\r
-          break;\r
-\r
-        case KeyEvent.VK_RIGHT:\r
-          if (evt.isAltDown() || !viewport.cursorMode)\r
-            slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());\r
-          else\r
-            alignPanel.seqPanel.moveCursor(1, 0);\r
-          break;\r
-\r
-        case KeyEvent.VK_SPACE:\r
-          if (viewport.cursorMode)\r
-          {\r
-            alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()\r
-                    || evt.isShiftDown() || evt.isAltDown());\r
-          }\r
-          break;\r
-\r
-        // case KeyEvent.VK_A:\r
-        // if (viewport.cursorMode)\r
-        // {\r
-        // alignPanel.seqPanel.insertNucAtCursor(false,"A");\r
-        // //System.out.println("A");\r
-        // }\r
-        // break;\r
-        /*\r
-         * case KeyEvent.VK_CLOSE_BRACKET: if (viewport.cursorMode) {\r
-         * System.out.println("closing bracket"); } break;\r
-         */\r
-        case KeyEvent.VK_DELETE:\r
-        case KeyEvent.VK_BACK_SPACE:\r
-          if (!viewport.cursorMode)\r
-          {\r
-            cut_actionPerformed(null);\r
-          }\r
-          else\r
-          {\r
-            alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()\r
-                    || evt.isShiftDown() || evt.isAltDown());\r
-          }\r
-\r
-          break;\r
-\r
-        case KeyEvent.VK_S:\r
-          if (viewport.cursorMode)\r
-          {\r
-            alignPanel.seqPanel.setCursorRow();\r
-          }\r
-          break;\r
-        case KeyEvent.VK_C:\r
-          if (viewport.cursorMode && !evt.isControlDown())\r
-          {\r
-            alignPanel.seqPanel.setCursorColumn();\r
-          }\r
-          break;\r
-        case KeyEvent.VK_P:\r
-          if (viewport.cursorMode)\r
-          {\r
-            alignPanel.seqPanel.setCursorPosition();\r
-          }\r
-          break;\r
-\r
-        case KeyEvent.VK_ENTER:\r
-        case KeyEvent.VK_COMMA:\r
-          if (viewport.cursorMode)\r
-          {\r
-            alignPanel.seqPanel.setCursorRowAndColumn();\r
-          }\r
-          break;\r
-\r
-        case KeyEvent.VK_Q:\r
-          if (viewport.cursorMode)\r
-          {\r
-            alignPanel.seqPanel.setSelectionAreaAtCursor(true);\r
-          }\r
-          break;\r
-        case KeyEvent.VK_M:\r
-          if (viewport.cursorMode)\r
-          {\r
-            alignPanel.seqPanel.setSelectionAreaAtCursor(false);\r
-          }\r
-          break;\r
-\r
-        case KeyEvent.VK_F2:\r
-          viewport.cursorMode = !viewport.cursorMode;\r
-          statusBar.setText(MessageManager.formatMessage("label.keyboard_editing_mode", new String[]{(viewport.cursorMode ? "on" : "off")}));\r
-          if (viewport.cursorMode)\r
-          {\r
-            alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;\r
-            alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;\r
-          }\r
-          alignPanel.seqPanel.seqCanvas.repaint();\r
-          break;\r
-\r
-        case KeyEvent.VK_F1:\r
-          try\r
-          {\r
-            ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();\r
-            java.net.URL url = javax.help.HelpSet.findHelpSet(cl,\r
-                    "help/help");\r
-            javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);\r
-\r
-            javax.help.HelpBroker hb = hs.createHelpBroker();\r
-            hb.setCurrentID("home");\r
-            hb.setDisplayed(true);\r
-          } catch (Exception ex)\r
-          {\r
-            ex.printStackTrace();\r
-          }\r
-          break;\r
-        case KeyEvent.VK_H:\r
-        {\r
-          boolean toggleSeqs = !evt.isControlDown();\r
-          boolean toggleCols = !evt.isShiftDown();\r
-          toggleHiddenRegions(toggleSeqs, toggleCols);\r
-          break;\r
-        }\r
-        case KeyEvent.VK_PAGE_UP:\r
-          if (viewport.wrapAlignment)\r
-          {\r
-            alignPanel.scrollUp(true);\r
-          }\r
-          else\r
-          {\r
-            alignPanel.setScrollValues(viewport.startRes, viewport.startSeq\r
-                    - viewport.endSeq + viewport.startSeq);\r
-          }\r
-          break;\r
-        case KeyEvent.VK_PAGE_DOWN:\r
-          if (viewport.wrapAlignment)\r
-          {\r
-            alignPanel.scrollUp(false);\r
-          }\r
-          else\r
-          {\r
-            alignPanel.setScrollValues(viewport.startRes, viewport.startSeq\r
-                    + viewport.endSeq - viewport.startSeq);\r
-          }\r
-          break;\r
-        }\r
-      }\r
-\r
-      @Override\r
-      public void keyReleased(KeyEvent evt)\r
-      {\r
-        switch (evt.getKeyCode())\r
-        {\r
-        case KeyEvent.VK_LEFT:\r
-          if (evt.isAltDown() || !viewport.cursorMode)\r
-            viewport.firePropertyChange("alignment", null, viewport\r
-                    .getAlignment().getSequences());\r
-          break;\r
-\r
-        case KeyEvent.VK_RIGHT:\r
-          if (evt.isAltDown() || !viewport.cursorMode)\r
-            viewport.firePropertyChange("alignment", null, viewport\r
-                    .getAlignment().getSequences());\r
-          break;\r
-        }\r
-      }\r
-    });\r
-  }\r
-\r
-  public void addAlignmentPanel(final AlignmentPanel ap, boolean newPanel)\r
-  {\r
-    ap.alignFrame = this;\r
-    avc = new jalview.controller.AlignViewController(viewport, alignPanel);\r
-\r
-    alignPanels.addElement(ap);\r
-\r
-    PaintRefresher.Register(ap, ap.av.getSequenceSetId());\r
-\r
-    int aSize = alignPanels.size();\r
-\r
-    tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);\r
-\r
-    if (aSize == 1 && ap.av.viewName == null)\r
-    {\r
-      this.getContentPane().add(ap, BorderLayout.CENTER);\r
-    }\r
-    else\r
-    {\r
-      if (aSize == 2)\r
-      {\r
-        setInitialTabVisible();\r
-      }\r
-\r
-      expandViews.setEnabled(true);\r
-      gatherViews.setEnabled(true);\r
-      tabbedPane.addTab(ap.av.viewName, ap);\r
-\r
-      ap.setVisible(false);\r
-    }\r
-\r
-    if (newPanel)\r
-    {\r
-      if (ap.av.isPadGaps())\r
-      {\r
-        ap.av.getAlignment().padGaps();\r
-      }\r
-      ap.av.updateConservation(ap);\r
-      ap.av.updateConsensus(ap);\r
-      ap.av.updateStrucConsensus(ap);\r
-    }\r
-  }\r
-\r
-  public void setInitialTabVisible()\r
-  {\r
-    expandViews.setEnabled(true);\r
-    gatherViews.setEnabled(true);\r
-    tabbedPane.setVisible(true);\r
-    AlignmentPanel first = (AlignmentPanel) alignPanels.firstElement();\r
-    tabbedPane.addTab(first.av.viewName, first);\r
-    this.getContentPane().add(tabbedPane, BorderLayout.CENTER);\r
-  }\r
-\r
-  public AlignViewport getViewport()\r
-  {\r
-    return viewport;\r
-  }\r
-\r
-  /* Set up intrinsic listeners for dynamically generated GUI bits. */\r
-  private void addServiceListeners()\r
-  {\r
-    final java.beans.PropertyChangeListener thisListener;\r
-    Desktop.instance.addJalviewPropertyChangeListener("services",\r
-            thisListener = new java.beans.PropertyChangeListener()\r
-            {\r
-              @Override\r
-              public void propertyChange(PropertyChangeEvent evt)\r
-              {\r
-                // // System.out.println("Discoverer property change.");\r
-                // if (evt.getPropertyName().equals("services"))\r
-                {\r
-                  SwingUtilities.invokeLater(new Runnable()\r
-                  {\r
-\r
-                    @Override\r
-                    public void run()\r
-                    {\r
-                      System.err\r
-                              .println("Rebuild WS Menu for service change");\r
-                      BuildWebServiceMenu();\r
-                    }\r
-\r
-                  });\r
-                }\r
-              }\r
-            });\r
-    addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()\r
-    {\r
-      @Override\r
-      public void internalFrameClosed(\r
-              javax.swing.event.InternalFrameEvent evt)\r
-      {\r
-        System.out.println("deregistering discoverer listener");\r
-        Desktop.instance.removeJalviewPropertyChangeListener("services",\r
-                thisListener);\r
-        closeMenuItem_actionPerformed(true);\r
-      };\r
-    });\r
-    // Finally, build the menu once to get current service state\r
-    new Thread(new Runnable()\r
-    {\r
-      @Override\r
-      public void run()\r
-      {\r
-        BuildWebServiceMenu();\r
-      }\r
-    }).start();\r
-  }\r
-\r
-  public void setGUINucleotide(boolean nucleotide)\r
-  {\r
-    showTranslation.setVisible(nucleotide);\r
-    conservationMenuItem.setEnabled(!nucleotide);\r
-    modifyConservation.setEnabled(!nucleotide);\r
-    showGroupConservation.setEnabled(!nucleotide);\r
-    rnahelicesColour.setEnabled(nucleotide);\r
-    purinePyrimidineColour.setEnabled(nucleotide);\r
-    // Remember AlignFrame always starts as protein\r
-    // if (!nucleotide)\r
-    // {\r
-    // showTr\r
-    // calculateMenu.remove(calculateMenu.getItemCount() - 2);\r
-    // }\r
-  }\r
-\r
-  /**\r
-   * set up menus for the currently viewport. This may be called after any\r
-   * operation that affects the data in the current view (selection changed,\r
-   * etc) to update the menus to reflect the new state.\r
-   */\r
-  public void setMenusForViewport()\r
-  {\r
-    setMenusFromViewport(viewport);\r
-  }\r
-\r
-  /**\r
-   * Need to call this method when tabs are selected for multiple views, or when\r
-   * loading from Jalview2XML.java\r
-   * \r
-   * @param av\r
-   *          AlignViewport\r
-   */\r
-  void setMenusFromViewport(AlignViewport av)\r
-  {\r
-    padGapsMenuitem.setSelected(av.isPadGaps());\r
-    colourTextMenuItem.setSelected(av.showColourText);\r
-    abovePIDThreshold.setSelected(av.getAbovePIDThreshold());\r
-    conservationMenuItem.setSelected(av.getConservationSelected());\r
-    seqLimits.setSelected(av.getShowJVSuffix());\r
-    idRightAlign.setSelected(av.rightAlignIds);\r
-    centreColumnLabelsMenuItem.setState(av.centreColumnLabels);\r
-    renderGapsMenuItem.setSelected(av.renderGaps);\r
-    wrapMenuItem.setSelected(av.wrapAlignment);\r
-    scaleAbove.setVisible(av.wrapAlignment);\r
-    scaleLeft.setVisible(av.wrapAlignment);\r
-    scaleRight.setVisible(av.wrapAlignment);\r
-    annotationPanelMenuItem.setState(av.showAnnotation);\r
-    viewBoxesMenuItem.setSelected(av.showBoxes);\r
-    viewTextMenuItem.setSelected(av.showText);\r
-    showNonconservedMenuItem.setSelected(av.getShowUnconserved());\r
-    showGroupConsensus.setSelected(av.isShowGroupConsensus());\r
-    showGroupConservation.setSelected(av.isShowGroupConservation());\r
-    showConsensusHistogram.setSelected(av.isShowConsensusHistogram());\r
-    showSequenceLogo.setSelected(av.isShowSequenceLogo());\r
-    normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo());\r
-\r
-    setColourSelected(ColourSchemeProperty.getColourName(av\r
-            .getGlobalColourScheme()));\r
-\r
-    showSeqFeatures.setSelected(av.showSequenceFeatures);\r
-    hiddenMarkers.setState(av.showHiddenMarkers);\r
-    applyToAllGroups.setState(av.getColourAppliesToAllGroups());\r
-    showNpFeatsMenuitem.setSelected(av.isShowNpFeats());\r
-    showDbRefsMenuitem.setSelected(av.isShowDbRefs());\r
-    autoCalculate.setSelected(av.autoCalculateConsensus);\r
-    sortByTree.setSelected(av.sortByTree);\r
-    listenToViewSelections.setSelected(av.followSelection);\r
-    rnahelicesColour.setEnabled(av.getAlignment().hasRNAStructure());\r
-    rnahelicesColour\r
-            .setSelected(av.getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);\r
-    setShowProductsEnabled();\r
-    updateEditMenuBar();\r
-  }\r
-\r
-  // methods for implementing IProgressIndicator\r
-  // need to refactor to a reusable stub class\r
-  Hashtable progressBars, progressBarHandlers;\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)\r
-   */\r
-  @Override\r
-  public void setProgressBar(String message, long id)\r
-  {\r
-    if (progressBars == null)\r
-    {\r
-      progressBars = new Hashtable();\r
-      progressBarHandlers = new Hashtable();\r
-    }\r
-\r
-    JPanel progressPanel;\r
-    Long lId = new Long(id);\r
-    GridLayout layout = (GridLayout) statusPanel.getLayout();\r
-    if (progressBars.get(lId) != null)\r
-    {\r
-      progressPanel = (JPanel) progressBars.get(new Long(id));\r
-      statusPanel.remove(progressPanel);\r
-      progressBars.remove(lId);\r
-      progressPanel = null;\r
-      if (message != null)\r
-      {\r
-        statusBar.setText(message);\r
-      }\r
-      if (progressBarHandlers.contains(lId))\r
-      {\r
-        progressBarHandlers.remove(lId);\r
-      }\r
-      layout.setRows(layout.getRows() - 1);\r
-    }\r
-    else\r
-    {\r
-      progressPanel = new JPanel(new BorderLayout(10, 5));\r
-\r
-      JProgressBar progressBar = new JProgressBar();\r
-      progressBar.setIndeterminate(true);\r
-\r
-      progressPanel.add(new JLabel(message), BorderLayout.WEST);\r
-      progressPanel.add(progressBar, BorderLayout.CENTER);\r
-\r
-      layout.setRows(layout.getRows() + 1);\r
-      statusPanel.add(progressPanel);\r
-\r
-      progressBars.put(lId, progressPanel);\r
-    }\r
-    // update GUI\r
-    // setMenusForViewport();\r
-    validate();\r
-  }\r
-\r
-  @Override\r
-  public void registerHandler(final long id,\r
-          final IProgressIndicatorHandler handler)\r
-  {\r
-    if (progressBarHandlers == null || !progressBars.contains(new Long(id)))\r
-    {\r
-      throw new Error(\r
-              "call setProgressBar before registering the progress bar's handler.");\r
-    }\r
-    progressBarHandlers.put(new Long(id), handler);\r
-    final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));\r
-    if (handler.canCancel())\r
-    {\r
-      JButton cancel = new JButton(MessageManager.getString("action.cancel"));\r
-      final IProgressIndicator us = this;\r
-      cancel.addActionListener(new ActionListener()\r
-      {\r
-\r
-        @Override\r
-        public void actionPerformed(ActionEvent e)\r
-        {\r
-          handler.cancelActivity(id);\r
-          us.setProgressBar(\r
-                  "Cancelled "\r
-                          + ((JLabel) progressPanel.getComponent(0))\r
-                                  .getText(), id);\r
-        }\r
-      });\r
-      progressPanel.add(cancel, BorderLayout.EAST);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * \r
-   * @return true if any progress bars are still active\r
-   */\r
-  @Override\r
-  public boolean operationInProgress()\r
-  {\r
-    if (progressBars != null && progressBars.size() > 0)\r
-    {\r
-      return true;\r
-    }\r
-    return false;\r
-  }\r
-\r
-  /*\r
-   * Added so Castor Mapping file can obtain Jalview Version\r
-   */\r
-  public String getVersion()\r
-  {\r
-    return jalview.bin.Cache.getProperty("VERSION");\r
-  }\r
-\r
-  public FeatureRenderer getFeatureRenderer()\r
-  {\r
-    return alignPanel.seqPanel.seqCanvas.getFeatureRenderer();\r
-  }\r
-\r
-  @Override\r
-  public void fetchSequence_actionPerformed(ActionEvent e)\r
-  {\r
-    new SequenceFetcher(this);\r
-  }\r
-\r
-  @Override\r
-  public void addFromFile_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);\r
-  }\r
-\r
-  @Override\r
-  public void reload_actionPerformed(ActionEvent e)\r
-  {\r
-    if (fileName != null)\r
-    {\r
-      // TODO: JAL-1108 - ensure all associated frames are closed regardless of\r
-      // originating file's format\r
-      // TODO: work out how to recover feature settings for correct view(s) when\r
-      // file is reloaded.\r
-      if (currentFileFormat.equals("Jalview"))\r
-      {\r
-        JInternalFrame[] frames = Desktop.desktop.getAllFrames();\r
-        for (int i = 0; i < frames.length; i++)\r
-        {\r
-          if (frames[i] instanceof AlignFrame && frames[i] != this\r
-                  && ((AlignFrame) frames[i]).fileName != null\r
-                  && ((AlignFrame) frames[i]).fileName.equals(fileName))\r
-          {\r
-            try\r
-            {\r
-              frames[i].setSelected(true);\r
-              Desktop.instance.closeAssociatedWindows();\r
-            } catch (java.beans.PropertyVetoException ex)\r
-            {\r
-            }\r
-          }\r
-\r
-        }\r
-        Desktop.instance.closeAssociatedWindows();\r
-\r
-        FileLoader loader = new FileLoader();\r
-        String protocol = fileName.startsWith("http:") ? "URL" : "File";\r
-        loader.LoadFile(viewport, fileName, protocol, currentFileFormat);\r
-      }\r
-      else\r
-      {\r
-        Rectangle bounds = this.getBounds();\r
-\r
-        FileLoader loader = new FileLoader();\r
-        String protocol = fileName.startsWith("http:") ? "URL" : "File";\r
-        AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,\r
-                protocol, currentFileFormat);\r
-\r
-        newframe.setBounds(bounds);\r
-        if (featureSettings != null && featureSettings.isShowing())\r
-        {\r
-          final Rectangle fspos = featureSettings.frame.getBounds();\r
-          // TODO: need a 'show feature settings' function that takes bounds -\r
-          // need to refactor Desktop.addFrame\r
-          newframe.featureSettings_actionPerformed(null);\r
-          final FeatureSettings nfs = newframe.featureSettings;\r
-          SwingUtilities.invokeLater(new Runnable()\r
-          {\r
-            @Override\r
-            public void run()\r
-            {\r
-              nfs.frame.setBounds(fspos);\r
-            }\r
-          });\r
-          this.featureSettings.close();\r
-          this.featureSettings = null;\r
-        }\r
-        this.closeMenuItem_actionPerformed(true);\r
-      }\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public void addFromText_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);\r
-  }\r
-\r
-  @Override\r
-  public void addFromURL_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.inputURLMenuItem_actionPerformed(viewport);\r
-  }\r
-\r
-  @Override\r
-  public void save_actionPerformed(ActionEvent e)\r
-  {\r
-    if (fileName == null\r
-            || (currentFileFormat == null || !jalview.io.FormatAdapter\r
-                    .isValidIOFormat(currentFileFormat, true))\r
-            || fileName.startsWith("http"))\r
-    {\r
-      saveAs_actionPerformed(null);\r
-    }\r
-    else\r
-    {\r
-      saveAlignment(fileName, currentFileFormat);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void saveAs_actionPerformed(ActionEvent e)\r
-  {\r
-    JalviewFileChooser chooser = new JalviewFileChooser(\r
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),\r
-            jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS,\r
-            jalview.io.AppletFormatAdapter.WRITABLE_FNAMES,\r
-            currentFileFormat, false);\r
-\r
-    chooser.setFileView(new JalviewFileView());\r
-    chooser.setDialogTitle("Save Alignment to file");\r
-    chooser.setToolTipText(MessageManager.getString("action.save"));\r
-\r
-    int value = chooser.showSaveDialog(this);\r
-\r
-    if (value == JalviewFileChooser.APPROVE_OPTION)\r
-    {\r
-      currentFileFormat = chooser.getSelectedFormat();\r
-      if (currentFileFormat == null)\r
-      {\r
-        JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
-                MessageManager.getString("label.select_file_format_before_saving"),\r
-                MessageManager.getString("label.file_format_not_specified"), JOptionPane.WARNING_MESSAGE);\r
-        value = chooser.showSaveDialog(this);\r
-        return;\r
-      }\r
-\r
-      fileName = chooser.getSelectedFile().getPath();\r
-\r
-      jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",\r
-              currentFileFormat);\r
-\r
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);\r
-      if (currentFileFormat.indexOf(" ") > -1)\r
-      {\r
-        currentFileFormat = currentFileFormat.substring(0,\r
-                currentFileFormat.indexOf(" "));\r
-      }\r
-      saveAlignment(fileName, currentFileFormat);\r
-    }\r
-  }\r
-\r
-  public boolean saveAlignment(String file, String format)\r
-  {\r
-    boolean success = true;\r
-\r
-    if (format.equalsIgnoreCase("Jalview"))\r
-    {\r
-      String shortName = title;\r
-\r
-      if (shortName.indexOf(java.io.File.separatorChar) > -1)\r
-      {\r
-        shortName = shortName.substring(shortName\r
-                .lastIndexOf(java.io.File.separatorChar) + 1);\r
-      }\r
-\r
-      success = new Jalview2XML().SaveAlignment(this, file, shortName);\r
-\r
-      statusBar.setText(MessageManager.formatMessage("label.successfully_saved_to_file_in_format",new String[]{fileName, format}));\r
-\r
-\r
-    }\r
-    else\r
-    {\r
-      if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))\r
-      {\r
-        warningMessage("Cannot save file " + fileName + " using format "\r
-                + format, "Alignment output format not supported");\r
-        saveAs_actionPerformed(null);\r
-        // JBPNote need to have a raise_gui flag here\r
-        return false;\r
-      }\r
-\r
-      String[] omitHidden = null;\r
-\r
-      if (viewport.hasHiddenColumns())\r
-      {\r
-        int reply = JOptionPane\r
-                .showInternalConfirmDialog(\r
-                        Desktop.desktop,\r
-                        MessageManager.getString("label.alignment_contains_hidden_columns"),\r
-                        MessageManager.getString("action.save_omit_hidden_columns"),\r
-                        JOptionPane.YES_NO_OPTION,\r
-                        JOptionPane.QUESTION_MESSAGE);\r
-\r
-        if (reply == JOptionPane.YES_OPTION)\r
-        {\r
-          omitHidden = viewport.getViewAsString(false);\r
-        }\r
-      }\r
-      FormatAdapter f = new FormatAdapter();\r
-      String output = f.formatSequences(format,\r
-              viewport.getAlignment(), // class cast exceptions will\r
-              // occur in the distant future\r
-              omitHidden, f.getCacheSuffixDefault(format),\r
-              viewport.getColumnSelection());\r
-\r
-      if (output == null)\r
-      {\r
-        success = false;\r
-      }\r
-      else\r
-      {\r
-        try\r
-        {\r
-          java.io.PrintWriter out = new java.io.PrintWriter(\r
-                  new java.io.FileWriter(file));\r
-\r
-          out.print(output);\r
-          out.close();\r
-          this.setTitle(file);\r
-          statusBar.setText(MessageManager.formatMessage("label.successfully_saved_to_file_in_format",new String[]{fileName, format}));\r
-        } catch (Exception ex)\r
-        {\r
-          success = false;\r
-          ex.printStackTrace();\r
-        }\r
-      }\r
-    }\r
-\r
-    if (!success)\r
-    {\r
-      JOptionPane.showInternalMessageDialog(this, MessageManager.formatMessage("label.couldnt_save_file", new String[]{fileName}),\r
-              MessageManager.getString("label.error_saving_file"), JOptionPane.WARNING_MESSAGE);\r
-    }\r
-\r
-    return success;\r
-  }\r
-\r
-  private void warningMessage(String warning, String title)\r
-  {\r
-    if (new jalview.util.Platform().isHeadless())\r
-    {\r
-      System.err.println("Warning: " + title + "\nWarning: " + warning);\r
-\r
-    }\r
-    else\r
-    {\r
-      JOptionPane.showInternalMessageDialog(this, warning, title,\r
-              JOptionPane.WARNING_MESSAGE);\r
-    }\r
-    return;\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void outputText_actionPerformed(ActionEvent e)\r
-  {\r
-    String[] omitHidden = null;\r
-\r
-    if (viewport.hasHiddenColumns())\r
-    {\r
-      int reply = JOptionPane\r
-              .showInternalConfirmDialog(\r
-                      Desktop.desktop,\r
-                      MessageManager.getString("label.alignment_contains_hidden_columns"),\r
-                      MessageManager.getString("action.save_omit_hidden_columns"),\r
-                      JOptionPane.YES_NO_OPTION,\r
-                      JOptionPane.QUESTION_MESSAGE);\r
-\r
-      if (reply == JOptionPane.YES_OPTION)\r
-      {\r
-        omitHidden = viewport.getViewAsString(false);\r
-      }\r
-    }\r
-\r
-    CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
-    cap.setForInput(null);\r
-\r
-    try\r
-    {\r
-      cap.setText(new FormatAdapter().formatSequences(e.getActionCommand(),\r
-              viewport.getAlignment(), omitHidden,\r
-              viewport.getColumnSelection()));\r
-      Desktop.addInternalFrame(cap,\r
-              MessageManager.formatMessage("label.alignment_output_command", new String[]{e.getActionCommand()}), 600, 500);\r
-    } catch (OutOfMemoryError oom)\r
-    {\r
-      new OOMWarning("Outputting alignment as " + e.getActionCommand(), oom);\r
-      cap.dispose();\r
-    }\r
-\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void htmlMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    new HTMLOutput(alignPanel,\r
-            alignPanel.seqPanel.seqCanvas.getSequenceRenderer(),\r
-            alignPanel.seqPanel.seqCanvas.getFeatureRenderer());\r
-  }\r
-\r
-  public void createImageMap(File file, String image)\r
-  {\r
-    alignPanel.makePNGImageMap(file, image);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void createPNG(File f)\r
-  {\r
-    alignPanel.makePNG(f);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void createEPS(File f)\r
-  {\r
-    alignPanel.makeEPS(f);\r
-  }\r
-\r
-  @Override\r
-  public void pageSetup_actionPerformed(ActionEvent e)\r
-  {\r
-    PrinterJob printJob = PrinterJob.getPrinterJob();\r
-    PrintThread.pf = printJob.pageDialog(printJob.defaultPage());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void printMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    // Putting in a thread avoids Swing painting problems\r
-    PrintThread thread = new PrintThread(alignPanel);\r
-    thread.start();\r
-  }\r
-\r
-  @Override\r
-  public void exportFeatures_actionPerformed(ActionEvent e)\r
-  {\r
-    new AnnotationExporter().exportFeatures(alignPanel);\r
-  }\r
-\r
-  @Override\r
-  public void exportAnnotations_actionPerformed(ActionEvent e)\r
-  {\r
-    new AnnotationExporter().exportAnnotations(alignPanel,\r
-            viewport.showAnnotation ? viewport.getAlignment()\r
-                    .getAlignmentAnnotation() : null, viewport\r
-                    .getAlignment().getGroups(), ((Alignment) viewport\r
-                    .getAlignment()).alignmentProperties);\r
-  }\r
-\r
-  @Override\r
-  public void associatedData_actionPerformed(ActionEvent e)\r
-  {\r
-    // Pick the tree file\r
-    JalviewFileChooser chooser = new JalviewFileChooser(\r
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));\r
-    chooser.setFileView(new JalviewFileView());\r
-    chooser.setDialogTitle(MessageManager.getString("label.load_jalview_annotations"));\r
-    chooser.setToolTipText(MessageManager.getString("label.load_jalview_annotations"));\r
-\r
-    int value = chooser.showOpenDialog(null);\r
-\r
-    if (value == JalviewFileChooser.APPROVE_OPTION)\r
-    {\r
-      String choice = chooser.getSelectedFile().getPath();\r
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);\r
-      loadJalviewDataFile(choice, null, null, null);\r
-    }\r
-\r
-  }\r
-\r
-  /**\r
-   * Close the current view or all views in the alignment frame. If the frame\r
-   * only contains one view then the alignment will be removed from memory.\r
-   * \r
-   * @param closeAllTabs\r
-   */\r
-  @Override\r
-  public void closeMenuItem_actionPerformed(boolean closeAllTabs)\r
-  {\r
-    if (alignPanels != null && alignPanels.size() < 2)\r
-    {\r
-      closeAllTabs = true;\r
-    }\r
-\r
-    try\r
-    {\r
-      if (alignPanels != null)\r
-      {\r
-        if (closeAllTabs)\r
-        {\r
-          if (this.isClosed())\r
-          {\r
-            // really close all the windows - otherwise wait till\r
-            // setClosed(true) is called\r
-            for (int i = 0; i < alignPanels.size(); i++)\r
-            {\r
-              AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i);\r
-              ap.closePanel();\r
-            }\r
-          }\r
-        }\r
-        else\r
-        {\r
-          closeView(alignPanel);\r
-        }\r
-      }\r
-\r
-      if (closeAllTabs)\r
-      {\r
-        this.setClosed(true);\r
-      }\r
-    } catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * close alignPanel2 and shuffle tabs appropriately.\r
-   * \r
-   * @param alignPanel2\r
-   */\r
-  public void closeView(AlignmentPanel alignPanel2)\r
-  {\r
-    int index = tabbedPane.getSelectedIndex();\r
-    int closedindex = tabbedPane.indexOfComponent(alignPanel2);\r
-    alignPanels.removeElement(alignPanel2);\r
-    // Unnecessary\r
-    // if (viewport == alignPanel2.av)\r
-    // {\r
-    // viewport = null;\r
-    // }\r
-    alignPanel2.closePanel();\r
-    alignPanel2 = null;\r
-\r
-    tabbedPane.removeTabAt(closedindex);\r
-    tabbedPane.validate();\r
-\r
-    if (index > closedindex || index == tabbedPane.getTabCount())\r
-    {\r
-      // modify currently selected tab index if necessary.\r
-      index--;\r
-    }\r
-\r
-    this.tabSelectionChanged(index);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   */\r
-  void updateEditMenuBar()\r
-  {\r
-\r
-    if (viewport.historyList.size() > 0)\r
-    {\r
-      undoMenuItem.setEnabled(true);\r
-      CommandI command = (CommandI) viewport.historyList.peek();\r
-      undoMenuItem.setText(MessageManager.formatMessage("label.undo_command", new String[]{command.getDescription()}));\r
-    }\r
-    else\r
-    {\r
-      undoMenuItem.setEnabled(false);\r
-      undoMenuItem.setText(MessageManager.getString("action.undo"));\r
-    }\r
-\r
-    if (viewport.redoList.size() > 0)\r
-    {\r
-      redoMenuItem.setEnabled(true);\r
-\r
-      CommandI command = (CommandI) viewport.redoList.peek();\r
-      redoMenuItem.setText(MessageManager.formatMessage("label.redo_command", new String[]{command.getDescription()}));\r
-    }\r
-    else\r
-    {\r
-      redoMenuItem.setEnabled(false);\r
-      redoMenuItem.setText(MessageManager.getString("action.redo"));\r
-    }\r
-  }\r
-\r
-  public void addHistoryItem(CommandI command)\r
-  {\r
-    if (command.getSize() > 0)\r
-    {\r
-      viewport.historyList.push(command);\r
-      viewport.redoList.clear();\r
-      updateEditMenuBar();\r
-      viewport.updateHiddenColumns();\r
-      // viewport.hasHiddenColumns = (viewport.getColumnSelection() != null\r
-      // && viewport.getColumnSelection().getHiddenColumns() != null &&\r
-      // viewport.getColumnSelection()\r
-      // .getHiddenColumns().size() > 0);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * \r
-   * @return alignment objects for all views\r
-   */\r
-  AlignmentI[] getViewAlignments()\r
-  {\r
-    if (alignPanels != null)\r
-    {\r
-      Enumeration e = alignPanels.elements();\r
-      AlignmentI[] als = new AlignmentI[alignPanels.size()];\r
-      for (int i = 0; e.hasMoreElements(); i++)\r
-      {\r
-        als[i] = ((AlignmentPanel) e.nextElement()).av.getAlignment();\r
-      }\r
-      return als;\r
-    }\r
-    if (viewport != null)\r
-    {\r
-      return new AlignmentI[]\r
-      { viewport.getAlignment() };\r
-    }\r
-    return null;\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void undoMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.historyList.empty())\r
-      return;\r
-    CommandI command = (CommandI) viewport.historyList.pop();\r
-    viewport.redoList.push(command);\r
-    command.undoCommand(getViewAlignments());\r
-\r
-    AlignViewport originalSource = getOriginatingSource(command);\r
-    updateEditMenuBar();\r
-\r
-    if (originalSource != null)\r
-    {\r
-      if (originalSource != viewport)\r
-      {\r
-        Cache.log\r
-                .warn("Implementation worry: mismatch of viewport origin for undo");\r
-      }\r
-      originalSource.updateHiddenColumns();\r
-      // originalSource.hasHiddenColumns = (viewport.getColumnSelection() !=\r
-      // null\r
-      // && viewport.getColumnSelection().getHiddenColumns() != null &&\r
-      // viewport.getColumnSelection()\r
-      // .getHiddenColumns().size() > 0);\r
-      originalSource.firePropertyChange("alignment", null, originalSource\r
-              .getAlignment().getSequences());\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void redoMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.redoList.size() < 1)\r
-    {\r
-      return;\r
-    }\r
-\r
-    CommandI command = (CommandI) viewport.redoList.pop();\r
-    viewport.historyList.push(command);\r
-    command.doCommand(getViewAlignments());\r
-\r
-    AlignViewport originalSource = getOriginatingSource(command);\r
-    updateEditMenuBar();\r
-\r
-    if (originalSource != null)\r
-    {\r
-\r
-      if (originalSource != viewport)\r
-      {\r
-        Cache.log\r
-                .warn("Implementation worry: mismatch of viewport origin for redo");\r
-      }\r
-      originalSource.updateHiddenColumns();\r
-      // originalSource.hasHiddenColumns = (viewport.getColumnSelection() !=\r
-      // null\r
-      // && viewport.getColumnSelection().getHiddenColumns() != null &&\r
-      // viewport.getColumnSelection()\r
-      // .getHiddenColumns().size() > 0);\r
-      originalSource.firePropertyChange("alignment", null, originalSource\r
-              .getAlignment().getSequences());\r
-    }\r
-  }\r
-\r
-  AlignViewport getOriginatingSource(CommandI command)\r
-  {\r
-    AlignViewport originalSource = null;\r
-    // For sequence removal and addition, we need to fire\r
-    // the property change event FROM the viewport where the\r
-    // original alignment was altered\r
-    AlignmentI al = null;\r
-    if (command instanceof EditCommand)\r
-    {\r
-      EditCommand editCommand = (EditCommand) command;\r
-      al = editCommand.getAlignment();\r
-      Vector comps = (Vector) PaintRefresher.components.get(viewport\r
-              .getSequenceSetId());\r
-\r
-      for (int i = 0; i < comps.size(); i++)\r
-      {\r
-        if (comps.elementAt(i) instanceof AlignmentPanel)\r
-        {\r
-          if (al == ((AlignmentPanel) comps.elementAt(i)).av.getAlignment())\r
-          {\r
-            originalSource = ((AlignmentPanel) comps.elementAt(i)).av;\r
-            break;\r
-          }\r
-        }\r
-      }\r
-    }\r
-\r
-    if (originalSource == null)\r
-    {\r
-      // The original view is closed, we must validate\r
-      // the current view against the closed view first\r
-      if (al != null)\r
-      {\r
-        PaintRefresher.validateSequences(al, viewport.getAlignment());\r
-      }\r
-\r
-      originalSource = viewport;\r
-    }\r
-\r
-    return originalSource;\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param up\r
-   *          DOCUMENT ME!\r
-   */\r
-  public void moveSelectedSequences(boolean up)\r
-  {\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-\r
-    if (sg == null)\r
-    {\r
-      return;\r
-    }\r
-    viewport.getAlignment().moveSelectedSequencesByOne(sg,\r
-            viewport.getHiddenRepSequences(), up);\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  synchronized void slideSequences(boolean right, int size)\r
-  {\r
-    List<SequenceI> sg = new Vector();\r
-    if (viewport.cursorMode)\r
-    {\r
-      sg.add(viewport.getAlignment().getSequenceAt(\r
-              alignPanel.seqPanel.seqCanvas.cursorY));\r
-    }\r
-    else if (viewport.getSelectionGroup() != null\r
-            && viewport.getSelectionGroup().getSize() != viewport\r
-                    .getAlignment().getHeight())\r
-    {\r
-      sg = viewport.getSelectionGroup().getSequences(\r
-              viewport.getHiddenRepSequences());\r
-    }\r
-\r
-    if (sg.size() < 1)\r
-    {\r
-      return;\r
-    }\r
-\r
-    Vector invertGroup = new Vector();\r
-\r
-    for (int i = 0; i < viewport.getAlignment().getHeight(); i++)\r
-    {\r
-      if (!sg.contains(viewport.getAlignment().getSequenceAt(i)))\r
-        invertGroup.add(viewport.getAlignment().getSequenceAt(i));\r
-    }\r
-\r
-    SequenceI[] seqs1 = sg.toArray(new SequenceI[0]);\r
-\r
-    SequenceI[] seqs2 = new SequenceI[invertGroup.size()];\r
-    for (int i = 0; i < invertGroup.size(); i++)\r
-      seqs2[i] = (SequenceI) invertGroup.elementAt(i);\r
-\r
-    SlideSequencesCommand ssc;\r
-    if (right)\r
-      ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1,\r
-              size, viewport.getGapCharacter());\r
-    else\r
-      ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2,\r
-              size, viewport.getGapCharacter());\r
-\r
-    int groupAdjustment = 0;\r
-    if (ssc.getGapsInsertedBegin() && right)\r
-    {\r
-      if (viewport.cursorMode)\r
-        alignPanel.seqPanel.moveCursor(size, 0);\r
-      else\r
-        groupAdjustment = size;\r
-    }\r
-    else if (!ssc.getGapsInsertedBegin() && !right)\r
-    {\r
-      if (viewport.cursorMode)\r
-        alignPanel.seqPanel.moveCursor(-size, 0);\r
-      else\r
-        groupAdjustment = -size;\r
-    }\r
-\r
-    if (groupAdjustment != 0)\r
-    {\r
-      viewport.getSelectionGroup().setStartRes(\r
-              viewport.getSelectionGroup().getStartRes() + groupAdjustment);\r
-      viewport.getSelectionGroup().setEndRes(\r
-              viewport.getSelectionGroup().getEndRes() + groupAdjustment);\r
-    }\r
-\r
-    boolean appendHistoryItem = false;\r
-    if (viewport.historyList != null && viewport.historyList.size() > 0\r
-            && viewport.historyList.peek() instanceof SlideSequencesCommand)\r
-    {\r
-      appendHistoryItem = ssc\r
-              .appendSlideCommand((SlideSequencesCommand) viewport.historyList\r
-                      .peek());\r
-    }\r
-\r
-    if (!appendHistoryItem)\r
-      addHistoryItem(ssc);\r
-\r
-    repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void copy_actionPerformed(ActionEvent e)\r
-  {\r
-    System.gc();\r
-    if (viewport.getSelectionGroup() == null)\r
-    {\r
-      return;\r
-    }\r
-    // TODO: preserve the ordering of displayed alignment annotation in any\r
-    // internal paste (particularly sequence associated annotation)\r
-    SequenceI[] seqs = viewport.getSelectionAsNewSequence();\r
-    String[] omitHidden = null;\r
-\r
-    if (viewport.hasHiddenColumns())\r
-    {\r
-      omitHidden = viewport.getViewAsString(true);\r
-    }\r
-\r
-    String output = new FormatAdapter().formatSequences("Fasta", seqs,\r
-            omitHidden);\r
-\r
-    StringSelection ss = new StringSelection(output);\r
-\r
-    try\r
-    {\r
-      jalview.gui.Desktop.internalCopy = true;\r
-      // Its really worth setting the clipboard contents\r
-      // to empty before setting the large StringSelection!!\r
-      Toolkit.getDefaultToolkit().getSystemClipboard()\r
-              .setContents(new StringSelection(""), null);\r
-\r
-      Toolkit.getDefaultToolkit().getSystemClipboard()\r
-              .setContents(ss, Desktop.instance);\r
-    } catch (OutOfMemoryError er)\r
-    {\r
-      new OOMWarning("copying region", er);\r
-      return;\r
-    }\r
-\r
-    Vector hiddenColumns = null;\r
-    if (viewport.hasHiddenColumns())\r
-    {\r
-      hiddenColumns = new Vector();\r
-      int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport\r
-              .getSelectionGroup().getEndRes();\r
-      for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()\r
-              .size(); i++)\r
-      {\r
-        int[] region = (int[]) viewport.getColumnSelection()\r
-                .getHiddenColumns().elementAt(i);\r
-        if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)\r
-        {\r
-          hiddenColumns.addElement(new int[]\r
-          { region[0] - hiddenOffset, region[1] - hiddenOffset });\r
-        }\r
-      }\r
-    }\r
-\r
-    Desktop.jalviewClipboard = new Object[]\r
-    { seqs, viewport.getAlignment().getDataset(), hiddenColumns };\r
-    statusBar.setText(MessageManager.formatMessage("label.copied_sequences_to_clipboard", new String[]{Integer.valueOf(seqs.length).toString()}));\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void pasteNew_actionPerformed(ActionEvent e)\r
-  {\r
-    paste(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void pasteThis_actionPerformed(ActionEvent e)\r
-  {\r
-    paste(false);\r
-  }\r
-\r
-  /**\r
-   * Paste contents of Jalview clipboard\r
-   * \r
-   * @param newAlignment\r
-   *          true to paste to a new alignment, otherwise add to this.\r
-   */\r
-  void paste(boolean newAlignment)\r
-  {\r
-    boolean externalPaste = true;\r
-    try\r
-    {\r
-      Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();\r
-      Transferable contents = c.getContents(this);\r
-\r
-      if (contents == null)\r
-      {\r
-        return;\r
-      }\r
-\r
-      String str, format;\r
-      try\r
-      {\r
-        str = (String) contents.getTransferData(DataFlavor.stringFlavor);\r
-        if (str.length() < 1)\r
-        {\r
-          return;\r
-        }\r
-\r
-        format = new IdentifyFile().Identify(str, "Paste");\r
-\r
-      } catch (OutOfMemoryError er)\r
-      {\r
-        new OOMWarning("Out of memory pasting sequences!!", er);\r
-        return;\r
-      }\r
-\r
-      SequenceI[] sequences;\r
-      boolean annotationAdded = false;\r
-      AlignmentI alignment = null;\r
-\r
-      if (Desktop.jalviewClipboard != null)\r
-      {\r
-        // The clipboard was filled from within Jalview, we must use the\r
-        // sequences\r
-        // And dataset from the copied alignment\r
-        SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];\r
-        // be doubly sure that we create *new* sequence objects.\r
-        sequences = new SequenceI[newseq.length];\r
-        for (int i = 0; i < newseq.length; i++)\r
-        {\r
-          sequences[i] = new Sequence(newseq[i]);\r
-        }\r
-        alignment = new Alignment(sequences);\r
-        externalPaste = false;\r
-      }\r
-      else\r
-      {\r
-        // parse the clipboard as an alignment.\r
-        alignment = new FormatAdapter().readFile(str, "Paste", format);\r
-        sequences = alignment.getSequencesArray();\r
-      }\r
-\r
-      int alwidth = 0;\r
-      ArrayList<Integer> newGraphGroups = new ArrayList<Integer>();\r
-      int fgroup = -1;\r
-\r
-      if (newAlignment)\r
-      {\r
-\r
-        if (Desktop.jalviewClipboard != null)\r
-        {\r
-          // dataset is inherited\r
-          alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);\r
-        }\r
-        else\r
-        {\r
-          // new dataset is constructed\r
-          alignment.setDataset(null);\r
-        }\r
-        alwidth = alignment.getWidth() + 1;\r
-      }\r
-      else\r
-      {\r
-        AlignmentI pastedal = alignment; // preserve pasted alignment object\r
-        // Add pasted sequences and dataset into existing alignment.\r
-        alignment = viewport.getAlignment();\r
-        alwidth = alignment.getWidth() + 1;\r
-        // decide if we need to import sequences from an existing dataset\r
-        boolean importDs = Desktop.jalviewClipboard != null\r
-                && Desktop.jalviewClipboard[1] != alignment.getDataset();\r
-        // importDs==true instructs us to copy over new dataset sequences from\r
-        // an existing alignment\r
-        Vector newDs = (importDs) ? new Vector() : null; // used to create\r
-        // minimum dataset set\r
-\r
-        for (int i = 0; i < sequences.length; i++)\r
-        {\r
-          if (importDs)\r
-          {\r
-            newDs.addElement(null);\r
-          }\r
-          SequenceI ds = sequences[i].getDatasetSequence(); // null for a simple\r
-          // paste\r
-          if (importDs && ds != null)\r
-          {\r
-            if (!newDs.contains(ds))\r
-            {\r
-              newDs.setElementAt(ds, i);\r
-              ds = new Sequence(ds);\r
-              // update with new dataset sequence\r
-              sequences[i].setDatasetSequence(ds);\r
-            }\r
-            else\r
-            {\r
-              ds = sequences[newDs.indexOf(ds)].getDatasetSequence();\r
-            }\r
-          }\r
-          else\r
-          {\r
-            // copy and derive new dataset sequence\r
-            sequences[i] = sequences[i].deriveSequence();\r
-            alignment.getDataset().addSequence(\r
-                    sequences[i].getDatasetSequence());\r
-            // TODO: avoid creation of duplicate dataset sequences with a\r
-            // 'contains' method using SequenceI.equals()/SequenceI.contains()\r
-          }\r
-          alignment.addSequence(sequences[i]); // merges dataset\r
-        }\r
-        if (newDs != null)\r
-        {\r
-          newDs.clear(); // tidy up\r
-        }\r
-        if (alignment.getAlignmentAnnotation() != null)\r
-        {\r
-          for (AlignmentAnnotation alan : alignment\r
-                  .getAlignmentAnnotation())\r
-          {\r
-            if (alan.graphGroup > fgroup)\r
-            {\r
-              fgroup = alan.graphGroup;\r
-            }\r
-          }\r
-        }\r
-        if (pastedal.getAlignmentAnnotation() != null)\r
-        {\r
-          // Add any annotation attached to alignment.\r
-          AlignmentAnnotation[] alann = pastedal.getAlignmentAnnotation();\r
-          for (int i = 0; i < alann.length; i++)\r
-          {\r
-            annotationAdded = true;\r
-            if (alann[i].sequenceRef == null && !alann[i].autoCalculated)\r
-            {\r
-              AlignmentAnnotation newann = new AlignmentAnnotation(alann[i]);\r
-              if (newann.graphGroup > -1)\r
-              {\r
-                if (newGraphGroups.size() <= newann.graphGroup\r
-                        || newGraphGroups.get(newann.graphGroup) == null)\r
-                {\r
-                  for (int q = newGraphGroups.size(); q <= newann.graphGroup; q++)\r
-                  {\r
-                    newGraphGroups.add(q, null);\r
-                  }\r
-                  newGraphGroups.set(newann.graphGroup, new Integer(\r
-                          ++fgroup));\r
-                }\r
-                newann.graphGroup = newGraphGroups.get(newann.graphGroup)\r
-                        .intValue();\r
-              }\r
-\r
-              newann.padAnnotation(alwidth);\r
-              alignment.addAnnotation(newann);\r
-            }\r
-          }\r
-        }\r
-      }\r
-      if (!newAlignment)\r
-      {\r
-        // /////\r
-        // ADD HISTORY ITEM\r
-        //\r
-        addHistoryItem(new EditCommand("Add sequences", EditCommand.PASTE,\r
-                sequences, 0, alignment.getWidth(), alignment));\r
-      }\r
-      // Add any annotations attached to sequences\r
-      for (int i = 0; i < sequences.length; i++)\r
-      {\r
-        if (sequences[i].getAnnotation() != null)\r
-        {\r
-          AlignmentAnnotation newann;\r
-          for (int a = 0; a < sequences[i].getAnnotation().length; a++)\r
-          {\r
-            annotationAdded = true;\r
-            newann = sequences[i].getAnnotation()[a];\r
-            newann.adjustForAlignment();\r
-            newann.padAnnotation(alwidth);\r
-            if (newann.graphGroup > -1)\r
-            {\r
-              if (newann.graphGroup > -1)\r
-              {\r
-                if (newGraphGroups.size() <= newann.graphGroup\r
-                        || newGraphGroups.get(newann.graphGroup) == null)\r
-                {\r
-                  for (int q = newGraphGroups.size(); q <= newann.graphGroup; q++)\r
-                  {\r
-                    newGraphGroups.add(q, null);\r
-                  }\r
-                  newGraphGroups.set(newann.graphGroup, new Integer(\r
-                          ++fgroup));\r
-                }\r
-                newann.graphGroup = newGraphGroups.get(newann.graphGroup)\r
-                        .intValue();\r
-              }\r
-            }\r
-            alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation\r
-            // was\r
-            // duplicated\r
-            // earlier\r
-            alignment\r
-                    .setAnnotationIndex(sequences[i].getAnnotation()[a], a);\r
-          }\r
-        }\r
-      }\r
-      if (!newAlignment)\r
-      {\r
-\r
-        // propagate alignment changed.\r
-        viewport.setEndSeq(alignment.getHeight());\r
-        if (annotationAdded)\r
-        {\r
-          // Duplicate sequence annotation in all views.\r
-          AlignmentI[] alview = this.getViewAlignments();\r
-          for (int i = 0; i < sequences.length; i++)\r
-          {\r
-            AlignmentAnnotation sann[] = sequences[i].getAnnotation();\r
-            if (sann == null)\r
-              continue;\r
-            for (int avnum = 0; avnum < alview.length; avnum++)\r
-            {\r
-              if (alview[avnum] != alignment)\r
-              {\r
-                // duplicate in a view other than the one with input focus\r
-                int avwidth = alview[avnum].getWidth() + 1;\r
-                // this relies on sann being preserved after we\r
-                // modify the sequence's annotation array for each duplication\r
-                for (int a = 0; a < sann.length; a++)\r
-                {\r
-                  AlignmentAnnotation newann = new AlignmentAnnotation(\r
-                          sann[a]);\r
-                  sequences[i].addAlignmentAnnotation(newann);\r
-                  newann.padAnnotation(avwidth);\r
-                  alview[avnum].addAnnotation(newann); // annotation was\r
-                  // duplicated earlier\r
-                  // TODO JAL-1145 graphGroups are not updated for sequence\r
-                  // annotation added to several views. This may cause\r
-                  // strangeness\r
-                  alview[avnum].setAnnotationIndex(newann, a);\r
-                }\r
-              }\r
-            }\r
-          }\r
-          buildSortByAnnotationScoresMenu();\r
-        }\r
-        viewport.firePropertyChange("alignment", null,\r
-                alignment.getSequences());\r
-        if (alignPanels != null)\r
-        {\r
-          for (AlignmentPanel ap : ((Vector<AlignmentPanel>) alignPanels))\r
-          {\r
-            ap.validateAnnotationDimensions(false);\r
-          }\r
-        }\r
-        else\r
-        {\r
-          alignPanel.validateAnnotationDimensions(false);\r
-        }\r
-\r
-      }\r
-      else\r
-      {\r
-        AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,\r
-                DEFAULT_HEIGHT);\r
-        String newtitle = new String("Copied sequences");\r
-\r
-        if (Desktop.jalviewClipboard != null\r
-                && Desktop.jalviewClipboard[2] != null)\r
-        {\r
-          Vector hc = (Vector) Desktop.jalviewClipboard[2];\r
-          for (int i = 0; i < hc.size(); i++)\r
-          {\r
-            int[] region = (int[]) hc.elementAt(i);\r
-            af.viewport.hideColumns(region[0], region[1]);\r
-          }\r
-        }\r
-\r
-        // >>>This is a fix for the moment, until a better solution is\r
-        // found!!<<<\r
-        af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()\r
-                .transferSettings(\r
-                        alignPanel.seqPanel.seqCanvas.getFeatureRenderer());\r
-\r
-        // TODO: maintain provenance of an alignment, rather than just make the\r
-        // title a concatenation of operations.\r
-        if (!externalPaste)\r
-        {\r
-          if (title.startsWith("Copied sequences"))\r
-          {\r
-            newtitle = title;\r
-          }\r
-          else\r
-          {\r
-            newtitle = newtitle.concat("- from " + title);\r
-          }\r
-        }\r
-        else\r
-        {\r
-          newtitle = new String("Pasted sequences");\r
-        }\r
-\r
-        Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,\r
-                DEFAULT_HEIGHT);\r
-\r
-      }\r
-\r
-    } catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-      System.out.println("Exception whilst pasting: " + ex);\r
-      // could be anything being pasted in here\r
-    }\r
-\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void cut_actionPerformed(ActionEvent e)\r
-  {\r
-    copy_actionPerformed(null);\r
-    delete_actionPerformed(null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void delete_actionPerformed(ActionEvent evt)\r
-  {\r
-\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-    if (sg == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    Vector seqs = new Vector();\r
-    SequenceI seq;\r
-    for (int i = 0; i < sg.getSize(); i++)\r
-    {\r
-      seq = sg.getSequenceAt(i);\r
-      seqs.addElement(seq);\r
-    }\r
-\r
-    // If the cut affects all sequences, remove highlighted columns\r
-    if (sg.getSize() == viewport.getAlignment().getHeight())\r
-    {\r
-      viewport.getColumnSelection().removeElements(sg.getStartRes(),\r
-              sg.getEndRes() + 1);\r
-    }\r
-\r
-    SequenceI[] cut = new SequenceI[seqs.size()];\r
-    for (int i = 0; i < seqs.size(); i++)\r
-    {\r
-      cut[i] = (SequenceI) seqs.elementAt(i);\r
-    }\r
-\r
-    /*\r
-     * //ADD HISTORY ITEM\r
-     */\r
-    addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,\r
-            sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,\r
-            viewport.getAlignment()));\r
-\r
-    viewport.setSelectionGroup(null);\r
-    viewport.sendSelection();\r
-    viewport.getAlignment().deleteGroup(sg);\r
-\r
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment()\r
-            .getSequences());\r
-    if (viewport.getAlignment().getHeight() < 1)\r
-    {\r
-      try\r
-      {\r
-        this.setClosed(true);\r
-      } catch (Exception ex)\r
-      {\r
-      }\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void deleteGroups_actionPerformed(ActionEvent e)\r
-  {\r
-    if (avc.deleteGroups()) {\r
-      PaintRefresher.Refresh(this, viewport.getSequenceSetId());\r
-      alignPanel.updateAnnotation();\r
-      alignPanel.paintAlignment(true);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceGroup sg = new SequenceGroup();\r
-\r
-    for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)\r
-    {\r
-      sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);\r
-    }\r
-\r
-    sg.setEndRes(viewport.getAlignment().getWidth() - 1);\r
-    viewport.setSelectionGroup(sg);\r
-    viewport.sendSelection();\r
-    alignPanel.paintAlignment(true);\r
-    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.cursorMode)\r
-    {\r
-      alignPanel.seqPanel.keyboardNo1 = null;\r
-      alignPanel.seqPanel.keyboardNo2 = null;\r
-    }\r
-    viewport.setSelectionGroup(null);\r
-    viewport.getColumnSelection().clear();\r
-    viewport.setSelectionGroup(null);\r
-    alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);\r
-    alignPanel.idPanel.idCanvas.searchResults = null;\r
-    alignPanel.paintAlignment(true);\r
-    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());\r
-    viewport.sendSelection();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void invertSequenceMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-\r
-    if (sg == null)\r
-    {\r
-      selectAllSequenceMenuItem_actionPerformed(null);\r
-\r
-      return;\r
-    }\r
-\r
-    for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)\r
-    {\r
-      sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);\r
-    }\r
-\r
-    alignPanel.paintAlignment(true);\r
-    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());\r
-    viewport.sendSelection();\r
-  }\r
-\r
-  @Override\r
-  public void invertColSel_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.invertColumnSelection();\r
-    alignPanel.paintAlignment(true);\r
-    viewport.sendSelection();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void remove2LeftMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    trimAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void remove2RightMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    trimAlignment(false);\r
-  }\r
-\r
-  void trimAlignment(boolean trimLeft)\r
-  {\r
-    ColumnSelection colSel = viewport.getColumnSelection();\r
-    int column;\r
-\r
-    if (colSel.size() > 0)\r
-    {\r
-      if (trimLeft)\r
-      {\r
-        column = colSel.getMin();\r
-      }\r
-      else\r
-      {\r
-        column = colSel.getMax();\r
-      }\r
-\r
-      SequenceI[] seqs;\r
-      if (viewport.getSelectionGroup() != null)\r
-      {\r
-        seqs = viewport.getSelectionGroup().getSequencesAsArray(\r
-                viewport.getHiddenRepSequences());\r
-      }\r
-      else\r
-      {\r
-        seqs = viewport.getAlignment().getSequencesArray();\r
-      }\r
-\r
-      TrimRegionCommand trimRegion;\r
-      if (trimLeft)\r
-      {\r
-        trimRegion = new TrimRegionCommand("Remove Left",\r
-                TrimRegionCommand.TRIM_LEFT, seqs, column,\r
-                viewport.getAlignment(), viewport.getColumnSelection(),\r
-                viewport.getSelectionGroup());\r
-        viewport.setStartRes(0);\r
-      }\r
-      else\r
-      {\r
-        trimRegion = new TrimRegionCommand("Remove Right",\r
-                TrimRegionCommand.TRIM_RIGHT, seqs, column,\r
-                viewport.getAlignment(), viewport.getColumnSelection(),\r
-                viewport.getSelectionGroup());\r
-      }\r
-\r
-      statusBar.setText(MessageManager.formatMessage("label.removed_columns", new String[]{Integer.valueOf(trimRegion.getSize()).toString()}));\r
-\r
-      addHistoryItem(trimRegion);\r
-\r
-      for (SequenceGroup sg : viewport.getAlignment().getGroups())\r
-      {\r
-        if ((trimLeft && !sg.adjustForRemoveLeft(column))\r
-                || (!trimLeft && !sg.adjustForRemoveRight(column)))\r
-        {\r
-          viewport.getAlignment().deleteGroup(sg);\r
-        }\r
-      }\r
-\r
-      viewport.firePropertyChange("alignment", null, viewport\r
-              .getAlignment().getSequences());\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    int start = 0, end = viewport.getAlignment().getWidth() - 1;\r
-\r
-    SequenceI[] seqs;\r
-    if (viewport.getSelectionGroup() != null)\r
-    {\r
-      seqs = viewport.getSelectionGroup().getSequencesAsArray(\r
-              viewport.getHiddenRepSequences());\r
-      start = viewport.getSelectionGroup().getStartRes();\r
-      end = viewport.getSelectionGroup().getEndRes();\r
-    }\r
-    else\r
-    {\r
-      seqs = viewport.getAlignment().getSequencesArray();\r
-    }\r
-\r
-    RemoveGapColCommand removeGapCols = new RemoveGapColCommand(\r
-            "Remove Gapped Columns", seqs, start, end,\r
-            viewport.getAlignment());\r
-\r
-    addHistoryItem(removeGapCols);\r
-\r
-    statusBar.setText(MessageManager.formatMessage("label.removed_empty_columns", new String[]{Integer.valueOf(removeGapCols.getSize()).toString()}));\r
-\r
-    // This is to maintain viewport position on first residue\r
-    // of first sequence\r
-    SequenceI seq = viewport.getAlignment().getSequenceAt(0);\r
-    int startRes = seq.findPosition(viewport.startRes);\r
-    // ShiftList shifts;\r
-    // viewport.getAlignment().removeGaps(shifts=new ShiftList());\r
-    // edit.alColumnChanges=shifts.getInverse();\r
-    // if (viewport.hasHiddenColumns)\r
-    // viewport.getColumnSelection().compensateForEdits(shifts);\r
-    viewport.setStartRes(seq.findIndex(startRes) - 1);\r
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment()\r
-            .getSequences());\r
-\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    int start = 0, end = viewport.getAlignment().getWidth() - 1;\r
-\r
-    SequenceI[] seqs;\r
-    if (viewport.getSelectionGroup() != null)\r
-    {\r
-      seqs = viewport.getSelectionGroup().getSequencesAsArray(\r
-              viewport.getHiddenRepSequences());\r
-      start = viewport.getSelectionGroup().getStartRes();\r
-      end = viewport.getSelectionGroup().getEndRes();\r
-    }\r
-    else\r
-    {\r
-      seqs = viewport.getAlignment().getSequencesArray();\r
-    }\r
-\r
-    // This is to maintain viewport position on first residue\r
-    // of first sequence\r
-    SequenceI seq = viewport.getAlignment().getSequenceAt(0);\r
-    int startRes = seq.findPosition(viewport.startRes);\r
-\r
-    addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,\r
-            viewport.getAlignment()));\r
-\r
-    viewport.setStartRes(seq.findIndex(startRes) - 1);\r
-\r
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment()\r
-            .getSequences());\r
-\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void padGapsMenuitem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setPadGaps(padGapsMenuitem.isSelected());\r
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment()\r
-            .getSequences());\r
-  }\r
-\r
-  // else\r
-  {\r
-    // if (justifySeqs>0)\r
-    {\r
-      // alignment.justify(justifySeqs!=RIGHT_JUSTIFY);\r
-    }\r
-  }\r
-\r
-  // }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void findMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    new Finder();\r
-  }\r
-\r
-  @Override\r
-  public void newView_actionPerformed(ActionEvent e)\r
-  {\r
-    newView(true);\r
-  }\r
-\r
-  /**\r
-   * \r
-   * @param copyAnnotation\r
-   *          if true then duplicate all annnotation, groups and settings\r
-   * @return new alignment panel, already displayed.\r
-   */\r
-  public AlignmentPanel newView(boolean copyAnnotation)\r
-  {\r
-    return newView(null, copyAnnotation);\r
-  }\r
-\r
-  /**\r
-   * \r
-   * @param viewTitle\r
-   *          title of newly created view\r
-   * @return new alignment panel, already displayed.\r
-   */\r
-  public AlignmentPanel newView(String viewTitle)\r
-  {\r
-    return newView(viewTitle, true);\r
-  }\r
-\r
-  /**\r
-   * \r
-   * @param viewTitle\r
-   *          title of newly created view\r
-   * @param copyAnnotation\r
-   *          if true then duplicate all annnotation, groups and settings\r
-   * @return new alignment panel, already displayed.\r
-   */\r
-  public AlignmentPanel newView(String viewTitle, boolean copyAnnotation)\r
-  {\r
-    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,\r
-            true);\r
-    if (!copyAnnotation)\r
-    {\r
-      // just remove all the current annotation except for the automatic stuff\r
-      newap.av.getAlignment().deleteAllGroups();\r
-      for (AlignmentAnnotation alan : newap.av.getAlignment()\r
-              .getAlignmentAnnotation())\r
-      {\r
-        if (!alan.autoCalculated)\r
-        {\r
-          newap.av.getAlignment().deleteAnnotation(alan);\r
-        }\r
-        ;\r
-      }\r
-    }\r
-\r
-    newap.av.gatherViewsHere = false;\r
-\r
-    if (viewport.viewName == null)\r
-    {\r
-      viewport.viewName = "Original";\r
-    }\r
-\r
-    newap.av.historyList = viewport.historyList;\r
-    newap.av.redoList = viewport.redoList;\r
-\r
-    int index = Desktop.getViewCount(viewport.getSequenceSetId());\r
-    // make sure the new view has a unique name - this is essential for Jalview\r
-    // 2 archives\r
-    boolean addFirstIndex = false;\r
-    if (viewTitle == null || viewTitle.trim().length() == 0)\r
-    {\r
-      viewTitle = "View";\r
-      addFirstIndex = true;\r
-    }\r
-    else\r
-    {\r
-      index = 1;// we count from 1 if given a specific name\r
-    }\r
-    String newViewName = viewTitle + ((addFirstIndex) ? " " + index : "");\r
-    Vector comps = (Vector) PaintRefresher.components.get(viewport\r
-            .getSequenceSetId());\r
-    Vector existingNames = new Vector();\r
-    for (int i = 0; i < comps.size(); i++)\r
-    {\r
-      if (comps.elementAt(i) instanceof AlignmentPanel)\r
-      {\r
-        AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);\r
-        if (!existingNames.contains(ap.av.viewName))\r
-        {\r
-          existingNames.addElement(ap.av.viewName);\r
-        }\r
-      }\r
-    }\r
-\r
-    while (existingNames.contains(newViewName))\r
-    {\r
-      newViewName = viewTitle + " " + (++index);\r
-    }\r
-\r
-    newap.av.viewName = newViewName;\r
-\r
-    addAlignmentPanel(newap, true);\r
-    newap.alignmentChanged();\r
-    \r
-    if (alignPanels.size() == 2)\r
-    {\r
-      viewport.gatherViewsHere = true;\r
-    }\r
-    tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);\r
-    return newap;\r
-  }\r
-\r
-  @Override\r
-  public void expandViews_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.explodeViews(this);\r
-  }\r
-\r
-  @Override\r
-  public void gatherViews_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.gatherViews(this);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void font_actionPerformed(ActionEvent e)\r
-  {\r
-    new FontChooser(alignPanel);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void seqLimit_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowJVSuffix(seqLimits.isSelected());\r
-\r
-    alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel\r
-            .calculateIdWidth());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  @Override\r
-  public void idRightAlign_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.rightAlignIds = idRightAlign.isSelected();\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  @Override\r
-  public void centreColumnLabels_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()\r
-   */\r
-  @Override\r
-  protected void followHighlight_actionPerformed()\r
-  {\r
-    if (viewport.followHighlight = this.followHighlightMenuItem.getState())\r
-    {\r
-      alignPanel.scrollToPosition(\r
-              alignPanel.seqPanel.seqCanvas.searchResults, false);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void colourTextMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setColourText(colourTextMenuItem.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void wrapMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    scaleAbove.setVisible(wrapMenuItem.isSelected());\r
-    scaleLeft.setVisible(wrapMenuItem.isSelected());\r
-    scaleRight.setVisible(wrapMenuItem.isSelected());\r
-    viewport.setWrapAlignment(wrapMenuItem.isSelected());\r
-    alignPanel.setWrapAlignment(wrapMenuItem.isSelected());\r
-  }\r
-\r
-  @Override\r
-  public void showAllSeqs_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.showAllHiddenSeqs();\r
-  }\r
-\r
-  @Override\r
-  public void showAllColumns_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.showAllHiddenColumns();\r
-    repaint();\r
-  }\r
-\r
-  @Override\r
-  public void hideSelSequences_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.hideAllSelectedSeqs();\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * called by key handler and the hide all/show all menu items\r
-   * \r
-   * @param toggleSeqs\r
-   * @param toggleCols\r
-   */\r
-  private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)\r
-  {\r
-\r
-    boolean hide = false;\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-    if (!toggleSeqs && !toggleCols)\r
-    {\r
-      // Hide everything by the current selection - this is a hack - we do the\r
-      // invert and then hide\r
-      // first check that there will be visible columns after the invert.\r
-      if ((viewport.getColumnSelection() != null\r
-              && viewport.getColumnSelection().getSelected() != null && viewport\r
-              .getColumnSelection().getSelected().size() > 0)\r
-              || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg\r
-                      .getEndRes()))\r
-      {\r
-        // now invert the sequence set, if required - empty selection implies\r
-        // that no hiding is required.\r
-        if (sg != null)\r
-        {\r
-          invertSequenceMenuItem_actionPerformed(null);\r
-          sg = viewport.getSelectionGroup();\r
-          toggleSeqs = true;\r
-\r
-        }\r
-        viewport.expandColSelection(sg, true);\r
-        // finally invert the column selection and get the new sequence\r
-        // selection.\r
-        invertColSel_actionPerformed(null);\r
-        toggleCols = true;\r
-      }\r
-    }\r
-\r
-    if (toggleSeqs)\r
-    {\r
-      if (sg != null && sg.getSize() != viewport.getAlignment().getHeight())\r
-      {\r
-        hideSelSequences_actionPerformed(null);\r
-        hide = true;\r
-      }\r
-      else if (!(toggleCols && viewport.getColumnSelection().getSelected()\r
-              .size() > 0))\r
-      {\r
-        showAllSeqs_actionPerformed(null);\r
-      }\r
-    }\r
-\r
-    if (toggleCols)\r
-    {\r
-      if (viewport.getColumnSelection().getSelected().size() > 0)\r
-      {\r
-        hideSelColumns_actionPerformed(null);\r
-        if (!toggleSeqs)\r
-        {\r
-          viewport.setSelectionGroup(sg);\r
-        }\r
-      }\r
-      else if (!hide)\r
-      {\r
-        showAllColumns_actionPerformed(null);\r
-      }\r
-    }\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.\r
-   * event.ActionEvent)\r
-   */\r
-  @Override\r
-  public void hideAllButSelection_actionPerformed(ActionEvent e)\r
-  {\r
-    toggleHiddenRegions(false, false);\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event\r
-   * .ActionEvent)\r
-   */\r
-  @Override\r
-  public void hideAllSelection_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-    viewport.expandColSelection(sg, false);\r
-    viewport.hideAllSelectedSeqs();\r
-    viewport.hideSelectedColumns();\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.\r
-   * ActionEvent)\r
-   */\r
-  @Override\r
-  public void showAllhidden_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.showAllHiddenColumns();\r
-    viewport.showAllHiddenSeqs();\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  @Override\r
-  public void hideSelColumns_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.hideSelectedColumns();\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  @Override\r
-  public void hiddenMarkers_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());\r
-    repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void scaleAbove_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setScaleAboveWrapped(scaleAbove.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void scaleLeft_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setScaleLeftWrapped(scaleLeft.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void scaleRight_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setScaleRightWrapped(scaleRight.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void viewBoxesMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowBoxes(viewBoxesMenuItem.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void viewTextMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowText(viewTextMenuItem.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void renderGapsMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setRenderGaps(renderGapsMenuItem.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  public FeatureSettings featureSettings;\r
-\r
-  @Override\r
-  public void featureSettings_actionPerformed(ActionEvent e)\r
-  {\r
-    if (featureSettings != null)\r
-    {\r
-      featureSettings.close();\r
-      featureSettings = null;\r
-    }\r
-    if (!showSeqFeatures.isSelected())\r
-    {\r
-      // make sure features are actually displayed\r
-      showSeqFeatures.setSelected(true);\r
-      showSeqFeatures_actionPerformed(null);\r
-    }\r
-    featureSettings = new FeatureSettings(this);\r
-  }\r
-\r
-  /**\r
-   * Set or clear 'Show Sequence Features'\r
-   * \r
-   * @param evt\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void showSeqFeatures_actionPerformed(ActionEvent evt)\r
-  {\r
-    viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());\r
-    alignPanel.paintAlignment(true);\r
-    if (alignPanel.getOverviewPanel() != null)\r
-    {\r
-      alignPanel.getOverviewPanel().updateOverviewImage();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Set or clear 'Show Sequence Features'\r
-   * \r
-   * @param evt\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)\r
-  {\r
-    viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight\r
-            .isSelected());\r
-    if (viewport.getShowSequenceFeaturesHeight())\r
-    {\r
-      // ensure we're actually displaying features\r
-      viewport.setShowSequenceFeatures(true);\r
-      showSeqFeatures.setSelected(true);\r
-    }\r
-    alignPanel.paintAlignment(true);\r
-    if (alignPanel.getOverviewPanel() != null)\r
-    {\r
-      alignPanel.getOverviewPanel().updateOverviewImage();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void annotationPanelMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());\r
-    alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());\r
-  }\r
-\r
-  @Override\r
-  public void alignmentProperties()\r
-  {\r
-    JEditorPane editPane = new JEditorPane("text/html", "");\r
-    editPane.setEditable(false);\r
-    StringBuffer contents = new AlignmentProperties(viewport.getAlignment())\r
-            .formatAsHtml();\r
-    editPane.setText(MessageManager.formatMessage("label.html_content", new String[]{contents.toString()}));\r
-    JInternalFrame frame = new JInternalFrame();\r
-    frame.getContentPane().add(new JScrollPane(editPane));\r
-\r
-    Desktop.instance.addInternalFrame(frame, MessageManager.formatMessage("label.alignment_properties", new String[]{getTitle()}), 500, 400);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void overviewMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if (alignPanel.overviewPanel != null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    JInternalFrame frame = new JInternalFrame();\r
-    OverviewPanel overview = new OverviewPanel(alignPanel);\r
-    frame.setContentPane(overview);\r
-    Desktop.addInternalFrame(frame, MessageManager.formatMessage("label.overview_params", new String[]{this.getTitle()}),\r
-            frame.getWidth(), frame.getHeight());\r
-    frame.pack();\r
-    frame.setLayer(JLayeredPane.PALETTE_LAYER);\r
-    frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()\r
-    {\r
-      @Override\r
-      public void internalFrameClosed(\r
-              javax.swing.event.InternalFrameEvent evt)\r
-      {\r
-        alignPanel.setOverviewPanel(null);\r
-      };\r
-    });\r
-\r
-    alignPanel.setOverviewPanel(overview);\r
-  }\r
-\r
-  @Override\r
-  public void textColour_actionPerformed(ActionEvent e)\r
-  {\r
-    new TextColourChooser().chooseColour(alignPanel, null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void noColourmenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void clustalColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new ClustalxColourScheme(viewport.getAlignment(),\r
-            viewport.getHiddenRepSequences()));\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void zappoColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new ZappoColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void taylorColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new TaylorColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void hydrophobicityColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new HydrophobicColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void helixColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new HelixColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void strandColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new StrandColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void turnColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new TurnColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void buriedColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new BuriedColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void nucleotideColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new NucleotideColourScheme());\r
-  }\r
-\r
-  @Override\r
-  public void purinePyrimidineColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new PurinePyrimidineColourScheme());\r
-  }\r
-\r
-  /*\r
-   * public void covariationColour_actionPerformed(ActionEvent e) {\r
-   * changeColour(new\r
-   * CovariationColourScheme(viewport.getAlignment().getAlignmentAnnotation\r
-   * ()[0])); }\r
-   */\r
-  @Override\r
-  public void annotationColour_actionPerformed(ActionEvent e)\r
-  {\r
-    new AnnotationColourChooser(viewport, alignPanel);\r
-  }\r
-\r
-  @Override\r
-  public void rnahelicesColour_actionPerformed(ActionEvent e)\r
-  {\r
-    new RNAHelicesColourChooser(viewport, alignPanel);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void applyToAllGroups_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param cs\r
-   *          DOCUMENT ME!\r
-   */\r
-  public void changeColour(ColourSchemeI cs)\r
-  {\r
-    // TODO: compare with applet and pull up to model method\r
-    int threshold = 0;\r
-\r
-    if (cs != null)\r
-    {\r
-      if (viewport.getAbovePIDThreshold())\r
-      {\r
-        threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,\r
-                "Background");\r
-\r
-        cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());\r
-\r
-        viewport.setGlobalColourScheme(cs);\r
-      }\r
-      else\r
-      {\r
-        cs.setThreshold(0, viewport.getIgnoreGapsConsensus());\r
-      }\r
-\r
-      if (viewport.getConservationSelected())\r
-      {\r
-\r
-        Alignment al = (Alignment) viewport.getAlignment();\r
-        Conservation c = new Conservation("All",\r
-                ResidueProperties.propHash, 3, al.getSequences(), 0,\r
-                al.getWidth() - 1);\r
-\r
-        c.calculate();\r
-        c.verdict(false, viewport.getConsPercGaps());\r
-\r
-        cs.setConservation(c);\r
-\r
-        cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,\r
-                cs, "Background"));\r
-      }\r
-      else\r
-      {\r
-        cs.setConservation(null);\r
-      }\r
-\r
-      cs.setConsensus(viewport.getSequenceConsensusHash());\r
-    }\r
-\r
-    viewport.setGlobalColourScheme(cs);\r
-\r
-    if (viewport.getColourAppliesToAllGroups())\r
-    {\r
-\r
-      for (SequenceGroup sg : viewport.getAlignment().getGroups())\r
-      {\r
-        if (cs == null)\r
-        {\r
-          sg.cs = null;\r
-          continue;\r
-        }\r
-\r
-        if (cs instanceof ClustalxColourScheme)\r
-        {\r
-          sg.cs = new ClustalxColourScheme(sg,\r
-                  viewport.getHiddenRepSequences());\r
-        }\r
-        else if (cs instanceof UserColourScheme)\r
-        {\r
-          sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());\r
-        }\r
-        else\r
-        {\r
-          try\r
-          {\r
-            sg.cs = cs.getClass().newInstance();\r
-          } catch (Exception ex)\r
-          {\r
-          }\r
-        }\r
-\r
-        if (viewport.getAbovePIDThreshold()\r
-                || cs instanceof PIDColourScheme\r
-                || cs instanceof Blosum62ColourScheme)\r
-        {\r
-          sg.cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());\r
-\r
-          sg.cs.setConsensus(AAFrequency.calculate(\r
-                  sg.getSequences(viewport.getHiddenRepSequences()),\r
-                  sg.getStartRes(), sg.getEndRes() + 1));\r
-        }\r
-        else\r
-        {\r
-          sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());\r
-        }\r
-\r
-        if (viewport.getConservationSelected())\r
-        {\r
-          Conservation c = new Conservation("Group",\r
-                  ResidueProperties.propHash, 3, sg.getSequences(viewport\r
-                          .getHiddenRepSequences()), sg.getStartRes(),\r
-                  sg.getEndRes() + 1);\r
-          c.calculate();\r
-          c.verdict(false, viewport.getConsPercGaps());\r
-          sg.cs.setConservation(c);\r
-        }\r
-        else\r
-        {\r
-          sg.cs.setConservation(null);\r
-        }\r
-      }\r
-    }\r
-\r
-    if (alignPanel.getOverviewPanel() != null)\r
-    {\r
-      alignPanel.getOverviewPanel().updateOverviewImage();\r
-    }\r
-\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void modifyPID_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.getAbovePIDThreshold()\r
-            && viewport.getGlobalColourScheme() != null)\r
-    {\r
-      SliderPanel.setPIDSliderSource(alignPanel,\r
-              viewport.getGlobalColourScheme(), "Background");\r
-      SliderPanel.showPIDSlider();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void modifyConservation_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.getConservationSelected()\r
-            && viewport.getGlobalColourScheme() != null)\r
-    {\r
-      SliderPanel.setConservationSlider(alignPanel,\r
-              viewport.getGlobalColourScheme(), "Background");\r
-      SliderPanel.showConservationSlider();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void conservationMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setConservationSelected(conservationMenuItem.isSelected());\r
-\r
-    viewport.setAbovePIDThreshold(false);\r
-    abovePIDThreshold.setSelected(false);\r
-\r
-    changeColour(viewport.getGlobalColourScheme());\r
-\r
-    modifyConservation_actionPerformed(null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void abovePIDThreshold_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());\r
-\r
-    conservationMenuItem.setSelected(false);\r
-    viewport.setConservationSelected(false);\r
-\r
-    changeColour(viewport.getGlobalColourScheme());\r
-\r
-    modifyPID_actionPerformed(null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void userDefinedColour_actionPerformed(ActionEvent e)\r
-  {\r
-    if (e.getActionCommand().equals(MessageManager.getString("action.user_defined")))\r
-    {\r
-      new UserDefinedColours(alignPanel, null);\r
-    }\r
-    else\r
-    {\r
-      UserColourScheme udc = (UserColourScheme) UserDefinedColours\r
-              .getUserColourSchemes().get(e.getActionCommand());\r
-\r
-      changeColour(udc);\r
-    }\r
-  }\r
-\r
-  public void updateUserColourMenu()\r
-  {\r
-\r
-    Component[] menuItems = colourMenu.getMenuComponents();\r
-    int i, iSize = menuItems.length;\r
-    for (i = 0; i < iSize; i++)\r
-    {\r
-      if (menuItems[i].getName() != null\r
-              && menuItems[i].getName().equals("USER_DEFINED"))\r
-      {\r
-        colourMenu.remove(menuItems[i]);\r
-        iSize--;\r
-      }\r
-    }\r
-    if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)\r
-    {\r
-      java.util.Enumeration userColours = jalview.gui.UserDefinedColours\r
-              .getUserColourSchemes().keys();\r
-\r
-      while (userColours.hasMoreElements())\r
-      {\r
-        final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(\r
-                userColours.nextElement().toString());\r
-        radioItem.setName("USER_DEFINED");\r
-        radioItem.addMouseListener(new MouseAdapter()\r
-        {\r
-          @Override\r
-          public void mousePressed(MouseEvent evt)\r
-          {\r
-            if (evt.isControlDown()\r
-                    || SwingUtilities.isRightMouseButton(evt))\r
-            {\r
-              radioItem.removeActionListener(radioItem.getActionListeners()[0]);\r
-\r
-              int option = JOptionPane.showInternalConfirmDialog(\r
-                      jalview.gui.Desktop.desktop,\r
-                      MessageManager.getString("label.remove_from_default_list"),\r
-                      MessageManager.getString("label.remove_user_defined_colour"),\r
-                      JOptionPane.YES_NO_OPTION);\r
-              if (option == JOptionPane.YES_OPTION)\r
-              {\r
-                jalview.gui.UserDefinedColours\r
-                        .removeColourFromDefaults(radioItem.getText());\r
-                colourMenu.remove(radioItem);\r
-              }\r
-              else\r
-              {\r
-                radioItem.addActionListener(new ActionListener()\r
-                {\r
-                  @Override\r
-                  public void actionPerformed(ActionEvent evt)\r
-                  {\r
-                    userDefinedColour_actionPerformed(evt);\r
-                  }\r
-                });\r
-              }\r
-            }\r
-          }\r
-        });\r
-        radioItem.addActionListener(new ActionListener()\r
-        {\r
-          @Override\r
-          public void actionPerformed(ActionEvent evt)\r
-          {\r
-            userDefinedColour_actionPerformed(evt);\r
-          }\r
-        });\r
-\r
-        colourMenu.insert(radioItem, 15);\r
-        colours.add(radioItem);\r
-      }\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void PIDColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new PIDColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void BLOSUM62Colour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new Blosum62ColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();\r
-    AlignmentSorter.sortByPID(viewport.getAlignment(), viewport\r
-            .getAlignment().getSequenceAt(0), null);\r
-    addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,\r
-            viewport.getAlignment()));\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void sortIDMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();\r
-    AlignmentSorter.sortByID(viewport.getAlignment());\r
-    addHistoryItem(new OrderCommand("ID Sort", oldOrder,\r
-            viewport.getAlignment()));\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void sortLengthMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();\r
-    AlignmentSorter.sortByLength(viewport.getAlignment());\r
-    addHistoryItem(new OrderCommand("Length Sort", oldOrder,\r
-            viewport.getAlignment()));\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void sortGroupMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();\r
-    AlignmentSorter.sortByGroup(viewport.getAlignment());\r
-    addHistoryItem(new OrderCommand("Group Sort", oldOrder,\r
-            viewport.getAlignment()));\r
-\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    new RedundancyPanel(alignPanel, this);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if ((viewport.getSelectionGroup() == null)\r
-            || (viewport.getSelectionGroup().getSize() < 2))\r
-    {\r
-      JOptionPane.showInternalMessageDialog(this,\r
-              MessageManager.getString("label.you_must_select_least_two_sequences"), MessageManager.getString("label.invalid_selection"),\r
-              JOptionPane.WARNING_MESSAGE);\r
-    }\r
-    else\r
-    {\r
-      JInternalFrame frame = new JInternalFrame();\r
-      frame.setContentPane(new PairwiseAlignPanel(viewport));\r
-      Desktop.addInternalFrame(frame, MessageManager.getString("action.pairwise_alignment"), 600, 500);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void PCAMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if (((viewport.getSelectionGroup() != null)\r
-            && (viewport.getSelectionGroup().getSize() < 4) && (viewport\r
-            .getSelectionGroup().getSize() > 0))\r
-            || (viewport.getAlignment().getHeight() < 4))\r
-    {\r
-      JOptionPane.showInternalMessageDialog(this,\r
-              MessageManager.getString("label.principal_component_analysis_must_take_least_four_input_sequences"),\r
-              MessageManager.getString("label.sequence_selection_insufficient"),\r
-              JOptionPane.WARNING_MESSAGE);\r
-\r
-      return;\r
-    }\r
-\r
-    new PCAPanel(alignPanel);\r
-  }\r
-\r
-  @Override\r
-  public void autoCalculate_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.autoCalculateConsensus = autoCalculate.isSelected();\r
-    if (viewport.autoCalculateConsensus)\r
-    {\r
-      viewport.firePropertyChange("alignment", null, viewport\r
-              .getAlignment().getSequences());\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public void sortByTreeOption_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.sortByTree = sortByTree.isSelected();\r
-  }\r
-\r
-  @Override\r
-  protected void listenToViewSelections_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.followSelection = listenToViewSelections.isSelected();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    NewTreePanel("AV", "PID", "Average distance tree using PID");\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param type\r
-   *          DOCUMENT ME!\r
-   * @param pwType\r
-   *          DOCUMENT ME!\r
-   * @param title\r
-   *          DOCUMENT ME!\r
-   */\r
-  void NewTreePanel(String type, String pwType, String title)\r
-  {\r
-    TreePanel tp;\r
-\r
-    if (viewport.getSelectionGroup() != null\r
-            && viewport.getSelectionGroup().getSize() > 0)\r
-    {\r
-      if (viewport.getSelectionGroup().getSize() < 3)\r
-      {\r
-        JOptionPane\r
-                .showMessageDialog(\r
-                        Desktop.desktop,\r
-                        MessageManager.getString("label.you_need_more_two_sequences_selected_build_tree"),\r
-                        MessageManager.getString("label.not_enough_sequences"), JOptionPane.WARNING_MESSAGE);\r
-        return;\r
-      }\r
-\r
-      SequenceGroup sg = viewport.getSelectionGroup();\r
-\r
-      /* Decide if the selection is a column region */\r
-      for (SequenceI _s : sg.getSequences())\r
-      {\r
-        if (_s.getLength() < sg.getEndRes())\r
-        {\r
-          JOptionPane\r
-                  .showMessageDialog(\r
-                          Desktop.desktop,\r
-                          MessageManager.getString("label.selected_region_to_tree_may_only_contain_residues_or_gaps"),\r
-                          MessageManager.getString("label.sequences_selection_not_aligned"),\r
-                          JOptionPane.WARNING_MESSAGE);\r
-\r
-          return;\r
-        }\r
-      }\r
-\r
-      title = title + " on region";\r
-      tp = new TreePanel(alignPanel, type, pwType);\r
-    }\r
-    else\r
-    {\r
-      // are the visible sequences aligned?\r
-      if (!viewport.getAlignment().isAligned(false))\r
-      {\r
-        JOptionPane\r
-                .showMessageDialog(\r
-                        Desktop.desktop,\r
-                        MessageManager.getString("label.sequences_must_be_aligned_before_creating_tree"),\r
-                        MessageManager.getString("label.sequences_not_aligned"),\r
-                        JOptionPane.WARNING_MESSAGE);\r
-\r
-        return;\r
-      }\r
-\r
-      if (viewport.getAlignment().getHeight() < 2)\r
-      {\r
-        return;\r
-      }\r
-\r
-      tp = new TreePanel(alignPanel, type, pwType);\r
-    }\r
-\r
-    title += " from ";\r
-\r
-    if (viewport.viewName != null)\r
-    {\r
-      title += viewport.viewName + " of ";\r
-    }\r
-\r
-    title += this.title;\r
-\r
-    Desktop.addInternalFrame(tp, title, 600, 500);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param title\r
-   *          DOCUMENT ME!\r
-   * @param order\r
-   *          DOCUMENT ME!\r
-   */\r
-  public void addSortByOrderMenuItem(String title,\r
-          final AlignmentOrder order)\r
-  {\r
-    final JMenuItem item = new JMenuItem("by " + title);\r
-    sort.add(item);\r
-    item.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      @Override\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();\r
-\r
-        // TODO: JBPNote - have to map order entries to curent SequenceI\r
-        // pointers\r
-        AlignmentSorter.sortBy(viewport.getAlignment(), order);\r
-\r
-        addHistoryItem(new OrderCommand(order.getName(), oldOrder, viewport\r
-                .getAlignment()));\r
-\r
-        alignPanel.paintAlignment(true);\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * Add a new sort by annotation score menu item\r
-   * \r
-   * @param sort\r
-   *          the menu to add the option to\r
-   * @param scoreLabel\r
-   *          the label used to retrieve scores for each sequence on the\r
-   *          alignment\r
-   */\r
-  public void addSortByAnnotScoreMenuItem(JMenu sort,\r
-          final String scoreLabel)\r
-  {\r
-    final JMenuItem item = new JMenuItem(scoreLabel);\r
-    sort.add(item);\r
-    item.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      @Override\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();\r
-        AlignmentSorter.sortByAnnotationScore(scoreLabel,\r
-                viewport.getAlignment());// ,viewport.getSelectionGroup());\r
-        addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,\r
-                viewport.getAlignment()));\r
-        alignPanel.paintAlignment(true);\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * last hash for alignment's annotation array - used to minimise cost of\r
-   * rebuild.\r
-   */\r
-  protected int _annotationScoreVectorHash;\r
-\r
-  /**\r
-   * search the alignment and rebuild the sort by annotation score submenu the\r
-   * last alignment annotation vector hash is stored to minimize cost of\r
-   * rebuilding in subsequence calls.\r
-   * \r
-   */\r
-  @Override\r
-  public void buildSortByAnnotationScoresMenu()\r
-  {\r
-    if (viewport.getAlignment().getAlignmentAnnotation() == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    if (viewport.getAlignment().getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)\r
-    {\r
-      sortByAnnotScore.removeAll();\r
-      // almost certainly a quicker way to do this - but we keep it simple\r
-      Hashtable scoreSorts = new Hashtable();\r
-      AlignmentAnnotation aann[];\r
-      for (SequenceI sqa : viewport.getAlignment().getSequences())\r
-      {\r
-        aann = sqa.getAnnotation();\r
-        for (int i = 0; aann != null && i < aann.length; i++)\r
-        {\r
-          if (aann[i].hasScore() && aann[i].sequenceRef != null)\r
-          {\r
-            scoreSorts.put(aann[i].label, aann[i].label);\r
-          }\r
-        }\r
-      }\r
-      Enumeration labels = scoreSorts.keys();\r
-      while (labels.hasMoreElements())\r
-      {\r
-        addSortByAnnotScoreMenuItem(sortByAnnotScore,\r
-                (String) labels.nextElement());\r
-      }\r
-      sortByAnnotScore.setVisible(scoreSorts.size() > 0);\r
-      scoreSorts.clear();\r
-\r
-      _annotationScoreVectorHash = viewport.getAlignment()\r
-              .getAlignmentAnnotation().hashCode();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a\r
-   * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>\r
-   * call. Listeners are added to remove the menu item when the treePanel is\r
-   * closed, and adjust the tree leaf to sequence mapping when the alignment is\r
-   * modified.\r
-   * \r
-   * @param treePanel\r
-   *          Displayed tree window.\r
-   * @param title\r
-   *          SortBy menu item title.\r
-   */\r
-  @Override\r
-  public void buildTreeMenu()\r
-  {\r
-    sortByTreeMenu.removeAll();\r
-\r
-    Vector comps = (Vector) PaintRefresher.components.get(viewport\r
-            .getSequenceSetId());\r
-    Vector treePanels = new Vector();\r
-    int i, iSize = comps.size();\r
-    for (i = 0; i < iSize; i++)\r
-    {\r
-      if (comps.elementAt(i) instanceof TreePanel)\r
-      {\r
-        treePanels.add(comps.elementAt(i));\r
-      }\r
-    }\r
-\r
-    iSize = treePanels.size();\r
-\r
-    if (iSize < 1)\r
-    {\r
-      sortByTreeMenu.setVisible(false);\r
-      return;\r
-    }\r
-\r
-    sortByTreeMenu.setVisible(true);\r
-\r
-    for (i = 0; i < treePanels.size(); i++)\r
-    {\r
-      final TreePanel tp = (TreePanel) treePanels.elementAt(i);\r
-      final JMenuItem item = new JMenuItem(tp.getTitle());\r
-      final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();\r
-      item.addActionListener(new java.awt.event.ActionListener()\r
-      {\r
-        @Override\r
-        public void actionPerformed(ActionEvent e)\r
-        {\r
-          tp.sortByTree_actionPerformed(null);\r
-          addHistoryItem(tp.sortAlignmentIn(alignPanel));\r
-\r
-        }\r
-      });\r
-\r
-      sortByTreeMenu.add(item);\r
-    }\r
-  }\r
-\r
-  public boolean sortBy(AlignmentOrder alorder, String undoname)\r
-  {\r
-    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();\r
-    AlignmentSorter.sortBy(viewport.getAlignment(), alorder);\r
-    if (undoname != null)\r
-    {\r
-      addHistoryItem(new OrderCommand(undoname, oldOrder,\r
-              viewport.getAlignment()));\r
-    }\r
-    alignPanel.paintAlignment(true);\r
-    return true;\r
-  }\r
-\r
-  /**\r
-   * Work out whether the whole set of sequences or just the selected set will\r
-   * be submitted for multiple alignment.\r
-   * \r
-   */\r
-  public jalview.datamodel.AlignmentView gatherSequencesForAlignment()\r
-  {\r
-    // Now, check we have enough sequences\r
-    AlignmentView msa = null;\r
-\r
-    if ((viewport.getSelectionGroup() != null)\r
-            && (viewport.getSelectionGroup().getSize() > 1))\r
-    {\r
-      // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to\r
-      // some common interface!\r
-      /*\r
-       * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new\r
-       * SequenceI[sz = seqs.getSize(false)];\r
-       * \r
-       * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)\r
-       * seqs.getSequenceAt(i); }\r
-       */\r
-      msa = viewport.getAlignmentView(true);\r
-    }\r
-    else\r
-    {\r
-      /*\r
-       * Vector seqs = viewport.getAlignment().getSequences();\r
-       * \r
-       * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];\r
-       * \r
-       * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)\r
-       * seqs.elementAt(i); } }\r
-       */\r
-      msa = viewport.getAlignmentView(false);\r
-    }\r
-    return msa;\r
-  }\r
-\r
-  /**\r
-   * Decides what is submitted to a secondary structure prediction service: the\r
-   * first sequence in the alignment, or in the current selection, or, if the\r
-   * alignment is 'aligned' (ie padded with gaps), then the currently selected\r
-   * region or the whole alignment. (where the first sequence in the set is the\r
-   * one that the prediction will be for).\r
-   */\r
-  public AlignmentView gatherSeqOrMsaForSecStrPrediction()\r
-  {\r
-    AlignmentView seqs = null;\r
-\r
-    if ((viewport.getSelectionGroup() != null)\r
-            && (viewport.getSelectionGroup().getSize() > 0))\r
-    {\r
-      seqs = viewport.getAlignmentView(true);\r
-    }\r
-    else\r
-    {\r
-      seqs = viewport.getAlignmentView(false);\r
-    }\r
-    // limit sequences - JBPNote in future - could spawn multiple prediction\r
-    // jobs\r
-    // TODO: viewport.getAlignment().isAligned is a global state - the local\r
-    // selection may well be aligned - we preserve 2.0.8 behaviour for moment.\r
-    if (!viewport.getAlignment().isAligned(false))\r
-    {\r
-      seqs.setSequences(new SeqCigar[]\r
-      { seqs.getSequences()[0] });\r
-      // TODO: if seqs.getSequences().length>1 then should really have warned\r
-      // user!\r
-\r
-    }\r
-    return seqs;\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   * \r
-   * @param e\r
-   *          DOCUMENT ME!\r
-   */\r
-  @Override\r
-  protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    // Pick the tree file\r
-    JalviewFileChooser chooser = new JalviewFileChooser(\r
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));\r
-    chooser.setFileView(new JalviewFileView());\r
-    chooser.setDialogTitle(MessageManager.getString("label.select_newick_like_tree_file"));\r
-    chooser.setToolTipText(MessageManager.getString("label.load_tree_file"));\r
-\r
-    int value = chooser.showOpenDialog(null);\r
-\r
-    if (value == JalviewFileChooser.APPROVE_OPTION)\r
-    {\r
-      String choice = chooser.getSelectedFile().getPath();\r
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);\r
-      jalview.io.NewickFile fin = null;\r
-      try\r
-      {\r
-        fin = new jalview.io.NewickFile(choice, "File");\r
-        viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());\r
-      } catch (Exception ex)\r
-      {\r
-        JOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),\r
-                MessageManager.getString("label.problem_reading_tree_file"), JOptionPane.WARNING_MESSAGE);\r
-        ex.printStackTrace();\r
-      }\r
-      if (fin != null && fin.hasWarningMessage())\r
-      {\r
-        JOptionPane.showMessageDialog(Desktop.desktop,\r
-                fin.getWarningMessage(), MessageManager.getString("label.possible_problem_with_tree_file"),\r
-                JOptionPane.WARNING_MESSAGE);\r
-      }\r
-    }\r
-  }\r
-\r
-  @Override\r
-  protected void tcoffeeColorScheme_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));\r
-  }\r
-\r
-  public TreePanel ShowNewickTree(NewickFile nf, String title)\r
-  {\r
-    return ShowNewickTree(nf, title, 600, 500, 4, 5);\r
-  }\r
-\r
-  public TreePanel ShowNewickTree(NewickFile nf, String title,\r
-          AlignmentView input)\r
-  {\r
-    return ShowNewickTree(nf, title, input, 600, 500, 4, 5);\r
-  }\r
-\r
-  public TreePanel ShowNewickTree(NewickFile nf, String title, int w,\r
-          int h, int x, int y)\r
-  {\r
-    return ShowNewickTree(nf, title, null, w, h, x, y);\r
-  }\r
-\r
-  /**\r
-   * Add a treeviewer for the tree extracted from a newick file object to the\r
-   * current alignment view\r
-   * \r
-   * @param nf\r
-   *          the tree\r
-   * @param title\r
-   *          tree viewer title\r
-   * @param input\r
-   *          Associated alignment input data (or null)\r
-   * @param w\r
-   *          width\r
-   * @param h\r
-   *          height\r
-   * @param x\r
-   *          position\r
-   * @param y\r
-   *          position\r
-   * @return TreePanel handle\r
-   */\r
-  public TreePanel ShowNewickTree(NewickFile nf, String title,\r
-          AlignmentView input, int w, int h, int x, int y)\r
-  {\r
-    TreePanel tp = null;\r
-\r
-    try\r
-    {\r
-      nf.parse();\r
-\r
-      if (nf.getTree() != null)\r
-      {\r
-        tp = new TreePanel(alignPanel, "FromFile", title, nf, input);\r
-\r
-        tp.setSize(w, h);\r
-\r
-        if (x > 0 && y > 0)\r
-        {\r
-          tp.setLocation(x, y);\r
-        }\r
-\r
-        Desktop.addInternalFrame(tp, title, w, h);\r
-      }\r
-    } catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    }\r
-\r
-    return tp;\r
-  }\r
-\r
-  private boolean buildingMenu = false;\r
-\r
-  /**\r
-   * Generates menu items and listener event actions for web service clients\r
-   * \r
-   */\r
-  public void BuildWebServiceMenu()\r
-  {\r
-    while (buildingMenu)\r
-    {\r
-      try\r
-      {\r
-        System.err.println("Waiting for building menu to finish.");\r
-        Thread.sleep(10);\r
-      } catch (Exception e)\r
-      {\r
-      }\r
-      ;\r
-    }\r
-    final AlignFrame me = this;\r
-    buildingMenu = true;\r
-    new Thread(new Runnable()\r
-    {\r
-      @Override\r
-      public void run()\r
-      {\r
-        final List<JMenuItem> legacyItems=new ArrayList<JMenuItem>();\r
-        try\r
-        {\r
-          System.err.println("Building ws menu again "\r
-                  + Thread.currentThread());\r
-          // TODO: add support for context dependent disabling of services based\r
-          // on\r
-          // alignment and current selection\r
-          // TODO: add additional serviceHandle parameter to specify abstract\r
-          // handler\r
-          // class independently of AbstractName\r
-          // TODO: add in rediscovery GUI function to restart discoverer\r
-          // TODO: group services by location as well as function and/or\r
-          // introduce\r
-          // object broker mechanism.\r
-          final Vector<JMenu> wsmenu = new Vector<JMenu>();\r
-          final IProgressIndicator af = me;\r
-          final JMenu msawsmenu = new JMenu("Alignment");\r
-          final JMenu secstrmenu = new JMenu(\r
-                  "Secondary Structure Prediction");\r
-          final JMenu seqsrchmenu = new JMenu("Sequence Database Search");\r
-          final JMenu analymenu = new JMenu("Analysis");\r
-          final JMenu dismenu = new JMenu("Protein Disorder");\r
-          // JAL-940 - only show secondary structure prediction services from\r
-          // the legacy server\r
-          if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)\r
-              // &&\r
-          Discoverer.services != null && (Discoverer.services.size() > 0))\r
-          {\r
-            // TODO: refactor to allow list of AbstractName/Handler bindings to\r
-            // be\r
-            // stored or retrieved from elsewhere\r
-            // No MSAWS used any more:\r
-            // Vector msaws = null; // (Vector) Discoverer.services.get("MsaWS");\r
-            Vector secstrpr = (Vector) Discoverer.services\r
-                    .get("SecStrPred");\r
-            if (secstrpr != null)\r
-            {\r
-              // Add any secondary structure prediction services\r
-              for (int i = 0, j = secstrpr.size(); i < j; i++)\r
-              {\r
-                final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr\r
-                        .get(i);\r
-                jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer\r
-                        .getServiceClient(sh);\r
-                int p=secstrmenu.getItemCount();\r
-                impl.attachWSMenuEntry(secstrmenu, me);\r
-                int q=secstrmenu.getItemCount();\r
-                for (int litm=p;litm<q; litm++)\r
-                {\r
-                  legacyItems.add(secstrmenu.getItem(litm));\r
-                }\r
-              }\r
-            }\r
-          }\r
-          \r
-          // Add all submenus in the order they should appear on the web\r
-          // services menu\r
-          wsmenu.add(msawsmenu);\r
-          wsmenu.add(secstrmenu);\r
-          wsmenu.add(dismenu);\r
-          wsmenu.add(analymenu);\r
-          // No search services yet\r
-          // wsmenu.add(seqsrchmenu);\r
-\r
-          javax.swing.SwingUtilities.invokeLater(new Runnable()\r
-          {\r
-            @Override\r
-            public void run()\r
-            {\r
-              try\r
-              {\r
-                webService.removeAll();\r
-                // first, add discovered services onto the webservices menu\r
-                if (wsmenu.size() > 0)\r
-                {\r
-                  for (int i = 0, j = wsmenu.size(); i < j; i++)\r
-                  {\r
-                    webService.add(wsmenu.get(i));\r
-                  }\r
-                }\r
-                else\r
-                {\r
-                  webService.add(me.webServiceNoServices);\r
-                }\r
-                // TODO: move into separate menu builder class.\r
-                boolean new_sspred=false;\r
-                if (Cache.getDefault("SHOW_JWS2_SERVICES", true))\r
-                {\r
-                  Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();\r
-                  if (jws2servs != null)\r
-                  {\r
-                    if (jws2servs.hasServices())\r
-                    {\r
-                      jws2servs.attachWSMenuEntry(webService, me);\r
-                      for (Jws2Instance sv:jws2servs.getServices()) {\r
-                        if (sv.description.toLowerCase().contains("jpred"))\r
-                        {\r
-                          for (JMenuItem jmi:legacyItems)\r
-                          {\r
-                            jmi.setVisible(false);\r
-                          }\r
-                        }\r
-                      }\r
-                      \r
-                    }\r
-                    if (jws2servs.isRunning())\r
-                    {\r
-                      JMenuItem tm = new JMenuItem(\r
-                              "Still discovering JABA Services");\r
-                      tm.setEnabled(false);\r
-                      webService.add(tm);\r
-                    }\r
-                  }\r
-                }\r
-                build_urlServiceMenu(me.webService);\r
-                build_fetchdbmenu(webService);\r
-                for (JMenu item : wsmenu)\r
-                {\r
-                  if (item.getItemCount() == 0)\r
-                  {\r
-                    item.setEnabled(false);\r
-                  }\r
-                  else\r
-                  {\r
-                    item.setEnabled(true);\r
-                  }\r
-                }\r
-              } catch (Exception e)\r
-              {\r
-                Cache.log\r
-                        .debug("Exception during web service menu building process.",\r
-                                e);\r
-              }\r
-              ;\r
-            }\r
-          });\r
-        } catch (Exception e)\r
-        {\r
-        }\r
-        ;\r
-\r
-        buildingMenu = false;\r
-      }\r
-    }).start();\r
-\r
-  }\r
-\r
-  /**\r
-   * construct any groupURL type service menu entries.\r
-   * \r
-   * @param webService\r
-   */\r
-  private void build_urlServiceMenu(JMenu webService)\r
-  {\r
-    // TODO: remove this code when 2.7 is released\r
-    // DEBUG - alignmentView\r
-    /*\r
-     * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final\r
-     * AlignFrame af = this; testAlView.addActionListener(new ActionListener() {\r
-     * \r
-     * @Override public void actionPerformed(ActionEvent e) {\r
-     * jalview.datamodel.AlignmentView\r
-     * .testSelectionViews(af.viewport.getAlignment(),\r
-     * af.viewport.getColumnSelection(), af.viewport.selectionGroup); }\r
-     * \r
-     * }); webService.add(testAlView);\r
-     */\r
-    // TODO: refactor to RestClient discoverer and merge menu entries for\r
-    // rest-style services with other types of analysis/calculation service\r
-    // SHmmr test client - still being implemented.\r
-    // DEBUG - alignmentView\r
-\r
-    for (jalview.ws.rest.RestClient client : jalview.ws.rest.RestClient\r
-            .getRestClients())\r
-    {\r
-      client.attachWSMenuEntry(\r
-              JvSwingUtils.findOrCreateMenu(webService, client.getAction()),\r
-              this);\r
-    }\r
-\r
-    if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))\r
-    {\r
-      jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(\r
-              webService, this);\r
-    }\r
-  }\r
-\r
-  /*\r
-   * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser\r
-   * chooser = new JalviewFileChooser(jalview.bin.Cache.\r
-   * getProperty("LAST_DIRECTORY"));\r
-   * \r
-   * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export\r
-   * to Vamsas file"); chooser.setToolTipText("Export");\r
-   * \r
-   * int value = chooser.showSaveDialog(this);\r
-   * \r
-   * if (value == JalviewFileChooser.APPROVE_OPTION) {\r
-   * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);\r
-   * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(\r
-   * chooser.getSelectedFile().getAbsolutePath(), this); } }\r
-   */\r
-  /**\r
-   * prototype of an automatically enabled/disabled analysis function\r
-   * \r
-   */\r
-  protected void setShowProductsEnabled()\r
-  {\r
-    SequenceI[] selection = viewport.getSequenceSelection();\r
-    if (canShowProducts(selection, viewport.getSelectionGroup() != null,\r
-            viewport.getAlignment().getDataset()))\r
-    {\r
-      showProducts.setEnabled(true);\r
-\r
-    }\r
-    else\r
-    {\r
-      showProducts.setEnabled(false);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * search selection for sequence xRef products and build the show products\r
-   * menu.\r
-   * \r
-   * @param selection\r
-   * @param dataset\r
-   * @return true if showProducts menu should be enabled.\r
-   */\r
-  public boolean canShowProducts(SequenceI[] selection,\r
-          boolean isRegionSelection, Alignment dataset)\r
-  {\r
-    boolean showp = false;\r
-    try\r
-    {\r
-      showProducts.removeAll();\r
-      final boolean dna = viewport.getAlignment().isNucleotide();\r
-      final Alignment ds = dataset;\r
-      String[] ptypes = (selection == null || selection.length == 0) ? null\r
-              : CrossRef.findSequenceXrefTypes(dna, selection, dataset);\r
-      // Object[] prods =\r
-      // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),\r
-      // selection, dataset, true);\r
-      final SequenceI[] sel = selection;\r
-      for (int t = 0; ptypes != null && t < ptypes.length; t++)\r
-      {\r
-        showp = true;\r
-        final boolean isRegSel = isRegionSelection;\r
-        final AlignFrame af = this;\r
-        final String source = ptypes[t];\r
-        JMenuItem xtype = new JMenuItem(ptypes[t]);\r
-        xtype.addActionListener(new ActionListener()\r
-        {\r
-\r
-          @Override\r
-          public void actionPerformed(ActionEvent e)\r
-          {\r
-            // TODO: new thread for this call with vis-delay\r
-            af.showProductsFor(af.viewport.getSequenceSelection(), ds,\r
-                    isRegSel, dna, source);\r
-          }\r
-\r
-        });\r
-        showProducts.add(xtype);\r
-      }\r
-      showProducts.setVisible(showp);\r
-      showProducts.setEnabled(showp);\r
-    } catch (Exception e)\r
-    {\r
-      jalview.bin.Cache.log\r
-              .warn("canTranslate threw an exception - please report to help@jalview.org",\r
-                      e);\r
-      return false;\r
-    }\r
-    return showp;\r
-  }\r
-\r
-  protected void showProductsFor(SequenceI[] sel, Alignment ds,\r
-          boolean isRegSel, boolean dna, String source)\r
-  {\r
-    final boolean fisRegSel = isRegSel;\r
-    final boolean fdna = dna;\r
-    final String fsrc = source;\r
-    final AlignFrame ths = this;\r
-    final SequenceI[] fsel = sel;\r
-    Runnable foo = new Runnable()\r
-    {\r
-\r
-      @Override\r
-      public void run()\r
-      {\r
-        final long sttime = System.currentTimeMillis();\r
-        ths.setProgressBar("Searching for sequences from " + fsrc, sttime);\r
-        try\r
-        {\r
-          Alignment ds = ths.getViewport().getAlignment().getDataset(); // update\r
-          // our local\r
-          // dataset\r
-          // reference\r
-          Alignment prods = CrossRef\r
-                  .findXrefSequences(fsel, fdna, fsrc, ds);\r
-          if (prods != null)\r
-          {\r
-            SequenceI[] sprods = new SequenceI[prods.getHeight()];\r
-            for (int s = 0; s < sprods.length; s++)\r
-            {\r
-              sprods[s] = (prods.getSequenceAt(s)).deriveSequence();\r
-              if (ds.getSequences() == null\r
-                      || !ds.getSequences().contains(\r
-                              sprods[s].getDatasetSequence()))\r
-                ds.addSequence(sprods[s].getDatasetSequence());\r
-              sprods[s].updatePDBIds();\r
-            }\r
-            Alignment al = new Alignment(sprods);\r
-            AlignedCodonFrame[] cf = prods.getCodonFrames();\r
-            al.setDataset(ds);\r
-            for (int s = 0; cf != null && s < cf.length; s++)\r
-            {\r
-              al.addCodonFrame(cf[s]);\r
-              cf[s] = null;\r
-            }\r
-            AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,\r
-                    DEFAULT_HEIGHT);\r
-            String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")\r
-                    + " for " + ((fisRegSel) ? "selected region of " : "")\r
-                    + getTitle();\r
-            Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,\r
-                    DEFAULT_HEIGHT);\r
-          }\r
-          else\r
-          {\r
-            System.err.println("No Sequences generated for xRef type "\r
-                    + fsrc);\r
-          }\r
-        } catch (Exception e)\r
-        {\r
-          jalview.bin.Cache.log.error(\r
-                  "Exception when finding crossreferences", e);\r
-        } catch (OutOfMemoryError e)\r
-        {\r
-          new OOMWarning("whilst fetching crossreferences", e);\r
-        } catch (Error e)\r
-        {\r
-          jalview.bin.Cache.log.error("Error when finding crossreferences",\r
-                  e);\r
-        }\r
-        ths.setProgressBar("Finished searching for sequences from " + fsrc,\r
-                sttime);\r
-      }\r
-\r
-    };\r
-    Thread frunner = new Thread(foo);\r
-    frunner.start();\r
-  }\r
-\r
-  public boolean canShowTranslationProducts(SequenceI[] selection,\r
-          AlignmentI alignment)\r
-  {\r
-    // old way\r
-    try\r
-    {\r
-      return (jalview.analysis.Dna.canTranslate(selection,\r
-              viewport.getViewAsVisibleContigs(true)));\r
-    } catch (Exception e)\r
-    {\r
-      jalview.bin.Cache.log\r
-              .warn("canTranslate threw an exception - please report to help@jalview.org",\r
-                      e);\r
-      return false;\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public void showProducts_actionPerformed(ActionEvent e)\r
-  {\r
-    // /////////////////////////////\r
-    // Collect Data to be translated/transferred\r
-\r
-    SequenceI[] selection = viewport.getSequenceSelection();\r
-    AlignmentI al = null;\r
-    try\r
-    {\r
-      al = jalview.analysis.Dna.CdnaTranslate(selection, viewport\r
-              .getViewAsVisibleContigs(true), viewport.getGapCharacter(),\r
-              viewport.getAlignment().getDataset());\r
-    } catch (Exception ex)\r
-    {\r
-      al = null;\r
-      jalview.bin.Cache.log.debug("Exception during translation.", ex);\r
-    }\r
-    if (al == null)\r
-    {\r
-      JOptionPane\r
-              .showMessageDialog(\r
-                      Desktop.desktop,\r
-                      MessageManager.getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"),\r
-                      MessageManager.getString("label.translation_failed"), JOptionPane.WARNING_MESSAGE);\r
-    }\r
-    else\r
-    {\r
-      AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);\r
-      Desktop.addInternalFrame(af, MessageManager.formatMessage("label.translation_of_params", new String[]{this.getTitle()}),\r
-              DEFAULT_WIDTH, DEFAULT_HEIGHT);\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public void showTranslation_actionPerformed(ActionEvent e)\r
-  {\r
-    // /////////////////////////////\r
-    // Collect Data to be translated/transferred\r
-\r
-    SequenceI[] selection = viewport.getSequenceSelection();\r
-    String[] seqstring = viewport.getViewAsString(true);\r
-    AlignmentI al = null;\r
-    try\r
-    {\r
-      al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,\r
-              viewport.getViewAsVisibleContigs(true), viewport\r
-                      .getGapCharacter(), viewport.getAlignment()\r
-                      .getAlignmentAnnotation(), viewport.getAlignment()\r
-                      .getWidth(), viewport.getAlignment().getDataset());\r
-    } catch (Exception ex)\r
-    {\r
-      al = null;\r
-      jalview.bin.Cache.log.error("Exception during translation. Please report this !", ex);\r
-      JOptionPane\r
-      .showMessageDialog(\r
-              Desktop.desktop,\r
-              MessageManager.getString("label.error_when_translating_sequences_submit_bug_report"),\r
-              MessageManager.getString("label.implementation_error") + MessageManager.getString("translation_failed"), JOptionPane.ERROR_MESSAGE);\r
-      return;\r
-    }\r
-    if (al == null)\r
-    {\r
-      JOptionPane\r
-              .showMessageDialog(\r
-                      Desktop.desktop,\r
-                      MessageManager.getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"),\r
-                      MessageManager.getString("label.translation_failed"), JOptionPane.WARNING_MESSAGE);\r
-    }\r
-    else\r
-    {\r
-      AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);\r
-      Desktop.addInternalFrame(af, MessageManager.formatMessage("label.translation_of_params", new String[]{this.getTitle()}),\r
-              DEFAULT_WIDTH, DEFAULT_HEIGHT);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Try to load a features file onto the alignment.\r
-   * \r
-   * @param file\r
-   *          contents or path to retrieve file\r
-   * @param type\r
-   *          access mode of file (see jalview.io.AlignFile)\r
-   * @return true if features file was parsed corectly.\r
-   */\r
-  public boolean parseFeaturesFile(String file, String type)\r
-  {\r
-    boolean featuresFile = false;\r
-    try\r
-    {\r
-      featuresFile = new FeaturesFile(file, type).parse(viewport\r
-              .getAlignment().getDataset(), alignPanel.seqPanel.seqCanvas\r
-              .getFeatureRenderer().featureColours, false,\r
-              jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));\r
-    } catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    }\r
-\r
-    if (featuresFile)\r
-    {\r
-      viewport.showSequenceFeatures = true;\r
-      showSeqFeatures.setSelected(true);\r
-      if (alignPanel.seqPanel.seqCanvas.fr != null)\r
-      {\r
-        // update the min/max ranges where necessary\r
-        alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);\r
-      }\r
-      if (featureSettings != null)\r
-      {\r
-        featureSettings.setTableData();\r
-      }\r
-      alignPanel.paintAlignment(true);\r
-    }\r
-\r
-    return featuresFile;\r
-  }\r
-\r
-  @Override\r
-  public void dragEnter(DropTargetDragEvent evt)\r
-  {\r
-  }\r
-\r
-  @Override\r
-  public void dragExit(DropTargetEvent evt)\r
-  {\r
-  }\r
-\r
-  @Override\r
-  public void dragOver(DropTargetDragEvent evt)\r
-  {\r
-  }\r
-\r
-  @Override\r
-  public void dropActionChanged(DropTargetDragEvent evt)\r
-  {\r
-  }\r
-\r
-  @Override\r
-  public void drop(DropTargetDropEvent evt)\r
-  {\r
-    Transferable t = evt.getTransferable();\r
-    java.util.List files = null;\r
-\r
-    try\r
-    {\r
-      DataFlavor uriListFlavor = new DataFlavor(\r
-              "text/uri-list;class=java.lang.String");\r
-      if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))\r
-      {\r
-        // Works on Windows and MacOSX\r
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);\r
-        files = (java.util.List) t\r
-                .getTransferData(DataFlavor.javaFileListFlavor);\r
-      }\r
-      else if (t.isDataFlavorSupported(uriListFlavor))\r
-      {\r
-        // This is used by Unix drag system\r
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);\r
-        String data = (String) t.getTransferData(uriListFlavor);\r
-        files = new java.util.ArrayList(1);\r
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(\r
-                data, "\r\n"); st.hasMoreTokens();)\r
-        {\r
-          String s = st.nextToken();\r
-          if (s.startsWith("#"))\r
-          {\r
-            // the line is a comment (as per the RFC 2483)\r
-            continue;\r
-          }\r
-\r
-          java.net.URI uri = new java.net.URI(s);\r
-          // check to see if we can handle this kind of URI\r
-          if (uri.getScheme().toLowerCase().startsWith("http"))\r
-          {\r
-            files.add(uri.toString());\r
-          }\r
-          else\r
-          {\r
-            // otherwise preserve old behaviour: catch all for file objects\r
-            java.io.File file = new java.io.File(uri);\r
-            files.add(file.toString());\r
-          }\r
-        }\r
-      }\r
-    } catch (Exception e)\r
-    {\r
-      e.printStackTrace();\r
-    }\r
-    if (files != null)\r
-    {\r
-      try\r
-      {\r
-        // check to see if any of these files have names matching sequences in\r
-        // the alignment\r
-        SequenceIdMatcher idm = new SequenceIdMatcher(viewport\r
-                .getAlignment().getSequencesArray());\r
-        /**\r
-         * Object[] { String,SequenceI}\r
-         */\r
-        ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();\r
-        ArrayList<String> filesnotmatched = new ArrayList<String>();\r
-        for (int i = 0; i < files.size(); i++)\r
-        {\r
-          String file = files.get(i).toString();\r
-          String pdbfn = "";\r
-          String protocol = FormatAdapter.checkProtocol(file);\r
-          if (protocol == jalview.io.FormatAdapter.FILE)\r
-          {\r
-            File fl = new File(file);\r
-            pdbfn = fl.getName();\r
-          }\r
-          else if (protocol == jalview.io.FormatAdapter.URL)\r
-          {\r
-            URL url = new URL(file);\r
-            pdbfn = url.getFile();\r
-          }\r
-          if (pdbfn.length() > 0)\r
-          {\r
-            // attempt to find a match in the alignment\r
-            SequenceI[] mtch = idm.findAllIdMatches(pdbfn);\r
-            int l = 0, c = pdbfn.indexOf(".");\r
-            while (mtch == null && c != -1)\r
-            {\r
-              do\r
-              {\r
-                l = c;\r
-              } while ((c = pdbfn.indexOf(".", l)) > l);\r
-              if (l > -1)\r
-              {\r
-                pdbfn = pdbfn.substring(0, l);\r
-              }\r
-              mtch = idm.findAllIdMatches(pdbfn);\r
-            }\r
-            if (mtch != null)\r
-            {\r
-              String type = null;\r
-              try\r
-              {\r
-                type = new IdentifyFile().Identify(file, protocol);\r
-              } catch (Exception ex)\r
-              {\r
-                type = null;\r
-              }\r
-              if (type != null)\r
-              {\r
-                if (type.equalsIgnoreCase("PDB"))\r
-                {\r
-                  filesmatched.add(new Object[]\r
-                  { file, protocol, mtch });\r
-                  continue;\r
-                }\r
-              }\r
-            }\r
-            // File wasn't named like one of the sequences or wasn't a PDB file.\r
-            filesnotmatched.add(file);\r
-          }\r
-        }\r
-        int assocfiles = 0;\r
-        if (filesmatched.size() > 0)\r
-        {\r
-          if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)\r
-                  || JOptionPane\r
-                          .showConfirmDialog(\r
-                                  this,\r
-                                  MessageManager.formatMessage("label.automatically_associate_pdb_files_with_sequences_same_name",\r
-                                                 new String[]{Integer.valueOf(filesmatched.size()).toString()}),\r
-                                  MessageManager.getString("label.automatically_associate_pdb_files_by_name"),\r
-                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)\r
-\r
-          {\r
-            for (Object[] fm : filesmatched)\r
-            {\r
-              // try and associate\r
-              // TODO: may want to set a standard ID naming formalism for\r
-              // associating PDB files which have no IDs.\r
-              for (SequenceI toassoc : (SequenceI[]) fm[2])\r
-              {\r
-                PDBEntry pe = new AssociatePdbFileWithSeq()\r
-                        .associatePdbWithSeq((String) fm[0],\r
-                                (String) fm[1], toassoc, false);\r
-                if (pe != null)\r
-                {\r
-                  System.err.println("Associated file : "\r
-                          + ((String) fm[0]) + " with "\r
-                          + toassoc.getDisplayId(true));\r
-                  assocfiles++;\r
-                }\r
-              }\r
-              alignPanel.paintAlignment(true);\r
-            }\r
-          }\r
-        }\r
-        if (filesnotmatched.size() > 0)\r
-        {\r
-          if (assocfiles > 0\r
-                  && (Cache.getDefault(\r
-                          "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane\r
-                          .showConfirmDialog(\r
-                                  this,\r
-                                  MessageManager.formatMessage("label.ignore_unmatched_dropped_files_info", new String[]{Integer.valueOf(filesnotmatched.size()).toString()}),\r
-                                  MessageManager.getString("label.ignore_unmatched_dropped_files"),\r
-                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))\r
-          {\r
-            return;\r
-          }\r
-          for (String fn : filesnotmatched)\r
-          {\r
-            loadJalviewDataFile(fn, null, null, null);\r
-          }\r
-\r
-        }\r
-      } catch (Exception ex)\r
-      {\r
-        ex.printStackTrace();\r
-      }\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Attempt to load a "dropped" file or URL string: First by testing whether\r
-   * it's and Annotation file, then a JNet file, and finally a features file. If\r
-   * all are false then the user may have dropped an alignment file onto this\r
-   * AlignFrame.\r
-   * \r
-   * @param file\r
-   *          either a filename or a URL string.\r
-   */\r
-  public void loadJalviewDataFile(String file, String protocol,\r
-          String format, SequenceI assocSeq)\r
-  {\r
-    try\r
-    {\r
-      if (protocol == null)\r
-      {\r
-        protocol = jalview.io.FormatAdapter.checkProtocol(file);\r
-      }\r
-      // if the file isn't identified, or not positively identified as some\r
-      // other filetype (PFAM is default unidentified alignment file type) then\r
-      // try to parse as annotation.\r
-      boolean isAnnotation = (format == null || format\r
-              .equalsIgnoreCase("PFAM")) ? new AnnotationFile()\r
-              .readAnnotationFile(viewport.getAlignment(), file, protocol)\r
-              : false;\r
-\r
-      if (!isAnnotation)\r
-      {\r
-        // first see if its a T-COFFEE score file\r
-        TCoffeeScoreFile tcf = null;\r
-        try\r
-        {\r
-          tcf = new TCoffeeScoreFile(file, protocol);\r
-          if (tcf.isValid())\r
-          {\r
-            if (tcf.annotateAlignment(viewport.getAlignment(), true))\r
-            {\r
-              tcoffeeColour.setEnabled(true);\r
-              tcoffeeColour.setSelected(true);\r
-              changeColour(new TCoffeeColourScheme(viewport.getAlignment()));\r
-              isAnnotation = true;\r
-              statusBar.setText(MessageManager.getString("label.successfully_pasted_tcoffee_scores_to_alignment"));\r
-            }\r
-            else\r
-            {\r
-              // some problem - if no warning its probable that the ID matching\r
-              // process didn't work\r
-              JOptionPane\r
-                      .showMessageDialog(\r
-                              Desktop.desktop,\r
-                              tcf.getWarningMessage() == null ? MessageManager.getString("label.check_file_matches_sequence_ids_alignment")\r
-                                      : tcf.getWarningMessage(),\r
-                              MessageManager.getString("label.problem_reading_tcoffee_score_file"),\r
-                              JOptionPane.WARNING_MESSAGE);\r
-            }\r
-          }\r
-          else\r
-          {\r
-            tcf = null;\r
-          }\r
-        } catch (Exception x)\r
-        {\r
-          Cache.log\r
-                  .debug("Exception when processing data source as T-COFFEE score file",\r
-                          x);\r
-          tcf = null;\r
-        }\r
-        if (tcf == null)\r
-        {\r
-          // try to see if its a JNet 'concise' style annotation file *before*\r
-          // we\r
-          // try to parse it as a features file\r
-          if (format == null)\r
-          {\r
-            format = new IdentifyFile().Identify(file, protocol);\r
-          }\r
-          if (format.equalsIgnoreCase("JnetFile"))\r
-          {\r
-            jalview.io.JPredFile predictions = new jalview.io.JPredFile(\r
-                    file, protocol);\r
-            new JnetAnnotationMaker().add_annotation(predictions,\r
-                    viewport.getAlignment(), 0, false);\r
-            isAnnotation = true;\r
-          }\r
-          else\r
-          {\r
-            /*\r
-             * if (format.equalsIgnoreCase("PDB")) {\r
-             * \r
-             * String pdbfn = ""; // try to match up filename with sequence id\r
-             * try { if (protocol == jalview.io.FormatAdapter.FILE) { File fl =\r
-             * new File(file); pdbfn = fl.getName(); } else if (protocol ==\r
-             * jalview.io.FormatAdapter.URL) { URL url = new URL(file); pdbfn =\r
-             * url.getFile(); } } catch (Exception e) { } ; if (assocSeq ==\r
-             * null) { SequenceIdMatcher idm = new SequenceIdMatcher(viewport\r
-             * .getAlignment().getSequencesArray()); if (pdbfn.length() > 0) {\r
-             * // attempt to find a match in the alignment SequenceI mtch =\r
-             * idm.findIdMatch(pdbfn); int l = 0, c = pdbfn.indexOf("."); while\r
-             * (mtch == null && c != -1) { while ((c = pdbfn.indexOf(".", l)) >\r
-             * l) { l = c; } if (l > -1) { pdbfn = pdbfn.substring(0, l); } mtch\r
-             * = idm.findIdMatch(pdbfn); } if (mtch != null) { // try and\r
-             * associate // prompt ? PDBEntry pe = new AssociatePdbFileWithSeq()\r
-             * .associatePdbWithSeq(file, protocol, mtch, true); if (pe != null)\r
-             * { System.err.println("Associated file : " + file + " with " +\r
-             * mtch.getDisplayId(true)); alignPanel.paintAlignment(true); } } //\r
-             * TODO: maybe need to load as normal otherwise return; } }\r
-             */\r
-            // try to parse it as a features file\r
-            boolean isGroupsFile = parseFeaturesFile(file, protocol);\r
-            // if it wasn't a features file then we just treat it as a general\r
-            // alignment file to load into the current view.\r
-            if (!isGroupsFile)\r
-            {\r
-              new FileLoader().LoadFile(viewport, file, protocol, format);\r
-            }\r
-            else\r
-            {\r
-              alignPanel.paintAlignment(true);\r
-            }\r
-          }\r
-        }\r
-      }\r
-      if (isAnnotation)\r
-      {\r
-\r
-        alignPanel.adjustAnnotationHeight();\r
-        viewport.updateSequenceIdColours();\r
-        buildSortByAnnotationScoresMenu();\r
-        alignPanel.paintAlignment(true);\r
-      }\r
-    } catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    } catch (OutOfMemoryError oom)\r
-    {\r
-      try\r
-      {\r
-        System.gc();\r
-      } catch (Exception x)\r
-      {\r
-      }\r
-      ;\r
-      new OOMWarning(\r
-              "loading data "\r
-                      + (protocol != null ? (protocol.equals(FormatAdapter.PASTE) ? "from clipboard."\r
-                              : "using " + protocol + " from " + file)\r
-                              : ".")\r
-                      + (format != null ? "(parsing as '" + format\r
-                              + "' file)" : ""), oom, Desktop.desktop);\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public void tabSelectionChanged(int index)\r
-  {\r
-    if (index > -1)\r
-    {\r
-      alignPanel = (AlignmentPanel) alignPanels.elementAt(index);\r
-      viewport = alignPanel.av;\r
-      avc.setViewportAndAlignmentPanel(viewport, alignPanel);\r
-      setMenusFromViewport(viewport);\r
-    }\r
-  }\r
-\r
-  @Override\r
-  public void tabbedPane_mousePressed(MouseEvent e)\r
-  {\r
-    if (SwingUtilities.isRightMouseButton(e))\r
-    {\r
-      String reply = JOptionPane.showInternalInputDialog(this,\r
-              MessageManager.getString("label.enter_view_name"), MessageManager.getString("label.enter_view_name"),\r
-              JOptionPane.QUESTION_MESSAGE);\r
-\r
-      if (reply != null)\r
-      {\r
-        viewport.viewName = reply;\r
-        tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);\r
-      }\r
-    }\r
-  }\r
-\r
-  public AlignViewport getCurrentView()\r
-  {\r
-    return viewport;\r
-  }\r
-\r
-  /**\r
-   * Open the dialog for regex description parsing.\r
-   */\r
-  @Override\r
-  protected void extractScores_actionPerformed(ActionEvent e)\r
-  {\r
-    ParseProperties pp = new jalview.analysis.ParseProperties(\r
-            viewport.getAlignment());\r
-    // TODO: verify regex and introduce GUI dialog for version 2.5\r
-    // if (pp.getScoresFromDescription("col", "score column ",\r
-    // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",\r
-    // true)>0)\r
-    if (pp.getScoresFromDescription("description column",\r
-            "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)\r
-    {\r
-      buildSortByAnnotationScoresMenu();\r
-    }\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent\r
-   * )\r
-   */\r
-  @Override\r
-  protected void showDbRefs_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.\r
-   * ActionEvent)\r
-   */\r
-  @Override\r
-  protected void showNpFeats_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());\r
-  }\r
-\r
-  /**\r
-   * find the viewport amongst the tabs in this alignment frame and close that\r
-   * tab\r
-   * \r
-   * @param av\r
-   */\r
-  public boolean closeView(AlignViewport av)\r
-  {\r
-    if (viewport == av)\r
-    {\r
-      this.closeMenuItem_actionPerformed(false);\r
-      return true;\r
-    }\r
-    Component[] comp = tabbedPane.getComponents();\r
-    for (int i = 0; comp != null && i < comp.length; i++)\r
-    {\r
-      if (comp[i] instanceof AlignmentPanel)\r
-      {\r
-        if (((AlignmentPanel) comp[i]).av == av)\r
-        {\r
-          // close the view.\r
-          closeView((AlignmentPanel) comp[i]);\r
-          return true;\r
-        }\r
-      }\r
-    }\r
-    return false;\r
-  }\r
-\r
-  protected void build_fetchdbmenu(JMenu webService)\r
-  {\r
-    // Temporary hack - DBRef Fetcher always top level ws entry.\r
-    // TODO We probably want to store a sequence database checklist in\r
-    // preferences and have checkboxes.. rather than individual sources selected\r
-    // here\r
-    final JMenu rfetch = new JMenu(MessageManager.getString("action.fetch_db_references"));\r
-    rfetch.setToolTipText(MessageManager.getString("label.retrieve_parse_sequence_database_records_alignment_or_selected_sequences"));\r
-    webService.add(rfetch);\r
-\r
-    JMenuItem fetchr = new JMenuItem(MessageManager.getString("label.standard_databases"));\r
-    fetchr.setToolTipText(MessageManager.getString("label.fetch_embl_uniprot"));\r
-    fetchr.addActionListener(new ActionListener()\r
-    {\r
-\r
-      @Override\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        new Thread(new Runnable()\r
-        {\r
-\r
-          @Override\r
-          public void run()\r
-          {\r
-            new jalview.ws.DBRefFetcher(alignPanel.av\r
-                    .getSequenceSelection(), alignPanel.alignFrame)\r
-                    .fetchDBRefs(false);\r
-          }\r
-        }).start();\r
-\r
-      }\r
-\r
-    });\r
-    rfetch.add(fetchr);\r
-    final AlignFrame me = this;\r
-    new Thread(new Runnable()\r
-    {\r
-      @Override\r
-      public void run()\r
-      {\r
-        final jalview.ws.SequenceFetcher sf = SequenceFetcher\r
-                .getSequenceFetcherSingleton(me);\r
-        javax.swing.SwingUtilities.invokeLater(new Runnable()\r
-        {\r
-          @Override\r
-          public void run()\r
-          {\r
-            String[] dbclasses = sf.getOrderedSupportedSources();\r
-            // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);\r
-            // jalview.util.QuickSort.sort(otherdb, otherdb);\r
-            List<DbSourceProxy> otherdb;\r
-            JMenu dfetch = new JMenu();\r
-            JMenu ifetch = new JMenu();\r
-            JMenuItem fetchr = null;\r
-            int comp = 0, icomp = 0, mcomp = 15;\r
-            String mname = null;\r
-            int dbi = 0;\r
-            for (String dbclass : dbclasses)\r
-            {\r
-              otherdb = sf.getSourceProxy(dbclass);\r
-              // add a single entry for this class, or submenu allowing 'fetch\r
-              // all' or pick one\r
-              if (otherdb == null || otherdb.size() < 1)\r
-              {\r
-                continue;\r
-              }\r
-              // List<DbSourceProxy> dbs=otherdb;\r
-              // otherdb=new ArrayList<DbSourceProxy>();\r
-              // for (DbSourceProxy db:dbs)\r
-              // {\r
-              // if (!db.isA(DBRefSource.ALIGNMENTDB)\r
-              // }\r
-              if (mname == null)\r
-              {\r
-                mname = "From " + dbclass;\r
-              }\r
-              if (otherdb.size() == 1)\r
-              {\r
-                final DbSourceProxy[] dassource = otherdb\r
-                        .toArray(new DbSourceProxy[0]);\r
-                DbSourceProxy src = otherdb.get(0);\r
-                fetchr = new JMenuItem(src.getDbSource());\r
-                fetchr.addActionListener(new ActionListener()\r
-                {\r
-\r
-                  @Override\r
-                  public void actionPerformed(ActionEvent e)\r
-                  {\r
-                    new Thread(new Runnable()\r
-                    {\r
-\r
-                      @Override\r
-                      public void run()\r
-                      {\r
-                        new jalview.ws.DBRefFetcher(alignPanel.av\r
-                                .getSequenceSelection(),\r
-                                alignPanel.alignFrame, dassource)\r
-                                .fetchDBRefs(false);\r
-                      }\r
-                    }).start();\r
-                  }\r
-\r
-                });\r
-                fetchr.setToolTipText("<html>"\r
-                        + JvSwingUtils.wrapTooltip("Retrieve from "\r
-                                + src.getDbName()) + "<html>");\r
-                dfetch.add(fetchr);\r
-                comp++;\r
-              }\r
-              else\r
-              {\r
-                final DbSourceProxy[] dassource = otherdb\r
-                        .toArray(new DbSourceProxy[0]);\r
-                // fetch all entry\r
-                DbSourceProxy src = otherdb.get(0);\r
-                fetchr = new JMenuItem(MessageManager.formatMessage("label.fetch_all_param", new String[]{src.getDbSource()}));\r
-                fetchr.addActionListener(new ActionListener()\r
-                {\r
-                  @Override\r
-                  public void actionPerformed(ActionEvent e)\r
-                  {\r
-                    new Thread(new Runnable()\r
-                    {\r
-\r
-                      @Override\r
-                      public void run()\r
-                      {\r
-                        new jalview.ws.DBRefFetcher(alignPanel.av\r
-                                .getSequenceSelection(),\r
-                                alignPanel.alignFrame, dassource)\r
-                                .fetchDBRefs(false);\r
-                      }\r
-                    }).start();\r
-                  }\r
-                });\r
-\r
-                fetchr.setToolTipText("<html>"\r
-                        + JvSwingUtils.wrapTooltip("Retrieve from all "\r
-                                + otherdb.size() + " sources in "\r
-                                + src.getDbSource() + "<br>First is :"\r
-                                + src.getDbName()) + "<html>");\r
-                dfetch.add(fetchr);\r
-                comp++;\r
-                // and then build the rest of the individual menus\r
-                ifetch = new JMenu("Sources from " + src.getDbSource());\r
-                icomp = 0;\r
-                String imname = null;\r
-                int i = 0;\r
-                for (DbSourceProxy sproxy : otherdb)\r
-                {\r
-                  String dbname = sproxy.getDbName();\r
-                  String sname = dbname.length() > 5 ? dbname.substring(0,\r
-                          5) + "..." : dbname;\r
-                  String msname = dbname.length() > 10 ? dbname.substring(\r
-                          0, 10) + "..." : dbname;\r
-                  if (imname == null)\r
-                  {\r
-                    imname = "from '" + sname + "'";\r
-                  }\r
-                  fetchr = new JMenuItem(msname);\r
-                  final DbSourceProxy[] dassrc =\r
-                  { sproxy };\r
-                  fetchr.addActionListener(new ActionListener()\r
-                  {\r
-\r
-                    @Override\r
-                    public void actionPerformed(ActionEvent e)\r
-                    {\r
-                      new Thread(new Runnable()\r
-                      {\r
-\r
-                        @Override\r
-                        public void run()\r
-                        {\r
-                          new jalview.ws.DBRefFetcher(alignPanel.av\r
-                                  .getSequenceSelection(),\r
-                                  alignPanel.alignFrame, dassrc)\r
-                                  .fetchDBRefs(false);\r
-                        }\r
-                      }).start();\r
-                    }\r
-\r
-                  });\r
-                  fetchr.setToolTipText("<html>"\r
-                          + JvSwingUtils.wrapTooltip("Retrieve from "\r
-                                  + dbname) + "</html>");\r
-                  ifetch.add(fetchr);\r
-                  ++i;\r
-                  if (++icomp >= mcomp || i == (otherdb.size()))\r
-                  {\r
-                    ifetch.setText(MessageManager.formatMessage("label.source_to_target",new String[]{imname,sname}));\r
-                    dfetch.add(ifetch);\r
-                    ifetch = new JMenu();\r
-                    imname = null;\r
-                    icomp = 0;\r
-                    comp++;\r
-                  }\r
-                }\r
-              }\r
-              ++dbi;\r
-              if (comp >= mcomp || dbi >= (dbclasses.length))\r
-              {\r
-                dfetch.setText(MessageManager.formatMessage("label.source_to_target",new String[]{mname,dbclass}));\r
-                rfetch.add(dfetch);\r
-                dfetch = new JMenu();\r
-                mname = null;\r
-                comp = 0;\r
-              }\r
-            }\r
-          }\r
-        });\r
-      }\r
-    }).start();\r
-\r
-  }\r
-\r
-  /**\r
-   * Left justify the whole alignment.\r
-   */\r
-  @Override\r
-  protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    AlignmentI al = viewport.getAlignment();\r
-    al.justify(false);\r
-    viewport.firePropertyChange("alignment", null, al);\r
-  }\r
-\r
-  /**\r
-   * Right justify the whole alignment.\r
-   */\r
-  @Override\r
-  protected void justifyRightMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    AlignmentI al = viewport.getAlignment();\r
-    al.justify(true);\r
-    viewport.firePropertyChange("alignment", null, al);\r
-  }\r
-\r
-  public void setShowSeqFeatures(boolean b)\r
-  {\r
-    showSeqFeatures.setSelected(true);\r
-    viewport.setShowSequenceFeatures(true);\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.\r
-   * awt.event.ActionEvent)\r
-   */\r
-  @Override\r
-  protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowUnconserved(showNonconservedMenuItem.getState());\r
-    alignPanel.paintAlignment(true);\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event\r
-   * .ActionEvent)\r
-   */\r
-  @Override\r
-  protected void showGroupConsensus_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowGroupConsensus(showGroupConsensus.getState());\r
-    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());\r
-\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt\r
-   * .event.ActionEvent)\r
-   */\r
-  @Override\r
-  protected void showGroupConservation_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowGroupConservation(showGroupConservation.getState());\r
-    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt\r
-   * .event.ActionEvent)\r
-   */\r
-  @Override\r
-  protected void showConsensusHistogram_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowConsensusHistogram(showConsensusHistogram.getState());\r
-    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt\r
-   * .event.ActionEvent)\r
-   */\r
-  @Override\r
-  protected void showSequenceLogo_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowSequenceLogo(showSequenceLogo.getState());\r
-    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());\r
-  }\r
-\r
-  @Override\r
-  protected void normaliseSequenceLogo_actionPerformed(ActionEvent e)\r
-  {\r
-    showSequenceLogo.setState(true);\r
-    viewport.setShowSequenceLogo(true);\r
-    viewport.setNormaliseSequenceLogo(normaliseSequenceLogo.getState());\r
-    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());\r
-  }\r
-\r
-  @Override\r
-  protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)\r
-  {\r
-    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());\r
-  }\r
-\r
-  /*\r
-   * (non-Javadoc)\r
-   * \r
-   * @see\r
-   * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt\r
-   * .event.ActionEvent)\r
-   */\r
-  @Override\r
-  protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)\r
-  {\r
-    if (avc.makeGroupsFromSelection()) {\r
-      PaintRefresher.Refresh(this, viewport.getSequenceSetId());\r
-      alignPanel.updateAnnotation();\r
-      alignPanel.paintAlignment(true);\r
-    }\r
-  }\r
-\r
-  @Override\r
-  protected void createGroup_actionPerformed(ActionEvent e)\r
-  {\r
-    if (avc.createGroup())\r
-    {\r
-      alignPanel.alignmentChanged();\r
-    }\r
-  }\r
-\r
-  @Override\r
-  protected void unGroup_actionPerformed(ActionEvent e)\r
-  {\r
-    if (avc.unGroup())\r
-    {\r
-      alignPanel.alignmentChanged();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * make the given alignmentPanel the currently selected tab\r
-   * \r
-   * @param alignmentPanel\r
-   */\r
-  public void setDisplayedView(AlignmentPanel alignmentPanel)\r
-  {\r
-    if (!viewport.getSequenceSetId().equals(\r
-            alignmentPanel.av.getSequenceSetId()))\r
-    {\r
-      throw new Error(\r
-              "Implementation error: cannot show a view from another alignment in an AlignFrame.");\r
-    }\r
-    if (tabbedPane != null\r
-            & alignPanels.indexOf(alignmentPanel) != tabbedPane\r
-                    .getSelectedIndex())\r
-    {\r
-      tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));\r
-    }\r
-  }\r
-}\r
-\r
-class PrintThread extends Thread\r
-{\r
-  AlignmentPanel ap;\r
-\r
-  public PrintThread(AlignmentPanel ap)\r
-  {\r
-    this.ap = ap;\r
-  }\r
-\r
-  static PageFormat pf;\r
-\r
-  @Override\r
-  public void run()\r
-  {\r
-    PrinterJob printJob = PrinterJob.getPrinterJob();\r
-\r
-    if (pf != null)\r
-    {\r
-      printJob.setPrintable(ap, pf);\r
-    }\r
-    else\r
-    {\r
-      printJob.setPrintable(ap);\r
-    }\r
-\r
-    if (printJob.printDialog())\r
-    {\r
-      try\r
-      {\r
-        printJob.print();\r
-      } catch (Exception PrintException)\r
-      {\r
-        PrintException.printStackTrace();\r
-      }\r
-    }\r
-  }\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
+ * Copyright (C) 2014 The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' 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.NJTree;
+import jalview.analysis.ParseProperties;
+import jalview.analysis.SequenceIdMatcher;
+import jalview.api.AlignViewControllerGuiI;
+import jalview.api.AlignViewControllerI;
+import jalview.api.AlignmentViewPanel;
+import jalview.api.analysis.ScoreModelI;
+import jalview.bin.Cache;
+import jalview.commands.CommandI;
+import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
+import jalview.commands.OrderCommand;
+import jalview.commands.RemoveGapColCommand;
+import jalview.commands.RemoveGapsCommand;
+import jalview.commands.SlideSequencesCommand;
+import jalview.commands.TrimRegionCommand;
+import jalview.datamodel.AlignedCodonFrame;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SeqCigar;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.io.AlignmentProperties;
+import jalview.io.AnnotationFile;
+import jalview.io.FeaturesFile;
+import jalview.io.FileLoader;
+import jalview.io.FormatAdapter;
+import jalview.io.HTMLOutput;
+import jalview.io.IdentifyFile;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
+import jalview.io.JnetAnnotationMaker;
+import jalview.io.NewickFile;
+import jalview.io.TCoffeeScoreFile;
+import jalview.jbgui.GAlignFrame;
+import jalview.schemes.Blosum62ColourScheme;
+import jalview.schemes.BuriedColourScheme;
+import jalview.schemes.ClustalxColourScheme;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.schemes.HelixColourScheme;
+import jalview.schemes.HydrophobicColourScheme;
+import jalview.schemes.NucleotideColourScheme;
+import jalview.schemes.PIDColourScheme;
+import jalview.schemes.PurinePyrimidineColourScheme;
+import jalview.schemes.RNAHelicesColourChooser;
+import jalview.schemes.ResidueProperties;
+import jalview.schemes.StrandColourScheme;
+import jalview.schemes.TCoffeeColourScheme;
+import jalview.schemes.TaylorColourScheme;
+import jalview.schemes.TurnColourScheme;
+import jalview.schemes.UserColourScheme;
+import jalview.schemes.ZappoColourScheme;
+import jalview.util.MessageManager;
+import jalview.ws.jws1.Discoverer;
+import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.seqfetcher.DbSourceProxy;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+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.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JEditorPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
+/**
+ * DOCUMENT ME!
+ * 
+ * @author $author$
+ * @version $Revision$
+ */
+public class AlignFrame extends GAlignFrame implements DropTargetListener,
+        IProgressIndicator, AlignViewControllerGuiI
+{
+
+  /** DOCUMENT ME!! */
+  public static final int DEFAULT_WIDTH = 700;
+
+  /** DOCUMENT ME!! */
+  public static final int DEFAULT_HEIGHT = 500;
+
+  public AlignmentPanel alignPanel;
+
+  AlignViewport viewport;
+
+  public AlignViewControllerI avc;
+
+  Vector alignPanels = new Vector();
+
+  /**
+   * Last format used to load or save alignments in this window
+   */
+  String currentFileFormat = null;
+
+  /**
+   * Current filename for this alignment
+   */
+  String fileName = null;
+
+  /**
+   * Creates a new AlignFrame object with specific width and height.
+   * 
+   * @param al
+   * @param width
+   * @param height
+   */
+  public AlignFrame(AlignmentI al, int width, int height)
+  {
+    this(al, null, width, height);
+  }
+
+  /**
+   * Creates a new AlignFrame object with specific width, height and
+   * sequenceSetId
+   * 
+   * @param al
+   * @param width
+   * @param height
+   * @param sequenceSetId
+   */
+  public AlignFrame(AlignmentI al, int width, int height,
+          String sequenceSetId)
+  {
+    this(al, null, width, height, sequenceSetId);
+  }
+
+  /**
+   * Creates a new AlignFrame object with specific width, height and
+   * sequenceSetId
+   * 
+   * @param al
+   * @param width
+   * @param height
+   * @param sequenceSetId
+   * @param viewId
+   */
+  public AlignFrame(AlignmentI al, int width, int height,
+          String sequenceSetId, String viewId)
+  {
+    this(al, null, width, height, sequenceSetId, viewId);
+  }
+
+  /**
+   * new alignment window with hidden columns
+   * 
+   * @param al
+   *          AlignmentI
+   * @param hiddenColumns
+   *          ColumnSelection or null
+   * @param width
+   *          Width of alignment frame
+   * @param height
+   *          height of frame.
+   */
+  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+          int width, int height)
+  {
+    this(al, hiddenColumns, width, height, null);
+  }
+
+  /**
+   * Create alignment frame for al with hiddenColumns, a specific width and
+   * height, and specific sequenceId
+   * 
+   * @param al
+   * @param hiddenColumns
+   * @param width
+   * @param height
+   * @param sequenceSetId
+   *          (may be null)
+   */
+  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+          int width, int height, String sequenceSetId)
+  {
+    this(al, hiddenColumns, width, height, sequenceSetId, null);
+  }
+
+  /**
+   * Create alignment frame for al with hiddenColumns, a specific width and
+   * height, and specific sequenceId
+   * 
+   * @param al
+   * @param hiddenColumns
+   * @param width
+   * @param height
+   * @param sequenceSetId
+   *          (may be null)
+   * @param viewId
+   *          (may be null)
+   */
+  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
+          int width, int height, String sequenceSetId, String viewId)
+  {
+    setSize(width, height);
+
+    if (al.getDataset() == null)
+    {
+      al.setDataset(null);
+    }
+
+    viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId);
+
+    alignPanel = new AlignmentPanel(this, viewport);
+
+
+    addAlignmentPanel(alignPanel, true);
+    init();
+  }
+
+  /**
+   * Make a new AlignFrame from existing alignmentPanels
+   * 
+   * @param ap
+   *          AlignmentPanel
+   * @param av
+   *          AlignViewport
+   */
+  public AlignFrame(AlignmentPanel ap)
+  {
+    viewport = ap.av;
+    alignPanel = ap;
+    addAlignmentPanel(ap, false);
+    init();
+  }
+
+  /**
+   * initalise the alignframe from the underlying viewport data and the
+   * configurations
+   */
+  void init()
+  {
+    avc = new jalview.controller.AlignViewController(this, viewport,
+            alignPanel);
+    if (viewport.getAlignmentConservationAnnotation() == null)
+    {
+      BLOSUM62Colour.setEnabled(false);
+      conservationMenuItem.setEnabled(false);
+      modifyConservation.setEnabled(false);
+      // PIDColour.setEnabled(false);
+      // abovePIDThreshold.setEnabled(false);
+      // modifyPID.setEnabled(false);
+    }
+
+    String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT",
+            "No sort");
+
+    if (sortby.equals("Id"))
+    {
+      sortIDMenuItem_actionPerformed(null);
+    }
+    else if (sortby.equals("Pairwise Identity"))
+    {
+      sortPairwiseMenuItem_actionPerformed(null);
+    }
+
+    if (Desktop.desktop != null)
+    {
+      this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
+      addServiceListeners();
+      setGUINucleotide(viewport.getAlignment().isNucleotide());
+    }
+
+    setMenusFromViewport(viewport);
+    buildSortByAnnotationScoresMenu();
+    buildTreeMenu();
+    
+    if (viewport.wrapAlignment)
+    {
+      wrapMenuItem_actionPerformed(null);
+    }
+
+    if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false))
+    {
+      this.overviewMenuItem_actionPerformed(null);
+    }
+
+    addKeyListener();
+
+  }
+
+  /**
+   * Change the filename and format for the alignment, and enable the 'reload'
+   * button functionality.
+   * 
+   * @param file
+   *          valid filename
+   * @param format
+   *          format of file
+   */
+  public void setFileName(String file, String format)
+  {
+    fileName = file;
+    currentFileFormat = format;
+    reload.setEnabled(true);
+  }
+
+  void addKeyListener()
+  {
+    addKeyListener(new KeyAdapter()
+    {
+      @Override
+      public void keyPressed(KeyEvent evt)
+      {
+        if (viewport.cursorMode
+                && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
+                        .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
+                        .getKeyCode() <= KeyEvent.VK_NUMPAD9))
+                && Character.isDigit(evt.getKeyChar()))
+        {
+          alignPanel.seqPanel.numberPressed(evt.getKeyChar());
+        }
+
+        switch (evt.getKeyCode())
+        {
+
+        case 27: // escape key
+          deselectAllSequenceMenuItem_actionPerformed(null);
+
+          break;
+
+        case KeyEvent.VK_DOWN:
+          if (evt.isAltDown() || !viewport.cursorMode)
+          {
+            moveSelectedSequences(false);
+          }
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.moveCursor(0, 1);
+          }
+          break;
+
+        case KeyEvent.VK_UP:
+          if (evt.isAltDown() || !viewport.cursorMode)
+          {
+            moveSelectedSequences(true);
+          }
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.moveCursor(0, -1);
+          }
+
+          break;
+
+        case KeyEvent.VK_LEFT:
+          if (evt.isAltDown() || !viewport.cursorMode)
+          {
+            slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());
+          }
+          else
+          {
+            alignPanel.seqPanel.moveCursor(-1, 0);
+          }
+
+          break;
+
+        case KeyEvent.VK_RIGHT:
+          if (evt.isAltDown() || !viewport.cursorMode)
+          {
+            slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());
+          }
+          else
+          {
+            alignPanel.seqPanel.moveCursor(1, 0);
+          }
+          break;
+
+        case KeyEvent.VK_SPACE:
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
+                    || evt.isShiftDown() || evt.isAltDown());
+          }
+          break;
+
+        // case KeyEvent.VK_A:
+        // if (viewport.cursorMode)
+        // {
+        // alignPanel.seqPanel.insertNucAtCursor(false,"A");
+        // //System.out.println("A");
+        // }
+        // break;
+        /*
+         * case KeyEvent.VK_CLOSE_BRACKET: if (viewport.cursorMode) {
+         * System.out.println("closing bracket"); } break;
+         */
+        case KeyEvent.VK_DELETE:
+        case KeyEvent.VK_BACK_SPACE:
+          if (!viewport.cursorMode)
+          {
+            cut_actionPerformed(null);
+          }
+          else
+          {
+            alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
+                    || evt.isShiftDown() || evt.isAltDown());
+          }
+
+          break;
+
+        case KeyEvent.VK_S:
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.setCursorRow();
+          }
+          break;
+        case KeyEvent.VK_C:
+          if (viewport.cursorMode && !evt.isControlDown())
+          {
+            alignPanel.seqPanel.setCursorColumn();
+          }
+          break;
+        case KeyEvent.VK_P:
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.setCursorPosition();
+          }
+          break;
+
+        case KeyEvent.VK_ENTER:
+        case KeyEvent.VK_COMMA:
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.setCursorRowAndColumn();
+          }
+          break;
+
+        case KeyEvent.VK_Q:
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.setSelectionAreaAtCursor(true);
+          }
+          break;
+        case KeyEvent.VK_M:
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.setSelectionAreaAtCursor(false);
+          }
+          break;
+
+        case KeyEvent.VK_F2:
+          viewport.cursorMode = !viewport.cursorMode;
+          statusBar.setText(MessageManager.formatMessage(
+                  "label.keyboard_editing_mode", new String[]
+                  { (viewport.cursorMode ? "on" : "off") }));
+          if (viewport.cursorMode)
+          {
+            alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
+            alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
+          }
+          alignPanel.seqPanel.seqCanvas.repaint();
+          break;
+
+        case KeyEvent.VK_F1:
+          try
+          {
+            Help.showHelpWindow();
+          } catch (Exception ex)
+          {
+            ex.printStackTrace();
+          }
+          break;
+        case KeyEvent.VK_H:
+        {
+          boolean toggleSeqs = !evt.isControlDown();
+          boolean toggleCols = !evt.isShiftDown();
+          toggleHiddenRegions(toggleSeqs, toggleCols);
+          break;
+        }
+        case KeyEvent.VK_PAGE_UP:
+          if (viewport.wrapAlignment)
+          {
+            alignPanel.scrollUp(true);
+          }
+          else
+          {
+            alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
+                    - viewport.endSeq + viewport.startSeq);
+          }
+          break;
+        case KeyEvent.VK_PAGE_DOWN:
+          if (viewport.wrapAlignment)
+          {
+            alignPanel.scrollUp(false);
+          }
+          else
+          {
+            alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
+                    + viewport.endSeq - viewport.startSeq);
+          }
+          break;
+        }
+      }
+
+      @Override
+      public void keyReleased(KeyEvent evt)
+      {
+        switch (evt.getKeyCode())
+        {
+        case KeyEvent.VK_LEFT:
+          if (evt.isAltDown() || !viewport.cursorMode)
+          {
+            viewport.firePropertyChange("alignment", null, viewport
+                    .getAlignment().getSequences());
+          }
+          break;
+
+        case KeyEvent.VK_RIGHT:
+          if (evt.isAltDown() || !viewport.cursorMode)
+          {
+            viewport.firePropertyChange("alignment", null, viewport
+                    .getAlignment().getSequences());
+          }
+          break;
+        }
+      }
+    });
+  }
+
+  public void addAlignmentPanel(final AlignmentPanel ap, boolean newPanel)
+  {
+    ap.alignFrame = this;
+    avc = new jalview.controller.AlignViewController(this, viewport,
+            alignPanel);
+
+    alignPanels.addElement(ap);
+
+    PaintRefresher.Register(ap, ap.av.getSequenceSetId());
+
+    int aSize = alignPanels.size();
+
+    tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);
+
+    if (aSize == 1 && ap.av.viewName == null)
+    {
+      this.getContentPane().add(ap, BorderLayout.CENTER);
+    }
+    else
+    {
+      if (aSize == 2)
+      {
+        setInitialTabVisible();
+      }
+
+      expandViews.setEnabled(true);
+      gatherViews.setEnabled(true);
+      tabbedPane.addTab(ap.av.viewName, ap);
+
+      ap.setVisible(false);
+    }
+
+    if (newPanel)
+    {
+      if (ap.av.isPadGaps())
+      {
+        ap.av.getAlignment().padGaps();
+      }
+      ap.av.updateConservation(ap);
+      ap.av.updateConsensus(ap);
+      ap.av.updateStrucConsensus(ap);
+    }
+  }
+
+  public void setInitialTabVisible()
+  {
+    expandViews.setEnabled(true);
+    gatherViews.setEnabled(true);
+    tabbedPane.setVisible(true);
+    AlignmentPanel first = (AlignmentPanel) alignPanels.firstElement();
+    tabbedPane.addTab(first.av.viewName, first);
+    this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
+  }
+
+  public AlignViewport getViewport()
+  {
+    return viewport;
+  }
+
+  /* Set up intrinsic listeners for dynamically generated GUI bits. */
+  private void addServiceListeners()
+  {
+    final java.beans.PropertyChangeListener thisListener;
+    Desktop.instance.addJalviewPropertyChangeListener("services",
+            thisListener = new java.beans.PropertyChangeListener()
+            {
+              @Override
+              public void propertyChange(PropertyChangeEvent evt)
+              {
+                // // System.out.println("Discoverer property change.");
+                // if (evt.getPropertyName().equals("services"))
+                {
+                  SwingUtilities.invokeLater(new Runnable()
+                  {
+
+                    @Override
+                    public void run()
+                    {
+                      System.err
+                              .println("Rebuild WS Menu for service change");
+                      BuildWebServiceMenu();
+                    }
+
+                  });
+                }
+              }
+            });
+    addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+    {
+      @Override
+      public void internalFrameClosed(
+              javax.swing.event.InternalFrameEvent evt)
+      {
+        System.out.println("deregistering discoverer listener");
+        Desktop.instance.removeJalviewPropertyChangeListener("services",
+                thisListener);
+        closeMenuItem_actionPerformed(true);
+      };
+    });
+    // Finally, build the menu once to get current service state
+    new Thread(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        BuildWebServiceMenu();
+      }
+    }).start();
+  }
+
+  public void setGUINucleotide(boolean nucleotide)
+  {
+    showTranslation.setVisible(nucleotide);
+    conservationMenuItem.setEnabled(!nucleotide);
+    modifyConservation.setEnabled(!nucleotide);
+    showGroupConservation.setEnabled(!nucleotide);
+    rnahelicesColour.setEnabled(nucleotide);
+    purinePyrimidineColour.setEnabled(nucleotide);
+    // Remember AlignFrame always starts as protein
+    // if (!nucleotide)
+    // {
+    // showTr
+    // calculateMenu.remove(calculateMenu.getItemCount() - 2);
+    // }
+  }
+
+  /**
+   * set up menus for the currently viewport. This may be called after any
+   * operation that affects the data in the current view (selection changed,
+   * etc) to update the menus to reflect the new state.
+   */
+  public void setMenusForViewport()
+  {
+    setMenusFromViewport(viewport);
+  }
+
+  /**
+   * Need to call this method when tabs are selected for multiple views, or when
+   * loading from Jalview2XML.java
+   * 
+   * @param av
+   *          AlignViewport
+   */
+  void setMenusFromViewport(AlignViewport av)
+  {
+    padGapsMenuitem.setSelected(av.isPadGaps());
+    colourTextMenuItem.setSelected(av.showColourText);
+    abovePIDThreshold.setSelected(av.getAbovePIDThreshold());
+    conservationMenuItem.setSelected(av.getConservationSelected());
+    seqLimits.setSelected(av.getShowJVSuffix());
+    idRightAlign.setSelected(av.rightAlignIds);
+    centreColumnLabelsMenuItem.setState(av.centreColumnLabels);
+    renderGapsMenuItem.setSelected(av.renderGaps);
+    wrapMenuItem.setSelected(av.wrapAlignment);
+    scaleAbove.setVisible(av.wrapAlignment);
+    scaleLeft.setVisible(av.wrapAlignment);
+    scaleRight.setVisible(av.wrapAlignment);
+    annotationPanelMenuItem.setState(av.showAnnotation);
+    /*
+     * Show/hide annotations only enabled if annotation panel is shown
+     */
+    showAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState());
+    hideAllSeqAnnotations.setEnabled(annotationPanelMenuItem.getState());
+    showAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState());
+    hideAllAlAnnotations.setEnabled(annotationPanelMenuItem.getState());
+    viewBoxesMenuItem.setSelected(av.showBoxes);
+    viewTextMenuItem.setSelected(av.showText);
+    showNonconservedMenuItem.setSelected(av.getShowUnconserved());
+    showGroupConsensus.setSelected(av.isShowGroupConsensus());
+    showGroupConservation.setSelected(av.isShowGroupConservation());
+    showConsensusHistogram.setSelected(av.isShowConsensusHistogram());
+    showSequenceLogo.setSelected(av.isShowSequenceLogo());
+    normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo());
+
+    setColourSelected(ColourSchemeProperty.getColourName(av
+            .getGlobalColourScheme()));
+
+    showSeqFeatures.setSelected(av.showSequenceFeatures);
+    hiddenMarkers.setState(av.showHiddenMarkers);
+    applyToAllGroups.setState(av.getColourAppliesToAllGroups());
+    showNpFeatsMenuitem.setSelected(av.isShowNpFeats());
+    showDbRefsMenuitem.setSelected(av.isShowDbRefs());
+    autoCalculate.setSelected(av.autoCalculateConsensus);
+    sortByTree.setSelected(av.sortByTree);
+    listenToViewSelections.setSelected(av.followSelection);
+    rnahelicesColour.setEnabled(av.getAlignment().hasRNAStructure());
+    rnahelicesColour
+            .setSelected(av.getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour);
+    setShowProductsEnabled();
+    updateEditMenuBar();
+  }
+
+  // methods for implementing IProgressIndicator
+  // need to refactor to a reusable stub class
+  Hashtable progressBars, progressBarHandlers;
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
+   */
+  @Override
+  public void setProgressBar(String message, long id)
+  {
+    if (progressBars == null)
+    {
+      progressBars = new Hashtable();
+      progressBarHandlers = new Hashtable();
+    }
+
+    JPanel progressPanel;
+    Long lId = new Long(id);
+    GridLayout layout = (GridLayout) statusPanel.getLayout();
+    if (progressBars.get(lId) != null)
+    {
+      progressPanel = (JPanel) progressBars.get(new Long(id));
+      statusPanel.remove(progressPanel);
+      progressBars.remove(lId);
+      progressPanel = null;
+      if (message != null)
+      {
+        statusBar.setText(message);
+      }
+      if (progressBarHandlers.contains(lId))
+      {
+        progressBarHandlers.remove(lId);
+      }
+      layout.setRows(layout.getRows() - 1);
+    }
+    else
+    {
+      progressPanel = new JPanel(new BorderLayout(10, 5));
+
+      JProgressBar progressBar = new JProgressBar();
+      progressBar.setIndeterminate(true);
+
+      progressPanel.add(new JLabel(message), BorderLayout.WEST);
+      progressPanel.add(progressBar, BorderLayout.CENTER);
+
+      layout.setRows(layout.getRows() + 1);
+      statusPanel.add(progressPanel);
+
+      progressBars.put(lId, progressPanel);
+    }
+    // update GUI
+    // setMenusForViewport();
+    validate();
+  }
+
+  @Override
+  public void registerHandler(final long id,
+          final IProgressIndicatorHandler handler)
+  {
+    if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
+    {
+      throw new Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler"));
+    }
+    progressBarHandlers.put(new Long(id), handler);
+    final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
+    if (handler.canCancel())
+    {
+      JButton cancel = new JButton(
+              MessageManager.getString("action.cancel"));
+      final IProgressIndicator us = this;
+      cancel.addActionListener(new ActionListener()
+      {
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          handler.cancelActivity(id);
+          us.setProgressBar(MessageManager.formatMessage("label.cancelled_params", new String[]{((JLabel) progressPanel.getComponent(0)).getText()}), id);
+        }
+      });
+      progressPanel.add(cancel, BorderLayout.EAST);
+    }
+  }
+
+  /**
+   * 
+   * @return true if any progress bars are still active
+   */
+  @Override
+  public boolean operationInProgress()
+  {
+    if (progressBars != null && progressBars.size() > 0)
+    {
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public void setStatus(String text)
+  {
+    statusBar.setText(text);
+  };
+
+  /*
+   * Added so Castor Mapping file can obtain Jalview Version
+   */
+  public String getVersion()
+  {
+    return jalview.bin.Cache.getProperty("VERSION");
+  }
+
+  public FeatureRenderer getFeatureRenderer()
+  {
+    return alignPanel.seqPanel.seqCanvas.getFeatureRenderer();
+  }
+
+  @Override
+  public void fetchSequence_actionPerformed(ActionEvent e)
+  {
+    new SequenceFetcher(this);
+  }
+
+  @Override
+  public void addFromFile_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);
+  }
+
+  @Override
+  public void reload_actionPerformed(ActionEvent e)
+  {
+    if (fileName != null)
+    {
+      // TODO: JAL-1108 - ensure all associated frames are closed regardless of
+      // originating file's format
+      // TODO: work out how to recover feature settings for correct view(s) when
+      // file is reloaded.
+      if (currentFileFormat.equals("Jalview"))
+      {
+        JInternalFrame[] frames = Desktop.desktop.getAllFrames();
+        for (int i = 0; i < frames.length; i++)
+        {
+          if (frames[i] instanceof AlignFrame && frames[i] != this
+                  && ((AlignFrame) frames[i]).fileName != null
+                  && ((AlignFrame) frames[i]).fileName.equals(fileName))
+          {
+            try
+            {
+              frames[i].setSelected(true);
+              Desktop.instance.closeAssociatedWindows();
+            } catch (java.beans.PropertyVetoException ex)
+            {
+            }
+          }
+
+        }
+        Desktop.instance.closeAssociatedWindows();
+
+        FileLoader loader = new FileLoader();
+        String protocol = fileName.startsWith("http:") ? "URL" : "File";
+        loader.LoadFile(viewport, fileName, protocol, currentFileFormat);
+      }
+      else
+      {
+        Rectangle bounds = this.getBounds();
+
+        FileLoader loader = new FileLoader();
+        String protocol = fileName.startsWith("http:") ? "URL" : "File";
+        AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,
+                protocol, currentFileFormat);
+
+        newframe.setBounds(bounds);
+        if (featureSettings != null && featureSettings.isShowing())
+        {
+          final Rectangle fspos = featureSettings.frame.getBounds();
+          // TODO: need a 'show feature settings' function that takes bounds -
+          // need to refactor Desktop.addFrame
+          newframe.featureSettings_actionPerformed(null);
+          final FeatureSettings nfs = newframe.featureSettings;
+          SwingUtilities.invokeLater(new Runnable()
+          {
+            @Override
+            public void run()
+            {
+              nfs.frame.setBounds(fspos);
+            }
+          });
+          this.featureSettings.close();
+          this.featureSettings = null;
+        }
+        this.closeMenuItem_actionPerformed(true);
+      }
+    }
+  }
+
+  @Override
+  public void addFromText_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
+  }
+
+  @Override
+  public void addFromURL_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputURLMenuItem_actionPerformed(viewport);
+  }
+
+  @Override
+  public void save_actionPerformed(ActionEvent e)
+  {
+    if (fileName == null
+            || (currentFileFormat == null || !jalview.io.FormatAdapter
+                    .isValidIOFormat(currentFileFormat, true))
+            || fileName.startsWith("http"))
+    {
+      saveAs_actionPerformed(null);
+    }
+    else
+    {
+      saveAlignment(fileName, currentFileFormat);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @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);
+
+    chooser.setFileView(new JalviewFileView());
+    chooser.setDialogTitle(MessageManager.getString("label.save_alignment_to_file"));
+    chooser.setToolTipText(MessageManager.getString("action.save"));
+
+    int value = chooser.showSaveDialog(this);
+
+    if (value == JalviewFileChooser.APPROVE_OPTION)
+    {
+      currentFileFormat = chooser.getSelectedFormat();
+      if (currentFileFormat == null)
+      {
+        JOptionPane
+                .showInternalMessageDialog(
+                        Desktop.desktop,
+                        MessageManager
+                                .getString("label.select_file_format_before_saving"),
+                        MessageManager
+                                .getString("label.file_format_not_specified"),
+                        JOptionPane.WARNING_MESSAGE);
+        value = chooser.showSaveDialog(this);
+        return;
+      }
+
+      fileName = chooser.getSelectedFile().getPath();
+
+      jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",
+              currentFileFormat);
+
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);
+      if (currentFileFormat.indexOf(" ") > -1)
+      {
+        currentFileFormat = currentFileFormat.substring(0,
+                currentFileFormat.indexOf(" "));
+      }
+      saveAlignment(fileName, currentFileFormat);
+    }
+  }
+
+  public boolean saveAlignment(String file, String format)
+  {
+    boolean success = true;
+
+    if (format.equalsIgnoreCase("Jalview"))
+    {
+      String shortName = title;
+
+      if (shortName.indexOf(java.io.File.separatorChar) > -1)
+      {
+        shortName = shortName.substring(shortName
+                .lastIndexOf(java.io.File.separatorChar) + 1);
+      }
+
+      success = new Jalview2XML().SaveAlignment(this, file, shortName);
+
+      statusBar.setText(MessageManager.formatMessage(
+              "label.successfully_saved_to_file_in_format", new String[]
+              { fileName, format }));
+
+    }
+    else
+    {
+      if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
+      {
+        warningMessage("Cannot save file " + fileName + " using format "
+                + format, "Alignment output format not supported");
+        saveAs_actionPerformed(null);
+        // JBPNote need to have a raise_gui flag here
+        return false;
+      }
+
+      String[] omitHidden = null;
+
+      if (viewport.hasHiddenColumns())
+      {
+        int reply = JOptionPane
+                .showInternalConfirmDialog(
+                        Desktop.desktop,
+                        MessageManager
+                                .getString("label.alignment_contains_hidden_columns"),
+                        MessageManager
+                                .getString("action.save_omit_hidden_columns"),
+                        JOptionPane.YES_NO_OPTION,
+                        JOptionPane.QUESTION_MESSAGE);
+
+        if (reply == JOptionPane.YES_OPTION)
+        {
+          omitHidden = viewport.getViewAsString(false);
+        }
+      }
+      FormatAdapter f = new FormatAdapter();
+      String output = f.formatSequences(format,
+              viewport.getAlignment(), // class cast exceptions will
+              // occur in the distant future
+              omitHidden, f.getCacheSuffixDefault(format),
+              viewport.getColumnSelection());
+
+      if (output == null)
+      {
+        success = false;
+      }
+      else
+      {
+        try
+        {
+          java.io.PrintWriter out = new java.io.PrintWriter(
+                  new java.io.FileWriter(file));
+
+          out.print(output);
+          out.close();
+          this.setTitle(file);
+          statusBar.setText(MessageManager.formatMessage(
+                  "label.successfully_saved_to_file_in_format",
+                  new String[]
+                  { fileName, format }));
+        } catch (Exception ex)
+        {
+          success = false;
+          ex.printStackTrace();
+        }
+      }
+    }
+
+    if (!success)
+    {
+      JOptionPane.showInternalMessageDialog(this, MessageManager
+              .formatMessage("label.couldnt_save_file", new String[]
+              { fileName }), MessageManager
+              .getString("label.error_saving_file"),
+              JOptionPane.WARNING_MESSAGE);
+    }
+
+    return success;
+  }
+
+  private void warningMessage(String warning, String title)
+  {
+    if (new jalview.util.Platform().isHeadless())
+    {
+      System.err.println("Warning: " + title + "\nWarning: " + warning);
+
+    }
+    else
+    {
+      JOptionPane.showInternalMessageDialog(this, warning, title,
+              JOptionPane.WARNING_MESSAGE);
+    }
+    return;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void outputText_actionPerformed(ActionEvent e)
+  {
+    String[] omitHidden = null;
+
+    if (viewport.hasHiddenColumns())
+    {
+      int reply = JOptionPane
+              .showInternalConfirmDialog(
+                      Desktop.desktop,
+                      MessageManager
+                              .getString("label.alignment_contains_hidden_columns"),
+                      MessageManager
+                              .getString("action.save_omit_hidden_columns"),
+                      JOptionPane.YES_NO_OPTION,
+                      JOptionPane.QUESTION_MESSAGE);
+
+      if (reply == JOptionPane.YES_OPTION)
+      {
+        omitHidden = viewport.getViewAsString(false);
+      }
+    }
+
+    CutAndPasteTransfer cap = new CutAndPasteTransfer();
+    cap.setForInput(null);
+
+    try
+    {
+      cap.setText(new FormatAdapter().formatSequences(e.getActionCommand(),
+              viewport.getAlignment(), omitHidden,
+              viewport.getColumnSelection()));
+      Desktop.addInternalFrame(cap, MessageManager.formatMessage(
+              "label.alignment_output_command", new String[]
+              { e.getActionCommand() }), 600, 500);
+    } catch (OutOfMemoryError oom)
+    {
+      new OOMWarning("Outputting alignment as " + e.getActionCommand(), oom);
+      cap.dispose();
+    }
+
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void htmlMenuItem_actionPerformed(ActionEvent e)
+  {
+    new HTMLOutput(alignPanel,
+            alignPanel.seqPanel.seqCanvas.getSequenceRenderer(),
+            alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
+  }
+
+  public void createImageMap(File file, String image)
+  {
+    alignPanel.makePNGImageMap(file, image);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void createPNG(File f)
+  {
+    alignPanel.makePNG(f);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void createEPS(File f)
+  {
+    alignPanel.makeEPS(f);
+  }
+
+  public void createSVG(File f)
+  {
+    alignPanel.makeSVG(f);
+  }
+  @Override
+  public void pageSetup_actionPerformed(ActionEvent e)
+  {
+    PrinterJob printJob = PrinterJob.getPrinterJob();
+    PrintThread.pf = printJob.pageDialog(printJob.defaultPage());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void printMenuItem_actionPerformed(ActionEvent e)
+  {
+    // Putting in a thread avoids Swing painting problems
+    PrintThread thread = new PrintThread(alignPanel);
+    thread.start();
+  }
+
+  @Override
+  public void exportFeatures_actionPerformed(ActionEvent e)
+  {
+    new AnnotationExporter().exportFeatures(alignPanel);
+  }
+
+  @Override
+  public void exportAnnotations_actionPerformed(ActionEvent e)
+  {
+    new AnnotationExporter().exportAnnotations(alignPanel,
+            viewport.showAnnotation ? viewport.getAlignment()
+                    .getAlignmentAnnotation() : null, viewport
+                    .getAlignment().getGroups(), ((Alignment) viewport
+                    .getAlignment()).alignmentProperties);
+  }
+
+  @Override
+  public void associatedData_actionPerformed(ActionEvent e)
+  {
+    // Pick the tree file
+    JalviewFileChooser chooser = new JalviewFileChooser(
+            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+    chooser.setFileView(new JalviewFileView());
+    chooser.setDialogTitle(MessageManager
+            .getString("label.load_jalview_annotations"));
+    chooser.setToolTipText(MessageManager
+            .getString("label.load_jalview_annotations"));
+
+    int value = chooser.showOpenDialog(null);
+
+    if (value == JalviewFileChooser.APPROVE_OPTION)
+    {
+      String choice = chooser.getSelectedFile().getPath();
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
+      loadJalviewDataFile(choice, null, null, null);
+    }
+
+  }
+
+  /**
+   * Close the current view or all views in the alignment frame. If the frame
+   * only contains one view then the alignment will be removed from memory.
+   * 
+   * @param closeAllTabs
+   */
+  @Override
+  public void closeMenuItem_actionPerformed(boolean closeAllTabs)
+  {
+    if (alignPanels != null && alignPanels.size() < 2)
+    {
+      closeAllTabs = true;
+    }
+
+    try
+    {
+      if (alignPanels != null)
+      {
+        if (closeAllTabs)
+        {
+          if (this.isClosed())
+          {
+            // really close all the windows - otherwise wait till
+            // setClosed(true) is called
+            for (int i = 0; i < alignPanels.size(); i++)
+            {
+              AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i);
+              ap.closePanel();
+            }
+          }
+        }
+        else
+        {
+          closeView(alignPanel);
+        }
+      }
+
+      if (closeAllTabs)
+      {
+        this.setClosed(true);
+      }
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+  }
+
+  /**
+   * close alignPanel2 and shuffle tabs appropriately.
+   * 
+   * @param alignPanel2
+   */
+  public void closeView(AlignmentPanel alignPanel2)
+  {
+    int index = tabbedPane.getSelectedIndex();
+    int closedindex = tabbedPane.indexOfComponent(alignPanel2);
+    alignPanels.removeElement(alignPanel2);
+    // Unnecessary
+    // if (viewport == alignPanel2.av)
+    // {
+    // viewport = null;
+    // }
+    alignPanel2.closePanel();
+    alignPanel2 = null;
+
+    tabbedPane.removeTabAt(closedindex);
+    tabbedPane.validate();
+
+    if (index > closedindex || index == tabbedPane.getTabCount())
+    {
+      // modify currently selected tab index if necessary.
+      index--;
+    }
+
+    this.tabSelectionChanged(index);
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  void updateEditMenuBar()
+  {
+
+    if (viewport.historyList.size() > 0)
+    {
+      undoMenuItem.setEnabled(true);
+      CommandI command = viewport.historyList.peek();
+      undoMenuItem.setText(MessageManager.formatMessage(
+              "label.undo_command", new String[]
+              { command.getDescription() }));
+    }
+    else
+    {
+      undoMenuItem.setEnabled(false);
+      undoMenuItem.setText(MessageManager.getString("action.undo"));
+    }
+
+    if (viewport.redoList.size() > 0)
+    {
+      redoMenuItem.setEnabled(true);
+
+      CommandI command = viewport.redoList.peek();
+      redoMenuItem.setText(MessageManager.formatMessage(
+              "label.redo_command", new String[]
+              { command.getDescription() }));
+    }
+    else
+    {
+      redoMenuItem.setEnabled(false);
+      redoMenuItem.setText(MessageManager.getString("action.redo"));
+    }
+  }
+
+  public void addHistoryItem(CommandI command)
+  {
+    if (command.getSize() > 0)
+    {
+      viewport.historyList.push(command);
+      viewport.redoList.clear();
+      updateEditMenuBar();
+      viewport.updateHiddenColumns();
+      // viewport.hasHiddenColumns = (viewport.getColumnSelection() != null
+      // && viewport.getColumnSelection().getHiddenColumns() != null &&
+      // viewport.getColumnSelection()
+      // .getHiddenColumns().size() > 0);
+    }
+  }
+
+  /**
+   * 
+   * @return alignment objects for all views
+   */
+  AlignmentI[] getViewAlignments()
+  {
+    if (alignPanels != null)
+    {
+      Enumeration e = alignPanels.elements();
+      AlignmentI[] als = new AlignmentI[alignPanels.size()];
+      for (int i = 0; e.hasMoreElements(); i++)
+      {
+        als[i] = ((AlignmentPanel) e.nextElement()).av.getAlignment();
+      }
+      return als;
+    }
+    if (viewport != null)
+    {
+      return new AlignmentI[]
+      { viewport.getAlignment() };
+    }
+    return null;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void undoMenuItem_actionPerformed(ActionEvent e)
+  {
+    if (viewport.historyList.empty())
+    {
+      return;
+    }
+    CommandI command = viewport.historyList.pop();
+    viewport.redoList.push(command);
+    command.undoCommand(getViewAlignments());
+
+    AlignViewport originalSource = getOriginatingSource(command);
+    updateEditMenuBar();
+
+    if (originalSource != null)
+    {
+      if (originalSource != viewport)
+      {
+        Cache.log
+                .warn("Implementation worry: mismatch of viewport origin for undo");
+      }
+      originalSource.updateHiddenColumns();
+      // originalSource.hasHiddenColumns = (viewport.getColumnSelection() !=
+      // null
+      // && viewport.getColumnSelection().getHiddenColumns() != null &&
+      // viewport.getColumnSelection()
+      // .getHiddenColumns().size() > 0);
+      originalSource.firePropertyChange("alignment", null, originalSource
+              .getAlignment().getSequences());
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void redoMenuItem_actionPerformed(ActionEvent e)
+  {
+    if (viewport.redoList.size() < 1)
+    {
+      return;
+    }
+
+    CommandI command = viewport.redoList.pop();
+    viewport.historyList.push(command);
+    command.doCommand(getViewAlignments());
+
+    AlignViewport originalSource = getOriginatingSource(command);
+    updateEditMenuBar();
+
+    if (originalSource != null)
+    {
+
+      if (originalSource != viewport)
+      {
+        Cache.log
+                .warn("Implementation worry: mismatch of viewport origin for redo");
+      }
+      originalSource.updateHiddenColumns();
+      // originalSource.hasHiddenColumns = (viewport.getColumnSelection() !=
+      // null
+      // && viewport.getColumnSelection().getHiddenColumns() != null &&
+      // viewport.getColumnSelection()
+      // .getHiddenColumns().size() > 0);
+      originalSource.firePropertyChange("alignment", null, originalSource
+              .getAlignment().getSequences());
+    }
+  }
+
+  AlignViewport getOriginatingSource(CommandI command)
+  {
+    AlignViewport originalSource = null;
+    // For sequence removal and addition, we need to fire
+    // the property change event FROM the viewport where the
+    // original alignment was altered
+    AlignmentI al = null;
+    if (command instanceof EditCommand)
+    {
+      EditCommand editCommand = (EditCommand) command;
+      al = editCommand.getAlignment();
+      Vector comps = (Vector) PaintRefresher.components.get(viewport
+              .getSequenceSetId());
+
+      for (int i = 0; i < comps.size(); i++)
+      {
+        if (comps.elementAt(i) instanceof AlignmentPanel)
+        {
+          if (al == ((AlignmentPanel) comps.elementAt(i)).av.getAlignment())
+          {
+            originalSource = ((AlignmentPanel) comps.elementAt(i)).av;
+            break;
+          }
+        }
+      }
+    }
+
+    if (originalSource == null)
+    {
+      // The original view is closed, we must validate
+      // the current view against the closed view first
+      if (al != null)
+      {
+        PaintRefresher.validateSequences(al, viewport.getAlignment());
+      }
+
+      originalSource = viewport;
+    }
+
+    return originalSource;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param up
+   *          DOCUMENT ME!
+   */
+  public void moveSelectedSequences(boolean up)
+  {
+    SequenceGroup sg = viewport.getSelectionGroup();
+
+    if (sg == null)
+    {
+      return;
+    }
+    viewport.getAlignment().moveSelectedSequencesByOne(sg,
+            viewport.getHiddenRepSequences(), up);
+    alignPanel.paintAlignment(true);
+  }
+
+  synchronized void slideSequences(boolean right, int size)
+  {
+    List<SequenceI> sg = new Vector();
+    if (viewport.cursorMode)
+    {
+      sg.add(viewport.getAlignment().getSequenceAt(
+              alignPanel.seqPanel.seqCanvas.cursorY));
+    }
+    else if (viewport.getSelectionGroup() != null
+            && viewport.getSelectionGroup().getSize() != viewport
+                    .getAlignment().getHeight())
+    {
+      sg = viewport.getSelectionGroup().getSequences(
+              viewport.getHiddenRepSequences());
+    }
+
+    if (sg.size() < 1)
+    {
+      return;
+    }
+
+    Vector invertGroup = new Vector();
+
+    for (int i = 0; i < viewport.getAlignment().getHeight(); i++)
+    {
+      if (!sg.contains(viewport.getAlignment().getSequenceAt(i)))
+      {
+        invertGroup.add(viewport.getAlignment().getSequenceAt(i));
+      }
+    }
+
+    SequenceI[] seqs1 = sg.toArray(new SequenceI[0]);
+
+    SequenceI[] seqs2 = new SequenceI[invertGroup.size()];
+    for (int i = 0; i < invertGroup.size(); i++)
+    {
+      seqs2[i] = (SequenceI) invertGroup.elementAt(i);
+    }
+
+    SlideSequencesCommand ssc;
+    if (right)
+    {
+      ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1,
+              size, viewport.getGapCharacter());
+    }
+    else
+    {
+      ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2,
+              size, viewport.getGapCharacter());
+    }
+
+    int groupAdjustment = 0;
+    if (ssc.getGapsInsertedBegin() && right)
+    {
+      if (viewport.cursorMode)
+      {
+        alignPanel.seqPanel.moveCursor(size, 0);
+      }
+      else
+      {
+        groupAdjustment = size;
+      }
+    }
+    else if (!ssc.getGapsInsertedBegin() && !right)
+    {
+      if (viewport.cursorMode)
+      {
+        alignPanel.seqPanel.moveCursor(-size, 0);
+      }
+      else
+      {
+        groupAdjustment = -size;
+      }
+    }
+
+    if (groupAdjustment != 0)
+    {
+      viewport.getSelectionGroup().setStartRes(
+              viewport.getSelectionGroup().getStartRes() + groupAdjustment);
+      viewport.getSelectionGroup().setEndRes(
+              viewport.getSelectionGroup().getEndRes() + groupAdjustment);
+    }
+
+    boolean appendHistoryItem = false;
+    if (viewport.historyList != null && viewport.historyList.size() > 0
+            && viewport.historyList.peek() instanceof SlideSequencesCommand)
+    {
+      appendHistoryItem = ssc
+              .appendSlideCommand((SlideSequencesCommand) viewport.historyList
+                      .peek());
+    }
+
+    if (!appendHistoryItem)
+    {
+      addHistoryItem(ssc);
+    }
+
+    repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void copy_actionPerformed(ActionEvent e)
+  {
+    System.gc();
+    if (viewport.getSelectionGroup() == null)
+    {
+      return;
+    }
+    // TODO: preserve the ordering of displayed alignment annotation in any
+    // internal paste (particularly sequence associated annotation)
+    SequenceI[] seqs = viewport.getSelectionAsNewSequence();
+    String[] omitHidden = null;
+
+    if (viewport.hasHiddenColumns())
+    {
+      omitHidden = viewport.getViewAsString(true);
+    }
+
+    String output = new FormatAdapter().formatSequences("Fasta", seqs,
+            omitHidden);
+
+    StringSelection ss = new StringSelection(output);
+
+    try
+    {
+      jalview.gui.Desktop.internalCopy = true;
+      // Its really worth setting the clipboard contents
+      // to empty before setting the large StringSelection!!
+      Toolkit.getDefaultToolkit().getSystemClipboard()
+              .setContents(new StringSelection(""), null);
+
+      Toolkit.getDefaultToolkit().getSystemClipboard()
+              .setContents(ss, Desktop.instance);
+    } catch (OutOfMemoryError er)
+    {
+      new OOMWarning("copying region", er);
+      return;
+    }
+
+    Vector hiddenColumns = null;
+    if (viewport.hasHiddenColumns())
+    {
+      hiddenColumns = new Vector();
+      int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport
+              .getSelectionGroup().getEndRes();
+      for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()
+              .size(); i++)
+      {
+        int[] region = (int[]) viewport.getColumnSelection()
+                .getHiddenColumns().elementAt(i);
+        if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
+        {
+          hiddenColumns.addElement(new int[]
+          { region[0] - hiddenOffset, region[1] - hiddenOffset });
+        }
+      }
+    }
+
+    Desktop.jalviewClipboard = new Object[]
+    { seqs, viewport.getAlignment().getDataset(), hiddenColumns };
+    statusBar.setText(MessageManager.formatMessage(
+            "label.copied_sequences_to_clipboard", new String[]
+            { Integer.valueOf(seqs.length).toString() }));
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void pasteNew_actionPerformed(ActionEvent e)
+  {
+    paste(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void pasteThis_actionPerformed(ActionEvent e)
+  {
+    paste(false);
+  }
+
+  /**
+   * Paste contents of Jalview clipboard
+   * 
+   * @param newAlignment
+   *          true to paste to a new alignment, otherwise add to this.
+   */
+  void paste(boolean newAlignment)
+  {
+    boolean externalPaste = true;
+    try
+    {
+      Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
+      Transferable contents = c.getContents(this);
+
+      if (contents == null)
+      {
+        return;
+      }
+
+      String str, format;
+      try
+      {
+        str = (String) contents.getTransferData(DataFlavor.stringFlavor);
+        if (str.length() < 1)
+        {
+          return;
+        }
+
+        format = new IdentifyFile().Identify(str, "Paste");
+
+      } catch (OutOfMemoryError er)
+      {
+        new OOMWarning("Out of memory pasting sequences!!", er);
+        return;
+      }
+
+      SequenceI[] sequences;
+      boolean annotationAdded = false;
+      AlignmentI alignment = null;
+
+      if (Desktop.jalviewClipboard != null)
+      {
+        // The clipboard was filled from within Jalview, we must use the
+        // sequences
+        // And dataset from the copied alignment
+        SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];
+        // be doubly sure that we create *new* sequence objects.
+        sequences = new SequenceI[newseq.length];
+        for (int i = 0; i < newseq.length; i++)
+        {
+          sequences[i] = new Sequence(newseq[i]);
+        }
+        alignment = new Alignment(sequences);
+        externalPaste = false;
+      }
+      else
+      {
+        // parse the clipboard as an alignment.
+        alignment = new FormatAdapter().readFile(str, "Paste", format);
+        sequences = alignment.getSequencesArray();
+      }
+
+      int alwidth = 0;
+      ArrayList<Integer> newGraphGroups = new ArrayList<Integer>();
+      int fgroup = -1;
+
+      if (newAlignment)
+      {
+
+        if (Desktop.jalviewClipboard != null)
+        {
+          // dataset is inherited
+          alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);
+        }
+        else
+        {
+          // new dataset is constructed
+          alignment.setDataset(null);
+        }
+        alwidth = alignment.getWidth() + 1;
+      }
+      else
+      {
+        AlignmentI pastedal = alignment; // preserve pasted alignment object
+        // Add pasted sequences and dataset into existing alignment.
+        alignment = viewport.getAlignment();
+        alwidth = alignment.getWidth() + 1;
+        // decide if we need to import sequences from an existing dataset
+        boolean importDs = Desktop.jalviewClipboard != null
+                && Desktop.jalviewClipboard[1] != alignment.getDataset();
+        // importDs==true instructs us to copy over new dataset sequences from
+        // an existing alignment
+        Vector newDs = (importDs) ? new Vector() : null; // used to create
+        // minimum dataset set
+
+        for (int i = 0; i < sequences.length; i++)
+        {
+          if (importDs)
+          {
+            newDs.addElement(null);
+          }
+          SequenceI ds = sequences[i].getDatasetSequence(); // null for a simple
+          // paste
+          if (importDs && ds != null)
+          {
+            if (!newDs.contains(ds))
+            {
+              newDs.setElementAt(ds, i);
+              ds = new Sequence(ds);
+              // update with new dataset sequence
+              sequences[i].setDatasetSequence(ds);
+            }
+            else
+            {
+              ds = sequences[newDs.indexOf(ds)].getDatasetSequence();
+            }
+          }
+          else
+          {
+            // copy and derive new dataset sequence
+            sequences[i] = sequences[i].deriveSequence();
+            alignment.getDataset().addSequence(
+                    sequences[i].getDatasetSequence());
+            // TODO: avoid creation of duplicate dataset sequences with a
+            // 'contains' method using SequenceI.equals()/SequenceI.contains()
+          }
+          alignment.addSequence(sequences[i]); // merges dataset
+        }
+        if (newDs != null)
+        {
+          newDs.clear(); // tidy up
+        }
+        if (alignment.getAlignmentAnnotation() != null)
+        {
+          for (AlignmentAnnotation alan : alignment
+                  .getAlignmentAnnotation())
+          {
+            if (alan.graphGroup > fgroup)
+            {
+              fgroup = alan.graphGroup;
+            }
+          }
+        }
+        if (pastedal.getAlignmentAnnotation() != null)
+        {
+          // Add any annotation attached to alignment.
+          AlignmentAnnotation[] alann = pastedal.getAlignmentAnnotation();
+          for (int i = 0; i < alann.length; i++)
+          {
+            annotationAdded = true;
+            if (alann[i].sequenceRef == null && !alann[i].autoCalculated)
+            {
+              AlignmentAnnotation newann = new AlignmentAnnotation(alann[i]);
+              if (newann.graphGroup > -1)
+              {
+                if (newGraphGroups.size() <= newann.graphGroup
+                        || newGraphGroups.get(newann.graphGroup) == null)
+                {
+                  for (int q = newGraphGroups.size(); q <= newann.graphGroup; q++)
+                  {
+                    newGraphGroups.add(q, null);
+                  }
+                  newGraphGroups.set(newann.graphGroup, new Integer(
+                          ++fgroup));
+                }
+                newann.graphGroup = newGraphGroups.get(newann.graphGroup)
+                        .intValue();
+              }
+
+              newann.padAnnotation(alwidth);
+              alignment.addAnnotation(newann);
+            }
+          }
+        }
+      }
+      if (!newAlignment)
+      {
+        // /////
+        // ADD HISTORY ITEM
+        //
+        addHistoryItem(new EditCommand(
+                MessageManager.getString("label.add_sequences"),
+                Action.PASTE,
+                sequences, 0, alignment.getWidth(), alignment));
+      }
+      // Add any annotations attached to sequences
+      for (int i = 0; i < sequences.length; i++)
+      {
+        if (sequences[i].getAnnotation() != null)
+        {
+          AlignmentAnnotation newann;
+          for (int a = 0; a < sequences[i].getAnnotation().length; a++)
+          {
+            annotationAdded = true;
+            newann = sequences[i].getAnnotation()[a];
+            newann.adjustForAlignment();
+            newann.padAnnotation(alwidth);
+            if (newann.graphGroup > -1)
+            {
+              if (newann.graphGroup > -1)
+              {
+                if (newGraphGroups.size() <= newann.graphGroup
+                        || newGraphGroups.get(newann.graphGroup) == null)
+                {
+                  for (int q = newGraphGroups.size(); q <= newann.graphGroup; q++)
+                  {
+                    newGraphGroups.add(q, null);
+                  }
+                  newGraphGroups.set(newann.graphGroup, new Integer(
+                          ++fgroup));
+                }
+                newann.graphGroup = newGraphGroups.get(newann.graphGroup)
+                        .intValue();
+              }
+            }
+            alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation
+            // was
+            // duplicated
+            // earlier
+            alignment
+                    .setAnnotationIndex(sequences[i].getAnnotation()[a], a);
+          }
+        }
+      }
+      if (!newAlignment)
+      {
+
+        // propagate alignment changed.
+        viewport.setEndSeq(alignment.getHeight());
+        if (annotationAdded)
+        {
+          // Duplicate sequence annotation in all views.
+          AlignmentI[] alview = this.getViewAlignments();
+          for (int i = 0; i < sequences.length; i++)
+          {
+            AlignmentAnnotation sann[] = sequences[i].getAnnotation();
+            if (sann == null)
+            {
+              continue;
+            }
+            for (int avnum = 0; avnum < alview.length; avnum++)
+            {
+              if (alview[avnum] != alignment)
+              {
+                // duplicate in a view other than the one with input focus
+                int avwidth = alview[avnum].getWidth() + 1;
+                // this relies on sann being preserved after we
+                // modify the sequence's annotation array for each duplication
+                for (int a = 0; a < sann.length; a++)
+                {
+                  AlignmentAnnotation newann = new AlignmentAnnotation(
+                          sann[a]);
+                  sequences[i].addAlignmentAnnotation(newann);
+                  newann.padAnnotation(avwidth);
+                  alview[avnum].addAnnotation(newann); // annotation was
+                  // duplicated earlier
+                  // TODO JAL-1145 graphGroups are not updated for sequence
+                  // annotation added to several views. This may cause
+                  // strangeness
+                  alview[avnum].setAnnotationIndex(newann, a);
+                }
+              }
+            }
+          }
+          buildSortByAnnotationScoresMenu();
+        }
+        viewport.firePropertyChange("alignment", null,
+                alignment.getSequences());
+        if (alignPanels != null)
+        {
+          for (AlignmentPanel ap : ((Vector<AlignmentPanel>) alignPanels))
+          {
+            ap.validateAnnotationDimensions(false);
+          }
+        }
+        else
+        {
+          alignPanel.validateAnnotationDimensions(false);
+        }
+
+      }
+      else
+      {
+        AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
+                DEFAULT_HEIGHT);
+        String newtitle = new String("Copied sequences");
+
+        if (Desktop.jalviewClipboard != null
+                && Desktop.jalviewClipboard[2] != null)
+        {
+          Vector hc = (Vector) Desktop.jalviewClipboard[2];
+          for (int i = 0; i < hc.size(); i++)
+          {
+            int[] region = (int[]) hc.elementAt(i);
+            af.viewport.hideColumns(region[0], region[1]);
+          }
+        }
+
+        // >>>This is a fix for the moment, until a better solution is
+        // found!!<<<
+        af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()
+                .transferSettings(
+                        alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
+
+        // TODO: maintain provenance of an alignment, rather than just make the
+        // title a concatenation of operations.
+        if (!externalPaste)
+        {
+          if (title.startsWith("Copied sequences"))
+          {
+            newtitle = title;
+          }
+          else
+          {
+            newtitle = newtitle.concat("- from " + title);
+          }
+        }
+        else
+        {
+          newtitle = new String("Pasted sequences");
+        }
+
+        Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
+                DEFAULT_HEIGHT);
+
+      }
+
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+      System.out.println("Exception whilst pasting: " + ex);
+      // could be anything being pasted in here
+    }
+
+  }
+
+  @Override
+  protected void expand_newalign(ActionEvent e)
+  {
+    try
+    {
+      AlignmentI alignment = AlignmentUtils.expandContext(getViewport()
+              .getAlignment(), -1);
+      AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
+              DEFAULT_HEIGHT);
+      String newtitle = new String("Flanking alignment");
+
+      if (Desktop.jalviewClipboard != null
+              && Desktop.jalviewClipboard[2] != null)
+      {
+        Vector hc = (Vector) Desktop.jalviewClipboard[2];
+        for (int i = 0; i < hc.size(); i++)
+        {
+          int[] region = (int[]) hc.elementAt(i);
+          af.viewport.hideColumns(region[0], region[1]);
+        }
+      }
+
+      // >>>This is a fix for the moment, until a better solution is
+      // found!!<<<
+      af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()
+              .transferSettings(
+                      alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
+
+      // TODO: maintain provenance of an alignment, rather than just make the
+      // title a concatenation of operations.
+      {
+        if (title.startsWith("Copied sequences"))
+        {
+          newtitle = title;
+        }
+        else
+        {
+          newtitle = newtitle.concat("- from " + title);
+        }
+      }
+
+      Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+      System.out.println("Exception whilst pasting: " + ex);
+      // could be anything being pasted in here
+    } catch (OutOfMemoryError oom)
+    {
+      new OOMWarning("Viewing flanking region of alignment", oom);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void cut_actionPerformed(ActionEvent e)
+  {
+    copy_actionPerformed(null);
+    delete_actionPerformed(null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void delete_actionPerformed(ActionEvent evt)
+  {
+
+    SequenceGroup sg = viewport.getSelectionGroup();
+    if (sg == null)
+    {
+      return;
+    }
+
+    List<SequenceI> seqs = new ArrayList<SequenceI>(sg.getSize());
+    SequenceI seq;
+    for (int i = 0; i < sg.getSize(); i++)
+    {
+      seq = sg.getSequenceAt(i);
+      seqs.add(seq);
+    }
+
+    // If the cut affects all sequences, warn, remove highlighted columns
+    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)
+      {
+        return;
+      }
+      viewport.getColumnSelection().removeElements(sg.getStartRes(),
+              sg.getEndRes() + 1);
+    }
+
+    SequenceI[] cut = new SequenceI[seqs.size()];
+    for (int i = 0; i < seqs.size(); i++)
+    {
+      cut[i] = seqs.get(i);
+    }
+
+    /*
+     * //ADD HISTORY ITEM
+     */
+    addHistoryItem(new EditCommand(
+            MessageManager.getString("label.cut_sequences"), Action.CUT,
+            cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
+            viewport.getAlignment()));
+
+    viewport.setSelectionGroup(null);
+    viewport.sendSelection();
+    viewport.getAlignment().deleteGroup(sg);
+
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
+            .getSequences());
+    if (viewport.getAlignment().getHeight() < 1)
+    {
+      try
+      {
+        this.setClosed(true);
+      } catch (Exception ex)
+      {
+      }
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void deleteGroups_actionPerformed(ActionEvent e)
+  {
+    if (avc.deleteGroups())
+    {
+      PaintRefresher.Refresh(this, viewport.getSequenceSetId());
+      alignPanel.updateAnnotation();
+      alignPanel.paintAlignment(true);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceGroup sg = new SequenceGroup();
+
+    for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
+    {
+      sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
+    }
+
+    sg.setEndRes(viewport.getAlignment().getWidth() - 1);
+    viewport.setSelectionGroup(sg);
+    viewport.sendSelection();
+    alignPanel.paintAlignment(true);
+    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
+  {
+    if (viewport.cursorMode)
+    {
+      alignPanel.seqPanel.keyboardNo1 = null;
+      alignPanel.seqPanel.keyboardNo2 = null;
+    }
+    viewport.setSelectionGroup(null);
+    viewport.getColumnSelection().clear();
+    viewport.setSelectionGroup(null);
+    alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
+    alignPanel.idPanel.idCanvas.searchResults = null;
+    alignPanel.paintAlignment(true);
+    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
+    viewport.sendSelection();
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceGroup sg = viewport.getSelectionGroup();
+
+    if (sg == null)
+    {
+      selectAllSequenceMenuItem_actionPerformed(null);
+
+      return;
+    }
+
+    for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
+    {
+      sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
+    }
+
+    alignPanel.paintAlignment(true);
+    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
+    viewport.sendSelection();
+  }
+
+  @Override
+  public void invertColSel_actionPerformed(ActionEvent e)
+  {
+    viewport.invertColumnSelection();
+    alignPanel.paintAlignment(true);
+    viewport.sendSelection();
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
+  {
+    trimAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void remove2RightMenuItem_actionPerformed(ActionEvent e)
+  {
+    trimAlignment(false);
+  }
+
+  void trimAlignment(boolean trimLeft)
+  {
+    ColumnSelection colSel = viewport.getColumnSelection();
+    int column;
+
+    if (colSel.size() > 0)
+    {
+      if (trimLeft)
+      {
+        column = colSel.getMin();
+      }
+      else
+      {
+        column = colSel.getMax();
+      }
+
+      SequenceI[] seqs;
+      if (viewport.getSelectionGroup() != null)
+      {
+        seqs = viewport.getSelectionGroup().getSequencesAsArray(
+                viewport.getHiddenRepSequences());
+      }
+      else
+      {
+        seqs = viewport.getAlignment().getSequencesArray();
+      }
+
+      TrimRegionCommand trimRegion;
+      if (trimLeft)
+      {
+        trimRegion = new TrimRegionCommand("Remove Left",
+                TrimRegionCommand.TRIM_LEFT, seqs, column,
+                viewport.getAlignment(), viewport.getColumnSelection(),
+                viewport.getSelectionGroup());
+        viewport.setStartRes(0);
+      }
+      else
+      {
+        trimRegion = new TrimRegionCommand("Remove Right",
+                TrimRegionCommand.TRIM_RIGHT, seqs, column,
+                viewport.getAlignment(), viewport.getColumnSelection(),
+                viewport.getSelectionGroup());
+      }
+
+      statusBar.setText(MessageManager.formatMessage(
+              "label.removed_columns", new String[]
+              { Integer.valueOf(trimRegion.getSize()).toString() }));
+
+      addHistoryItem(trimRegion);
+
+      for (SequenceGroup sg : viewport.getAlignment().getGroups())
+      {
+        if ((trimLeft && !sg.adjustForRemoveLeft(column))
+                || (!trimLeft && !sg.adjustForRemoveRight(column)))
+        {
+          viewport.getAlignment().deleteGroup(sg);
+        }
+      }
+
+      viewport.firePropertyChange("alignment", null, viewport
+              .getAlignment().getSequences());
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
+  {
+    int start = 0, end = viewport.getAlignment().getWidth() - 1;
+
+    SequenceI[] seqs;
+    if (viewport.getSelectionGroup() != null)
+    {
+      seqs = viewport.getSelectionGroup().getSequencesAsArray(
+              viewport.getHiddenRepSequences());
+      start = viewport.getSelectionGroup().getStartRes();
+      end = viewport.getSelectionGroup().getEndRes();
+    }
+    else
+    {
+      seqs = viewport.getAlignment().getSequencesArray();
+    }
+
+    RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
+            "Remove Gapped Columns", seqs, start, end,
+            viewport.getAlignment());
+
+    addHistoryItem(removeGapCols);
+
+    statusBar.setText(MessageManager.formatMessage(
+            "label.removed_empty_columns", new String[]
+            { Integer.valueOf(removeGapCols.getSize()).toString() }));
+
+    // This is to maintain viewport position on first residue
+    // of first sequence
+    SequenceI seq = viewport.getAlignment().getSequenceAt(0);
+    int startRes = seq.findPosition(viewport.startRes);
+    // ShiftList shifts;
+    // viewport.getAlignment().removeGaps(shifts=new ShiftList());
+    // edit.alColumnChanges=shifts.getInverse();
+    // if (viewport.hasHiddenColumns)
+    // viewport.getColumnSelection().compensateForEdits(shifts);
+    viewport.setStartRes(seq.findIndex(startRes) - 1);
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
+            .getSequences());
+
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
+  {
+    int start = 0, end = viewport.getAlignment().getWidth() - 1;
+
+    SequenceI[] seqs;
+    if (viewport.getSelectionGroup() != null)
+    {
+      seqs = viewport.getSelectionGroup().getSequencesAsArray(
+              viewport.getHiddenRepSequences());
+      start = viewport.getSelectionGroup().getStartRes();
+      end = viewport.getSelectionGroup().getEndRes();
+    }
+    else
+    {
+      seqs = viewport.getAlignment().getSequencesArray();
+    }
+
+    // This is to maintain viewport position on first residue
+    // of first sequence
+    SequenceI seq = viewport.getAlignment().getSequenceAt(0);
+    int startRes = seq.findPosition(viewport.startRes);
+
+    addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
+            viewport.getAlignment()));
+
+    viewport.setStartRes(seq.findIndex(startRes) - 1);
+
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
+            .getSequences());
+
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void padGapsMenuitem_actionPerformed(ActionEvent e)
+  {
+    viewport.setPadGaps(padGapsMenuitem.isSelected());
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
+            .getSequences());
+  }
+
+  // else
+  {
+    // if (justifySeqs>0)
+    {
+      // alignment.justify(justifySeqs!=RIGHT_JUSTIFY);
+    }
+  }
+
+  // }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void findMenuItem_actionPerformed(ActionEvent e)
+  {
+    new Finder();
+  }
+
+  @Override
+  public void newView_actionPerformed(ActionEvent e)
+  {
+    newView(true);
+  }
+
+  /**
+   * 
+   * @param copyAnnotation
+   *          if true then duplicate all annnotation, groups and settings
+   * @return new alignment panel, already displayed.
+   */
+  public AlignmentPanel newView(boolean copyAnnotation)
+  {
+    return newView(null, copyAnnotation);
+  }
+
+  /**
+   * 
+   * @param viewTitle
+   *          title of newly created view
+   * @return new alignment panel, already displayed.
+   */
+  public AlignmentPanel newView(String viewTitle)
+  {
+    return newView(viewTitle, true);
+  }
+
+  /**
+   * 
+   * @param viewTitle
+   *          title of newly created view
+   * @param copyAnnotation
+   *          if true then duplicate all annnotation, groups and settings
+   * @return new alignment panel, already displayed.
+   */
+  public AlignmentPanel newView(String viewTitle, boolean copyAnnotation)
+  {
+    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
+            true);
+    if (!copyAnnotation)
+    {
+      // just remove all the current annotation except for the automatic stuff
+      newap.av.getAlignment().deleteAllGroups();
+      for (AlignmentAnnotation alan : newap.av.getAlignment()
+              .getAlignmentAnnotation())
+      {
+        if (!alan.autoCalculated)
+        {
+          newap.av.getAlignment().deleteAnnotation(alan);
+        }
+        ;
+      }
+    }
+
+    newap.av.gatherViewsHere = false;
+
+    if (viewport.viewName == null)
+    {
+      viewport.viewName = "Original";
+    }
+
+    newap.av.historyList = viewport.historyList;
+    newap.av.redoList = viewport.redoList;
+
+    int index = Desktop.getViewCount(viewport.getSequenceSetId());
+    // make sure the new view has a unique name - this is essential for Jalview
+    // 2 archives
+    boolean addFirstIndex = false;
+    if (viewTitle == null || viewTitle.trim().length() == 0)
+    {
+      viewTitle = MessageManager.getString("action.view");
+      addFirstIndex = true;
+    }
+    else
+    {
+      index = 1;// we count from 1 if given a specific name
+    }
+    String newViewName = viewTitle + ((addFirstIndex) ? " " + index : "");
+    Vector comps = (Vector) PaintRefresher.components.get(viewport
+            .getSequenceSetId());
+    Vector existingNames = new Vector();
+    for (int i = 0; i < comps.size(); i++)
+    {
+      if (comps.elementAt(i) instanceof AlignmentPanel)
+      {
+        AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
+        if (!existingNames.contains(ap.av.viewName))
+        {
+          existingNames.addElement(ap.av.viewName);
+        }
+      }
+    }
+
+    while (existingNames.contains(newViewName))
+    {
+      newViewName = viewTitle + " " + (++index);
+    }
+
+    newap.av.viewName = newViewName;
+
+    addAlignmentPanel(newap, true);
+    newap.alignmentChanged();
+
+    if (alignPanels.size() == 2)
+    {
+      viewport.gatherViewsHere = true;
+    }
+    tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
+    return newap;
+  }
+
+  @Override
+  public void expandViews_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.explodeViews(this);
+  }
+
+  @Override
+  public void gatherViews_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.gatherViews(this);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void font_actionPerformed(ActionEvent e)
+  {
+    new FontChooser(alignPanel);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void seqLimit_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowJVSuffix(seqLimits.isSelected());
+
+    alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
+            .calculateIdWidth());
+    alignPanel.paintAlignment(true);
+  }
+
+  @Override
+  public void idRightAlign_actionPerformed(ActionEvent e)
+  {
+    viewport.rightAlignIds = idRightAlign.isSelected();
+    alignPanel.paintAlignment(true);
+  }
+
+  @Override
+  public void centreColumnLabels_actionPerformed(ActionEvent e)
+  {
+    viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
+    alignPanel.paintAlignment(true);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
+   */
+  @Override
+  protected void followHighlight_actionPerformed()
+  {
+    if (viewport.followHighlight = this.followHighlightMenuItem.getState())
+    {
+      alignPanel.scrollToPosition(
+              alignPanel.seqPanel.seqCanvas.searchResults, false);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void colourTextMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setColourText(colourTextMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void wrapMenuItem_actionPerformed(ActionEvent e)
+  {
+    scaleAbove.setVisible(wrapMenuItem.isSelected());
+    scaleLeft.setVisible(wrapMenuItem.isSelected());
+    scaleRight.setVisible(wrapMenuItem.isSelected());
+    viewport.setWrapAlignment(wrapMenuItem.isSelected());
+    alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
+  }
+
+  @Override
+  public void showAllSeqs_actionPerformed(ActionEvent e)
+  {
+    viewport.showAllHiddenSeqs();
+  }
+
+  @Override
+  public void showAllColumns_actionPerformed(ActionEvent e)
+  {
+    viewport.showAllHiddenColumns();
+    repaint();
+  }
+
+  @Override
+  public void hideSelSequences_actionPerformed(ActionEvent e)
+  {
+    viewport.hideAllSelectedSeqs();
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * called by key handler and the hide all/show all menu items
+   * 
+   * @param toggleSeqs
+   * @param toggleCols
+   */
+  private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
+  {
+
+    boolean hide = false;
+    SequenceGroup sg = viewport.getSelectionGroup();
+    if (!toggleSeqs && !toggleCols)
+    {
+      // 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)
+              || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
+                      .getEndRes()))
+      {
+        // now invert the sequence set, if required - empty selection implies
+        // that no hiding is required.
+        if (sg != null)
+        {
+          invertSequenceMenuItem_actionPerformed(null);
+          sg = viewport.getSelectionGroup();
+          toggleSeqs = true;
+
+        }
+        viewport.expandColSelection(sg, true);
+        // finally invert the column selection and get the new sequence
+        // selection.
+        invertColSel_actionPerformed(null);
+        toggleCols = true;
+      }
+    }
+
+    if (toggleSeqs)
+    {
+      if (sg != null && sg.getSize() != viewport.getAlignment().getHeight())
+      {
+        hideSelSequences_actionPerformed(null);
+        hide = true;
+      }
+      else if (!(toggleCols && viewport.getColumnSelection().getSelected()
+              .size() > 0))
+      {
+        showAllSeqs_actionPerformed(null);
+      }
+    }
+
+    if (toggleCols)
+    {
+      if (viewport.getColumnSelection().getSelected().size() > 0)
+      {
+        hideSelColumns_actionPerformed(null);
+        if (!toggleSeqs)
+        {
+          viewport.setSelectionGroup(sg);
+        }
+      }
+      else if (!hide)
+      {
+        showAllColumns_actionPerformed(null);
+      }
+    }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
+   * event.ActionEvent)
+   */
+  @Override
+  public void hideAllButSelection_actionPerformed(ActionEvent e)
+  {
+    toggleHiddenRegions(false, false);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
+   * .ActionEvent)
+   */
+  @Override
+  public void hideAllSelection_actionPerformed(ActionEvent e)
+  {
+    SequenceGroup sg = viewport.getSelectionGroup();
+    viewport.expandColSelection(sg, false);
+    viewport.hideAllSelectedSeqs();
+    viewport.hideSelectedColumns();
+    alignPanel.paintAlignment(true);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
+   * ActionEvent)
+   */
+  @Override
+  public void showAllhidden_actionPerformed(ActionEvent e)
+  {
+    viewport.showAllHiddenColumns();
+    viewport.showAllHiddenSeqs();
+    alignPanel.paintAlignment(true);
+  }
+
+  @Override
+  public void hideSelColumns_actionPerformed(ActionEvent e)
+  {
+    viewport.hideSelectedColumns();
+    alignPanel.paintAlignment(true);
+  }
+
+  @Override
+  public void hiddenMarkers_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
+    repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void scaleAbove_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleAboveWrapped(scaleAbove.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void scaleLeft_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleLeftWrapped(scaleLeft.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void scaleRight_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleRightWrapped(scaleRight.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void viewTextMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowText(viewTextMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setRenderGaps(renderGapsMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  public FeatureSettings featureSettings;
+
+  @Override
+  public void featureSettings_actionPerformed(ActionEvent e)
+  {
+    if (featureSettings != null)
+    {
+      featureSettings.close();
+      featureSettings = null;
+    }
+    if (!showSeqFeatures.isSelected())
+    {
+      // make sure features are actually displayed
+      showSeqFeatures.setSelected(true);
+      showSeqFeatures_actionPerformed(null);
+    }
+    featureSettings = new FeatureSettings(this);
+  }
+
+  /**
+   * Set or clear 'Show Sequence Features'
+   * 
+   * @param evt
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void showSeqFeatures_actionPerformed(ActionEvent evt)
+  {
+    viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
+    alignPanel.paintAlignment(true);
+    if (alignPanel.getOverviewPanel() != null)
+    {
+      alignPanel.getOverviewPanel().updateOverviewImage();
+    }
+  }
+
+  /**
+   * Set or clear 'Show Sequence Features'
+   * 
+   * @param evt
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
+  {
+    viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
+            .isSelected());
+    if (viewport.getShowSequenceFeaturesHeight())
+    {
+      // 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.
+   * 
+   * The options to show/hide all annotations should be enabled when the panel
+   * is shown, and disabled when the panel is hidden.
+   * 
+   * @param e
+   */
+  @Override
+  public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
+  {
+    final boolean setVisible = annotationPanelMenuItem.isSelected();
+    viewport.setShowAnnotation(setVisible);
+    alignPanel.setAnnotationVisible(setVisible);
+    this.showAllSeqAnnotations.setEnabled(setVisible);
+    this.hideAllSeqAnnotations.setEnabled(setVisible);
+    this.showAllAlAnnotations.setEnabled(setVisible);
+    this.hideAllAlAnnotations.setEnabled(setVisible);
+  }
+
+  @Override
+  public void alignmentProperties()
+  {
+    JEditorPane editPane = new JEditorPane("text/html", "");
+    editPane.setEditable(false);
+    StringBuffer contents = new AlignmentProperties(viewport.getAlignment())
+            .formatAsHtml();
+    editPane.setText(MessageManager.formatMessage("label.html_content",
+            new String[]
+            { contents.toString() }));
+    JInternalFrame frame = new JInternalFrame();
+    frame.getContentPane().add(new JScrollPane(editPane));
+
+    Desktop.instance.addInternalFrame(frame, MessageManager.formatMessage(
+            "label.alignment_properties", new String[]
+            { getTitle() }), 500, 400);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void overviewMenuItem_actionPerformed(ActionEvent e)
+  {
+    if (alignPanel.overviewPanel != null)
+    {
+      return;
+    }
+
+    JInternalFrame frame = new JInternalFrame();
+    OverviewPanel overview = new OverviewPanel(alignPanel);
+    frame.setContentPane(overview);
+    Desktop.addInternalFrame(frame, MessageManager.formatMessage(
+            "label.overview_params", new String[]
+            { this.getTitle() }), frame.getWidth(), frame.getHeight());
+    frame.pack();
+    frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+    {
+      @Override
+      public void internalFrameClosed(
+              javax.swing.event.InternalFrameEvent evt)
+      {
+        alignPanel.setOverviewPanel(null);
+      };
+    });
+
+    alignPanel.setOverviewPanel(overview);
+  }
+
+  @Override
+  public void textColour_actionPerformed(ActionEvent e)
+  {
+    new TextColourChooser().chooseColour(alignPanel, null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void noColourmenuItem_actionPerformed(ActionEvent e)
+  {
+    changeColour(null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void clustalColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new ClustalxColourScheme(viewport.getAlignment(),
+            viewport.getHiddenRepSequences()));
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void zappoColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new ZappoColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void taylorColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new TaylorColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void hydrophobicityColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new HydrophobicColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void helixColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new HelixColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void strandColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new StrandColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void turnColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new TurnColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void buriedColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new BuriedColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void nucleotideColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new NucleotideColourScheme());
+  }
+
+  @Override
+  public void purinePyrimidineColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new PurinePyrimidineColourScheme());
+  }
+
+  /*
+   * public void covariationColour_actionPerformed(ActionEvent e) {
+   * changeColour(new
+   * CovariationColourScheme(viewport.getAlignment().getAlignmentAnnotation
+   * ()[0])); }
+   */
+  @Override
+  public void annotationColour_actionPerformed(ActionEvent e)
+  {
+    new AnnotationColourChooser(viewport, alignPanel);
+  }
+
+  @Override
+  public void rnahelicesColour_actionPerformed(ActionEvent e)
+  {
+    new RNAHelicesColourChooser(viewport, alignPanel);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void applyToAllGroups_actionPerformed(ActionEvent e)
+  {
+    viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param cs
+   *          DOCUMENT ME!
+   */
+  public void changeColour(ColourSchemeI cs)
+  {
+    // TODO: compare with applet and pull up to model method
+    int threshold = 0;
+
+    if (cs != null)
+    {
+      if (viewport.getAbovePIDThreshold())
+      {
+        threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
+                "Background");
+        cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
+      }
+      else
+      {
+        cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
+      }
+
+      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
+      {
+        cs.setConservation(null);
+      }
+
+      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.getIgnoreGapsConsensus());
+
+          sg.cs.setConsensus(AAFrequency.calculate(
+                  sg.getSequences(viewport.getHiddenRepSequences()),
+                  sg.getStartRes(), sg.getEndRes() + 1));
+        }
+        else
+        {
+          sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
+        }
+
+        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);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void modifyPID_actionPerformed(ActionEvent e)
+  {
+    if (viewport.getAbovePIDThreshold()
+            && viewport.getGlobalColourScheme() != null)
+    {
+      SliderPanel.setPIDSliderSource(alignPanel,
+              viewport.getGlobalColourScheme(), "Background");
+      SliderPanel.showPIDSlider();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void modifyConservation_actionPerformed(ActionEvent e)
+  {
+    if (viewport.getConservationSelected()
+            && viewport.getGlobalColourScheme() != null)
+    {
+      SliderPanel.setConservationSlider(alignPanel,
+              viewport.getGlobalColourScheme(), "Background");
+      SliderPanel.showConservationSlider();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void conservationMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setConservationSelected(conservationMenuItem.isSelected());
+
+    viewport.setAbovePIDThreshold(false);
+    abovePIDThreshold.setSelected(false);
+
+    changeColour(viewport.getGlobalColourScheme());
+
+    modifyConservation_actionPerformed(null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void abovePIDThreshold_actionPerformed(ActionEvent e)
+  {
+    viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
+
+    conservationMenuItem.setSelected(false);
+    viewport.setConservationSelected(false);
+
+    changeColour(viewport.getGlobalColourScheme());
+
+    modifyPID_actionPerformed(null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void userDefinedColour_actionPerformed(ActionEvent e)
+  {
+    if (e.getActionCommand().equals(
+            MessageManager.getString("action.user_defined")))
+    {
+      new UserDefinedColours(alignPanel, null);
+    }
+    else
+    {
+      UserColourScheme udc = (UserColourScheme) UserDefinedColours
+              .getUserColourSchemes().get(e.getActionCommand());
+
+      changeColour(udc);
+    }
+  }
+
+  public void updateUserColourMenu()
+  {
+
+    Component[] menuItems = colourMenu.getMenuComponents();
+    int i, iSize = menuItems.length;
+    for (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!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void PIDColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new PIDColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void BLOSUM62Colour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new Blosum62ColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
+            .getAlignment().getSequenceAt(0), null);
+    addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void sortIDMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByID(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("ID Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void sortLengthMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByLength(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Length Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void sortGroupMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByGroup(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.getAlignment()));
+
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
+  {
+    new RedundancyPanel(alignPanel, this);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
+  {
+    if ((viewport.getSelectionGroup() == null)
+            || (viewport.getSelectionGroup().getSize() < 2))
+    {
+      JOptionPane.showInternalMessageDialog(this, MessageManager
+              .getString("label.you_must_select_least_two_sequences"),
+              MessageManager.getString("label.invalid_selection"),
+              JOptionPane.WARNING_MESSAGE);
+    }
+    else
+    {
+      JInternalFrame frame = new JInternalFrame();
+      frame.setContentPane(new PairwiseAlignPanel(viewport));
+      Desktop.addInternalFrame(frame,
+              MessageManager.getString("action.pairwise_alignment"), 600,
+              500);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void PCAMenuItem_actionPerformed(ActionEvent e)
+  {
+    if (((viewport.getSelectionGroup() != null)
+            && (viewport.getSelectionGroup().getSize() < 4) && (viewport
+            .getSelectionGroup().getSize() > 0))
+            || (viewport.getAlignment().getHeight() < 4))
+    {
+      JOptionPane
+              .showInternalMessageDialog(
+                      this,
+                      MessageManager
+                              .getString("label.principal_component_analysis_must_take_least_four_input_sequences"),
+                      MessageManager
+                              .getString("label.sequence_selection_insufficient"),
+                      JOptionPane.WARNING_MESSAGE);
+
+      return;
+    }
+
+    new PCAPanel(alignPanel);
+  }
+
+  @Override
+  public void autoCalculate_actionPerformed(ActionEvent e)
+  {
+    viewport.autoCalculateConsensus = autoCalculate.isSelected();
+    if (viewport.autoCalculateConsensus)
+    {
+      viewport.firePropertyChange("alignment", null, viewport
+              .getAlignment().getSequences());
+    }
+  }
+
+  @Override
+  public void sortByTreeOption_actionPerformed(ActionEvent e)
+  {
+    viewport.sortByTree = sortByTree.isSelected();
+  }
+
+  @Override
+  protected void listenToViewSelections_actionPerformed(ActionEvent e)
+  {
+    viewport.followSelection = listenToViewSelections.isSelected();
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
+  {
+    NewTreePanel("AV", "PID", "Average distance tree using PID");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
+  {
+    NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
+  {
+    NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
+  {
+    NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param type
+   *          DOCUMENT ME!
+   * @param pwType
+   *          DOCUMENT ME!
+   * @param title
+   *          DOCUMENT ME!
+   */
+  void NewTreePanel(String type, String pwType, String title)
+  {
+    TreePanel tp;
+
+    if (viewport.getSelectionGroup() != null
+            && viewport.getSelectionGroup().getSize() > 0)
+    {
+      if (viewport.getSelectionGroup().getSize() < 3)
+      {
+        JOptionPane
+                .showMessageDialog(
+                        Desktop.desktop,
+                        MessageManager
+                                .getString("label.you_need_more_two_sequences_selected_build_tree"),
+                        MessageManager
+                                .getString("label.not_enough_sequences"),
+                        JOptionPane.WARNING_MESSAGE);
+        return;
+      }
+
+      SequenceGroup sg = viewport.getSelectionGroup();
+
+      /* Decide if the selection is a column region */
+      for (SequenceI _s : sg.getSequences())
+      {
+        if (_s.getLength() < sg.getEndRes())
+        {
+          JOptionPane
+                  .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);
+
+          return;
+        }
+      }
+
+      title = title + " on region";
+      tp = new TreePanel(alignPanel, type, pwType);
+    }
+    else
+    {
+      // are the visible sequences aligned?
+      if (!viewport.getAlignment().isAligned(false))
+      {
+        JOptionPane
+                .showMessageDialog(
+                        Desktop.desktop,
+                        MessageManager
+                                .getString("label.sequences_must_be_aligned_before_creating_tree"),
+                        MessageManager
+                                .getString("label.sequences_not_aligned"),
+                        JOptionPane.WARNING_MESSAGE);
+
+        return;
+      }
+
+      if (viewport.getAlignment().getHeight() < 2)
+      {
+        return;
+      }
+
+      tp = new TreePanel(alignPanel, type, pwType);
+    }
+
+    title += " from ";
+
+    if (viewport.viewName != null)
+    {
+      title += viewport.viewName + " of ";
+    }
+
+    title += this.title;
+
+    Desktop.addInternalFrame(tp, title, 600, 500);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param title
+   *          DOCUMENT ME!
+   * @param order
+   *          DOCUMENT ME!
+   */
+  public void addSortByOrderMenuItem(String title,
+          final AlignmentOrder order)
+  {
+    final JMenuItem item = new JMenuItem(MessageManager.formatMessage("action.by_title_param", new String[]{title}));
+    sort.add(item);
+    item.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+
+        // TODO: JBPNote - have to map order entries to curent SequenceI
+        // pointers
+        AlignmentSorter.sortBy(viewport.getAlignment(), order);
+
+        addHistoryItem(new OrderCommand(order.getName(), oldOrder, viewport
+                .getAlignment()));
+
+        alignPanel.paintAlignment(true);
+      }
+    });
+  }
+
+  /**
+   * Add a new sort by annotation score menu item
+   * 
+   * @param sort
+   *          the menu to add the option to
+   * @param scoreLabel
+   *          the label used to retrieve scores for each sequence on the
+   *          alignment
+   */
+  public void addSortByAnnotScoreMenuItem(JMenu sort,
+          final String scoreLabel)
+  {
+    final JMenuItem item = new JMenuItem(scoreLabel);
+    sort.add(item);
+    item.addActionListener(new java.awt.event.ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+        AlignmentSorter.sortByAnnotationScore(scoreLabel,
+                viewport.getAlignment());// ,viewport.getSelectionGroup());
+        addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
+                viewport.getAlignment()));
+        alignPanel.paintAlignment(true);
+      }
+    });
+  }
+
+  /**
+   * last hash for alignment's annotation array - used to minimise cost of
+   * rebuild.
+   */
+  protected int _annotationScoreVectorHash;
+
+  /**
+   * search the alignment and rebuild the sort by annotation score submenu the
+   * last alignment annotation vector hash is stored to minimize cost of
+   * rebuilding in subsequence calls.
+   * 
+   */
+  @Override
+  public void buildSortByAnnotationScoresMenu()
+  {
+    if (viewport.getAlignment().getAlignmentAnnotation() == null)
+    {
+      return;
+    }
+
+    if (viewport.getAlignment().getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)
+    {
+      sortByAnnotScore.removeAll();
+      // almost certainly a quicker way to do this - but we keep it simple
+      Hashtable scoreSorts = new Hashtable();
+      AlignmentAnnotation aann[];
+      for (SequenceI sqa : viewport.getAlignment().getSequences())
+      {
+        aann = sqa.getAnnotation();
+        for (int i = 0; aann != null && i < aann.length; i++)
+        {
+          if (aann[i].hasScore() && aann[i].sequenceRef != null)
+          {
+            scoreSorts.put(aann[i].label, aann[i].label);
+          }
+        }
+      }
+      Enumeration labels = scoreSorts.keys();
+      while (labels.hasMoreElements())
+      {
+        addSortByAnnotScoreMenuItem(sortByAnnotScore,
+                (String) labels.nextElement());
+      }
+      sortByAnnotScore.setVisible(scoreSorts.size() > 0);
+      scoreSorts.clear();
+
+      _annotationScoreVectorHash = viewport.getAlignment()
+              .getAlignmentAnnotation().hashCode();
+    }
+  }
+
+  /**
+   * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
+   * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
+   * call. Listeners are added to remove the menu item when the treePanel is
+   * closed, and adjust the tree leaf to sequence mapping when the alignment is
+   * modified.
+   * 
+   * @param treePanel
+   *          Displayed tree window.
+   * @param title
+   *          SortBy menu item title.
+   */
+  @Override
+  public void buildTreeMenu()
+  {
+    calculateTree.removeAll();
+    // build the calculate menu
+
+    for (final String type : new String[]
+    { "NJ", "AV" })
+    {
+      String treecalcnm = MessageManager.getString("label.tree_calc_"
+              + type.toLowerCase());
+      for (final Object pwtype : ResidueProperties.scoreMatrices.keySet())
+      {
+        JMenuItem tm = new JMenuItem();
+        ScoreModelI sm = ResidueProperties.scoreMatrices.get(pwtype);
+        if (sm.isProtein() == !viewport.getAlignment().isNucleotide())
+        {
+          String smn = MessageManager.getStringOrReturn(
+                  "label.score_model_", sm.getName());
+          final String title = MessageManager.formatMessage(
+                  "label.treecalc_title", treecalcnm, smn);
+          tm.setText(title);//
+          tm.addActionListener(new java.awt.event.ActionListener()
+          {
+            @Override
+            public void actionPerformed(ActionEvent e)
+            {
+              NewTreePanel(type, (String) pwtype, title);
+            }
+          });
+          calculateTree.add(tm);
+        }
+
+      }
+    }
+    sortByTreeMenu.removeAll();
+
+    Vector comps = (Vector) PaintRefresher.components.get(viewport
+            .getSequenceSetId());
+    Vector treePanels = new Vector();
+    int i, iSize = comps.size();
+    for (i = 0; i < iSize; i++)
+    {
+      if (comps.elementAt(i) instanceof TreePanel)
+      {
+        treePanels.add(comps.elementAt(i));
+      }
+    }
+
+    iSize = treePanels.size();
+
+    if (iSize < 1)
+    {
+      sortByTreeMenu.setVisible(false);
+      return;
+    }
+
+    sortByTreeMenu.setVisible(true);
+
+    for (i = 0; i < treePanels.size(); i++)
+    {
+      final TreePanel tp = (TreePanel) treePanels.elementAt(i);
+      final JMenuItem item = new JMenuItem(tp.getTitle());
+      final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
+      item.addActionListener(new java.awt.event.ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          tp.sortByTree_actionPerformed(null);
+          addHistoryItem(tp.sortAlignmentIn(alignPanel));
+
+        }
+      });
+
+      sortByTreeMenu.add(item);
+    }
+  }
+
+  public boolean sortBy(AlignmentOrder alorder, String undoname)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
+    if (undoname != null)
+    {
+      addHistoryItem(new OrderCommand(undoname, oldOrder,
+              viewport.getAlignment()));
+    }
+    alignPanel.paintAlignment(true);
+    return true;
+  }
+
+  /**
+   * Work out whether the whole set of sequences or just the selected set will
+   * be submitted for multiple alignment.
+   * 
+   */
+  public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
+  {
+    // Now, check we have enough sequences
+    AlignmentView msa = null;
+
+    if ((viewport.getSelectionGroup() != null)
+            && (viewport.getSelectionGroup().getSize() > 1))
+    {
+      // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
+      // some common interface!
+      /*
+       * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
+       * SequenceI[sz = seqs.getSize(false)];
+       * 
+       * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)
+       * seqs.getSequenceAt(i); }
+       */
+      msa = viewport.getAlignmentView(true);
+    }
+    else if (viewport.getSelectionGroup() != null
+            && viewport.getSelectionGroup().getSize() == 1)
+    {
+      int option = JOptionPane.showConfirmDialog(this,
+              MessageManager.getString("warn.oneseq_msainput_selection"),
+              MessageManager.getString("label.invalid_selection"),
+              JOptionPane.OK_CANCEL_OPTION);
+      if (option == JOptionPane.OK_OPTION)
+      {
+        msa = viewport.getAlignmentView(false);
+      }
+    }
+    else
+    {
+      msa = viewport.getAlignmentView(false);
+    }
+    return msa;
+  }
+
+  /**
+   * Decides what is submitted to a secondary structure prediction service: the
+   * first sequence in the alignment, or in the current selection, or, if the
+   * alignment is 'aligned' (ie padded with gaps), then the currently selected
+   * region or the whole alignment. (where the first sequence in the set is the
+   * one that the prediction will be for).
+   */
+  public AlignmentView gatherSeqOrMsaForSecStrPrediction()
+  {
+    AlignmentView seqs = null;
+
+    if ((viewport.getSelectionGroup() != null)
+            && (viewport.getSelectionGroup().getSize() > 0))
+    {
+      seqs = viewport.getAlignmentView(true);
+    }
+    else
+    {
+      seqs = viewport.getAlignmentView(false);
+    }
+    // limit sequences - JBPNote in future - could spawn multiple prediction
+    // jobs
+    // TODO: viewport.getAlignment().isAligned is a global state - the local
+    // 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] });
+      // TODO: if seqs.getSequences().length>1 then should really have warned
+      // user!
+
+    }
+    return seqs;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *          DOCUMENT ME!
+   */
+  @Override
+  protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
+  {
+    // Pick the tree file
+    JalviewFileChooser chooser = new JalviewFileChooser(
+            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+    chooser.setFileView(new JalviewFileView());
+    chooser.setDialogTitle(MessageManager
+            .getString("label.select_newick_like_tree_file"));
+    chooser.setToolTipText(MessageManager.getString("label.load_tree_file"));
+
+    int value = chooser.showOpenDialog(null);
+
+    if (value == JalviewFileChooser.APPROVE_OPTION)
+    {
+      String choice = chooser.getSelectedFile().getPath();
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
+      jalview.io.NewickFile fin = null;
+      try
+      {
+        fin = new jalview.io.NewickFile(choice, "File");
+        viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
+      } catch (Exception ex)
+      {
+        JOptionPane
+                .showMessageDialog(
+                        Desktop.desktop,
+                        ex.getMessage(),
+                        MessageManager
+                                .getString("label.problem_reading_tree_file"),
+                        JOptionPane.WARNING_MESSAGE);
+        ex.printStackTrace();
+      }
+      if (fin != null && fin.hasWarningMessage())
+      {
+        JOptionPane.showMessageDialog(Desktop.desktop, fin
+                .getWarningMessage(), MessageManager
+                .getString("label.possible_problem_with_tree_file"),
+                JOptionPane.WARNING_MESSAGE);
+      }
+    }
+  }
+
+  @Override
+  protected void tcoffeeColorScheme_actionPerformed(ActionEvent e)
+  {
+    changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
+  }
+
+  public TreePanel ShowNewickTree(NewickFile nf, String title)
+  {
+    return ShowNewickTree(nf, title, 600, 500, 4, 5);
+  }
+
+  public TreePanel ShowNewickTree(NewickFile nf, String title,
+          AlignmentView input)
+  {
+    return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
+  }
+
+  public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
+          int h, int x, int y)
+  {
+    return ShowNewickTree(nf, title, null, w, h, x, y);
+  }
+
+  /**
+   * Add a treeviewer for the tree extracted from a newick file object to the
+   * current alignment view
+   * 
+   * @param nf
+   *          the tree
+   * @param title
+   *          tree viewer title
+   * @param input
+   *          Associated alignment input data (or null)
+   * @param w
+   *          width
+   * @param h
+   *          height
+   * @param x
+   *          position
+   * @param y
+   *          position
+   * @return TreePanel handle
+   */
+  public TreePanel ShowNewickTree(NewickFile nf, String title,
+          AlignmentView input, int w, int h, int x, int y)
+  {
+    TreePanel tp = null;
+
+    try
+    {
+      nf.parse();
+
+      if (nf.getTree() != null)
+      {
+        tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
+
+        tp.setSize(w, h);
+
+        if (x > 0 && y > 0)
+        {
+          tp.setLocation(x, y);
+        }
+
+        Desktop.addInternalFrame(tp, title, w, h);
+      }
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+
+    return tp;
+  }
+
+  private boolean buildingMenu = false;
+
+  /**
+   * Generates menu items and listener event actions for web service clients
+   * 
+   */
+  public void BuildWebServiceMenu()
+  {
+    while (buildingMenu)
+    {
+      try
+      {
+        System.err.println("Waiting for building menu to finish.");
+        Thread.sleep(10);
+      } catch (Exception e)
+      {
+      }
+      ;
+    }
+    final AlignFrame me = this;
+    buildingMenu = true;
+    new Thread(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        final List<JMenuItem> legacyItems = new ArrayList<JMenuItem>();
+        try
+        {
+          System.err.println("Building ws menu again "
+                  + Thread.currentThread());
+          // TODO: add support for context dependent disabling of services based
+          // on
+          // alignment and current selection
+          // TODO: add additional serviceHandle parameter to specify abstract
+          // handler
+          // class independently of AbstractName
+          // TODO: add in rediscovery GUI function to restart discoverer
+          // TODO: group services by location as well as function and/or
+          // introduce
+          // object broker mechanism.
+          final Vector<JMenu> wsmenu = new Vector<JMenu>();
+          final IProgressIndicator af = me;
+          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)
+              // &&
+          Discoverer.services != null && (Discoverer.services.size() > 0))
+          {
+            // TODO: refactor to allow list of AbstractName/Handler bindings to
+            // be
+            // stored or retrieved from elsewhere
+            // No MSAWS used any more:
+            // Vector msaws = null; // (Vector)
+            // Discoverer.services.get("MsaWS");
+            Vector secstrpr = (Vector) Discoverer.services
+                    .get("SecStrPred");
+            if (secstrpr != null)
+            {
+              // Add any secondary structure prediction services
+              for (int i = 0, j = secstrpr.size(); i < j; i++)
+              {
+                final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
+                        .get(i);
+                jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
+                        .getServiceClient(sh);
+                int p = secstrmenu.getItemCount();
+                impl.attachWSMenuEntry(secstrmenu, me);
+                int q = secstrmenu.getItemCount();
+                for (int litm = p; litm < q; litm++)
+                {
+                  legacyItems.add(secstrmenu.getItem(litm));
+                }
+              }
+            }
+          }
+
+          // Add all submenus in the order they should appear on the web
+          // services menu
+          wsmenu.add(msawsmenu);
+          wsmenu.add(secstrmenu);
+          wsmenu.add(dismenu);
+          wsmenu.add(analymenu);
+          // No search services yet
+          // wsmenu.add(seqsrchmenu);
+
+          javax.swing.SwingUtilities.invokeLater(new Runnable()
+          {
+            @Override
+            public void run()
+            {
+              try
+              {
+                webService.removeAll();
+                // first, add discovered services onto the webservices menu
+                if (wsmenu.size() > 0)
+                {
+                  for (int i = 0, j = wsmenu.size(); i < j; i++)
+                  {
+                    webService.add(wsmenu.get(i));
+                  }
+                }
+                else
+                {
+                  webService.add(me.webServiceNoServices);
+                }
+                // TODO: move into separate menu builder class.
+                boolean new_sspred = false;
+                if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
+                {
+                  Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
+                  if (jws2servs != null)
+                  {
+                    if (jws2servs.hasServices())
+                    {
+                      jws2servs.attachWSMenuEntry(webService, me);
+                      for (Jws2Instance sv : jws2servs.getServices())
+                      {
+                        if (sv.description.toLowerCase().contains("jpred"))
+                        {
+                          for (JMenuItem jmi : legacyItems)
+                          {
+                            jmi.setVisible(false);
+                          }
+                        }
+                      }
+
+                    }
+                    if (jws2servs.isRunning())
+                    {
+                      JMenuItem tm = new JMenuItem(
+                              "Still discovering JABA Services");
+                      tm.setEnabled(false);
+                      webService.add(tm);
+                    }
+                  }
+                }
+                build_urlServiceMenu(me.webService);
+                build_fetchdbmenu(webService);
+                for (JMenu item : wsmenu)
+                {
+                  if (item.getItemCount() == 0)
+                  {
+                    item.setEnabled(false);
+                  }
+                  else
+                  {
+                    item.setEnabled(true);
+                  }
+                }
+              } catch (Exception e)
+              {
+                Cache.log
+                        .debug("Exception during web service menu building process.",
+                                e);
+              }
+              ;
+            }
+          });
+        } catch (Exception e)
+        {
+        }
+        ;
+
+        buildingMenu = false;
+      }
+    }).start();
+
+  }
+
+  /**
+   * construct any groupURL type service menu entries.
+   * 
+   * @param webService
+   */
+  private void build_urlServiceMenu(JMenu webService)
+  {
+    // TODO: remove this code when 2.7 is released
+    // DEBUG - alignmentView
+    /*
+     * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final
+     * AlignFrame af = this; testAlView.addActionListener(new ActionListener() {
+     * 
+     * @Override public void actionPerformed(ActionEvent e) {
+     * jalview.datamodel.AlignmentView
+     * .testSelectionViews(af.viewport.getAlignment(),
+     * af.viewport.getColumnSelection(), af.viewport.selectionGroup); }
+     * 
+     * }); webService.add(testAlView);
+     */
+    // TODO: refactor to RestClient discoverer and merge menu entries for
+    // rest-style services with other types of analysis/calculation service
+    // SHmmr test client - still being implemented.
+    // DEBUG - alignmentView
+
+    for (jalview.ws.rest.RestClient client : jalview.ws.rest.RestClient
+            .getRestClients())
+    {
+      client.attachWSMenuEntry(
+              JvSwingUtils.findOrCreateMenu(webService, client.getAction()),
+              this);
+    }
+  }
+
+  /*
+   * 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
+   * 
+   */
+  protected void setShowProductsEnabled()
+  {
+    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)
+  {
+    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]);
+        xtype.addActionListener(new ActionListener()
+        {
+
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            // TODO: new thread for this call with vis-delay
+            af.showProductsFor(af.viewport.getSequenceSelection(), ds,
+                    isRegSel, dna, source);
+          }
+
+        });
+        showProducts.add(xtype);
+      }
+      showProducts.setVisible(showp);
+      showProducts.setEnabled(showp);
+    } catch (Exception e)
+    {
+      jalview.bin.Cache.log
+              .warn("canTranslate threw an exception - please report to help@jalview.org",
+                      e);
+      return false;
+    }
+    return showp;
+  }
+
+  protected void showProductsFor(SequenceI[] sel, Alignment ds,
+          boolean isRegSel, boolean dna, String source)
+  {
+    final boolean fisRegSel = isRegSel;
+    final boolean fdna = dna;
+    final String fsrc = source;
+    final AlignFrame ths = this;
+    final SequenceI[] fsel = sel;
+    Runnable foo = new Runnable()
+    {
+
+      @Override
+      public void run()
+      {
+        final long sttime = System.currentTimeMillis();
+        ths.setProgressBar(MessageManager.formatMessage("status.searching_for_sequences_from", new String[]{fsrc}), sttime);
+        try
+        {
+          Alignment ds = ths.getViewport().getAlignment().getDataset(); // update
+          // our local
+          // dataset
+          // reference
+          Alignment prods = CrossRef
+                  .findXrefSequences(fsel, fdna, fsrc, ds);
+          if (prods != null)
+          {
+            SequenceI[] sprods = new SequenceI[prods.getHeight()];
+            for (int s = 0; s < sprods.length; s++)
+            {
+              sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
+              if (ds.getSequences() == null
+                      || !ds.getSequences().contains(
+                              sprods[s].getDatasetSequence()))
+              {
+                ds.addSequence(sprods[s].getDatasetSequence());
+              }
+              sprods[s].updatePDBIds();
+            }
+            Alignment al = new Alignment(sprods);
+            AlignedCodonFrame[] cf = prods.getCodonFrames();
+            al.setDataset(ds);
+            for (int s = 0; cf != null && s < cf.length; s++)
+            {
+              al.addCodonFrame(cf[s]);
+              cf[s] = null;
+            }
+            AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
+                    DEFAULT_HEIGHT);
+            String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
+                    + " for " + ((fisRegSel) ? "selected region of " : "")
+                    + getTitle();
+            Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
+                    DEFAULT_HEIGHT);
+          }
+          else
+          {
+            System.err.println("No Sequences generated for xRef type "
+                    + fsrc);
+          }
+        } catch (Exception e)
+        {
+          jalview.bin.Cache.log.error(
+                  "Exception when finding crossreferences", e);
+        } catch (OutOfMemoryError e)
+        {
+          new OOMWarning("whilst fetching crossreferences", e);
+        } catch (Error e)
+        {
+          jalview.bin.Cache.log.error("Error when finding crossreferences",
+                  e);
+        }
+        ths.setProgressBar(MessageManager.formatMessage("status.finished_searching_for_sequences_from", new String[]{fsrc}),
+                sttime);
+      }
+
+    };
+    Thread frunner = new Thread(foo);
+    frunner.start();
+  }
+
+  public boolean canShowTranslationProducts(SequenceI[] selection,
+          AlignmentI alignment)
+  {
+    // old way
+    try
+    {
+      return (jalview.analysis.Dna.canTranslate(selection,
+              viewport.getViewAsVisibleContigs(true)));
+    } catch (Exception e)
+    {
+      jalview.bin.Cache.log
+              .warn("canTranslate threw an exception - please report to help@jalview.org",
+                      e);
+      return false;
+    }
+  }
+
+  @Override
+  public void showProducts_actionPerformed(ActionEvent e)
+  {
+    // /////////////////////////////
+    // Collect Data to be translated/transferred
+
+    SequenceI[] selection = viewport.getSequenceSelection();
+    AlignmentI al = null;
+    try
+    {
+      al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
+              .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
+              viewport.getAlignment().getDataset());
+    } catch (Exception ex)
+    {
+      al = null;
+      jalview.bin.Cache.log.debug("Exception during translation.", ex);
+    }
+    if (al == null)
+    {
+      JOptionPane
+              .showMessageDialog(
+                      Desktop.desktop,
+                      MessageManager
+                              .getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"),
+                      MessageManager.getString("label.translation_failed"),
+                      JOptionPane.WARNING_MESSAGE);
+    }
+    else
+    {
+      AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+      Desktop.addInternalFrame(af, MessageManager.formatMessage(
+              "label.translation_of_params", new String[]
+              { this.getTitle() }), DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    }
+  }
+
+  @Override
+  public void showTranslation_actionPerformed(ActionEvent e)
+  {
+    // /////////////////////////////
+    // Collect Data to be translated/transferred
+
+    SequenceI[] selection = viewport.getSequenceSelection();
+    String[] seqstring = viewport.getViewAsString(true);
+    AlignmentI al = null;
+    try
+    {
+      al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
+              viewport.getViewAsVisibleContigs(true), viewport
+                      .getGapCharacter(), viewport.getAlignment()
+                      .getAlignmentAnnotation(), viewport.getAlignment()
+                      .getWidth(), viewport.getAlignment().getDataset());
+    } catch (Exception ex)
+    {
+      al = null;
+      jalview.bin.Cache.log.error(
+              "Exception during translation. Please report this !", ex);
+      JOptionPane
+              .showMessageDialog(
+                      Desktop.desktop,
+                      MessageManager
+                              .getString("label.error_when_translating_sequences_submit_bug_report"),
+                      MessageManager
+                              .getString("label.implementation_error")
+                              + MessageManager
+                                      .getString("translation_failed"),
+                      JOptionPane.ERROR_MESSAGE);
+      return;
+    }
+    if (al == null)
+    {
+      JOptionPane
+              .showMessageDialog(
+                      Desktop.desktop,
+                      MessageManager
+                              .getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation"),
+                      MessageManager.getString("label.translation_failed"),
+                      JOptionPane.WARNING_MESSAGE);
+    }
+    else
+    {
+      AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+      Desktop.addInternalFrame(af, MessageManager.formatMessage(
+              "label.translation_of_params", new String[]
+              { this.getTitle() }), DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    }
+  }
+
+  /**
+   * Try to load a features file onto the alignment.
+   * 
+   * @param file
+   *          contents or path to retrieve file
+   * @param type
+   *          access mode of file (see jalview.io.AlignFile)
+   * @return true if features file was parsed corectly.
+   */
+  public boolean parseFeaturesFile(String file, String type)
+  {
+    boolean featuresFile = false;
+    try
+    {
+      featuresFile = new FeaturesFile(file, type).parse(viewport
+              .getAlignment().getDataset(), alignPanel.seqPanel.seqCanvas
+              .getFeatureRenderer().featureColours, false,
+              jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+
+    if (featuresFile)
+    {
+      viewport.showSequenceFeatures = true;
+      showSeqFeatures.setSelected(true);
+      if (alignPanel.seqPanel.seqCanvas.fr != null)
+      {
+        // update the min/max ranges where necessary
+        alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
+      }
+      if (featureSettings != null)
+      {
+        featureSettings.setTableData();
+      }
+      alignPanel.paintAlignment(true);
+    }
+
+    return featuresFile;
+  }
+
+  @Override
+  public void dragEnter(DropTargetDragEvent evt)
+  {
+  }
+
+  @Override
+  public void dragExit(DropTargetEvent evt)
+  {
+  }
+
+  @Override
+  public void dragOver(DropTargetDragEvent evt)
+  {
+  }
+
+  @Override
+  public void dropActionChanged(DropTargetDragEvent evt)
+  {
+  }
+
+  @Override
+  public void drop(DropTargetDropEvent evt)
+  {
+    Transferable t = evt.getTransferable();
+    java.util.List files = null;
+
+    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());
+          }
+        }
+      }
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    if (files != null)
+    {
+      try
+      {
+        // check to see if any of these files have names matching sequences in
+        // the alignment
+        SequenceIdMatcher idm = new SequenceIdMatcher(viewport
+                .getAlignment().getSequencesArray());
+        /**
+         * Object[] { String,SequenceI}
+         */
+        ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
+        ArrayList<String> filesnotmatched = new ArrayList<String>();
+        for (int i = 0; i < files.size(); i++)
+        {
+          String file = files.get(i).toString();
+          String pdbfn = "";
+          String protocol = FormatAdapter.checkProtocol(file);
+          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();
+          }
+          if (pdbfn.length() > 0)
+          {
+            // attempt to find a match in the alignment
+            SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
+            int l = 0, c = pdbfn.indexOf(".");
+            while (mtch == null && c != -1)
+            {
+              do
+              {
+                l = c;
+              } while ((c = pdbfn.indexOf(".", l)) > l);
+              if (l > -1)
+              {
+                pdbfn = pdbfn.substring(0, l);
+              }
+              mtch = idm.findAllIdMatches(pdbfn);
+            }
+            if (mtch != null)
+            {
+              String type = null;
+              try
+              {
+                type = new IdentifyFile().Identify(file, protocol);
+              } catch (Exception ex)
+              {
+                type = null;
+              }
+              if (type != null)
+              {
+                if (type.equalsIgnoreCase("PDB"))
+                {
+                  filesmatched.add(new Object[]
+                  { file, protocol, mtch });
+                  continue;
+                }
+              }
+            }
+            // File wasn't named like one of the sequences or wasn't a PDB file.
+            filesnotmatched.add(file);
+          }
+        }
+        int assocfiles = 0;
+        if (filesmatched.size() > 0)
+        {
+          if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
+                  || JOptionPane
+                          .showConfirmDialog(
+                                  this,
+                                  MessageManager
+                                          .formatMessage(
+                                                  "label.automatically_associate_pdb_files_with_sequences_same_name",
+                                                  new String[]
+                                                  { Integer.valueOf(
+                                                          filesmatched
+                                                                  .size())
+                                                          .toString() }),
+                                  MessageManager
+                                          .getString("label.automatically_associate_pdb_files_by_name"),
+                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
+
+          {
+            for (Object[] fm : filesmatched)
+            {
+              // try and associate
+              // TODO: may want to set a standard ID naming formalism for
+              // associating PDB files which have no IDs.
+              for (SequenceI toassoc : (SequenceI[]) fm[2])
+              {
+                PDBEntry pe = new AssociatePdbFileWithSeq()
+                        .associatePdbWithSeq((String) fm[0],
+                                (String) fm[1], toassoc, false,
+                                Desktop.instance);
+                if (pe != null)
+                {
+                  System.err.println("Associated file : "
+                          + ((String) fm[0]) + " with "
+                          + toassoc.getDisplayId(true));
+                  assocfiles++;
+                }
+              }
+              alignPanel.paintAlignment(true);
+            }
+          }
+        }
+        if (filesnotmatched.size() > 0)
+        {
+          if (assocfiles > 0
+                  && (Cache.getDefault(
+                          "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
+                          .showConfirmDialog(
+                                  this,
+                                  "<html>"+MessageManager
+                                          .formatMessage(
+                                                  "label.ignore_unmatched_dropped_files_info",
+                                                  new String[]
+                                                  { Integer.valueOf(
+                                                          filesnotmatched
+                                                                  .size())
+                                                          .toString() })+"</html>",
+                                  MessageManager
+                                          .getString("label.ignore_unmatched_dropped_files"),
+                                  JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
+          {
+            return;
+          }
+          for (String fn : filesnotmatched)
+          {
+            loadJalviewDataFile(fn, null, null, null);
+          }
+
+        }
+      } catch (Exception ex)
+      {
+        ex.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * 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
+   * all are false then the user may have dropped an alignment file onto this
+   * AlignFrame.
+   * 
+   * @param file
+   *          either a filename or a URL string.
+   */
+  public void loadJalviewDataFile(String file, String protocol,
+          String format, SequenceI assocSeq)
+  {
+    try
+    {
+      if (protocol == null)
+      {
+        protocol = jalview.io.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()
+              .readAnnotationFile(viewport.getAlignment(), file, protocol)
+              : false;
+
+      if (!isAnnotation)
+      {
+        // first see if its a T-COFFEE score file
+        TCoffeeScoreFile tcf = null;
+        try
+        {
+          tcf = new TCoffeeScoreFile(file, protocol);
+          if (tcf.isValid())
+          {
+            if (tcf.annotateAlignment(viewport.getAlignment(), true))
+            {
+              tcoffeeColour.setEnabled(true);
+              tcoffeeColour.setSelected(true);
+              changeColour(new TCoffeeColourScheme(viewport.getAlignment()));
+              isAnnotation = true;
+              statusBar
+                      .setText(MessageManager
+                              .getString("label.successfully_pasted_tcoffee_scores_to_alignment"));
+            }
+            else
+            {
+              // some problem - if no warning its probable that the ID matching
+              // process didn't work
+              JOptionPane
+                      .showMessageDialog(
+                              Desktop.desktop,
+                              tcf.getWarningMessage() == null ? MessageManager
+                                      .getString("label.check_file_matches_sequence_ids_alignment")
+                                      : tcf.getWarningMessage(),
+                              MessageManager
+                                      .getString("label.problem_reading_tcoffee_score_file"),
+                              JOptionPane.WARNING_MESSAGE);
+            }
+          }
+          else
+          {
+            tcf = null;
+          }
+        } catch (Exception x)
+        {
+          Cache.log
+                  .debug("Exception when processing data source as T-COFFEE score file",
+                          x);
+          tcf = null;
+        }
+        if (tcf == null)
+        {
+          // try to see if its a JNet 'concise' style annotation file *before*
+          // we
+          // try to parse it as a features file
+          if (format == null)
+          {
+            format = new IdentifyFile().Identify(file, protocol);
+          }
+          if (format.equalsIgnoreCase("JnetFile"))
+          {
+            jalview.io.JPredFile predictions = new jalview.io.JPredFile(
+                    file, protocol);
+            new JnetAnnotationMaker().add_annotation(predictions,
+                    viewport.getAlignment(), 0, false);
+            isAnnotation = true;
+          }
+          else
+          {
+            /*
+             * 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
+            {
+              alignPanel.paintAlignment(true);
+            }
+          }
+        }
+      }
+      if (isAnnotation)
+      {
+
+        alignPanel.adjustAnnotationHeight();
+        viewport.updateSequenceIdColours();
+        buildSortByAnnotationScoresMenu();
+        alignPanel.paintAlignment(true);
+      }
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    } catch (OutOfMemoryError oom)
+    {
+      try
+      {
+        System.gc();
+      } catch (Exception x)
+      {
+      }
+      ;
+      new OOMWarning(
+              "loading data "
+                      + (protocol != null ? (protocol.equals(FormatAdapter.PASTE) ? "from clipboard."
+                              : "using " + protocol + " from " + file)
+                              : ".")
+                      + (format != null ? "(parsing as '" + format
+                              + "' file)" : ""), oom, Desktop.desktop);
+    }
+  }
+
+  @Override
+  public void tabSelectionChanged(int index)
+  {
+    if (index > -1)
+    {
+      alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
+      viewport = alignPanel.av;
+      avc.setViewportAndAlignmentPanel(viewport, alignPanel);
+      setMenusFromViewport(viewport);
+    }
+  }
+
+  @Override
+  public void tabbedPane_mousePressed(MouseEvent e)
+  {
+    if (SwingUtilities.isRightMouseButton(e))
+    {
+      String reply = JOptionPane.showInternalInputDialog(this,
+              MessageManager.getString("label.enter_view_name"),
+              MessageManager.getString("label.enter_view_name"),
+              JOptionPane.QUESTION_MESSAGE);
+
+      if (reply != null)
+      {
+        viewport.viewName = reply;
+        tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
+      }
+    }
+  }
+
+  public AlignViewport getCurrentView()
+  {
+    return viewport;
+  }
+
+  /**
+   * Open the dialog for regex description parsing.
+   */
+  @Override
+  protected void extractScores_actionPerformed(ActionEvent e)
+  {
+    ParseProperties pp = new jalview.analysis.ParseProperties(
+            viewport.getAlignment());
+    // TODO: verify regex and introduce GUI dialog for version 2.5
+    // if (pp.getScoresFromDescription("col", "score column ",
+    // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
+    // true)>0)
+    if (pp.getScoresFromDescription("description column",
+            "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
+    {
+      buildSortByAnnotationScoresMenu();
+    }
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
+   * )
+   */
+  @Override
+  protected void showDbRefs_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
+   * ActionEvent)
+   */
+  @Override
+  protected void showNpFeats_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
+  }
+
+  /**
+   * find the viewport amongst the tabs in this alignment frame and close that
+   * tab
+   * 
+   * @param av
+   */
+  public boolean closeView(AlignViewport av)
+  {
+    if (viewport == av)
+    {
+      this.closeMenuItem_actionPerformed(false);
+      return true;
+    }
+    Component[] comp = tabbedPane.getComponents();
+    for (int i = 0; comp != null && i < comp.length; i++)
+    {
+      if (comp[i] instanceof AlignmentPanel)
+      {
+        if (((AlignmentPanel) comp[i]).av == av)
+        {
+          // close the view.
+          closeView((AlignmentPanel) comp[i]);
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  protected void build_fetchdbmenu(JMenu webService)
+  {
+    // Temporary hack - DBRef Fetcher always top level ws entry.
+    // TODO We probably want to store a sequence database checklist in
+    // preferences and have checkboxes.. rather than individual sources selected
+    // here
+    final JMenu rfetch = new JMenu(
+            MessageManager.getString("action.fetch_db_references"));
+    rfetch.setToolTipText(MessageManager
+            .getString("label.retrieve_parse_sequence_database_records_alignment_or_selected_sequences"));
+    webService.add(rfetch);
+
+    final JCheckBoxMenuItem trimrs = new JCheckBoxMenuItem(
+            MessageManager.getString("option.trim_retrieved_seqs"));
+    trimrs.setToolTipText(MessageManager
+            .getString("label.trim_retrieved_sequences"));
+    trimrs.setSelected(Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true));
+    trimrs.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        trimrs.setSelected(trimrs.isSelected());
+        Cache.setProperty("TRIM_FETCHED_DATASET_SEQS",
+                Boolean.valueOf(trimrs.isSelected()).toString());
+      };
+    });
+    rfetch.add(trimrs);
+    JMenuItem fetchr = new JMenuItem(
+            MessageManager.getString("label.standard_databases"));
+    fetchr.setToolTipText(MessageManager
+            .getString("label.fetch_embl_uniprot"));
+    fetchr.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        new Thread(new Runnable()
+        {
+
+          @Override
+          public void run()
+          {
+            new jalview.ws.DBRefFetcher(alignPanel.av
+                    .getSequenceSelection(), alignPanel.alignFrame)
+                    .fetchDBRefs(false);
+          }
+        }).start();
+
+      }
+
+    });
+    rfetch.add(fetchr);
+    final AlignFrame me = this;
+    new Thread(new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        final jalview.ws.SequenceFetcher sf = SequenceFetcher
+                .getSequenceFetcherSingleton(me);
+        javax.swing.SwingUtilities.invokeLater(new Runnable()
+        {
+          @Override
+          public void run()
+          {
+            String[] dbclasses = sf.getOrderedSupportedSources();
+            // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
+            // jalview.util.QuickSort.sort(otherdb, otherdb);
+            List<DbSourceProxy> otherdb;
+            JMenu dfetch = new JMenu();
+            JMenu ifetch = new JMenu();
+            JMenuItem fetchr = null;
+            int comp = 0, icomp = 0, mcomp = 15;
+            String mname = null;
+            int dbi = 0;
+            for (String dbclass : dbclasses)
+            {
+              otherdb = sf.getSourceProxy(dbclass);
+              // add a single entry for this class, or submenu allowing 'fetch
+              // all' or pick one
+              if (otherdb == null || otherdb.size() < 1)
+              {
+                continue;
+              }
+              // List<DbSourceProxy> dbs=otherdb;
+              // otherdb=new ArrayList<DbSourceProxy>();
+              // for (DbSourceProxy db:dbs)
+              // {
+              // if (!db.isA(DBRefSource.ALIGNMENTDB)
+              // }
+              if (mname == null)
+              {
+                mname = "From " + dbclass;
+              }
+              if (otherdb.size() == 1)
+              {
+                final DbSourceProxy[] dassource = otherdb
+                        .toArray(new DbSourceProxy[0]);
+                DbSourceProxy src = otherdb.get(0);
+                fetchr = new JMenuItem(src.getDbSource());
+                fetchr.addActionListener(new ActionListener()
+                {
+
+                  @Override
+                  public void actionPerformed(ActionEvent e)
+                  {
+                    new Thread(new Runnable()
+                    {
+
+                      @Override
+                      public void run()
+                      {
+                        new jalview.ws.DBRefFetcher(alignPanel.av
+                                .getSequenceSelection(),
+                                alignPanel.alignFrame, dassource)
+                                .fetchDBRefs(false);
+                      }
+                    }).start();
+                  }
+
+                });
+                fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager.formatMessage("label.fetch_retrieve_from", new String[]{src.getDbName()})));
+                dfetch.add(fetchr);
+                comp++;
+              }
+              else
+              {
+                final DbSourceProxy[] dassource = otherdb
+                        .toArray(new DbSourceProxy[0]);
+                // fetch all entry
+                DbSourceProxy src = otherdb.get(0);
+                fetchr = new JMenuItem(MessageManager.formatMessage(
+                        "label.fetch_all_param", new String[]
+                        { src.getDbSource() }));
+                fetchr.addActionListener(new ActionListener()
+                {
+                  @Override
+                  public void actionPerformed(ActionEvent e)
+                  {
+                    new Thread(new Runnable()
+                    {
+
+                      @Override
+                      public void run()
+                      {
+                        new jalview.ws.DBRefFetcher(alignPanel.av
+                                .getSequenceSelection(),
+                                alignPanel.alignFrame, dassource)
+                                .fetchDBRefs(false);
+                      }
+                    }).start();
+                  }
+                });
+
+                fetchr.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager.formatMessage("label.fetch_retrieve_from_all_sources", new String[]{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 String[]{src.getDbSource()}));
+                icomp = 0;
+                String imname = null;
+                int i = 0;
+                for (DbSourceProxy sproxy : otherdb)
+                {
+                  String dbname = sproxy.getDbName();
+                  String sname = dbname.length() > 5 ? dbname.substring(0,
+                          5) + "..." : dbname;
+                  String msname = dbname.length() > 10 ? dbname.substring(
+                          0, 10) + "..." : dbname;
+                  if (imname == null)
+                  {
+                    imname = MessageManager.formatMessage("label.from_msname", new String[]{sname});
+                  }
+                  fetchr = new JMenuItem(msname);
+                  final DbSourceProxy[] dassrc =
+                  { sproxy };
+                  fetchr.addActionListener(new ActionListener()
+                  {
+
+                    @Override
+                    public void actionPerformed(ActionEvent e)
+                    {
+                      new Thread(new Runnable()
+                      {
+
+                        @Override
+                        public void run()
+                        {
+                          new jalview.ws.DBRefFetcher(alignPanel.av
+                                  .getSequenceSelection(),
+                                  alignPanel.alignFrame, dassrc)
+                                  .fetchDBRefs(false);
+                        }
+                      }).start();
+                    }
+
+                  });
+                  fetchr.setToolTipText("<html>"
+                          + MessageManager.formatMessage("label.fetch_retrieve_from", new String[]{dbname}));
+                  ifetch.add(fetchr);
+                  ++i;
+                  if (++icomp >= mcomp || i == (otherdb.size()))
+                  {
+                    ifetch.setText(MessageManager.formatMessage(
+                            "label.source_to_target", imname, sname));
+                    dfetch.add(ifetch);
+                    ifetch = new JMenu();
+                    imname = null;
+                    icomp = 0;
+                    comp++;
+                  }
+                }
+              }
+              ++dbi;
+              if (comp >= mcomp || dbi >= (dbclasses.length))
+              {
+                dfetch.setText(MessageManager.formatMessage(
+                        "label.source_to_target", mname, dbclass));
+                rfetch.add(dfetch);
+                dfetch = new JMenu();
+                mname = null;
+                comp = 0;
+              }
+            }
+          }
+        });
+      }
+    }).start();
+
+  }
+
+  /**
+   * Left justify the whole alignment.
+   */
+  @Override
+  protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
+  {
+    AlignmentI al = viewport.getAlignment();
+    al.justify(false);
+    viewport.firePropertyChange("alignment", null, al);
+  }
+
+  /**
+   * Right justify the whole alignment.
+   */
+  @Override
+  protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
+  {
+    AlignmentI al = viewport.getAlignment();
+    al.justify(true);
+    viewport.firePropertyChange("alignment", null, al);
+  }
+
+  public void setShowSeqFeatures(boolean b)
+  {
+    showSeqFeatures.setSelected(true);
+    viewport.setShowSequenceFeatures(true);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
+   * awt.event.ActionEvent)
+   */
+  @Override
+  protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowUnconserved(showNonconservedMenuItem.getState());
+    alignPanel.paintAlignment(true);
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
+   * .ActionEvent)
+   */
+  @Override
+  protected void showGroupConsensus_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowGroupConsensus(showGroupConsensus.getState());
+    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
+   * .event.ActionEvent)
+   */
+  @Override
+  protected void showGroupConservation_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowGroupConservation(showGroupConservation.getState());
+    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
+   * .event.ActionEvent)
+   */
+  @Override
+  protected void showConsensusHistogram_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
+    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
+   * .event.ActionEvent)
+   */
+  @Override
+  protected void showSequenceLogo_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowSequenceLogo(showSequenceLogo.getState());
+    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+  }
+
+  @Override
+  protected void normaliseSequenceLogo_actionPerformed(ActionEvent e)
+  {
+    showSequenceLogo.setState(true);
+    viewport.setShowSequenceLogo(true);
+    viewport.setNormaliseSequenceLogo(normaliseSequenceLogo.getState());
+    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+  }
+
+  @Override
+  protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
+  {
+    alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see
+   * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
+   * .event.ActionEvent)
+   */
+  @Override
+  protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
+  {
+    if (avc.makeGroupsFromSelection())
+    {
+      PaintRefresher.Refresh(this, viewport.getSequenceSetId());
+      alignPanel.updateAnnotation();
+      alignPanel.paintAlignment(true);
+    }
+  }
+
+  @Override
+  protected void createGroup_actionPerformed(ActionEvent e)
+  {
+    if (avc.createGroup())
+    {
+      alignPanel.alignmentChanged();
+    }
+  }
+
+  @Override
+  protected void unGroup_actionPerformed(ActionEvent e)
+  {
+    if (avc.unGroup())
+    {
+      alignPanel.alignmentChanged();
+    }
+  }
+
+  /**
+   * make the given alignmentPanel the currently selected tab
+   * 
+   * @param alignmentPanel
+   */
+  public void setDisplayedView(AlignmentPanel alignmentPanel)
+  {
+    if (!viewport.getSequenceSetId().equals(
+            alignmentPanel.av.getSequenceSetId()))
+    {
+      throw new Error(MessageManager.getString("error.implementation_error_cannot_show_view_alignment_frame"));
+    }
+    if (tabbedPane != null
+            & alignPanels.indexOf(alignmentPanel) != tabbedPane
+                    .getSelectedIndex())
+    {
+      tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));
+    }
+  }
+
+  /**
+   * Action on selection of menu options to Show or Hide annotations.
+   * 
+   * @param visible
+   * @param forSequences
+   *          update sequence-related annotations
+   * @param forAlignment
+   *          update non-sequence-related annotations
+   */
+  @Override
+  protected void setAnnotationsVisibility(boolean visible,
+          boolean forSequences, boolean forAlignment)
+  {
+    for (AlignmentAnnotation aa : alignPanel.getAlignment()
+            .getAlignmentAnnotation())
+    {
+      boolean apply = (aa.sequenceRef == null && forAlignment)
+              || (aa.sequenceRef != null && forSequences);
+      if (apply)
+      {
+        aa.visible = visible;
+      }
+    }
+    alignPanel.validateAnnotationDimensions(false);
+    alignPanel.alignmentChanged();
+  }
+
+  /**
+   * Store selected annotation sort order for the view and repaint.
+   */
+  @Override
+  protected void sortAnnotations_actionPerformed()
+  {
+    this.alignPanel.av.setSortAnnotationsBy(getAnnotationSortOrder());
+    this.alignPanel.av
+            .setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * 
+   * @return alignment panels in this alignemnt frame
+   */
+  public List<AlignmentViewPanel> getAlignPanels()
+  {
+    return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels;
+  }
+}
+
+class PrintThread extends Thread
+{
+  AlignmentPanel ap;
+
+  public PrintThread(AlignmentPanel ap)
+  {
+    this.ap = ap;
+  }
+
+  static PageFormat pf;
+
+  @Override
+  public void run()
+  {
+    PrinterJob printJob = PrinterJob.getPrinterJob();
+
+    if (pf != null)
+    {
+      printJob.setPrintable(ap, pf);
+    }
+    else
+    {
+      printJob.setPrintable(ap);
+    }
+
+    if (printJob.printDialog())
+    {
+      try
+      {
+        printJob.print();
+      } catch (Exception PrintException)
+      {
+        PrintException.printStackTrace();
+      }
+    }
+  }
+}