pickmanager on sequence and alignment position, vamsas pick broadcast and refactor...
authorjprocter <Jim Procter>
Fri, 13 Jul 2007 15:09:14 +0000 (15:09 +0000)
committerjprocter <Jim Procter>
Fri, 13 Jul 2007 15:09:14 +0000 (15:09 +0000)
12 files changed:
src/jalview/appletgui/SeqPanel.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AppJmol.java
src/jalview/gui/DasSourceBrowser.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/SeqPanel.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/TreeCanvas.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/structure/SequenceListener.java
src/jalview/structure/StructureSelectionManager.java

index 24a934c..a010364 100755 (executable)
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2007 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
-\r
-package jalview.appletgui;\r
-\r
-import java.util.*;\r
-\r
-import java.awt.*;\r
-import java.awt.event.*;\r
-\r
-import jalview.commands.*;\r
-import jalview.datamodel.*;\r
-import jalview.schemes.*;\r
-import jalview.structure.SequenceListener;\r
-import jalview.structure.StructureSelectionManager;\r
-\r
-public class SeqPanel\r
-    extends Panel implements MouseMotionListener, MouseListener, SequenceListener\r
-{\r
-\r
-  public SeqCanvas seqCanvas;\r
-  public AlignmentPanel ap;\r
-\r
-  protected int lastres;\r
-  protected int startseq;\r
-\r
-  protected AlignViewport av;\r
-\r
-  // if character is inserted or deleted, we will need to recalculate the conservation\r
-  boolean seqEditOccurred = false;\r
-\r
-  ScrollThread scrollThread = null;\r
-  boolean mouseDragging = false;\r
-  boolean editingSeqs = false;\r
-  boolean groupEditing = false;\r
-\r
-  int oldSeq = -1;\r
-  boolean changeEndSeq = false;\r
-  boolean changeStartSeq = false;\r
-  boolean changeEndRes = false;\r
-  boolean changeStartRes = false;\r
-  SequenceGroup stretchGroup = null;\r
-\r
-  StringBuffer keyboardNo1;\r
-  StringBuffer keyboardNo2;\r
-\r
-  boolean mouseWheelPressed = false;\r
-  Point lastMousePress;\r
-\r
-  EditCommand editCommand;\r
-\r
-  StructureSelectionManager ssm;\r
-\r
-\r
-  public SeqPanel(AlignViewport avp, AlignmentPanel p)\r
-  {\r
-    this.av = avp;\r
-\r
-    seqCanvas = new SeqCanvas(avp);\r
-    setLayout(new BorderLayout());\r
-    add(seqCanvas);\r
-\r
-    ap = p;\r
-\r
-    seqCanvas.addMouseMotionListener(this);\r
-    seqCanvas.addMouseListener(this);\r
-    ssm = StructureSelectionManager.getStructureSelectionManager();\r
-    ssm.addStructureViewerListener(this);\r
-\r
-    seqCanvas.repaint();\r
-  }\r
-\r
-  void endEditing()\r
-  {\r
-    if (editCommand != null && editCommand.getSize() > 0)\r
-    {\r
-      ap.alignFrame.addHistoryItem(editCommand);\r
-      av.firePropertyChange("alignment", null,\r
-                            av.getAlignment().getSequences());\r
-    }\r
-\r
-    startseq = -1;\r
-    lastres = -1;\r
-    editingSeqs = false;\r
-    groupEditing = false;\r
-    keyboardNo1 = null;\r
-    keyboardNo2 = null;\r
-    editCommand = null;\r
-  }\r
-\r
-  void setCursorRow()\r
-  {\r
-    seqCanvas.cursorY = getKeyboardNo1() - 1;\r
-    scrollToVisible();\r
-  }\r
-\r
-  void setCursorColumn()\r
-  {\r
-    seqCanvas.cursorX = getKeyboardNo1() - 1;\r
-    scrollToVisible();\r
-  }\r
-\r
-  void setCursorRowAndColumn()\r
-  {\r
-    if (keyboardNo2 == null)\r
-    {\r
-      keyboardNo2 = new StringBuffer();\r
-    }\r
-    else\r
-    {\r
-      seqCanvas.cursorX = getKeyboardNo1() - 1;\r
-      seqCanvas.cursorY = getKeyboardNo2() - 1;\r
-      scrollToVisible();\r
-    }\r
-  }\r
-\r
-  void setCursorPosition()\r
-  {\r
-    SequenceI sequence =\r
-        (Sequence) av.getAlignment().getSequenceAt(seqCanvas.cursorY);\r
-\r
-    seqCanvas.cursorX = sequence.findIndex(\r
-        getKeyboardNo1() - 1\r
-        );\r
-    scrollToVisible();\r
-  }\r
-\r
-  void moveCursor(int dx, int dy)\r
-  {\r
-    seqCanvas.cursorX += dx;\r
-    seqCanvas.cursorY += dy;\r
-    if (av.hasHiddenColumns && !av.colSel.isVisible(seqCanvas.cursorX))\r
-    {\r
-      int original = seqCanvas.cursorX - dx;\r
-      int maxWidth = av.alignment.getWidth();\r
-\r
-      while (!av.colSel.isVisible(seqCanvas.cursorX)\r
-             && seqCanvas.cursorX < maxWidth\r
-             && seqCanvas.cursorX > 0)\r
-      {\r
-        seqCanvas.cursorX += dx;\r
-      }\r
-\r
-      if (seqCanvas.cursorX >= maxWidth\r
-          || !av.colSel.isVisible(seqCanvas.cursorX))\r
-      {\r
-        seqCanvas.cursorX = original;\r
-      }\r
-    }\r
-    scrollToVisible();\r
-  }\r
-\r
-  void scrollToVisible()\r
-  {\r
-    if (seqCanvas.cursorX < 0)\r
-    {\r
-      seqCanvas.cursorX = 0;\r
-    }\r
-    else if (seqCanvas.cursorX > av.alignment.getWidth() - 1)\r
-    {\r
-      seqCanvas.cursorX = av.alignment.getWidth() - 1;\r
-    }\r
-\r
-    if (seqCanvas.cursorY < 0)\r
-    {\r
-      seqCanvas.cursorY = 0;\r
-    }\r
-    else if (seqCanvas.cursorY > av.alignment.getHeight() - 1)\r
-    {\r
-      seqCanvas.cursorY = av.alignment.getHeight() - 1;\r
-    }\r
-\r
-    endEditing();\r
-    if (av.wrapAlignment)\r
-    {\r
-      ap.scrollToWrappedVisible(seqCanvas.cursorX);\r
-    }\r
-    else\r
-    {\r
-      while (seqCanvas.cursorY < av.startSeq)\r
-      {\r
-        ap.scrollUp(true);\r
-      }\r
-      while (seqCanvas.cursorY + 1 > av.endSeq)\r
-      {\r
-        ap.scrollUp(false);\r
-      }\r
-      while (seqCanvas.cursorX < av.colSel.adjustForHiddenColumns(av.startRes))\r
-      {\r
-\r
-        if (!ap.scrollRight(false))\r
-        {\r
-          break;\r
-        }\r
-      }\r
-      while (seqCanvas.cursorX > av.colSel.adjustForHiddenColumns(av.endRes))\r
-      {\r
-        if (!ap.scrollRight(true))\r
-        {\r
-          break;\r
-        }\r
-      }\r
-    }\r
-    setStatusMessage(av.alignment.getSequenceAt(seqCanvas.cursorY),\r
-                     seqCanvas.cursorX, seqCanvas.cursorY);\r
-\r
-    seqCanvas.repaint();\r
-  }\r
-\r
-  void setSelectionAreaAtCursor(boolean topLeft)\r
-  {\r
-    SequenceI sequence =\r
-        (Sequence) av.getAlignment().getSequenceAt(seqCanvas.cursorY);\r
-\r
-    if (av.getSelectionGroup() != null)\r
-    {\r
-      SequenceGroup sg = av.selectionGroup;\r
-      //Find the top and bottom of this group\r
-      int min = av.alignment.getHeight(), max = 0;\r
-      for (int i = 0; i < sg.getSize(); i++)\r
-      {\r
-        int index = av.alignment.findIndex(sg.getSequenceAt(i));\r
-        if (index > max)\r
-        {\r
-          max = index;\r
-        }\r
-        if (index < min)\r
-        {\r
-          min = index;\r
-        }\r
-      }\r
-\r
-      max++;\r
-\r
-      if (topLeft)\r
-      {\r
-        sg.setStartRes(seqCanvas.cursorX);\r
-        if (sg.getEndRes() < seqCanvas.cursorX)\r
-        {\r
-          sg.setEndRes(seqCanvas.cursorX);\r
-        }\r
-\r
-        min = seqCanvas.cursorY;\r
-      }\r
-      else\r
-      {\r
-        sg.setEndRes(seqCanvas.cursorX);\r
-        if (sg.getStartRes() > seqCanvas.cursorX)\r
-        {\r
-          sg.setStartRes(seqCanvas.cursorX);\r
-        }\r
-\r
-        max = seqCanvas.cursorY + 1;\r
-      }\r
-\r
-      if (min > max)\r
-      {\r
-        // Only the user can do this\r
-        av.setSelectionGroup(null);\r
-      }\r
-      else\r
-      {\r
-        // Now add any sequences between min and max\r
-        sg.getSequences(null).removeAllElements();\r
-        for (int i = min; i < max; i++)\r
-        {\r
-          sg.addSequence(av.alignment.getSequenceAt(i), false);\r
-        }\r
-      }\r
-    }\r
-\r
-    if (av.getSelectionGroup() == null)\r
-    {\r
-      SequenceGroup sg = new SequenceGroup();\r
-      sg.setStartRes(seqCanvas.cursorX);\r
-      sg.setEndRes(seqCanvas.cursorX);\r
-      sg.addSequence(sequence, false);\r
-      av.setSelectionGroup(sg);\r
-    }\r
-\r
-    ap.paintAlignment(false);\r
-  }\r
-\r
-  void insertGapAtCursor(boolean group)\r
-  {\r
-    groupEditing = group;\r
-    startseq = seqCanvas.cursorY;\r
-    lastres = seqCanvas.cursorX;\r
-    editSequence(true, seqCanvas.cursorX + getKeyboardNo1());\r
-    endEditing();\r
-  }\r
-\r
-  void deleteGapAtCursor(boolean group)\r
-  {\r
-    groupEditing = group;\r
-    startseq = seqCanvas.cursorY;\r
-    lastres = seqCanvas.cursorX + getKeyboardNo1();\r
-    editSequence(false, seqCanvas.cursorX);\r
-    endEditing();\r
-  }\r
-\r
-  void numberPressed(char value)\r
-  {\r
-    if (keyboardNo1 == null)\r
-    {\r
-      keyboardNo1 = new StringBuffer();\r
-    }\r
-\r
-    if (keyboardNo2 != null)\r
-    {\r
-      keyboardNo2.append(value);\r
-    }\r
-    else\r
-    {\r
-      keyboardNo1.append(value);\r
-    }\r
-  }\r
-\r
-  int getKeyboardNo1()\r
-  {\r
-    if (keyboardNo1 == null)\r
-      return 1;\r
-    else\r
-    {\r
-      int value = Integer.parseInt(keyboardNo1.toString());\r
-      keyboardNo1 = null;\r
-      return value;\r
-    }\r
-  }\r
-\r
-  int getKeyboardNo2()\r
-  {\r
-    if (keyboardNo2 == null)\r
-      return 1;\r
-    else\r
-    {\r
-      int value = Integer.parseInt(keyboardNo2.toString());\r
-      keyboardNo2 = null;\r
-      return value;\r
-    }\r
-  }\r
-\r
-\r
-  void setStatusMessage(SequenceI sequence, int res, int seq)\r
-  {\r
-    StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +\r
-                                         sequence.getName());\r
-\r
-    Object obj = null;\r
-    if (av.alignment.isNucleotide())\r
-    {\r
-      obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +\r
-                                                 "");\r
-      if (obj != null)\r
-      {\r
-        text.append(" Nucleotide: ");\r
-      }\r
-    }\r
-    else\r
-    {\r
-      obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");\r
-      if (obj != null)\r
-      {\r
-        text.append("  Residue: ");\r
-      }\r
-    }\r
-\r
-    if (obj != null)\r
-    {\r
-\r
-      if (obj != "")\r
-      {\r
-        text.append(obj + " (" + sequence.findPosition(res) +\r
-                    ")");\r
-      }\r
-    }\r
-\r
-    ap.alignFrame.statusBar.setText(text.toString());\r
-\r
-  }\r
-\r
-  public void mousePressed(MouseEvent evt)\r
-  {\r
-    lastMousePress = evt.getPoint();\r
-\r
-    //For now, ignore the mouseWheel font resizing on Macs\r
-    //As the Button2_mask always seems to be true\r
-    if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) ==\r
-        InputEvent.BUTTON2_MASK && !av.MAC)\r
-    {\r
-      mouseWheelPressed = true;\r
-      return;\r
-    }\r
-\r
-    if (evt.isShiftDown()\r
-        || evt.isControlDown()\r
-        || evt.isAltDown())\r
-    {\r
-      if (evt.isControlDown() || evt.isAltDown())\r
-      {\r
-        groupEditing = true;\r
-      }\r
-      editingSeqs = true;\r
-    }\r
-    else\r
-    {\r
-      doMousePressedDefineMode(evt);\r
-      return;\r
-    }\r
-\r
-    int seq = findSeq(evt);\r
-    int res = findRes(evt);\r
-\r
-    if (seq < 0 || res < 0)\r
-    {\r
-      return;\r
-    }\r
-\r
-    if ( (seq < av.getAlignment().getHeight()) &&\r
-        (res < av.getAlignment().getSequenceAt(seq).getLength()))\r
-    {\r
-      startseq = seq;\r
-      lastres = res;\r
-    }\r
-    else\r
-    {\r
-      startseq = -1;\r
-      lastres = -1;\r
-    }\r
-\r
-    return;\r
-  }\r
-\r
-  public void mouseClicked(MouseEvent evt)\r
-  {\r
-    SequenceI sequence = av.alignment.getSequenceAt(findSeq(evt));\r
-    if (evt.getClickCount() > 1)\r
-    {\r
-      if (av.getSelectionGroup().getSize() == 1\r
-          && av.getSelectionGroup().getEndRes()\r
-          - av.getSelectionGroup().getStartRes() < 2)\r
-      {\r
-        av.setSelectionGroup(null);\r
-      }\r
-\r
-      SequenceFeature[] features = findFeaturesAtRes(\r
-          sequence,\r
-          sequence.findPosition(findRes(evt))\r
-          );\r
-\r
-      if (features != null && features.length > 0)\r
-      {\r
-        SearchResults highlight = new SearchResults();\r
-        highlight.addResult(sequence,\r
-                            features[0].getBegin(),\r
-                            features[0].getEnd());\r
-        seqCanvas.highlightSearchResults(highlight);\r
-      }\r
-      if (features != null && features.length > 0)\r
-      {\r
-        seqCanvas.getFeatureRenderer().amendFeatures(\r
-            new SequenceI[]\r
-            {sequence}, features, false, ap);\r
-\r
-        seqCanvas.highlightSearchResults(null);\r
-      }\r
-    }\r
-  }\r
-\r
-  public void mouseReleased(MouseEvent evt)\r
-  {\r
-    mouseDragging = false;\r
-    mouseWheelPressed = false;\r
-    ap.paintAlignment(true);\r
-\r
-    if (!editingSeqs)\r
-    {\r
-      doMouseReleasedDefineMode(evt);\r
-      return;\r
-    }\r
-\r
-    endEditing();\r
-\r
-  }\r
-\r
-  int startWrapBlock = -1;\r
-  int wrappedBlock = -1;\r
-  int findRes(MouseEvent evt)\r
-  {\r
-    int res = 0;\r
-    int x = evt.getX();\r
-\r
-    if (av.wrapAlignment)\r
-    {\r
-\r
-      int hgap = av.charHeight;\r
-      if (av.scaleAboveWrapped)\r
-      {\r
-        hgap += av.charHeight;\r
-      }\r
-\r
-      int cHeight = av.getAlignment().getHeight() * av.charHeight\r
-          + hgap + seqCanvas.getAnnotationHeight();\r
-\r
-      int y = evt.getY();\r
-      y -= hgap;\r
-      x -= seqCanvas.LABEL_WEST;\r
-\r
-      int cwidth = seqCanvas.getWrappedCanvasWidth(getSize().width);\r
-      if (cwidth < 1)\r
-      {\r
-        return 0;\r
-      }\r
-\r
-      wrappedBlock = y / cHeight;\r
-      wrappedBlock += av.getStartRes() / cwidth;\r
-\r
-      res = wrappedBlock * cwidth + x / av.getCharWidth();\r
-\r
-    }\r
-    else\r
-    {\r
-      res = (x / av.getCharWidth()) + av.getStartRes();\r
-    }\r
-\r
-    if (av.hasHiddenColumns)\r
-    {\r
-      res = av.getColumnSelection().adjustForHiddenColumns(res);\r
-    }\r
-\r
-    return res;\r
-\r
-  }\r
-\r
-  int findSeq(MouseEvent evt)\r
-  {\r
-\r
-    int seq = 0;\r
-    int y = evt.getY();\r
-\r
-    if (av.wrapAlignment)\r
-    {\r
-      int hgap = av.charHeight;\r
-      if (av.scaleAboveWrapped)\r
-      {\r
-        hgap += av.charHeight;\r
-      }\r
-\r
-      int cHeight = av.getAlignment().getHeight() * av.charHeight\r
-          + hgap + seqCanvas.getAnnotationHeight();\r
-\r
-      y -= hgap;\r
-\r
-      seq = Math.min( (y % cHeight) / av.getCharHeight(),\r
-                     av.alignment.getHeight() - 1);\r
-      if (seq < 0)\r
-      {\r
-        seq = 0;\r
-      }\r
-    }\r
-    else\r
-    {\r
-      seq = Math.min( (y / av.getCharHeight()) + av.getStartSeq(),\r
-                     av.alignment.getHeight() - 1);\r
-      if (seq < 0)\r
-      {\r
-        seq = 0;\r
-      }\r
-    }\r
-\r
-    return seq;\r
-  }\r
-\r
-\r
-\r
-  public void doMousePressed(MouseEvent evt)\r
-  {\r
-\r
-    int seq = findSeq(evt);\r
-    int res = findRes(evt);\r
-\r
-    if (seq < av.getAlignment().getHeight() &&\r
-        res < av.getAlignment().getSequenceAt(seq).getLength())\r
-    {\r
-      //char resstr = align.getSequenceAt(seq).getSequence().charAt(res);\r
-      // Find the residue's position in the sequence (res is the position\r
-      // in the alignment\r
-\r
-      startseq = seq;\r
-      lastres = res;\r
-    }\r
-    else\r
-    {\r
-      startseq = -1;\r
-      lastres = -1;\r
-    }\r
-\r
-    return;\r
-  }\r
-\r
-\r
-  String lastMessage;\r
-  public void mouseOverSequence(SequenceI sequence, int index)\r
-  {\r
-    String tmp = sequence.hashCode()+index+"";\r
-    if (lastMessage == null || !lastMessage.equals(tmp))\r
-      ssm.mouseOverSequence(sequence, index);\r
-\r
-    lastMessage = tmp;\r
-  }\r
-\r
-\r
-  public void highlightSequence(SearchResults results)\r
-  {\r
-    seqCanvas.highlightSearchResults(results);\r
-  }\r
-\r
-  public void updateColours(SequenceI seq, int index)\r
-  {\r
-    System.out.println("update the seqPanel colours");\r
-    //repaint();\r
-  }\r
-\r
-  public void mouseMoved(MouseEvent evt)\r
-  {\r
-    int res = findRes(evt);\r
-    int seq = findSeq(evt);\r
-\r
-    if (seq >= av.getAlignment().getHeight() || seq < 0 || res < 0)\r
-    {\r
-      if (tooltip != null)\r
-      {\r
-        tooltip.setTip("");\r
-      }\r
-      return;\r
-    }\r
-\r
-    SequenceI sequence = av.getAlignment().getSequenceAt(seq);\r
-    if (res > sequence.getLength())\r
-    {\r
-      if (tooltip != null)\r
-      {\r
-        tooltip.setTip("");\r
-      }\r
-      return;\r
-    }\r
-\r
-\r
-    if (ssm != null)\r
-      mouseOverSequence(sequence, sequence.findPosition(res));\r
-\r
-\r
-    StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +\r
-                                         sequence.getName());\r
-\r
-    Object obj = null;\r
-    if (av.alignment.isNucleotide())\r
-    {\r
-      obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +\r
-                                                 "");\r
-      if (obj != null)\r
-      {\r
-        text.append(" Nucleotide: ");\r
-      }\r
-    }\r
-    else\r
-    {\r
-      obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");\r
-      if (obj != null)\r
-      {\r
-        text.append("  Residue: ");\r
-      }\r
-    }\r
-\r
-    if (obj != null)\r
-    {\r
-      if (obj != "")\r
-      {\r
-        text.append(obj + " (" + sequence.findPosition(res) + ")");\r
-      }\r
-    }\r
-\r
-    ap.alignFrame.statusBar.setText(text.toString());\r
-\r
-    StringBuffer tooltipText = new StringBuffer();\r
-    SequenceGroup[] groups = av.alignment.findAllGroups(sequence);\r
-    if (groups != null)\r
-    {\r
-      for (int g = 0; g < groups.length; g++)\r
-      {\r
-        if (groups[g].getStartRes() <= res && groups[g].getEndRes() >= res)\r
-        {\r
-          if (!groups[g].getName().startsWith("JTreeGroup") &&\r
-              !groups[g].getName().startsWith("JGroup"))\r
-          {\r
-            tooltipText.append(groups[g].getName() + " ");\r
-          }\r
-          if (groups[g].getDescription() != null)\r
-          {\r
-            tooltipText.append(groups[g].getDescription());\r
-          }\r
-          tooltipText.append("\n");\r
-        }\r
-      }\r
-    }\r
-\r
-    // use aa to see if the mouse pointer is on a\r
-    SequenceFeature [] allFeatures = findFeaturesAtRes(sequence,\r
-                                               sequence.findPosition(res));\r
-\r
-      int index = 0;\r
-      while (index < allFeatures.length)\r
-      {\r
-        SequenceFeature sf = allFeatures[index];\r
-\r
-        tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);\r
-\r
-        if (sf.getDescription() != null)\r
-        {\r
-          tooltipText.append(" " + sf.getDescription());\r
-        }\r
-\r
-        if (sf.getValue("status") != null)\r
-        {\r
-          String status = sf.getValue("status").toString();\r
-          if (status.length() > 0)\r
-          {\r
-            tooltipText.append(" (" + sf.getValue("status") + ")");\r
-          }\r
-        }\r
-        tooltipText.append("\n");\r
-\r
-        index++;\r
-      }\r
-\r
-    if (tooltip == null)\r
-    {\r
-      tooltip = new Tooltip(tooltipText.toString(), seqCanvas);\r
-    }\r
-    else\r
-    {\r
-      tooltip.setTip(tooltipText.toString());\r
-    }\r
-  }\r
-\r
-  SequenceFeature[] findFeaturesAtRes(SequenceI sequence, int res)\r
-  {\r
-    Vector tmp = new Vector();\r
-    SequenceFeature[] features = sequence.getSequenceFeatures();\r
-    if (features != null)\r
-    {\r
-      for (int i = 0; i < features.length; i++)\r
-      {\r
-        if (av.featuresDisplayed == null\r
-            || !av.featuresDisplayed.containsKey(features[i].getType()))\r
-        {\r
-          continue;\r
-        }\r
-\r
-\r
-\r
-        if (features[i].featureGroup != null\r
-           && seqCanvas.fr.featureGroups!=null\r
-            && seqCanvas.fr.featureGroups.containsKey(features[i].featureGroup)\r
-            && !((Boolean)seqCanvas.fr.featureGroups.get(features[i].featureGroup)).booleanValue())\r
-          continue;\r
-\r
-\r
-        if ( (features[i].getBegin() <= res) &&\r
-            (features[i].getEnd() >= res))\r
-        {\r
-          tmp.addElement(features[i]);\r
-        }\r
-      }\r
-    }\r
-\r
-    features = new SequenceFeature[tmp.size()];\r
-    tmp.copyInto(features);\r
-\r
-    return features;\r
-  }\r
-\r
-\r
-  Tooltip tooltip;\r
-\r
-  public void mouseDragged(MouseEvent evt)\r
-  {\r
-    if (mouseWheelPressed)\r
-    {\r
-      int oldWidth = av.charWidth;\r
-\r
-      //Which is bigger, left-right or up-down?\r
-      if (Math.abs(evt.getY() - lastMousePress.y)\r
-          > Math.abs(evt.getX() - lastMousePress.x))\r
-      {\r
-        int fontSize = av.font.getSize();\r
-\r
-        if (evt.getY() < lastMousePress.y && av.charHeight > 1)\r
-        {\r
-          fontSize--;\r
-        }\r
-        else if (evt.getY() > lastMousePress.y)\r
-        {\r
-          fontSize++;\r
-        }\r
-\r
-        if (fontSize < 1)\r
-        {\r
-          fontSize = 1;\r
-        }\r
-\r
-        av.setFont(new Font(av.font.getName(), av.font.getStyle(), fontSize));\r
-        av.charWidth = oldWidth;\r
-      }\r
-      else\r
-      {\r
-        if (evt.getX() < lastMousePress.x && av.charWidth > 1)\r
-        {\r
-          av.charWidth--;\r
-        }\r
-        else if (evt.getX() > lastMousePress.x)\r
-        {\r
-          av.charWidth++;\r
-        }\r
-\r
-        if (av.charWidth < 1)\r
-        {\r
-          av.charWidth = 1;\r
-        }\r
-      }\r
-\r
-      ap.fontChanged();\r
-\r
-      FontMetrics fm = getFontMetrics(av.getFont());\r
-      av.validCharWidth = fm.charWidth('M') <= av.charWidth;\r
-\r
-      lastMousePress = evt.getPoint();\r
-\r
-      ap.paintAlignment(false);\r
-      ap.annotationPanel.image = null;\r
-      return;\r
-    }\r
-\r
-    if (!editingSeqs)\r
-    {\r
-      doMouseDraggedDefineMode(evt);\r
-      return;\r
-    }\r
-\r
-    int res = findRes(evt);\r
-\r
-    if (res < 0)\r
-    {\r
-      res = 0;\r
-    }\r
-\r
-    if ( (lastres == -1) || (lastres == res))\r
-    {\r
-      return;\r
-    }\r
-\r
-    if ( (res < av.getAlignment().getWidth()) && (res < lastres))\r
-    {\r
-      // dragLeft, delete gap\r
-      editSequence(false, res);\r
-    }\r
-    else\r
-    {\r
-      editSequence(true, res);\r
-    }\r
-\r
-    mouseDragging = true;\r
-    if (scrollThread != null)\r
-    {\r
-      scrollThread.setEvent(evt);\r
-    }\r
-\r
-  }\r
-\r
-  synchronized void editSequence(boolean insertGap, int startres)\r
-  {\r
-    int fixedLeft = -1;\r
-    int fixedRight = -1;\r
-    boolean fixedColumns = false;\r
-    SequenceGroup sg = av.getSelectionGroup();\r
-\r
-    SequenceI seq = av.alignment.getSequenceAt(startseq);\r
-\r
-    if (!groupEditing && av.hasHiddenRows)\r
-    {\r
-      if (av.hiddenRepSequences != null\r
-          && av.hiddenRepSequences.containsKey(seq))\r
-      {\r
-        sg = (SequenceGroup) av.hiddenRepSequences.get(seq);\r
-        groupEditing = true;\r
-      }\r
-    }\r
-\r
-    StringBuffer message = new StringBuffer();\r
-    if (groupEditing)\r
-    {\r
-      message.append("Edit group:");\r
-      if (editCommand == null)\r
-      {\r
-        editCommand = new EditCommand("Edit Group");\r
-      }\r
-    }\r
-    else\r
-    {\r
-      message.append("Edit sequence: " + seq.getName());\r
-      String label = seq.getName();\r
-      if (label.length() > 10)\r
-      {\r
-        label = label.substring(0, 10);\r
-      }\r
-      if (editCommand == null)\r
-      {\r
-        editCommand = new EditCommand("Edit " + label);\r
-      }\r
-    }\r
-\r
-    if (insertGap)\r
-    {\r
-      message.append(" insert ");\r
-    }\r
-    else\r
-    {\r
-      message.append(" delete ");\r
-    }\r
-\r
-    message.append(Math.abs(startres - lastres) + " gaps.");\r
-    ap.alignFrame.statusBar.setText(message.toString());\r
-\r
-    //Are we editing within a selection group?\r
-    if (groupEditing\r
-        || (sg != null && sg.getSequences(av.hiddenRepSequences).contains(seq)))\r
-    {\r
-      fixedColumns = true;\r
-\r
-      //sg might be null as the user may only see 1 sequence,\r
-      //but the sequence represents a group\r
-      if (sg == null)\r
-      {\r
-        if (av.hiddenRepSequences == null\r
-            || !av.hiddenRepSequences.containsKey(seq))\r
-        {\r
-          endEditing();\r
-          return;\r
-        }\r
-\r
-        sg = (SequenceGroup) av.hiddenRepSequences.get(seq);\r
-      }\r
-\r
-      fixedLeft = sg.getStartRes();\r
-      fixedRight = sg.getEndRes();\r
-\r
-      if ( (startres < fixedLeft && lastres >= fixedLeft)\r
-          || (startres >= fixedLeft && lastres < fixedLeft)\r
-          || (startres > fixedRight && lastres <= fixedRight)\r
-          || (startres <= fixedRight && lastres > fixedRight))\r
-      {\r
-        endEditing();\r
-        return;\r
-      }\r
-\r
-      if (fixedLeft > startres)\r
-      {\r
-        fixedRight = fixedLeft - 1;\r
-        fixedLeft = 0;\r
-      }\r
-      else if (fixedRight < startres)\r
-      {\r
-        fixedLeft = fixedRight;\r
-        fixedRight = -1;\r
-      }\r
-    }\r
-\r
-    if (av.hasHiddenColumns)\r
-    {\r
-      fixedColumns = true;\r
-      int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);\r
-      int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);\r
-\r
-      if ( (insertGap && startres > y1 && lastres < y1)\r
-          || (!insertGap && startres < y2 && lastres > y2))\r
-      {\r
-        endEditing();\r
-        return;\r
-      }\r
-\r
-      //System.out.print(y1+" "+y2+" "+fixedLeft+" "+fixedRight+"~~");\r
-      //Selection spans a hidden region\r
-      if (fixedLeft < y1 && (fixedRight > y2 || fixedRight == -1))\r
-      {\r
-        if (startres >= y2)\r
-        {\r
-          fixedLeft = y2;\r
-        }\r
-        else\r
-        {\r
-          fixedRight = y2 - 1;\r
-        }\r
-      }\r
-    }\r
-\r
-    if (groupEditing)\r
-    {\r
-      Vector vseqs = sg.getSequences(av.hiddenRepSequences);\r
-      int g, groupSize = vseqs.size();\r
-      SequenceI[] groupSeqs = new SequenceI[groupSize];\r
-      for (g = 0; g < groupSeqs.length; g++)\r
-      {\r
-        groupSeqs[g] = (SequenceI) vseqs.elementAt(g);\r
-      }\r
-\r
-      // drag to right\r
-      if (insertGap)\r
-      {\r
-        //If the user has selected the whole sequence, and is dragging to\r
-        // the right, we can still extend the alignment and selectionGroup\r
-        if (sg.getStartRes() == 0\r
-            && sg.getEndRes() == fixedRight\r
-            && sg.getEndRes() == av.alignment.getWidth() - 1\r
-            )\r
-        {\r
-          sg.setEndRes(av.alignment.getWidth() + startres - lastres);\r
-          fixedRight = sg.getEndRes();\r
-        }\r
-\r
-        // Is it valid with fixed columns??\r
-        // Find the next gap before the end\r
-        // of the visible region boundary\r
-        boolean blank = false;\r
-        for (fixedRight = fixedRight;\r
-             fixedRight > lastres;\r
-             fixedRight--)\r
-        {\r
-          blank = true;\r
-\r
-          for (g = 0; g < groupSize; g++)\r
-          {\r
-            for (int j = 0; j < startres - lastres; j++)\r
-            {\r
-              if (!jalview.util.Comparison.isGap(\r
-                  groupSeqs[g].getCharAt(fixedRight - j)))\r
-              {\r
-                blank = false;\r
-                break;\r
-              }\r
-            }\r
-          }\r
-          if (blank)\r
-          {\r
-            break;\r
-          }\r
-        }\r
-\r
-        if (!blank)\r
-        {\r
-          if (sg.getSize() == av.alignment.getHeight())\r
-          {\r
-            if ( (av.hasHiddenColumns\r
-                  &&\r
-                  startres < av.getColumnSelection().getHiddenBoundaryRight(startres)))\r
-            {\r
-              endEditing();\r
-              return;\r
-            }\r
-\r
-            int alWidth = av.alignment.getWidth();\r
-            if (av.hasHiddenRows)\r
-            {\r
-              int hwidth = av.alignment.getHiddenSequences().getWidth();\r
-              if (hwidth > alWidth)\r
-              {\r
-                alWidth = hwidth;\r
-              }\r
-            }\r
-            //We can still insert gaps if the selectionGroup\r
-            //contains all the sequences\r
-            sg.setEndRes(sg.getEndRes() + startres - lastres);\r
-            fixedRight = alWidth + startres - lastres;\r
-          }\r
-          else\r
-          {\r
-            endEditing();\r
-            return;\r
-          }\r
-        }\r
-      }\r
-\r
-      // drag to left\r
-      else if (!insertGap)\r
-      {\r
-        /// Are we able to delete?\r
-        // ie are all columns blank?\r
-\r
-        for (g = 0; g < groupSize; g++)\r
-        {\r
-          for (int j = startres; j < lastres; j++)\r
-          {\r
-            if (groupSeqs[g].getLength() <= j)\r
-            {\r
-              continue;\r
-            }\r
-\r
-            if (!jalview.util.Comparison.isGap(\r
-                groupSeqs[g].getCharAt(j)))\r
-            {\r
-              // Not a gap, block edit not valid\r
-              endEditing();\r
-              return;\r
-            }\r
-          }\r
-        }\r
-      }\r
-\r
-      if (insertGap)\r
-      {\r
-        // dragging to the right\r
-        if (fixedColumns && fixedRight != -1)\r
-        {\r
-          for (int j = lastres; j < startres; j++)\r
-          {\r
-            insertChar(j, groupSeqs, fixedRight);\r
-          }\r
-        }\r
-        else\r
-        {\r
-          editCommand.appendEdit(EditCommand.INSERT_GAP,\r
-                                 groupSeqs,\r
-                                 startres, startres - lastres,\r
-                                 av.alignment,\r
-                                 true);\r
-        }\r
-      }\r
-      else\r
-      {\r
-        // dragging to the left\r
-        if (fixedColumns && fixedRight != -1)\r
-        {\r
-          for (int j = lastres; j > startres; j--)\r
-          {\r
-            deleteChar(startres, groupSeqs, fixedRight);\r
-          }\r
-        }\r
-        else\r
-        {\r
-          editCommand.appendEdit(EditCommand.DELETE_GAP,\r
-                                 groupSeqs,\r
-                                 startres, lastres - startres,\r
-                                 av.alignment,\r
-                                 true);\r
-        }\r
-\r
-      }\r
-    }\r
-    else /////Editing a single sequence///////////\r
-    {\r
-      if (insertGap)\r
-      {\r
-        // dragging to the right\r
-        if (fixedColumns && fixedRight != -1)\r
-        {\r
-          for (int j = lastres; j < startres; j++)\r
-          {\r
-            insertChar(j, new SequenceI[]\r
-                       {seq}, fixedRight);\r
-          }\r
-        }\r
-        else\r
-        {\r
-          editCommand.appendEdit(EditCommand.INSERT_GAP,\r
-                                 new SequenceI[]\r
-                                 {seq},\r
-                                 lastres, startres - lastres,\r
-                                 av.alignment,\r
-                                 true);\r
-        }\r
-      }\r
-      else\r
-      {\r
-        // dragging to the left\r
-        if (fixedColumns && fixedRight != -1)\r
-        {\r
-          for (int j = lastres; j > startres; j--)\r
-          {\r
-            if (!jalview.util.Comparison.isGap(seq.getCharAt(startres)))\r
-            {\r
-              endEditing();\r
-              break;\r
-            }\r
-            deleteChar(startres, new SequenceI[]\r
-                       {seq}, fixedRight);\r
-          }\r
-        }\r
-        else\r
-        {\r
-          //could be a keyboard edit trying to delete none gaps\r
-          int max = 0;\r
-          for (int m = startres; m < lastres; m++)\r
-          {\r
-            if (!jalview.util.Comparison.isGap(seq.getCharAt(m)))\r
-            {\r
-              break;\r
-            }\r
-            max++;\r
-          }\r
-\r
-          if (max > 0)\r
-          {\r
-            editCommand.appendEdit(EditCommand.DELETE_GAP,\r
-                                   new SequenceI[]\r
-                                   {seq},\r
-                                   startres, max,\r
-                                   av.alignment,\r
-                                   true);\r
-          }\r
-        }\r
-      }\r
-    }\r
-\r
-    lastres = startres;\r
-    seqCanvas.repaint();\r
-  }\r
-\r
-  void insertChar(int j, SequenceI[] seq, int fixedColumn)\r
-  {\r
-    int blankColumn = fixedColumn;\r
-    for (int s = 0; s < seq.length; s++)\r
-    {\r
-      //Find the next gap before the end of the visible region boundary\r
-      //If lastCol > j, theres a boundary after the gap insertion\r
-\r
-      for (blankColumn = fixedColumn; blankColumn > j; blankColumn--)\r
-      {\r
-        if (jalview.util.Comparison.isGap(seq[s].getCharAt(blankColumn)))\r
-        {\r
-          //Theres a space, so break and insert the gap\r
-          break;\r
-        }\r
-      }\r
-\r
-      if (blankColumn <= j)\r
-      {\r
-        blankColumn = fixedColumn;\r
-        endEditing();\r
-        return;\r
-      }\r
-    }\r
-\r
-    editCommand.appendEdit(EditCommand.DELETE_GAP,\r
-                           seq,\r
-                           blankColumn, 1, av.alignment, true);\r
-\r
-    editCommand.appendEdit(EditCommand.INSERT_GAP,\r
-                           seq,\r
-                           j, 1, av.alignment,\r
-                           true);\r
-\r
-  }\r
-\r
-  void deleteChar(int j, SequenceI[] seq, int fixedColumn)\r
-  {\r
-\r
-    editCommand.appendEdit(EditCommand.DELETE_GAP,\r
-                           seq,\r
-                           j, 1, av.alignment, true);\r
-\r
-    editCommand.appendEdit(EditCommand.INSERT_GAP,\r
-                           seq,\r
-                           fixedColumn, 1, av.alignment, true);\r
-  }\r
-\r
-//////////////////////////////////////////\r
-/////Everything below this is for defining the boundary of the rubberband\r
-//////////////////////////////////////////\r
-  public void doMousePressedDefineMode(MouseEvent evt)\r
-  {\r
-    if (scrollThread != null)\r
-    {\r
-      scrollThread.running = false;\r
-      scrollThread = null;\r
-    }\r
-\r
-    int res = findRes(evt);\r
-    int seq = findSeq(evt);\r
-    oldSeq = seq;\r
-    startWrapBlock = wrappedBlock;\r
-\r
-    if (seq == -1)\r
-    {\r
-      return;\r
-    }\r
-\r
-    SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);\r
-\r
-    if (sequence == null || res > sequence.getLength())\r
-    {\r
-      return;\r
-    }\r
-\r
-    stretchGroup = av.getSelectionGroup();\r
-\r
-    if (stretchGroup == null)\r
-    {\r
-      stretchGroup = av.alignment.findGroup(sequence);\r
-      if (stretchGroup != null && res > stretchGroup.getStartRes() &&\r
-          res < stretchGroup.getEndRes())\r
-      {\r
-        av.setSelectionGroup(stretchGroup);\r
-      }\r
-      else\r
-      {\r
-        stretchGroup = null;\r
-      }\r
-    }\r
-\r
-    else if (!stretchGroup.getSequences(null).contains(sequence)\r
-             || stretchGroup.getStartRes() > res\r
-             || stretchGroup.getEndRes() < res)\r
-    {\r
-      stretchGroup = null;\r
-\r
-      SequenceGroup[] allGroups = av.alignment.findAllGroups(sequence);\r
-\r
-      if (allGroups != null)\r
-      {\r
-        for (int i = 0; i < allGroups.length; i++)\r
-        {\r
-          if (allGroups[i].getStartRes() <= res &&\r
-              allGroups[i].getEndRes() >= res)\r
-          {\r
-            stretchGroup = allGroups[i];\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      av.setSelectionGroup(stretchGroup);\r
-    }\r
-\r
-    // DETECT RIGHT MOUSE BUTTON IN AWT\r
-    if ( (evt.getModifiers() & InputEvent.BUTTON3_MASK) ==\r
-        InputEvent.BUTTON3_MASK)\r
-    {\r
-      SequenceFeature [] allFeatures = findFeaturesAtRes(sequence,\r
-                                               sequence.findPosition(res));\r
-\r
-      Vector links = null;\r
-      if (allFeatures != null)\r
-      {\r
-        for (int i = 0; i < allFeatures.length; i++)\r
-        {\r
-          if (allFeatures[i].links != null)\r
-          {\r
-            links = new Vector();\r
-            for (int j = 0; j < allFeatures[i].links.size(); j++)\r
-            {\r
-              links.addElement(allFeatures[i].links.elementAt(j));\r
-            }\r
-          }\r
-        }\r
-      }\r
-      APopupMenu popup = new APopupMenu(ap, null, links);\r
-      this.add(popup);\r
-      popup.show(this, evt.getX(), evt.getY());\r
-      return;\r
-    }\r
-\r
-    if (av.cursorMode)\r
-    {\r
-      seqCanvas.cursorX = findRes(evt);\r
-      seqCanvas.cursorY = findSeq(evt);\r
-      seqCanvas.repaint();\r
-      return;\r
-    }\r
-\r
-    //Only if left mouse button do we want to change group sizes\r
-\r
-    if (stretchGroup == null)\r
-    {\r
-      // define a new group here\r
-      SequenceGroup sg = new SequenceGroup();\r
-      sg.setStartRes(res);\r
-      sg.setEndRes(res);\r
-      sg.addSequence(sequence, false);\r
-      av.setSelectionGroup(sg);\r
-      stretchGroup = sg;\r
-\r
-      if (av.getConservationSelected())\r
-      {\r
-        SliderPanel.setConservationSlider(ap, av.getGlobalColourScheme(),\r
-                                          "Background");\r
-      }\r
-      if (av.getAbovePIDThreshold())\r
-      {\r
-        SliderPanel.setPIDSliderSource(ap, av.getGlobalColourScheme(),\r
-                                       "Background");\r
-      }\r
-\r
-    }\r
-  }\r
-\r
-  public void doMouseReleasedDefineMode(MouseEvent evt)\r
-  {\r
-    if (stretchGroup == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    if (stretchGroup.cs != null)\r
-    {\r
-      if (stretchGroup.cs instanceof ClustalxColourScheme)\r
-      {\r
-        ( (ClustalxColourScheme) stretchGroup.cs).resetClustalX(\r
-            stretchGroup.getSequences(av.hiddenRepSequences),\r
-            stretchGroup.getWidth());\r
-      }\r
-\r
-      if (stretchGroup.cs instanceof Blosum62ColourScheme\r
-          || stretchGroup.cs instanceof PIDColourScheme\r
-          || stretchGroup.cs.conservationApplied()\r
-          || stretchGroup.cs.getThreshold() > 0)\r
-      {\r
-        stretchGroup.recalcConservation();\r
-      }\r
-\r
-      if (stretchGroup.cs.conservationApplied())\r
-      {\r
-        SliderPanel.setConservationSlider(ap, stretchGroup.cs,\r
-                                          stretchGroup.getName());\r
-        stretchGroup.recalcConservation();\r
-      }\r
-      else\r
-      {\r
-        SliderPanel.setPIDSliderSource(ap, stretchGroup.cs,\r
-                                       stretchGroup.getName());\r
-      }\r
-    }\r
-    changeEndRes = false;\r
-    changeStartRes = false;\r
-    stretchGroup = null;\r
-    PaintRefresher.Refresh(ap, av.getSequenceSetId());\r
-    ap.paintAlignment(true);\r
-  }\r
-\r
-  public void doMouseDraggedDefineMode(MouseEvent evt)\r
-  {\r
-    int res = findRes(evt);\r
-    int y = findSeq(evt);\r
-\r
-    if (wrappedBlock != startWrapBlock)\r
-    {\r
-      return;\r
-    }\r
-\r
-    if (stretchGroup == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    mouseDragging = true;\r
-\r
-    if (y > av.alignment.getHeight())\r
-    {\r
-      y = av.alignment.getHeight() - 1;\r
-    }\r
-\r
-    if (res >= av.alignment.getWidth())\r
-    {\r
-      res = av.alignment.getWidth() - 1;\r
-    }\r
-\r
-    if (stretchGroup.getEndRes() == res)\r
-    {\r
-      // Edit end res position of selected group\r
-      changeEndRes = true;\r
-    }\r
-    else if (stretchGroup.getStartRes() == res)\r
-    {\r
-      // Edit start res position of selected group\r
-      changeStartRes = true;\r
-    }\r
-\r
-    if (res < 0)\r
-    {\r
-      res = 0;\r
-    }\r
-\r
-    if (changeEndRes)\r
-    {\r
-      if (res > (stretchGroup.getStartRes() - 1))\r
-      {\r
-        stretchGroup.setEndRes(res);\r
-      }\r
-    }\r
-    else if (changeStartRes)\r
-    {\r
-      if (res < (stretchGroup.getEndRes() + 1))\r
-      {\r
-        stretchGroup.setStartRes(res);\r
-      }\r
-    }\r
-\r
-    int dragDirection = 0;\r
-\r
-    if (y > oldSeq)\r
-    {\r
-      dragDirection = 1;\r
-    }\r
-    else if (y < oldSeq)\r
-    {\r
-      dragDirection = -1;\r
-    }\r
-\r
-    while ( (y != oldSeq) && (oldSeq > -1) && (y < av.alignment.getHeight()))\r
-    {\r
-      // This routine ensures we don't skip any sequences, as the\r
-      // selection is quite slow.\r
-      Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
-\r
-      oldSeq += dragDirection;\r
-\r
-      if (oldSeq < 0)\r
-      {\r
-        break;\r
-      }\r
-\r
-      Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);\r
-\r
-      if (stretchGroup.getSequences(null).contains(nextSeq))\r
-      {\r
-        stretchGroup.deleteSequence(seq, false);\r
-      }\r
-      else\r
-      {\r
-        if (seq != null)\r
-        {\r
-          stretchGroup.addSequence(seq, false);\r
-        }\r
-\r
-        stretchGroup.addSequence(nextSeq, false);\r
-      }\r
-    }\r
-\r
-    if (oldSeq < 0)\r
-    {\r
-      oldSeq = -1;\r
-    }\r
-\r
-    if (res > av.endRes || res < av.startRes\r
-        || y < av.startSeq || y > av.endSeq)\r
-    {\r
-      mouseExited(evt);\r
-    }\r
-\r
-    if (scrollThread != null)\r
-    {\r
-      scrollThread.setEvent(evt);\r
-    }\r
-\r
-    seqCanvas.repaint();\r
-  }\r
-\r
-  public void mouseEntered(MouseEvent e)\r
-  {\r
-    if (oldSeq < 0)\r
-    {\r
-      oldSeq = 0;\r
-    }\r
-\r
-    if (scrollThread != null)\r
-    {\r
-      scrollThread.running = false;\r
-      scrollThread = null;\r
-    }\r
-  }\r
-\r
-  public void mouseExited(MouseEvent e)\r
-  {\r
-    if (av.getWrapAlignment())\r
-    {\r
-      return;\r
-    }\r
-\r
-    if (mouseDragging && scrollThread == null)\r
-    {\r
-      scrollThread = new ScrollThread();\r
-    }\r
-  }\r
-\r
-  void scrollCanvas(MouseEvent evt)\r
-  {\r
-    if (evt == null)\r
-    {\r
-      if (scrollThread != null)\r
-      {\r
-        scrollThread.running = false;\r
-        scrollThread = null;\r
-      }\r
-      mouseDragging = false;\r
-    }\r
-    else\r
-    {\r
-      if (scrollThread == null)\r
-      {\r
-        scrollThread = new ScrollThread();\r
-      }\r
-\r
-      mouseDragging = true;\r
-      scrollThread.setEvent(evt);\r
-    }\r
-\r
-  }\r
-\r
-  // this class allows scrolling off the bottom of the visible alignment\r
-  class ScrollThread\r
-      extends Thread\r
-  {\r
-    MouseEvent evt;\r
-    boolean running = false;\r
-    public ScrollThread()\r
-    {\r
-      start();\r
-    }\r
-\r
-    public void setEvent(MouseEvent e)\r
-    {\r
-      evt = e;\r
-    }\r
-\r
-    public void stopScrolling()\r
-    {\r
-      running = false;\r
-    }\r
-\r
-    public void run()\r
-    {\r
-      running = true;\r
-      while (running)\r
-      {\r
-\r
-        if (evt != null)\r
-        {\r
-\r
-          if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0)\r
-          {\r
-            running = ap.scrollUp(true);\r
-          }\r
-\r
-          if (mouseDragging && evt.getY() >= getSize().height &&\r
-              av.alignment.getHeight() > av.getEndSeq())\r
-          {\r
-            running = ap.scrollUp(false);\r
-          }\r
-\r
-          if (mouseDragging && evt.getX() < 0)\r
-          {\r
-            running = ap.scrollRight(false);\r
-          }\r
-\r
-          else if (mouseDragging && evt.getX() >= getSize().width)\r
-          {\r
-            running = ap.scrollRight(true);\r
-          }\r
-        }\r
-\r
-        try\r
-        {\r
-          Thread.sleep(75);\r
-        }\r
-        catch (Exception ex)\r
-        {}\r
-      }\r
-    }\r
-  }\r
-\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 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.appletgui;
+
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import jalview.commands.*;
+import jalview.datamodel.*;
+import jalview.schemes.*;
+import jalview.structure.SequenceListener;
+import jalview.structure.StructureSelectionManager;
+
+public class SeqPanel
+    extends Panel implements MouseMotionListener, MouseListener, SequenceListener
+{
+
+  public SeqCanvas seqCanvas;
+  public AlignmentPanel ap;
+
+  protected int lastres;
+  protected int startseq;
+
+  protected AlignViewport av;
+
+  // if character is inserted or deleted, we will need to recalculate the conservation
+  boolean seqEditOccurred = false;
+
+  ScrollThread scrollThread = null;
+  boolean mouseDragging = false;
+  boolean editingSeqs = false;
+  boolean groupEditing = false;
+
+  int oldSeq = -1;
+  boolean changeEndSeq = false;
+  boolean changeStartSeq = false;
+  boolean changeEndRes = false;
+  boolean changeStartRes = false;
+  SequenceGroup stretchGroup = null;
+
+  StringBuffer keyboardNo1;
+  StringBuffer keyboardNo2;
+
+  boolean mouseWheelPressed = false;
+  Point lastMousePress;
+
+  EditCommand editCommand;
+
+  StructureSelectionManager ssm;
+
+
+  public SeqPanel(AlignViewport avp, AlignmentPanel p)
+  {
+    this.av = avp;
+
+    seqCanvas = new SeqCanvas(avp);
+    setLayout(new BorderLayout());
+    add(seqCanvas);
+
+    ap = p;
+
+    seqCanvas.addMouseMotionListener(this);
+    seqCanvas.addMouseListener(this);
+    ssm = StructureSelectionManager.getStructureSelectionManager();
+    ssm.addStructureViewerListener(this);
+
+    seqCanvas.repaint();
+  }
+
+  void endEditing()
+  {
+    if (editCommand != null && editCommand.getSize() > 0)
+    {
+      ap.alignFrame.addHistoryItem(editCommand);
+      av.firePropertyChange("alignment", null,
+                            av.getAlignment().getSequences());
+    }
+
+    startseq = -1;
+    lastres = -1;
+    editingSeqs = false;
+    groupEditing = false;
+    keyboardNo1 = null;
+    keyboardNo2 = null;
+    editCommand = null;
+  }
+
+  void setCursorRow()
+  {
+    seqCanvas.cursorY = getKeyboardNo1() - 1;
+    scrollToVisible();
+  }
+
+  void setCursorColumn()
+  {
+    seqCanvas.cursorX = getKeyboardNo1() - 1;
+    scrollToVisible();
+  }
+
+  void setCursorRowAndColumn()
+  {
+    if (keyboardNo2 == null)
+    {
+      keyboardNo2 = new StringBuffer();
+    }
+    else
+    {
+      seqCanvas.cursorX = getKeyboardNo1() - 1;
+      seqCanvas.cursorY = getKeyboardNo2() - 1;
+      scrollToVisible();
+    }
+  }
+
+  void setCursorPosition()
+  {
+    SequenceI sequence =
+        (Sequence) av.getAlignment().getSequenceAt(seqCanvas.cursorY);
+
+    seqCanvas.cursorX = sequence.findIndex(
+        getKeyboardNo1() - 1
+        );
+    scrollToVisible();
+  }
+
+  void moveCursor(int dx, int dy)
+  {
+    seqCanvas.cursorX += dx;
+    seqCanvas.cursorY += dy;
+    if (av.hasHiddenColumns && !av.colSel.isVisible(seqCanvas.cursorX))
+    {
+      int original = seqCanvas.cursorX - dx;
+      int maxWidth = av.alignment.getWidth();
+
+      while (!av.colSel.isVisible(seqCanvas.cursorX)
+             && seqCanvas.cursorX < maxWidth
+             && seqCanvas.cursorX > 0)
+      {
+        seqCanvas.cursorX += dx;
+      }
+
+      if (seqCanvas.cursorX >= maxWidth
+          || !av.colSel.isVisible(seqCanvas.cursorX))
+      {
+        seqCanvas.cursorX = original;
+      }
+    }
+    scrollToVisible();
+  }
+
+  void scrollToVisible()
+  {
+    if (seqCanvas.cursorX < 0)
+    {
+      seqCanvas.cursorX = 0;
+    }
+    else if (seqCanvas.cursorX > av.alignment.getWidth() - 1)
+    {
+      seqCanvas.cursorX = av.alignment.getWidth() - 1;
+    }
+
+    if (seqCanvas.cursorY < 0)
+    {
+      seqCanvas.cursorY = 0;
+    }
+    else if (seqCanvas.cursorY > av.alignment.getHeight() - 1)
+    {
+      seqCanvas.cursorY = av.alignment.getHeight() - 1;
+    }
+
+    endEditing();
+    if (av.wrapAlignment)
+    {
+      ap.scrollToWrappedVisible(seqCanvas.cursorX);
+    }
+    else
+    {
+      while (seqCanvas.cursorY < av.startSeq)
+      {
+        ap.scrollUp(true);
+      }
+      while (seqCanvas.cursorY + 1 > av.endSeq)
+      {
+        ap.scrollUp(false);
+      }
+      while (seqCanvas.cursorX < av.colSel.adjustForHiddenColumns(av.startRes))
+      {
+
+        if (!ap.scrollRight(false))
+        {
+          break;
+        }
+      }
+      while (seqCanvas.cursorX > av.colSel.adjustForHiddenColumns(av.endRes))
+      {
+        if (!ap.scrollRight(true))
+        {
+          break;
+        }
+      }
+    }
+    setStatusMessage(av.alignment.getSequenceAt(seqCanvas.cursorY),
+                     seqCanvas.cursorX, seqCanvas.cursorY);
+
+    seqCanvas.repaint();
+  }
+
+  void setSelectionAreaAtCursor(boolean topLeft)
+  {
+    SequenceI sequence =
+        (Sequence) av.getAlignment().getSequenceAt(seqCanvas.cursorY);
+
+    if (av.getSelectionGroup() != null)
+    {
+      SequenceGroup sg = av.selectionGroup;
+      //Find the top and bottom of this group
+      int min = av.alignment.getHeight(), max = 0;
+      for (int i = 0; i < sg.getSize(); i++)
+      {
+        int index = av.alignment.findIndex(sg.getSequenceAt(i));
+        if (index > max)
+        {
+          max = index;
+        }
+        if (index < min)
+        {
+          min = index;
+        }
+      }
+
+      max++;
+
+      if (topLeft)
+      {
+        sg.setStartRes(seqCanvas.cursorX);
+        if (sg.getEndRes() < seqCanvas.cursorX)
+        {
+          sg.setEndRes(seqCanvas.cursorX);
+        }
+
+        min = seqCanvas.cursorY;
+      }
+      else
+      {
+        sg.setEndRes(seqCanvas.cursorX);
+        if (sg.getStartRes() > seqCanvas.cursorX)
+        {
+          sg.setStartRes(seqCanvas.cursorX);
+        }
+
+        max = seqCanvas.cursorY + 1;
+      }
+
+      if (min > max)
+      {
+        // Only the user can do this
+        av.setSelectionGroup(null);
+      }
+      else
+      {
+        // Now add any sequences between min and max
+        sg.getSequences(null).removeAllElements();
+        for (int i = min; i < max; i++)
+        {
+          sg.addSequence(av.alignment.getSequenceAt(i), false);
+        }
+      }
+    }
+
+    if (av.getSelectionGroup() == null)
+    {
+      SequenceGroup sg = new SequenceGroup();
+      sg.setStartRes(seqCanvas.cursorX);
+      sg.setEndRes(seqCanvas.cursorX);
+      sg.addSequence(sequence, false);
+      av.setSelectionGroup(sg);
+    }
+
+    ap.paintAlignment(false);
+  }
+
+  void insertGapAtCursor(boolean group)
+  {
+    groupEditing = group;
+    startseq = seqCanvas.cursorY;
+    lastres = seqCanvas.cursorX;
+    editSequence(true, seqCanvas.cursorX + getKeyboardNo1());
+    endEditing();
+  }
+
+  void deleteGapAtCursor(boolean group)
+  {
+    groupEditing = group;
+    startseq = seqCanvas.cursorY;
+    lastres = seqCanvas.cursorX + getKeyboardNo1();
+    editSequence(false, seqCanvas.cursorX);
+    endEditing();
+  }
+
+  void numberPressed(char value)
+  {
+    if (keyboardNo1 == null)
+    {
+      keyboardNo1 = new StringBuffer();
+    }
+
+    if (keyboardNo2 != null)
+    {
+      keyboardNo2.append(value);
+    }
+    else
+    {
+      keyboardNo1.append(value);
+    }
+  }
+
+  int getKeyboardNo1()
+  {
+    if (keyboardNo1 == null)
+      return 1;
+    else
+    {
+      int value = Integer.parseInt(keyboardNo1.toString());
+      keyboardNo1 = null;
+      return value;
+    }
+  }
+
+  int getKeyboardNo2()
+  {
+    if (keyboardNo2 == null)
+      return 1;
+    else
+    {
+      int value = Integer.parseInt(keyboardNo2.toString());
+      keyboardNo2 = null;
+      return value;
+    }
+  }
+
+
+  void setStatusMessage(SequenceI sequence, int res, int seq)
+  {
+    StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +
+                                         sequence.getName());
+
+    Object obj = null;
+    if (av.alignment.isNucleotide())
+    {
+      obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +
+                                                 "");
+      if (obj != null)
+      {
+        text.append(" Nucleotide: ");
+      }
+    }
+    else
+    {
+      obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");
+      if (obj != null)
+      {
+        text.append("  Residue: ");
+      }
+    }
+
+    if (obj != null)
+    {
+
+      if (obj != "")
+      {
+        text.append(obj + " (" + sequence.findPosition(res) +
+                    ")");
+      }
+    }
+
+    ap.alignFrame.statusBar.setText(text.toString());
+
+  }
+
+  public void mousePressed(MouseEvent evt)
+  {
+    lastMousePress = evt.getPoint();
+
+    //For now, ignore the mouseWheel font resizing on Macs
+    //As the Button2_mask always seems to be true
+    if ( (evt.getModifiers() & InputEvent.BUTTON2_MASK) ==
+        InputEvent.BUTTON2_MASK && !av.MAC)
+    {
+      mouseWheelPressed = true;
+      return;
+    }
+
+    if (evt.isShiftDown()
+        || evt.isControlDown()
+        || evt.isAltDown())
+    {
+      if (evt.isControlDown() || evt.isAltDown())
+      {
+        groupEditing = true;
+      }
+      editingSeqs = true;
+    }
+    else
+    {
+      doMousePressedDefineMode(evt);
+      return;
+    }
+
+    int seq = findSeq(evt);
+    int res = findRes(evt);
+
+    if (seq < 0 || res < 0)
+    {
+      return;
+    }
+
+    if ( (seq < av.getAlignment().getHeight()) &&
+        (res < av.getAlignment().getSequenceAt(seq).getLength()))
+    {
+      startseq = seq;
+      lastres = res;
+    }
+    else
+    {
+      startseq = -1;
+      lastres = -1;
+    }
+
+    return;
+  }
+
+  public void mouseClicked(MouseEvent evt)
+  {
+    SequenceI sequence = av.alignment.getSequenceAt(findSeq(evt));
+    if (evt.getClickCount() > 1)
+    {
+      if (av.getSelectionGroup().getSize() == 1
+          && av.getSelectionGroup().getEndRes()
+          - av.getSelectionGroup().getStartRes() < 2)
+      {
+        av.setSelectionGroup(null);
+      }
+
+      SequenceFeature[] features = findFeaturesAtRes(
+          sequence,
+          sequence.findPosition(findRes(evt))
+          );
+
+      if (features != null && features.length > 0)
+      {
+        SearchResults highlight = new SearchResults();
+        highlight.addResult(sequence,
+                            features[0].getBegin(),
+                            features[0].getEnd());
+        seqCanvas.highlightSearchResults(highlight);
+      }
+      if (features != null && features.length > 0)
+      {
+        seqCanvas.getFeatureRenderer().amendFeatures(
+            new SequenceI[]
+            {sequence}, features, false, ap);
+
+        seqCanvas.highlightSearchResults(null);
+      }
+    }
+  }
+
+  public void mouseReleased(MouseEvent evt)
+  {
+    mouseDragging = false;
+    mouseWheelPressed = false;
+    ap.paintAlignment(true);
+
+    if (!editingSeqs)
+    {
+      doMouseReleasedDefineMode(evt);
+      return;
+    }
+
+    endEditing();
+
+  }
+
+  int startWrapBlock = -1;
+  int wrappedBlock = -1;
+  int findRes(MouseEvent evt)
+  {
+    int res = 0;
+    int x = evt.getX();
+
+    if (av.wrapAlignment)
+    {
+
+      int hgap = av.charHeight;
+      if (av.scaleAboveWrapped)
+      {
+        hgap += av.charHeight;
+      }
+
+      int cHeight = av.getAlignment().getHeight() * av.charHeight
+          + hgap + seqCanvas.getAnnotationHeight();
+
+      int y = evt.getY();
+      y -= hgap;
+      x -= seqCanvas.LABEL_WEST;
+
+      int cwidth = seqCanvas.getWrappedCanvasWidth(getSize().width);
+      if (cwidth < 1)
+      {
+        return 0;
+      }
+
+      wrappedBlock = y / cHeight;
+      wrappedBlock += av.getStartRes() / cwidth;
+
+      res = wrappedBlock * cwidth + x / av.getCharWidth();
+
+    }
+    else
+    {
+      res = (x / av.getCharWidth()) + av.getStartRes();
+    }
+
+    if (av.hasHiddenColumns)
+    {
+      res = av.getColumnSelection().adjustForHiddenColumns(res);
+    }
+
+    return res;
+
+  }
+
+  int findSeq(MouseEvent evt)
+  {
+
+    int seq = 0;
+    int y = evt.getY();
+
+    if (av.wrapAlignment)
+    {
+      int hgap = av.charHeight;
+      if (av.scaleAboveWrapped)
+      {
+        hgap += av.charHeight;
+      }
+
+      int cHeight = av.getAlignment().getHeight() * av.charHeight
+          + hgap + seqCanvas.getAnnotationHeight();
+
+      y -= hgap;
+
+      seq = Math.min( (y % cHeight) / av.getCharHeight(),
+                     av.alignment.getHeight() - 1);
+      if (seq < 0)
+      {
+        seq = 0;
+      }
+    }
+    else
+    {
+      seq = Math.min( (y / av.getCharHeight()) + av.getStartSeq(),
+                     av.alignment.getHeight() - 1);
+      if (seq < 0)
+      {
+        seq = 0;
+      }
+    }
+
+    return seq;
+  }
+
+
+
+  public void doMousePressed(MouseEvent evt)
+  {
+
+    int seq = findSeq(evt);
+    int res = findRes(evt);
+
+    if (seq < av.getAlignment().getHeight() &&
+        res < av.getAlignment().getSequenceAt(seq).getLength())
+    {
+      //char resstr = align.getSequenceAt(seq).getSequence().charAt(res);
+      // Find the residue's position in the sequence (res is the position
+      // in the alignment
+
+      startseq = seq;
+      lastres = res;
+    }
+    else
+    {
+      startseq = -1;
+      lastres = -1;
+    }
+
+    return;
+  }
+
+
+  String lastMessage;
+  public void mouseOverSequence(SequenceI sequence, int index, int pos)
+  {
+    String tmp = sequence.hashCode()+index+"";
+    if (lastMessage == null || !lastMessage.equals(tmp))
+      ssm.mouseOverSequence(sequence, index, pos);
+
+    lastMessage = tmp;
+  }
+
+
+  public void highlightSequence(SearchResults results)
+  {
+    seqCanvas.highlightSearchResults(results);
+  }
+
+  public void updateColours(SequenceI seq, int index)
+  {
+    System.out.println("update the seqPanel colours");
+    //repaint();
+  }
+
+  public void mouseMoved(MouseEvent evt)
+  {
+    int res = findRes(evt);
+    int seq = findSeq(evt);
+
+    if (seq >= av.getAlignment().getHeight() || seq < 0 || res < 0)
+    {
+      if (tooltip != null)
+      {
+        tooltip.setTip("");
+      }
+      return;
+    }
+
+    SequenceI sequence = av.getAlignment().getSequenceAt(seq);
+    if (res > sequence.getLength())
+    {
+      if (tooltip != null)
+      {
+        tooltip.setTip("");
+      }
+      return;
+    }
+
+    int respos = sequence.findPosition(res);
+    if (ssm != null)
+      mouseOverSequence(sequence, res, respos);
+
+
+    StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: " +
+                                         sequence.getName());
+
+    Object obj = null;
+    if (av.alignment.isNucleotide())
+    {
+      obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res) +
+                                                 "");
+      if (obj != null)
+      {
+        text.append(" Nucleotide: ");
+      }
+    }
+    else
+    {
+      obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");
+      if (obj != null)
+      {
+        text.append("  Residue: ");
+      }
+    }
+
+    if (obj != null)
+    {
+      if (obj != "")
+      {
+        text.append(obj + " (" + respos + ")");
+      }
+    }
+
+    ap.alignFrame.statusBar.setText(text.toString());
+
+    StringBuffer tooltipText = new StringBuffer();
+    SequenceGroup[] groups = av.alignment.findAllGroups(sequence);
+    if (groups != null)
+    {
+      for (int g = 0; g < groups.length; g++)
+      {
+        if (groups[g].getStartRes() <= res && groups[g].getEndRes() >= res)
+        {
+          if (!groups[g].getName().startsWith("JTreeGroup") &&
+              !groups[g].getName().startsWith("JGroup"))
+          {
+            tooltipText.append(groups[g].getName() + " ");
+          }
+          if (groups[g].getDescription() != null)
+          {
+            tooltipText.append(groups[g].getDescription());
+          }
+          tooltipText.append("\n");
+        }
+      }
+    }
+
+    // use aa to see if the mouse pointer is on a
+    SequenceFeature [] allFeatures = findFeaturesAtRes(sequence,
+                                               sequence.findPosition(res));
+
+      int index = 0;
+      while (index < allFeatures.length)
+      {
+        SequenceFeature sf = allFeatures[index];
+
+        tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);
+
+        if (sf.getDescription() != null)
+        {
+          tooltipText.append(" " + sf.getDescription());
+        }
+
+        if (sf.getValue("status") != null)
+        {
+          String status = sf.getValue("status").toString();
+          if (status.length() > 0)
+          {
+            tooltipText.append(" (" + sf.getValue("status") + ")");
+          }
+        }
+        tooltipText.append("\n");
+
+        index++;
+      }
+
+    if (tooltip == null)
+    {
+      tooltip = new Tooltip(tooltipText.toString(), seqCanvas);
+    }
+    else
+    {
+      tooltip.setTip(tooltipText.toString());
+    }
+  }
+
+  SequenceFeature[] findFeaturesAtRes(SequenceI sequence, int res)
+  {
+    Vector tmp = new Vector();
+    SequenceFeature[] features = sequence.getSequenceFeatures();
+    if (features != null)
+    {
+      for (int i = 0; i < features.length; i++)
+      {
+        if (av.featuresDisplayed == null
+            || !av.featuresDisplayed.containsKey(features[i].getType()))
+        {
+          continue;
+        }
+
+
+
+        if (features[i].featureGroup != null
+           && seqCanvas.fr.featureGroups!=null
+            && seqCanvas.fr.featureGroups.containsKey(features[i].featureGroup)
+            && !((Boolean)seqCanvas.fr.featureGroups.get(features[i].featureGroup)).booleanValue())
+          continue;
+
+
+        if ( (features[i].getBegin() <= res) &&
+            (features[i].getEnd() >= res))
+        {
+          tmp.addElement(features[i]);
+        }
+      }
+    }
+
+    features = new SequenceFeature[tmp.size()];
+    tmp.copyInto(features);
+
+    return features;
+  }
+
+
+  Tooltip tooltip;
+
+  public void mouseDragged(MouseEvent evt)
+  {
+    if (mouseWheelPressed)
+    {
+      int oldWidth = av.charWidth;
+
+      //Which is bigger, left-right or up-down?
+      if (Math.abs(evt.getY() - lastMousePress.y)
+          > Math.abs(evt.getX() - lastMousePress.x))
+      {
+        int fontSize = av.font.getSize();
+
+        if (evt.getY() < lastMousePress.y && av.charHeight > 1)
+        {
+          fontSize--;
+        }
+        else if (evt.getY() > lastMousePress.y)
+        {
+          fontSize++;
+        }
+
+        if (fontSize < 1)
+        {
+          fontSize = 1;
+        }
+
+        av.setFont(new Font(av.font.getName(), av.font.getStyle(), fontSize));
+        av.charWidth = oldWidth;
+      }
+      else
+      {
+        if (evt.getX() < lastMousePress.x && av.charWidth > 1)
+        {
+          av.charWidth--;
+        }
+        else if (evt.getX() > lastMousePress.x)
+        {
+          av.charWidth++;
+        }
+
+        if (av.charWidth < 1)
+        {
+          av.charWidth = 1;
+        }
+      }
+
+      ap.fontChanged();
+
+      FontMetrics fm = getFontMetrics(av.getFont());
+      av.validCharWidth = fm.charWidth('M') <= av.charWidth;
+
+      lastMousePress = evt.getPoint();
+
+      ap.paintAlignment(false);
+      ap.annotationPanel.image = null;
+      return;
+    }
+
+    if (!editingSeqs)
+    {
+      doMouseDraggedDefineMode(evt);
+      return;
+    }
+
+    int res = findRes(evt);
+
+    if (res < 0)
+    {
+      res = 0;
+    }
+
+    if ( (lastres == -1) || (lastres == res))
+    {
+      return;
+    }
+
+    if ( (res < av.getAlignment().getWidth()) && (res < lastres))
+    {
+      // dragLeft, delete gap
+      editSequence(false, res);
+    }
+    else
+    {
+      editSequence(true, res);
+    }
+
+    mouseDragging = true;
+    if (scrollThread != null)
+    {
+      scrollThread.setEvent(evt);
+    }
+
+  }
+
+  synchronized void editSequence(boolean insertGap, int startres)
+  {
+    int fixedLeft = -1;
+    int fixedRight = -1;
+    boolean fixedColumns = false;
+    SequenceGroup sg = av.getSelectionGroup();
+
+    SequenceI seq = av.alignment.getSequenceAt(startseq);
+
+    if (!groupEditing && av.hasHiddenRows)
+    {
+      if (av.hiddenRepSequences != null
+          && av.hiddenRepSequences.containsKey(seq))
+      {
+        sg = (SequenceGroup) av.hiddenRepSequences.get(seq);
+        groupEditing = true;
+      }
+    }
+
+    StringBuffer message = new StringBuffer();
+    if (groupEditing)
+    {
+      message.append("Edit group:");
+      if (editCommand == null)
+      {
+        editCommand = new EditCommand("Edit Group");
+      }
+    }
+    else
+    {
+      message.append("Edit sequence: " + seq.getName());
+      String label = seq.getName();
+      if (label.length() > 10)
+      {
+        label = label.substring(0, 10);
+      }
+      if (editCommand == null)
+      {
+        editCommand = new EditCommand("Edit " + label);
+      }
+    }
+
+    if (insertGap)
+    {
+      message.append(" insert ");
+    }
+    else
+    {
+      message.append(" delete ");
+    }
+
+    message.append(Math.abs(startres - lastres) + " gaps.");
+    ap.alignFrame.statusBar.setText(message.toString());
+
+    //Are we editing within a selection group?
+    if (groupEditing
+        || (sg != null && sg.getSequences(av.hiddenRepSequences).contains(seq)))
+    {
+      fixedColumns = true;
+
+      //sg might be null as the user may only see 1 sequence,
+      //but the sequence represents a group
+      if (sg == null)
+      {
+        if (av.hiddenRepSequences == null
+            || !av.hiddenRepSequences.containsKey(seq))
+        {
+          endEditing();
+          return;
+        }
+
+        sg = (SequenceGroup) av.hiddenRepSequences.get(seq);
+      }
+
+      fixedLeft = sg.getStartRes();
+      fixedRight = sg.getEndRes();
+
+      if ( (startres < fixedLeft && lastres >= fixedLeft)
+          || (startres >= fixedLeft && lastres < fixedLeft)
+          || (startres > fixedRight && lastres <= fixedRight)
+          || (startres <= fixedRight && lastres > fixedRight))
+      {
+        endEditing();
+        return;
+      }
+
+      if (fixedLeft > startres)
+      {
+        fixedRight = fixedLeft - 1;
+        fixedLeft = 0;
+      }
+      else if (fixedRight < startres)
+      {
+        fixedLeft = fixedRight;
+        fixedRight = -1;
+      }
+    }
+
+    if (av.hasHiddenColumns)
+    {
+      fixedColumns = true;
+      int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
+      int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
+
+      if ( (insertGap && startres > y1 && lastres < y1)
+          || (!insertGap && startres < y2 && lastres > y2))
+      {
+        endEditing();
+        return;
+      }
+
+      //System.out.print(y1+" "+y2+" "+fixedLeft+" "+fixedRight+"~~");
+      //Selection spans a hidden region
+      if (fixedLeft < y1 && (fixedRight > y2 || fixedRight == -1))
+      {
+        if (startres >= y2)
+        {
+          fixedLeft = y2;
+        }
+        else
+        {
+          fixedRight = y2 - 1;
+        }
+      }
+    }
+
+    if (groupEditing)
+    {
+      Vector vseqs = sg.getSequences(av.hiddenRepSequences);
+      int g, groupSize = vseqs.size();
+      SequenceI[] groupSeqs = new SequenceI[groupSize];
+      for (g = 0; g < groupSeqs.length; g++)
+      {
+        groupSeqs[g] = (SequenceI) vseqs.elementAt(g);
+      }
+
+      // drag to right
+      if (insertGap)
+      {
+        //If the user has selected the whole sequence, and is dragging to
+        // the right, we can still extend the alignment and selectionGroup
+        if (sg.getStartRes() == 0
+            && sg.getEndRes() == fixedRight
+            && sg.getEndRes() == av.alignment.getWidth() - 1
+            )
+        {
+          sg.setEndRes(av.alignment.getWidth() + startres - lastres);
+          fixedRight = sg.getEndRes();
+        }
+
+        // Is it valid with fixed columns??
+        // Find the next gap before the end
+        // of the visible region boundary
+        boolean blank = false;
+        for (fixedRight = fixedRight;
+             fixedRight > lastres;
+             fixedRight--)
+        {
+          blank = true;
+
+          for (g = 0; g < groupSize; g++)
+          {
+            for (int j = 0; j < startres - lastres; j++)
+            {
+              if (!jalview.util.Comparison.isGap(
+                  groupSeqs[g].getCharAt(fixedRight - j)))
+              {
+                blank = false;
+                break;
+              }
+            }
+          }
+          if (blank)
+          {
+            break;
+          }
+        }
+
+        if (!blank)
+        {
+          if (sg.getSize() == av.alignment.getHeight())
+          {
+            if ( (av.hasHiddenColumns
+                  &&
+                  startres < av.getColumnSelection().getHiddenBoundaryRight(startres)))
+            {
+              endEditing();
+              return;
+            }
+
+            int alWidth = av.alignment.getWidth();
+            if (av.hasHiddenRows)
+            {
+              int hwidth = av.alignment.getHiddenSequences().getWidth();
+              if (hwidth > alWidth)
+              {
+                alWidth = hwidth;
+              }
+            }
+            //We can still insert gaps if the selectionGroup
+            //contains all the sequences
+            sg.setEndRes(sg.getEndRes() + startres - lastres);
+            fixedRight = alWidth + startres - lastres;
+          }
+          else
+          {
+            endEditing();
+            return;
+          }
+        }
+      }
+
+      // drag to left
+      else if (!insertGap)
+      {
+        /// Are we able to delete?
+        // ie are all columns blank?
+
+        for (g = 0; g < groupSize; g++)
+        {
+          for (int j = startres; j < lastres; j++)
+          {
+            if (groupSeqs[g].getLength() <= j)
+            {
+              continue;
+            }
+
+            if (!jalview.util.Comparison.isGap(
+                groupSeqs[g].getCharAt(j)))
+            {
+              // Not a gap, block edit not valid
+              endEditing();
+              return;
+            }
+          }
+        }
+      }
+
+      if (insertGap)
+      {
+        // dragging to the right
+        if (fixedColumns && fixedRight != -1)
+        {
+          for (int j = lastres; j < startres; j++)
+          {
+            insertChar(j, groupSeqs, fixedRight);
+          }
+        }
+        else
+        {
+          editCommand.appendEdit(EditCommand.INSERT_GAP,
+                                 groupSeqs,
+                                 startres, startres - lastres,
+                                 av.alignment,
+                                 true);
+        }
+      }
+      else
+      {
+        // dragging to the left
+        if (fixedColumns && fixedRight != -1)
+        {
+          for (int j = lastres; j > startres; j--)
+          {
+            deleteChar(startres, groupSeqs, fixedRight);
+          }
+        }
+        else
+        {
+          editCommand.appendEdit(EditCommand.DELETE_GAP,
+                                 groupSeqs,
+                                 startres, lastres - startres,
+                                 av.alignment,
+                                 true);
+        }
+
+      }
+    }
+    else /////Editing a single sequence///////////
+    {
+      if (insertGap)
+      {
+        // dragging to the right
+        if (fixedColumns && fixedRight != -1)
+        {
+          for (int j = lastres; j < startres; j++)
+          {
+            insertChar(j, new SequenceI[]
+                       {seq}, fixedRight);
+          }
+        }
+        else
+        {
+          editCommand.appendEdit(EditCommand.INSERT_GAP,
+                                 new SequenceI[]
+                                 {seq},
+                                 lastres, startres - lastres,
+                                 av.alignment,
+                                 true);
+        }
+      }
+      else
+      {
+        // dragging to the left
+        if (fixedColumns && fixedRight != -1)
+        {
+          for (int j = lastres; j > startres; j--)
+          {
+            if (!jalview.util.Comparison.isGap(seq.getCharAt(startres)))
+            {
+              endEditing();
+              break;
+            }
+            deleteChar(startres, new SequenceI[]
+                       {seq}, fixedRight);
+          }
+        }
+        else
+        {
+          //could be a keyboard edit trying to delete none gaps
+          int max = 0;
+          for (int m = startres; m < lastres; m++)
+          {
+            if (!jalview.util.Comparison.isGap(seq.getCharAt(m)))
+            {
+              break;
+            }
+            max++;
+          }
+
+          if (max > 0)
+          {
+            editCommand.appendEdit(EditCommand.DELETE_GAP,
+                                   new SequenceI[]
+                                   {seq},
+                                   startres, max,
+                                   av.alignment,
+                                   true);
+          }
+        }
+      }
+    }
+
+    lastres = startres;
+    seqCanvas.repaint();
+  }
+
+  void insertChar(int j, SequenceI[] seq, int fixedColumn)
+  {
+    int blankColumn = fixedColumn;
+    for (int s = 0; s < seq.length; s++)
+    {
+      //Find the next gap before the end of the visible region boundary
+      //If lastCol > j, theres a boundary after the gap insertion
+
+      for (blankColumn = fixedColumn; blankColumn > j; blankColumn--)
+      {
+        if (jalview.util.Comparison.isGap(seq[s].getCharAt(blankColumn)))
+        {
+          //Theres a space, so break and insert the gap
+          break;
+        }
+      }
+
+      if (blankColumn <= j)
+      {
+        blankColumn = fixedColumn;
+        endEditing();
+        return;
+      }
+    }
+
+    editCommand.appendEdit(EditCommand.DELETE_GAP,
+                           seq,
+                           blankColumn, 1, av.alignment, true);
+
+    editCommand.appendEdit(EditCommand.INSERT_GAP,
+                           seq,
+                           j, 1, av.alignment,
+                           true);
+
+  }
+
+  void deleteChar(int j, SequenceI[] seq, int fixedColumn)
+  {
+
+    editCommand.appendEdit(EditCommand.DELETE_GAP,
+                           seq,
+                           j, 1, av.alignment, true);
+
+    editCommand.appendEdit(EditCommand.INSERT_GAP,
+                           seq,
+                           fixedColumn, 1, av.alignment, true);
+  }
+
+//////////////////////////////////////////
+/////Everything below this is for defining the boundary of the rubberband
+//////////////////////////////////////////
+  public void doMousePressedDefineMode(MouseEvent evt)
+  {
+    if (scrollThread != null)
+    {
+      scrollThread.running = false;
+      scrollThread = null;
+    }
+
+    int res = findRes(evt);
+    int seq = findSeq(evt);
+    oldSeq = seq;
+    startWrapBlock = wrappedBlock;
+
+    if (seq == -1)
+    {
+      return;
+    }
+
+    SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);
+
+    if (sequence == null || res > sequence.getLength())
+    {
+      return;
+    }
+
+    stretchGroup = av.getSelectionGroup();
+
+    if (stretchGroup == null)
+    {
+      stretchGroup = av.alignment.findGroup(sequence);
+      if (stretchGroup != null && res > stretchGroup.getStartRes() &&
+          res < stretchGroup.getEndRes())
+      {
+        av.setSelectionGroup(stretchGroup);
+      }
+      else
+      {
+        stretchGroup = null;
+      }
+    }
+
+    else if (!stretchGroup.getSequences(null).contains(sequence)
+             || stretchGroup.getStartRes() > res
+             || stretchGroup.getEndRes() < res)
+    {
+      stretchGroup = null;
+
+      SequenceGroup[] allGroups = av.alignment.findAllGroups(sequence);
+
+      if (allGroups != null)
+      {
+        for (int i = 0; i < allGroups.length; i++)
+        {
+          if (allGroups[i].getStartRes() <= res &&
+              allGroups[i].getEndRes() >= res)
+          {
+            stretchGroup = allGroups[i];
+            break;
+          }
+        }
+      }
+      av.setSelectionGroup(stretchGroup);
+    }
+
+    // DETECT RIGHT MOUSE BUTTON IN AWT
+    if ( (evt.getModifiers() & InputEvent.BUTTON3_MASK) ==
+        InputEvent.BUTTON3_MASK)
+    {
+      SequenceFeature [] allFeatures = findFeaturesAtRes(sequence,
+                                               sequence.findPosition(res));
+
+      Vector links = null;
+      if (allFeatures != null)
+      {
+        for (int i = 0; i < allFeatures.length; i++)
+        {
+          if (allFeatures[i].links != null)
+          {
+            links = new Vector();
+            for (int j = 0; j < allFeatures[i].links.size(); j++)
+            {
+              links.addElement(allFeatures[i].links.elementAt(j));
+            }
+          }
+        }
+      }
+      APopupMenu popup = new APopupMenu(ap, null, links);
+      this.add(popup);
+      popup.show(this, evt.getX(), evt.getY());
+      return;
+    }
+
+    if (av.cursorMode)
+    {
+      seqCanvas.cursorX = findRes(evt);
+      seqCanvas.cursorY = findSeq(evt);
+      seqCanvas.repaint();
+      return;
+    }
+
+    //Only if left mouse button do we want to change group sizes
+
+    if (stretchGroup == null)
+    {
+      // define a new group here
+      SequenceGroup sg = new SequenceGroup();
+      sg.setStartRes(res);
+      sg.setEndRes(res);
+      sg.addSequence(sequence, false);
+      av.setSelectionGroup(sg);
+      stretchGroup = sg;
+
+      if (av.getConservationSelected())
+      {
+        SliderPanel.setConservationSlider(ap, av.getGlobalColourScheme(),
+                                          "Background");
+      }
+      if (av.getAbovePIDThreshold())
+      {
+        SliderPanel.setPIDSliderSource(ap, av.getGlobalColourScheme(),
+                                       "Background");
+      }
+
+    }
+  }
+
+  public void doMouseReleasedDefineMode(MouseEvent evt)
+  {
+    if (stretchGroup == null)
+    {
+      return;
+    }
+
+    if (stretchGroup.cs != null)
+    {
+      if (stretchGroup.cs instanceof ClustalxColourScheme)
+      {
+        ( (ClustalxColourScheme) stretchGroup.cs).resetClustalX(
+            stretchGroup.getSequences(av.hiddenRepSequences),
+            stretchGroup.getWidth());
+      }
+
+      if (stretchGroup.cs instanceof Blosum62ColourScheme
+          || stretchGroup.cs instanceof PIDColourScheme
+          || stretchGroup.cs.conservationApplied()
+          || stretchGroup.cs.getThreshold() > 0)
+      {
+        stretchGroup.recalcConservation();
+      }
+
+      if (stretchGroup.cs.conservationApplied())
+      {
+        SliderPanel.setConservationSlider(ap, stretchGroup.cs,
+                                          stretchGroup.getName());
+        stretchGroup.recalcConservation();
+      }
+      else
+      {
+        SliderPanel.setPIDSliderSource(ap, stretchGroup.cs,
+                                       stretchGroup.getName());
+      }
+    }
+    changeEndRes = false;
+    changeStartRes = false;
+    stretchGroup = null;
+    PaintRefresher.Refresh(ap, av.getSequenceSetId());
+    ap.paintAlignment(true);
+  }
+
+  public void doMouseDraggedDefineMode(MouseEvent evt)
+  {
+    int res = findRes(evt);
+    int y = findSeq(evt);
+
+    if (wrappedBlock != startWrapBlock)
+    {
+      return;
+    }
+
+    if (stretchGroup == null)
+    {
+      return;
+    }
+
+    mouseDragging = true;
+
+    if (y > av.alignment.getHeight())
+    {
+      y = av.alignment.getHeight() - 1;
+    }
+
+    if (res >= av.alignment.getWidth())
+    {
+      res = av.alignment.getWidth() - 1;
+    }
+
+    if (stretchGroup.getEndRes() == res)
+    {
+      // Edit end res position of selected group
+      changeEndRes = true;
+    }
+    else if (stretchGroup.getStartRes() == res)
+    {
+      // Edit start res position of selected group
+      changeStartRes = true;
+    }
+
+    if (res < 0)
+    {
+      res = 0;
+    }
+
+    if (changeEndRes)
+    {
+      if (res > (stretchGroup.getStartRes() - 1))
+      {
+        stretchGroup.setEndRes(res);
+      }
+    }
+    else if (changeStartRes)
+    {
+      if (res < (stretchGroup.getEndRes() + 1))
+      {
+        stretchGroup.setStartRes(res);
+      }
+    }
+
+    int dragDirection = 0;
+
+    if (y > oldSeq)
+    {
+      dragDirection = 1;
+    }
+    else if (y < oldSeq)
+    {
+      dragDirection = -1;
+    }
+
+    while ( (y != oldSeq) && (oldSeq > -1) && (y < av.alignment.getHeight()))
+    {
+      // This routine ensures we don't skip any sequences, as the
+      // selection is quite slow.
+      Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);
+
+      oldSeq += dragDirection;
+
+      if (oldSeq < 0)
+      {
+        break;
+      }
+
+      Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);
+
+      if (stretchGroup.getSequences(null).contains(nextSeq))
+      {
+        stretchGroup.deleteSequence(seq, false);
+      }
+      else
+      {
+        if (seq != null)
+        {
+          stretchGroup.addSequence(seq, false);
+        }
+
+        stretchGroup.addSequence(nextSeq, false);
+      }
+    }
+
+    if (oldSeq < 0)
+    {
+      oldSeq = -1;
+    }
+
+    if (res > av.endRes || res < av.startRes
+        || y < av.startSeq || y > av.endSeq)
+    {
+      mouseExited(evt);
+    }
+
+    if (scrollThread != null)
+    {
+      scrollThread.setEvent(evt);
+    }
+
+    seqCanvas.repaint();
+  }
+
+  public void mouseEntered(MouseEvent e)
+  {
+    if (oldSeq < 0)
+    {
+      oldSeq = 0;
+    }
+
+    if (scrollThread != null)
+    {
+      scrollThread.running = false;
+      scrollThread = null;
+    }
+  }
+
+  public void mouseExited(MouseEvent e)
+  {
+    if (av.getWrapAlignment())
+    {
+      return;
+    }
+
+    if (mouseDragging && scrollThread == null)
+    {
+      scrollThread = new ScrollThread();
+    }
+  }
+
+  void scrollCanvas(MouseEvent evt)
+  {
+    if (evt == null)
+    {
+      if (scrollThread != null)
+      {
+        scrollThread.running = false;
+        scrollThread = null;
+      }
+      mouseDragging = false;
+    }
+    else
+    {
+      if (scrollThread == null)
+      {
+        scrollThread = new ScrollThread();
+      }
+
+      mouseDragging = true;
+      scrollThread.setEvent(evt);
+    }
+
+  }
+
+  // this class allows scrolling off the bottom of the visible alignment
+  class ScrollThread
+      extends Thread
+  {
+    MouseEvent evt;
+    boolean running = false;
+    public ScrollThread()
+    {
+      start();
+    }
+
+    public void setEvent(MouseEvent e)
+    {
+      evt = e;
+    }
+
+    public void stopScrolling()
+    {
+      running = false;
+    }
+
+    public void run()
+    {
+      running = true;
+      while (running)
+      {
+
+        if (evt != null)
+        {
+
+          if (mouseDragging && evt.getY() < 0 && av.getStartSeq() > 0)
+          {
+            running = ap.scrollUp(true);
+          }
+
+          if (mouseDragging && evt.getY() >= getSize().height &&
+              av.alignment.getHeight() > av.getEndSeq())
+          {
+            running = ap.scrollUp(false);
+          }
+
+          if (mouseDragging && evt.getX() < 0)
+          {
+            running = ap.scrollRight(false);
+          }
+
+          else if (mouseDragging && evt.getX() >= getSize().width)
+          {
+            running = ap.scrollRight(true);
+          }
+        }
+
+        try
+        {
+          Thread.sleep(75);
+        }
+        catch (Exception ex)
+        {}
+      }
+    }
+  }
+
+}
index c7887da..a8cd23a 100755 (executable)
@@ -498,14 +498,17 @@ public class AlignFrame
     showTranslation.setVisible( nucleotide );
     conservationMenuItem.setEnabled( !nucleotide );
     modifyConservation.setEnabled(   !nucleotide );
-
+    
     //Remember AlignFrame always starts as protein
     if(!nucleotide)
     {
       calculateMenu.remove(calculateMenu.getItemCount()-2);
     }
+    setShowProductsEnabled();
   }
 
+
+
   /**
    * Need to call this method when tabs are selected for multiple views,
    * or when loading from Jalview2XML.java
@@ -3527,7 +3530,7 @@ public class AlignFrame
 
       public void actionPerformed(ActionEvent e)
       {
-        new jalview.io.DBRefFetcher(
+        new jalview.ws.DBRefFetcher(
                 alignPanel.av.getSequenceSelection(),
                 alignPanel.alignFrame).fetchDBRefs(false);
       }
@@ -3553,8 +3556,134 @@ public class AlignFrame
       vs.storeJalview( chooser.getSelectedFile().getAbsolutePath(), this);
     }
   }*/
+  /**
+   * prototype of an automatically enabled/disabled analysis function
+   *
+   */
+  protected void setShowProductsEnabled()
+  {
+    SequenceI [] selection = viewport.getSequenceSelection();
+    if (canShowProducts(selection, viewport.getSelectionGroup()!=null, viewport.getAlignment().getDataset()))
+    {
+      showProducts.setEnabled(true);
+      
+    } else {
+      showProducts.setEnabled(false);
+    }
+  }
+  /**
+   * search selection for sequence xRef products and build the
+   * show products menu.
+   * @param selection
+   * @param dataset
+   * @return true if showProducts menu should be enabled.
+   */
+  public boolean canShowProducts(SequenceI[] selection, boolean isRegionSelection, Alignment dataset)
+  {
+    boolean showp=false;
+    try {
+      showProducts.removeAll();
+      final boolean dna = viewport.getAlignment().isNucleotide();
+      String[] ptypes = CrossRef.findSequenceXrefTypes(dna, selection, dataset);
+      //Object[] prods = CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(), selection, dataset, true);
+      final SequenceI[] sel = selection;
+      for (int t=0; ptypes!=null && t<ptypes.length; t++)
+      {
+        showp=true;
+        final boolean isRegSel = isRegionSelection;
+        final AlignFrame af = this;
+        final String source = ptypes[t];
+        JMenuItem xtype = new JMenuItem(ptypes[t]);
+        xtype.addActionListener(new ActionListener() {
+
+          public void actionPerformed(ActionEvent e)
+          {
+            af.showProductsFor(sel, isRegSel, dna, source);
+          }
+          
+        });
+        showProducts.add(xtype);
+      }
+      showProducts.setVisible(showp);
+      showProducts.setEnabled(showp);
+    } catch (Exception e)
+    {
+      jalview.bin.Cache.log.warn("canTranslate threw an exception - please report to help@jalview.org",e);
+     return false;
+    }
+    return showp;
+  }
+protected void showProductsFor(SequenceI[] sel, boolean isRegSel, boolean dna, String source)
+  {
+  Alignment ds = getViewport().alignment.getDataset();
+  Alignment prods = CrossRef.findXrefSequences(sel, dna, source, ds);
+  if (prods!=null)
+  {
+    SequenceI[] sprods = new SequenceI[prods.getHeight()];
+    for (int s=0; s<sprods.length;s++)
+    {
+      sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
+      if (!ds.getSequences().contains(sprods[s].getDatasetSequence()))
+        ds.addSequence(sprods[s].getDatasetSequence());
+    }
+    Alignment al = new Alignment(sprods);
+    AlignedCodonFrame[] cf = prods.getCodonFrames();
+    for (int s=0; cf!=null && s<cf.length; s++)
+    {
+      al.addCodonFrame(cf[s]);
+      cf[s] = null;
+    }
+    al.setDataset(ds);
+    AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+    String newtitle =""+((dna) ? "Proteins " : "Nucleotides ") + " for "+((isRegSel) ? "selected region of " : "")
+            + getTitle();
+    Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
+            DEFAULT_HEIGHT);
+  } else {
+    System.err.println("No Sequences generated for xRef type "+source);
+  }
+  }
+
 
+public boolean canShowTranslationProducts(SequenceI[] selection, AlignmentI alignment)
+{
+  // old way
+  try {
+      return (jalview.analysis.Dna.canTranslate(selection, viewport.getViewAsVisibleContigs(true)));
+  } catch (Exception e)
+  {
+    jalview.bin.Cache.log.warn("canTranslate threw an exception - please report to help@jalview.org",e);
+   return false;
+  }
+}
 
+public void showProducts_actionPerformed(ActionEvent e)
+{
+  ///////////////////////////////
+  // Collect Data to be translated/transferred
+  
+  SequenceI [] selection = viewport.getSequenceSelection();
+  AlignmentI al  = null;
+  try {
+      al = jalview.analysis.Dna.CdnaTranslate(selection, viewport.getViewAsVisibleContigs(true),
+          viewport.getGapCharacter(), viewport.getAlignment().getDataset());
+    } catch (Exception ex) {
+      al = null;
+      jalview.bin.Cache.log.debug("Exception during translation.",ex);
+    }
+    if (al==null)
+    {
+      JOptionPane.showMessageDialog(Desktop.desktop,
+          "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
+          "Translation Failed",
+          JOptionPane.WARNING_MESSAGE);
+    } else {
+      AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+      Desktop.addInternalFrame(af, "Translation of "+this.getTitle(),
+                               DEFAULT_WIDTH,
+                               DEFAULT_HEIGHT);
+    }
+  }
 
 public void showTranslation_actionPerformed(ActionEvent e)
 {
@@ -3567,7 +3696,7 @@ public void showTranslation_actionPerformed(ActionEvent e)
   try {
     al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring, viewport.getViewAsVisibleContigs(true),
         viewport.getGapCharacter(), viewport.alignment.getAlignmentAnnotation(),
-        viewport.alignment.getWidth());
+        viewport.alignment.getWidth(), viewport.getAlignment().getDataset());
   } catch (Exception ex) {
     al = null;
     jalview.bin.Cache.log.debug("Exception during translation.",ex);
index c082463..5f1a70b 100644 (file)
@@ -33,6 +33,7 @@ import jalview.structure.*;
 import jalview.datamodel.PDBEntry;
 import jalview.io.*;
 import jalview.schemes.*;
+import jalview.ws.EBIFetchClient;
 
 import org.jmol.api.*;
 import org.jmol.adapter.smarter.SmarterJmolAdapter;
index 7f41d3c..d6c0247 100755 (executable)
@@ -267,7 +267,7 @@ public class DasSourceBrowser
     progressBar.setVisible(true);\r
     progressBar.setIndeterminate(true);\r
 \r
-    dasSources = jalview.io.DasSequenceFeatureFetcher.getDASSources();\r
+    dasSources = jalview.ws.DasSequenceFeatureFetcher.getDASSources();\r
 \r
     appendLocalSources();\r
 \r
@@ -300,7 +300,7 @@ public class DasSourceBrowser
   {\r
     if (dasSources == null)\r
     {\r
-      dasSources = jalview.io.DasSequenceFeatureFetcher.getDASSources();\r
+      dasSources = jalview.ws.DasSequenceFeatureFetcher.getDASSources();\r
       appendLocalSources();\r
     }\r
 \r
index 2d47b60..de61be3 100755 (executable)
@@ -37,7 +37,7 @@ public class FeatureSettings
     extends JPanel
 {
   DasSourceBrowser dassourceBrowser;
-  jalview.io.DasSequenceFeatureFetcher dasFeatureFetcher;
+  jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
   JPanel settingsPane = new JPanel();
   JPanel dasSettingsPane = new JPanel();
 
@@ -778,7 +778,7 @@ public class FeatureSettings
     }
 
     dasFeatureFetcher =
-        new jalview.io.DasSequenceFeatureFetcher(
+        new jalview.ws.DasSequenceFeatureFetcher(
             dataset,
             this,
             selectedSources);
index 888dba1..2068b0b 100755 (executable)
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2007 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.gui;\r
-\r
-import java.util.*;\r
-\r
-import java.awt.*;\r
-import java.awt.event.*;\r
-import javax.swing.*;\r
-\r
-import MCview.*;\r
-import jalview.analysis.*;\r
-import jalview.commands.*;\r
-import jalview.datamodel.*;\r
-import jalview.io.*;\r
-import jalview.schemes.*;\r
-\r
-/**\r
- * DOCUMENT ME!\r
- *\r
- * @author $author$\r
- * @version $Revision$\r
- */\r
-public class PopupMenu\r
-    extends JPopupMenu\r
-{\r
-  JMenu groupMenu = new JMenu();\r
-  JMenuItem groupName = new JMenuItem();\r
-  protected JRadioButtonMenuItem clustalColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem zappoColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem taylorColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem hydrophobicityColour = new\r
-      JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem helixColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem strandColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem turnColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem buriedColour = new JRadioButtonMenuItem();\r
-  protected JCheckBoxMenuItem abovePIDColour = new JCheckBoxMenuItem();\r
-  protected JRadioButtonMenuItem userDefinedColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem PIDColour = new JRadioButtonMenuItem();\r
-  protected JRadioButtonMenuItem BLOSUM62Colour = new JRadioButtonMenuItem();\r
-  JRadioButtonMenuItem noColourmenuItem = new JRadioButtonMenuItem();\r
-  protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem();\r
-  AlignmentPanel ap;\r
-  JMenu sequenceMenu = new JMenu();\r
-  JMenuItem sequenceName = new JMenuItem();\r
-  Sequence sequence;\r
-  JMenuItem unGroupMenuItem = new JMenuItem();\r
-  JMenuItem outline = new JMenuItem();\r
-  JRadioButtonMenuItem nucleotideMenuItem = new JRadioButtonMenuItem();\r
-  JMenu colourMenu = new JMenu();\r
-  JCheckBoxMenuItem showBoxes = new JCheckBoxMenuItem();\r
-  JCheckBoxMenuItem showText = new JCheckBoxMenuItem();\r
-  JCheckBoxMenuItem showColourText = new JCheckBoxMenuItem();\r
-  JMenu editMenu = new JMenu();\r
-  JMenuItem cut = new JMenuItem();\r
-  JMenuItem copy = new JMenuItem();\r
-  JMenuItem upperCase = new JMenuItem();\r
-  JMenuItem lowerCase = new JMenuItem();\r
-  JMenuItem toggle = new JMenuItem();\r
-  JMenu pdbMenu = new JMenu();\r
-  JMenuItem pdbFromFile = new JMenuItem();\r
-  JMenuItem enterPDB = new JMenuItem();\r
-  JMenuItem discoverPDB = new JMenuItem();\r
-  JMenu outputMenu = new JMenu();\r
-  JMenuItem sequenceFeature = new JMenuItem();\r
-  JMenuItem textColour = new JMenuItem();\r
-  JMenu jMenu1 = new JMenu();\r
-  JMenu structureMenu = new JMenu();\r
-  JMenu viewStructureMenu = new JMenu();\r
- // JMenu colStructureMenu = new JMenu();\r
-  JMenuItem editSequence = new JMenuItem();\r
- // JMenuItem annotationMenuItem = new JMenuItem();\r
-\r
-  /**\r
-   * Creates a new PopupMenu object.\r
-   *\r
-   * @param ap DOCUMENT ME!\r
-   * @param seq DOCUMENT ME!\r
-   */\r
-  public PopupMenu(final AlignmentPanel ap, Sequence seq, Vector links)\r
-  {\r
-    ///////////////////////////////////////////////////////////\r
-    // If this is activated from the sequence panel, the user may want to\r
-    // edit or annotate a particular residue. Therefore display the residue menu\r
-    //\r
-    // If from the IDPanel, we must display the sequence menu\r
-    //////////////////////////////////////////////////////////\r
-    this.ap = ap;\r
-    sequence = seq;\r
-\r
-    ButtonGroup colours = new ButtonGroup();\r
-    colours.add(noColourmenuItem);\r
-    colours.add(clustalColour);\r
-    colours.add(zappoColour);\r
-    colours.add(taylorColour);\r
-    colours.add(hydrophobicityColour);\r
-    colours.add(helixColour);\r
-    colours.add(strandColour);\r
-    colours.add(turnColour);\r
-    colours.add(buriedColour);\r
-    colours.add(abovePIDColour);\r
-    colours.add(userDefinedColour);\r
-    colours.add(PIDColour);\r
-    colours.add(BLOSUM62Colour);\r
-\r
-    for (int i = 0; i < jalview.io.FormatAdapter.WRITEABLE_FORMATS.length; i++)\r
-    {\r
-      JMenuItem item = new JMenuItem(jalview.io.FormatAdapter.WRITEABLE_FORMATS[\r
-                                     i]);\r
-\r
-      item.addActionListener(new java.awt.event.ActionListener()\r
-      {\r
-        public void actionPerformed(ActionEvent e)\r
-        {\r
-          outputText_actionPerformed(e);\r
-        }\r
-      });\r
-\r
-      outputMenu.add(item);\r
-    }\r
-\r
-    try\r
-    {\r
-      jbInit();\r
-    }\r
-    catch (Exception e)\r
-    {\r
-      e.printStackTrace();\r
-    }\r
-\r
-    if (seq != null)\r
-    {\r
-      sequenceMenu.setText(sequence.getName());\r
-\r
-      JMenuItem menuItem;\r
-      if (seq.getDatasetSequence().getPDBId() != null\r
-          && seq.getDatasetSequence().getPDBId().size()>0)\r
-      {\r
-        java.util.Enumeration e = seq.getDatasetSequence().getPDBId().\r
-            elements();\r
-\r
-        while (e.hasMoreElements())\r
-        {\r
-          final PDBEntry pdb = (PDBEntry) e.nextElement();\r
-\r
-          menuItem = new JMenuItem();\r
-          menuItem.setText(pdb.getId());\r
-          menuItem.addActionListener(new java.awt.event.ActionListener()\r
-          {\r
-            public void actionPerformed(ActionEvent e)\r
-            {\r
-              Vector seqs = new Vector();\r
-              for (int i = 0; i < ap.av.alignment.getHeight(); i++)\r
-              {\r
-                Vector pdbs = ap.av.alignment.getSequenceAt(i).getDatasetSequence().getPDBId();\r
-                if(pdbs==null)\r
-                  continue;\r
-\r
-                for(int p=0; p<pdbs.size(); p++)\r
-                {\r
-                  PDBEntry p1 = (PDBEntry)pdbs.elementAt(p);\r
-                  if(p1.getId().equals(pdb.getId()))\r
-                  {\r
-                    if (!seqs.contains(ap.av.alignment.getSequenceAt(i)))\r
-                        seqs.addElement(ap.av.alignment.getSequenceAt(i));\r
-\r
-                      continue;\r
-                  }\r
-                }\r
-              }\r
-\r
-              SequenceI [] seqs2 = new SequenceI[seqs.size()];\r
-              seqs.toArray(seqs2);\r
-\r
-              new AppJmol(pdb, seqs2, null, ap);\r
-              //  new PDBViewer(pdb, seqs2, null, ap, AppletFormatAdapter.FILE);\r
-            }\r
-          });\r
-          viewStructureMenu.add(menuItem);\r
-\r
-       /*   menuItem = new JMenuItem();\r
-          menuItem.setText(pdb.getId());\r
-          menuItem.addActionListener(new java.awt.event.ActionListener()\r
-          {\r
-            public void actionPerformed(ActionEvent e)\r
-            {\r
-              colourByStructure(pdb.getId());\r
-            }\r
-          });\r
-          colStructureMenu.add(menuItem);*/\r
-        }\r
-      }\r
-      else\r
-      {\r
-        structureMenu.remove(viewStructureMenu);\r
-       // structureMenu.remove(colStructureMenu);\r
-      }\r
-\r
-      menuItem = new JMenuItem("Hide Sequences");\r
-      menuItem.addActionListener(new java.awt.event.ActionListener()\r
-      {\r
-        public void actionPerformed(ActionEvent e)\r
-        {\r
-          hideSequences(false);\r
-        }\r
-      });\r
-      add(menuItem);\r
-\r
-      if (ap.av.getSelectionGroup() != null\r
-          && ap.av.getSelectionGroup().getSize() > 1)\r
-      {\r
-        menuItem = new JMenuItem("Represent Group with " + seq.getName());\r
-        menuItem.addActionListener(new java.awt.event.ActionListener()\r
-        {\r
-          public void actionPerformed(ActionEvent e)\r
-          {\r
-            hideSequences(true);\r
-          }\r
-        });\r
-        sequenceMenu.add(menuItem);\r
-      }\r
-\r
-      if (ap.av.hasHiddenRows)\r
-      {\r
-        final int index = ap.av.alignment.findIndex(seq);\r
-\r
-        if (ap.av.adjustForHiddenSeqs(index) -\r
-            ap.av.adjustForHiddenSeqs(index - 1) > 1)\r
-        {\r
-          menuItem = new JMenuItem("Reveal Sequences");\r
-          menuItem.addActionListener(new ActionListener()\r
-          {\r
-            public void actionPerformed(ActionEvent e)\r
-            {\r
-              ap.av.showSequence(index);\r
-              if (ap.overviewPanel != null)\r
-              {\r
-                ap.overviewPanel.updateOverviewImage();\r
-              }\r
-            }\r
-          });\r
-          add(menuItem);\r
-        }\r
-\r
-        menuItem = new JMenuItem("Reveal All");\r
-        menuItem.addActionListener(new ActionListener()\r
-        {\r
-          public void actionPerformed(ActionEvent e)\r
-          {\r
-            ap.av.showAllHiddenSeqs();\r
-            if (ap.overviewPanel != null)\r
-            {\r
-              ap.overviewPanel.updateOverviewImage();\r
-            }\r
-          }\r
-        });\r
-\r
-        add(menuItem);\r
-      }\r
-\r
-    }\r
-\r
-    SequenceGroup sg = ap.av.getSelectionGroup();\r
-\r
-    if (sg != null)\r
-    {\r
-      groupName.setText(sg.getName());\r
-\r
-      if (sg.cs instanceof ZappoColourScheme)\r
-      {\r
-        zappoColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof TaylorColourScheme)\r
-      {\r
-        taylorColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof PIDColourScheme)\r
-      {\r
-        PIDColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof Blosum62ColourScheme)\r
-      {\r
-        BLOSUM62Colour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof UserColourScheme)\r
-      {\r
-        userDefinedColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof HydrophobicColourScheme)\r
-      {\r
-        hydrophobicityColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof HelixColourScheme)\r
-      {\r
-        helixColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof StrandColourScheme)\r
-      {\r
-        strandColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof TurnColourScheme)\r
-      {\r
-        turnColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof BuriedColourScheme)\r
-      {\r
-        buriedColour.setSelected(true);\r
-      }\r
-      else if (sg.cs instanceof ClustalxColourScheme)\r
-      {\r
-        clustalColour.setSelected(true);\r
-      }\r
-      else\r
-      {\r
-        noColourmenuItem.setSelected(true);\r
-      }\r
-\r
-      if (sg.cs != null && sg.cs.conservationApplied())\r
-      {\r
-        conservationMenuItem.setSelected(true);\r
-      }\r
-\r
-      showText.setSelected(sg.getDisplayText());\r
-      showColourText.setSelected(sg.getColourText());\r
-      showBoxes.setSelected(sg.getDisplayBoxes());\r
-    }\r
-    else\r
-    {\r
-      groupMenu.setVisible(false);\r
-      editMenu.setVisible(false);\r
-    }\r
-\r
-    if (!ap.av.alignment.getGroups().contains(sg))\r
-    {\r
-      unGroupMenuItem.setVisible(false);\r
-    }\r
-\r
-    if (seq == null)\r
-    {\r
-      sequenceMenu.setVisible(false);\r
-      structureMenu.setVisible(false);\r
-    }\r
-\r
-    if (links != null && links.size() > 0)\r
-    {\r
-      JMenu linkMenu = new JMenu("Link");\r
-      JMenuItem item;\r
-      for (int i = 0; i < links.size(); i++)\r
-      {\r
-        String link = links.elementAt(i).toString();\r
-        final String label = link.substring(0, link.indexOf("|"));\r
-        item = new JMenuItem(label);\r
-        final String url;\r
-\r
-        if (link.indexOf("$SEQUENCE_ID$") > -1)\r
-        {\r
-          String id = seq.getName();\r
-          if (id.indexOf("|") > -1)\r
-          {\r
-            id = id.substring(id.lastIndexOf("|") + 1);\r
-          }\r
-\r
-          url = link.substring(link.indexOf("|") + 1,\r
-                               link.indexOf("$SEQUENCE_ID$"))\r
-              + id +\r
-              link.substring(link.indexOf("$SEQUENCE_ID$") + 13);\r
-        }\r
-        else\r
-        {\r
-          url = link.substring(link.lastIndexOf("|") + 1);\r
-        }\r
-\r
-        item.addActionListener(new java.awt.event.ActionListener()\r
-        {\r
-          public void actionPerformed(ActionEvent e)\r
-          {\r
-            showLink(url);\r
-          }\r
-        });\r
-\r
-        linkMenu.add(item);\r
-      }\r
-      if (sequence != null)\r
-      {\r
-        sequenceMenu.add(linkMenu);\r
-      }\r
-      else\r
-      {\r
-        add(linkMenu);\r
-      }\r
-    }\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @throws Exception DOCUMENT ME!\r
-   */\r
-  private void jbInit()\r
-      throws Exception\r
-  {\r
-    groupMenu.setText("Group");\r
-    groupMenu.setText("Selection");\r
-    groupName.setText("Name");\r
-    groupName.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        groupName_actionPerformed();\r
-      }\r
-    });\r
-    sequenceMenu.setText("Sequence");\r
-    sequenceName.setText("Edit Name/Description");\r
-    sequenceName.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        sequenceName_actionPerformed();\r
-      }\r
-    });\r
-    PIDColour.setFocusPainted(false);\r
-    unGroupMenuItem.setText("Remove Group");\r
-    unGroupMenuItem.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        unGroupMenuItem_actionPerformed();\r
-      }\r
-    });\r
-\r
-    outline.setText("Border colour");\r
-    outline.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        outline_actionPerformed();\r
-      }\r
-    });\r
-    nucleotideMenuItem.setText("Nucleotide");\r
-    nucleotideMenuItem.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        nucleotideMenuItem_actionPerformed();\r
-      }\r
-    });\r
-    colourMenu.setText("Group Colour");\r
-    showBoxes.setText("Boxes");\r
-    showBoxes.setState(true);\r
-    showBoxes.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        showBoxes_actionPerformed();\r
-      }\r
-    });\r
-    showText.setText("Text");\r
-    showText.setState(true);\r
-    showText.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        showText_actionPerformed();\r
-      }\r
-    });\r
-    showColourText.setText("Colour Text");\r
-    showColourText.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        showColourText_actionPerformed();\r
-      }\r
-    });\r
-    editMenu.setText("Edit");\r
-    cut.setText("Cut");\r
-    cut.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        cut_actionPerformed();\r
-      }\r
-    });\r
-    upperCase.setText("To Upper Case");\r
-    upperCase.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        changeCase(e);\r
-      }\r
-    });\r
-    copy.setText("Copy");\r
-    copy.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        copy_actionPerformed();\r
-      }\r
-    });\r
-    lowerCase.setText("To Lower Case");\r
-    lowerCase.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        changeCase(e);\r
-      }\r
-    });\r
-    toggle.setText("Toggle Case");\r
-    toggle.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        changeCase(e);\r
-      }\r
-    });\r
-    pdbMenu.setText("Associate Structure with Sequence");\r
-    pdbFromFile.setText("From File");\r
-    pdbFromFile.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        pdbFromFile_actionPerformed();\r
-      }\r
-    });\r
-    enterPDB.setText("Enter PDB Id");\r
-    enterPDB.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        enterPDB_actionPerformed();\r
-      }\r
-    });\r
-    discoverPDB.setText("Discover PDB ids");\r
-    discoverPDB.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        discoverPDB_actionPerformed();\r
-      }\r
-    });\r
-    outputMenu.setText("Output to Textbox...");\r
-    sequenceFeature.setText("Create Sequence Feature");\r
-    sequenceFeature.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        sequenceFeature_actionPerformed();\r
-      }\r
-    });\r
-    textColour.setText("Text Colour");\r
-    textColour.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        textColour_actionPerformed();\r
-      }\r
-    });\r
-    jMenu1.setText("Group");\r
-    structureMenu.setText("Structure");\r
-    viewStructureMenu.setText("View Structure");\r
-  //  colStructureMenu.setText("Colour By Structure");\r
-    editSequence.setText("Edit Sequence...");\r
-    editSequence.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent actionEvent)\r
-      {\r
-        editSequence_actionPerformed(actionEvent);\r
-      }\r
-    });\r
-   /* annotationMenuItem.setText("By Annotation");\r
-    annotationMenuItem.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent actionEvent)\r
-      {\r
-        annotationMenuItem_actionPerformed(actionEvent);\r
-      }\r
-    });*/\r
-\r
-    add(groupMenu);\r
-\r
-    add(sequenceMenu);\r
-    this.add(structureMenu);\r
-    groupMenu.add(editMenu);\r
-    groupMenu.add(outputMenu);\r
-    groupMenu.add(sequenceFeature);\r
-    groupMenu.add(jMenu1);\r
-    sequenceMenu.add(sequenceName);\r
-    colourMenu.add(textColour);\r
-    colourMenu.add(noColourmenuItem);\r
-    colourMenu.add(clustalColour);\r
-    colourMenu.add(BLOSUM62Colour);\r
-    colourMenu.add(PIDColour);\r
-    colourMenu.add(zappoColour);\r
-    colourMenu.add(taylorColour);\r
-    colourMenu.add(hydrophobicityColour);\r
-    colourMenu.add(helixColour);\r
-    colourMenu.add(strandColour);\r
-    colourMenu.add(turnColour);\r
-    colourMenu.add(buriedColour);\r
-    colourMenu.add(nucleotideMenuItem);\r
-    colourMenu.add(userDefinedColour);\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
-        JMenuItem item = new JMenuItem(userColours.\r
-                                       nextElement().toString());\r
-        item.addActionListener(new ActionListener()\r
-        {\r
-          public void actionPerformed(ActionEvent evt)\r
-          {\r
-            userDefinedColour_actionPerformed(evt);\r
-          }\r
-        });\r
-        colourMenu.add(item);\r
-      }\r
-    }\r
-\r
-    colourMenu.addSeparator();\r
-    colourMenu.add(abovePIDColour);\r
-    colourMenu.add(conservationMenuItem);\r
-    //colourMenu.add(annotationMenuItem);\r
-    editMenu.add(copy);\r
-    editMenu.add(cut);\r
-    editMenu.add(editSequence);\r
-    editMenu.add(upperCase);\r
-    editMenu.add(lowerCase);\r
-    editMenu.add(toggle);\r
-    pdbMenu.add(pdbFromFile);\r
-    pdbMenu.add(enterPDB);\r
-    pdbMenu.add(discoverPDB);\r
-    jMenu1.add(groupName);\r
-    jMenu1.add(unGroupMenuItem);\r
-    jMenu1.add(colourMenu);\r
-    jMenu1.add(showBoxes);\r
-    jMenu1.add(showText);\r
-    jMenu1.add(showColourText);\r
-    jMenu1.add(outline);\r
-    structureMenu.add(pdbMenu);\r
-    structureMenu.add(viewStructureMenu);\r
-   // structureMenu.add(colStructureMenu);\r
-    noColourmenuItem.setText("None");\r
-    noColourmenuItem.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        noColourmenuItem_actionPerformed();\r
-      }\r
-    });\r
-\r
-    clustalColour.setText("Clustalx colours");\r
-    clustalColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        clustalColour_actionPerformed();\r
-      }\r
-    });\r
-    zappoColour.setText("Zappo");\r
-    zappoColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        zappoColour_actionPerformed();\r
-      }\r
-    });\r
-    taylorColour.setText("Taylor");\r
-    taylorColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        taylorColour_actionPerformed();\r
-      }\r
-    });\r
-    hydrophobicityColour.setText("Hydrophobicity");\r
-    hydrophobicityColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        hydrophobicityColour_actionPerformed();\r
-      }\r
-    });\r
-    helixColour.setText("Helix propensity");\r
-    helixColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        helixColour_actionPerformed();\r
-      }\r
-    });\r
-    strandColour.setText("Strand propensity");\r
-    strandColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        strandColour_actionPerformed();\r
-      }\r
-    });\r
-    turnColour.setText("Turn propensity");\r
-    turnColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        turnColour_actionPerformed();\r
-      }\r
-    });\r
-    buriedColour.setText("Buried Index");\r
-    buriedColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        buriedColour_actionPerformed();\r
-      }\r
-    });\r
-    abovePIDColour.setText("Above % Identity");\r
-    abovePIDColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        abovePIDColour_actionPerformed();\r
-      }\r
-    });\r
-    userDefinedColour.setText("User Defined...");\r
-    userDefinedColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        userDefinedColour_actionPerformed(e);\r
-      }\r
-    });\r
-    PIDColour.setText("Percentage Identity");\r
-    PIDColour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        PIDColour_actionPerformed();\r
-      }\r
-    });\r
-    BLOSUM62Colour.setText("BLOSUM62");\r
-    BLOSUM62Colour.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        BLOSUM62Colour_actionPerformed();\r
-      }\r
-    });\r
-    conservationMenuItem.setText("Conservation");\r
-    conservationMenuItem.addActionListener(new java.awt.event.ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        conservationMenuItem_actionPerformed();\r
-      }\r
-    });\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   */\r
-  void refresh()\r
-  {\r
-    ap.paintAlignment(true);\r
-\r
-    PaintRefresher.Refresh(this, ap.av.getSequenceSetId());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void clustalColour_actionPerformed()\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-    sg.cs = new ClustalxColourScheme(sg.getSequences(ap.av.hiddenRepSequences),\r
-                                     ap.av.alignment.getWidth());\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void zappoColour_actionPerformed()\r
-  {\r
-    getGroup().cs = new ZappoColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void taylorColour_actionPerformed()\r
-  {\r
-    getGroup().cs = new TaylorColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void hydrophobicityColour_actionPerformed()\r
-  {\r
-    getGroup().cs = new HydrophobicColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void helixColour_actionPerformed()\r
-  {\r
-    getGroup().cs = new HelixColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void strandColour_actionPerformed()\r
-  {\r
-    getGroup().cs = new StrandColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void turnColour_actionPerformed()\r
-  {\r
-    getGroup().cs = new TurnColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void buriedColour_actionPerformed()\r
-  {\r
-    getGroup().cs = new BuriedColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void nucleotideMenuItem_actionPerformed()\r
-  {\r
-    getGroup().cs = new NucleotideColourScheme();\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void abovePIDColour_actionPerformed()\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-    if (sg.cs == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    if (abovePIDColour.isSelected())\r
-    {\r
-      sg.cs.setConsensus(AAFrequency.calculate(\r
-          sg.getSequences(ap.av.hiddenRepSequences), sg.getStartRes(),\r
-          sg.getEndRes() + 1));\r
-\r
-      int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs,\r
-          getGroup().getName());\r
-\r
-      sg.cs.setThreshold(threshold, ap.av.getIgnoreGapsConsensus());\r
-\r
-      SliderPanel.showPIDSlider();\r
-    }\r
-    else // remove PIDColouring\r
-    {\r
-      sg.cs.setThreshold(0, ap.av.getIgnoreGapsConsensus());\r
-    }\r
-\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void userDefinedColour_actionPerformed(ActionEvent e)\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-\r
-    if (e.getActionCommand().equals("User Defined..."))\r
-    {\r
-      new UserDefinedColours(ap, sg);\r
-    }\r
-    else\r
-    {\r
-      UserColourScheme udc = (UserColourScheme) UserDefinedColours.\r
-          getUserColourSchemes().get(e.getActionCommand());\r
-\r
-      sg.cs = udc;\r
-    }\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void PIDColour_actionPerformed()\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-    sg.cs = new PIDColourScheme();\r
-    sg.cs.setConsensus(AAFrequency.calculate(sg.getSequences(ap.av.\r
-        hiddenRepSequences),\r
-                                             sg.getStartRes(),\r
-                                             sg.getEndRes() + 1));\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void BLOSUM62Colour_actionPerformed()\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-\r
-    sg.cs = new Blosum62ColourScheme();\r
-\r
-    sg.cs.setConsensus(AAFrequency.calculate(sg.getSequences(ap.av.\r
-        hiddenRepSequences),\r
-                                             sg.getStartRes(),\r
-                                             sg.getEndRes() + 1));\r
-\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void noColourmenuItem_actionPerformed()\r
-  {\r
-    getGroup().cs = null;\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void conservationMenuItem_actionPerformed()\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-    if (sg.cs == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    if (conservationMenuItem.isSelected())\r
-    {\r
-      Conservation c = new Conservation("Group",\r
-                                        ResidueProperties.propHash, 3,\r
-                                        sg.getSequences(ap.av.\r
-          hiddenRepSequences),\r
-                                        sg.getStartRes(),\r
-                                        sg.getEndRes() + 1);\r
-\r
-      c.calculate();\r
-      c.verdict(false, ap.av.ConsPercGaps);\r
-\r
-      sg.cs.setConservation(c);\r
-\r
-      SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());\r
-      SliderPanel.showConservationSlider();\r
-    }\r
-    else // remove ConservationColouring\r
-    {\r
-      sg.cs.setConservation(null);\r
-    }\r
-\r
-    refresh();\r
-  }\r
-\r
-  public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-    if (sg == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    AnnotationColourGradient acg = new AnnotationColourGradient(\r
-        sequence.getAnnotation()[0], null, AnnotationColourGradient.NO_THRESHOLD);\r
-\r
-    acg.predefinedColours = true;\r
-    sg.cs = acg;\r
-\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void groupName_actionPerformed()\r
-  {\r
-\r
-    SequenceGroup sg = getGroup();\r
-    EditNameDialog dialog = new EditNameDialog(sg.getName(),\r
-                                               sg.getDescription(),\r
-                                               "       Group Name ",\r
-                                               "Group Description ",\r
-                                               "Edit Group Name/Description");\r
-\r
-    if (!dialog.accept)\r
-    {\r
-      return;\r
-    }\r
-\r
-    sg.setName(dialog.getName());\r
-    sg.setDescription(dialog.getDescription());\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @return DOCUMENT ME!\r
-   */\r
-  SequenceGroup getGroup()\r
-  {\r
-    SequenceGroup sg = ap.av.getSelectionGroup();\r
-    // this method won't add a new group if it already exists\r
-    if (sg != null)\r
-    {\r
-      ap.av.alignment.addGroup(sg);\r
-    }\r
-\r
-    return sg;\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  void sequenceName_actionPerformed()\r
-  {\r
-    EditNameDialog dialog = new EditNameDialog(sequence.getName(),\r
-                                               sequence.getDescription(),\r
-                                               "       Sequence Name ",\r
-                                               "Sequence Description ",\r
-                                               "Edit Sequence Name/Description");\r
-\r
-    if (!dialog.accept)\r
-    {\r
-      return;\r
-    }\r
-\r
-    if (dialog.getName() != null)\r
-    {\r
-      if (dialog.getName().indexOf(" ") > -1)\r
-      {\r
-        JOptionPane.showMessageDialog(ap,\r
-                                      "Spaces have been converted to \"_\"",\r
-                                      "No spaces allowed in Sequence Name",\r
-                                      JOptionPane.WARNING_MESSAGE);\r
-      }\r
-\r
-      sequence.setName(dialog.getName().replace(' ', '_'));\r
-      ap.paintAlignment(false);\r
-    }\r
-\r
-    sequence.setDescription(dialog.getDescription());\r
-\r
-    ap.av.firePropertyChange("alignment", null,\r
-                             ap.av.getAlignment().getSequences());\r
-\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  void unGroupMenuItem_actionPerformed()\r
-  {\r
-    SequenceGroup sg = ap.av.getSelectionGroup();\r
-    ap.av.alignment.deleteGroup(sg);\r
-    ap.av.setSelectionGroup(null);\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  protected void outline_actionPerformed()\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-    Color col = JColorChooser.showDialog(this, "Select Outline Colour",\r
-                                         Color.BLUE);\r
-\r
-    if (col != null)\r
-    {\r
-      sg.setOutlineColour(col);\r
-    }\r
-\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void showBoxes_actionPerformed()\r
-  {\r
-    getGroup().setDisplayBoxes(showBoxes.isSelected());\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void showText_actionPerformed()\r
-  {\r
-    getGroup().setDisplayText(showText.isSelected());\r
-    refresh();\r
-  }\r
-\r
-  /**\r
-   * DOCUMENT ME!\r
-   *\r
-   * @param e DOCUMENT ME!\r
-   */\r
-  public void showColourText_actionPerformed()\r
-  {\r
-    getGroup().setColourText(showColourText.isSelected());\r
-    refresh();\r
-  }\r
-\r
-  public void showLink(String url)\r
-  {\r
-    try\r
-    {\r
-      jalview.util.BrowserLauncher.openURL(url);\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-      JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
-                                            "Unixers: Couldn't find default web browser."\r
-                                            +\r
-          "\nAdd the full path to your browser in Preferences.",\r
-                                            "Web browser not found",\r
-                                            JOptionPane.WARNING_MESSAGE);\r
-\r
-      ex.printStackTrace();\r
-    }\r
-  }\r
-\r
-  void hideSequences(boolean representGroup)\r
-  {\r
-    SequenceGroup sg = ap.av.getSelectionGroup();\r
-    if (sg == null || sg.getSize() < 1)\r
-    {\r
-      ap.av.hideSequence(new SequenceI[]\r
-                         {sequence});\r
-      return;\r
-    }\r
-\r
-    ap.av.setSelectionGroup(null);\r
-\r
-    if (representGroup)\r
-    {\r
-      ap.av.hideRepSequences(sequence, sg);\r
-\r
-      return;\r
-    }\r
-\r
-    int gsize = sg.getSize();\r
-    SequenceI[] hseqs;\r
-\r
-    hseqs = new SequenceI[gsize];\r
-\r
-    int index = 0;\r
-    for (int i = 0; i < gsize; i++)\r
-    {\r
-      hseqs[index++] = sg.getSequenceAt(i);\r
-    }\r
-\r
-    ap.av.hideSequence(hseqs);\r
-  }\r
-\r
-  public void copy_actionPerformed()\r
-  {\r
-    ap.alignFrame.copy_actionPerformed(null);\r
-  }\r
-\r
-  public void cut_actionPerformed()\r
-  {\r
-    ap.alignFrame.cut_actionPerformed(null);\r
-  }\r
-\r
-  void changeCase(ActionEvent e)\r
-  {\r
-    Object source = e.getSource();\r
-    SequenceGroup sg = ap.av.getSelectionGroup();\r
-\r
-    if (sg != null)\r
-    {\r
-      int[][] startEnd = ap.av.getVisibleRegionBoundaries(\r
-          sg.getStartRes(), sg.getEndRes() + 1);\r
-\r
-      String description;\r
-      int caseChange;\r
-\r
-      if (source == toggle)\r
-      {\r
-        description = "Toggle Case";\r
-        caseChange = ChangeCaseCommand.TOGGLE_CASE;\r
-      }\r
-      else if (source == upperCase)\r
-      {\r
-        description = "To Upper Case";\r
-        caseChange = ChangeCaseCommand.TO_UPPER;\r
-      }\r
-      else\r
-      {\r
-        description = "To Lower Case";\r
-        caseChange = ChangeCaseCommand.TO_LOWER;\r
-      }\r
-\r
-      ChangeCaseCommand caseCommand = new ChangeCaseCommand(\r
-          description, sg.getSequencesAsArray(ap.av.hiddenRepSequences),\r
-          startEnd, caseChange\r
-          );\r
-\r
-      ap.alignFrame.addHistoryItem(caseCommand);\r
-\r
-      ap.av.firePropertyChange("alignment", null,\r
-                               ap.av.getAlignment().getSequences());\r
-\r
-    }\r
-  }\r
-\r
-  public void outputText_actionPerformed(ActionEvent e)\r
-  {\r
-    CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
-    cap.setForInput(null);\r
-    Desktop.addInternalFrame(cap,\r
-                             "Alignment output - " + e.getActionCommand(), 600,\r
-                             500);\r
-\r
-    String[] omitHidden = null;\r
-\r
-    if (ap.av.hasHiddenColumns)\r
-    {\r
-      System.out.println("PROMPT USER HERE");\r
-      omitHidden = ap.av.getViewAsString(true);\r
-    }\r
-\r
-    cap.setText(new FormatAdapter().formatSequences(\r
-        e.getActionCommand(),\r
-        ap.av.getSelectionAsNewSequence(),\r
-        omitHidden));\r
-  }\r
-\r
-  public void pdbFromFile_actionPerformed()\r
-  {\r
-    jalview.io.JalviewFileChooser chooser\r
-        = new jalview.io.JalviewFileChooser(jalview.bin.Cache.\r
-                                            getProperty(\r
-                                                "LAST_DIRECTORY"));\r
-    chooser.setFileView(new jalview.io.JalviewFileView());\r
-    chooser.setDialogTitle("Select a PDB file");\r
-    chooser.setToolTipText("Load a PDB file");\r
-\r
-    int value = chooser.showOpenDialog(null);\r
-\r
-    if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)\r
-    {\r
-      PDBEntry entry = new PDBEntry();\r
-      String choice = chooser.getSelectedFile().getPath();\r
-      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);\r
-      try\r
-      {\r
-        MCview.PDBfile pdbfile = new MCview.PDBfile(choice,\r
-            jalview.io.AppletFormatAdapter.FILE);\r
-\r
-        if (pdbfile.id == null)\r
-        {\r
-          String reply = JOptionPane.showInternalInputDialog(\r
-              Desktop.desktop,\r
-              "Couldn't find a PDB id in the file supplied."\r
-              + "Please enter an Id to identify this structure.",\r
-              "No PDB Id in File", JOptionPane.QUESTION_MESSAGE);\r
-          if (reply == null)\r
-          {\r
-            return;\r
-          }\r
-\r
-          entry.setId(reply);\r
-        }\r
-        else\r
-        {\r
-          entry.setId(pdbfile.id);\r
-        }\r
-      }\r
-      catch (java.io.IOException ex)\r
-      {\r
-        ex.printStackTrace();\r
-      }\r
-\r
-      entry.setFile(choice);\r
-      sequence.getDatasetSequence().addPDBId(entry);\r
-    }\r
-\r
-  }\r
-\r
-  public void enterPDB_actionPerformed()\r
-  {\r
-    String id = JOptionPane.showInternalInputDialog(Desktop.desktop,\r
-        "Enter PDB Id", "Enter PDB Id", JOptionPane.QUESTION_MESSAGE);\r
-\r
-    if (id != null && id.length() > 0)\r
-    {\r
-      PDBEntry entry = new PDBEntry();\r
-      entry.setId(id.toUpperCase());\r
-      sequence.getDatasetSequence()\r
-          .addPDBId(entry);\r
-    }\r
-  }\r
-\r
-  public void discoverPDB_actionPerformed()\r
-  {\r
-    SequenceI[] sequences =\r
-         ap.av.selectionGroup == null ?\r
-           new Sequence[]{sequence}\r
-         : ap.av.selectionGroup.getSequencesInOrder(ap.av.alignment);\r
-\r
-    new jalview.io.DBRefFetcher(sequences,\r
-        ap.alignFrame).fetchDBRefs(false);\r
-  }\r
-\r
-  public void sequenceFeature_actionPerformed()\r
-  {\r
-    SequenceGroup sg = ap.av.getSelectionGroup();\r
-    if (sg == null)\r
-    {\r
-      return;\r
-    }\r
-\r
-    int gSize = sg.getSize();\r
-    SequenceI[] seqs = new SequenceI[gSize];\r
-    SequenceFeature[] features = new SequenceFeature[gSize];\r
-\r
-    for (int i = 0; i < gSize; i++)\r
-    {\r
-      seqs[i] = sg.getSequenceAt(i).getDatasetSequence();\r
-      int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());\r
-      int end = sg.findEndRes(sg.getSequenceAt(i));\r
-      features[i] = new SequenceFeature(null, null, null, start, end, "Jalview");\r
-    }\r
-\r
-    if (ap.seqPanel.seqCanvas.getFeatureRenderer()\r
-        .amendFeatures(seqs, features, true, ap))\r
-    {\r
-      ap.alignFrame.showSeqFeatures.setSelected(true);\r
-      ap.av.setShowSequenceFeatures(true);\r
-      ap.highlightSearchResults(null);\r
-    }\r
-  }\r
-\r
-  public void textColour_actionPerformed()\r
-  {\r
-    SequenceGroup sg = getGroup();\r
-    if (sg != null)\r
-    {\r
-      new TextColourChooser().chooseColour(ap, sg);\r
-    }\r
-  }\r
-\r
-  public void colourByStructure(String pdbid)\r
-  {\r
-    Annotation [] anots = jalview.structure.StructureSelectionManager.getStructureSelectionManager()\r
-        .colourSequenceFromStructure(sequence, pdbid);\r
-\r
-    AlignmentAnnotation an = new AlignmentAnnotation(\r
-      "Structure", "Coloured by "+pdbid, anots);\r
-\r
-    ap.av.alignment.addAnnotation(an);\r
-    an.createSequenceMapping(sequence, 0, true);\r
-    //an.adjustForAlignment();\r
-    ap.av.alignment.setAnnotationIndex(an,0);\r
-\r
-    ap.adjustAnnotationHeight();\r
-\r
-    sequence.addAlignmentAnnotation(an);\r
-\r
-    }\r
-\r
-  public void editSequence_actionPerformed(ActionEvent actionEvent)\r
-  {\r
-      SequenceGroup sg = ap.av.getSelectionGroup();\r
-\r
-      if(sg!=null)\r
-      {\r
-        if (sequence == null)\r
-          sequence = (Sequence) sg.getSequenceAt(0);\r
-\r
-        EditNameDialog dialog = new EditNameDialog(\r
-            sequence.getSequenceAsString(\r
-                sg.getStartRes(),\r
-                sg.getEndRes() + 1),\r
-            null,\r
-            "Edit Sequence ",\r
-            null,\r
-            "Edit Sequence");\r
-\r
-        if (dialog.accept)\r
-        {\r
-          EditCommand editCommand = new EditCommand(\r
-              "Edit Sequences", EditCommand.REPLACE,\r
-              dialog.getName().replace(' ', ap.av.getGapCharacter()),\r
-              sg.getSequencesAsArray(ap.av.hiddenRepSequences),\r
-              sg.getStartRes(), sg.getEndRes() + 1, ap.av.alignment\r
-              );\r
-\r
-          ap.alignFrame.addHistoryItem(editCommand);\r
-\r
-          ap.av.firePropertyChange("alignment", null,\r
-                                   ap.av.getAlignment().getSequences());\r
-        }\r
-      }\r
-  }\r
-\r
-\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+package jalview.gui;
+
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+import MCview.*;
+import jalview.analysis.*;
+import jalview.commands.*;
+import jalview.datamodel.*;
+import jalview.io.*;
+import jalview.schemes.*;
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class PopupMenu
+    extends JPopupMenu
+{
+  JMenu groupMenu = new JMenu();
+  JMenuItem groupName = new JMenuItem();
+  protected JRadioButtonMenuItem clustalColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem zappoColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem taylorColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem hydrophobicityColour = new
+      JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem helixColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem strandColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem turnColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem buriedColour = new JRadioButtonMenuItem();
+  protected JCheckBoxMenuItem abovePIDColour = new JCheckBoxMenuItem();
+  protected JRadioButtonMenuItem userDefinedColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem PIDColour = new JRadioButtonMenuItem();
+  protected JRadioButtonMenuItem BLOSUM62Colour = new JRadioButtonMenuItem();
+  JRadioButtonMenuItem noColourmenuItem = new JRadioButtonMenuItem();
+  protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem();
+  AlignmentPanel ap;
+  JMenu sequenceMenu = new JMenu();
+  JMenuItem sequenceName = new JMenuItem();
+  Sequence sequence;
+  JMenuItem unGroupMenuItem = new JMenuItem();
+  JMenuItem outline = new JMenuItem();
+  JRadioButtonMenuItem nucleotideMenuItem = new JRadioButtonMenuItem();
+  JMenu colourMenu = new JMenu();
+  JCheckBoxMenuItem showBoxes = new JCheckBoxMenuItem();
+  JCheckBoxMenuItem showText = new JCheckBoxMenuItem();
+  JCheckBoxMenuItem showColourText = new JCheckBoxMenuItem();
+  JMenu editMenu = new JMenu();
+  JMenuItem cut = new JMenuItem();
+  JMenuItem copy = new JMenuItem();
+  JMenuItem upperCase = new JMenuItem();
+  JMenuItem lowerCase = new JMenuItem();
+  JMenuItem toggle = new JMenuItem();
+  JMenu pdbMenu = new JMenu();
+  JMenuItem pdbFromFile = new JMenuItem();
+  JMenuItem enterPDB = new JMenuItem();
+  JMenuItem discoverPDB = new JMenuItem();
+  JMenu outputMenu = new JMenu();
+  JMenuItem sequenceFeature = new JMenuItem();
+  JMenuItem textColour = new JMenuItem();
+  JMenu jMenu1 = new JMenu();
+  JMenu structureMenu = new JMenu();
+  JMenu viewStructureMenu = new JMenu();
+ // JMenu colStructureMenu = new JMenu();
+  JMenuItem editSequence = new JMenuItem();
+ // JMenuItem annotationMenuItem = new JMenuItem();
+
+  /**
+   * Creates a new PopupMenu object.
+   *
+   * @param ap DOCUMENT ME!
+   * @param seq DOCUMENT ME!
+   */
+  public PopupMenu(final AlignmentPanel ap, Sequence seq, Vector links)
+  {
+    ///////////////////////////////////////////////////////////
+    // If this is activated from the sequence panel, the user may want to
+    // edit or annotate a particular residue. Therefore display the residue menu
+    //
+    // If from the IDPanel, we must display the sequence menu
+    //////////////////////////////////////////////////////////
+    this.ap = ap;
+    sequence = seq;
+
+    ButtonGroup colours = new ButtonGroup();
+    colours.add(noColourmenuItem);
+    colours.add(clustalColour);
+    colours.add(zappoColour);
+    colours.add(taylorColour);
+    colours.add(hydrophobicityColour);
+    colours.add(helixColour);
+    colours.add(strandColour);
+    colours.add(turnColour);
+    colours.add(buriedColour);
+    colours.add(abovePIDColour);
+    colours.add(userDefinedColour);
+    colours.add(PIDColour);
+    colours.add(BLOSUM62Colour);
+
+    for (int i = 0; i < jalview.io.FormatAdapter.WRITEABLE_FORMATS.length; i++)
+    {
+      JMenuItem item = new JMenuItem(jalview.io.FormatAdapter.WRITEABLE_FORMATS[
+                                     i]);
+
+      item.addActionListener(new java.awt.event.ActionListener()
+      {
+        public void actionPerformed(ActionEvent e)
+        {
+          outputText_actionPerformed(e);
+        }
+      });
+
+      outputMenu.add(item);
+    }
+
+    try
+    {
+      jbInit();
+    }
+    catch (Exception e)
+    {
+      e.printStackTrace();
+    }
+
+    if (seq != null)
+    {
+      sequenceMenu.setText(sequence.getName());
+
+      JMenuItem menuItem;
+      if (seq.getDatasetSequence().getPDBId() != null
+          && seq.getDatasetSequence().getPDBId().size()>0)
+      {
+        java.util.Enumeration e = seq.getDatasetSequence().getPDBId().
+            elements();
+
+        while (e.hasMoreElements())
+        {
+          final PDBEntry pdb = (PDBEntry) e.nextElement();
+
+          menuItem = new JMenuItem();
+          menuItem.setText(pdb.getId());
+          menuItem.addActionListener(new java.awt.event.ActionListener()
+          {
+            public void actionPerformed(ActionEvent e)
+            {
+              Vector seqs = new Vector();
+              for (int i = 0; i < ap.av.alignment.getHeight(); i++)
+              {
+                Vector pdbs = ap.av.alignment.getSequenceAt(i).getDatasetSequence().getPDBId();
+                if(pdbs==null)
+                  continue;
+
+                for(int p=0; p<pdbs.size(); p++)
+                {
+                  PDBEntry p1 = (PDBEntry)pdbs.elementAt(p);
+                  if(p1.getId().equals(pdb.getId()))
+                  {
+                    if (!seqs.contains(ap.av.alignment.getSequenceAt(i)))
+                        seqs.addElement(ap.av.alignment.getSequenceAt(i));
+
+                      continue;
+                  }
+                }
+              }
+
+              SequenceI [] seqs2 = new SequenceI[seqs.size()];
+              seqs.toArray(seqs2);
+
+              new AppJmol(pdb, seqs2, null, ap);
+              //  new PDBViewer(pdb, seqs2, null, ap, AppletFormatAdapter.FILE);
+            }
+          });
+          viewStructureMenu.add(menuItem);
+
+       /*   menuItem = new JMenuItem();
+          menuItem.setText(pdb.getId());
+          menuItem.addActionListener(new java.awt.event.ActionListener()
+          {
+            public void actionPerformed(ActionEvent e)
+            {
+              colourByStructure(pdb.getId());
+            }
+          });
+          colStructureMenu.add(menuItem);*/
+        }
+      }
+      else
+      {
+        structureMenu.remove(viewStructureMenu);
+       // structureMenu.remove(colStructureMenu);
+      }
+
+      menuItem = new JMenuItem("Hide Sequences");
+      menuItem.addActionListener(new java.awt.event.ActionListener()
+      {
+        public void actionPerformed(ActionEvent e)
+        {
+          hideSequences(false);
+        }
+      });
+      add(menuItem);
+
+      if (ap.av.getSelectionGroup() != null
+          && ap.av.getSelectionGroup().getSize() > 1)
+      {
+        menuItem = new JMenuItem("Represent Group with " + seq.getName());
+        menuItem.addActionListener(new java.awt.event.ActionListener()
+        {
+          public void actionPerformed(ActionEvent e)
+          {
+            hideSequences(true);
+          }
+        });
+        sequenceMenu.add(menuItem);
+      }
+
+      if (ap.av.hasHiddenRows)
+      {
+        final int index = ap.av.alignment.findIndex(seq);
+
+        if (ap.av.adjustForHiddenSeqs(index) -
+            ap.av.adjustForHiddenSeqs(index - 1) > 1)
+        {
+          menuItem = new JMenuItem("Reveal Sequences");
+          menuItem.addActionListener(new ActionListener()
+          {
+            public void actionPerformed(ActionEvent e)
+            {
+              ap.av.showSequence(index);
+              if (ap.overviewPanel != null)
+              {
+                ap.overviewPanel.updateOverviewImage();
+              }
+            }
+          });
+          add(menuItem);
+        }
+
+        menuItem = new JMenuItem("Reveal All");
+        menuItem.addActionListener(new ActionListener()
+        {
+          public void actionPerformed(ActionEvent e)
+          {
+            ap.av.showAllHiddenSeqs();
+            if (ap.overviewPanel != null)
+            {
+              ap.overviewPanel.updateOverviewImage();
+            }
+          }
+        });
+
+        add(menuItem);
+      }
+
+    }
+
+    SequenceGroup sg = ap.av.getSelectionGroup();
+
+    if (sg != null)
+    {
+      groupName.setText(sg.getName());
+
+      if (sg.cs instanceof ZappoColourScheme)
+      {
+        zappoColour.setSelected(true);
+      }
+      else if (sg.cs instanceof TaylorColourScheme)
+      {
+        taylorColour.setSelected(true);
+      }
+      else if (sg.cs instanceof PIDColourScheme)
+      {
+        PIDColour.setSelected(true);
+      }
+      else if (sg.cs instanceof Blosum62ColourScheme)
+      {
+        BLOSUM62Colour.setSelected(true);
+      }
+      else if (sg.cs instanceof UserColourScheme)
+      {
+        userDefinedColour.setSelected(true);
+      }
+      else if (sg.cs instanceof HydrophobicColourScheme)
+      {
+        hydrophobicityColour.setSelected(true);
+      }
+      else if (sg.cs instanceof HelixColourScheme)
+      {
+        helixColour.setSelected(true);
+      }
+      else if (sg.cs instanceof StrandColourScheme)
+      {
+        strandColour.setSelected(true);
+      }
+      else if (sg.cs instanceof TurnColourScheme)
+      {
+        turnColour.setSelected(true);
+      }
+      else if (sg.cs instanceof BuriedColourScheme)
+      {
+        buriedColour.setSelected(true);
+      }
+      else if (sg.cs instanceof ClustalxColourScheme)
+      {
+        clustalColour.setSelected(true);
+      }
+      else
+      {
+        noColourmenuItem.setSelected(true);
+      }
+
+      if (sg.cs != null && sg.cs.conservationApplied())
+      {
+        conservationMenuItem.setSelected(true);
+      }
+
+      showText.setSelected(sg.getDisplayText());
+      showColourText.setSelected(sg.getColourText());
+      showBoxes.setSelected(sg.getDisplayBoxes());
+    }
+    else
+    {
+      groupMenu.setVisible(false);
+      editMenu.setVisible(false);
+    }
+
+    if (!ap.av.alignment.getGroups().contains(sg))
+    {
+      unGroupMenuItem.setVisible(false);
+    }
+
+    if (seq == null)
+    {
+      sequenceMenu.setVisible(false);
+      structureMenu.setVisible(false);
+    }
+
+    if (links != null && links.size() > 0)
+    {
+      JMenu linkMenu = new JMenu("Link");
+      JMenuItem item;
+      for (int i = 0; i < links.size(); i++)
+      {
+        String link = links.elementAt(i).toString();
+        final String label = link.substring(0, link.indexOf("|"));
+        item = new JMenuItem(label);
+        final String url;
+
+        if (link.indexOf("$SEQUENCE_ID$") > -1)
+        {
+          String id = seq.getName();
+          if (id.indexOf("|") > -1)
+          {
+            id = id.substring(id.lastIndexOf("|") + 1);
+          }
+
+          url = link.substring(link.indexOf("|") + 1,
+                               link.indexOf("$SEQUENCE_ID$"))
+              + id +
+              link.substring(link.indexOf("$SEQUENCE_ID$") + 13);
+        }
+        else
+        {
+          url = link.substring(link.lastIndexOf("|") + 1);
+        }
+
+        item.addActionListener(new java.awt.event.ActionListener()
+        {
+          public void actionPerformed(ActionEvent e)
+          {
+            showLink(url);
+          }
+        });
+
+        linkMenu.add(item);
+      }
+      if (sequence != null)
+      {
+        sequenceMenu.add(linkMenu);
+      }
+      else
+      {
+        add(linkMenu);
+      }
+    }
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @throws Exception DOCUMENT ME!
+   */
+  private void jbInit()
+      throws Exception
+  {
+    groupMenu.setText("Group");
+    groupMenu.setText("Selection");
+    groupName.setText("Name");
+    groupName.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        groupName_actionPerformed();
+      }
+    });
+    sequenceMenu.setText("Sequence");
+    sequenceName.setText("Edit Name/Description");
+    sequenceName.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        sequenceName_actionPerformed();
+      }
+    });
+    PIDColour.setFocusPainted(false);
+    unGroupMenuItem.setText("Remove Group");
+    unGroupMenuItem.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        unGroupMenuItem_actionPerformed();
+      }
+    });
+
+    outline.setText("Border colour");
+    outline.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        outline_actionPerformed();
+      }
+    });
+    nucleotideMenuItem.setText("Nucleotide");
+    nucleotideMenuItem.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        nucleotideMenuItem_actionPerformed();
+      }
+    });
+    colourMenu.setText("Group Colour");
+    showBoxes.setText("Boxes");
+    showBoxes.setState(true);
+    showBoxes.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        showBoxes_actionPerformed();
+      }
+    });
+    showText.setText("Text");
+    showText.setState(true);
+    showText.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        showText_actionPerformed();
+      }
+    });
+    showColourText.setText("Colour Text");
+    showColourText.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        showColourText_actionPerformed();
+      }
+    });
+    editMenu.setText("Edit");
+    cut.setText("Cut");
+    cut.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        cut_actionPerformed();
+      }
+    });
+    upperCase.setText("To Upper Case");
+    upperCase.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        changeCase(e);
+      }
+    });
+    copy.setText("Copy");
+    copy.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        copy_actionPerformed();
+      }
+    });
+    lowerCase.setText("To Lower Case");
+    lowerCase.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        changeCase(e);
+      }
+    });
+    toggle.setText("Toggle Case");
+    toggle.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        changeCase(e);
+      }
+    });
+    pdbMenu.setText("Associate Structure with Sequence");
+    pdbFromFile.setText("From File");
+    pdbFromFile.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        pdbFromFile_actionPerformed();
+      }
+    });
+    enterPDB.setText("Enter PDB Id");
+    enterPDB.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        enterPDB_actionPerformed();
+      }
+    });
+    discoverPDB.setText("Discover PDB ids");
+    discoverPDB.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        discoverPDB_actionPerformed();
+      }
+    });
+    outputMenu.setText("Output to Textbox...");
+    sequenceFeature.setText("Create Sequence Feature");
+    sequenceFeature.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        sequenceFeature_actionPerformed();
+      }
+    });
+    textColour.setText("Text Colour");
+    textColour.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        textColour_actionPerformed();
+      }
+    });
+    jMenu1.setText("Group");
+    structureMenu.setText("Structure");
+    viewStructureMenu.setText("View Structure");
+  //  colStructureMenu.setText("Colour By Structure");
+    editSequence.setText("Edit Sequence...");
+    editSequence.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent actionEvent)
+      {
+        editSequence_actionPerformed(actionEvent);
+      }
+    });
+   /* annotationMenuItem.setText("By Annotation");
+    annotationMenuItem.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent actionEvent)
+      {
+        annotationMenuItem_actionPerformed(actionEvent);
+      }
+    });*/
+
+    add(groupMenu);
+
+    add(sequenceMenu);
+    this.add(structureMenu);
+    groupMenu.add(editMenu);
+    groupMenu.add(outputMenu);
+    groupMenu.add(sequenceFeature);
+    groupMenu.add(jMenu1);
+    sequenceMenu.add(sequenceName);
+    colourMenu.add(textColour);
+    colourMenu.add(noColourmenuItem);
+    colourMenu.add(clustalColour);
+    colourMenu.add(BLOSUM62Colour);
+    colourMenu.add(PIDColour);
+    colourMenu.add(zappoColour);
+    colourMenu.add(taylorColour);
+    colourMenu.add(hydrophobicityColour);
+    colourMenu.add(helixColour);
+    colourMenu.add(strandColour);
+    colourMenu.add(turnColour);
+    colourMenu.add(buriedColour);
+    colourMenu.add(nucleotideMenuItem);
+    colourMenu.add(userDefinedColour);
+
+    if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
+    {
+      java.util.Enumeration userColours = jalview.gui.UserDefinedColours.
+          getUserColourSchemes().keys();
+
+      while (userColours.hasMoreElements())
+      {
+        JMenuItem item = new JMenuItem(userColours.
+                                       nextElement().toString());
+        item.addActionListener(new ActionListener()
+        {
+          public void actionPerformed(ActionEvent evt)
+          {
+            userDefinedColour_actionPerformed(evt);
+          }
+        });
+        colourMenu.add(item);
+      }
+    }
+
+    colourMenu.addSeparator();
+    colourMenu.add(abovePIDColour);
+    colourMenu.add(conservationMenuItem);
+    //colourMenu.add(annotationMenuItem);
+    editMenu.add(copy);
+    editMenu.add(cut);
+    editMenu.add(editSequence);
+    editMenu.add(upperCase);
+    editMenu.add(lowerCase);
+    editMenu.add(toggle);
+    pdbMenu.add(pdbFromFile);
+    pdbMenu.add(enterPDB);
+    pdbMenu.add(discoverPDB);
+    jMenu1.add(groupName);
+    jMenu1.add(unGroupMenuItem);
+    jMenu1.add(colourMenu);
+    jMenu1.add(showBoxes);
+    jMenu1.add(showText);
+    jMenu1.add(showColourText);
+    jMenu1.add(outline);
+    structureMenu.add(pdbMenu);
+    structureMenu.add(viewStructureMenu);
+   // structureMenu.add(colStructureMenu);
+    noColourmenuItem.setText("None");
+    noColourmenuItem.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        noColourmenuItem_actionPerformed();
+      }
+    });
+
+    clustalColour.setText("Clustalx colours");
+    clustalColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        clustalColour_actionPerformed();
+      }
+    });
+    zappoColour.setText("Zappo");
+    zappoColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        zappoColour_actionPerformed();
+      }
+    });
+    taylorColour.setText("Taylor");
+    taylorColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        taylorColour_actionPerformed();
+      }
+    });
+    hydrophobicityColour.setText("Hydrophobicity");
+    hydrophobicityColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        hydrophobicityColour_actionPerformed();
+      }
+    });
+    helixColour.setText("Helix propensity");
+    helixColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        helixColour_actionPerformed();
+      }
+    });
+    strandColour.setText("Strand propensity");
+    strandColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        strandColour_actionPerformed();
+      }
+    });
+    turnColour.setText("Turn propensity");
+    turnColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        turnColour_actionPerformed();
+      }
+    });
+    buriedColour.setText("Buried Index");
+    buriedColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        buriedColour_actionPerformed();
+      }
+    });
+    abovePIDColour.setText("Above % Identity");
+    abovePIDColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        abovePIDColour_actionPerformed();
+      }
+    });
+    userDefinedColour.setText("User Defined...");
+    userDefinedColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        userDefinedColour_actionPerformed(e);
+      }
+    });
+    PIDColour.setText("Percentage Identity");
+    PIDColour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        PIDColour_actionPerformed();
+      }
+    });
+    BLOSUM62Colour.setText("BLOSUM62");
+    BLOSUM62Colour.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        BLOSUM62Colour_actionPerformed();
+      }
+    });
+    conservationMenuItem.setText("Conservation");
+    conservationMenuItem.addActionListener(new java.awt.event.ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        conservationMenuItem_actionPerformed();
+      }
+    });
+  }
+
+  /**
+   * DOCUMENT ME!
+   */
+  void refresh()
+  {
+    ap.paintAlignment(true);
+
+    PaintRefresher.Refresh(this, ap.av.getSequenceSetId());
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void clustalColour_actionPerformed()
+  {
+    SequenceGroup sg = getGroup();
+    sg.cs = new ClustalxColourScheme(sg.getSequences(ap.av.hiddenRepSequences),
+                                     ap.av.alignment.getWidth());
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void zappoColour_actionPerformed()
+  {
+    getGroup().cs = new ZappoColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void taylorColour_actionPerformed()
+  {
+    getGroup().cs = new TaylorColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void hydrophobicityColour_actionPerformed()
+  {
+    getGroup().cs = new HydrophobicColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void helixColour_actionPerformed()
+  {
+    getGroup().cs = new HelixColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void strandColour_actionPerformed()
+  {
+    getGroup().cs = new StrandColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void turnColour_actionPerformed()
+  {
+    getGroup().cs = new TurnColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void buriedColour_actionPerformed()
+  {
+    getGroup().cs = new BuriedColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void nucleotideMenuItem_actionPerformed()
+  {
+    getGroup().cs = new NucleotideColourScheme();
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void abovePIDColour_actionPerformed()
+  {
+    SequenceGroup sg = getGroup();
+    if (sg.cs == null)
+    {
+      return;
+    }
+
+    if (abovePIDColour.isSelected())
+    {
+      sg.cs.setConsensus(AAFrequency.calculate(
+          sg.getSequences(ap.av.hiddenRepSequences), sg.getStartRes(),
+          sg.getEndRes() + 1));
+
+      int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs,
+          getGroup().getName());
+
+      sg.cs.setThreshold(threshold, ap.av.getIgnoreGapsConsensus());
+
+      SliderPanel.showPIDSlider();
+    }
+    else // remove PIDColouring
+    {
+      sg.cs.setThreshold(0, ap.av.getIgnoreGapsConsensus());
+    }
+
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void userDefinedColour_actionPerformed(ActionEvent e)
+  {
+    SequenceGroup sg = getGroup();
+
+    if (e.getActionCommand().equals("User Defined..."))
+    {
+      new UserDefinedColours(ap, sg);
+    }
+    else
+    {
+      UserColourScheme udc = (UserColourScheme) UserDefinedColours.
+          getUserColourSchemes().get(e.getActionCommand());
+
+      sg.cs = udc;
+    }
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void PIDColour_actionPerformed()
+  {
+    SequenceGroup sg = getGroup();
+    sg.cs = new PIDColourScheme();
+    sg.cs.setConsensus(AAFrequency.calculate(sg.getSequences(ap.av.
+        hiddenRepSequences),
+                                             sg.getStartRes(),
+                                             sg.getEndRes() + 1));
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void BLOSUM62Colour_actionPerformed()
+  {
+    SequenceGroup sg = getGroup();
+
+    sg.cs = new Blosum62ColourScheme();
+
+    sg.cs.setConsensus(AAFrequency.calculate(sg.getSequences(ap.av.
+        hiddenRepSequences),
+                                             sg.getStartRes(),
+                                             sg.getEndRes() + 1));
+
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void noColourmenuItem_actionPerformed()
+  {
+    getGroup().cs = null;
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void conservationMenuItem_actionPerformed()
+  {
+    SequenceGroup sg = getGroup();
+    if (sg.cs == null)
+    {
+      return;
+    }
+
+    if (conservationMenuItem.isSelected())
+    {
+      Conservation c = new Conservation("Group",
+                                        ResidueProperties.propHash, 3,
+                                        sg.getSequences(ap.av.
+          hiddenRepSequences),
+                                        sg.getStartRes(),
+                                        sg.getEndRes() + 1);
+
+      c.calculate();
+      c.verdict(false, ap.av.ConsPercGaps);
+
+      sg.cs.setConservation(c);
+
+      SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
+      SliderPanel.showConservationSlider();
+    }
+    else // remove ConservationColouring
+    {
+      sg.cs.setConservation(null);
+    }
+
+    refresh();
+  }
+
+  public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)
+  {
+    SequenceGroup sg = getGroup();
+    if (sg == null)
+    {
+      return;
+    }
+
+    AnnotationColourGradient acg = new AnnotationColourGradient(
+        sequence.getAnnotation()[0], null, AnnotationColourGradient.NO_THRESHOLD);
+
+    acg.predefinedColours = true;
+    sg.cs = acg;
+
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void groupName_actionPerformed()
+  {
+
+    SequenceGroup sg = getGroup();
+    EditNameDialog dialog = new EditNameDialog(sg.getName(),
+                                               sg.getDescription(),
+                                               "       Group Name ",
+                                               "Group Description ",
+                                               "Edit Group Name/Description");
+
+    if (!dialog.accept)
+    {
+      return;
+    }
+
+    sg.setName(dialog.getName());
+    sg.setDescription(dialog.getDescription());
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @return DOCUMENT ME!
+   */
+  SequenceGroup getGroup()
+  {
+    SequenceGroup sg = ap.av.getSelectionGroup();
+    // this method won't add a new group if it already exists
+    if (sg != null)
+    {
+      ap.av.alignment.addGroup(sg);
+    }
+
+    return sg;
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  void sequenceName_actionPerformed()
+  {
+    EditNameDialog dialog = new EditNameDialog(sequence.getName(),
+                                               sequence.getDescription(),
+                                               "       Sequence Name ",
+                                               "Sequence Description ",
+                                               "Edit Sequence Name/Description");
+
+    if (!dialog.accept)
+    {
+      return;
+    }
+
+    if (dialog.getName() != null)
+    {
+      if (dialog.getName().indexOf(" ") > -1)
+      {
+        JOptionPane.showMessageDialog(ap,
+                                      "Spaces have been converted to \"_\"",
+                                      "No spaces allowed in Sequence Name",
+                                      JOptionPane.WARNING_MESSAGE);
+      }
+
+      sequence.setName(dialog.getName().replace(' ', '_'));
+      ap.paintAlignment(false);
+    }
+
+    sequence.setDescription(dialog.getDescription());
+
+    ap.av.firePropertyChange("alignment", null,
+                             ap.av.getAlignment().getSequences());
+
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  void unGroupMenuItem_actionPerformed()
+  {
+    SequenceGroup sg = ap.av.getSelectionGroup();
+    ap.av.alignment.deleteGroup(sg);
+    ap.av.setSelectionGroup(null);
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  protected void outline_actionPerformed()
+  {
+    SequenceGroup sg = getGroup();
+    Color col = JColorChooser.showDialog(this, "Select Outline Colour",
+                                         Color.BLUE);
+
+    if (col != null)
+    {
+      sg.setOutlineColour(col);
+    }
+
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void showBoxes_actionPerformed()
+  {
+    getGroup().setDisplayBoxes(showBoxes.isSelected());
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void showText_actionPerformed()
+  {
+    getGroup().setDisplayText(showText.isSelected());
+    refresh();
+  }
+
+  /**
+   * DOCUMENT ME!
+   *
+   * @param e DOCUMENT ME!
+   */
+  public void showColourText_actionPerformed()
+  {
+    getGroup().setColourText(showColourText.isSelected());
+    refresh();
+  }
+
+  public void showLink(String url)
+  {
+    try
+    {
+      jalview.util.BrowserLauncher.openURL(url);
+    }
+    catch (Exception ex)
+    {
+      JOptionPane.showInternalMessageDialog(Desktop.desktop,
+                                            "Unixers: Couldn't find default web browser."
+                                            +
+          "\nAdd the full path to your browser in Preferences.",
+                                            "Web browser not found",
+                                            JOptionPane.WARNING_MESSAGE);
+
+      ex.printStackTrace();
+    }
+  }
+
+  void hideSequences(boolean representGroup)
+  {
+    SequenceGroup sg = ap.av.getSelectionGroup();
+    if (sg == null || sg.getSize() < 1)
+    {
+      ap.av.hideSequence(new SequenceI[]
+                         {sequence});
+      return;
+    }
+
+    ap.av.setSelectionGroup(null);
+
+    if (representGroup)
+    {
+      ap.av.hideRepSequences(sequence, sg);
+
+      return;
+    }
+
+    int gsize = sg.getSize();
+    SequenceI[] hseqs;
+
+    hseqs = new SequenceI[gsize];
+
+    int index = 0;
+    for (int i = 0; i < gsize; i++)
+    {
+      hseqs[index++] = sg.getSequenceAt(i);
+    }
+
+    ap.av.hideSequence(hseqs);
+  }
+
+  public void copy_actionPerformed()
+  {
+    ap.alignFrame.copy_actionPerformed(null);
+  }
+
+  public void cut_actionPerformed()
+  {
+    ap.alignFrame.cut_actionPerformed(null);
+  }
+
+  void changeCase(ActionEvent e)
+  {
+    Object source = e.getSource();
+    SequenceGroup sg = ap.av.getSelectionGroup();
+
+    if (sg != null)
+    {
+      int[][] startEnd = ap.av.getVisibleRegionBoundaries(
+          sg.getStartRes(), sg.getEndRes() + 1);
+
+      String description;
+      int caseChange;
+
+      if (source == toggle)
+      {
+        description = "Toggle Case";
+        caseChange = ChangeCaseCommand.TOGGLE_CASE;
+      }
+      else if (source == upperCase)
+      {
+        description = "To Upper Case";
+        caseChange = ChangeCaseCommand.TO_UPPER;
+      }
+      else
+      {
+        description = "To Lower Case";
+        caseChange = ChangeCaseCommand.TO_LOWER;
+      }
+
+      ChangeCaseCommand caseCommand = new ChangeCaseCommand(
+          description, sg.getSequencesAsArray(ap.av.hiddenRepSequences),
+          startEnd, caseChange
+          );
+
+      ap.alignFrame.addHistoryItem(caseCommand);
+
+      ap.av.firePropertyChange("alignment", null,
+                               ap.av.getAlignment().getSequences());
+
+    }
+  }
+
+  public void outputText_actionPerformed(ActionEvent e)
+  {
+    CutAndPasteTransfer cap = new CutAndPasteTransfer();
+    cap.setForInput(null);
+    Desktop.addInternalFrame(cap,
+                             "Alignment output - " + e.getActionCommand(), 600,
+                             500);
+
+    String[] omitHidden = null;
+
+    if (ap.av.hasHiddenColumns)
+    {
+      System.out.println("PROMPT USER HERE");
+      omitHidden = ap.av.getViewAsString(true);
+    }
+
+    cap.setText(new FormatAdapter().formatSequences(
+        e.getActionCommand(),
+        ap.av.getSelectionAsNewSequence(),
+        omitHidden));
+  }
+
+  public void pdbFromFile_actionPerformed()
+  {
+    jalview.io.JalviewFileChooser chooser
+        = new jalview.io.JalviewFileChooser(jalview.bin.Cache.
+                                            getProperty(
+                                                "LAST_DIRECTORY"));
+    chooser.setFileView(new jalview.io.JalviewFileView());
+    chooser.setDialogTitle("Select a PDB file");
+    chooser.setToolTipText("Load a PDB file");
+
+    int value = chooser.showOpenDialog(null);
+
+    if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
+    {
+      PDBEntry entry = new PDBEntry();
+      String choice = chooser.getSelectedFile().getPath();
+      jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
+      try
+      {
+        MCview.PDBfile pdbfile = new MCview.PDBfile(choice,
+            jalview.io.AppletFormatAdapter.FILE);
+
+        if (pdbfile.id == null)
+        {
+          String reply = JOptionPane.showInternalInputDialog(
+              Desktop.desktop,
+              "Couldn't find a PDB id in the file supplied."
+              + "Please enter an Id to identify this structure.",
+              "No PDB Id in File", JOptionPane.QUESTION_MESSAGE);
+          if (reply == null)
+          {
+            return;
+          }
+
+          entry.setId(reply);
+        }
+        else
+        {
+          entry.setId(pdbfile.id);
+        }
+      }
+      catch (java.io.IOException ex)
+      {
+        ex.printStackTrace();
+      }
+
+      entry.setFile(choice);
+      sequence.getDatasetSequence().addPDBId(entry);
+    }
+
+  }
+
+  public void enterPDB_actionPerformed()
+  {
+    String id = JOptionPane.showInternalInputDialog(Desktop.desktop,
+        "Enter PDB Id", "Enter PDB Id", JOptionPane.QUESTION_MESSAGE);
+
+    if (id != null && id.length() > 0)
+    {
+      PDBEntry entry = new PDBEntry();
+      entry.setId(id.toUpperCase());
+      sequence.getDatasetSequence()
+          .addPDBId(entry);
+    }
+  }
+
+  public void discoverPDB_actionPerformed()
+  {
+    SequenceI[] sequences =
+         ap.av.selectionGroup == null ?
+           new Sequence[]{sequence}
+         : ap.av.selectionGroup.getSequencesInOrder(ap.av.alignment);
+
+    new jalview.ws.DBRefFetcher(sequences,
+        ap.alignFrame).fetchDBRefs(false);
+  }
+
+  public void sequenceFeature_actionPerformed()
+  {
+    SequenceGroup sg = ap.av.getSelectionGroup();
+    if (sg == null)
+    {
+      return;
+    }
+
+    int gSize = sg.getSize();
+    SequenceI[] seqs = new SequenceI[gSize];
+    SequenceFeature[] features = new SequenceFeature[gSize];
+
+    for (int i = 0; i < gSize; i++)
+    {
+      seqs[i] = sg.getSequenceAt(i).getDatasetSequence();
+      int start = sg.getSequenceAt(i).findPosition(sg.getStartRes());
+      int end = sg.findEndRes(sg.getSequenceAt(i));
+      features[i] = new SequenceFeature(null, null, null, start, end, "Jalview");
+    }
+
+    if (ap.seqPanel.seqCanvas.getFeatureRenderer()
+        .amendFeatures(seqs, features, true, ap))
+    {
+      ap.alignFrame.showSeqFeatures.setSelected(true);
+      ap.av.setShowSequenceFeatures(true);
+      ap.highlightSearchResults(null);
+    }
+  }
+
+  public void textColour_actionPerformed()
+  {
+    SequenceGroup sg = getGroup();
+    if (sg != null)
+    {
+      new TextColourChooser().chooseColour(ap, sg);
+    }
+  }
+
+  public void colourByStructure(String pdbid)
+  {
+    Annotation [] anots = jalview.structure.StructureSelectionManager.getStructureSelectionManager()
+        .colourSequenceFromStructure(sequence, pdbid);
+
+    AlignmentAnnotation an = new AlignmentAnnotation(
+      "Structure", "Coloured by "+pdbid, anots);
+
+    ap.av.alignment.addAnnotation(an);
+    an.createSequenceMapping(sequence, 0, true);
+    //an.adjustForAlignment();
+    ap.av.alignment.setAnnotationIndex(an,0);
+
+    ap.adjustAnnotationHeight();
+
+    sequence.addAlignmentAnnotation(an);
+
+    }
+
+  public void editSequence_actionPerformed(ActionEvent actionEvent)
+  {
+      SequenceGroup sg = ap.av.getSelectionGroup();
+
+      if(sg!=null)
+      {
+        if (sequence == null)
+          sequence = (Sequence) sg.getSequenceAt(0);
+
+        EditNameDialog dialog = new EditNameDialog(
+            sequence.getSequenceAsString(
+                sg.getStartRes(),
+                sg.getEndRes() + 1),
+            null,
+            "Edit Sequence ",
+            null,
+            "Edit Sequence");
+
+        if (dialog.accept)
+        {
+          EditCommand editCommand = new EditCommand(
+              "Edit Sequences", EditCommand.REPLACE,
+              dialog.getName().replace(' ', ap.av.getGapCharacter()),
+              sg.getSequencesAsArray(ap.av.hiddenRepSequences),
+              sg.getStartRes(), sg.getEndRes() + 1, ap.av.alignment
+              );
+
+          ap.alignFrame.addHistoryItem(editCommand);
+
+          ap.av.firePropertyChange("alignment", null,
+                                   ap.av.getAlignment().getSequences());
+        }
+      }
+  }
+
+
+}
index dc326de..7d451da 100755 (executable)
@@ -572,14 +572,14 @@ public class SeqPanel
   }
 
   String lastMessage;
-  public void mouseOverSequence(SequenceI sequence, int index)
+  public void mouseOverSequence(SequenceI sequence, int index, int pos)
   {
-    String tmp = sequence.hashCode()+" "+index+"";
+    String tmp = sequence.hashCode()+" "+index+" "+pos;
     
     if (lastMessage == null || !lastMessage.equals(tmp))
     {
       // System.err.println("mouseOver Sequence: "+tmp);
-      ssm.mouseOverSequence(sequence, index);
+      ssm.mouseOverSequence(sequence, index, pos);
     }
     lastMessage = tmp;
   }
@@ -627,7 +627,7 @@ public class SeqPanel
 
     pos = setStatusMessage(sequence, res, seq);
     if (ssm != null && pos>-1)
-      mouseOverSequence(sequence, pos);
+      mouseOverSequence(sequence, res, pos);
 
 
     tooltipText.setLength(6); // Cuts the buffer back to <html>
index 989227b..10e1b59 100755 (executable)
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2007 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.gui;\r
-\r
-import java.io.*;\r
-import java.util.*;\r
-\r
-import java.awt.*;\r
-import java.awt.event.*;\r
-import javax.swing.*;\r
-\r
-import MCview.*;\r
-import jalview.datamodel.*;\r
-import jalview.datamodel.xdb.embl.*;\r
-import java.io.File;\r
-import jalview.io.*;\r
-import java.awt.Rectangle;\r
-import java.awt.BorderLayout;\r
-import java.awt.Dimension;\r
-\r
-public class SequenceFetcher\r
-extends JPanel implements Runnable\r
-{\r
-  JInternalFrame frame;\r
-  AlignFrame alignFrame;\r
-  StringBuffer result;\r
-  final String noDbSelected = "-- Select Database --";\r
-  public SequenceFetcher(AlignFrame af)\r
-  {\r
-    alignFrame = af;\r
-    database.addItem(noDbSelected);\r
-    database.addItem("Uniprot");\r
-    database.addItem("EMBL");\r
-    database.addItem("EMBLCDS");\r
-    database.addItem("PDB");\r
-    database.addItem("PFAM");\r
-\r
-    try\r
-    {\r
-      jbInit();\r
-    }\r
-    catch (Exception ex)\r
-    {\r
-      ex.printStackTrace();\r
-    }\r
-\r
-    frame = new JInternalFrame();\r
-    frame.setContentPane(this);\r
-    if (System.getProperty("os.name").startsWith("Mac"))\r
-    {\r
-      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 140);\r
-    }\r
-    else\r
-    {\r
-      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 125);\r
-    }\r
-  }\r
-\r
-  private String getFrameTitle()\r
-  {\r
-    return ( (alignFrame == null) ? "New " : "Additional ") +\r
-    "Sequence Fetcher";\r
-  }\r
-\r
-  private void jbInit()\r
-  throws Exception\r
-  {\r
-    this.setLayout(borderLayout2);\r
-\r
-    database.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
-    jLabel1.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));\r
-    jLabel1.setHorizontalAlignment(SwingConstants.CENTER);\r
-    jLabel1.setText(\r
-    "Separate multiple accession ids with semi colon \";\"");\r
-    ok.setText("OK");\r
-    ok.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        ok_actionPerformed();\r
-      }\r
-    });\r
-    close.setText("Close");\r
-    close.addActionListener(new ActionListener()\r
-    {\r
-      public void actionPerformed(ActionEvent e)\r
-      {\r
-        close_actionPerformed(e);\r
-      }\r
-    });\r
-    textArea.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));\r
-    textArea.setLineWrap(true);\r
-    textArea.addKeyListener(new KeyAdapter()\r
-    {\r
-      public void keyPressed(KeyEvent e)\r
-      {\r
-        if(e.getKeyCode()==KeyEvent.VK_ENTER)\r
-          ok_actionPerformed();\r
-      }\r
-    });\r
-    jPanel3.setLayout(borderLayout1);\r
-    borderLayout1.setVgap(5);\r
-    jPanel1.add(ok);\r
-    jPanel1.add(close);\r
-    jPanel3.add(jPanel2, java.awt.BorderLayout.WEST);\r
-    jPanel2.add(database);\r
-    jPanel3.add(jScrollPane1, java.awt.BorderLayout.CENTER);\r
-    jPanel3.add(jLabel1, java.awt.BorderLayout.NORTH);\r
-    this.add(jPanel1, java.awt.BorderLayout.SOUTH);\r
-    this.add(jPanel3, java.awt.BorderLayout.CENTER);\r
-    jScrollPane1.getViewport().add(textArea);\r
-\r
-  }\r
-\r
-  JComboBox database = new JComboBox();\r
-  JLabel jLabel1 = new JLabel();\r
-  JButton ok = new JButton();\r
-  JButton close = new JButton();\r
-  JPanel jPanel1 = new JPanel();\r
-  JTextArea textArea = new JTextArea();\r
-  JScrollPane jScrollPane1 = new JScrollPane();\r
-  JPanel jPanel2 = new JPanel();\r
-  JPanel jPanel3 = new JPanel();\r
-  BorderLayout borderLayout1 = new BorderLayout();\r
-  BorderLayout borderLayout2 = new BorderLayout();\r
-  public void close_actionPerformed(ActionEvent e)\r
-  {\r
-    try\r
-    {\r
-      frame.setClosed(true);\r
-    }\r
-    catch (Exception ex)\r
-    {}\r
-  }\r
-\r
-  public void ok_actionPerformed()\r
-  {\r
-    database.setEnabled(false);\r
-    textArea.setEnabled(false);\r
-    ok.setEnabled(false);\r
-    close.setEnabled(false);\r
-\r
-    Thread worker = new Thread(this);\r
-    worker.start();\r
-  }\r
-\r
-  private void resetDialog()\r
-  {\r
-    database.setEnabled(true);\r
-    textArea.setEnabled(true);\r
-    ok.setEnabled(true);\r
-    close.setEnabled(true);\r
-  }\r
-\r
-  public void run()\r
-  {\r
-    String error = "";\r
-    if (database.getSelectedItem().equals(noDbSelected))\r
-    {\r
-      error += "Please select the source database\n";\r
-    }\r
-    com.stevesoft.pat.Regex empty = new com.stevesoft.pat.Regex("\\s+", "");\r
-    textArea.setText(empty.replaceAll(textArea.getText()));\r
-    if (textArea.getText().length() == 0)\r
-    {\r
-      error += "Please enter a (semi-colon separated list of) database id(s)";\r
-    }\r
-    if (error.length() > 0)\r
-    {\r
-      showErrorMessage(error);\r
-      resetDialog();\r
-      return;\r
-    }\r
-\r
-    result = new StringBuffer();\r
-    if (database.getSelectedItem().equals("Uniprot"))\r
-    {\r
-      getUniprotFile(textArea.getText());\r
-    }\r
-    else if (database.getSelectedItem().equals("EMBL")\r
-        || database.getSelectedItem().equals("EMBLCDS"))\r
-    {\r
-      String DBRefSource = database.getSelectedItem().equals("EMBLCDS")\r
-      ? jalview.datamodel.DBRefSource.EMBLCDS\r
-          : jalview.datamodel.DBRefSource.EMBL;\r
-\r
-      StringTokenizer st = new StringTokenizer(textArea.getText(), ";");\r
-      SequenceI[] seqs = null;\r
-      while(st.hasMoreTokens())\r
-      {\r
-        EBIFetchClient dbFetch = new EBIFetchClient();\r
-\r
-        File reply = dbFetch.fetchDataAsFile(\r
-            database.getSelectedItem().toString().toLowerCase(\r
-            ) + ":" + st.nextToken(),\r
-            "emblxml",null);\r
-\r
-        jalview.datamodel.xdb.embl.EmblFile efile=null;\r
-        if (reply != null && reply.exists())\r
-        {\r
-          efile = jalview.datamodel.xdb.embl.EmblFile.getEmblFile(reply);\r
-        }\r
-        if (efile!=null) {\r
-          for (Iterator i=efile.getEntries().iterator(); i.hasNext(); ) {\r
-            EmblEntry entry = (EmblEntry) i.next();\r
-            SequenceI[] seqparts = entry.getSequences(false,true, DBRefSource);\r
-            if (seqparts!=null) {\r
-              SequenceI[] newseqs = null;\r
-              int si=0;\r
-              if (seqs==null) {\r
-                newseqs = new SequenceI[seqparts.length];\r
-              } else {\r
-                newseqs  = new SequenceI[seqs.length+seqparts.length];\r
-\r
-                for (;si<seqs.length; si++) {\r
-                  newseqs[si] = seqs[si];\r
-                  seqs[si] = null;\r
-                }\r
-              }\r
-              for (int j=0;j<seqparts.length; si++, j++) {\r
-                newseqs[si] = seqparts[j].deriveSequence(); // place DBReferences on dataset and refer\r
-              }\r
-              seqs=newseqs;\r
-\r
-            }\r
-          }\r
-        } else {\r
-          result=null;\r
-        }\r
-      }\r
-      if (seqs!=null && seqs.length>0) {\r
-        if (parseResult(new Alignment(seqs), null, null)!=null)\r
-          result.append("# Successfully parsed the "+database.getSelectedItem()+" Queries into an Alignment");\r
-      }\r
-    }\r
-    else if (database.getSelectedItem().equals("PDB"))\r
-    {\r
-      StringTokenizer qset = new StringTokenizer(textArea.getText(), ";");\r
-      String query;\r
-      SequenceI[] seqs = null;\r
-      while (qset.hasMoreTokens() && ((query = qset.nextToken())!=null))\r
-      {\r
-        SequenceI[] seqparts = getPDBFile(query.toUpperCase());\r
-        if (seqparts != null)\r
-        {\r
-          if (seqs == null)\r
-          {\r
-            seqs = seqparts;\r
-          }\r
-          else\r
-          {\r
-            SequenceI[] newseqs = new SequenceI[seqs.length+seqparts.length];\r
-            int i=0;\r
-            for (; i < seqs.length; i++)\r
-            {\r
-              newseqs[i] = seqs[i];\r
-              seqs[i] = null;\r
-            }\r
-            for (int j=0;j<seqparts.length; i++, j++)\r
-            {\r
-              newseqs[i] = seqparts[j];\r
-            }\r
-            seqs=newseqs;\r
-          }\r
-          result.append("# Success for "+query.toUpperCase()+"\n");\r
-        }\r
-      }\r
-      if (seqs != null && seqs.length > 0)\r
-      {\r
-        if (parseResult(new Alignment(seqs), null, null)!=null)\r
-        {\r
-          result.append(\r
-          "# Successfully parsed the PDB File Queries into an Alignment");\r
-        }\r
-      }\r
-    }\r
-    else if( database.getSelectedItem().equals("PFAM"))\r
-    {\r
-      try\r
-      {\r
-        result.append(new FastaFile(\r
-            "http://www.sanger.ac.uk/cgi-bin/Pfam/getalignment.pl?format=fal&acc="\r
-            +  textArea.getText().toUpperCase(), "URL").print()\r
-        );\r
-\r
-        if(result.length()>0)\r
-        {\r
-          parseResult( result.toString(), textArea.getText().toUpperCase() );\r
-        }\r
-\r
-      }\r
-      catch (java.io.IOException ex)\r
-      {\r
-        result = null;\r
-      }\r
-    }\r
-\r
-    if (result == null || result.length() == 0)\r
-    {\r
-      showErrorMessage("Error retrieving " + textArea.getText()\r
-          + " from " + database.getSelectedItem());\r
-    }\r
-\r
-    resetDialog();\r
-    return;\r
-  }\r
-\r
-  void getUniprotFile(String id)\r
-  {\r
-    EBIFetchClient ebi = new EBIFetchClient();\r
-    File file = ebi.fetchDataAsFile("uniprot:" + id, "xml", null);\r
-\r
-    DBRefFetcher dbref = new DBRefFetcher();\r
-    Vector entries = dbref.getUniprotEntries(file);\r
-\r
-    if (entries != null)\r
-    {\r
-      //First, make the new sequences\r
-      Enumeration en = entries.elements();\r
-      while (en.hasMoreElements())\r
-      {\r
-        UniprotEntry entry = (UniprotEntry) en.nextElement();\r
-\r
-        StringBuffer name = new StringBuffer(">UniProt/Swiss-Prot");\r
-        Enumeration en2 = entry.getAccession().elements();\r
-        while (en2.hasMoreElements())\r
-        {\r
-          name.append("|");\r
-          name.append(en2.nextElement());\r
-        }\r
-        en2 = entry.getName().elements();\r
-        while (en2.hasMoreElements())\r
-        {\r
-          name.append("|");\r
-          name.append(en2.nextElement());\r
-        }\r
-\r
-        if (entry.getProtein() != null)\r
-        {\r
-          name.append(" " + entry.getProtein().getName().elementAt(0));\r
-        }\r
-\r
-        result.append(name + "\n" + entry.getUniprotSequence().getContent() +\r
-        "\n");\r
-\r
-      }\r
-\r
-      //Then read in the features and apply them to the dataset\r
-      Alignment al = parseResult(result.toString(), null);\r
-      for (int i = 0; i < entries.size(); i++)\r
-      {\r
-        UniprotEntry entry = (UniprotEntry) entries.elementAt(i);\r
-        Enumeration e = entry.getDbReference().elements();\r
-        Vector onlyPdbEntries = new Vector();\r
-        while (e.hasMoreElements())\r
-        {\r
-          PDBEntry pdb = (PDBEntry) e.nextElement();\r
-          if (!pdb.getType().equals("PDB"))\r
-          {\r
-            continue;\r
-          }\r
-\r
-          onlyPdbEntries.addElement(pdb);\r
-        }\r
-\r
-        Enumeration en2 = entry.getAccession().elements();\r
-        while (en2.hasMoreElements())\r
-        {\r
-          al.getSequenceAt(i).getDatasetSequence().addDBRef(new DBRefEntry(\r
-              DBRefSource.UNIPROT,\r
-              "0",\r
-              en2.nextElement().toString()));\r
-        }\r
-\r
-\r
-\r
-\r
-        al.getSequenceAt(i).getDatasetSequence().setPDBId(onlyPdbEntries);\r
-        if (entry.getFeature() != null)\r
-        {\r
-          e = entry.getFeature().elements();\r
-          while (e.hasMoreElements())\r
-          {\r
-            SequenceFeature sf = (SequenceFeature) e.nextElement();\r
-            sf.setFeatureGroup("Uniprot");\r
-            al.getSequenceAt(i).getDatasetSequence().addSequenceFeature( sf );\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }\r
-\r
-  SequenceI[] getPDBFile(String id)\r
-  {\r
-    Vector result = new Vector();\r
-    String chain = null;\r
-    if (id.indexOf(":") > -1)\r
-    {\r
-      chain = id.substring(id.indexOf(":") + 1);\r
-      id = id.substring(0, id.indexOf(":"));\r
-    }\r
-\r
-    EBIFetchClient ebi = new EBIFetchClient();\r
-    String file = ebi.fetchDataAsFile("pdb:" + id, "pdb", "raw").\r
-    getAbsolutePath();\r
-    if (file == null)\r
-    {\r
-      return null;\r
-    }\r
-    try\r
-    {\r
-      PDBfile pdbfile = new PDBfile(file, jalview.io.AppletFormatAdapter.FILE);\r
-      for (int i = 0; i < pdbfile.chains.size(); i++)\r
-      {\r
-        if (chain == null ||\r
-            ( (PDBChain) pdbfile.chains.elementAt(i)).id.\r
-            toUpperCase().equals(chain))\r
-        {\r
-          PDBChain pdbchain = (PDBChain) pdbfile.chains.elementAt(i);\r
-          // Get the Chain's Sequence - who's dataset includes any special features added from the PDB file\r
-          SequenceI sq = pdbchain.sequence;\r
-          // Specially formatted name for the PDB chain sequences retrieved from the PDB\r
-          sq.setName("PDB|"+id+"|"+sq.getName());\r
-          // Might need to add more metadata to the PDBEntry object\r
-          // like below\r
-          /*\r
-           * PDBEntry entry = new PDBEntry();\r
-            // Construct the PDBEntry\r
-            entry.setId(id);\r
-            if (entry.getProperty() == null)\r
-                entry.setProperty(new Hashtable());\r
-            entry.getProperty().put("chains",\r
-                        pdbchain.id\r
-                        + "=" + sq.getStart()\r
-                        + "-" + sq.getEnd());\r
-            sq.getDatasetSequence().addPDBId(entry);\r
-           */\r
-          // Add PDB DB Refs\r
-          // We make a DBRefEtntry because we have obtained the PDB file from a verifiable source\r
-          // JBPNote - PDB DBRefEntry should also carry the chain and mapping information\r
-          DBRefEntry dbentry = new DBRefEntry(jalview.datamodel.DBRefSource.PDB,\r
-              "0", id + pdbchain.id);\r
-          sq.addDBRef(dbentry);\r
-          // and add seuqence to the retrieved set\r
-          result.addElement(sq.deriveSequence());\r
-        }\r
-      }\r
-\r
-      if (result.size() < 1)\r
-      {\r
-        throw new Exception("WsDBFetch for PDB id resulted in zero result size");\r
-      }\r
-    }\r
-    catch (Exception ex) // Problem parsing PDB file\r
-    {\r
-      jalview.bin.Cache.log.warn("Exception when retrieving " +\r
-          textArea.getText() + " from " +\r
-          database.getSelectedItem(), ex);\r
-      return null;\r
-    }\r
-\r
-\r
-    SequenceI[] results = new SequenceI[result.size()];\r
-    for (int i = 0, j = result.size(); i < j; i++)\r
-    {\r
-      results[i] = (SequenceI) result.elementAt(i);\r
-      result.setElementAt(null,i);\r
-    }\r
-    return results;\r
-  }\r
-  Alignment parseResult(String result, String title)\r
-  {\r
-    String format = new IdentifyFile().Identify(result, "Paste");\r
-    Alignment sequences = null;\r
-    if (FormatAdapter.isValidFormat(format))\r
-    {\r
-      sequences = null;\r
-      try\r
-      {\r
-        sequences = new FormatAdapter().readFile(result.toString(), "Paste",\r
-            format);\r
-      }\r
-      catch (Exception ex)\r
-      {}\r
-\r
-      if (sequences!=null)\r
-      {\r
-        return parseResult(sequences, title, format);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      showErrorMessage("Error retrieving " + textArea.getText()\r
-          + " from " + database.getSelectedItem());\r
-    }\r
-\r
-    return null;\r
-  }\r
-\r
-  Alignment parseResult(Alignment al, String title, String currentFileFormat)\r
-  {\r
-\r
-    if (al != null && al.getHeight() > 0)\r
-    {\r
-      if (alignFrame == null)\r
-      {\r
-        AlignFrame af = new AlignFrame(al,\r
-            AlignFrame.DEFAULT_WIDTH,\r
-            AlignFrame.DEFAULT_HEIGHT);\r
-        if (currentFileFormat!=null)\r
-        {\r
-          af.currentFileFormat = currentFileFormat; // WHAT IS THE DEFAULT FORMAT FOR NON-FormatAdapter Sourced Alignments?\r
-        }\r
-\r
-        if(title==null)\r
-        {\r
-          title = "Retrieved from " + database.getSelectedItem();\r
-        }\r
-\r
-        Desktop.addInternalFrame(af,\r
-            title,\r
-            AlignFrame.DEFAULT_WIDTH,\r
-            AlignFrame.DEFAULT_HEIGHT);\r
-\r
-        af.statusBar.setText("Successfully pasted alignment file");\r
-\r
-        try\r
-        {\r
-          af.setMaximum(jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false));\r
-        }\r
-        catch (Exception ex)\r
-        {}\r
-      }\r
-      else\r
-      {\r
-        for (int i = 0; i < al.getHeight(); i++)\r
-        {\r
-          alignFrame.viewport.alignment.addSequence(al.getSequenceAt(i)); // this also creates dataset sequence entries\r
-        }\r
-        alignFrame.viewport.setEndSeq(alignFrame.viewport.alignment.\r
-            getHeight());\r
-        alignFrame.viewport.alignment.getWidth();\r
-        alignFrame.viewport.firePropertyChange("alignment", null,\r
-            alignFrame.viewport.\r
-            getAlignment().getSequences());\r
-      }\r
-    }\r
-    return al;\r
-  }\r
-\r
-  void showErrorMessage(final String error)\r
-  {\r
-    resetDialog();\r
-    javax.swing.SwingUtilities.invokeLater(new Runnable()\r
-    {\r
-      public void run()\r
-      {\r
-        JOptionPane.showInternalMessageDialog(Desktop.desktop,\r
-            error, "Error Retrieving Data",\r
-            JOptionPane.WARNING_MESSAGE);\r
-      }\r
-    });\r
-  }\r
-}\r
-\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+package jalview.gui;
+
+import java.io.*;
+import java.util.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+import MCview.*;
+import jalview.datamodel.*;
+import jalview.datamodel.xdb.embl.*;
+import java.io.File;
+import jalview.io.*;
+import jalview.ws.DBRefFetcher;
+import jalview.ws.EBIFetchClient;
+
+import java.awt.Rectangle;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+
+public class SequenceFetcher
+extends JPanel implements Runnable
+{
+  jalview.ws.SequenceFetcher sfetch; 
+  JInternalFrame frame;
+  AlignFrame alignFrame;
+  StringBuffer result;
+  final String noDbSelected = "-- Select Database --";
+  public SequenceFetcher(AlignFrame af)
+  {
+    alignFrame = af;
+    sfetch = new jalview.ws.SequenceFetcher();
+    database.addItem(noDbSelected);
+    /*
+     * Dynamically generated database list
+     * will need a translation function from
+     * internal source to externally distinct names.
+     * UNIPROT and UP_NAME are identical DB sources,
+     * and should be collapsed. 
+     *
+     
+     String dbs[] = sfetch.getSupportedDb();
+    for (int i=0; i<dbs.length;i++)
+    {
+      if (DBRefSource.isPrimaryDb(dbs[i]))
+      {  
+        database.addItem(dbs[i]);
+        // should have some kind of human readable description of each database displayed when
+         * that combo is selected.
+      }
+    }*/
+    database.addItem("Uniprot");
+    database.addItem("EMBL");
+    database.addItem("EMBLCDS");
+    database.addItem("PDB");
+    database.addItem("PFAM");
+
+    try
+    {
+      jbInit();
+    }
+    catch (Exception ex)
+    {
+      ex.printStackTrace();
+    }
+
+    frame = new JInternalFrame();
+    frame.setContentPane(this);
+    if (System.getProperty("os.name").startsWith("Mac"))
+    {
+      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 140);
+    }
+    else
+    {
+      Desktop.addInternalFrame(frame, getFrameTitle(), 400, 125);
+    }
+  }
+
+  private String getFrameTitle()
+  {
+    return ( (alignFrame == null) ? "New " : "Additional ") +
+    "Sequence Fetcher";
+  }
+
+  private void jbInit()
+  throws Exception
+  {
+    this.setLayout(borderLayout2);
+
+    database.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
+    jLabel1.setFont(new java.awt.Font("Verdana", Font.ITALIC, 11));
+    jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
+    jLabel1.setText(
+    "Separate multiple accession ids with semi colon \";\"");
+    ok.setText("OK");
+    ok.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        ok_actionPerformed();
+      }
+    });
+    close.setText("Close");
+    close.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent e)
+      {
+        close_actionPerformed(e);
+      }
+    });
+    textArea.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
+    textArea.setLineWrap(true);
+    textArea.addKeyListener(new KeyAdapter()
+    {
+      public void keyPressed(KeyEvent e)
+      {
+        if(e.getKeyCode()==KeyEvent.VK_ENTER)
+          ok_actionPerformed();
+      }
+    });
+    jPanel3.setLayout(borderLayout1);
+    borderLayout1.setVgap(5);
+    jPanel1.add(ok);
+    jPanel1.add(close);
+    jPanel3.add(jPanel2, java.awt.BorderLayout.WEST);
+    jPanel2.add(database);
+    jPanel3.add(jScrollPane1, java.awt.BorderLayout.CENTER);
+    jPanel3.add(jLabel1, java.awt.BorderLayout.NORTH);
+    this.add(jPanel1, java.awt.BorderLayout.SOUTH);
+    this.add(jPanel3, java.awt.BorderLayout.CENTER);
+    jScrollPane1.getViewport().add(textArea);
+
+  }
+
+  JComboBox database = new JComboBox();
+  JLabel jLabel1 = new JLabel();
+  JButton ok = new JButton();
+  JButton close = new JButton();
+  JPanel jPanel1 = new JPanel();
+  JTextArea textArea = new JTextArea();
+  JScrollPane jScrollPane1 = new JScrollPane();
+  JPanel jPanel2 = new JPanel();
+  JPanel jPanel3 = new JPanel();
+  BorderLayout borderLayout1 = new BorderLayout();
+  BorderLayout borderLayout2 = new BorderLayout();
+  public void close_actionPerformed(ActionEvent e)
+  {
+    try
+    {
+      frame.setClosed(true);
+    }
+    catch (Exception ex)
+    {}
+  }
+
+  public void ok_actionPerformed()
+  {
+    database.setEnabled(false);
+    textArea.setEnabled(false);
+    ok.setEnabled(false);
+    close.setEnabled(false);
+
+    Thread worker = new Thread(this);
+    worker.start();
+  }
+
+  private void resetDialog()
+  {
+    database.setEnabled(true);
+    textArea.setEnabled(true);
+    ok.setEnabled(true);
+    close.setEnabled(true);
+  }
+
+  public void run()
+  {
+    String error = "";
+    if (database.getSelectedItem().equals(noDbSelected))
+    {
+      error += "Please select the source database\n";
+    }
+    com.stevesoft.pat.Regex empty = new com.stevesoft.pat.Regex("\\s+", "");
+    textArea.setText(empty.replaceAll(textArea.getText()));
+    if (textArea.getText().length() == 0)
+    {
+      error += "Please enter a (semi-colon separated list of) database id(s)";
+    }
+    if (error.length() > 0)
+    {
+      showErrorMessage(error);
+      resetDialog();
+      return;
+    }
+
+    result = new StringBuffer();
+    if (database.getSelectedItem().equals("Uniprot"))
+    {
+      getUniprotFile(textArea.getText());
+    }
+    else if (database.getSelectedItem().equals("EMBL")
+        || database.getSelectedItem().equals("EMBLCDS"))
+    {
+      String DBRefSource = database.getSelectedItem().equals("EMBLCDS")
+      ? jalview.datamodel.DBRefSource.EMBLCDS
+          : jalview.datamodel.DBRefSource.EMBL;
+
+      StringTokenizer st = new StringTokenizer(textArea.getText(), ";");
+      SequenceI[] seqs = null;
+      while(st.hasMoreTokens())
+      {
+        EBIFetchClient dbFetch = new EBIFetchClient();
+
+        File reply = dbFetch.fetchDataAsFile(
+            database.getSelectedItem().toString().toLowerCase(
+            ) + ":" + st.nextToken(),
+            "emblxml",null);
+
+        jalview.datamodel.xdb.embl.EmblFile efile=null;
+        if (reply != null && reply.exists())
+        {
+          efile = jalview.datamodel.xdb.embl.EmblFile.getEmblFile(reply);
+        }
+        if (efile!=null) {
+          for (Iterator i=efile.getEntries().iterator(); i.hasNext(); ) {
+            EmblEntry entry = (EmblEntry) i.next();
+            SequenceI[] seqparts = entry.getSequences(false,true, DBRefSource);
+            if (seqparts!=null) {
+              SequenceI[] newseqs = null;
+              int si=0;
+              if (seqs==null) {
+                newseqs = new SequenceI[seqparts.length];
+              } else {
+                newseqs  = new SequenceI[seqs.length+seqparts.length];
+
+                for (;si<seqs.length; si++) {
+                  newseqs[si] = seqs[si];
+                  seqs[si] = null;
+                }
+              }
+              for (int j=0;j<seqparts.length; si++, j++) {
+                newseqs[si] = seqparts[j].deriveSequence(); // place DBReferences on dataset and refer
+              }
+              seqs=newseqs;
+
+            }
+          }
+        } else {
+          result=null;
+        }
+      }
+      if (seqs!=null && seqs.length>0) {
+        if (parseResult(new Alignment(seqs), null, null)!=null)
+          result.append("# Successfully parsed the "+database.getSelectedItem()+" Queries into an Alignment");
+      }
+    }
+    else if (database.getSelectedItem().equals("PDB"))
+    {
+      StringTokenizer qset = new StringTokenizer(textArea.getText(), ";");
+      String query;
+      SequenceI[] seqs = null;
+      while (qset.hasMoreTokens() && ((query = qset.nextToken())!=null))
+      {
+        SequenceI[] seqparts = getPDBFile(query.toUpperCase());
+        if (seqparts != null)
+        {
+          if (seqs == null)
+          {
+            seqs = seqparts;
+          }
+          else
+          {
+            SequenceI[] newseqs = new SequenceI[seqs.length+seqparts.length];
+            int i=0;
+            for (; i < seqs.length; i++)
+            {
+              newseqs[i] = seqs[i];
+              seqs[i] = null;
+            }
+            for (int j=0;j<seqparts.length; i++, j++)
+            {
+              newseqs[i] = seqparts[j];
+            }
+            seqs=newseqs;
+          }
+          result.append("# Success for "+query.toUpperCase()+"\n");
+        }
+      }
+      if (seqs != null && seqs.length > 0)
+      {
+        if (parseResult(new Alignment(seqs), null, null)!=null)
+        {
+          result.append(
+          "# Successfully parsed the PDB File Queries into an Alignment");
+        }
+      }
+    }
+    else if( database.getSelectedItem().equals("PFAM"))
+    {
+      try
+      {
+        result.append(new FastaFile(
+            "http://www.sanger.ac.uk/cgi-bin/Pfam/getalignment.pl?format=fal&acc="
+            +  textArea.getText().toUpperCase(), "URL").print()
+        );
+
+        if(result.length()>0)
+        {
+          parseResult( result.toString(), textArea.getText().toUpperCase() );
+        }
+
+      }
+      catch (java.io.IOException ex)
+      {
+        result = null;
+      }
+    }
+
+    if (result == null || result.length() == 0)
+    {
+      showErrorMessage("Error retrieving " + textArea.getText()
+          + " from " + database.getSelectedItem());
+    }
+
+    resetDialog();
+    return;
+  }
+
+  void getUniprotFile(String id)
+  {
+    EBIFetchClient ebi = new EBIFetchClient();
+    File file = ebi.fetchDataAsFile("uniprot:" + id, "xml", null);
+
+    DBRefFetcher dbref = new DBRefFetcher();
+    Vector entries = dbref.getUniprotEntries(file);
+
+    if (entries != null)
+    {
+      //First, make the new sequences
+      Enumeration en = entries.elements();
+      while (en.hasMoreElements())
+      {
+        UniprotEntry entry = (UniprotEntry) en.nextElement();
+
+        StringBuffer name = new StringBuffer(">UniProt/Swiss-Prot");
+        Enumeration en2 = entry.getAccession().elements();
+        while (en2.hasMoreElements())
+        {
+          name.append("|");
+          name.append(en2.nextElement());
+        }
+        en2 = entry.getName().elements();
+        while (en2.hasMoreElements())
+        {
+          name.append("|");
+          name.append(en2.nextElement());
+        }
+
+        if (entry.getProtein() != null)
+        {
+          name.append(" " + entry.getProtein().getName().elementAt(0));
+        }
+
+        result.append(name + "\n" + entry.getUniprotSequence().getContent() +
+        "\n");
+
+      }
+
+      //Then read in the features and apply them to the dataset
+      Alignment al = parseResult(result.toString(), null);
+      for (int i = 0; i < entries.size(); i++)
+      {
+        UniprotEntry entry = (UniprotEntry) entries.elementAt(i);
+        Enumeration e = entry.getDbReference().elements();
+        Vector onlyPdbEntries = new Vector();
+        while (e.hasMoreElements())
+        {
+          PDBEntry pdb = (PDBEntry) e.nextElement();
+          if (!pdb.getType().equals("PDB"))
+          {
+            continue;
+          }
+
+          onlyPdbEntries.addElement(pdb);
+        }
+
+        Enumeration en2 = entry.getAccession().elements();
+        while (en2.hasMoreElements())
+        {
+          al.getSequenceAt(i).getDatasetSequence().addDBRef(new DBRefEntry(
+              DBRefSource.UNIPROT,
+              "0",
+              en2.nextElement().toString()));
+        }
+
+
+
+
+        al.getSequenceAt(i).getDatasetSequence().setPDBId(onlyPdbEntries);
+        if (entry.getFeature() != null)
+        {
+          e = entry.getFeature().elements();
+          while (e.hasMoreElements())
+          {
+            SequenceFeature sf = (SequenceFeature) e.nextElement();
+            sf.setFeatureGroup("Uniprot");
+            al.getSequenceAt(i).getDatasetSequence().addSequenceFeature( sf );
+          }
+        }
+      }
+    }
+  }
+
+  SequenceI[] getPDBFile(String id)
+  {
+    Vector result = new Vector();
+    String chain = null;
+    if (id.indexOf(":") > -1)
+    {
+      chain = id.substring(id.indexOf(":") + 1);
+      id = id.substring(0, id.indexOf(":"));
+    }
+
+    EBIFetchClient ebi = new EBIFetchClient();
+    String file = ebi.fetchDataAsFile("pdb:" + id, "pdb", "raw").
+    getAbsolutePath();
+    if (file == null)
+    {
+      return null;
+    }
+    try
+    {
+      PDBfile pdbfile = new PDBfile(file, jalview.io.AppletFormatAdapter.FILE);
+      for (int i = 0; i < pdbfile.chains.size(); i++)
+      {
+        if (chain == null ||
+            ( (PDBChain) pdbfile.chains.elementAt(i)).id.
+            toUpperCase().equals(chain))
+        {
+          PDBChain pdbchain = (PDBChain) pdbfile.chains.elementAt(i);
+          // Get the Chain's Sequence - who's dataset includes any special features added from the PDB file
+          SequenceI sq = pdbchain.sequence;
+          // Specially formatted name for the PDB chain sequences retrieved from the PDB
+          sq.setName("PDB|"+id+"|"+sq.getName());
+          // Might need to add more metadata to the PDBEntry object
+          // like below
+          /*
+           * PDBEntry entry = new PDBEntry();
+            // Construct the PDBEntry
+            entry.setId(id);
+            if (entry.getProperty() == null)
+                entry.setProperty(new Hashtable());
+            entry.getProperty().put("chains",
+                        pdbchain.id
+                        + "=" + sq.getStart()
+                        + "-" + sq.getEnd());
+            sq.getDatasetSequence().addPDBId(entry);
+           */
+          // Add PDB DB Refs
+          // We make a DBRefEtntry because we have obtained the PDB file from a verifiable source
+          // JBPNote - PDB DBRefEntry should also carry the chain and mapping information
+          DBRefEntry dbentry = new DBRefEntry(jalview.datamodel.DBRefSource.PDB,
+              "0", id + pdbchain.id);
+          sq.addDBRef(dbentry);
+          // and add seuqence to the retrieved set
+          result.addElement(sq.deriveSequence());
+        }
+      }
+
+      if (result.size() < 1)
+      {
+        throw new Exception("WsDBFetch for PDB id resulted in zero result size");
+      }
+    }
+    catch (Exception ex) // Problem parsing PDB file
+    {
+      jalview.bin.Cache.log.warn("Exception when retrieving " +
+          textArea.getText() + " from " +
+          database.getSelectedItem(), ex);
+      return null;
+    }
+
+
+    SequenceI[] results = new SequenceI[result.size()];
+    for (int i = 0, j = result.size(); i < j; i++)
+    {
+      results[i] = (SequenceI) result.elementAt(i);
+      result.setElementAt(null,i);
+    }
+    return results;
+  }
+  Alignment parseResult(String result, String title)
+  {
+    String format = new IdentifyFile().Identify(result, "Paste");
+    Alignment sequences = null;
+    if (FormatAdapter.isValidFormat(format))
+    {
+      sequences = null;
+      try
+      {
+        sequences = new FormatAdapter().readFile(result.toString(), "Paste",
+            format);
+      }
+      catch (Exception ex)
+      {}
+
+      if (sequences!=null)
+      {
+        return parseResult(sequences, title, format);
+      }
+    }
+    else
+    {
+      showErrorMessage("Error retrieving " + textArea.getText()
+          + " from " + database.getSelectedItem());
+    }
+
+    return null;
+  }
+
+  Alignment parseResult(Alignment al, String title, String currentFileFormat)
+  {
+
+    if (al != null && al.getHeight() > 0)
+    {
+      if (alignFrame == null)
+      {
+        AlignFrame af = new AlignFrame(al,
+            AlignFrame.DEFAULT_WIDTH,
+            AlignFrame.DEFAULT_HEIGHT);
+        if (currentFileFormat!=null)
+        {
+          af.currentFileFormat = currentFileFormat; // WHAT IS THE DEFAULT FORMAT FOR NON-FormatAdapter Sourced Alignments?
+        }
+
+        if(title==null)
+        {
+          title = "Retrieved from " + database.getSelectedItem();
+        }
+
+        Desktop.addInternalFrame(af,
+            title,
+            AlignFrame.DEFAULT_WIDTH,
+            AlignFrame.DEFAULT_HEIGHT);
+
+        af.statusBar.setText("Successfully pasted alignment file");
+
+        try
+        {
+          af.setMaximum(jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false));
+        }
+        catch (Exception ex)
+        {}
+      }
+      else
+      {
+        for (int i = 0; i < al.getHeight(); i++)
+        {
+          alignFrame.viewport.alignment.addSequence(al.getSequenceAt(i)); // this also creates dataset sequence entries
+        }
+        alignFrame.viewport.setEndSeq(alignFrame.viewport.alignment.
+            getHeight());
+        alignFrame.viewport.alignment.getWidth();
+        alignFrame.viewport.firePropertyChange("alignment", null,
+            alignFrame.viewport.
+            getAlignment().getSequences());
+      }
+    }
+    return al;
+  }
+
+  void showErrorMessage(final String error)
+  {
+    resetDialog();
+    javax.swing.SwingUtilities.invokeLater(new Runnable()
+    {
+      public void run()
+      {
+        JOptionPane.showInternalMessageDialog(Desktop.desktop,
+            error, "Error Retrieving Data",
+            JOptionPane.WARNING_MESSAGE);
+      }
+    });
+  }
+}
+
index 58ca6f6..ea2ef4d 100755 (executable)
@@ -423,7 +423,7 @@ public class TreeCanvas
       return;
     }
 
-    if ( (node.left() == null) && (node.right() == null))
+    if ( (node.left() == null) && (node.right() == null)) // TODO: internal node
     {
       node.color = c;
 
index b37e4c1..36378d4 100755 (executable)
@@ -116,6 +116,7 @@ public class GAlignFrame
   JMenuItem vamsasStore = new JMenuItem();
   protected JMenuItem showTranslation = new JMenuItem();
   protected JMenuItem extractScores = new JMenuItem();
+  protected JMenu showProducts = new JMenu();
   public JMenuItem featureSettings = new JMenuItem();
   JMenuItem fetchSequence = new JMenuItem();
   JMenuItem annotationColour = new JMenuItem();
@@ -1026,7 +1027,16 @@ public class GAlignFrame
         extractScores_actionPerformed(e);
       }
     });
-    extractScores.setVisible(false); // JBPNote: TODO: make gui for regex based score extraction
+    extractScores.setVisible(true); // JBPNote: TODO: make gui for regex based score extraction
+    showProducts.setText("Get Cross References");
+    /*showProducts.addActionListener(new ActionListener()
+    {
+
+      public void actionPerformed(ActionEvent e)
+      {
+        showProducts_actionPerformed(e);
+      }
+    });*/
     featureSettings.setText("Feature Settings...");
     featureSettings.addActionListener(new ActionListener()
     {
@@ -1362,6 +1372,7 @@ public class GAlignFrame
     calculateMenu.add(PCAMenuItem);
     calculateMenu.addSeparator();
     calculateMenu.add(showTranslation);
+    calculateMenu.add(showProducts);
     calculateMenu.add(autoCalculate);
     calculateMenu.addSeparator();
     calculateMenu.add(extractScores);
@@ -1412,6 +1423,12 @@ public class GAlignFrame
     selectMenu.add(deleteGroups);
   }
 
+  protected void showProducts_actionPerformed(ActionEvent e)
+  {
+    // TODO Auto-generated method stub
+    
+  }
+
   protected void buildSortByAnnotationScoresMenu()
   {
   }
index bda215e..5370e12 100644 (file)
@@ -1,30 +1,30 @@
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2007 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.structure;\r
-\r
-import jalview.datamodel.*;\r
-\r
-public interface SequenceListener\r
-{\r
-  public void mouseOverSequence(SequenceI sequence, int index);\r
-\r
-  public void highlightSequence(jalview.datamodel.SearchResults results);\r
-\r
-  public void updateColours(SequenceI sequence, int index);\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer
+ * Copyright (C) 2007 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.structure;
+
+import jalview.datamodel.*;
+
+public interface SequenceListener
+{
+  public void mouseOverSequence(SequenceI sequence, int index, int pos);
+
+  public void highlightSequence(jalview.datamodel.SearchResults results);
+
+  public void updateColours(SequenceI sequence, int index);
+}
index b07b7a4..d36d009 100644 (file)
@@ -293,10 +293,12 @@ public class StructureSelectionManager
 
   // pairs
 
-  public void mouseOverSequence(SequenceI seq, int index)
+  public void mouseOverSequence(SequenceI seq, int indexpos, int index)
   {
     boolean hasSequenceListeners = handlingVamsasMo || seqmappings != null;
     SearchResults results = null;
+    if (index==-1)
+      index=seq.findPosition(indexpos);
     StructureListener sl;
     int atomNo = 0;
     for (int i = 0; i < listeners.size(); i++)
@@ -307,7 +309,7 @@ public class StructureSelectionManager
 
         for (int j = 0; j < mappings.length; j++)
         {
-          if (mappings[j].sequence == seq)
+          if (mappings[j].sequence == seq || mappings[j].sequence==seq.getDatasetSequence())
           {
             atomNo = mappings[j].getAtomNum(index);
 
@@ -348,6 +350,7 @@ public class StructureSelectionManager
               // hasSequenceListeners = results.getSize() > 0;
               if (handlingVamsasMo)
               {
+                // maybe have to resolve seq to a dataset seqeunce...
                 // add in additional direct sequence and/or dataset sequence
                 // highlighting
                 results.addResult(seq, index, index);
@@ -366,8 +369,8 @@ public class StructureSelectionManager
           // DEBUG 
           //System.err.println("Vamsas from Seq " + seq.getDisplayId(false) + " " +
           // index);
-          // pass the mouse over onto the VamsasListener(s)
-          ((VamsasListener) listeners.elementAt(i)).mouseOver(seq, index);
+          // pass the mouse over and absolute position onto the VamsasListener(s)
+          ((VamsasListener) listeners.elementAt(i)).mouseOver(seq, indexpos);
         }
       }
     }
@@ -378,18 +381,23 @@ public class StructureSelectionManager
    * handled
    */
   boolean handlingVamsasMo = false;
-
+  long lastmsg=0;
   /**
    * as mouseOverSequence but only route event to SequenceListeners
    * 
    * @param sequenceI
-   * @param position
+   * @param position in an alignment sequence
    */
   public void mouseOverVamsasSequence(SequenceI sequenceI, int position)
   {
     handlingVamsasMo = true;
-    mouseOverSequence(sequenceI, position);
-    handlingVamsasMo = false;
+    long msg = sequenceI.hashCode()*(1+position);
+    if (lastmsg!=msg)
+    {
+      lastmsg = msg;
+      mouseOverSequence(sequenceI, position, -1);
+    }
+      handlingVamsasMo = false;
   }
 
   public Annotation[] colourSequenceFromStructure(SequenceI seq,