selection sending and receiving, autoscrolling to highlighted position, new viewport...
[jalview.git] / src / jalview / gui / AlignFrame.java
index bdcea36..f5a1494 100755 (executable)
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
- *\r
- * This program 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 2\r
- * of the License, or (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Softwarechang\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
- */\r
-package jalview.gui;\r
-\r
-import java.beans.*;\r
-import java.io.*;\r
-import java.util.*;\r
-\r
-import java.awt.*;\r
-import java.awt.datatransfer.*;\r
-import java.awt.event.*;\r
-import java.awt.print.*;\r
-import javax.swing.*;\r
-import javax.swing.event.*;\r
-\r
-import jalview.analysis.*;\r
-import jalview.datamodel.*;\r
-import jalview.io.*;\r
-import jalview.jbgui.*;\r
-import jalview.schemes.*;\r
-import jalview.ws.*;\r
-\r
-/**\r
- * DOCUMENT ME!\r
- *\r
- * @author $author$\r
- * @version $Revision$\r
- */\r
-public class AlignFrame\r
-    extends GAlignFrame\r
-{\r
-  /** DOCUMENT ME!! */\r
-  public static final int NEW_WINDOW_WIDTH = 700;\r
-\r
-  /** DOCUMENT ME!! */\r
-  public static final int NEW_WINDOW_HEIGHT = 500;\r
-  final AlignmentPanel alignPanel;\r
-  final AlignViewport viewport;\r
-\r
-  /** DOCUMENT ME!! */\r
-  public String currentFileFormat = null;\r
-  Stack historyList = new Stack();\r
-  Stack redoList = new Stack();\r
-  private int treeCount = 0;\r
-\r
-  /**\r
-   * Creates a new AlignFrame object.\r
-   *\r
-   * @param al DOCUMENT ME!\r
-   */\r
-  public AlignFrame(AlignmentI al)\r
-  {\r
-    viewport = new AlignViewport(al);\r
-\r
-    alignPanel = new AlignmentPanel(this, viewport);\r
-    alignPanel.annotationPanel.adjustPanelHeight();\r
-    alignPanel.annotationSpaceFillerHolder.setPreferredSize(alignPanel.\r
-        annotationPanel.getPreferredSize());\r
-    alignPanel.annotationScroller.setPreferredSize(alignPanel.annotationPanel.\r
-        getPreferredSize());\r
-    alignPanel.setAnnotationVisible(viewport.getShowAnnotation());\r
-\r
-    getContentPane().add(alignPanel, java.awt.BorderLayout.CENTER);\r
-\r
-    addInternalFrameListener(new InternalFrameAdapter()\r
-    {\r
-      public void internalFrameActivated(InternalFrameEvent evt)\r
-      {\r
-        javax.swing.SwingUtilities.invokeLater(new Runnable()\r
-        {\r
-          public void run()\r
-          {\r
-            alignPanel.requestFocus();\r
-          }\r
-        });\r
-      }\r
-    });\r
-    addServiceListeners();\r
-  }\r
-\r
-  /* Set up intrinsic listeners for dynamically generated GUI bits. */\r
-  private void addServiceListeners()\r
-  {\r
-    final java.beans.PropertyChangeListener thisListener;\r
-    // Do this once to get current state\r
-    BuildWebServiceMenu();\r
-    Desktop.discoverer.addPropertyChangeListener(\r
-        thisListener = new java.beans.PropertyChangeListener()\r
-    {\r
-      public void propertyChange(PropertyChangeEvent evt)\r
-      {\r
-        // System.out.println("Discoverer property change.");\r
-        if (evt.getPropertyName().equals("services"))\r
-        {\r
-          // System.out.println("Rebuilding web service menu");\r
-          BuildWebServiceMenu();\r
-        }\r
-      }\r
-    });\r
-    addInternalFrameListener(new javax.swing.event.\r
-                             InternalFrameAdapter()\r
-    {\r
-      public void internalFrameClosed(\r
-          javax.swing.event.InternalFrameEvent evt)\r
-      {\r
-        // System.out.println("deregistering discoverer listener");\r
-        Desktop.discoverer.removePropertyChangeListener(thisListener);\r
-        closeMenuItem_actionPerformed(null);\r
-      }\r
-      ;\r
-    });\r
-\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param String DOCUMENT ME!\r
-   */\r
-\r
-  public void parseGroupsFile(String file)\r
-  {\r
-    try\r
-    {\r
-      BufferedReader in = new BufferedReader(new FileReader(file));\r
-      SequenceI seq = null;\r
-      String line, text, token;\r
-      UserColourScheme ucs;\r
-      int index, start, end;\r
-      StringTokenizer st;\r
-      SequenceGroup sg;\r
-      while ( (line = in.readLine()) != null)\r
-      {\r
-        st = new StringTokenizer(line, "\t");\r
-        if (st.countTokens() != 6)\r
-        {\r
-          System.out.println("Groups file " + file +\r
-                             " is invalid. Read help file.");\r
-          System.exit(1);\r
-        }\r
-\r
-        while (st.hasMoreElements())\r
-        {\r
-          text = st.nextToken();\r
-          token = st.nextToken();\r
-          if (!token.equals("ID_NOT_SPECIFIED"))\r
-          {\r
-            index = viewport.alignment.findIndex(viewport.alignment.findName(\r
-                token));\r
-            st.nextToken();\r
-          }\r
-          else\r
-          {\r
-            index = Integer.parseInt(st.nextToken());\r
-          }\r
-\r
-          start = Integer.parseInt(st.nextToken());\r
-          end = Integer.parseInt(st.nextToken());\r
-          ucs = new UserColourScheme(st.nextToken());\r
-\r
-          seq = viewport.alignment.getSequenceAt(index);\r
-          start = seq.findIndex(start) - 1;\r
-          end = seq.findIndex(end) - 1;\r
-\r
-          sg = new SequenceGroup(text, ucs, true, true, false, start, end);\r
-          sg.addSequence(seq, true);\r
-\r
-          viewport.alignment.addGroup(sg);\r
-        }\r
-      }\r
-\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-      System.out.println("Error parsing groups file: " + ex);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void saveAlignmentMenu_actionPerformed(ActionEvent e)\r
-  {\r
-    JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.\r
-        getProperty(\r
-            "LAST_DIRECTORY"),\r
-        new String[]\r
-        {\r
-        "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc",\r
-        "jar"\r
-    },\r
-        new String[]\r
-        {\r
-        "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "Jalview"\r
-    }, currentFileFormat);\r
-\r
-    chooser.setAcceptAllFileFilterUsed(false);\r
-    chooser.setFileView(new JalviewFileView());\r
-    chooser.setDialogTitle("Save Alignment to file");\r
-    chooser.setToolTipText("Save");\r
-\r
-    int value = chooser.showSaveDialog(this);\r
-\r
-    if (value == JalviewFileChooser.APPROVE_OPTION)\r
-    {\r
-      currentFileFormat = chooser.getSelectedFormat();\r
-      jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",\r
-                                    currentFileFormat);\r
-\r
-      String choice = chooser.getSelectedFile().getPath();\r
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);\r
-\r
-      saveAlignment(choice, currentFileFormat);\r
-    }\r
-  }\r
-\r
-  public boolean saveAlignment(String file, String format)\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.lastIndexOf(\r
-            java.io.File.separatorChar) + 1);\r
-      }\r
-\r
-      Jalview2XML.SaveAlignment(this, file, shortName);\r
-\r
-      // USE Jalview2XML to save this file\r
-      return true;\r
-    }\r
-    else\r
-    {\r
-      String output = FormatAdapter.formatSequences(format,\r
-          viewport.getAlignment().\r
-          getSequences());\r
-      if (output == null)\r
-      {\r
-        return false;\r
-      }\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
-        return true;\r
-      }\r
-      catch (Exception ex)\r
-      {\r
-        ex.printStackTrace();\r
-      }\r
-    }\r
-    return false;\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void outputText_actionPerformed(ActionEvent e)\r
-  {\r
-    CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
-    Desktop.addInternalFrame(cap,\r
-                             "Alignment output - " + e.getActionCommand(), 600,\r
-                             500);\r
-    cap.setText(FormatAdapter.formatSequences(e.getActionCommand(),\r
-                                              viewport.getAlignment().\r
-                                              getSequences()));\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void htmlMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    new HTMLOutput(viewport);\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 DOCUMENT ME!\r
-   */\r
-  public void createPNG(File f)\r
-  {\r
-    alignPanel.makePNG(f);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void createEPS(File f)\r
-  {\r
-    alignPanel.makeEPS(f);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void printMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    //Putting in a thread avoids Swing painting problems\r
-    PrintThread thread = new PrintThread();\r
-    thread.start();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void closeMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    try\r
-    {\r
-      PaintRefresher.components.remove(viewport.alignment);\r
-      this.setClosed(true);\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   */\r
-  void updateEditMenuBar()\r
-  {\r
-    if (historyList.size() > 0)\r
-    {\r
-      undoMenuItem.setEnabled(true);\r
-\r
-      HistoryItem hi = (HistoryItem) historyList.peek();\r
-      undoMenuItem.setText("Undo " + hi.getDescription());\r
-    }\r
-    else\r
-    {\r
-      undoMenuItem.setEnabled(false);\r
-      undoMenuItem.setText("Undo");\r
-    }\r
-\r
-    if (redoList.size() > 0)\r
-    {\r
-      redoMenuItem.setEnabled(true);\r
-\r
-      HistoryItem hi = (HistoryItem) redoList.peek();\r
-      redoMenuItem.setText("Redo " + hi.getDescription());\r
-    }\r
-    else\r
-    {\r
-      redoMenuItem.setEnabled(false);\r
-      redoMenuItem.setText("Redo");\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param hi DOCUMENT ME!\r
-   */\r
-  public void addHistoryItem(HistoryItem hi)\r
-  {\r
-    historyList.push(hi);\r
-    updateEditMenuBar();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void undoMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    HistoryItem hi = (HistoryItem) historyList.pop();\r
-    redoList.push(new HistoryItem(hi.getDescription(), viewport.alignment,\r
-                                  HistoryItem.HIDE));\r
-    restoreHistoryItem(hi);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void redoMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    HistoryItem hi = (HistoryItem) redoList.pop();\r
-    restoreHistoryItem(hi);\r
-    updateEditMenuBar();\r
-    viewport.updateConsensus();\r
-    alignPanel.repaint();\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  // used by undo and redo\r
-  void restoreHistoryItem(HistoryItem hi)\r
-  {\r
-    if (hi.getType() == HistoryItem.SORT)\r
-    {\r
-      for (int i = 0; i < hi.getSequences().size(); i++)\r
-      {\r
-        viewport.alignment.getSequences().setElementAt(hi.getSequences()\r
-            .elementAt(i),\r
-            i);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      for (int i = 0; i < hi.getSequences().size(); i++)\r
-      {\r
-        SequenceI restore = (SequenceI) hi.getSequences().elementAt(i);\r
-\r
-        if (restore.getLength() == 0)\r
-        {\r
-          restore.setSequence(hi.getHidden().elementAt(i).toString());\r
-          viewport.alignment.getSequences().insertElementAt(restore,\r
-              hi.getAlignIndex(i));\r
-        }\r
-        else\r
-        {\r
-          restore.setSequence(hi.getHidden().elementAt(i).toString());\r
-        }\r
-      }\r
-\r
-      if (hi.getType() == HistoryItem.PASTE)\r
-      {\r
-        for (int i = viewport.alignment.getHeight() - 1;\r
-             i > (hi.getSequences().size() - 1); i--)\r
-        {\r
-          viewport.alignment.deleteSequence(i);\r
-        }\r
-      }\r
-    }\r
-\r
-    updateEditMenuBar();\r
-\r
-    viewport.updateConsensus();\r
-    viewport.updateConservation();\r
-    alignPanel.repaint();\r
-    viewport.firePropertyChange("alignment", null,\r
-                                viewport.getAlignment().getSequences());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param up 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
-\r
-    if (up)\r
-    {\r
-      for (int i = 1; i < viewport.alignment.getHeight(); i++)\r
-      {\r
-        SequenceI seq = viewport.alignment.getSequenceAt(i);\r
-\r
-        if (!sg.sequences.contains(seq))\r
-        {\r
-          continue;\r
-        }\r
-\r
-        SequenceI temp = viewport.alignment.getSequenceAt(i - 1);\r
-\r
-        if (sg.sequences.contains(temp))\r
-        {\r
-          continue;\r
-        }\r
-\r
-        viewport.alignment.getSequences().setElementAt(temp, i);\r
-        viewport.alignment.getSequences().setElementAt(seq, i - 1);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)\r
-      {\r
-        SequenceI seq = viewport.alignment.getSequenceAt(i);\r
-\r
-        if (!sg.sequences.contains(seq))\r
-        {\r
-          continue;\r
-        }\r
-\r
-        SequenceI temp = viewport.alignment.getSequenceAt(i + 1);\r
-\r
-        if (sg.sequences.contains(temp))\r
-        {\r
-          continue;\r
-        }\r
-\r
-        viewport.alignment.getSequences().setElementAt(temp, i);\r
-        viewport.alignment.getSequences().setElementAt(seq, i + 1);\r
-      }\r
-    }\r
-\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void copy_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.getSelectionGroup() == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-\r
-    Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();\r
-    StringBuffer buffer = new StringBuffer();\r
-\r
-    Hashtable orderedSeqs = new Hashtable();\r
-\r
-    for (int i = 0; i < sg.getSize(); i++)\r
-    {\r
-      SequenceI seq = sg.getSequenceAt(i);\r
-      int index = viewport.alignment.findIndex(seq);\r
-      orderedSeqs.put(index + "", seq);\r
-    }\r
-\r
-    int index = 0, startRes, endRes;\r
-    char ch;\r
-\r
-    for (int i = 0; i < sg.getSize(); i++)\r
-    {\r
-      SequenceI seq = null;\r
-\r
-      while (seq == null)\r
-      {\r
-        if (orderedSeqs.containsKey(index + ""))\r
-        {\r
-          seq = (SequenceI) orderedSeqs.get(index + "");\r
-          index++;\r
-\r
-          break;\r
-        }\r
-        else\r
-        {\r
-          index++;\r
-        }\r
-      }\r
-      //FIND START RES\r
-      //Returns residue following index if gap\r
-      startRes = seq.findPosition(sg.getStartRes());\r
-\r
-      //FIND END RES\r
-      //Need to find the residue preceeding index if gap\r
-      endRes = 0;\r
-\r
-      for (int j = 0; j < sg.getEndRes() + 1 && j < seq.getLength(); j++)\r
-      {\r
-        ch = seq.getCharAt(j);\r
-        if (!jalview.util.Comparison.isGap( (ch)))\r
-        {\r
-          endRes++;\r
-        }\r
-      }\r
-\r
-      if (endRes > 0)\r
-      {\r
-        endRes += seq.getStart() - 1;\r
-      }\r
-\r
-      buffer.append(seq.getName() + "\t" +\r
-                    startRes + "\t" +\r
-                    endRes + "\t" +\r
-                    seq.getSequence(sg.getStartRes(),\r
-                                    sg.getEndRes() + 1) + "\n");\r
-    }\r
-\r
-    c.setContents(new StringSelection(buffer.toString()), null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void pasteNew_actionPerformed(ActionEvent e)\r
-  {\r
-    paste(true);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void pasteThis_actionPerformed(ActionEvent e)\r
-  {\r
-    addHistoryItem(new HistoryItem("Paste Sequences", viewport.alignment,\r
-                                   HistoryItem.PASTE));\r
-    paste(false);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param newAlignment DOCUMENT ME!\r
-   */\r
-  void paste(boolean newAlignment)\r
-  {\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 = (String) contents.getTransferData(DataFlavor.stringFlavor);\r
-      StringTokenizer st = new StringTokenizer(str);\r
-      ArrayList seqs = new ArrayList();\r
-\r
-      while (st.hasMoreElements())\r
-      {\r
-        String name = st.nextToken();\r
-        int start = Integer.parseInt(st.nextToken());\r
-        int end = Integer.parseInt(st.nextToken());\r
-        Sequence sequence = new Sequence(name, st.nextToken(), start,\r
-                                         end);\r
-\r
-        if (!newAlignment)\r
-        {\r
-          viewport.alignment.addSequence(sequence);\r
-        }\r
-        else\r
-        {\r
-          seqs.add(sequence);\r
-        }\r
-      }\r
-\r
-      if (newAlignment)\r
-      {\r
-        SequenceI[] newSeqs = new SequenceI[seqs.size()];\r
-        seqs.toArray(newSeqs);\r
-\r
-        AlignFrame af = new AlignFrame(new Alignment(newSeqs));\r
-        String newtitle = new String("Copied sequences");\r
-\r
-        if (title.startsWith("Copied sequences"))\r
-        {\r
-          newtitle = title;\r
-        }\r
-        else\r
-        {\r
-          newtitle = newtitle.concat("- from " + title);\r
-        }\r
-\r
-        Desktop.addInternalFrame(af, newtitle, NEW_WINDOW_WIDTH,\r
-                                 NEW_WINDOW_HEIGHT);\r
-      }\r
-      else\r
-      {\r
-        viewport.firePropertyChange("alignment", null,\r
-                                    viewport.getAlignment().getSequences());\r
-        viewport.setEndSeq(viewport.alignment.getHeight());\r
-        viewport.alignment.getWidth();\r
-        viewport.updateConservation();\r
-        viewport.updateConsensus();\r
-        alignPanel.repaint();\r
-      }\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-    }\r
-\r
-    // could be anything being pasted in here\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\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 DOCUMENT ME!\r
-   */\r
-  protected void delete_actionPerformed(ActionEvent e)\r
-  {\r
-    boolean seqsdeleted = false;\r
-\r
-    if (viewport.getSelectionGroup() == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    addHistoryItem(new HistoryItem("Delete Sequences", viewport.alignment,\r
-                                   HistoryItem.HIDE));\r
-\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-    boolean allSequences = false;\r
-    if (sg.sequences.size() == viewport.alignment.getHeight())\r
-    {\r
-      allSequences = true;\r
-    }\r
-\r
-    for (int i = 0; i < sg.sequences.size(); i++)\r
-    {\r
-      SequenceI seq = sg.getSequenceAt(i);\r
-      int index = viewport.getAlignment().findIndex(seq);\r
-      seq.deleteChars(sg.getStartRes(), sg.getEndRes() + 1);\r
-\r
-      // If the cut affects all sequences, remove highlighted columns\r
-      if (allSequences)\r
-      {\r
-        viewport.getColumnSelection().removeElements(sg.getStartRes(),\r
-            sg.getEndRes() + 1);\r
-      }\r
-\r
-      if (seq.getSequence().length() < 1)\r
-      {\r
-        seqsdeleted = true;\r
-        viewport.getAlignment().deleteSequence(seq);\r
-      }\r
-      else\r
-      {\r
-        viewport.getAlignment().getSequences().setElementAt(seq, index);\r
-      }\r
-    }\r
-\r
-    viewport.setSelectionGroup(null);\r
-    viewport.alignment.deleteGroup(sg);\r
-\r
-    if (seqsdeleted)\r
-    {\r
-      viewport.firePropertyChange("alignment", null,\r
-                                  viewport.getAlignment().getSequences());\r
-    }\r
-\r
-    viewport.resetSeqLimits(alignPanel.seqPanel.seqCanvas.getHeight());\r
-\r
-    if (viewport.getAlignment().getHeight() < 1)\r
-    {\r
-      try\r
-      {\r
-        this.setClosed(true);\r
-      }\r
-      catch (Exception ex)\r
-      {\r
-      }\r
-    }\r
-\r
-    viewport.updateConservation();\r
-    viewport.updateConsensus();\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void deleteGroups_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.alignment.deleteAllGroups();\r
-    viewport.setSelectionGroup(null);\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceGroup sg = new SequenceGroup();\r
-\r
-    for (int i = 0; i < viewport.getAlignment().getSequences().size();\r
-         i++)\r
-    {\r
-      sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);\r
-    }\r
-\r
-    sg.setEndRes(viewport.alignment.getWidth() - 1);\r
-    viewport.setSelectionGroup(sg);\r
-    PaintRefresher.Refresh(null, viewport.alignment);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setSelectionGroup(null);\r
-    viewport.getColumnSelection().clear();\r
-    viewport.setSelectionGroup(null);\r
-    alignPanel.annotationPanel.activeRes = null;\r
-    PaintRefresher.Refresh(null, viewport.alignment);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\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();\r
-         i++)\r
-    {\r
-      sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);\r
-    }\r
-\r
-    PaintRefresher.Refresh(null, viewport.alignment);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void remove2LeftMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    ColumnSelection colSel = viewport.getColumnSelection();\r
-\r
-    if (colSel.size() > 0)\r
-    {\r
-      addHistoryItem(new HistoryItem("Remove Left", viewport.alignment,\r
-                                     HistoryItem.HIDE));\r
-\r
-      int min = colSel.getMin();\r
-      viewport.getAlignment().trimLeft(min);\r
-      colSel.compensateForEdit(0, min);\r
-\r
-      if (viewport.getSelectionGroup() != null)\r
-      {\r
-        viewport.getSelectionGroup().adjustForRemoveLeft(min);\r
-      }\r
-\r
-      Vector groups = viewport.alignment.getGroups();\r
-\r
-      for (int i = 0; i < groups.size(); i++)\r
-      {\r
-        SequenceGroup sg = (SequenceGroup) groups.get(i);\r
-\r
-        if (!sg.adjustForRemoveLeft(min))\r
-        {\r
-          viewport.alignment.deleteGroup(sg);\r
-        }\r
-      }\r
-\r
-      alignPanel.repaint();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void remove2RightMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    ColumnSelection colSel = viewport.getColumnSelection();\r
-\r
-    if (colSel.size() > 0)\r
-    {\r
-      addHistoryItem(new HistoryItem("Remove Right", viewport.alignment,\r
-                                     HistoryItem.HIDE));\r
-\r
-      int max = colSel.getMax();\r
-      viewport.getAlignment().trimRight(max);\r
-\r
-      if (viewport.getSelectionGroup() != null)\r
-      {\r
-        viewport.getSelectionGroup().adjustForRemoveRight(max);\r
-      }\r
-\r
-      Vector groups = viewport.alignment.getGroups();\r
-\r
-      for (int i = 0; i < groups.size(); i++)\r
-      {\r
-        SequenceGroup sg = (SequenceGroup) groups.get(i);\r
-\r
-        if (!sg.adjustForRemoveRight(max))\r
-        {\r
-          viewport.alignment.deleteGroup(sg);\r
-        }\r
-      }\r
-\r
-      alignPanel.repaint();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    addHistoryItem(new HistoryItem("Remove Gapped Columns",\r
-                                   viewport.alignment, HistoryItem.HIDE));\r
-\r
-    viewport.getAlignment().removeGaps();\r
-    viewport.updateConservation();\r
-    viewport.updateConsensus();\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    addHistoryItem(new HistoryItem("Remove Gaps", viewport.alignment,\r
-                                   HistoryItem.HIDE));\r
-\r
-    SequenceI current;\r
-    int jSize;\r
-\r
-    Vector seqs = null;\r
-\r
-    int start = 0;\r
-    int end = viewport.alignment.getWidth();\r
-\r
-    if (viewport.getSelectionGroup() != null\r
-        && viewport.getSelectionGroup().sequences != null\r
-        && viewport.getSelectionGroup().sequences.size() > 0)\r
-    {\r
-      seqs = viewport.getSelectionGroup().sequences;\r
-      start = viewport.getSelectionGroup().getStartRes();\r
-      end = viewport.getSelectionGroup().getEndRes();\r
-    }\r
-    else\r
-    {\r
-      seqs = viewport.alignment.getSequences();\r
-    }\r
-\r
-    for (int i = 0; i < seqs.size(); i++)\r
-    {\r
-      current = (SequenceI) seqs.elementAt(i);\r
-      jSize = current.getLength();\r
-\r
-      int j = start;\r
-\r
-      do\r
-      {\r
-        if (jalview.util.Comparison.isGap(current.getCharAt(j)))\r
-        {\r
-          current.deleteCharAt(j);\r
-          j--;\r
-          jSize--;\r
-        }\r
-        j++;\r
-      }\r
-      while (j < end && j < jSize);\r
-    }\r
-\r
-    viewport.updateConservation();\r
-    viewport.updateConsensus();\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void padGapsMenuitem_actionPerformed(ActionEvent e)\r
-  {\r
-    addHistoryItem(new HistoryItem("Pad Gaps", viewport.alignment,\r
-                                   HistoryItem.HIDE));\r
-\r
-    SequenceI current;\r
-    int Width = viewport.getAlignment().getWidth();\r
-\r
-    for (int i = 0; i < viewport.getAlignment().getSequences().size();\r
-         i++)\r
-    {\r
-      current = viewport.getAlignment().getSequenceAt(i);\r
-\r
-      if (current.getLength() < Width)\r
-      {\r
-        current.insertCharAt(Width - 1, viewport.getGapCharacter());\r
-      }\r
-    }\r
-\r
-    viewport.updateConservation();\r
-    viewport.updateConsensus();\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void findMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    JInternalFrame frame = new JInternalFrame();\r
-    Finder finder = new Finder(viewport, alignPanel, frame);\r
-    frame.setContentPane(finder);\r
-    Desktop.addInternalFrame(frame, "Find", 340, 110);\r
-    frame.setLayer(JLayeredPane.PALETTE_LAYER);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void font_actionPerformed(ActionEvent e)\r
-  {\r
-    FontChooser fc = new FontChooser(alignPanel);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void fullSeqId_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowFullId(fullSeqId.isSelected());\r
-\r
-    alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel.calculateIdWidth());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void colourTextMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setColourText(colourTextMenuItem.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void wrapMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setWrapAlignment(wrapMenuItem.isSelected());\r
-    alignPanel.setWrapAlignment(wrapMenuItem.isSelected());\r
-    scaleAbove.setVisible(wrapMenuItem.isSelected());\r
-    scaleLeft.setVisible(wrapMenuItem.isSelected());\r
-    scaleRight.setVisible(wrapMenuItem.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void scaleAbove_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setScaleAboveWrapped(scaleAbove.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void scaleLeft_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setScaleLeftWrapped(scaleLeft.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void scaleRight_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setScaleRightWrapped(scaleRight.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void viewBoxesMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowBoxes(viewBoxesMenuItem.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void viewTextMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowText(viewTextMenuItem.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void renderGapsMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setRenderGaps(renderGapsMenuItem.isSelected());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param evt DOCUMENT ME!\r
-   */\r
-  public void sequenceFeatures_actionPerformed(ActionEvent evt)\r
-  {\r
-    viewport.showSequenceFeatures(sequenceFeatures.isSelected());\r
-\r
-    if (viewport.showSequenceFeatures &&\r
-        ! ( (Alignment) viewport.alignment).featuresAdded)\r
-    {\r
-      SequenceFeatureFetcher sft = new SequenceFeatureFetcher(viewport.\r
-          alignment,\r
-          alignPanel);\r
-      ( (Alignment) viewport.alignment).featuresAdded = true;\r
-    }\r
-\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void annotationPanelMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if (annotationPanelMenuItem.isSelected() &&\r
-        viewport.getWrapAlignment())\r
-    {\r
-      annotationPanelMenuItem.setSelected(false);\r
-\r
-      return;\r
-    }\r
-\r
-    viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());\r
-    alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\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, "Overview " + 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
-      public void internalFrameClosed(\r
-          javax.swing.event.InternalFrameEvent evt)\r
-      {\r
-        alignPanel.setOverviewPanel(null);\r
-      }\r
-      ;\r
-    });\r
-\r
-    alignPanel.setOverviewPanel(overview);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void noColourmenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void clustalColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new ClustalxColourScheme(\r
-        viewport.alignment.getSequences(), viewport.alignment.getWidth()));\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void zappoColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new ZappoColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void taylorColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new TaylorColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void hydrophobicityColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new HydrophobicColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void helixColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new HelixColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void strandColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new StrandColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void turnColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new TurnColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void buriedColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new BuriedColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void nucleotideColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new NucleotideColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void applyToAllGroups_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param cs DOCUMENT ME!\r
-   */\r
-  void changeColour(ColourSchemeI cs)\r
-  {\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,\r
-                        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.alignment;\r
-        Conservation c = new Conservation("All",\r
-                                          ResidueProperties.propHash, 3,\r
-                                          al.getSequences(), 0,\r
-                                          al.getWidth() - 1);\r
-\r
-        c.calculate();\r
-        c.verdict(false, viewport.ConsPercGaps);\r
-\r
-        cs.setConservation(c);\r
-\r
-        cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel, cs,\r
-            "Background"));\r
-      }\r
-      else\r
-      {\r
-        cs.setConservation(null);\r
-      }\r
-\r
-      cs.setConsensus(viewport.vconsensus);\r
-    }\r
-\r
-    viewport.setGlobalColourScheme(cs);\r
-\r
-    if (viewport.getColourAppliesToAllGroups())\r
-    {\r
-      Vector groups = viewport.alignment.getGroups();\r
-\r
-      for (int i = 0; i < groups.size(); i++)\r
-      {\r
-        SequenceGroup sg = (SequenceGroup) groups.elementAt(i);\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.sequences, sg.getWidth());\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 = (ColourSchemeI) cs.getClass().newInstance();\r
-          }\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,\r
-                viewport.getIgnoreGapsConsensus());\r
-\r
-          sg.cs.setConsensus(AAFrequency.calculate(sg.sequences, 0,\r
-              sg.getWidth()));\r
-        }\r
-        else\r
-          sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());\r
-\r
-\r
-        if (viewport.getConservationSelected())\r
-        {\r
-          Conservation c = new Conservation("Group",\r
-                                            ResidueProperties.propHash, 3,\r
-                                            sg.sequences, 0,\r
-                                            viewport.alignment.getWidth() - 1);\r
-          c.calculate();\r
-          c.verdict(false, viewport.ConsPercGaps);\r
-          sg.cs.setConservation(c);\r
-        }\r
-        else\r
-          sg.cs.setConservation(null);\r
-      }\r
-    }\r
-\r
-    if (alignPanel.getOverviewPanel() != null)\r
-    {\r
-      alignPanel.getOverviewPanel().updateOverviewImage();\r
-    }\r
-\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void modifyPID_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.getAbovePIDThreshold() && viewport.globalColourScheme!=null)\r
-    {\r
-      SliderPanel.setPIDSliderSource(alignPanel,\r
-                                     viewport.getGlobalColourScheme(),\r
-                                     "Background");\r
-      SliderPanel.showPIDSlider();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void modifyConservation_actionPerformed(ActionEvent e)\r
-  {\r
-    if (viewport.getConservationSelected() && viewport.globalColourScheme!=null)\r
-    {\r
-      SliderPanel.setConservationSlider(alignPanel,\r
-                                        viewport.globalColourScheme,\r
-                                        "Background");\r
-      SliderPanel.showConservationSlider();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\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 DOCUMENT ME!\r
-   */\r
-  public void abovePIDThreshold_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());\r
-\r
-    conservationMenuItem.setSelected(false);\r
-    viewport.setConservationSelected(false);\r
-\r
-    ColourSchemeI cs = viewport.getGlobalColourScheme();\r
-\r
-    changeColour(viewport.getGlobalColourScheme());\r
-\r
-    modifyPID_actionPerformed(null);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void userDefinedColour_actionPerformed(ActionEvent e)\r
-  {\r
-    if (e.getActionCommand().equals("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(userColours.\r
-            nextElement().toString());\r
-        radioItem.setName("USER_DEFINED");\r
-        radioItem.addMouseListener(new MouseAdapter()\r
-            {\r
-              public void mousePressed(MouseEvent evt)\r
-              {\r
-                if(evt.isControlDown() || SwingUtilities.isRightMouseButton(evt))\r
-                {\r
-                  radioItem.removeActionListener(radioItem.getActionListeners()[0]);\r
-\r
-                  int option = JOptionPane.showInternalConfirmDialog(jalview.gui.Desktop.desktop,\r
-                      "Remove from default list?",\r
-                      "Remove user defined colour",\r
-                      JOptionPane.YES_NO_OPTION);\r
-                  if(option == JOptionPane.YES_OPTION)\r
-                  {\r
-                    jalview.gui.UserDefinedColours.removeColourFromDefaults(radioItem.getText());\r
-                    colourMenu.remove(radioItem);\r
-                  }\r
-                  else\r
-                    radioItem.addActionListener(new ActionListener()\r
-                    {\r
-                      public void actionPerformed(ActionEvent evt)\r
-                      {\r
-                        userDefinedColour_actionPerformed(evt);\r
-                      }\r
-                    });\r
-                }\r
-              }\r
-            });\r
-        radioItem.addActionListener(new ActionListener()\r
-        {\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 DOCUMENT ME!\r
-   */\r
-  public void PIDColour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new PIDColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void BLOSUM62Colour_actionPerformed(ActionEvent e)\r
-  {\r
-    changeColour(new Blosum62ColourScheme());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    addHistoryItem(new HistoryItem("Pairwise Sort", viewport.alignment,\r
-                                   HistoryItem.SORT));\r
-    AlignmentSorter.sortByPID(viewport.getAlignment(),\r
-                              viewport.getAlignment().getSequenceAt(0));\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void sortIDMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    addHistoryItem(new HistoryItem("ID Sort", viewport.alignment,\r
-                                   HistoryItem.SORT));\r
-    AlignmentSorter.sortByID(viewport.getAlignment());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void sortGroupMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    addHistoryItem(new HistoryItem("Group Sort", viewport.alignment,\r
-                                   HistoryItem.SORT));\r
-\r
-    AlignmentSorter.sortByGroup(viewport.getAlignment());\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    RedundancyPanel sp = new RedundancyPanel(alignPanel, this);\r
-    JInternalFrame frame = new JInternalFrame();\r
-    frame.setContentPane(sp);\r
-    Desktop.addInternalFrame(frame, "Redundancy threshold selection", 400,\r
-                             100, false);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if ( (viewport.getSelectionGroup() == null) ||\r
-        (viewport.getSelectionGroup().getSize() < 2))\r
-    {\r
-      JOptionPane.showInternalMessageDialog(this,\r
-                                            "You must select at least 2 sequences.",\r
-                                            "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, "Pairwise Alignment", 600, 500);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void PCAMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    if ( ( (viewport.getSelectionGroup() != null) &&\r
-          (viewport.getSelectionGroup().getSize() < 4) &&\r
-          (viewport.getSelectionGroup().getSize() > 0)) ||\r
-        (viewport.getAlignment().getHeight() < 4))\r
-    {\r
-      JOptionPane.showInternalMessageDialog(this,\r
-                                            "Principal component analysis must take\n" +\r
-                                            "at least 4 input sequences.",\r
-                                            "Sequence selection insufficient",\r
-                                            JOptionPane.WARNING_MESSAGE);\r
-\r
-      return;\r
-    }\r
-\r
-    try\r
-    {\r
-      PCAPanel pcaPanel = new PCAPanel(viewport, null);\r
-      JInternalFrame frame = new JInternalFrame();\r
-      frame.setContentPane(pcaPanel);\r
-      Desktop.addInternalFrame(frame, "Principal component analysis",\r
-                               400, 400);\r
-    }\r
-    catch (java.lang.OutOfMemoryError ex)\r
-    {\r
-      JOptionPane.showInternalMessageDialog(this,\r
-                                            "Too many sequences selected\nfor Principal Component Analysis!!",\r
-                                            "Out of memory",\r
-                                            JOptionPane.WARNING_MESSAGE);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\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 DOCUMENT ME!\r
-   */\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 DOCUMENT ME!\r
-   */\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 DOCUMENT ME!\r
-   */\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 DOCUMENT ME!\r
-   * @param pwType DOCUMENT ME!\r
-   * @param title DOCUMENT ME!\r
-   */\r
-  void NewTreePanel(String type, String pwType, String title)\r
-  {\r
-    final TreePanel tp;\r
-\r
-    if ( (viewport.getSelectionGroup() != null) &&\r
-        (viewport.getSelectionGroup().getSize() > 3))\r
-    {\r
-      int s = 0;\r
-      SequenceGroup sg = viewport.getSelectionGroup();\r
-\r
-      /* Decide if the selection is a column region */\r
-      while (s < sg.sequences.size())\r
-      {\r
-        if ( ( (SequenceI) sg.sequences.elementAt(s++)).getLength() <\r
-            sg.getEndRes())\r
-        {\r
-          JOptionPane.showMessageDialog(Desktop.desktop,\r
-                                        "The selected region to create a tree may\nonly contain residues or gaps.\n" +\r
-                                        "Try using the Pad function in the edit menu,\n" +\r
-                                        "or one of the multiple sequence alignment web services.",\r
-                                        "Sequences in selection are not aligned",\r
-                                        JOptionPane.WARNING_MESSAGE);\r
-\r
-          return;\r
-        }\r
-      }\r
-\r
-      title = title + " on region";\r
-      tp = new TreePanel(viewport,\r
-                         viewport.getSelectionGroup().sequences, type, pwType,\r
-                         sg.getStartRes(), sg.getEndRes());\r
-    }\r
-    else\r
-    {\r
-      //are the sequences aligned?\r
-      if (!viewport.alignment.isAligned())\r
-      {\r
-        JOptionPane.showMessageDialog(Desktop.desktop,\r
-                                      "The sequences must be aligned before creating a tree.\n" +\r
-                                      "Try using the Pad function in the edit menu,\n" +\r
-                                      "or one of the multiple sequence alignment web services.",\r
-                                      "Sequences not aligned",\r
-                                      JOptionPane.WARNING_MESSAGE);\r
-\r
-        return;\r
-      }\r
-\r
-      tp = new TreePanel(viewport,\r
-                         viewport.getAlignment().getSequences(), type, pwType,\r
-                         0,\r
-                         viewport.alignment.getWidth());\r
-    }\r
-\r
-    addTreeMenuItem(tp, title);\r
-    viewport.setCurrentTree(tp.getTree());\r
-\r
-    Desktop.addInternalFrame(tp, title + " from " + this.title, 600, 500);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param title DOCUMENT ME!\r
-   * @param order DOCUMENT ME!\r
-   */\r
-  public void addSortByOrderMenuItem(String title, 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
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        addHistoryItem(new HistoryItem("Sort", viewport.alignment,\r
-                                       HistoryItem.SORT));\r
-\r
-        // TODO: JBPNote - have to map order entries to curent SequenceI pointers\r
-        AlignmentSorter.sortBy(viewport.getAlignment(), order);\r
-        alignPanel.repaint();\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * Maintain the Order by->Displayed Tree menu.\r
-   * Creates a new menu item for a TreePanel with an appropriate\r
-   * <code>jalview.analysis.AlignmentSorter</code> call. Listeners are added\r
-   * to remove the menu item when the treePanel is closed, and adjust\r
-   * the tree leaf to sequence mapping when the alignment is modified.\r
-   * @param treePanel Displayed tree window.\r
-   * @param title SortBy menu item title.\r
-   */\r
-  void addTreeMenuItem(final TreePanel treePanel, String title)\r
-  {\r
-    final JMenuItem item = new JMenuItem(title);\r
-\r
-    treeCount++;\r
-\r
-    if (treeCount == 1)\r
-    {\r
-      sort.add(sortByTreeMenu);\r
-    }\r
-\r
-    sortByTreeMenu.add(item);\r
-    item.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        addHistoryItem(new HistoryItem("Tree Sort",\r
-                                       viewport.alignment, HistoryItem.SORT));\r
-        AlignmentSorter.sortByTree(viewport.getAlignment(),\r
-                                   treePanel.getTree());\r
-        alignPanel.repaint();\r
-      }\r
-    });\r
-\r
-    treePanel.addInternalFrameListener(new javax.swing.event.\r
-                                       InternalFrameAdapter()\r
-    {\r
-      public void internalFrameClosed(\r
-          javax.swing.event.InternalFrameEvent evt)\r
-      {\r
-        treeCount--;\r
-        sortByTreeMenu.remove(item);\r
-\r
-        if (treeCount == 0)\r
-        {\r
-          sort.remove(sortByTreeMenu);\r
-        }\r
-      }\r
-      ;\r
-    });\r
-    viewport.addPropertyChangeListener(new java.beans.PropertyChangeListener()\r
-    {\r
-      public void propertyChange(PropertyChangeEvent evt)\r
-      {\r
-        if (evt.getPropertyName().equals("alignment"))\r
-        {\r
-          treePanel.getTree().UpdatePlaceHolders( (Vector) evt.getNewValue());\r
-          treePanel.repaint();\r
-        }\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * Work out whether the whole set of sequences\r
-   * or just the selected set will be submitted for multiple alignment.\r
-   *\r
-   */\r
-  private SequenceI[] gatherSequencesForAlignment()\r
-  {\r
-    // Now, check we have enough sequences\r
-    SequenceI[] 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 some common interface!\r
-      SequenceGroup seqs = viewport.getSelectionGroup();\r
-      int sz;\r
-      msa = new SequenceI[sz = seqs.getSize()];\r
-\r
-      for (int i = 0; i < sz; i++)\r
-      {\r
-        msa[i] = (SequenceI) seqs.getSequenceAt(i);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      Vector seqs = viewport.getAlignment().getSequences();\r
-\r
-      if (seqs.size() > 1)\r
-      {\r
-        msa = new SequenceI[seqs.size()];\r
-\r
-        for (int i = 0; i < seqs.size(); i++)\r
-        {\r
-          msa[i] = (SequenceI) seqs.elementAt(i);\r
-        }\r
-      }\r
-    }\r
-    return msa;\r
-  }\r
-\r
-  /**\r
-   * Decides what is submitted to a secondary structure prediction service,\r
-   * the currently selected sequence, or the currently selected alignment\r
-   * (where the first sequence in the set is the one that the prediction\r
-   * will be for).\r
-   */\r
-  SequenceI[] gatherSeqOrMsaForSecStrPrediction()\r
-  {\r
-    SequenceI seq = null;\r
-    SequenceI[] msa = null;\r
-\r
-    if ( (viewport.getSelectionGroup() != null) &&\r
-        (viewport.getSelectionGroup().getSize() > 0))\r
-    {\r
-      // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to some common interface!\r
-      SequenceGroup seqs = viewport.getSelectionGroup();\r
-\r
-      if ( (seqs.getSize() == 1) || !viewport.alignment.isAligned())\r
-      {\r
-        seq = (SequenceI) seqs.getSequenceAt(0);\r
-      }\r
-      else\r
-      {\r
-        int sz;\r
-        msa = new SequenceI[sz = seqs.getSize()];\r
-\r
-        for (int i = 0; i < sz; i++)\r
-        {\r
-          msa[i] = (SequenceI) seqs.getSequenceAt(i);\r
-        }\r
-      }\r
-    }\r
-    else\r
-    {\r
-      Vector seqs = viewport.getAlignment().getSequences();\r
-\r
-      if ( (seqs.size() == 1) || !viewport.alignment.isAligned())\r
-      {\r
-        seq = (SequenceI) seqs.elementAt(0);\r
-      }\r
-      else\r
-      {\r
-        msa = new SequenceI[seqs.size()];\r
-\r
-        for (int i = 0; i < seqs.size(); i++)\r
-        {\r
-          msa[i] = (SequenceI) seqs.elementAt(i);\r
-        }\r
-      }\r
-    }\r
-    if (msa != null)\r
-    {\r
-      return msa;\r
-    }\r
-    else\r
-    {\r
-      if (seq != null)\r
-      {\r
-        return new SequenceI[]\r
-            {\r
-            seq};\r
-      }\r
-    }\r
-    return null;\r
-  }\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    // Pick the tree file\r
-    JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.\r
-        getProperty(\r
-            "LAST_DIRECTORY"));\r
-    chooser.setFileView(new JalviewFileView());\r
-    chooser.setDialogTitle("Select a newick-like tree file");\r
-    chooser.setToolTipText("Load a 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
-\r
-      try\r
-      {\r
-        jalview.io.NewickFile fin = new jalview.io.NewickFile(choice,\r
-            "File");\r
-        viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());\r
-      }\r
-      catch (Exception ex)\r
-      {\r
-        JOptionPane.showMessageDialog(Desktop.desktop,\r
-                                      "Problem reading tree file",\r
-                                      ex.getMessage(),\r
-                                      JOptionPane.WARNING_MESSAGE);\r
-        ex.printStackTrace();\r
-      }\r
-    }\r
-  }\r
-\r
-\r
-  public TreePanel ShowNewickTree(NewickFile nf, String title)\r
-  {\r
-    return ShowNewickTree(nf,title,600,500,4,5);\r
-  }\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param nf DOCUMENT ME!\r
-   * @param title DOCUMENT ME!\r
-   *\r
-   * @return DOCUMENT ME!\r
-   */\r
-  public TreePanel ShowNewickTree(NewickFile nf, String title, 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(viewport,\r
-                           viewport.getAlignment().getSequences(), nf,\r
-                           "FromFile",\r
-                           title);\r
-\r
-        tp.setSize(w,h);\r
-\r
-        if(x>0 && y>0)\r
-          tp.setLocation(x,y);\r
-\r
-\r
-        Desktop.addInternalFrame(tp, title, w, h);\r
-        addTreeMenuItem(tp, title);\r
-      }\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    }\r
-\r
-    return tp;\r
-  }\r
-\r
-  class PrintThread\r
-      extends Thread\r
-  {\r
-    public void run()\r
-    {\r
-      PrinterJob printJob = PrinterJob.getPrinterJob();\r
-      PageFormat pf = printJob.pageDialog(printJob.defaultPage());\r
-      printJob.setPrintable(alignPanel, pf);\r
-\r
-      if (printJob.printDialog())\r
-      {\r
-        try\r
-        {\r
-          printJob.print();\r
-        }\r
-        catch (Exception PrintException)\r
-        {\r
-          PrintException.printStackTrace();\r
-        }\r
-      }\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Generates menu items and listener event actions for web service clients\r
-   *\r
-   */\r
-  public void BuildWebServiceMenu()\r
-  {\r
-    if ( (Desktop.discoverer.services != null)\r
-        && (Desktop.discoverer.services.size() > 0))\r
-    {\r
-      Vector msaws = (Vector) Desktop.discoverer.services.get("MsaWS");\r
-      Vector secstrpr = (Vector) Desktop.discoverer.services.get("SecStrPred");\r
-      Vector wsmenu = new Vector();\r
-      if (msaws != null)\r
-      {\r
-        // Add any Multiple Sequence Alignment Services\r
-        final JMenu msawsmenu = new JMenu("Alignment");\r
-        for (int i = 0, j = msaws.size(); i < j; i++)\r
-        {\r
-          final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws.\r
-              get(i);\r
-          final JMenuItem method = new JMenuItem(sh.getName());\r
-          method.addActionListener(new ActionListener()\r
-          {\r
-            public void actionPerformed(ActionEvent e)\r
-            {\r
-              SequenceI[] msa = gatherSequencesForAlignment();\r
-              MsaWSClient ct = new jalview.ws.MsaWSClient(sh, title, msa,\r
-                  false, true);\r
-\r
-            }\r
-\r
-          });\r
-          msawsmenu.add(method);\r
-          // Deal with services that we know accept partial alignments.\r
-          if (sh.getName().indexOf("lustal") > -1)\r
-          {\r
-            // We know that ClustalWS can accept partial alignments for refinement.\r
-            final JMenuItem methodR = new JMenuItem(sh.getName()+" Realign");\r
-            methodR.addActionListener(new ActionListener()\r
-            {\r
-              public void actionPerformed(ActionEvent e)\r
-              {\r
-                SequenceI[] msa = gatherSequencesForAlignment();\r
-                MsaWSClient ct = new jalview.ws.MsaWSClient(sh, title, msa,\r
-                    true, true);\r
-\r
-              }\r
-\r
-            });\r
-            msawsmenu.add(methodR);\r
-\r
-          }\r
-        }\r
-        wsmenu.add(msawsmenu);\r
-      }\r
-      if (secstrpr != null)\r
-      {\r
-        // Add any secondary structure prediction services\r
-        final JMenu secstrmenu = new JMenu("Secondary Structure Prediction");\r
-        for (int i = 0, j = secstrpr.size(); i < j; i++)\r
-        {\r
-          final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle)\r
-              secstrpr.get(i);\r
-          final JMenuItem method = new JMenuItem(sh.getName());\r
-          method.addActionListener(new ActionListener()\r
-          {\r
-            public void actionPerformed(ActionEvent e)\r
-            {\r
-              SequenceI[] msa = gatherSeqOrMsaForSecStrPrediction();\r
-              if (msa.length == 1)\r
-              {\r
-                // Single Sequence prediction\r
-                jalview.ws.JPredClient ct = new jalview.ws.JPredClient(sh,\r
-                    title, msa[0]);\r
-              }\r
-              else\r
-              {\r
-                if (msa.length > 1)\r
-                {\r
-                  // Single Sequence prediction\r
-                  jalview.ws.JPredClient ct = new jalview.ws.JPredClient(sh,\r
-                      title, msa);\r
-                }\r
-              }\r
-            }\r
-          });\r
-          secstrmenu.add(method);\r
-        }\r
-        wsmenu.add(secstrmenu);\r
-      }\r
-      this.webService.removeAll();\r
-      for (int i = 0, j = wsmenu.size(); i < j; i++)\r
-      {\r
-        webService.add( (JMenu) wsmenu.get(i));\r
-      }\r
-    }\r
-    else\r
-    {\r
-      this.webService.removeAll();\r
-      this.webService.add(this.webServiceNoServices);\r
-    }\r
-    // TODO: add in rediscovery function\r
-    // TODO: reduce code redundancy.\r
-    // TODO: group services by location as well as function.\r
-  }\r
-\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
+ * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * 
+ * This program 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 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+package jalview.gui;
+
+import java.beans.*;
+import java.io.*;
+import java.util.*;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import java.awt.event.*;
+import java.awt.print.*;
+import javax.swing.*;
+import javax.swing.event.MenuEvent;
+
+import jalview.analysis.*;
+import jalview.commands.*;
+import jalview.datamodel.*;
+import jalview.io.*;
+import jalview.jbgui.*;
+import jalview.schemes.*;
+import jalview.ws.*;
+
+/**
+ * DOCUMENT ME!
+ * 
+ * @author $author$
+ * @version $Revision$
+ */
+public class AlignFrame extends GAlignFrame implements DropTargetListener,
+        IProgressIndicator
+{
+
+  /** DOCUMENT ME!! */
+  public static final int DEFAULT_WIDTH = 700;
+
+  /** DOCUMENT ME!! */
+  public static final int DEFAULT_HEIGHT = 500;
+
+  public AlignmentPanel alignPanel;
+
+  AlignViewport viewport;
+
+  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);
+    viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId);
+
+    alignPanel = new AlignmentPanel(this, viewport);
+
+    if (al.getDataset() == null)
+    {
+      al.setDataset(null);
+    }
+
+    addAlignmentPanel(alignPanel, true);
+    init();
+  }
+
+  /**
+   * Make a new AlignFrame from exisiting 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()
+  {
+    if (viewport.conservation == 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.alignment.isNucleotide());
+    }
+
+    setMenusFromViewport(viewport);
+    buildSortByAnnotationScoresMenu();
+    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()
+    {
+      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_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("Keyboard editing mode is "
+                  + (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
+          {
+            ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
+            java.net.URL url = javax.help.HelpSet.findHelpSet(cl,
+                    "help/help");
+            javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
+
+            javax.help.HelpBroker hb = hs.createHelpBroker();
+            hb.setCurrentID("home");
+            hb.setDisplayed(true);
+          } catch (Exception ex)
+          {
+            ex.printStackTrace();
+          }
+          break;
+        case KeyEvent.VK_H:
+        {
+          boolean toggleSeqs = !evt.isControlDown();
+          boolean toggleCols = !evt.isShiftDown();
+
+          boolean hide = false;
+
+          SequenceGroup sg = viewport.getSelectionGroup();
+          if (toggleSeqs)
+          {
+            if (sg != null
+                    && sg.getSize() != viewport.alignment.getHeight())
+            {
+              hideSelSequences_actionPerformed(null);
+              hide = true;
+            }
+            else if (!(toggleCols && viewport.colSel.getSelected().size() > 0))
+            {
+              showAllSeqs_actionPerformed(null);
+            }
+          }
+
+          if (toggleCols)
+          {
+            if (viewport.colSel.getSelected().size() > 0)
+            {
+              hideSelColumns_actionPerformed(null);
+              if (!toggleSeqs)
+              {
+                viewport.selectionGroup = sg;
+              }
+            }
+            else if (!hide)
+            {
+              showAllColumns_actionPerformed(null);
+            }
+          }
+          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;
+        }
+      }
+
+      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;
+
+    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.padGaps)
+      {
+        ap.av.alignment.padGaps();
+      }
+      ap.av.updateConservation(ap);
+      ap.av.updateConsensus(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;
+    // Do this once to get current state
+    BuildWebServiceMenu();
+    Desktop.discoverer
+            .addPropertyChangeListener(thisListener = new java.beans.PropertyChangeListener()
+            {
+              public void propertyChange(PropertyChangeEvent evt)
+              {
+                // System.out.println("Discoverer property change.");
+                if (evt.getPropertyName().equals("services"))
+                {
+                  // System.out.println("Rebuilding web service menu");
+                  BuildWebServiceMenu();
+                }
+              }
+            });
+
+    addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+    {
+      public void internalFrameClosed(
+              javax.swing.event.InternalFrameEvent evt)
+      {
+        // System.out.println("deregistering discoverer listener");
+        Desktop.discoverer.removePropertyChangeListener(thisListener);
+        closeMenuItem_actionPerformed(true);
+      };
+    });
+  }
+
+  public void setGUINucleotide(boolean nucleotide)
+  {
+    showTranslation.setVisible(nucleotide);
+    conservationMenuItem.setEnabled(!nucleotide);
+    modifyConservation.setEnabled(!nucleotide);
+
+    // Remember AlignFrame always starts as protein
+    if (!nucleotide)
+    {
+      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.padGaps);
+    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);
+    viewBoxesMenuItem.setSelected(av.showBoxes);
+    viewTextMenuItem.setSelected(av.showText);
+
+    setColourSelected(ColourSchemeProperty.getColourName(av
+            .getGlobalColourScheme()));
+
+    showSeqFeatures.setSelected(av.showSequenceFeatures);
+    hiddenMarkers.setState(av.showHiddenMarkers);
+    applyToAllGroups.setState(av.colourAppliesToAllGroups);
+    showNpFeatsMenuitem.setSelected(av.isShowNpFeats());
+    showDbRefsMenuitem.setSelected(av.isShowDbRefs());
+
+    setShowProductsEnabled();
+
+    updateEditMenuBar();
+  }
+
+  Hashtable progressBars;
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
+   */
+  public void setProgressBar(String message, long id)
+  {
+    if (progressBars == null)
+    {
+      progressBars = new Hashtable();
+    }
+
+    JPanel progressPanel;
+    GridLayout layout = (GridLayout) statusPanel.getLayout();
+    if (progressBars.get(new Long(id)) != null)
+    {
+      progressPanel = (JPanel) progressBars.get(new Long(id));
+      statusPanel.remove(progressPanel);
+      progressBars.remove(progressPanel);
+      progressPanel = null;
+      if (message != null)
+      {
+        statusBar.setText(message);
+      }
+
+      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(new Long(id), progressPanel);
+    }
+    // update GUI
+    setMenusForViewport();
+    validate();
+  }
+
+  /**
+   * 
+   * @return true if any progress bars are still active
+   */
+  public boolean operationInProgress()
+  {
+    if (progressBars != null && progressBars.size() > 0)
+    {
+      return true;
+    }
+    return false;
+  }
+
+  /*
+   * 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();
+  }
+
+  public void fetchSequence_actionPerformed(ActionEvent e)
+  {
+    new SequenceFetcher(this);
+  }
+
+  public void addFromFile_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);
+  }
+
+  public void reload_actionPerformed(ActionEvent e)
+  {
+    if (fileName != null)
+    {
+      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.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);
+
+        this.closeMenuItem_actionPerformed(true);
+      }
+    }
+  }
+
+  public void addFromText_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
+  }
+
+  public void addFromURL_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputURLMenuItem_actionPerformed(viewport);
+  }
+
+  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!
+   */
+  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("Save Alignment to file");
+    chooser.setToolTipText("Save");
+
+    int value = chooser.showSaveDialog(this);
+
+    if (value == JalviewFileChooser.APPROVE_OPTION)
+    {
+      currentFileFormat = chooser.getSelectedFormat();
+      if (currentFileFormat == null)
+      {
+        JOptionPane.showInternalMessageDialog(Desktop.desktop,
+                "You must select a file format before saving!",
+                "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("Successfully saved to file: " + fileName + " in "
+              + format + " format.");
+
+    }
+    else
+    {
+      if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
+      {
+        // JBPNote need to have a raise_gui flag here
+        JOptionPane.showInternalMessageDialog(this, "Cannot save file "
+                + fileName + " using format " + format,
+                "Alignment output format not supported",
+                JOptionPane.WARNING_MESSAGE);
+        saveAs_actionPerformed(null);
+        return false;
+      }
+
+      String[] omitHidden = null;
+
+      if (viewport.hasHiddenColumns)
+      {
+        int reply = JOptionPane
+                .showInternalConfirmDialog(
+                        Desktop.desktop,
+                        "The Alignment contains hidden columns."
+                                + "\nDo you want to save only the visible alignment?",
+                        "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,
+              (Alignment) viewport.alignment, // class cast exceptions will
+              // occur in the distant future
+              omitHidden, f.getCacheSuffixDefault(format), viewport.colSel);
+
+      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("Successfully saved to file: " + fileName
+                  + " in " + format + " format.");
+        } catch (Exception ex)
+        {
+          success = false;
+          ex.printStackTrace();
+        }
+      }
+    }
+
+    if (!success)
+    {
+      JOptionPane.showInternalMessageDialog(this, "Couldn't save file: "
+              + fileName, "Error Saving File", JOptionPane.WARNING_MESSAGE);
+    }
+
+    return success;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void outputText_actionPerformed(ActionEvent e)
+  {
+    String[] omitHidden = null;
+
+    if (viewport.hasHiddenColumns)
+    {
+      int reply = JOptionPane
+              .showInternalConfirmDialog(
+                      Desktop.desktop,
+                      "The Alignment contains hidden columns."
+                              + "\nDo you want to output only the visible alignment?",
+                      "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);
+    Desktop.addInternalFrame(cap, "Alignment output - "
+            + e.getActionCommand(), 600, 500);
+
+    cap.setText(new FormatAdapter().formatSequences(e.getActionCommand(),
+            viewport.alignment, omitHidden, viewport.colSel));
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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!
+   */
+  public void createPNG(File f)
+  {
+    alignPanel.makePNG(f);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void createEPS(File f)
+  {
+    alignPanel.makeEPS(f);
+  }
+
+  public void pageSetup_actionPerformed(ActionEvent e)
+  {
+    PrinterJob printJob = PrinterJob.getPrinterJob();
+    PrintThread.pf = printJob.pageDialog(printJob.defaultPage());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void printMenuItem_actionPerformed(ActionEvent e)
+  {
+    // Putting in a thread avoids Swing painting problems
+    PrintThread thread = new PrintThread(alignPanel);
+    thread.start();
+  }
+
+  public void exportFeatures_actionPerformed(ActionEvent e)
+  {
+    new AnnotationExporter().exportFeatures(alignPanel);
+  }
+
+  public void exportAnnotations_actionPerformed(ActionEvent e)
+  {
+    new AnnotationExporter().exportAnnotations(alignPanel,
+            viewport.showAnnotation ? viewport.alignment
+                    .getAlignmentAnnotation() : null, viewport.alignment
+                    .getGroups(),
+            ((Alignment) viewport.alignment).alignmentProperties);
+  }
+
+  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("Load Jalview Annotations or Features File");
+    chooser.setToolTipText("Load Jalview Annotations / Features file");
+
+    int value = chooser.showOpenDialog(null);
+
+    if (value == JalviewFileChooser.APPROVE_OPTION)
+    {
+      String choice = chooser.getSelectedFile().getPath();
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
+      loadJalviewDataFile(choice);
+    }
+
+  }
+
+  /**
+   * 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 
+   */
+  public void closeMenuItem_actionPerformed(boolean closeAllTabs)
+  {
+    if (alignPanels != null && alignPanels.size() < 2)
+    {
+      closeAllTabs = true;
+    }
+
+    try
+    {
+      if (alignPanels != null)
+      {
+        if (closeAllTabs)
+        {
+          for (int i = 0; i < alignPanels.size(); i++)
+          {
+            AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i);
+            jalview.structure.StructureSelectionManager ssm = 
+              jalview.structure.StructureSelectionManager
+                    .getStructureSelectionManager();
+            ssm.removeStructureViewerListener(ap.seqPanel, null);
+            ssm.removeSelectionListener(ap.seqPanel);
+            PaintRefresher.RemoveComponent(ap.seqPanel.seqCanvas);
+            PaintRefresher.RemoveComponent(ap.idPanel.idCanvas);
+            PaintRefresher.RemoveComponent(ap);
+            ap.av.alignment = null;
+          }
+        }
+        else
+        {
+          closeView(alignPanel);
+          viewport = null;
+        }
+      }
+
+      if (closeAllTabs)
+      {
+        this.setClosed(true);
+      }
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+  }
+
+  public void closeView(AlignmentPanel alignPanel2)
+  {
+    int index = tabbedPane.getSelectedIndex();
+    int closedindex = tabbedPane.indexOfComponent(alignPanel2);
+    alignPanels.removeElement(alignPanel2);
+    PaintRefresher.RemoveComponent(alignPanel2.seqPanel.seqCanvas);
+    PaintRefresher.RemoveComponent(alignPanel2.idPanel.idCanvas);
+    PaintRefresher.RemoveComponent(alignPanel2);
+    alignPanel2.av.alignment = null;
+    
+    if (viewport == alignPanel2.av)
+    {
+      viewport = null;
+    }
+    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 = (CommandI) viewport.historyList.peek();
+      undoMenuItem.setText("Undo " + command.getDescription());
+    }
+    else
+    {
+      undoMenuItem.setEnabled(false);
+      undoMenuItem.setText("Undo");
+    }
+
+    if (viewport.redoList.size() > 0)
+    {
+      redoMenuItem.setEnabled(true);
+
+      CommandI command = (CommandI) viewport.redoList.peek();
+      redoMenuItem.setText("Redo " + command.getDescription());
+    }
+    else
+    {
+      redoMenuItem.setEnabled(false);
+      redoMenuItem.setText("Redo");
+    }
+  }
+
+  public void addHistoryItem(CommandI command)
+  {
+    if (command.getSize() > 0)
+    {
+      viewport.historyList.push(command);
+      viewport.redoList.clear();
+      updateEditMenuBar();
+      viewport.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
+    }
+  }
+
+  /**
+   * 
+   * @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.alignment };
+    }
+    return null;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void undoMenuItem_actionPerformed(ActionEvent e)
+  {
+    if (viewport.historyList.empty())
+      return;
+    CommandI command = (CommandI) viewport.historyList.pop();
+    viewport.redoList.push(command);
+    command.undoCommand(getViewAlignments());
+
+    AlignViewport originalSource = getOriginatingSource(command);
+    updateEditMenuBar();
+
+    if (originalSource != null)
+    {
+      originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
+      originalSource.firePropertyChange("alignment", null,
+              originalSource.alignment.getSequences());
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void redoMenuItem_actionPerformed(ActionEvent e)
+  {
+    if (viewport.redoList.size() < 1)
+    {
+      return;
+    }
+
+    CommandI command = (CommandI) viewport.redoList.pop();
+    viewport.historyList.push(command);
+    command.doCommand(getViewAlignments());
+
+    AlignViewport originalSource = getOriginatingSource(command);
+    updateEditMenuBar();
+
+    if (originalSource != null)
+    {
+      originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
+      originalSource.firePropertyChange("alignment", null,
+              originalSource.alignment.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.alignment)
+          {
+            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.alignment);
+      }
+
+      originalSource = viewport;
+    }
+
+    return originalSource;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param up
+   *                DOCUMENT ME!
+   */
+  public void moveSelectedSequences(boolean up)
+  {
+    SequenceGroup sg = viewport.getSelectionGroup();
+
+    if (sg == null)
+    {
+      return;
+    }
+
+    if (up)
+    {
+      for (int i = 1; i < viewport.alignment.getHeight(); i++)
+      {
+        SequenceI seq = viewport.alignment.getSequenceAt(i);
+
+        if (!sg.getSequences(null).contains(seq))
+        {
+          continue;
+        }
+
+        SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
+
+        if (sg.getSequences(null).contains(temp))
+        {
+          continue;
+        }
+
+        viewport.alignment.getSequences().setElementAt(temp, i);
+        viewport.alignment.getSequences().setElementAt(seq, i - 1);
+      }
+    }
+    else
+    {
+      for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)
+      {
+        SequenceI seq = viewport.alignment.getSequenceAt(i);
+
+        if (!sg.getSequences(null).contains(seq))
+        {
+          continue;
+        }
+
+        SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
+
+        if (sg.getSequences(null).contains(temp))
+        {
+          continue;
+        }
+
+        viewport.alignment.getSequences().setElementAt(temp, i);
+        viewport.alignment.getSequences().setElementAt(seq, i + 1);
+      }
+    }
+
+    alignPanel.paintAlignment(true);
+  }
+
+  synchronized void slideSequences(boolean right, int size)
+  {
+    Vector sg = new Vector();
+    if (viewport.cursorMode)
+    {
+      sg.addElement(viewport.alignment
+              .getSequenceAt(alignPanel.seqPanel.seqCanvas.cursorY));
+    }
+    else if (viewport.getSelectionGroup() != null
+            && viewport.getSelectionGroup().getSize() != viewport.alignment
+                    .getHeight())
+    {
+      sg = viewport.getSelectionGroup().getSequences(
+              viewport.hiddenRepSequences);
+    }
+
+    if (sg.size() < 1)
+    {
+      return;
+    }
+
+    Vector invertGroup = new Vector();
+
+    for (int i = 0; i < viewport.alignment.getHeight(); i++)
+    {
+      if (!sg.contains(viewport.alignment.getSequenceAt(i)))
+        invertGroup.add(viewport.alignment.getSequenceAt(i));
+    }
+
+    SequenceI[] seqs1 = new SequenceI[sg.size()];
+    for (int i = 0; i < sg.size(); i++)
+      seqs1[i] = (SequenceI) sg.elementAt(i);
+
+    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!
+   */
+  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();
+      for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()
+              .size(); i++)
+      {
+        int[] region = (int[]) viewport.getColumnSelection()
+                .getHiddenColumns().elementAt(i);
+
+        hiddenColumns.addElement(new int[]
+        { region[0] - hiddenOffset, region[1] - hiddenOffset });
+      }
+    }
+
+    Desktop.jalviewClipboard = new Object[]
+    { seqs, viewport.alignment.getDataset(), hiddenColumns };
+    statusBar.setText("Copied " + seqs.length + " sequences to clipboard.");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void pasteNew_actionPerformed(ActionEvent e)
+  {
+    paste(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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;
+
+      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 (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]);
+              newann.padAnnotation(alwidth);
+              alignment.addAnnotation(newann);
+            }
+          }
+        }
+      }
+      if (!newAlignment)
+      {
+        // /////
+        // ADD HISTORY ITEM
+        //
+        addHistoryItem(new EditCommand("Add sequences", EditCommand.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)
+        {
+          for (int a = 0; a < sequences[i].getAnnotation().length; a++)
+          {
+            annotationAdded = true;
+            sequences[i].getAnnotation()[a].adjustForAlignment();
+            sequences[i].getAnnotation()[a].padAnnotation(alwidth);
+            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
+                  alview[avnum].setAnnotationIndex(newann, a);
+                }
+              }
+            }
+          }
+          buildSortByAnnotationScoresMenu();
+        }
+        viewport.firePropertyChange("alignment", null, alignment
+                .getSequences());
+
+      }
+      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
+    }
+
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void cut_actionPerformed(ActionEvent e)
+  {
+    copy_actionPerformed(null);
+    delete_actionPerformed(null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void delete_actionPerformed(ActionEvent evt)
+  {
+
+    SequenceGroup sg = viewport.getSelectionGroup();
+    if (sg == null)
+    {
+      return;
+    }
+
+    Vector seqs = new Vector();
+    SequenceI seq;
+    for (int i = 0; i < sg.getSize(); i++)
+    {
+      seq = sg.getSequenceAt(i);
+      seqs.addElement(seq);
+    }
+
+    // If the cut affects all sequences, remove highlighted columns
+    if (sg.getSize() == viewport.alignment.getHeight())
+    {
+      viewport.getColumnSelection().removeElements(sg.getStartRes(),
+              sg.getEndRes() + 1);
+    }
+
+    SequenceI[] cut = new SequenceI[seqs.size()];
+    for (int i = 0; i < seqs.size(); i++)
+    {
+      cut[i] = (SequenceI) seqs.elementAt(i);
+    }
+
+    /*
+     * //ADD HISTORY ITEM
+     */
+    addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,
+            sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
+            viewport.alignment));
+
+    viewport.setSelectionGroup(null);
+    viewport.sendSelection();
+    viewport.alignment.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!
+   */
+  protected void deleteGroups_actionPerformed(ActionEvent e)
+  {
+    viewport.alignment.deleteAllGroups();
+    viewport.sequenceColours = null;
+    viewport.setSelectionGroup(null);
+    PaintRefresher.Refresh(this, viewport.getSequenceSetId());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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.alignment.getWidth() - 1);
+    viewport.setSelectionGroup(sg);
+    viewport.sendSelection();
+    alignPanel.paintAlignment(true);
+    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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);
+    viewport.sendSelection();
+    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
+  }
+
+  public void invertColSel_actionPerformed(ActionEvent e)
+  {
+    viewport.invertColumnSelection();
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
+  {
+    trimAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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.hiddenRepSequences);
+      }
+      else
+      {
+        seqs = viewport.alignment.getSequencesArray();
+      }
+
+      TrimRegionCommand trimRegion;
+      if (trimLeft)
+      {
+        trimRegion = new TrimRegionCommand("Remove Left",
+                TrimRegionCommand.TRIM_LEFT, seqs, column,
+                viewport.alignment, viewport.colSel,
+                viewport.selectionGroup);
+        viewport.setStartRes(0);
+      }
+      else
+      {
+        trimRegion = new TrimRegionCommand("Remove Right",
+                TrimRegionCommand.TRIM_RIGHT, seqs, column,
+                viewport.alignment, viewport.colSel,
+                viewport.selectionGroup);
+      }
+
+      statusBar.setText("Removed " + trimRegion.getSize() + " columns.");
+
+      addHistoryItem(trimRegion);
+
+      Vector groups = viewport.alignment.getGroups();
+
+      for (int i = 0; i < groups.size(); i++)
+      {
+        SequenceGroup sg = (SequenceGroup) groups.get(i);
+
+        if ((trimLeft && !sg.adjustForRemoveLeft(column))
+                || (!trimLeft && !sg.adjustForRemoveRight(column)))
+        {
+          viewport.alignment.deleteGroup(sg);
+        }
+      }
+
+      viewport.firePropertyChange("alignment", null, viewport
+              .getAlignment().getSequences());
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
+  {
+    int start = 0, end = viewport.alignment.getWidth() - 1;
+
+    SequenceI[] seqs;
+    if (viewport.getSelectionGroup() != null)
+    {
+      seqs = viewport.getSelectionGroup().getSequencesAsArray(
+              viewport.hiddenRepSequences);
+      start = viewport.getSelectionGroup().getStartRes();
+      end = viewport.getSelectionGroup().getEndRes();
+    }
+    else
+    {
+      seqs = viewport.alignment.getSequencesArray();
+    }
+
+    RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
+            "Remove Gapped Columns", seqs, start, end, viewport.alignment);
+
+    addHistoryItem(removeGapCols);
+
+    statusBar.setText("Removed " + removeGapCols.getSize()
+            + " empty columns.");
+
+    // This is to maintain viewport position on first residue
+    // of first sequence
+    SequenceI seq = viewport.alignment.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!
+   */
+  public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
+  {
+    int start = 0, end = viewport.alignment.getWidth() - 1;
+
+    SequenceI[] seqs;
+    if (viewport.getSelectionGroup() != null)
+    {
+      seqs = viewport.getSelectionGroup().getSequencesAsArray(
+              viewport.hiddenRepSequences);
+      start = viewport.getSelectionGroup().getStartRes();
+      end = viewport.getSelectionGroup().getEndRes();
+    }
+    else
+    {
+      seqs = viewport.alignment.getSequencesArray();
+    }
+
+    // This is to maintain viewport position on first residue
+    // of first sequence
+    SequenceI seq = viewport.alignment.getSequenceAt(0);
+    int startRes = seq.findPosition(viewport.startRes);
+
+    addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
+            viewport.alignment));
+
+    viewport.setStartRes(seq.findIndex(startRes) - 1);
+
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
+            .getSequences());
+
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void padGapsMenuitem_actionPerformed(ActionEvent e)
+  {
+    viewport.padGaps = padGapsMenuitem.isSelected();
+
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment()
+            .getSequences());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void findMenuItem_actionPerformed(ActionEvent e)
+  {
+    new Finder();
+  }
+
+  public void newView_actionPerformed(ActionEvent e)
+  {
+    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
+            true);
+
+    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());
+    String newViewName = "View " + 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 = "View " + (++index);
+    }
+
+    newap.av.viewName = newViewName;
+
+    addAlignmentPanel(newap, true);
+
+    if (alignPanels.size() == 2)
+    {
+      viewport.gatherViewsHere = true;
+    }
+    tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
+  }
+
+  public void expandViews_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.explodeViews(this);
+  }
+
+  public void gatherViews_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.gatherViews(this);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void font_actionPerformed(ActionEvent e)
+  {
+    new FontChooser(alignPanel);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void seqLimit_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowJVSuffix(seqLimits.isSelected());
+
+    alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
+            .calculateIdWidth());
+    alignPanel.paintAlignment(true);
+  }
+
+  public void idRightAlign_actionPerformed(ActionEvent e)
+  {
+    viewport.rightAlignIds = idRightAlign.isSelected();
+    alignPanel.paintAlignment(true);
+  }
+
+  public void centreColumnLabels_actionPerformed(ActionEvent e)
+  {
+    viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
+    alignPanel.paintAlignment(true);
+  }
+  /* (non-Javadoc)
+   * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
+   */
+  protected void followHighlight_actionPerformed()
+  {
+    if (viewport.followHighlight = this.followHighlightMenuItem.getState())
+    {
+      alignPanel.scrollToPosition(alignPanel.seqPanel.seqCanvas.searchResults, false);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void colourTextMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setColourText(colourTextMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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());
+  }
+
+  public void showAllSeqs_actionPerformed(ActionEvent e)
+  {
+    viewport.showAllHiddenSeqs();
+  }
+
+  public void showAllColumns_actionPerformed(ActionEvent e)
+  {
+    viewport.showAllHiddenColumns();
+    repaint();
+  }
+
+  public void hideSelSequences_actionPerformed(ActionEvent e)
+  {
+    viewport.hideAllSelectedSeqs();
+    alignPanel.paintAlignment(true);
+  }
+
+  public void hideSelColumns_actionPerformed(ActionEvent e)
+  {
+    viewport.hideSelectedColumns();
+    alignPanel.paintAlignment(true);
+  }
+
+  public void hiddenMarkers_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
+    repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void scaleAbove_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleAboveWrapped(scaleAbove.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void scaleLeft_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleLeftWrapped(scaleLeft.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void scaleRight_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleRightWrapped(scaleRight.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void viewTextMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowText(viewTextMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setRenderGaps(renderGapsMenuItem.isSelected());
+    alignPanel.paintAlignment(true);
+  }
+
+  public FeatureSettings featureSettings;
+
+  public void featureSettings_actionPerformed(ActionEvent e)
+  {
+    if (featureSettings != null)
+    {
+      featureSettings.close();
+      featureSettings = null;
+    }
+    featureSettings = new FeatureSettings(this);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param evt
+   *                DOCUMENT ME!
+   */
+  public void showSeqFeatures_actionPerformed(ActionEvent evt)
+  {
+    viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
+    alignPanel.paintAlignment(true);
+    if (alignPanel.getOverviewPanel() != null)
+    {
+      alignPanel.getOverviewPanel().updateOverviewImage();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
+    alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
+  }
+
+  public void alignmentProperties()
+  {
+    JEditorPane editPane = new JEditorPane("text/html", "");
+    editPane.setEditable(false);
+    StringBuffer contents = new StringBuffer("<html>");
+
+    float avg = 0;
+    int min = Integer.MAX_VALUE, max = 0;
+    for (int i = 0; i < viewport.alignment.getHeight(); i++)
+    {
+      int size = viewport.alignment.getSequenceAt(i).getEnd()
+              - viewport.alignment.getSequenceAt(i).getStart();
+      avg += size;
+      if (size > max)
+        max = size;
+      if (size < min)
+        min = size;
+    }
+    avg = avg / (float) viewport.alignment.getHeight();
+
+    contents.append("<br>Sequences: " + viewport.alignment.getHeight());
+    contents.append("<br>Minimum Sequence Length: " + min);
+    contents.append("<br>Maximum Sequence Length: " + max);
+    contents.append("<br>Average Length: " + (int) avg);
+
+    if (((Alignment) viewport.alignment).getProperties() != null)
+    {
+      Hashtable props = ((Alignment) viewport.alignment).getProperties();
+      Enumeration en = props.keys();
+      contents.append("<br><br><table border=\"1\">");
+      while (en.hasMoreElements())
+      {
+        String key = en.nextElement().toString();
+        StringBuffer val = new StringBuffer();
+        String vals = props.get(key).toString();
+        int pos = 0, npos;
+        do
+        {
+          npos = vals.indexOf("\n", pos);
+          if (npos == -1)
+          {
+            val.append(vals.substring(pos));
+          }
+          else
+          {
+            val.append(vals.substring(pos, npos));
+            val.append("<br>");
+          }
+          pos = npos + 1;
+        } while (npos != -1);
+        contents
+                .append("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
+      }
+      contents.append("</table>");
+    }
+    editPane.setText(contents.toString() + "</html>");
+    JInternalFrame frame = new JInternalFrame();
+    frame.getContentPane().add(new JScrollPane(editPane));
+
+    Desktop.instance.addInternalFrame(frame, "Alignment Properties: "
+            + getTitle(), 500, 400);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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, "Overview " + this.getTitle(), frame
+            .getWidth(), frame.getHeight());
+    frame.pack();
+    frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    frame
+            .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+            {
+              public void internalFrameClosed(
+                      javax.swing.event.InternalFrameEvent evt)
+              {
+                alignPanel.setOverviewPanel(null);
+              };
+            });
+
+    alignPanel.setOverviewPanel(overview);
+  }
+
+  public void textColour_actionPerformed(ActionEvent e)
+  {
+    new TextColourChooser().chooseColour(alignPanel, null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void noColourmenuItem_actionPerformed(ActionEvent e)
+  {
+    changeColour(null);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void clustalColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new ClustalxColourScheme(
+            viewport.alignment.getSequences(), viewport.alignment
+                    .getWidth()));
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void zappoColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new ZappoColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void taylorColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new TaylorColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void hydrophobicityColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new HydrophobicColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void helixColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new HelixColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void strandColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new StrandColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void turnColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new TurnColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void buriedColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new BuriedColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void nucleotideColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new NucleotideColourScheme());
+  }
+
+  public void annotationColour_actionPerformed(ActionEvent e)
+  {
+    new AnnotationColourChooser(viewport, alignPanel);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void applyToAllGroups_actionPerformed(ActionEvent e)
+  {
+    viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param cs
+   *                DOCUMENT ME!
+   */
+  public void changeColour(ColourSchemeI cs)
+  {
+    int threshold = 0;
+
+    if (cs != null)
+    {
+      if (viewport.getAbovePIDThreshold())
+      {
+        threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
+                "Background");
+
+        cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
+
+        viewport.setGlobalColourScheme(cs);
+      }
+      else
+      {
+        cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
+      }
+
+      if (viewport.getConservationSelected())
+      {
+
+        Alignment al = (Alignment) viewport.alignment;
+        Conservation c = new Conservation("All",
+                ResidueProperties.propHash, 3, al.getSequences(), 0, al
+                        .getWidth() - 1);
+
+        c.calculate();
+        c.verdict(false, viewport.ConsPercGaps);
+
+        cs.setConservation(c);
+
+        cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
+                cs, "Background"));
+      }
+      else
+      {
+        cs.setConservation(null);
+      }
+
+      cs.setConsensus(viewport.hconsensus);
+    }
+
+    viewport.setGlobalColourScheme(cs);
+
+    if (viewport.getColourAppliesToAllGroups())
+    {
+      Vector groups = viewport.alignment.getGroups();
+
+      for (int i = 0; i < groups.size(); i++)
+      {
+        SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
+
+        if (cs == null)
+        {
+          sg.cs = null;
+          continue;
+        }
+
+        if (cs instanceof ClustalxColourScheme)
+        {
+          sg.cs = new ClustalxColourScheme(sg
+                  .getSequences(viewport.hiddenRepSequences), sg.getWidth());
+        }
+        else if (cs instanceof UserColourScheme)
+        {
+          sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
+        }
+        else
+        {
+          try
+          {
+            sg.cs = (ColourSchemeI) 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.hiddenRepSequences), 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.hiddenRepSequences), sg
+                          .getStartRes(), sg.getEndRes() + 1);
+          c.calculate();
+          c.verdict(false, viewport.ConsPercGaps);
+          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!
+   */
+  protected void modifyPID_actionPerformed(ActionEvent e)
+  {
+    if (viewport.getAbovePIDThreshold()
+            && viewport.globalColourScheme != null)
+    {
+      SliderPanel.setPIDSliderSource(alignPanel, viewport
+              .getGlobalColourScheme(), "Background");
+      SliderPanel.showPIDSlider();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void modifyConservation_actionPerformed(ActionEvent e)
+  {
+    if (viewport.getConservationSelected()
+            && viewport.globalColourScheme != null)
+    {
+      SliderPanel.setConservationSlider(alignPanel,
+              viewport.globalColourScheme, "Background");
+      SliderPanel.showConservationSlider();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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!
+   */
+  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!
+   */
+  public void userDefinedColour_actionPerformed(ActionEvent e)
+  {
+    if (e.getActionCommand().equals("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()
+        {
+          public void mousePressed(MouseEvent evt)
+          {
+            if (evt.isControlDown()
+                    || SwingUtilities.isRightMouseButton(evt))
+            {
+              radioItem
+                      .removeActionListener(radioItem.getActionListeners()[0]);
+
+              int option = JOptionPane.showInternalConfirmDialog(
+                      jalview.gui.Desktop.desktop,
+                      "Remove from default list?",
+                      "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()
+                {
+                  public void actionPerformed(ActionEvent evt)
+                  {
+                    userDefinedColour_actionPerformed(evt);
+                  }
+                });
+              }
+            }
+          }
+        });
+        radioItem.addActionListener(new ActionListener()
+        {
+          public void actionPerformed(ActionEvent evt)
+          {
+            userDefinedColour_actionPerformed(evt);
+          }
+        });
+
+        colourMenu.insert(radioItem, 15);
+        colours.add(radioItem);
+      }
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void PIDColour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new PIDColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void BLOSUM62Colour_actionPerformed(ActionEvent e)
+  {
+    changeColour(new Blosum62ColourScheme());
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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.alignment));
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void sortIDMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByID(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("ID Sort", oldOrder, viewport.alignment));
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void sortGroupMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByGroup(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.alignment));
+
+    alignPanel.paintAlignment(true);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
+  {
+    new RedundancyPanel(alignPanel, this);
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
+  {
+    if ((viewport.getSelectionGroup() == null)
+            || (viewport.getSelectionGroup().getSize() < 2))
+    {
+      JOptionPane.showInternalMessageDialog(this,
+              "You must select at least 2 sequences.", "Invalid Selection",
+              JOptionPane.WARNING_MESSAGE);
+    }
+    else
+    {
+      JInternalFrame frame = new JInternalFrame();
+      frame.setContentPane(new PairwiseAlignPanel(viewport));
+      Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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,
+              "Principal component analysis must take\n"
+                      + "at least 4 input sequences.",
+              "Sequence selection insufficient",
+              JOptionPane.WARNING_MESSAGE);
+
+      return;
+    }
+
+    new PCAPanel(alignPanel);
+  }
+
+  public void autoCalculate_actionPerformed(ActionEvent e)
+  {
+    viewport.autoCalculateConsensus = autoCalculate.isSelected();
+    if (viewport.autoCalculateConsensus)
+    {
+      viewport.firePropertyChange("alignment", null, viewport
+              .getAlignment().getSequences());
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
+  {
+    NewTreePanel("AV", "PID", "Average distance tree using PID");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
+  {
+    NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
+  {
+    NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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)
+    {
+      if (viewport.getSelectionGroup().getSize() < 3)
+      {
+        JOptionPane
+                .showMessageDialog(
+                        Desktop.desktop,
+                        "You need to have more than two sequences selected to build a tree!",
+                        "Not enough sequences", JOptionPane.WARNING_MESSAGE);
+        return;
+      }
+
+      int s = 0;
+      SequenceGroup sg = viewport.getSelectionGroup();
+
+      /* Decide if the selection is a column region */
+      while (s < sg.getSize())
+      {
+        if (((SequenceI) sg.getSequences(null).elementAt(s++)).getLength() < sg
+                .getEndRes())
+        {
+          JOptionPane
+                  .showMessageDialog(
+                          Desktop.desktop,
+                          "The selected region to create a tree may\nonly contain residues or gaps.\n"
+                                  + "Try using the Pad function in the edit menu,\n"
+                                  + "or one of the multiple sequence alignment web services.",
+                          "Sequences in selection are not aligned",
+                          JOptionPane.WARNING_MESSAGE);
+
+          return;
+        }
+      }
+
+      title = title + " on region";
+      tp = new TreePanel(alignPanel, type, pwType);
+    }
+    else
+    {
+      // are the sequences aligned?
+      if (!viewport.alignment.isAligned())
+      {
+        JOptionPane
+                .showMessageDialog(
+                        Desktop.desktop,
+                        "The sequences must be aligned before creating a tree.\n"
+                                + "Try using the Pad function in the edit menu,\n"
+                                + "or one of the multiple sequence alignment web services.",
+                        "Sequences not aligned",
+                        JOptionPane.WARNING_MESSAGE);
+
+        return;
+      }
+
+      if (viewport.alignment.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("by " + title);
+    sort.add(item);
+    item.addActionListener(new java.awt.event.ActionListener()
+    {
+      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.alignment));
+
+        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()
+    {
+      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.alignment));
+        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.
+   * 
+   */
+  public void buildSortByAnnotationScoresMenu()
+  {
+    if (viewport.alignment.getAlignmentAnnotation() == null)
+    {
+      return;
+    }
+
+    if (viewport.alignment.getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)
+    {
+      sortByAnnotScore.removeAll();
+      // almost certainly a quicker way to do this - but we keep it simple
+      Hashtable scoreSorts = new Hashtable();
+      AlignmentAnnotation aann[];
+      Enumeration sq = viewport.alignment.getSequences().elements();
+      while (sq.hasMoreElements())
+      {
+        aann = ((SequenceI) sq.nextElement()).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.alignment
+              .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.
+   */
+  public void buildTreeMenu()
+  {
+    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++)
+    {
+      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()
+      {
+        public void actionPerformed(ActionEvent e)
+        {
+          SequenceI[] oldOrder = viewport.getAlignment()
+                  .getSequencesArray();
+          AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
+
+          addHistoryItem(new OrderCommand("Tree Sort", oldOrder,
+                  viewport.alignment));
+
+          alignPanel.paintAlignment(true);
+        }
+      });
+
+      sortByTreeMenu.add(item);
+    }
+  }
+
+  /**
+   * 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
+    {
+      /*
+       * Vector seqs = viewport.getAlignment().getSequences();
+       * 
+       * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];
+       * 
+       * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)
+       * seqs.elementAt(i); } }
+       */
+      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.alignment.isAligned is a global state - the local
+    // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
+    if (!viewport.alignment.isAligned())
+    {
+      seqs.setSequences(new SeqCigar[]
+      { seqs.getSequences()[0] });
+    }
+    return seqs;
+  }
+
+  /**
+   * DOCUMENT ME!
+   * 
+   * @param e
+   *                DOCUMENT ME!
+   */
+  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("Select a newick-like tree file");
+    chooser.setToolTipText("Load a 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(),
+                "Problem reading tree file", JOptionPane.WARNING_MESSAGE);
+        ex.printStackTrace();
+      }
+      if (fin != null && fin.hasWarningMessage())
+      {
+        JOptionPane.showMessageDialog(Desktop.desktop, fin
+                .getWarningMessage(), "Possible problem with tree file",
+                JOptionPane.WARNING_MESSAGE);
+      }
+    }
+  }
+
+  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;
+  }
+
+  /**
+   * Generates menu items and listener event actions for web service clients
+   * 
+   */
+  public void BuildWebServiceMenu()
+  {
+    // 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.
+    if ((Discoverer.services != null) && (Discoverer.services.size() > 0))
+    {
+      // TODO: refactor to allow list of AbstractName/Handler bindings to be
+      // stored or retrieved from elsewhere
+      Vector msaws = (Vector) Discoverer.services.get("MsaWS");
+      Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred");
+      Vector seqsrch = (Vector) Discoverer.services.get("SeqSearch");
+      // TODO: move GUI generation code onto service implementation - so a
+      // client instance attaches itself to the GUI with method call like
+      // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
+      // alignframe)
+      Vector wsmenu = new Vector();
+      final IProgressIndicator af = this;
+      if (msaws != null)
+      {
+        // Add any Multiple Sequence Alignment Services
+        final JMenu msawsmenu = new JMenu("Alignment");
+        for (int i = 0, j = msaws.size(); i < j; i++)
+        {
+          final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
+                  .get(i);
+          jalview.ws.WSClient impl = jalview.ws.Discoverer
+                  .getServiceClient(sh);
+          impl.attachWSMenuEntry(msawsmenu, this);
+
+        }
+        wsmenu.add(msawsmenu);
+      }
+      if (secstrpr != null)
+      {
+        // Add any secondary structure prediction services
+        final JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
+        for (int i = 0, j = secstrpr.size(); i < j; i++)
+        {
+          final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
+                  .get(i);
+          jalview.ws.WSClient impl = jalview.ws.Discoverer
+                  .getServiceClient(sh);
+          impl.attachWSMenuEntry(secstrmenu, this);
+        }
+        wsmenu.add(secstrmenu);
+      }
+      if (seqsrch != null)
+      {
+        // Add any sequence search services
+        final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
+        for (int i = 0, j = seqsrch.size(); i < j; i++)
+        {
+          final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
+                  .elementAt(i);
+          jalview.ws.WSClient impl = jalview.ws.Discoverer
+                  .getServiceClient(sh);
+          impl.attachWSMenuEntry(seqsrchmenu, this);
+        }
+        // finally, add the whole shebang onto the webservices menu
+        wsmenu.add(seqsrchmenu);
+      }
+      resetWebServiceMenu();
+      for (int i = 0, j = wsmenu.size(); i < j; i++)
+      {
+        webService.add((JMenu) wsmenu.get(i));
+      }
+    }
+    else
+    {
+      resetWebServiceMenu();
+      this.webService.add(this.webServiceNoServices);
+    }
+  }
+
+  /**
+   * empty the web service menu and add any ad-hoc functions not dynamically
+   * discovered.
+   * 
+   */
+  private void resetWebServiceMenu()
+  {
+    webService.removeAll();
+    // Temporary hack - DBRef Fetcher always top level ws entry.
+    JMenuItem rfetch = new JMenuItem("Fetch DB References");
+    rfetch
+            .setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
+    webService.add(rfetch);
+    rfetch.addActionListener(new ActionListener()
+    {
+
+      public void actionPerformed(ActionEvent e)
+      {
+        new Thread(new Runnable()
+        {
+
+          public void run()
+          {
+            new jalview.ws.DBRefFetcher(alignPanel.av
+                    .getSequenceSelection(), alignPanel.alignFrame)
+                    .fetchDBRefs(false);
+          }
+        }).start();
+
+      }
+
+    });
+  }
+
+  /*
+   * 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 = 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()
+        {
+
+          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()
+    {
+
+      public void run()
+      {
+        final long sttime = System.currentTimeMillis();
+        ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
+        try
+        {
+          Alignment ds = ths.getViewport().alignment.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("Finished searching for sequences from " + 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;
+    }
+  }
+
+  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,
+                      "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
+                      "Translation Failed", JOptionPane.WARNING_MESSAGE);
+    }
+    else
+    {
+      AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+      Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
+              DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    }
+  }
+
+  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.alignment
+                      .getAlignmentAnnotation(), viewport.alignment
+                      .getWidth(), viewport.getAlignment().getDataset());
+    } catch (Exception ex)
+    {
+      al = null;
+      jalview.bin.Cache.log.debug("Exception during translation.", ex);
+    }
+    if (al == null)
+    {
+      JOptionPane
+              .showMessageDialog(
+                      Desktop.desktop,
+                      "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
+                      "Translation Failed", JOptionPane.WARNING_MESSAGE);
+    }
+    else
+    {
+      AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+      Desktop.addInternalFrame(af, "Translation of " + 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.alignment
+              .getDataset(), alignPanel.seqPanel.seqCanvas
+              .getFeatureRenderer().featureColours, false);
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+
+    if (featuresFile)
+    {
+      viewport.showSequenceFeatures = true;
+      showSeqFeatures.setSelected(true);
+      alignPanel.paintAlignment(true);
+    }
+
+    return featuresFile;
+  }
+
+  public void dragEnter(DropTargetDragEvent evt)
+  {
+  }
+
+  public void dragExit(DropTargetEvent evt)
+  {
+  }
+
+  public void dragOver(DropTargetDragEvent evt)
+  {
+  }
+
+  public void dropActionChanged(DropTargetDragEvent evt)
+  {
+  }
+
+  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);
+          java.io.File file = new java.io.File(uri);
+          files.add(file);
+        }
+      }
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+    if (files != null)
+    {
+      try
+      {
+
+        for (int i = 0; i < files.size(); i++)
+        {
+          loadJalviewDataFile(files.get(i).toString());
+        }
+      } catch (Exception ex)
+      {
+        ex.printStackTrace();
+      }
+    }
+  }
+
+  /**
+   * Attempt to load a "dropped" file: 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)
+  {
+    try
+    {
+      String protocol = "File";
+
+      if (file.indexOf("http:") > -1 || file.indexOf("file:") > -1)
+      {
+        protocol = "URL";
+      }
+
+      boolean isAnnotation = new AnnotationFile().readAnnotationFile(
+              viewport.alignment, file, protocol);
+
+      if (!isAnnotation)
+      {
+        // try to see if its a JNet 'concise' style annotation file *before* we
+        // try to parse it as a features file
+        String 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
+        {
+          // 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();
+    }
+  }
+
+  public void tabSelectionChanged(int index)
+  {
+    if (index > -1)
+    {
+      alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
+      viewport = alignPanel.av;
+      setMenusFromViewport(viewport);
+    }
+  }
+
+  public void tabbedPane_mousePressed(MouseEvent e)
+  {
+    if (SwingUtilities.isRightMouseButton(e))
+    {
+      String reply = JOptionPane.showInternalInputDialog(this,
+              "Enter View Name", "Edit 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.
+   */
+  protected void extractScores_actionPerformed(ActionEvent e)
+  {
+    ParseProperties pp = new jalview.analysis.ParseProperties(
+            viewport.alignment);
+    // 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)
+   */
+  protected void showDbRefs_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.ActionEvent)
+   */
+  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;
+  }
+}
+
+class PrintThread extends Thread
+{
+  AlignmentPanel ap;
+
+  public PrintThread(AlignmentPanel ap)
+  {
+    this.ap = ap;
+  }
+
+  static PageFormat pf;
+
+  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();
+      }
+    }
+  }
+}