Refactored Jnet and added hidden columns support.
authorjprocter <Jim Procter>
Mon, 21 Aug 2006 13:41:41 +0000 (13:41 +0000)
committerjprocter <Jim Procter>
Mon, 21 Aug 2006 13:41:41 +0000 (13:41 +0000)
fixed undo-redo bug, hidden columns are moved with gapped columns and delete columns and undo-redo.

src/jalview/gui/AlignFrame.java
src/jalview/ws/JPredClient.java

index 28961e5..2d39108 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
-\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
-import java.awt.dnd.*;\r
-import org.biojava.dasobert.eventmodel.*;\r
-\r
-/**\r
- * DOCUMENT ME!\r
- *\r
- * @author $author$\r
- * @version $Revision$\r
- */\r
-public class AlignFrame\r
-    extends GAlignFrame implements DropTargetListener, FeatureListener\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
-  AlignmentPanel alignPanel;\r
-  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
-   * new alignment window with hidden columns\r
-   * @param al AlignmentI\r
-   * @param hiddenColumns ColumnSelection or null\r
-   */\r
-  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns) {\r
-\r
-    viewport = new AlignViewport(al, hiddenColumns);\r
-\r
-    this.setDropTarget(new java.awt.dnd.DropTarget(this, this));\r
-\r
-    if(viewport.vconsensus==null)\r
-    {\r
-      //Out of memory calculating consensus.\r
-      BLOSUM62Colour.setEnabled(false);\r
-      PIDColour.setEnabled(false);\r
-      conservationMenuItem.setEnabled(false);\r
-      modifyConservation.setEnabled(false);\r
-      abovePIDThreshold.setEnabled(false);\r
-      modifyPID.setEnabled(false);\r
-    }\r
-\r
-    alignPanel = new AlignmentPanel(this, viewport);\r
-\r
-    String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT", "No sort");\r
-\r
-    if(sortby.equals("Id"))\r
-      sortIDMenuItem_actionPerformed(null);\r
-    else if(sortby.equals("Pairwise Identity"))\r
-      sortPairwiseMenuItem_actionPerformed(null);\r
-\r
-   // remove(tabbedPane);\r
-    getContentPane().add(alignPanel, BorderLayout.CENTER);\r
-\r
-\r
-\r
-  //  tabbedPane.add(al.isNucleotide() ? "DNA":"Protein", alignPanel);\r
-\r
-    ///Dataset tab\r
-    /////////////////////////\r
-    if(al.getDataset()==null)\r
-    {\r
-      al.setDataset(null);\r
-    }\r
-   // AlignViewport ds = new AlignViewport(al.getDataset(), true);\r
-   // AlignmentPanel dap = new AlignmentPanel(this, ds);\r
-  //  tabbedPane.add("Dataset", dap);\r
-  //  viewports.add(ds);\r
-  //  alignPanels.add(dap);\r
-    /////////////////////////\r
-\r
-\r
-    viewport.addPropertyChangeListener(new PropertyChangeListener()\r
-    {\r
-     public void propertyChange(PropertyChangeEvent evt)\r
-     {\r
-       if (evt.getPropertyName().equals("alignment"))\r
-       {\r
-         alignmentChanged();\r
-       }\r
-     }\r
-   });\r
-\r
-\r
-    if (Desktop.desktop != null)\r
-    {\r
-      addServiceListeners();\r
-      setGUINucleotide(al.isNucleotide());\r
-    }\r
-\r
-\r
-    if (jalview.bin.Cache.getDefault("WRAP_ALIGNMENT", false))\r
-    {\r
-      wrapMenuItem.setSelected(true);\r
-      wrapMenuItem_actionPerformed(null);\r
-    }\r
-\r
-  }\r
-\r
-\r
-  /**\r
-   * Creates a new AlignFrame object.\r
-   *\r
-   * @param al DOCUMENT ME!\r
-   */\r
-  public AlignFrame(AlignmentI al)\r
-  {\r
-    this(al, null);\r
-  }\r
-\r
-  public AlignViewport getViewport()\r
-  {\r
-    return viewport;\r
-  }\r
-\r
-  /* Set up intrinsic listeners for dynamically generated GUI bits. */\r
-  private void addServiceListeners()\r
-  {\r
-    final java.beans.PropertyChangeListener thisListener;\r
-    // 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
-  public void setGUINucleotide(boolean nucleotide)\r
-  {\r
-    showTranslation.setVisible( nucleotide );\r
-    //sequenceFeatures.setVisible(!nucleotide );\r
-    //featureSettings.setVisible( !nucleotide );\r
-    conservationMenuItem.setVisible( !nucleotide );\r
-    modifyConservation.setVisible(   !nucleotide );\r
-\r
-    //Remember AlignFrame always starts as protein\r
-    if(!nucleotide)\r
-    {\r
-      calculateMenu.remove(calculateMenu.getItemCount()-2);\r
-    }\r
-  }\r
-\r
-  public void comeBackLater(FeatureEvent evt)\r
-  {}\r
-\r
-  public void newFeatures(FeatureEvent evt)\r
-  {\r
-    if (evt.getFeatures().length > 0)\r
-    {\r
-      alignPanel.seqPanel.seqCanvas.fr.featuresAdded();\r
-      alignPanel.repaint();\r
-    }\r
-  }\r
-\r
-  Hashtable progressBars;\r
-  public void setProgressBar(String message, long id)\r
-  {\r
-    if(progressBars == null)\r
-      progressBars = new Hashtable();\r
-\r
-    JPanel progressPanel;\r
-    GridLayout layout = (GridLayout) statusPanel.getLayout();\r
-    if(progressBars.get( new Long(id) )!=null)\r
-     {\r
-       progressPanel = (JPanel)progressBars.get( new Long(id) );\r
-       statusPanel.remove(progressPanel);\r
-       progressBars.remove( progressPanel );\r
-       progressPanel = null;\r
-       if(message!=null)\r
-         statusBar.setText(message);\r
-\r
-       layout.setRows(layout.getRows() - 1);\r
-     }\r
-    else\r
-    {\r
-      progressPanel = new JPanel(new BorderLayout(10, 5));\r
-\r
-      JProgressBar progressBar = new JProgressBar();\r
-      progressBar.setIndeterminate(true);\r
-\r
-      progressPanel.add(new JLabel(message), BorderLayout.WEST);\r
-      progressPanel.add(progressBar, BorderLayout.CENTER);\r
-\r
-      layout.setRows(layout.getRows() + 1);\r
-      statusPanel.add(progressPanel);\r
-\r
-      progressBars.put(new Long(id), progressPanel);\r
-    }\r
-\r
-    validate();\r
-  }\r
-\r
-\r
-  /*\r
-   Added so Castor Mapping file can obtain Jalview Version\r
-  */\r
-  public String getVersion()\r
-  {\r
-    return  jalview.bin.Cache.getProperty("VERSION");\r
-  }\r
-\r
-  public FeatureRenderer getFeatureRenderer()\r
-  {\r
-    return alignPanel.seqPanel.seqCanvas.getFeatureRenderer();\r
-  }\r
-\r
-\r
-  public void fetchSequence_actionPerformed(ActionEvent e)\r
-  {\r
-    new SequenceFetcher(this);\r
-  }\r
-\r
-  public void addFromFile_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);\r
-  }\r
-\r
-  public void addFromText_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);\r
-  }\r
-\r
-  public void addFromURL_actionPerformed(ActionEvent e)\r
-  {\r
-    Desktop.instance.inputURLMenuItem_actionPerformed(viewport);\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( "LAST_DIRECTORY"),\r
-        new String[]\r
-        { "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc","jar" },\r
-        new String[]\r
-        { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "Jalview" },\r
-        currentFileFormat,\r
-        false);\r
-\r
-\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
-\r
-        if (currentFileFormat == null)\r
-        {\r
-          JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
-                                                "You must select a file format before saving!",\r
-                                                "File format not specified",\r
-                                                JOptionPane.WARNING_MESSAGE);\r
-          value = chooser.showSaveDialog(this);\r
-          return;\r
-        }\r
-\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
-      new Jalview2XML().SaveAlignment(this, file, shortName);\r
-\r
-      // USE Jalview2XML to save this file\r
-      return true;\r
-    }\r
-    else\r
-    {\r
-\r
-      String[] omitHidden = null;\r
-\r
-      if (viewport.hasHiddenColumns)\r
-      {\r
-        int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,\r
-            "The Alignment contains hidden columns."\r
-            + "\nDo you want to save only the visible alignment?",\r
-            "Save / Omit Hidden Columns",\r
-            JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);\r
-\r
-        if (reply == JOptionPane.YES_OPTION)\r
-          omitHidden = viewport.getViewAsString(false);\r
-      }\r
-\r
-      String output = new FormatAdapter().formatSequences(\r
-          format,\r
-          viewport.alignment.getSequencesArray(),\r
-          omitHidden);\r
-\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
-        this.setTitle(file);\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
-    String [] omitHidden = null;\r
-\r
-    if(viewport.hasHiddenColumns)\r
-    {\r
-      int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,\r
-          "The Alignment contains hidden columns."\r
-      +"\nDo you want to output only the visible alignment?",\r
-      "Save / Omit Hidden Columns",\r
-      JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);\r
-\r
-      if(reply==JOptionPane.YES_OPTION)\r
-      {\r
-        omitHidden = viewport.getViewAsString(false);\r
-      }\r
-    }\r
-\r
-    CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
-    Desktop.addInternalFrame(cap,\r
-                             "Alignment output - " + e.getActionCommand(), 600,\r
-                             500);\r
-\r
-\r
-    cap.setText(new FormatAdapter().formatSequences(\r
-        e.getActionCommand(),\r
-        viewport.alignment.getSequencesArray(),\r
-        omitHidden));\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
-                   alignPanel.seqPanel.seqCanvas.getSequenceRenderer(),\r
-        alignPanel.seqPanel.seqCanvas.getFeatureRenderer());\r
-  }\r
-\r
-  public void createImageMap(File file, String image)\r
-  {\r
-    alignPanel.makePNGImageMap(file, image);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e 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
-  public void exportFeatures_actionPerformed(ActionEvent e)\r
-  {\r
-    new AnnotationExporter().exportFeatures(alignPanel);\r
-  }\r
-\r
-\r
-  public void exportAnnotations_actionPerformed(ActionEvent e)\r
-  {\r
-    new AnnotationExporter().exportAnnotations(\r
-      alignPanel,\r
-      viewport.alignment.getAlignmentAnnotation()\r
-        );\r
-  }\r
-\r
-\r
-  public void associatedData_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("Load Jalview Annotations or Features File");\r
-    chooser.setToolTipText("Load Jalview Annotations / Features 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
-      loadJalviewDataFile(choice);\r
-    }\r
-\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
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());\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.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());\r
-  }\r
-\r
-  // used by undo and redo\r
-  void restoreHistoryItem(HistoryItem hi)\r
-  {\r
-\r
-    hi.restore();\r
-\r
-    updateEditMenuBar();\r
-\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.getSequences(false).contains(seq))\r
-        {\r
-          continue;\r
-        }\r
-\r
-        SequenceI temp = viewport.alignment.getSequenceAt(i - 1);\r
-\r
-        if (sg.getSequences(false).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.getSequences(false).contains(seq))\r
-        {\r
-          continue;\r
-        }\r
-\r
-        SequenceI temp = viewport.alignment.getSequenceAt(i + 1);\r
-\r
-        if (sg.getSequences(false).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
-\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
-    SequenceI [] seqs = viewport.getSelectionAsNewSequence();\r
-    String[] omitHidden = null;\r
-\r
-    if (viewport.hasHiddenColumns)\r
-    {\r
-      omitHidden = viewport.getViewAsString(true);\r
-    }\r
-\r
-    String output = new FormatAdapter().formatSequences(\r
-        "Fasta",\r
-        seqs,\r
-        omitHidden);\r
-\r
-\r
-    Toolkit.getDefaultToolkit().getSystemClipboard()\r
-        .setContents(new StringSelection(output), Desktop.instance);\r
-\r
-    Vector hiddenColumns = null;\r
-    if(viewport.hasHiddenColumns)\r
-    {\r
-      hiddenColumns =new Vector();\r
-      int hiddenOffset = viewport.getSelectionGroup().getStartRes();\r
-      for(int i=0; i<viewport.getColumnSelection().getHiddenColumns().size(); i++)\r
-      {\r
-        int[] region = (int[])\r
-            viewport.getColumnSelection().getHiddenColumns().elementAt(i);\r
-\r
-        hiddenColumns.addElement(new int[]{region[0]-hiddenOffset,\r
-                          region[1]-hiddenOffset});\r
-      }\r
-    }\r
-\r
-    Desktop.jalviewClipboard = new Object[]{ seqs,\r
-        viewport.alignment.getDataset(),\r
-        hiddenColumns};\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
-      if(str.length()<1)\r
-        return;\r
-\r
-      String format = new IdentifyFile().Identify(str, "Paste");\r
-      SequenceI[] sequences;\r
-\r
-\r
-     if(Desktop.jalviewClipboard!=null)\r
-     {\r
-       // The clipboard was filled from within Jalview, we must use the sequences\r
-       // And dataset from the copied alignment\r
-       sequences = (SequenceI[])Desktop.jalviewClipboard[0];\r
-     }\r
-     else\r
-     {\r
-       sequences = new FormatAdapter().readFile(str, "Paste", format);\r
-     }\r
-\r
-     AlignmentI alignment = null;\r
-\r
-      if (newAlignment)\r
-      {\r
-        alignment = new Alignment(sequences);\r
-\r
-        if(Desktop.jalviewClipboard!=null)\r
-           alignment.setDataset( (Alignment)Desktop.jalviewClipboard[1] );\r
-        else\r
-           alignment.setDataset( null );\r
-\r
-      }\r
-      else\r
-      {\r
-        alignment = viewport.getAlignment();\r
-\r
-        //!newAlignment\r
-        for (int i = 0; i < sequences.length; i++)\r
-        {\r
-          Sequence newseq = new Sequence(sequences[i].getName(),\r
-              sequences[i].getSequence(), sequences[i].getStart(),\r
-              sequences[i].getEnd());\r
-\r
-          alignment.addSequence(newseq);\r
-        }\r
-\r
-\r
-        viewport.setEndSeq(alignment.getHeight());\r
-        alignment.getWidth();\r
-        viewport.firePropertyChange("alignment", null, alignment.getSequences());\r
-      }\r
-\r
-\r
-\r
-\r
-\r
-      // Add any annotations attached to sequences\r
-      for (int i = 0; i < sequences.length; i++)\r
-     {\r
-       if (sequences[i].getAnnotation() != null)\r
-       {\r
-         for (int a = 0; a < sequences[i].getAnnotation().length; a++)\r
-         {\r
-           AlignmentAnnotation newAnnot =\r
-               new AlignmentAnnotation(\r
-                   sequences[i].getAnnotation()[a].label,\r
-                   sequences[i].getAnnotation()[a].description,\r
-                   sequences[i].getAnnotation()[a].annotations,\r
-                   sequences[i].getAnnotation()[a].graphMin,\r
-                   sequences[i].getAnnotation()[a].graphMax,\r
-                   sequences[i].getAnnotation()[a].graph);\r
-\r
-           sequences[i].getAnnotation()[a] = newAnnot;\r
-           newAnnot.sequenceMapping = sequences[i].getAnnotation()[a].\r
-               sequenceMapping;\r
-           newAnnot.sequenceRef = sequences[i];\r
-           newAnnot.adjustForAlignment();\r
-           alignment.addAnnotation(newAnnot);\r
-           alignment.setAnnotationIndex(newAnnot, a);\r
-         }\r
-\r
-         alignPanel.annotationPanel.adjustPanelHeight();\r
-       }\r
-     }\r
-\r
-     if(newAlignment)\r
-     {\r
-       AlignFrame af = new AlignFrame(alignment);\r
-       String newtitle = new String("Copied sequences");\r
-\r
-       if(Desktop.jalviewClipboard!=null && Desktop.jalviewClipboard[2]!=null)\r
-         {\r
-           Vector hc = (Vector)Desktop.jalviewClipboard[2];\r
-           for(int i=0; i<hc.size(); i++)\r
-           {\r
-             int [] region = (int[]) hc.elementAt(i);\r
-             af.viewport.hideColumns(region[0], region[1]);\r
-           }\r
-         }\r
-\r
-\r
-       //>>>This is a fix for the moment, until a better solution is found!!<<<\r
-       af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer().transferSettings(\r
-           alignPanel.seqPanel.seqCanvas.getFeatureRenderer());\r
-\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
-     }\r
-\r
-\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-        System.out.println("Exception whilst pasting: "+ex);\r
-        // could be anything being pasted in here\r
-    }\r
-\r
-\r
-  }\r
-\r
-  /**\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
-\r
-    if (viewport.getSelectionGroup() == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-\r
-    SequenceGroup sg = viewport.getSelectionGroup();\r
-\r
-\r
-\r
-    //Jalview no longer allows deletion of residues.\r
-    //Check here whether any residues are in selection area\r
-   /* if( sg.getEndRes()-sg.getStartRes() < viewport.alignment.getWidth()-1)\r
-    {\r
-      for (int i = 0; i < sg.sequences.size(); i++)\r
-      {\r
-        SequenceI seq = sg.getSequenceAt(i);\r
-        int j = sg.getStartRes();\r
-        do\r
-        {\r
-          if (!jalview.util.Comparison.isGap(seq.getCharAt(j)))\r
-          {\r
-            JOptionPane.showInternalMessageDialog(\r
-                Desktop.desktop, "Cannot delete residues from alignment!\n"\r
-                + "Try hiding columns instead.",\r
-                "Deletion of residues not permitted",\r
-                JOptionPane.WARNING_MESSAGE);\r
-\r
-            return;\r
-          }\r
-          j++;\r
-        }while(j<=sg.getEndRes());\r
-      }\r
-    }*/\r
-\r
-\r
-    addHistoryItem(new HistoryItem("Delete Sequences", viewport.alignment,\r
-                                   HistoryItem.HIDE));\r
-\r
-\r
-    for (int i = 0; i < sg.getSize(false); i++)\r
-    {\r
-      SequenceI seq = sg.getSequenceAt(i);\r
-      int index = viewport.getAlignment().findIndex(seq);\r
-\r
-      seq.deleteChars(sg.getStartRes(), sg.getEndRes() + 1);\r
-\r
-      // If the cut affects all sequences, remove highlighted columns\r
-      if (sg.getSize(false) == viewport.alignment.getHeight())\r
-      {\r
-        viewport.getColumnSelection().removeElements(sg.getStartRes(),\r
-            sg.getEndRes() + 1);\r
-      }\r
-\r
-      if (seq.getSequence().length() < 1)\r
-      {\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
-    viewport.firePropertyChange("alignment", null,\r
-                                  viewport.getAlignment().getSequences());\r
-\r
-\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
-\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
-    if(viewport.cursorMode)\r
-    {\r
-      alignPanel.seqPanel.keyboardNo1 = null;\r
-      alignPanel.seqPanel.keyboardNo2 = null;\r
-    }\r
-    viewport.setSelectionGroup(null);\r
-    viewport.getColumnSelection().clear();\r
-    viewport.setSelectionGroup(null);\r
-    alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);\r
-    alignPanel.idPanel.idCanvas.searchResults = null;\r
-    alignPanel.repaint();\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
-  public void invertColSel_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.invertColumnSelection();\r
-    alignPanel.repaint();\r
-  }\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
-      viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());\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
-      viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());\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
-    //This is to maintain viewport position on first residue\r
-    //of first sequence\r
-    SequenceI seq = viewport.alignment.getSequenceAt(0);\r
-    int startRes = seq.findPosition(viewport.startRes);\r
-\r
-    viewport.getAlignment().removeGaps();\r
-\r
-    viewport.setStartRes(seq.findIndex(startRes)-1);\r
-\r
-   viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());\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
-    //This is to maintain viewport position on first residue\r
-    //of first sequence\r
-    SequenceI seq = viewport.alignment.getSequenceAt(0);\r
-    int startRes = seq.findPosition(viewport.startRes);\r
-\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().getSequences(true) != null\r
-        && viewport.getSelectionGroup().getSize(true) > 0)\r
-    {\r
-      seqs = viewport.getSelectionGroup().getSequences(true);\r
-      start = viewport.getSelectionGroup().getStartRes();\r
-      end = viewport.getSelectionGroup().getEndRes()+1;\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
-      // Removing a range is much quicker than removing gaps\r
-      // one by one for long sequences\r
-      int j = start;\r
-      int rangeStart=-1, rangeEnd=-1;\r
-\r
-      do\r
-      {\r
-        if (jalview.util.Comparison.isGap(current.getCharAt(j)))\r
-        {\r
-          if(rangeStart==-1)\r
-           {\r
-             rangeStart = j;\r
-             rangeEnd = j+1;\r
-           }\r
-           else\r
-           {\r
-             rangeEnd++;\r
-           }\r
-           j++;\r
-        }\r
-        else\r
-        {\r
-          if(rangeStart>-1)\r
-          {\r
-            current.deleteChars(rangeStart, rangeEnd);\r
-            j-=rangeEnd-rangeStart;\r
-            jSize-=rangeEnd-rangeStart;\r
-            rangeStart = -1;\r
-            rangeEnd = -1;\r
-          }\r
-          else\r
-            j++;\r
-        }\r
-      }\r
-      while (j < end && j < jSize);\r
-      if(rangeStart>-1)\r
-      {\r
-       current.deleteChars(rangeStart, rangeEnd);\r
-      }\r
-    }\r
-\r
-    viewport.setStartRes(seq.findIndex(startRes)-1);\r
-\r
-    viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());\r
-  }\r
-\r
- public void alignmentChanged()\r
- {\r
-   if(viewport.padGaps)\r
-     viewport.getAlignment().padGaps();\r
-\r
-   if(viewport.vconsensus!=null && viewport.autoCalculateConsensus)\r
-   {\r
-     viewport.updateConsensus();\r
-     viewport.updateConservation();\r
-   }\r
-\r
-   resetAllColourSchemes();\r
-   if(alignPanel.overviewPanel!=null)\r
-     alignPanel.overviewPanel.updateOverviewImage();\r
-\r
-   viewport.alignment.adjustSequenceAnnotations();\r
-\r
-   if(alignPanel.overviewPanel!=null)\r
-     alignPanel.overviewPanel.updateOverviewImage();\r
-\r
-   alignPanel.repaint();\r
- }\r
-\r
-  void resetAllColourSchemes()\r
-  {\r
-    ColourSchemeI cs = viewport.globalColourScheme;\r
-    if(cs!=null)\r
-    {\r
-      if (cs instanceof ClustalxColourScheme)\r
-      {\r
-        ( (ClustalxColourScheme) viewport.getGlobalColourScheme()).\r
-            resetClustalX(viewport.alignment.getSequences(),\r
-                          viewport.alignment.getWidth());\r
-      }\r
-\r
-      cs.setConsensus(viewport.vconsensus);\r
-      if (cs.conservationApplied())\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
-        c.calculate();\r
-        c.verdict(false, viewport.ConsPercGaps);\r
-\r
-        cs.setConservation(c);\r
-      }\r
-    }\r
-\r
-    int s, sSize = viewport.alignment.getGroups().size();\r
-    for(s=0; s<sSize; s++)\r
-    {\r
-      SequenceGroup sg = (SequenceGroup)viewport.alignment.getGroups().elementAt(s);\r
-      if(sg.cs!=null && sg.cs instanceof ClustalxColourScheme)\r
-      {\r
-        ((ClustalxColourScheme)sg.cs).resetClustalX(\r
-            sg.getSequences(true), sg.getWidth());\r
-      }\r
-      sg.recalcConservation();\r
-    }\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
-    viewport.padGaps = padGapsMenuitem.isSelected();\r
-\r
-   // if (viewport.padGaps)\r
-    alignmentChanged();\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
-    frame.setLayer(JLayeredPane.PALETTE_LAYER);\r
-    Desktop.addInternalFrame(frame, "Find", 340, 110);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void font_actionPerformed(ActionEvent e)\r
-  {\r
-    new FontChooser(alignPanel);\r
-  }\r
-\r
-  public void smoothFont_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.antiAlias = smoothFont.isSelected();\r
-    alignPanel.annotationPanel.image = null;\r
-    alignPanel.repaint();\r
-  }\r
-\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void seqLimit_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowJVSuffix(seqLimits.isSelected());\r
-\r
-    alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel.calculateIdWidth());\r
-    alignPanel.repaint();\r
-  }\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
-  public void wrapMenuItem_actionPerformed(ActionEvent e)\r
-  {\r
-    scaleAbove.setVisible(wrapMenuItem.isSelected());\r
-    scaleLeft.setVisible(wrapMenuItem.isSelected());\r
-    scaleRight.setVisible(wrapMenuItem.isSelected());\r
-    viewport.setWrapAlignment(wrapMenuItem.isSelected());\r
-    alignPanel.setWrapAlignment(wrapMenuItem.isSelected());\r
-  }\r
-\r
-  public void showAllSeqs_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.showAllHiddenSeqs();\r
-  }\r
-\r
-  public void showAllColumns_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.showAllHiddenColumns();\r
-    repaint();\r
-  }\r
-\r
-  public void hideSelSequences_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.hideAllSelectedSeqs();\r
-  }\r
-\r
-  public void hideSelColumns_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.hideSelectedColumns();\r
-    alignPanel.repaint();\r
-  }\r
-\r
-  public void hiddenMarkers_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());\r
-    repaint();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e 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
-  public FeatureSettings featureSettings;\r
-  public void featureSettings_actionPerformed(ActionEvent e)\r
-  {\r
-    if(featureSettings !=null )\r
-    {\r
-      featureSettings.close();\r
-      featureSettings = null;\r
-    }\r
-    featureSettings = new FeatureSettings(this);\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param evt DOCUMENT ME!\r
-   */\r
-  public void showSeqFeatures_actionPerformed(ActionEvent evt)\r
-  {\r
-    viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());\r
-    alignPanel.repaint();\r
-    if (alignPanel.getOverviewPanel() != null)\r
-    {\r
-      alignPanel.getOverviewPanel().updateOverviewImage();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void annotationPanelMenuItem_actionPerformed(ActionEvent e)\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
-  public void annotationColour_actionPerformed(ActionEvent e)\r
-  {\r
-    new AnnotationColourChooser(viewport, alignPanel);\r
-  }\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
-  public 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(\r
-              sg.getSequences(true), 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(\r
-             sg.getSequences(true), 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.getSequences(true), 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
-    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
-    new RedundancyPanel(alignPanel, this);\r
-  }\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(false) < 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(false) < 4) &&\r
-          (viewport.getSelectionGroup().getSize(false) > 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
-     new PCAPanel(viewport);\r
-  }\r
-\r
-\r
-  public void autoCalculate_actionPerformed(ActionEvent e)\r
-  {\r
-    viewport.autoCalculateConsensus = autoCalculate.isSelected();\r
-    if(viewport.autoCalculateConsensus)\r
-    {\r
-      alignmentChanged();\r
-    }\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
-    TreePanel tp;\r
-\r
-    if ( (viewport.getSelectionGroup() != null) &&\r
-        (viewport.getSelectionGroup().getSize(false) > 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.getSize(false))\r
-      {\r
-        if ( ( (SequenceI) sg.getSequences(false).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, type, pwType);\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
-      if(viewport.alignment.getHeight()<2)\r
-        return;\r
-\r
-      tp = new TreePanel(viewport, type, pwType);\r
-    }\r
-\r
-    addTreeMenuItem(tp, title);\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
-  }\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 jalview.datamodel.AlignmentView gatherSequencesForAlignment()\r
-  {\r
-    // Now, check we have enough sequences\r
-    AlignmentView msa = null;\r
-\r
-    if ( (viewport.getSelectionGroup() != null) &&\r
-        (viewport.getSelectionGroup().getSize(false) > 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(false)];\r
-\r
-      for (int i = 0; i < sz; i++)\r
-      {\r
-        msa[i] = (SequenceI) seqs.getSequenceAt(i);\r
-      } */\r
-      msa = viewport.getAlignmentView(true);\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
-      msa = viewport.getAlignmentView(false);\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(false) > 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(false) == 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(false)];\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
-                           "FromFile",\r
-                           title,\r
-                           nf);\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 ( (Discoverer.services != null)\r
-        && (Discoverer.services.size() > 0))\r
-    {\r
-      Vector msaws = (Vector) Discoverer.services.get("MsaWS");\r
-      Vector secstrpr = (Vector) 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
-        final AlignFrame af = this;\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
-              AlignmentView msa = gatherSequencesForAlignment();\r
-              new jalview.ws.MsaWSClient(sh, title, msa,\r
-                  false, true, viewport.getAlignment().getDataset(), af);\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
-                AlignmentView msa = gatherSequencesForAlignment();\r
-                new jalview.ws.MsaWSClient(sh, title, msa,\r
-                    true, true, viewport.getAlignment().getDataset(), af);\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
-                new jalview.ws.JPredClient(sh, title, msa[0], null);\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, null);\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
- /* public void vamsasStore_actionPerformed(ActionEvent e)\r
-  {\r
-    JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.\r
-        getProperty("LAST_DIRECTORY"));\r
-\r
-    chooser.setFileView(new JalviewFileView());\r
-    chooser.setDialogTitle("Export to Vamsas file");\r
-    chooser.setToolTipText("Export");\r
-\r
-    int value = chooser.showSaveDialog(this);\r
-\r
-    if (value == JalviewFileChooser.APPROVE_OPTION)\r
-    {\r
-      jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);\r
-      //vs.store(chooser.getSelectedFile().getAbsolutePath()   );\r
-      vs.storeJalview( chooser.getSelectedFile().getAbsolutePath(), this);\r
-    }\r
-  }*/\r
-\r
-\r
-\r
-\r
-public void showTranslation_actionPerformed(ActionEvent e)\r
-{\r
-  SequenceI [] selection = viewport.getSelectionAsNewSequence();\r
-  String [] seqstring = viewport.getViewAsString(true);\r
-\r
-  int s, sSize = selection.length;\r
-  SequenceI [] newSeq = new SequenceI[sSize];\r
-\r
-  int res, resSize;\r
-  StringBuffer protein;\r
-  String seq;\r
-  for(s=0; s<sSize; s++)\r
-  {\r
-    protein = new StringBuffer();\r
-    seq = AlignSeq.extractGaps("-. ", seqstring[s]);\r
-    resSize = seq.length();\r
-    resSize -= resSize%3;\r
-\r
-    for(res = 0; res < resSize; res+=3)\r
-    {\r
-      String codon = seq.substring(res, res+3);\r
-      codon = codon.replace('U', 'T');\r
-      String aa = ResidueProperties.codonTranslate(codon);\r
-      if(aa==null)\r
-        protein.append(viewport.getGapCharacter());\r
-      else if(aa.equals("STOP"))\r
-        protein.append("X");\r
-      else\r
-        protein.append( aa );\r
-    }\r
-    newSeq[s] = new Sequence(selection[s].getName(),\r
-                             protein.toString());\r
-  }\r
-\r
-\r
-  AlignmentI al = new Alignment(newSeq);\r
-  al.setDataset(null);\r
-\r
-\r
-  ////////////////////////////////\r
-  // Copy annotations across\r
-  jalview.datamodel.AlignmentAnnotation[] annotations\r
-      = viewport.alignment.getAlignmentAnnotation();\r
-  int a, aSize;\r
-  if(annotations!=null)\r
-  {\r
-    for (int i = 0; i < annotations.length; i++)\r
-    {\r
-      if (annotations[i].label.equals("Quality") ||\r
-          annotations[i].label.equals("Conservation") ||\r
-          annotations[i].label.equals("Consensus"))\r
-      {\r
-        continue;\r
-      }\r
-\r
-      aSize = viewport.alignment.getWidth() / 3;\r
-      jalview.datamodel.Annotation[] anots =\r
-          new jalview.datamodel.Annotation[aSize];\r
-\r
-      for (a = 0; a < viewport.alignment.getWidth(); a++)\r
-      {\r
-        if (annotations[i].annotations[a] == null\r
-            || annotations[i].annotations[a] == null)\r
-          continue;\r
-\r
-        anots[a / 3] = new Annotation(\r
-            annotations[i].annotations[a].displayCharacter,\r
-            annotations[i].annotations[a].description,\r
-            annotations[i].annotations[a].secondaryStructure,\r
-            annotations[i].annotations[a].value,\r
-            annotations[i].annotations[a].colour);\r
-      }\r
-\r
-      jalview.datamodel.AlignmentAnnotation aa\r
-          = new jalview.datamodel.AlignmentAnnotation(annotations[i].label,\r
-          annotations[i].description, anots);\r
-      al.addAnnotation(aa);\r
-    }\r
-  }\r
-\r
-    AlignFrame af = new AlignFrame(al);\r
-    Desktop.addInternalFrame(af, "Translation of "+this.getTitle(),\r
-                             NEW_WINDOW_WIDTH,\r
-                             NEW_WINDOW_HEIGHT);\r
-\r
-\r
-   // AlignViewport newViewport = new AlignViewport(al);\r
-   // AlignmentPanel ap = new AlignmentPanel(this, newViewport);\r
-   // tabbedPane.add("Protein", ap);\r
-   // viewports.add(newViewport);\r
-  //  alignPanels.add(ap);\r
-\r
-    ///Dataset tab\r
-  /////////////////////////\r
-\r
-  //  AlignViewport ds = new AlignViewport(al.getDataset());\r
-  //  ds.setDataset(true);\r
-  //  AlignmentPanel dap = new AlignmentPanel(this, ds);\r
-  //  tabbedPane.add("Dataset", dap);\r
-  //  viewports.add(ds);\r
-  //  alignPanels.add(dap);\r
-  /////////////////////////\r
-\r
-\r
-}\r
-\r
-/*public void tabSelected()\r
- {\r
-  int index = tabbedPane.getSelectedIndex();\r
-  viewport = (AlignViewport)viewports.elementAt(index);\r
-  alignPanel = (AlignmentPanel)alignPanels.elementAt(index);\r
- }*/\r
-\r
-/**\r
- * DOCUMENT ME!\r
- *\r
- * @param String DOCUMENT ME!\r
- */\r
-public boolean parseFeaturesFile(String file, String type)\r
-{\r
-    boolean featuresFile = false;\r
-    try{\r
-      featuresFile = new FeaturesFile(file, type).parse(viewport.alignment.getDataset(),\r
-                                         alignPanel.seqPanel.seqCanvas.\r
-                                         getFeatureRenderer().featureColours,\r
-                                         false);\r
-    }\r
-    catch(Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    }\r
-\r
-    if(featuresFile)\r
-    {\r
-      viewport.showSequenceFeatures = true;\r
-      showSeqFeatures.setSelected(true);\r
-      alignPanel.repaint();\r
-    }\r
-\r
-    return featuresFile;\r
-}\r
-\r
-public void dragEnter(DropTargetDragEvent evt)\r
-{}\r
-\r
-public void dragExit(DropTargetEvent evt)\r
-{}\r
-\r
-public void dragOver(DropTargetDragEvent evt)\r
-{}\r
-\r
-public void dropActionChanged(DropTargetDragEvent evt)\r
-{}\r
-\r
-public void drop(DropTargetDropEvent evt)\r
-{\r
-    Transferable t = evt.getTransferable();\r
-    java.util.List files = null;\r
-\r
-    try\r
-    {\r
-      DataFlavor uriListFlavor = new DataFlavor("text/uri-list;class=java.lang.String");\r
-      if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))\r
-      {\r
-        //Works on Windows and MacOSX\r
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);\r
-        files = (java.util.List) t.getTransferData(DataFlavor.javaFileListFlavor);\r
-      }\r
-      else if (t.isDataFlavorSupported(uriListFlavor))\r
-      {\r
-        // This is used by Unix drag system\r
-        evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);\r
-        String data = (String) t.getTransferData(uriListFlavor);\r
-        files = new java.util.ArrayList(1);\r
-        for (java.util.StringTokenizer st = new java.util.StringTokenizer(\r
-            data,\r
-            "\r\n");\r
-             st.hasMoreTokens(); )\r
-        {\r
-          String s = st.nextToken();\r
-          if (s.startsWith("#"))\r
-          {\r
-            // the line is a comment (as per the RFC 2483)\r
-            continue;\r
-          }\r
-\r
-          java.net.URI uri = new java.net.URI(s);\r
-          java.io.File file = new java.io.File(uri);\r
-          files.add(file);\r
-        }\r
-      }\r
-    }\r
-    catch (Exception e)\r
-    {\r
-      e.printStackTrace();\r
-    }\r
-    if (files != null)\r
-    {\r
-      try\r
-      {\r
-\r
-        for (int i = 0; i < files.size(); i++)\r
-        {\r
-          loadJalviewDataFile(files.get(i).toString());\r
-        }\r
-      }\r
-      catch (Exception ex)\r
-      {\r
-        ex.printStackTrace();\r
-      }\r
-    }\r
-}\r
-\r
-  // This method will attempt to load a "dropped" file first by testing\r
-  // whether its and Annotation file, then features file. If both are\r
-  // false then the user may have dropped an alignment file onto this\r
-  // AlignFrame\r
-   public void loadJalviewDataFile(String file)\r
-  {\r
-    try{\r
-      boolean isAnnotation = new AnnotationFile().readAnnotationFile(viewport.\r
-          alignment, file);\r
-\r
-      if (!isAnnotation)\r
-      {\r
-        boolean isGroupsFile = parseFeaturesFile(file,\r
-                                                AppletFormatAdapter.FILE);\r
-        if (!isGroupsFile)\r
-        {\r
-          String format = new IdentifyFile().Identify(file, FormatAdapter.FILE);\r
-          new FileLoader().LoadFile(viewport, file, FormatAdapter.FILE, format);\r
-        }\r
-      }\r
-      else\r
-      {\r
-        // (isAnnotation)\r
-        alignPanel.adjustAnnotationHeight();\r
-      }\r
-\r
-    }catch(Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    }\r
-  }\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2005 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 Softwarechang
+ * 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.event.*;
+import java.awt.print.*;
+import javax.swing.*;
+
+import jalview.analysis.*;
+import jalview.datamodel.*;
+import jalview.io.*;
+import jalview.jbgui.*;
+import jalview.schemes.*;
+import jalview.util.ShiftList;
+import jalview.ws.*;
+import java.awt.dnd.*;
+import org.biojava.dasobert.eventmodel.*;
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class AlignFrame
+    extends GAlignFrame implements DropTargetListener, FeatureListener
+{
+  /** DOCUMENT ME!! */
+  public static final int NEW_WINDOW_WIDTH = 700;
+
+  /** DOCUMENT ME!! */
+  public static final int NEW_WINDOW_HEIGHT = 500;
+  AlignmentPanel alignPanel;
+  AlignViewport viewport;
+
+  /** DOCUMENT ME!! */
+  public String currentFileFormat = null;
+  Stack historyList = new Stack();
+  Stack redoList = new Stack();
+  private int treeCount = 0;
+
+  /**
+   * new alignment window with hidden columns
+   * @param al AlignmentI
+   * @param hiddenColumns ColumnSelection or null
+   */
+  public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns) {
+
+    viewport = new AlignViewport(al, hiddenColumns);
+
+    this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
+
+    if(viewport.vconsensus==null)
+    {
+      //Out of memory calculating consensus.
+      BLOSUM62Colour.setEnabled(false);
+      PIDColour.setEnabled(false);
+      conservationMenuItem.setEnabled(false);
+      modifyConservation.setEnabled(false);
+      abovePIDThreshold.setEnabled(false);
+      modifyPID.setEnabled(false);
+    }
+
+    alignPanel = new AlignmentPanel(this, viewport);
+
+    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);
+
+   // remove(tabbedPane);
+    getContentPane().add(alignPanel, BorderLayout.CENTER);
+
+
+
+  //  tabbedPane.add(al.isNucleotide() ? "DNA":"Protein", alignPanel);
+
+    ///Dataset tab
+    /////////////////////////
+    if(al.getDataset()==null)
+    {
+      al.setDataset(null);
+    }
+   // AlignViewport ds = new AlignViewport(al.getDataset(), true);
+   // AlignmentPanel dap = new AlignmentPanel(this, ds);
+  //  tabbedPane.add("Dataset", dap);
+  //  viewports.add(ds);
+  //  alignPanels.add(dap);
+    /////////////////////////
+
+
+    viewport.addPropertyChangeListener(new PropertyChangeListener()
+    {
+     public void propertyChange(PropertyChangeEvent evt)
+     {
+       if (evt.getPropertyName().equals("alignment"))
+       {
+         alignmentChanged();
+       }
+     }
+   });
+
+
+    if (Desktop.desktop != null)
+    {
+      addServiceListeners();
+      setGUINucleotide(al.isNucleotide());
+    }
+
+
+    if (jalview.bin.Cache.getDefault("WRAP_ALIGNMENT", false))
+    {
+      wrapMenuItem.setSelected(true);
+      wrapMenuItem_actionPerformed(null);
+    }
+
+  }
+
+
+  /**
+   * Creates a new AlignFrame object.
+   *
+   * @param al DOCUMENT ME!
+   */
+  public AlignFrame(AlignmentI al)
+  {
+    this(al, null);
+  }
+
+  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(null);
+      }
+      ;
+    });
+  }
+
+  public void setGUINucleotide(boolean nucleotide)
+  {
+    showTranslation.setVisible( nucleotide );
+    //sequenceFeatures.setVisible(!nucleotide );
+    //featureSettings.setVisible( !nucleotide );
+    conservationMenuItem.setVisible( !nucleotide );
+    modifyConservation.setVisible(   !nucleotide );
+
+    //Remember AlignFrame always starts as protein
+    if(!nucleotide)
+    {
+      calculateMenu.remove(calculateMenu.getItemCount()-2);
+    }
+  }
+
+  public void comeBackLater(FeatureEvent evt)
+  {}
+
+  public void newFeatures(FeatureEvent evt)
+  {
+    if (evt.getFeatures().length > 0)
+    {
+      alignPanel.seqPanel.seqCanvas.fr.featuresAdded();
+      alignPanel.repaint();
+    }
+  }
+
+  Hashtable progressBars;
+  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);
+    }
+
+    validate();
+  }
+
+
+  /*
+   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 addFromText_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
+  }
+
+  public void addFromURL_actionPerformed(ActionEvent e)
+  {
+    Desktop.instance.inputURLMenuItem_actionPerformed(viewport);
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void saveAlignmentMenu_actionPerformed(ActionEvent e)
+  {
+    JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
+        getProperty( "LAST_DIRECTORY"),
+        new String[]
+        { "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc","jar" },
+        new String[]
+        { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "Jalview" },
+        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;
+        }
+
+      jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",
+                                    currentFileFormat);
+
+      String choice = chooser.getSelectedFile().getPath();
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
+
+      saveAlignment(choice, currentFileFormat);
+    }
+  }
+
+  public boolean saveAlignment(String file, String format)
+  {
+    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);
+      }
+
+      new Jalview2XML().SaveAlignment(this, file, shortName);
+
+      // USE Jalview2XML to save this file
+      return true;
+    }
+    else
+    {
+
+      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);
+      }
+
+      String output = new FormatAdapter().formatSequences(
+          format,
+          viewport.alignment.getSequencesArray(),
+          omitHidden);
+
+      if (output == null)
+      {
+        return false;
+      }
+
+      try
+      {
+        java.io.PrintWriter out = new java.io.PrintWriter(
+            new java.io.FileWriter(file));
+
+        out.print(output);
+        out.close();
+        this.setTitle(file);
+        return true;
+      }
+      catch (Exception ex)
+      {
+        ex.printStackTrace();
+      }
+    }
+    return false;
+  }
+
+  /**
+   * 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();
+    Desktop.addInternalFrame(cap,
+                             "Alignment output - " + e.getActionCommand(), 600,
+                             500);
+
+
+    cap.setText(new FormatAdapter().formatSequences(
+        e.getActionCommand(),
+        viewport.alignment.getSequencesArray(),
+        omitHidden));
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void htmlMenuItem_actionPerformed(ActionEvent e)
+  {
+    new HTMLOutput(viewport,
+                   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);
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void printMenuItem_actionPerformed(ActionEvent e)
+  {
+    //Putting in a thread avoids Swing painting problems
+    PrintThread thread = new PrintThread();
+    thread.start();
+  }
+
+  public void exportFeatures_actionPerformed(ActionEvent e)
+  {
+    new AnnotationExporter().exportFeatures(alignPanel);
+  }
+
+
+  public void exportAnnotations_actionPerformed(ActionEvent e)
+  {
+    new AnnotationExporter().exportAnnotations(
+      alignPanel,
+      viewport.alignment.getAlignmentAnnotation()
+        );
+  }
+
+
+  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);
+    }
+
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void closeMenuItem_actionPerformed(ActionEvent e)
+  {
+    try
+    {
+      PaintRefresher.components.remove(viewport.alignment);
+      this.setClosed(true);
+    }
+    catch (Exception ex)
+    {
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  void updateEditMenuBar()
+  {
+    if (historyList.size() > 0)
+    {
+      undoMenuItem.setEnabled(true);
+
+      HistoryItem hi = (HistoryItem) historyList.peek();
+      undoMenuItem.setText("Undo " + hi.getDescription());
+    }
+    else
+    {
+      undoMenuItem.setEnabled(false);
+      undoMenuItem.setText("Undo");
+    }
+
+    if (redoList.size() > 0)
+    {
+      redoMenuItem.setEnabled(true);
+
+      HistoryItem hi = (HistoryItem) redoList.peek();
+      redoMenuItem.setText("Redo " + hi.getDescription());
+    }
+    else
+    {
+      redoMenuItem.setEnabled(false);
+      redoMenuItem.setText("Redo");
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param hi DOCUMENT ME!
+   */
+  public void addHistoryItem(HistoryItem hi)
+  {
+    historyList.push(hi);
+    redoList.clear();
+    updateEditMenuBar();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void undoMenuItem_actionPerformed(ActionEvent e)
+  {
+    HistoryItem nh,hi = (HistoryItem) historyList.pop();
+    redoList.push(nh=new HistoryItem(hi.getDescription(), viewport.alignment,
+                                  HistoryItem.HIDE));
+    if (hi.alColumnChanges!=null)
+      nh.alColumnChanges = hi.alColumnChanges.getInverse();
+    restoreHistoryItem(hi);
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void redoMenuItem_actionPerformed(ActionEvent e)
+  {
+    HistoryItem nh,hi = (HistoryItem) redoList.pop();
+    historyList.push(nh=new HistoryItem(hi.getDescription(), viewport.alignment,
+        HistoryItem.HIDE)); 
+    if (hi.alColumnChanges!=null)
+      nh.alColumnChanges=hi.alColumnChanges.getInverse();
+    restoreHistoryItem(hi);
+    updateEditMenuBar();
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
+  }
+
+  // used by undo and redo
+  void restoreHistoryItem(HistoryItem hi)
+  {
+
+    hi.restore(viewport.getColumnSelection());
+
+    updateEditMenuBar();
+
+    viewport.firePropertyChange("alignment", null,
+                                viewport.getAlignment().getSequences());
+  }
+
+  /**
+   * 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(false).contains(seq))
+        {
+          continue;
+        }
+
+        SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
+
+        if (sg.getSequences(false).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(false).contains(seq))
+        {
+          continue;
+        }
+
+        SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
+
+        if (sg.getSequences(false).contains(temp))
+        {
+          continue;
+        }
+
+        viewport.alignment.getSequences().setElementAt(temp, i);
+        viewport.alignment.getSequences().setElementAt(seq, i + 1);
+      }
+    }
+
+    alignPanel.repaint();
+  }
+
+
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void copy_actionPerformed(ActionEvent e)
+  {
+    if (viewport.getSelectionGroup() == null)
+    {
+      return;
+    }
+
+    SequenceI [] seqs = viewport.getSelectionAsNewSequence();
+    String[] omitHidden = null;
+
+    if (viewport.hasHiddenColumns)
+    {
+      omitHidden = viewport.getViewAsString(true);
+    }
+
+    String output = new FormatAdapter().formatSequences(
+        "Fasta",
+        seqs,
+        omitHidden);
+
+
+    Toolkit.getDefaultToolkit().getSystemClipboard()
+        .setContents(new StringSelection(output), Desktop.instance);
+
+    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};
+  }
+
+  /**
+   * 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)
+  {
+    addHistoryItem(new HistoryItem("Paste Sequences", viewport.alignment,
+                                   HistoryItem.PASTE));
+    paste(false);
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param newAlignment DOCUMENT ME!
+   */
+  void paste(boolean newAlignment)
+  {
+    try
+    {
+      Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
+      Transferable contents = c.getContents(this);
+
+      if (contents == null)
+      {
+        return;
+      }
+
+      String str = (String) contents.getTransferData(DataFlavor.stringFlavor);
+      if(str.length()<1)
+        return;
+
+      String format = new IdentifyFile().Identify(str, "Paste");
+      SequenceI[] sequences;
+
+
+     if(Desktop.jalviewClipboard!=null)
+     {
+       // The clipboard was filled from within Jalview, we must use the sequences
+       // And dataset from the copied alignment
+       sequences = (SequenceI[])Desktop.jalviewClipboard[0];
+     }
+     else
+     {
+       sequences = new FormatAdapter().readFile(str, "Paste", format);
+     }
+
+     AlignmentI alignment = null;
+
+      if (newAlignment)
+      {
+        alignment = new Alignment(sequences);
+
+        if(Desktop.jalviewClipboard!=null)
+           alignment.setDataset( (Alignment)Desktop.jalviewClipboard[1] );
+        else
+           alignment.setDataset( null );
+
+      }
+      else
+      {
+        alignment = viewport.getAlignment();
+
+        //!newAlignment
+        for (int i = 0; i < sequences.length; i++)
+        {
+          Sequence newseq = new Sequence(sequences[i].getName(),
+              sequences[i].getSequence(), sequences[i].getStart(),
+              sequences[i].getEnd());
+
+          alignment.addSequence(newseq);
+        }
+
+
+        viewport.setEndSeq(alignment.getHeight());
+        alignment.getWidth();
+        viewport.firePropertyChange("alignment", null, alignment.getSequences());
+      }
+
+
+
+
+
+      // 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++)
+         {
+           AlignmentAnnotation newAnnot =
+               new AlignmentAnnotation(
+                   sequences[i].getAnnotation()[a].label,
+                   sequences[i].getAnnotation()[a].description,
+                   sequences[i].getAnnotation()[a].annotations,
+                   sequences[i].getAnnotation()[a].graphMin,
+                   sequences[i].getAnnotation()[a].graphMax,
+                   sequences[i].getAnnotation()[a].graph);
+
+           sequences[i].getAnnotation()[a] = newAnnot;
+           newAnnot.sequenceMapping = sequences[i].getAnnotation()[a].
+               sequenceMapping;
+           newAnnot.sequenceRef = sequences[i];
+           newAnnot.adjustForAlignment();
+           alignment.addAnnotation(newAnnot);
+           alignment.setAnnotationIndex(newAnnot, a);
+         }
+
+         alignPanel.annotationPanel.adjustPanelHeight();
+       }
+     }
+
+     if(newAlignment)
+     {
+       AlignFrame af = new AlignFrame(alignment);
+       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());
+
+
+       if (title.startsWith("Copied sequences"))
+       {
+         newtitle = title;
+       }
+       else
+       {
+         newtitle = newtitle.concat("- from " + title);
+       }
+
+       Desktop.addInternalFrame(af, newtitle, NEW_WINDOW_WIDTH,
+                                NEW_WINDOW_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 e)
+  {
+
+    if (viewport.getSelectionGroup() == null)
+    {
+      return;
+    }
+
+
+    SequenceGroup sg = viewport.getSelectionGroup();
+
+
+
+    //Jalview no longer allows deletion of residues.
+    //Check here whether any residues are in selection area
+   /* if( sg.getEndRes()-sg.getStartRes() < viewport.alignment.getWidth()-1)
+    {
+      for (int i = 0; i < sg.sequences.size(); i++)
+      {
+        SequenceI seq = sg.getSequenceAt(i);
+        int j = sg.getStartRes();
+        do
+        {
+          if (!jalview.util.Comparison.isGap(seq.getCharAt(j)))
+          {
+            JOptionPane.showInternalMessageDialog(
+                Desktop.desktop, "Cannot delete residues from alignment!\n"
+                + "Try hiding columns instead.",
+                "Deletion of residues not permitted",
+                JOptionPane.WARNING_MESSAGE);
+
+            return;
+          }
+          j++;
+        }while(j<=sg.getEndRes());
+      }
+    }*/
+
+
+    addHistoryItem(new HistoryItem("Delete Sequences", viewport.alignment,
+                                   HistoryItem.HIDE));
+
+
+    for (int i = 0; i < sg.getSize(false); i++)
+    {
+      SequenceI seq = sg.getSequenceAt(i);
+      int index = viewport.getAlignment().findIndex(seq);
+
+      seq.deleteChars(sg.getStartRes(), sg.getEndRes() + 1);
+
+      // If the cut affects all sequences, remove highlighted columns
+      if (sg.getSize(false) == viewport.alignment.getHeight())
+      {
+        viewport.getColumnSelection().removeElements(sg.getStartRes(),
+            sg.getEndRes() + 1);
+      }
+
+      if (seq.getSequence().length() < 1)
+      {
+        viewport.getAlignment().deleteSequence(seq);
+      }
+      else
+      {
+        viewport.getAlignment().getSequences().setElementAt(seq, index);
+      }
+    }
+
+    viewport.setSelectionGroup(null);
+    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.setSelectionGroup(null);
+    alignPanel.repaint();
+  }
+
+  /**
+   * 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);
+    PaintRefresher.Refresh(null, viewport.alignment);
+  }
+
+  /**
+   * 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.repaint();
+    PaintRefresher.Refresh(null, viewport.alignment);
+  }
+
+  /**
+   * 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);
+    }
+
+    PaintRefresher.Refresh(null, viewport.alignment);
+  }
+
+  public void invertColSel_actionPerformed(ActionEvent e)
+  {
+    viewport.invertColumnSelection();
+    alignPanel.repaint();
+  }
+
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
+  {
+    ColumnSelection colSel = viewport.getColumnSelection();
+
+    if (colSel.size() > 0)
+    {
+      HistoryItem edit;
+      addHistoryItem(edit=new HistoryItem("Remove Left", viewport.alignment,
+                                     HistoryItem.HIDE));
+
+      int min = colSel.getMin();
+      viewport.getAlignment().trimLeft(min);
+      colSel.compensateForEdit(0, min);
+      edit.addShift(0,min);
+      if (viewport.getSelectionGroup() != null)
+      {
+        viewport.getSelectionGroup().adjustForRemoveLeft(min);
+      }
+
+      Vector groups = viewport.alignment.getGroups();
+
+      for (int i = 0; i < groups.size(); i++)
+      {
+        SequenceGroup sg = (SequenceGroup) groups.get(i);
+
+        if (!sg.adjustForRemoveLeft(min))
+        {
+          viewport.alignment.deleteGroup(sg);
+        }
+      }
+
+      viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void remove2RightMenuItem_actionPerformed(ActionEvent e)
+  {
+    ColumnSelection colSel = viewport.getColumnSelection();
+
+    if (colSel.size() > 0)
+    {
+      addHistoryItem(new HistoryItem("Remove Right", viewport.alignment,
+                                     HistoryItem.HIDE));
+
+      int max = colSel.getMax();
+      viewport.getAlignment().trimRight(max);
+      // TODO: delete hidden column entries in colSel to right of max
+      // TODO: record hidden columns in history for undo.
+      if (viewport.getSelectionGroup() != null)
+      {
+        viewport.getSelectionGroup().adjustForRemoveRight(max);
+      }
+
+      Vector groups = viewport.alignment.getGroups();
+
+      for (int i = 0; i < groups.size(); i++)
+      {
+        SequenceGroup sg = (SequenceGroup) groups.get(i);
+
+        if (!sg.adjustForRemoveRight(max))
+        {
+          viewport.alignment.deleteGroup(sg);
+        }
+      }
+
+      viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
+  {
+    HistoryItem edit;
+    addHistoryItem(edit=new HistoryItem("Remove Gapped Columns",
+                                   viewport.alignment, HistoryItem.HIDE));
+
+    //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)
+  {
+    // TODO: hidden regions should not be touched by removeAllGaps - a minimal number of gaps will remain in alignment segments containing uneven length subsequences
+    // TODO: columnSelection.compensateforedits should be called (and passed to history item)
+    addHistoryItem(new HistoryItem("Remove Gaps", viewport.alignment,
+                                   HistoryItem.HIDE));
+
+    //This is to maintain viewport position on first residue
+    //of first sequence
+    SequenceI seq = viewport.alignment.getSequenceAt(0);
+    int startRes = seq.findPosition(viewport.startRes);
+
+
+    SequenceI current;
+    int jSize;
+
+    Vector seqs = null;
+
+    int start = 0;
+    int end = viewport.alignment.getWidth();
+
+    if (viewport.getSelectionGroup() != null
+        && viewport.getSelectionGroup().getSequences(true) != null
+        && viewport.getSelectionGroup().getSize(true) > 0)
+    {
+      seqs = viewport.getSelectionGroup().getSequences(true);
+      start = viewport.getSelectionGroup().getStartRes();
+      end = viewport.getSelectionGroup().getEndRes()+1;
+    }
+    else
+    {
+      seqs = viewport.alignment.getSequences();
+    }
+    /* Commented out regions below are partial implementation of todo above.
+       * divide start,end into visible chunks, and for each:
+      int diff=end-start+1;
+      int diffmax=0;
+      int dr[] = new int[seqs.size()];
+      */
+     for (int i = 0; i < seqs.size(); i++)
+     {
+       current = (SequenceI) seqs.elementAt(i);
+       //dr[i]=
+       current.removeGaps(start, end);
+       /*if (d<diff) // can only shift 
+         diff=d;
+       if (diffmax<d)
+         diffmax=d;
+         */
+     }
+     /* // after the end of each chunk - 
+      * if (diff>0) {
+      // record shift for history.
+       editgaps.addShift(start, diff);
+       if (viewport.hasHiddenColumns && diffmax>diff) {
+       // pad sequence
+        StringBuffer gaps=new StringBuffer(diffmax);
+        for (int i=0,j=diffmax-diff; i<j; i++)
+        gaps.append(viewport.getGapCharacter());
+        for (int i=0, j=seqs.size(); i<j; i++) {
+        current = (SequenceI) seqs.elementAt(i);
+        if (dr[i]-diff>0) {
+        String sq = current.getSequence();
+        current.setSequence(sq.substring(0, hcend-dr[i])+gaps.substring(0, dr[i]-diff)+sq.substring()); 
+        }
+        }
+       } 
+       }*/
+
+    viewport.setStartRes(seq.findIndex(startRes)-1);
+
+    viewport.firePropertyChange("alignment", null, viewport.getAlignment().getSequences());
+  }
+
+ public void alignmentChanged()
+ {
+   if(viewport.padGaps)
+     viewport.getAlignment().padGaps();
+
+   if(viewport.vconsensus!=null && viewport.autoCalculateConsensus)
+   {
+     viewport.updateConsensus();
+     viewport.updateConservation();
+   }
+
+   resetAllColourSchemes();
+   if(alignPanel.overviewPanel!=null)
+     alignPanel.overviewPanel.updateOverviewImage();
+
+   viewport.alignment.adjustSequenceAnnotations();
+
+   if(alignPanel.overviewPanel!=null)
+     alignPanel.overviewPanel.updateOverviewImage();
+
+   alignPanel.repaint();
+ }
+
+  void resetAllColourSchemes()
+  {
+    ColourSchemeI cs = viewport.globalColourScheme;
+    if(cs!=null)
+    {
+      if (cs instanceof ClustalxColourScheme)
+      {
+        ( (ClustalxColourScheme) viewport.getGlobalColourScheme()).
+            resetClustalX(viewport.alignment.getSequences(),
+                          viewport.alignment.getWidth());
+      }
+
+      cs.setConsensus(viewport.vconsensus);
+      if (cs.conservationApplied())
+      {
+        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);
+      }
+    }
+
+    int s, sSize = viewport.alignment.getGroups().size();
+    for(s=0; s<sSize; s++)
+    {
+      SequenceGroup sg = (SequenceGroup)viewport.alignment.getGroups().elementAt(s);
+      if(sg.cs!=null && sg.cs instanceof ClustalxColourScheme)
+      {
+        ((ClustalxColourScheme)sg.cs).resetClustalX(
+            sg.getSequences(true), sg.getWidth());
+      }
+      sg.recalcConservation();
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void padGapsMenuitem_actionPerformed(ActionEvent e)
+  {
+    addHistoryItem(new HistoryItem("Pad Gaps", viewport.alignment,
+                                   HistoryItem.HIDE));
+
+    viewport.padGaps = padGapsMenuitem.isSelected();
+
+   // if (viewport.padGaps)
+    alignmentChanged();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void findMenuItem_actionPerformed(ActionEvent e)
+  {
+    JInternalFrame frame = new JInternalFrame();
+    Finder finder = new Finder(viewport, alignPanel, frame);
+    frame.setContentPane(finder);
+    frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    Desktop.addInternalFrame(frame, "Find", 340, 110);
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void font_actionPerformed(ActionEvent e)
+  {
+    new FontChooser(alignPanel);
+  }
+
+  public void smoothFont_actionPerformed(ActionEvent e)
+  {
+    viewport.antiAlias = smoothFont.isSelected();
+    alignPanel.annotationPanel.image = null;
+    alignPanel.repaint();
+  }
+
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void seqLimit_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowJVSuffix(seqLimits.isSelected());
+
+    alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel.calculateIdWidth());
+    alignPanel.repaint();
+  }
+
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void colourTextMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setColourText(colourTextMenuItem.isSelected());
+    alignPanel.repaint();
+  }
+
+  /**
+   * 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();
+  }
+
+  public void hideSelColumns_actionPerformed(ActionEvent e)
+  {
+    viewport.hideSelectedColumns();
+    alignPanel.repaint();
+  }
+
+  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.repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void scaleLeft_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleLeftWrapped(scaleLeft.isSelected());
+    alignPanel.repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void scaleRight_actionPerformed(ActionEvent e)
+  {
+    viewport.setScaleRightWrapped(scaleRight.isSelected());
+    alignPanel.repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
+    alignPanel.repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void viewTextMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setShowText(viewTextMenuItem.isSelected());
+    alignPanel.repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
+  {
+    viewport.setRenderGaps(renderGapsMenuItem.isSelected());
+    alignPanel.repaint();
+  }
+
+
+  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.repaint();
+    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());
+  }
+
+  /**
+   * 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);
+  }
+
+  /**
+   * 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.vconsensus);
+    }
+
+    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(true), 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(true), 0,
+             sg.getWidth()));
+       }
+        else
+          sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
+
+
+        if (viewport.getConservationSelected())
+        {
+          Conservation c = new Conservation("Group",
+                                            ResidueProperties.propHash, 3,
+                                            sg.getSequences(true), 0,
+                                            viewport.alignment.getWidth() - 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.repaint();
+  }
+
+  /**
+   * 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)
+  {
+    addHistoryItem(new HistoryItem("Pairwise Sort", viewport.alignment,
+                                   HistoryItem.SORT));
+    AlignmentSorter.sortByPID(viewport.getAlignment(),
+                              viewport.getAlignment().getSequenceAt(0));
+    alignPanel.repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void sortIDMenuItem_actionPerformed(ActionEvent e)
+  {
+    addHistoryItem(new HistoryItem("ID Sort", viewport.alignment,
+                                   HistoryItem.SORT));
+    AlignmentSorter.sortByID(viewport.getAlignment());
+    alignPanel.repaint();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void sortGroupMenuItem_actionPerformed(ActionEvent e)
+  {
+    addHistoryItem(new HistoryItem("Group Sort", viewport.alignment,
+                                   HistoryItem.SORT));
+
+    AlignmentSorter.sortByGroup(viewport.getAlignment());
+    alignPanel.repaint();
+  }
+
+  /**
+   * 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(false) < 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(false) < 4) &&
+          (viewport.getSelectionGroup().getSize(false) > 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(viewport);
+  }
+
+
+  public void autoCalculate_actionPerformed(ActionEvent e)
+  {
+    viewport.autoCalculateConsensus = autoCalculate.isSelected();
+    if(viewport.autoCalculateConsensus)
+    {
+      alignmentChanged();
+    }
+  }
+
+
+  /**
+   * 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) &&
+        (viewport.getSelectionGroup().getSize(false) > 3))
+    {
+      int s = 0;
+      SequenceGroup sg = viewport.getSelectionGroup();
+
+      /* Decide if the selection is a column region */
+      while (s < sg.getSize(false))
+      {
+        if ( ( (SequenceI) sg.getSequences(false).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(viewport, 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(viewport, type, pwType);
+    }
+
+    addTreeMenuItem(tp, title);
+
+    Desktop.addInternalFrame(tp, title + " from " + this.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)
+      {
+        addHistoryItem(new HistoryItem("Sort", viewport.alignment,
+                                       HistoryItem.SORT));
+
+        // TODO: JBPNote - have to map order entries to curent SequenceI pointers
+        AlignmentSorter.sortBy(viewport.getAlignment(), order);
+        alignPanel.repaint();
+      }
+    });
+  }
+
+  /**
+   * 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.
+   */
+  void addTreeMenuItem(final TreePanel treePanel, String title)
+  {
+    final JMenuItem item = new JMenuItem(title);
+
+    treeCount++;
+
+    if (treeCount == 1)
+    {
+      sort.add(sortByTreeMenu);
+    }
+
+    sortByTreeMenu.add(item);
+    item.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        addHistoryItem(new HistoryItem("Tree Sort",
+                                       viewport.alignment, HistoryItem.SORT));
+        AlignmentSorter.sortByTree(viewport.getAlignment(),
+                                   treePanel.getTree());
+        alignPanel.repaint();
+      }
+    });
+
+    treePanel.addInternalFrameListener(new javax.swing.event.
+                                       InternalFrameAdapter()
+    {
+      public void internalFrameClosed(
+          javax.swing.event.InternalFrameEvent evt)
+      {
+        treeCount--;
+        sortByTreeMenu.remove(item);
+
+        if (treeCount == 0)
+        {
+          sort.remove(sortByTreeMenu);
+        }
+      }
+      ;
+    });
+  }
+
+  /**
+   * Work out whether the whole set of sequences
+   * or just the selected set will be submitted for multiple alignment.
+   *
+   */
+  private jalview.datamodel.AlignmentView gatherSequencesForAlignment()
+  {
+    // Now, check we have enough sequences
+    AlignmentView msa = null;
+
+    if ( (viewport.getSelectionGroup() != null) &&
+        (viewport.getSelectionGroup().getSize(false) > 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 currently selected sequence, or the currently selected alignment
+   * (where the first sequence in the set is the one that the prediction
+   * will be for).
+   */
+  AlignmentView gatherSeqOrMsaForSecStrPrediction()
+  {
+   AlignmentView seqs = null;
+
+    if ( (viewport.getSelectionGroup() != null) &&
+        (viewport.getSelectionGroup().getSize(false) > 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);
+
+      try
+      {
+        jalview.io.NewickFile fin = new jalview.io.NewickFile(choice,
+            "File");
+        viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
+      }
+      catch (Exception ex)
+      {
+        JOptionPane.showMessageDialog(Desktop.desktop,
+                                      "Problem reading tree file",
+                                      ex.getMessage(),
+                                      JOptionPane.WARNING_MESSAGE);
+        ex.printStackTrace();
+      }
+    }
+  }
+
+
+  public TreePanel ShowNewickTree(NewickFile nf, String title)
+  {
+    return ShowNewickTree(nf,title,600,500,4,5);
+  }
+  /**
+   * DOCUMENT ME!
+   *
+   * @param nf DOCUMENT ME!
+   * @param title DOCUMENT ME!
+   *
+   * @return DOCUMENT ME!
+   */
+  public TreePanel ShowNewickTree(NewickFile nf, String title, int w,int h,int x, int y)
+  {
+    TreePanel tp = null;
+
+    try
+    {
+      nf.parse();
+
+      if (nf.getTree() != null)
+      {
+        tp = new TreePanel(viewport,
+                           "FromFile",
+                           title,
+                           nf);
+
+        tp.setSize(w,h);
+
+        if(x>0 && y>0)
+          tp.setLocation(x,y);
+
+
+        Desktop.addInternalFrame(tp, title, w, h);
+        addTreeMenuItem(tp, title);
+      }
+    }
+    catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+
+    return tp;
+  }
+
+  class PrintThread
+      extends Thread
+  {
+    public void run()
+    {
+      PrinterJob printJob = PrinterJob.getPrinterJob();
+      PageFormat pf = printJob.pageDialog(printJob.defaultPage());
+      printJob.setPrintable(alignPanel, pf);
+
+      if (printJob.printDialog())
+      {
+        try
+        {
+          printJob.print();
+        }
+        catch (Exception PrintException)
+        {
+          PrintException.printStackTrace();
+        }
+      }
+    }
+  }
+
+  /**
+   * Generates menu items and listener event actions for web service clients
+   *
+   */
+  public void BuildWebServiceMenu()
+  {
+    if ( (Discoverer.services != null)
+        && (Discoverer.services.size() > 0))
+    {
+      Vector msaws = (Vector) Discoverer.services.get("MsaWS");
+      Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred");
+      Vector wsmenu = new Vector();
+      final AlignFrame 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);
+          final JMenuItem method = new JMenuItem(sh.getName());
+          method.addActionListener(new ActionListener()
+          {
+            public void actionPerformed(ActionEvent e)
+            {
+              AlignmentView msa = gatherSequencesForAlignment();
+              new jalview.ws.MsaWSClient(sh, title, msa,
+                  false, true, viewport.getAlignment().getDataset(), af);
+
+            }
+
+          });
+          msawsmenu.add(method);
+          // Deal with services that we know accept partial alignments.
+          if (sh.getName().indexOf("lustal") > -1)
+          {
+            // We know that ClustalWS can accept partial alignments for refinement.
+            final JMenuItem methodR = new JMenuItem(sh.getName()+" Realign");
+            methodR.addActionListener(new ActionListener()
+            {
+              public void actionPerformed(ActionEvent e)
+              {
+                AlignmentView msa = gatherSequencesForAlignment();
+                new jalview.ws.MsaWSClient(sh, title, msa,
+                    true, true, viewport.getAlignment().getDataset(), af);
+
+              }
+
+            });
+            msawsmenu.add(methodR);
+
+          }
+        }
+        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);
+          final JMenuItem method = new JMenuItem(sh.getName());
+          method.addActionListener(new ActionListener()
+          {
+            public void actionPerformed(ActionEvent e)
+            {
+              AlignmentView msa = gatherSeqOrMsaForSecStrPrediction();
+              if (msa.getSequences().length == 1)
+              {
+                // Single Sequence prediction
+                new jalview.ws.JPredClient(sh, title, false, msa, af);
+              }
+              else
+              {
+                if (msa.getSequences().length > 1)
+                {
+                  // Sequence profile based prediction
+                  new jalview.ws.JPredClient(sh,
+                      title, true, msa, af);
+                }
+              }
+            }
+          });
+          secstrmenu.add(method);
+        }
+        wsmenu.add(secstrmenu);
+      }
+      this.webService.removeAll();
+      for (int i = 0, j = wsmenu.size(); i < j; i++)
+      {
+        webService.add( (JMenu) wsmenu.get(i));
+      }
+    }
+    else
+    {
+      this.webService.removeAll();
+      this.webService.add(this.webServiceNoServices);
+    }
+    // TODO: add in rediscovery function
+    // TODO: reduce code redundancy.
+    // TODO: group services by location as well as function.
+  }
+
+ /* 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);
+    }
+  }*/
+
+
+
+
+public void showTranslation_actionPerformed(ActionEvent e)
+{
+  SequenceI [] selection = viewport.getSelectionAsNewSequence();
+  String [] seqstring = viewport.getViewAsString(true);
+
+  int s, sSize = selection.length;
+  SequenceI [] newSeq = new SequenceI[sSize];
+
+  int res, resSize;
+  StringBuffer protein;
+  String seq;
+  for(s=0; s<sSize; s++)
+  {
+    protein = new StringBuffer();
+    seq = AlignSeq.extractGaps("-. ", seqstring[s]);
+    resSize = seq.length();
+    resSize -= resSize%3;
+
+    for(res = 0; res < resSize; res+=3)
+    {
+      String codon = seq.substring(res, res+3);
+      codon = codon.replace('U', 'T');
+      String aa = ResidueProperties.codonTranslate(codon);
+      if(aa==null)
+        protein.append(viewport.getGapCharacter());
+      else if(aa.equals("STOP"))
+        protein.append("X");
+      else
+        protein.append( aa );
+    }
+    newSeq[s] = new Sequence(selection[s].getName(),
+                             protein.toString());
+  }
+
+
+  AlignmentI al = new Alignment(newSeq);
+  al.setDataset(null);
+
+
+  ////////////////////////////////
+  // Copy annotations across
+  jalview.datamodel.AlignmentAnnotation[] annotations
+      = viewport.alignment.getAlignmentAnnotation();
+  int a, aSize;
+  if(annotations!=null)
+  {
+    for (int i = 0; i < annotations.length; i++)
+    {
+      if (annotations[i].label.equals("Quality") ||
+          annotations[i].label.equals("Conservation") ||
+          annotations[i].label.equals("Consensus"))
+      {
+        continue;
+      }
+
+      aSize = viewport.alignment.getWidth() / 3;
+      jalview.datamodel.Annotation[] anots =
+          new jalview.datamodel.Annotation[aSize];
+
+      for (a = 0; a < viewport.alignment.getWidth(); a++)
+      {
+        if (annotations[i].annotations[a] == null
+            || annotations[i].annotations[a] == null)
+          continue;
+
+        anots[a / 3] = new Annotation(
+            annotations[i].annotations[a].displayCharacter,
+            annotations[i].annotations[a].description,
+            annotations[i].annotations[a].secondaryStructure,
+            annotations[i].annotations[a].value,
+            annotations[i].annotations[a].colour);
+      }
+
+      jalview.datamodel.AlignmentAnnotation aa
+          = new jalview.datamodel.AlignmentAnnotation(annotations[i].label,
+          annotations[i].description, anots);
+      al.addAnnotation(aa);
+    }
+  }
+
+    AlignFrame af = new AlignFrame(al);
+    Desktop.addInternalFrame(af, "Translation of "+this.getTitle(),
+                             NEW_WINDOW_WIDTH,
+                             NEW_WINDOW_HEIGHT);
+
+
+   // AlignViewport newViewport = new AlignViewport(al);
+   // AlignmentPanel ap = new AlignmentPanel(this, newViewport);
+   // tabbedPane.add("Protein", ap);
+   // viewports.add(newViewport);
+  //  alignPanels.add(ap);
+
+    ///Dataset tab
+  /////////////////////////
+
+  //  AlignViewport ds = new AlignViewport(al.getDataset());
+  //  ds.setDataset(true);
+  //  AlignmentPanel dap = new AlignmentPanel(this, ds);
+  //  tabbedPane.add("Dataset", dap);
+  //  viewports.add(ds);
+  //  alignPanels.add(dap);
+  /////////////////////////
+
+
+}
+
+/*public void tabSelected()
+ {
+  int index = tabbedPane.getSelectedIndex();
+  viewport = (AlignViewport)viewports.elementAt(index);
+  alignPanel = (AlignmentPanel)alignPanels.elementAt(index);
+ }*/
+
+/**
+ * DOCUMENT ME!
+ *
+ * @param String DOCUMENT ME!
+ */
+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.repaint();
+    }
+
+    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();
+      }
+    }
+}
+
+  // This method will attempt to load a "dropped" file first by testing
+  // whether its and Annotation file, then features file. If both are
+  // false then the user may have dropped an alignment file onto this
+  // AlignFrame
+   public void loadJalviewDataFile(String file)
+  {
+    try{
+      boolean isAnnotation = new AnnotationFile().readAnnotationFile(viewport.
+          alignment, file);
+
+      if (!isAnnotation)
+      {
+        boolean isGroupsFile = parseFeaturesFile(file,
+                                                AppletFormatAdapter.FILE);
+        if (!isGroupsFile)
+        {
+          String format = new IdentifyFile().Identify(file, FormatAdapter.FILE);
+          new FileLoader().LoadFile(viewport, file, FormatAdapter.FILE, format);
+        }
+      }
+      else
+      {
+        // (isAnnotation)
+        alignPanel.adjustAnnotationHeight();
+      }
+
+    }catch(Exception ex)
+    {
+      ex.printStackTrace();
+    }
+  }
+}
index d7e75f4..366c90a 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 Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
- */\r
-package jalview.ws;\r
-\r
-import java.util.*;\r
-\r
-import javax.swing.*;\r
-\r
-import ext.vamsas.*;\r
-import jalview.analysis.*;\r
-import jalview.bin.*;\r
-import jalview.datamodel.*;\r
-import jalview.datamodel.Alignment;\r
-import jalview.datamodel.AlignmentView;\r
-import jalview.gui.*;\r
-import jalview.io.*;\r
-import jalview.util.*;\r
-import jalview.ws.WSThread.*;\r
-import vamsas.objects.simple.*;\r
-\r
-public class JPredClient\r
-    extends WSClient\r
-{\r
-  AlignFrame parentFrame=null;\r
-    /**\r
-     * crate a new GUI JPred Job\r
-     * @param sh ServiceHandle\r
-     * @param title String\r
-     * @param msa boolean - true - submit alignment as a sequence profile\r
-     * @param alview AlignmentView\r
-     */\r
-    public JPredClient(ext.vamsas.ServiceHandle sh, String title, boolean msa, AlignmentView alview, AlignFrame parentFrame) {\r
-    wsInfo=setWebService(sh);\r
-    this.parentFrame=parentFrame;\r
-    startJPredClient(title, msa, alview);\r
-\r
-  }\r
-\r
-  /**\r
-   * startJPredClient\r
-   *\r
-   * @param title String\r
-   * @param msa boolean\r
-   * @param alview AlignmentView\r
-   */\r
-  private void startJPredClient(String title, boolean msa,\r
-                                jalview.datamodel.AlignmentView alview)\r
-  {\r
-  }\r
-\r
-  public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI seq, AlignFrame parentFrame)\r
-  {\r
-    wsInfo = setWebService(sh);\r
-    this.parentFrame=parentFrame;\r
-    startJPredClient(title, seq);\r
-  }\r
-\r
-  public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI[] msa, AlignFrame parentFrame)\r
-  {\r
-    wsInfo = setWebService(sh);\r
-    this.parentFrame=parentFrame;\r
-    startJPredClient(title, msa);\r
-  }\r
-\r
-  public JPredClient(String title, SequenceI[] msf)\r
-  {\r
-    startJPredClient(title, msf);\r
-  }\r
-\r
-  public JPredClient(String title, SequenceI seq)\r
-  {\r
-    startJPredClient(title, seq);\r
-  }\r
-\r
-  private void startJPredClient(String title, SequenceI[] msf)\r
-  {\r
-    if (wsInfo == null)\r
-    {\r
-      wsInfo = setWebService();\r
-    }\r
-\r
-    SequenceI seq = msf[0];\r
-\r
-    String altitle = "JNet prediction on " + seq.getName() +\r
-        " using alignment from " + title;\r
-\r
-    wsInfo.setProgressText("Job details for MSA based prediction (" +\r
-                           title + ") on sequence :\n>" + seq.getName() + "\n" +\r
-                           AlignSeq.extractGaps("-. ", seq.getSequence()) +\r
-                           "\n");\r
-    SequenceI aln[] = new SequenceI[msf.length];\r
-    for (int i = 0, j = msf.length; i < j; i++)\r
-    {\r
-      aln[i] = new jalview.datamodel.Sequence(msf[i]);\r
-    }\r
-\r
-    Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true);\r
-\r
-    Jpred server = locateWebService();\r
-    if (server==null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, aln);\r
-    wsInfo.setthisService(jthread);\r
-    jthread.start();\r
-  }\r
-\r
-  public void startJPredClient(String title, SequenceI seq)\r
-  {\r
-    if (wsInfo == null)\r
-    {\r
-      wsInfo = setWebService();\r
-    }\r
-    wsInfo.setProgressText("Job details for prediction on sequence :\n>" +\r
-                           seq.getName() + "\n" +\r
-                           AlignSeq.extractGaps("-. ", seq.getSequence()) +\r
-                           "\n");\r
-    String altitle = "JNet prediction for sequence " + seq.getName() + " from " +\r
-        title;\r
-\r
-    Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash(seq);\r
-\r
-    Jpred server = locateWebService();\r
-    if (server==null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, seq);\r
-    wsInfo.setthisService(jthread);\r
-    jthread.start();\r
-  }\r
-\r
-  private WebserviceInfo setWebService()\r
-  {\r
-    WebServiceName = "JNetWS";\r
-    WebServiceJobTitle = "JNet secondary structure prediction";\r
-    WebServiceReference =\r
-        "\"Cuff J. A and Barton G.J (2000) Application of " +\r
-        "multiple sequence alignment profiles to improve protein secondary structure prediction, " +\r
-        "Proteins 40:502-511\".";\r
-    WsURL = "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred";\r
-\r
-    WebserviceInfo wsInfo = new WebserviceInfo(WebServiceJobTitle,\r
-                                               WebServiceReference);\r
-\r
-    return wsInfo;\r
-  }\r
-\r
-  private ext.vamsas.Jpred locateWebService()\r
-  {\r
-    ext.vamsas.JpredServiceLocator loc = new JpredServiceLocator(); // Default\r
-    ext.vamsas.Jpred server=null;\r
-    try\r
-    {\r
-      server = loc.getjpred(new java.net.URL(WsURL)); // JBPNote will be set from properties\r
-      ( (JpredSoapBindingStub)server).setTimeout(60000); // one minute stub\r
-      //((JpredSoapBindingStub)this.server)._setProperty(org.apache.axis.encoding.C, Boolean.TRUE);\r
-\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-      JOptionPane.showMessageDialog(Desktop.desktop,\r
-                                    "The Secondary Structure Prediction Service named " +\r
-                                    WebServiceName + " at " + WsURL +\r
-                                    " couldn't be located.",\r
-                                    "Internal Jalview Error",\r
-                                    JOptionPane.WARNING_MESSAGE);\r
-      wsInfo.setProgressText("Serious! " + WebServiceName +\r
-                             " Service location failed\nfor URL :" + WsURL +\r
-                             "\n" +\r
-                             ex.getMessage());\r
-      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
-\r
-    }\r
-\r
-    return server;\r
-  }\r
-\r
-  class JPredThread\r
-      extends WSThread\r
-      implements WSClientI\r
-  {\r
-    class JPredJob\r
-        extends WSThread.WSJob\r
-    {\r
-\r
-      vamsas.objects.simple.Sequence sequence;\r
-      vamsas.objects.simple.Msfalignment msa;\r
-      java.util.Hashtable SequenceInfo = null;\r
-      /**\r
-       *\r
-       * @return true if getResultSet will return a valid alignment and prediction result.\r
-       */\r
-      public boolean hasResults()\r
-      {\r
-        if (subjobComplete && result != null && result.isFinished()\r
-            && ( (JpredResult) result).getPredfile() != null &&\r
-            ( (JpredResult) result).getAligfile() != null)\r
-        {\r
-          return true;\r
-        }\r
-        return false;\r
-      }\r
-\r
-      boolean hasValidInput()\r
-      {\r
-        if (sequence != null)\r
-        {\r
-          return true;\r
-        }\r
-        return false;\r
-      }\r
-\r
-      public Alignment getResultSet()\r
-          throws Exception\r
-      {\r
-        if (result == null || !result.isFinished())\r
-        {\r
-          return null;\r
-        }\r
-        Alignment al = null;\r
-        int FirstSeq = -1; // the position of the query sequence in Alignment al\r
-        boolean noMsa = true; // set if no MSA has been returned by JPred\r
-\r
-        JpredResult result = (JpredResult)this.result;\r
-\r
-        jalview.bin.Cache.log.debug("Parsing output from JNet job.");\r
-        // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File");\r
-        jalview.io.JPredFile prediction = new jalview.io.JPredFile(result.\r
-            getPredfile(),\r
-            "Paste");\r
-        SequenceI[] preds = prediction.getSeqsAsArray();\r
-        jalview.bin.Cache.log.debug("Got prediction profile.");\r
-\r
-        if ( (this.msa != null) && (result.getAligfile() != null))\r
-        {\r
-          jalview.bin.Cache.log.debug("Getting associated alignment.");\r
-          // we ignore the returned alignment if we only predicted on a single sequence\r
-          String format = new jalview.io.IdentifyFile().Identify(result.\r
-              getAligfile(),\r
-              "Paste");\r
-\r
-          if (jalview.io.FormatAdapter.isValidFormat(format))\r
-          {\r
-            al = new Alignment(new FormatAdapter().readFile(result.getAligfile(),\r
-                "Paste", format));\r
-            SequenceI sqs[] = new SequenceI[al.getHeight()];\r
-            for (int i = 0, j = al.getHeight(); i < j; i++)\r
-            {\r
-              sqs[i] = al.getSequenceAt(i);\r
-            }\r
-            if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable)\r
-                SequenceInfo, sqs))\r
-            {\r
-              throw (new Exception(\r
-                  "Couldn't recover sequence properties for alignment."));\r
-            }\r
-\r
-            noMsa = false;\r
-            FirstSeq = 0;\r
-          }\r
-          else\r
-          {\r
-            throw (new Exception(\r
-                "Unknown format "+format+" for file : \n" +\r
-                result.getAligfile()));\r
-          }\r
-        }\r
-        else\r
-        {\r
-          al = new Alignment(preds);\r
-          FirstSeq = prediction.getQuerySeqPosition();\r
-          if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(\r
-              al.getSequenceAt(FirstSeq), SequenceInfo))\r
-          {\r
-            throw (new Exception(\r
-                "Couldn't recover sequence properties for JNet Query sequence!"));\r
-          }\r
-        }\r
-\r
-        al.setDataset(null);\r
-\r
-        jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq,\r
-            noMsa);\r
-        return al; // , FirstSeq, noMsa};\r
-      }\r
-      public JPredJob(Hashtable SequenceInfo, SequenceI seq)\r
-      {\r
-        super();\r
-        String sq = AlignSeq.extractGaps(Comparison.GapChars, seq.getSequence());\r
-        if (sq.length() >= 20)\r
-        {\r
-          this.SequenceInfo = SequenceInfo;\r
-          sequence = new vamsas.objects.simple.Sequence();\r
-          sequence.setId(seq.getName());\r
-          sequence.setSeq(sq);\r
-        }\r
-      }\r
-\r
-      public JPredJob(Hashtable SequenceInfo, SequenceI[] msf)\r
-      {\r
-        this(SequenceInfo, msf[0]);\r
-        if (sequence != null)\r
-        {\r
-          if (msf.length > 1)\r
-          {\r
-            msa = new vamsas.objects.simple.Msfalignment();\r
-            jalview.io.PileUpfile pileup = new jalview.io.PileUpfile();\r
-            msa.setMsf(pileup.print(msf));\r
-          }\r
-        }\r
-      }\r
-    }\r
-    ext.vamsas.Jpred server;\r
-    String altitle = "";\r
-    JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server) {\r
-      this.altitle = altitle;\r
-      this.server = server;\r
-      this.wsInfo = wsinfo;\r
-    }\r
-\r
-//    String OutputHeader;\r
-//    vamsas.objects.simple.JpredResult result;\r
-\r
-    JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo,SequenceI seq)\r
-    {\r
-      this(wsinfo, altitle, server);\r
-      JPredJob job = new JPredJob(SequenceInfo, seq);\r
-      if (job.hasValidInput())\r
-      {\r
-        OutputHeader = wsInfo.getProgressText();\r
-        jobs = new WSJob[]\r
-            {\r
-            job};\r
-        job.jobnum = 0;\r
-      }\r
-    }\r
-\r
-    JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo, SequenceI[] msf)\r
-    {\r
-      this(wsinfo, altitle, server);\r
-      JPredJob job = new JPredJob(SequenceInfo, msf);\r
-      if (job.hasValidInput())\r
-      {\r
-        jobs = new WSJob[]\r
-            {\r
-            job};\r
-        OutputHeader = wsInfo.getProgressText();\r
-        job.jobnum = 0;\r
-      }\r
-    }\r
-\r
-    /*\r
-        public void run()\r
-        {\r
-          StartJob();\r
-\r
-          while (!jobComplete && (allowedServerExceptions > 0))\r
-          {\r
-            try\r
-            {\r
-              if ( (result = server.getresult(jobId)) == null)\r
-              {\r
-                throw (new Exception(\r
-     "Timed out when communicating with server\nTry again later.\n"));\r
-              }\r
-              if (result.getState()==0)\r
-                jalview.bin.Cache.log.debug("Finished "+jobId);\r
-              if (result.isRunning())\r
-              {\r
-                wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);\r
-              }\r
-              if (result.isQueued())\r
-              {\r
-                wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);\r
-              }\r
-\r
-              wsInfo.setProgressText(OutputHeader + "\n" +\r
-                                     result.getStatus());\r
-\r
-              if (result.isFinished())\r
-              {\r
-\r
-                parseResult();\r
-                jobComplete = true;\r
-                jobsRunning--;\r
-              } else {\r
-                // catch exceptions\r
-                if (! (result.isJobFailed() || result.isServerError()))\r
-                {\r
-                  try\r
-                  {\r
-                    Thread.sleep(5000);\r
-                  }\r
-                  catch (InterruptedException ex1)\r
-                  {\r
-                  }\r
-\r
-                  //  System.out.println("I'm alive "+seqid+" "+jobid);\r
-                }\r
-                else\r
-                {\r
-                  wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
-                  jobsRunning--;\r
-                  jobComplete = true;\r
-                }\r
-              }\r
-            }\r
-            catch (Exception ex)\r
-            {\r
-              allowedServerExceptions--;\r
-\r
-              wsInfo.appendProgressText("\nJPredWS Server exception!\n" +\r
-                                        ex.getMessage());\r
-\r
-              try\r
-              {\r
-                if (allowedServerExceptions > 0)\r
-                {\r
-                  Thread.sleep(5000);\r
-                }\r
-              }\r
-              catch (InterruptedException ex1)\r
-              {\r
-              }\r
-            }\r
-            catch (OutOfMemoryError er)\r
-            {\r
-              jobComplete = true;\r
-              wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
-              JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
-     "Out of memory handling result!!"\r
-                                                    +\r
-     "\nSee help files for increasing Java Virtual Machine memory."\r
-                                                    , "Out of memory",\r
-     JOptionPane.WARNING_MESSAGE);\r
-              System.out.println("JPredClient: "+er);\r
-              System.gc();\r
-            }\r
-          }\r
-          if (result!=null)\r
-            if (! (result.isJobFailed() || result.isServerError()))\r
-            {\r
-              wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);\r
-            }\r
-            else\r
-            {\r
-              wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
-            }\r
-        }\r
-     */\r
-    void StartJob(WSJob j)\r
-    {\r
-      if (! (j instanceof JPredJob))\r
-      {\r
-        throw new Error("Implementation error - StartJob(JpredJob) called on " +\r
-                        j.getClass());\r
-      }\r
-      try\r
-      {\r
-        JPredJob job = (JPredJob) j;\r
-        if (job.msa != null)\r
-        {\r
-          job.jobId = server.predictOnMsa(job.msa);\r
-        }\r
-        else\r
-          if (job.sequence!=null)\r
-          {\r
-            job.jobId = server.predict(job.sequence);\r
-          }\r
-\r
-        if (job.jobId != null)\r
-        {\r
-          if (job.jobId.startsWith("Broken"))\r
-          {\r
-            job.result = (vamsas.objects.simple.Result)new JpredResult();\r
-            job.result.setInvalid(true);\r
-            job.result.setStatus("Submission " + job.jobId);\r
-          }\r
-          else\r
-          {\r
-            job.submitted = true;\r
-            job.subjobComplete = false;\r
-            Cache.log.info(WsURL + " Job Id '" + job.jobId + "'");\r
-          }\r
-        }\r
-        else\r
-        {\r
-          throw new Exception("Server timed out - try again later\n");\r
-        }\r
-      }\r
-      catch (Exception e)\r
-      {\r
-        if (e.getMessage().indexOf("Exception") > -1)\r
-        {\r
-          wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);\r
-          wsInfo.setProgressText(j.jobnum,\r
-                                 "Failed to submit the prediction. (Just close the window)\n"\r
-                                 +\r
-                                 "It is most likely that there is a problem with the server.\n");\r
-          System.err.println(\r
-              "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" +\r
-              e.getMessage() + "\n");\r
-\r
-          jalview.bin.Cache.log.warn("Server Exception", e);\r
-        }\r
-        else\r
-        {\r
-          wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);\r
-          // JBPNote - this could be a popup informing the user of the problem.\r
-          wsInfo.appendProgressText(j.jobnum,\r
-                                    "Failed to submit the prediction:\n"\r
-                                    + e.getMessage() +\r
-                                    wsInfo.getProgressText());\r
-\r
-          jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e);\r
-\r
-        }\r
-        j.allowedServerExceptions = -1;\r
-        j.subjobComplete = true;\r
-      }\r
-    }\r
-\r
-    /*  private void addFloatAnnotations(Alignment al, int[] gapmap,\r
-                                       Vector values, String Symname,\r
-                                       String Visname, float min,\r
-                                       float max, int winLength)\r
-      {\r
-        Annotation[] annotations = new Annotation[al.getWidth()];\r
-\r
-        for (int j = 0; j < values.size(); j++)\r
-        {\r
-          float value = Float.parseFloat(values.get(j).toString());\r
-          annotations[gapmap[j]] = new Annotation("", value + "", ' ',\r
-                                                  value);\r
-        }\r
-\r
-        al.addAnnotation(new AlignmentAnnotation(Symname, Visname,\r
-     annotations, min, max, winLength));\r
-      }*/\r
-\r
-    void parseResult()\r
-    {\r
-      int results = 0; // number of result sets received\r
-      JobStateSummary finalState = new JobStateSummary();\r
-      try\r
-      {\r
-        for (int j = 0; j < jobs.length; j++)\r
-        {\r
-          finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);\r
-          if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())\r
-          {\r
-            results++;\r
-          }\r
-        }\r
-      }\r
-      catch (Exception ex)\r
-      {\r
-\r
-        Cache.log.error("Unexpected exception when processing results for " +\r
-                        altitle, ex);\r
-        wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);\r
-      }\r
-      if (results > 0)\r
-      {\r
-        wsInfo.showResultsNewFrame\r
-            .addActionListener(new java.awt.event.ActionListener()\r
-        {\r
-          public void actionPerformed(\r
-              java.awt.event.ActionEvent evt)\r
-          {\r
-            displayResults(true);\r
-          }\r
-        });\r
-        wsInfo.mergeResults\r
-            .addActionListener(new java.awt.event.ActionListener()\r
-        {\r
-          public void actionPerformed(\r
-              java.awt.event.ActionEvent evt)\r
-          {\r
-            displayResults(false);\r
-          }\r
-        });\r
-        wsInfo.setResultsReady();\r
-      }\r
-      else\r
-      {\r
-        wsInfo.setFinishedNoResults();\r
-      }\r
-    }\r
-\r
-    void displayResults(boolean newWindow)\r
-    {\r
-      if (jobs != null)\r
-      {\r
-        Alignment res = null;\r
-        for (int jn = 0; jn < jobs.length; jn++)\r
-        {\r
-          Alignment jobres = null;\r
-          JPredJob j = (JPredJob) jobs[jn];\r
-\r
-          if (j.hasResults())\r
-          {\r
-            try\r
-            {\r
-              jalview.bin.Cache.log.debug("Parsing output of job " + jn);\r
-              jobres = j.getResultSet();\r
-              jalview.bin.Cache.log.debug("Finished parsing output.");\r
-              if (jobs.length==1)\r
-                res = jobres;\r
-              else {\r
-                  // do merge with other job results\r
-              }\r
-            }\r
-            catch (Exception e)\r
-            {\r
-              jalview.bin.Cache.log.error(\r
-                  "JNet Client: JPred Annotation Parse Error",\r
-                  e);\r
-              wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);\r
-              wsInfo.appendProgressText(j.jobnum,\r
-                                        OutputHeader + "\n" +\r
-                                        j.result.getStatus() +\r
-                                        "\nInvalid JNet job result data!\n" +\r
-                                        e.getMessage());\r
-              j.result.setBroken(true);\r
-            }\r
-          }\r
-        }\r
-\r
-        if (res != null)\r
-        {\r
-          if (newWindow)\r
-          {\r
-            AlignFrame af = new AlignFrame(res);\r
-            Desktop.addInternalFrame(af, altitle,\r
-                                     AlignFrame.NEW_WINDOW_WIDTH,\r
-                                     AlignFrame.NEW_WINDOW_HEIGHT);\r
-          }\r
-          else\r
-          {\r
-            Cache.log.info("Append results onto existing alignment.");\r
-          }\r
-        }\r
-      }\r
-    }\r
-    void pollJob(WSJob job)\r
-        throws Exception\r
-    {\r
-      job.result = server.getresult(job.jobId);\r
-    }\r
-    public boolean isCancellable()\r
-    {\r
-      return false;\r
-    }\r
-\r
-    public void cancelJob()\r
-    {\r
-      throw new Error("Implementation error!");\r
-    }\r
-\r
-    public boolean canMergeResults()\r
-    {\r
-      return false;\r
-    }\r
-\r
-  }\r
-}\r
-\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2005 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.ws;
+
+import java.util.*;
+
+import javax.swing.*;
+
+import ext.vamsas.*;
+import jalview.analysis.*;
+import jalview.bin.*;
+import jalview.datamodel.*;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentView;
+import jalview.gui.*;
+import jalview.io.*;
+import jalview.util.*;
+import jalview.ws.WSThread.*;
+import vamsas.objects.simple.*;
+
+public class JPredClient
+    extends WSClient
+{
+    /**
+     * crate a new GUI JPred Job
+     * @param sh ServiceHandle
+     * @param title String
+     * @param msa boolean - true - submit alignment as a sequence profile
+     * @param alview AlignmentView
+     */
+    public JPredClient(ext.vamsas.ServiceHandle sh, String title, boolean msa, AlignmentView alview, AlignFrame parentFrame) {
+    super();
+    wsInfo=setWebService(sh);
+    startJPredClient(title, msa, alview, parentFrame);
+
+  }
+  /**
+   * startJPredClient
+   * TODO: refine submission to cope with local prediction of visible regions or multiple single sequence jobs
+   * TODO: sequence representative support - could submit alignment of representatives as msa.
+   * TODO:  msa hidden region prediction - submit each chunk for prediction. concatenate results of each.
+   * TODO:  single seq prediction - submit each contig of each sequence for prediction (but must cope with flanking regions and short seqs)
+   * @param title String
+   * @param msa boolean
+   * @param alview AlignmentView
+   */
+  private void startJPredClient(String title, boolean msa,
+                                jalview.datamodel.AlignmentView alview, AlignFrame parentFrame)
+  {
+    AlignmentView input = alview;
+    if (wsInfo == null)
+    {
+      wsInfo = setWebService();
+    }
+    Jpred server = locateWebService();
+    if (server == null)
+    {
+      Cache.log.warn("Couldn't find a Jpred webservice to invoke!");
+      return;
+    }
+
+    SeqCigar[] msf = input.getSequences();
+    SequenceI seq = msf[0].getSeq('-');
+    if (msa && msf.length > 1)
+    {
+
+      String altitle = "JNet prediction on " + seq.getName() +
+          " using alignment from " + title;
+
+      wsInfo.setProgressText("Job details for MSA based prediction (" +
+                             title + ") on sequence :\n>" + seq.getName() +
+                             "\n" +
+                             AlignSeq.extractGaps("-. ", seq.getSequence()) +
+                             "\n");
+      SequenceI aln[] = new SequenceI[msf.length];
+      for (int i = 0, j = msf.length; i < j; i++)
+      {
+        aln[i] = msf[i].getSeq('-');
+      }
+
+      Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true);
+
+      JPredThread jthread = new JPredThread(wsInfo, altitle, server,
+                                            SequenceInfo, aln, alview, parentFrame);
+      wsInfo.setthisService(jthread);
+      jthread.start();
+    }
+    else
+    {
+      if (!msa && msf.length>1)
+        throw new Error("Implementation Error! Multiple single sequence prediction jobs are not yet supported.");
+      wsInfo.setProgressText("Job details for prediction on sequence :\n>" +
+                             seq.getName() + "\n" +
+                             AlignSeq.extractGaps("-. ", seq.getSequence()) +
+                             "\n");
+      String altitle = "JNet prediction for sequence " + seq.getName() +
+          " from " +
+          title;
+
+      Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash(
+          seq);
+
+      JPredThread jthread = new JPredThread(wsInfo, altitle, server,
+                                            SequenceInfo, seq, alview, parentFrame);
+      wsInfo.setthisService(jthread);
+      jthread.start();
+    }
+  }
+  public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI seq, AlignFrame parentFrame)
+  {
+    super();
+    wsInfo = setWebService(sh);
+    startJPredClient(title, seq, parentFrame);
+  }
+
+  public JPredClient(ext.vamsas.ServiceHandle sh, String title, SequenceI[] msa, AlignFrame parentFrame)
+  {
+    wsInfo = setWebService(sh);
+    startJPredClient(title, msa, parentFrame);
+  }
+
+  public JPredClient(String title, SequenceI[] msf)
+  {
+    startJPredClient(title, msf, null);
+  }
+
+  public JPredClient(String title, SequenceI seq)
+  {
+    startJPredClient(title, seq, null);
+  }
+
+  private void startJPredClient(String title, SequenceI[] msf, AlignFrame parentFrame)
+  {
+    if (wsInfo == null)
+    {
+      wsInfo = setWebService();
+    }
+
+    SequenceI seq = msf[0];
+
+    String altitle = "JNet prediction on " + seq.getName() +
+        " using alignment from " + title;
+
+    wsInfo.setProgressText("Job details for MSA based prediction (" +
+                           title + ") on sequence :\n>" + seq.getName() + "\n" +
+                           AlignSeq.extractGaps("-. ", seq.getSequence()) +
+                           "\n");
+    SequenceI aln[] = new SequenceI[msf.length];
+    for (int i = 0, j = msf.length; i < j; i++)
+    {
+      aln[i] = new jalview.datamodel.Sequence(msf[i]);
+    }
+
+    Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.uniquify(aln, true);
+
+    Jpred server = locateWebService();
+    if (server==null)
+    {
+      return;
+    }
+
+    JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, aln,null, parentFrame);
+    wsInfo.setthisService(jthread);
+    jthread.start();
+  }
+
+  public void startJPredClient(String title, SequenceI seq, AlignFrame parentFrame)
+  {
+    if (wsInfo == null)
+    {
+      wsInfo = setWebService();
+    }
+    wsInfo.setProgressText("Job details for prediction on sequence :\n>" +
+                           seq.getName() + "\n" +
+                           AlignSeq.extractGaps("-. ", seq.getSequence()) +
+                           "\n");
+    String altitle = "JNet prediction for sequence " + seq.getName() + " from " +
+        title;
+
+    Hashtable SequenceInfo = jalview.analysis.SeqsetUtils.SeqCharacterHash(seq);
+
+    Jpred server = locateWebService();
+    if (server==null)
+    {
+      return;
+    }
+
+    JPredThread jthread = new JPredThread(wsInfo, altitle, server, SequenceInfo, seq,null, parentFrame);
+    wsInfo.setthisService(jthread);
+    jthread.start();
+  }
+
+  private WebserviceInfo setWebService()
+  {
+    WebServiceName = "JNetWS";
+    WebServiceJobTitle = "JNet secondary structure prediction";
+    WebServiceReference =
+        "\"Cuff J. A and Barton G.J (2000) Application of " +
+        "multiple sequence alignment profiles to improve protein secondary structure prediction, " +
+        "Proteins 40:502-511\".";
+    WsURL = "http://www.compbio.dundee.ac.uk/JalviewWS/services/jpred";
+
+    WebserviceInfo wsInfo = new WebserviceInfo(WebServiceJobTitle,
+                                               WebServiceReference);
+
+    return wsInfo;
+  }
+
+  private ext.vamsas.Jpred locateWebService()
+  {
+    ext.vamsas.JpredServiceLocator loc = new JpredServiceLocator(); // Default
+    ext.vamsas.Jpred server=null;
+    try
+    {
+      server = loc.getjpred(new java.net.URL(WsURL)); // JBPNote will be set from properties
+      ( (JpredSoapBindingStub)server).setTimeout(60000); // one minute stub
+      //((JpredSoapBindingStub)this.server)._setProperty(org.apache.axis.encoding.C, Boolean.TRUE);
+
+    }
+    catch (Exception ex)
+    {
+      JOptionPane.showMessageDialog(Desktop.desktop,
+                                    "The Secondary Structure Prediction Service named " +
+                                    WebServiceName + " at " + WsURL +
+                                    " couldn't be located.",
+                                    "Internal Jalview Error",
+                                    JOptionPane.WARNING_MESSAGE);
+      wsInfo.setProgressText("Serious! " + WebServiceName +
+                             " Service location failed\nfor URL :" + WsURL +
+                             "\n" +
+                             ex.getMessage());
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
+
+    }
+
+    return server;
+  }
+
+  class JPredThread
+      extends WSThread
+      implements WSClientI
+  {
+    class JPredJob
+        extends WSThread.WSJob
+    {
+
+      vamsas.objects.simple.Sequence sequence;
+      vamsas.objects.simple.Msfalignment msa;
+      java.util.Hashtable SequenceInfo = null;
+      /**
+       *
+       * @return true if getResultSet will return a valid alignment and prediction result.
+       */
+      public boolean hasResults()
+      {
+        if (subjobComplete && result != null && result.isFinished()
+            && ( (JpredResult) result).getPredfile() != null &&
+            ( (JpredResult) result).getAligfile() != null)
+        {
+          return true;
+        }
+        return false;
+      }
+
+      boolean hasValidInput()
+      {
+        if (sequence != null)
+        {
+          return true;
+        }
+        return false;
+      }
+
+      public Alignment getResultSet()
+          throws Exception
+      {
+        if (result == null || !result.isFinished())
+        {
+          return null;
+        }
+        Alignment al = null;
+        int FirstSeq = -1; // the position of the query sequence in Alignment al
+
+        JpredResult result = (JpredResult)this.result;
+
+        jalview.bin.Cache.log.debug("Parsing output from JNet job.");
+        // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt", "File");
+        jalview.io.JPredFile prediction = new jalview.io.JPredFile(result.
+            getPredfile(),
+            "Paste");
+        SequenceI[] preds = prediction.getSeqsAsArray();
+        jalview.bin.Cache.log.debug("Got prediction profile.");
+
+        if ( (this.msa != null) && (result.getAligfile() != null))
+        {
+          jalview.bin.Cache.log.debug("Getting associated alignment.");
+          // we ignore the returned alignment if we only predicted on a single sequence
+          String format = new jalview.io.IdentifyFile().Identify(result.
+              getAligfile(),
+              "Paste");
+
+          if (jalview.io.FormatAdapter.isValidFormat(format))
+          {
+            al = new Alignment(new FormatAdapter().readFile(result.getAligfile(),
+                "Paste", format));
+            SequenceI sqs[] = new SequenceI[al.getHeight()];
+            for (int i = 0, j = al.getHeight(); i < j; i++)
+            {
+              sqs[i] = al.getSequenceAt(i);
+            }
+            if (!jalview.analysis.SeqsetUtils.deuniquify( (Hashtable)
+                SequenceInfo, sqs))
+            {
+              throw (new Exception(
+                  "Couldn't recover sequence properties for alignment."));
+            }
+
+            FirstSeq = 0;
+            al.setDataset(null);
+
+            jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq,
+                                                          false);
+
+          }
+          else
+          {
+            throw (new Exception(
+                "Unknown format "+format+" for file : \n" +
+                result.getAligfile()));
+          }
+        }
+        else
+        {
+          al = new Alignment(preds);
+          FirstSeq = prediction.getQuerySeqPosition();
+          if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(
+              al.getSequenceAt(FirstSeq), SequenceInfo))
+          {
+            throw (new Exception(
+                "Couldn't recover sequence properties for JNet Query sequence!"));
+          } else {
+            al.setDataset(null);
+            jalview.io.JnetAnnotationMaker.add_annotation(prediction, al, FirstSeq,
+                true);
+          }
+        }
+
+        return al; // , FirstSeq, noMsa};
+      }
+      public JPredJob(Hashtable SequenceInfo, SequenceI seq)
+      {
+        super();
+        String sq = AlignSeq.extractGaps(Comparison.GapChars, seq.getSequence());
+        if (sq.length() >= 20)
+        {
+          this.SequenceInfo = SequenceInfo;
+          sequence = new vamsas.objects.simple.Sequence();
+          sequence.setId(seq.getName());
+          sequence.setSeq(sq);
+        }
+      }
+
+      public JPredJob(Hashtable SequenceInfo, SequenceI[] msf)
+      {
+        this(SequenceInfo, msf[0]);
+        if (sequence != null)
+        {
+          if (msf.length > 1)
+          {
+            msa = new vamsas.objects.simple.Msfalignment();
+            jalview.io.PileUpfile pileup = new jalview.io.PileUpfile();
+            msa.setMsf(pileup.print(msf));
+          }
+        }
+      }
+    }
+    ext.vamsas.Jpred server;
+    String altitle = "";
+    JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, AlignmentView alview, AlignFrame alframe) {
+      this.altitle = altitle;
+      this.server = server;
+      this.wsInfo = wsinfo;
+      this.input = alview;
+      this.alignFrame = alframe;
+    }
+
+//    String OutputHeader;
+//    vamsas.objects.simple.JpredResult result;
+
+    JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo,SequenceI seq, AlignmentView alview, AlignFrame alframe)
+    {
+      this(wsinfo, altitle, server,alview, alframe);
+      JPredJob job = new JPredJob(SequenceInfo, seq);
+      if (job.hasValidInput())
+      {
+        OutputHeader = wsInfo.getProgressText();
+        jobs = new WSJob[]
+            {
+            job};
+        job.jobnum = 0;
+      }
+    }
+
+    JPredThread(WebserviceInfo wsinfo, String altitle, ext.vamsas.Jpred server, Hashtable SequenceInfo, SequenceI[] msf, AlignmentView alview, AlignFrame alframe)
+    {
+      this(wsinfo, altitle, server,alview, alframe);
+      JPredJob job = new JPredJob(SequenceInfo, msf);
+      if (job.hasValidInput())
+      {
+        jobs = new WSJob[]
+            {
+            job};
+        OutputHeader = wsInfo.getProgressText();
+        job.jobnum = 0;
+      }
+    }
+
+    /*
+        public void run()
+        {
+          StartJob();
+
+          while (!jobComplete && (allowedServerExceptions > 0))
+          {
+            try
+            {
+              if ( (result = server.getresult(jobId)) == null)
+              {
+                throw (new Exception(
+     "Timed out when communicating with server\nTry again later.\n"));
+              }
+              if (result.getState()==0)
+                jalview.bin.Cache.log.debug("Finished "+jobId);
+              if (result.isRunning())
+              {
+                wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);
+              }
+              if (result.isQueued())
+              {
+                wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);
+              }
+
+              wsInfo.setProgressText(OutputHeader + "\n" +
+                                     result.getStatus());
+
+              if (result.isFinished())
+              {
+
+                parseResult();
+                jobComplete = true;
+                jobsRunning--;
+              } else {
+                // catch exceptions
+                if (! (result.isJobFailed() || result.isServerError()))
+                {
+                  try
+                  {
+                    Thread.sleep(5000);
+                  }
+                  catch (InterruptedException ex1)
+                  {
+                  }
+
+                  //  System.out.println("I'm alive "+seqid+" "+jobid);
+                }
+                else
+                {
+                  wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+                  jobsRunning--;
+                  jobComplete = true;
+                }
+              }
+            }
+            catch (Exception ex)
+            {
+              allowedServerExceptions--;
+
+              wsInfo.appendProgressText("\nJPredWS Server exception!\n" +
+                                        ex.getMessage());
+
+              try
+              {
+                if (allowedServerExceptions > 0)
+                {
+                  Thread.sleep(5000);
+                }
+              }
+              catch (InterruptedException ex1)
+              {
+              }
+            }
+            catch (OutOfMemoryError er)
+            {
+              jobComplete = true;
+              wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+              JOptionPane.showInternalMessageDialog(Desktop.desktop,
+     "Out of memory handling result!!"
+                                                    +
+     "\nSee help files for increasing Java Virtual Machine memory."
+                                                    , "Out of memory",
+     JOptionPane.WARNING_MESSAGE);
+              System.out.println("JPredClient: "+er);
+              System.gc();
+            }
+          }
+          if (result!=null)
+            if (! (result.isJobFailed() || result.isServerError()))
+            {
+              wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);
+            }
+            else
+            {
+              wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+            }
+        }
+     */
+    void StartJob(WSJob j)
+    {
+      if (! (j instanceof JPredJob))
+      {
+        throw new Error("Implementation error - StartJob(JpredJob) called on " +
+                        j.getClass());
+      }
+      try
+      {
+        JPredJob job = (JPredJob) j;
+        if (job.msa != null)
+        {
+          job.jobId = server.predictOnMsa(job.msa);
+        }
+        else
+          if (job.sequence!=null)
+          {
+            job.jobId = server.predict(job.sequence);
+          }
+
+        if (job.jobId != null)
+        {
+          if (job.jobId.startsWith("Broken"))
+          {
+            job.result = (vamsas.objects.simple.Result)new JpredResult();
+            job.result.setInvalid(true);
+            job.result.setStatus("Submission " + job.jobId);
+          }
+          else
+          {
+            job.submitted = true;
+            job.subjobComplete = false;
+            Cache.log.info(WsURL + " Job Id '" + job.jobId + "'");
+          }
+        }
+        else
+        {
+          throw new Exception("Server timed out - try again later\n");
+        }
+      }
+      catch (Exception e)
+      {
+        if (e.getMessage().indexOf("Exception") > -1)
+        {
+          wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
+          wsInfo.setProgressText(j.jobnum,
+                                 "Failed to submit the prediction. (Just close the window)\n"
+                                 +
+                                 "It is most likely that there is a problem with the server.\n");
+          System.err.println(
+              "JPredWS Client: Failed to submit the prediction. Quite possibly because of a server error - see below)\n" +
+              e.getMessage() + "\n");
+
+          jalview.bin.Cache.log.warn("Server Exception", e);
+        }
+        else
+        {
+          wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
+          // JBPNote - this could be a popup informing the user of the problem.
+          wsInfo.appendProgressText(j.jobnum,
+                                    "Failed to submit the prediction:\n"
+                                    + e.getMessage() +
+                                    wsInfo.getProgressText());
+
+          jalview.bin.Cache.log.debug("Failed Submission of job " + j.jobnum, e);
+
+        }
+        j.allowedServerExceptions = -1;
+        j.subjobComplete = true;
+      }
+    }
+
+    /*  private void addFloatAnnotations(Alignment al, int[] gapmap,
+                                       Vector values, String Symname,
+                                       String Visname, float min,
+                                       float max, int winLength)
+      {
+        Annotation[] annotations = new Annotation[al.getWidth()];
+
+        for (int j = 0; j < values.size(); j++)
+        {
+          float value = Float.parseFloat(values.get(j).toString());
+          annotations[gapmap[j]] = new Annotation("", value + "", ' ',
+                                                  value);
+        }
+
+        al.addAnnotation(new AlignmentAnnotation(Symname, Visname,
+     annotations, min, max, winLength));
+      }*/
+
+    void parseResult()
+    {
+      int results = 0; // number of result sets received
+      JobStateSummary finalState = new JobStateSummary();
+      try
+      {
+        for (int j = 0; j < jobs.length; j++)
+        {
+          finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
+          if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
+          {
+            results++;
+          }
+        }
+      }
+      catch (Exception ex)
+      {
+
+        Cache.log.error("Unexpected exception when processing results for " +
+                        altitle, ex);
+        wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+      }
+      if (results > 0)
+      {
+        wsInfo.showResultsNewFrame
+            .addActionListener(new java.awt.event.ActionListener()
+        {
+          public void actionPerformed(
+              java.awt.event.ActionEvent evt)
+          {
+            displayResults(true);
+          }
+        });
+        wsInfo.mergeResults
+            .addActionListener(new java.awt.event.ActionListener()
+        {
+          public void actionPerformed(
+              java.awt.event.ActionEvent evt)
+          {
+            displayResults(false);
+          }
+        });
+        wsInfo.setResultsReady();
+      }
+      else
+      {
+        wsInfo.setFinishedNoResults();
+      }
+    }
+
+    void displayResults(boolean newWindow)
+    {
+      // TODO: cope with multiple subjobs.
+      if (jobs != null)
+      {
+        Alignment res = null;
+        boolean msa=false;
+        for (int jn = 0; jn < jobs.length; jn++)
+        {
+          Alignment jobres = null;
+          JPredJob j = (JPredJob) jobs[jn];
+
+          if (j.hasResults())
+          {
+            // hack - we only deal with all single seuqence predictions or all profile predictions
+            msa = (j.msa!=null) ? true : msa;
+            try
+            {
+              jalview.bin.Cache.log.debug("Parsing output of job " + jn);
+              jobres = j.getResultSet();
+              jalview.bin.Cache.log.debug("Finished parsing output.");
+              if (jobs.length==1)
+                res = jobres;
+              else {
+                  // do merge with other job results
+                  throw new Error("Multiple JNet subjob merging not yet implemented.");
+              }
+            }
+            catch (Exception e)
+            {
+              jalview.bin.Cache.log.error(
+                  "JNet Client: JPred Annotation Parse Error",
+                  e);
+              wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_ERROR);
+              wsInfo.appendProgressText(j.jobnum,
+                                        OutputHeader + "\n" +
+                                        j.result.getStatus() +
+                                        "\nInvalid JNet job result data!\n" +
+                                        e.getMessage());
+              j.result.setBroken(true);
+            }
+          }
+        }
+
+        if (res != null)
+        {
+          if (newWindow)
+          {
+            AlignFrame af;
+           if (input==null) {
+             af = new AlignFrame(res);
+           } else {
+             java.lang.Object[] alandcolsel = input.getAlignmentAndColumnSelection(alignFrame.getViewport().getGapCharacter());
+             
+             if (((SequenceI[])alandcolsel[0])[0].getLength()!=res.getWidth()) {
+               if (msa) {
+                 throw new Error("Implementation Error! ColumnSelection from input alignment will not map to result alignment!");
+               } else {
+                 // test this.
+                 ((ColumnSelection) alandcolsel[1]).compensateForEdits(ShiftList.parseMap(((SequenceI[]) alandcolsel[0])[0].gapMap()));
+               }
+             }
+             af = new AlignFrame(res, (ColumnSelection) alandcolsel[1]);
+           }
+            Desktop.addInternalFrame(af, altitle,
+                                     AlignFrame.NEW_WINDOW_WIDTH,
+                                     AlignFrame.NEW_WINDOW_HEIGHT);
+          }
+          else
+          {
+            Cache.log.info("Append results onto existing alignment.");
+          }
+        }
+      }
+    }
+    void pollJob(WSJob job)
+        throws Exception
+    {
+      job.result = server.getresult(job.jobId);
+    }
+    public boolean isCancellable()
+    {
+      return false;
+    }
+
+    public void cancelJob()
+    {
+      throw new Error("Implementation error!");
+    }
+
+    public boolean canMergeResults()
+    {
+      return false;
+    }
+
+  }
+}
+