Tooltips for features, links for features added
authoramwaterhouse <Andrew Waterhouse>
Wed, 7 Jun 2006 12:52:43 +0000 (12:52 +0000)
committeramwaterhouse <Andrew Waterhouse>
Wed, 7 Jun 2006 12:52:43 +0000 (12:52 +0000)
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java

index 8f6e49f..1c9b3cd 100755 (executable)
@@ -87,6 +87,11 @@ public class APopupMenu
       showText.setState(sg.getDisplayText());\r
       showColourText.setState(sg.getColourText());\r
       showBoxes.setState(sg.getDisplayBoxes());\r
+      if (!ap.av.alignment.getGroups().contains(sg))\r
+      {\r
+        groupMenu.remove(unGroupMenuItem);\r
+      }\r
+\r
     }\r
     else\r
     {\r
@@ -94,12 +99,7 @@ public class APopupMenu
       remove(editMenu);\r
     }\r
 \r
-    if (!ap.av.alignment.getGroups().contains(sg))\r
-    {\r
-      groupMenu.remove(unGroupMenuItem);\r
-    }\r
-\r
-    if (seq != null && links!=null)\r
+    if (links!=null)\r
     {\r
       Menu linkMenu = new Menu("Link");\r
       MenuItem item;\r
@@ -109,13 +109,22 @@ public class APopupMenu
         link = links.elementAt(i).toString();\r
         final String target = link.substring(0, link.indexOf("|"));\r
         item = new MenuItem(target);\r
-        String id = seq.getName();\r
-        if(id.indexOf("|")>-1)\r
-             id = id.substring(id.lastIndexOf("|")+1);\r
 \r
-        final String url = link.substring(link.indexOf("|")+1, link.indexOf("$SEQUENCE_ID$"))\r
-               + id +\r
-               link.substring(link.indexOf("$SEQUENCE_ID$") + 13);\r
+        final String url;\r
+\r
+        if (link.indexOf("$SEQUENCE_ID$") > -1)\r
+        {\r
+          String id = seq.getName();\r
+          if (id.indexOf("|") > -1)\r
+            id = id.substring(id.lastIndexOf("|") + 1);\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
+          url = link.substring(link.lastIndexOf("|")+1);\r
 \r
            item.addActionListener(new java.awt.event.ActionListener()\r
            {\r
@@ -128,18 +137,19 @@ public class APopupMenu
       }\r
       add(linkMenu);\r
 \r
-      item = new MenuItem("Show PDB Structure");\r
-      item.addActionListener(new java.awt.event.ActionListener()\r
-           {\r
-               public void actionPerformed(ActionEvent e)\r
-               {\r
-                  addPDB(seq);\r
-               }\r
-           });\r
-\r
-      add(item);\r
-\r
+      if(seq!=null)\r
+      {\r
+        item = new MenuItem("Show PDB Structure");\r
+        item.addActionListener(new java.awt.event.ActionListener()\r
+        {\r
+          public void actionPerformed(ActionEvent e)\r
+          {\r
+            addPDB(seq);\r
+          }\r
+        });\r
 \r
+        add(item);\r
+      }\r
     }\r
   }\r
 \r
index 1ecf254..77154e0 100755 (executable)
@@ -172,18 +172,26 @@ public class AlignFrame extends Frame implements ActionListener,
       StringTokenizer st;\r
       SequenceFeature sf;\r
       FeatureRenderer fr = alignPanel.seqPanel.seqCanvas.getFeatureRenderer();\r
-      int lineNo = 0;\r
-      String featureGroup = null;\r
+      String featureGroup = null, groupLink = null;\r
+      Hashtable typeLink = new Hashtable();\r
+\r
       while ( (line = in.readLine()) != null)\r
       {\r
-        lineNo++;\r
         st = new StringTokenizer(line, "\t");\r
-        if (st.countTokens() == 2)\r
+        if(!st.hasMoreTokens())\r
+          continue;\r
+\r
+        if (st.countTokens() < 4)\r
         {\r
           type = st.nextToken();\r
           if(type.equalsIgnoreCase("startgroup"))\r
           {\r
             featureGroup = st.nextToken();\r
+            if (st.hasMoreElements())\r
+            {\r
+              groupLink = st.nextToken();\r
+              fr.addFeatureLink(featureGroup, groupLink);\r
+            }\r
           }\r
           else if(type.equalsIgnoreCase("endgroup"))\r
           {\r
@@ -191,11 +199,19 @@ public class AlignFrame extends Frame implements ActionListener,
             //but at present theres no way of showing more than 1 group\r
             st.nextToken();\r
             featureGroup = null;\r
+            groupLink = null;\r
           }\r
           else\r
           {\r
             UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
             fr.setColour(type, ucs.findColour("A"));\r
+            if (st.hasMoreElements())\r
+            {\r
+                String link = st.nextToken();\r
+                typeLink.put(type, link);\r
+                fr.addFeatureLink(type, link);\r
+            }\r
+\r
           }\r
           continue;\r
         }\r
@@ -203,6 +219,7 @@ public class AlignFrame extends Frame implements ActionListener,
         while (st.hasMoreElements())\r
         {\r
           desc = st.nextToken();\r
+\r
           token = st.nextToken();\r
           if (!token.equals("ID_NOT_SPECIFIED"))\r
           {\r
@@ -229,9 +246,21 @@ public class AlignFrame extends Frame implements ActionListener,
             fr.setColour(type, ucs.findColour("A"));\r
           }\r
 \r
-          sf = new SequenceFeature(type, desc, "", start, end, featureGroup);\r
-\r
+          sf = new SequenceFeature(type, desc, start, end, 0f, featureGroup);\r
           seq.addSequenceFeature(sf);\r
+\r
+          if(groupLink!=null)\r
+          {\r
+            sf.addLink(groupLink);\r
+            sf.description += "%LINK%";\r
+          }\r
+          if(typeLink.containsKey(type))\r
+          {\r
+            sf.addLink(typeLink.get(type).toString());\r
+            sf.description += "%LINK%";\r
+          }\r
+\r
+          parseDescriptionHTML(sf);\r
         }\r
       }\r
 \r
@@ -248,6 +277,33 @@ public class AlignFrame extends Frame implements ActionListener,
     }\r
   }\r
 \r
+  void parseDescriptionHTML(SequenceFeature sf)\r
+  {\r
+    StringBuffer sb = new StringBuffer();\r
+    StringTokenizer st = new StringTokenizer(sf.getDescription(), "<");\r
+    String token,  link;\r
+    while(st.hasMoreElements())\r
+    {\r
+      token = st.nextToken("<>");\r
+      if(token.equalsIgnoreCase("html") || token.startsWith("/"))\r
+        continue;\r
+\r
+      if(token.startsWith("a href="))\r
+      {\r
+        link = token.substring(token.indexOf("\"")+1, token.length()-1);\r
+        String label = st.nextToken("<>");\r
+        sf.addLink(label+"|"+link);\r
+        sb.append(label+"%LINK%");\r
+      }\r
+      else if(token.equalsIgnoreCase("br"))\r
+        sb.append("\n");\r
+      else\r
+        sb.append(token);\r
+    }\r
+\r
+    sf.description = sb.toString();\r
+  }\r
+\r
   public void keyPressed(KeyEvent evt)\r
   {\r
     if (viewport.cursorMode\r
index 481a657..152966e 100755 (executable)
@@ -79,7 +79,7 @@ public class AlignViewport
 \r
   // The following vector holds the features which are\r
  // currently visible, in the correct order or rendering\r
-  Hashtable featuresDisplayed = null;\r
+  Hashtable featuresDisplayed;\r
 \r
 \r
   public Vector vconsensus;\r
index 900de83..aa3f830 100755 (executable)
@@ -40,6 +40,11 @@ public class FeatureRenderer
     // particular type\r
     Hashtable featureGroups = null;\r
 \r
+    // Holds web links for feature groups and feature types\r
+    // in the form label|link\r
+    Hashtable featureLinks = null;\r
+\r
+\r
     // This is actually an Integer held in the hashtable,\r
     // Retrieved using the key feature type\r
     Object currentColour;\r
@@ -49,6 +54,10 @@ public class FeatureRenderer
     FontMetrics fm;\r
     int charOffset;\r
 \r
+    float transparency = 1f;\r
+\r
+    TransparencySetter transparencySetter = null;\r
+\r
     /**\r
      * Creates a new FeatureRenderer object.\r
      *\r
@@ -58,6 +67,17 @@ public class FeatureRenderer
     {\r
         this.av = av;\r
         initColours();\r
+\r
+        if(!System.getProperty("java.version").startsWith("1.1"))\r
+             transparencySetter = new TransparencySetter();\r
+    }\r
+\r
+    public void addFeatureLink(String feature, String link)\r
+    {\r
+      if(featureLinks == null)\r
+        featureLinks = new Hashtable();\r
+\r
+       featureLinks.put(feature, link);\r
     }\r
 \r
 \r
@@ -160,6 +180,10 @@ public class FeatureRenderer
           || seq.getSequenceFeatures().length==0)\r
         return;\r
 \r
+      if(transparencySetter!=null && g!=null)\r
+      {\r
+        transparencySetter.setTransparency(g, transparency);\r
+      }\r
 \r
       if (av.featuresDisplayed == null || renderOrder==null)\r
        {\r
@@ -248,6 +272,11 @@ public class FeatureRenderer
 \r
         }\r
       }\r
+\r
+      if(transparencySetter!=null && g!=null)\r
+      {\r
+        transparencySetter.setTransparency(g, 1.0f);\r
+      }\r
     }\r
 \r
 \r
@@ -417,8 +446,19 @@ public class FeatureRenderer
       featureColours.put("unsure residue", new Color(0, 75, 245));\r
       featureColours.put("zinc finger region", new Color(0, 65, 255));\r
     }\r
-\r
 }\r
 \r
+  class TransparencySetter\r
+  {\r
+    void setTransparency(Graphics g, float value)\r
+    {\r
+      Graphics2D g2 = (Graphics2D) g;\r
+      g2.setComposite(\r
+          AlphaComposite.getInstance(\r
+              AlphaComposite.SRC_OVER, value));\r
+    }\r
+  }\r
+\r
+\r
 \r
 \r
index 6710ed4..b642fb3 100755 (executable)
@@ -25,7 +25,7 @@ import java.awt.event.*;
 \r
 \r
 public class FeatureSettings extends Panel implements ItemListener,\r
-    MouseListener, MouseMotionListener\r
+    MouseListener, MouseMotionListener, ActionListener, AdjustmentListener\r
 {\r
   FeatureRenderer fr;\r
   AlignmentPanel ap;\r
@@ -35,6 +35,8 @@ public class FeatureSettings extends Panel implements ItemListener,
   Panel featurePanel = new Panel();\r
   ScrollPane scrollPane;\r
   boolean alignmentHasFeatures = false;\r
+  Image linkImage;\r
+  Scrollbar transparency ;\r
 \r
   public FeatureSettings(AlignViewport av, final AlignmentPanel ap)\r
   {\r
@@ -42,6 +44,26 @@ public class FeatureSettings extends Panel implements ItemListener,
     this.av = av;\r
     fr = ap.seqPanel.seqCanvas.getFeatureRenderer();\r
 \r
+    transparency = new Scrollbar(Scrollbar.HORIZONTAL,\r
+     100 - (int)(fr.transparency*100), 1, 1, 100);\r
+\r
+    if(fr.transparencySetter!=null)\r
+    {\r
+      transparency.addAdjustmentListener(this);\r
+    }\r
+    else\r
+      transparency.setEnabled(false);\r
+\r
+    java.net.URL url = getClass().getResource("/images/link.gif");\r
+    if (url != null)\r
+    {\r
+      linkImage = java.awt.Toolkit.getDefaultToolkit().getImage(url);\r
+    }\r
+\r
+\r
+    if(av.featuresDisplayed==null)\r
+      fr.findAllFeatures();\r
+\r
     setTableData();\r
 \r
     this.setLayout(new BorderLayout());\r
@@ -50,6 +72,28 @@ public class FeatureSettings extends Panel implements ItemListener,
     if (alignmentHasFeatures)\r
       add(scrollPane, BorderLayout.CENTER);\r
 \r
+    Button invert = new Button("Invert Selection");\r
+    invert.addActionListener(this);\r
+\r
+    Panel lowerPanel = new Panel(new GridLayout(2,1,5,10));\r
+    lowerPanel.add(invert);\r
+\r
+    Panel tPanel = new Panel(new BorderLayout());\r
+\r
+    if(fr.transparencySetter!=null)\r
+    {\r
+      tPanel.add(transparency, BorderLayout.CENTER);\r
+      tPanel.add(new Label("Transparency"), BorderLayout.EAST);\r
+    }\r
+    else\r
+      tPanel.add(new Label("Transparency not available in this web browser"), BorderLayout.CENTER);\r
+\r
+    lowerPanel.add(tPanel, BorderLayout.SOUTH);\r
+\r
+    add(lowerPanel, BorderLayout.SOUTH);\r
+\r
+\r
+\r
     if(groupPanel!=null)\r
     {\r
       groupPanel.setLayout(\r
@@ -119,7 +163,14 @@ public class FeatureSettings extends Panel implements ItemListener,
                groupPanel = new Panel();\r
              }\r
 \r
-             Checkbox check = new Checkbox(group, visible);\r
+             Checkbox check =  new MyCheckbox(\r
+                group,\r
+                visible,\r
+                (fr.featureLinks!=null && fr.featureLinks.containsKey(group))\r
+                 );\r
+\r
+\r
+             check.addMouseListener(this);\r
              check.setFont(new Font("Serif", Font.BOLD, 12));\r
              check.addItemListener(this);\r
              groupPanel.add(check);\r
@@ -206,6 +257,7 @@ public class FeatureSettings extends Panel implements ItemListener,
        // now add checkboxes which should be visible,\r
        // if they have not already been added\r
        Enumeration en = visibleChecks.elements();\r
+\r
        while(en.hasMoreElements())\r
        {\r
          addCheck(groupsChanged, en.nextElement().toString());\r
@@ -246,7 +298,11 @@ public class FeatureSettings extends Panel implements ItemListener,
         selected = true;\r
       }\r
 \r
-      check = new Checkbox(type, selected);\r
+      check = new MyCheckbox(type,\r
+                             selected,\r
+          (fr.featureLinks!=null && fr.featureLinks.containsKey(type))\r
+           );\r
+\r
       check.addMouseListener(this);\r
       check.addMouseMotionListener(this);\r
       check.setBackground(fr.getColour(type));\r
@@ -255,6 +311,16 @@ public class FeatureSettings extends Panel implements ItemListener,
     }\r
   }\r
 \r
+  public void actionPerformed(ActionEvent evt)\r
+  {\r
+    for(int i=0; i<featurePanel.getComponentCount(); i++)\r
+    {\r
+      Checkbox check = (Checkbox)featurePanel.getComponent(i);\r
+      check.setState(!check.getState());\r
+    }\r
+    selectionChanged();\r
+  }\r
+\r
   public void itemStateChanged(ItemEvent evt)\r
   {\r
     if (evt != null)\r
@@ -272,7 +338,11 @@ public class FeatureSettings extends Panel implements ItemListener,
         return;\r
       }\r
     }\r
+    selectionChanged();\r
+  }\r
 \r
+  void selectionChanged()\r
+  {\r
       Component[] comps = featurePanel.getComponents();\r
       int cSize = comps.length;\r
 \r
@@ -296,21 +366,36 @@ public class FeatureSettings extends Panel implements ItemListener,
         ap.overviewPanel.updateOverviewImage();\r
   }\r
 \r
-  Checkbox selectedCheck;\r
+  MyCheckbox selectedCheck;\r
   boolean dragging = false;\r
 \r
   public void mousePressed(MouseEvent evt)\r
   {\r
-    selectedCheck = (Checkbox)evt.getSource();\r
+\r
+    selectedCheck = (MyCheckbox)evt.getSource();\r
+\r
+    if ( fr.featureLinks.containsKey(selectedCheck.getLabel() )   )\r
+      {\r
+        if(evt.getX()>selectedCheck.stringWidth+20)\r
+        {\r
+          evt.consume();\r
+        }\r
+      }\r
+\r
   }\r
 \r
   public void mouseDragged(MouseEvent evt)\r
   {\r
+    if(((Component)evt.getSource()).getParent()!=featurePanel)\r
+      return;\r
       dragging = true;\r
   }\r
 \r
   public void mouseReleased(MouseEvent evt)\r
   {\r
+    if(((Component)evt.getSource()).getParent()!=featurePanel)\r
+      return;\r
+\r
     Component comp = null;\r
     Checkbox  target = null;\r
 \r
@@ -364,7 +449,22 @@ public class FeatureSettings extends Panel implements ItemListener,
   public void mouseExited(MouseEvent evt){}\r
   public void mouseClicked(MouseEvent evt)\r
   {\r
-    Checkbox check = (Checkbox) evt.getSource();\r
+    MyCheckbox check = (MyCheckbox) evt.getSource();\r
+\r
+    if (fr.featureLinks.containsKey(check.getLabel()))\r
+    {\r
+      if (evt.getX() > check.stringWidth + 20)\r
+      {\r
+        evt.consume();\r
+        String link = fr.featureLinks.get(check.getLabel()).toString();\r
+        ap.alignFrame.showURL(link.substring(link.indexOf("|") + 1),\r
+                              link.substring(0, link.indexOf("|")));\r
+      }\r
+    }\r
+\r
+    if(check.getParent()!=featurePanel)\r
+      return;\r
+\r
     if(evt.getClickCount()>1)\r
     {\r
        new UserDefinedColours(this, check.getLabel(),\r
@@ -372,4 +472,34 @@ public class FeatureSettings extends Panel implements ItemListener,
     }\r
   }\r
   public void mouseMoved(MouseEvent evt){}\r
+\r
+  public void adjustmentValueChanged(AdjustmentEvent evt)\r
+  {\r
+    fr.transparency = ( (float) (100 - transparency.getValue()) / 100f);\r
+    ap.seqPanel.seqCanvas.repaint();\r
+\r
+  }\r
+\r
+  class MyCheckbox extends Checkbox\r
+  {\r
+    public int stringWidth;\r
+    boolean hasLink;\r
+    public MyCheckbox(String label, boolean checked, boolean haslink)\r
+    {\r
+      super(label, checked);\r
+      FontMetrics fm = av.nullFrame.getFontMetrics(av.nullFrame.getFont());\r
+      stringWidth = fm.stringWidth(label);\r
+      this.hasLink = haslink;\r
+    }\r
+\r
+    public void paint(Graphics g)\r
+    {\r
+      if (hasLink)\r
+        g.drawImage(linkImage, stringWidth + 25,(\r
+        getSize().height-linkImage.getHeight(this))/2,\r
+                    this);\r
+    }\r
+  }\r
 }\r
+\r
+\r
index 71acfa2..1a61429 100755 (executable)
@@ -69,8 +69,42 @@ public class IdPanel
     }\r
   }\r
 \r
+  Tooltip tooltip;\r
   public void mouseMoved(MouseEvent e)\r
-  {}\r
+  {\r
+    int y = e.getY();\r
+    if (av.getWrapAlignment())\r
+    {\r
+      y -= 2 * av.charHeight;\r
+    }\r
+\r
+    int seq = av.getIndex(y);\r
+    if (seq == -1)\r
+    {\r
+      return;\r
+    }\r
+\r
+    SequenceI sequence = av.getAlignment().getSequenceAt(seq);\r
+\r
+    if(sequence.getDescription()==null)\r
+    {\r
+      if(tooltip!=null)\r
+        tooltip.setVisible(false);\r
+      tooltip = null;\r
+      return;\r
+    }\r
+\r
+    if (tooltip == null)\r
+      tooltip = new Tooltip(\r
+          sequence.getDisplayId(true)\r
+          + "\n" + sequence.getDescription(), idCanvas);\r
+    else\r
+      tooltip.setTip(sequence.getDisplayId(true)\r
+                     + "\n" + sequence.getDescription());\r
+\r
+    tooltip.repaint();\r
+\r
+  }\r
 \r
   public void mouseDragged(MouseEvent e)\r
   {\r
index 3e47139..02c9990 100755 (executable)
@@ -294,6 +294,8 @@ public class SeqCanvas
   int LABEL_WEST, LABEL_EAST;\r
   public int getWrappedCanvasWidth(int cwidth)\r
   {\r
+      cwidth -= cwidth % av.charWidth;\r
+\r
       FontMetrics fm = getFontMetrics(av.getFont());\r
 \r
       LABEL_EAST = 0;\r
@@ -334,15 +336,12 @@ public class SeqCanvas
 \r
     FontMetrics fm = getFontMetrics(av.getFont());\r
 \r
-    int LABEL_EAST = 0;\r
 \r
     if (av.scaleRightWrapped)\r
     {\r
         LABEL_EAST = fm.stringWidth(getMask());\r
     }\r
 \r
-    int LABEL_WEST = 0;\r
-\r
     if (av.scaleLeftWrapped)\r
     {\r
         LABEL_WEST = fm.stringWidth(getMask());\r
@@ -496,7 +495,7 @@ public class SeqCanvas
       groupIndex = 0;\r
   }\r
 \r
-  if ( group != null)\r
+  if ( group != null )\r
   {\r
       do\r
       {\r
@@ -505,6 +504,7 @@ public class SeqCanvas
           boolean inGroup = false;\r
           int top = -1;\r
           int bottom = -1;\r
+          int alHeight = av.alignment.getHeight()-1;\r
 \r
           for (i = startSeq; i < endSeq; i++)\r
           {\r
@@ -522,9 +522,10 @@ public class SeqCanvas
                       group.sequences.contains(av.alignment.getSequenceAt(\r
                               i)))\r
               {\r
-                if ((bottom == -1) &&\r
-                        !group.sequences.contains(\r
-                            av.alignment.getSequenceAt(i + 1)))\r
+                if ( (bottom == -1) &&\r
+                    (i >= alHeight ||\r
+                     !group.sequences.contains(\r
+                         av.alignment.getSequenceAt(i + 1))))\r
                 {\r
                     bottom = sy + av.charHeight;\r
                 }\r
index 87e9bec..4b7a45e 100755 (executable)
@@ -25,6 +25,8 @@ import java.awt.event.*;
 import jalview.datamodel.*;\r
 import jalview.schemes.*;\r
 \r
+import java.util.Vector;\r
+\r
 public class SeqPanel\r
     extends Panel implements MouseMotionListener, MouseListener\r
 {\r
@@ -312,6 +314,7 @@ public class SeqPanel
                      ")");\r
        }\r
      }\r
+\r
      ap.alignFrame.statusBar.setText(text.toString());\r
 \r
     }\r
@@ -535,48 +538,71 @@ public class SeqPanel
         && sequence.getSequenceFeatures()!=null\r
         && av.featuresDisplayed!=null)\r
     {\r
+      StringBuffer featureText = new StringBuffer();\r
+      Vector allFeatures = getAllFeaturesAtRes(sequence, sequence.findPosition(res));\r
+\r
       int index = 0;\r
-      sequence.getSequenceFeatures();\r
-      boolean first = true;\r
-      while (index < sequence.getSequenceFeatures().length)\r
+      while (index < allFeatures.size())\r
       {\r
-        SequenceFeature sf = sequence.getSequenceFeatures()[index];\r
-        if (sf.getBegin() <= sequence.findPosition(res) &&\r
-            sf.getEnd() >= sequence.findPosition(res))\r
-        {\r
-          if(!av.featuresDisplayed.containsKey(sf.getType()))\r
-           {\r
-             index++;\r
-             continue;\r
-           }\r
+        SequenceFeature sf = (SequenceFeature) allFeatures.elementAt(index);\r
 \r
-          if(first)\r
-          {\r
-            text.append(" Sequence Feature:");\r
-            first = false;\r
-          }\r
-\r
-          text.append(" "+sf.getType());\r
+        featureText.append(sf.getType()+" "+sf.begin+":"+sf.end);\r
 \r
-          if(sf.getDescription()!=null)\r
-            text.append(" "+sf.getDescription());\r
+        if (sf.getDescription() != null)\r
+          featureText.append(" " + sf.getDescription());\r
 \r
-          if (sf.getStatus()!=null && sf.getStatus().length() > 0)\r
-          {\r
-            text.append(" (" + sf.getStatus() + ")");\r
-          }\r
-          text.append("; ");\r
+        if (sf.getStatus() != null && sf.getStatus().length() > 0)\r
+        {\r
+          featureText.append(" (" + sf.getStatus() + ")");\r
         }\r
+        featureText.append("\n");\r
 \r
         index++;\r
-\r
       }\r
+\r
+\r
+        if (tooltip == null)\r
+          tooltip = new Tooltip(featureText.toString(), seqCanvas);\r
+        else\r
+          tooltip.setTip(featureText.toString());\r
+\r
+        tooltip.repaint();\r
+\r
+     //   text.append(" Sequence Feature:");\r
+     //   text.append(featureText);\r
+\r
     }\r
 \r
+\r
      ap.alignFrame.statusBar.setText(text.toString());\r
 \r
   }\r
 \r
+  Vector getAllFeaturesAtRes(SequenceI seq, int res)\r
+  {\r
+    Vector allFeatures = new Vector();\r
+    int index = 0;\r
+    if(seq.getSequenceFeatures()!=null)\r
+    {\r
+      while (index < seq.getSequenceFeatures().length)\r
+      {\r
+        SequenceFeature sf = seq.getSequenceFeatures()[index];\r
+        if (sf.getBegin() <= res &&\r
+            sf.getEnd() >= res)\r
+        {\r
+          if (av.featuresDisplayed.containsKey(sf.getType()))\r
+          {\r
+            allFeatures.addElement(sf);\r
+          }\r
+        }\r
+        index++;\r
+      }\r
+    }\r
+    return allFeatures;\r
+  }\r
+\r
+  Tooltip tooltip;\r
+\r
   public void mouseDragged(MouseEvent evt)\r
   {\r
     if (mouseWheelPressed)\r
@@ -1048,57 +1074,90 @@ public class SeqPanel
               allGroups[i].getEndRes() >= res)\r
           {\r
             stretchGroup = allGroups[i];\r
-            av.setSelectionGroup(stretchGroup);\r
             break;\r
           }\r
         }\r
       }\r
+      av.setSelectionGroup(stretchGroup);\r
     }\r
 \r
-    if (stretchGroup == null)\r
+    if (av.cursorMode)\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
+      seqCanvas.cursorX = findRes(evt);\r
+      seqCanvas.cursorY = findSeq(evt);\r
+      seqCanvas.repaint();\r
+      return;\r
     }\r
 \r
+\r
+\r
     // DETECT RIGHT MOUSE BUTTON IN AWT\r
-    else if ( (evt.getModifiers() & InputEvent.BUTTON3_MASK) ==\r
+    if ( (evt.getModifiers() & InputEvent.BUTTON3_MASK) ==\r
              InputEvent.BUTTON3_MASK)\r
     {\r
-      APopupMenu popup = new APopupMenu(ap, null, null);\r
+      Vector allFeatures = getAllFeaturesAtRes(sequence,\r
+                                               sequence.findPosition(res));\r
+\r
+      Vector links = null;\r
+      if(allFeatures!=null)\r
+      {\r
+        for (int i = 0; i < allFeatures.size(); i++)\r
+        {\r
+          SequenceFeature sf = (SequenceFeature) allFeatures.elementAt(i);\r
+          if (sf.links != null)\r
+          {\r
+            links = new Vector();\r
+            for (int j = 0; j < sf.links.size(); j++)\r
+            {\r
+              links.addElement(sf.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
+      ap.repaint();\r
     }\r
-\r
-    if (stretchGroup != null && stretchGroup.getEndRes() == res)\r
+    else\r
     {\r
-      // Edit end res position of selected group\r
-      changeEndRes = true;\r
-    }\r
+      //Only if left mouse button do we want to change group sizes\r
 \r
-    else if (stretchGroup != null && stretchGroup.getStartRes() == res)\r
-    {\r
-      // Edit end res position of selected group\r
-      changeStartRes = true;\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
+      if (stretchGroup != null && stretchGroup.getEndRes() == res)\r
+      {\r
+        // Edit end res position of selected group\r
+        changeEndRes = true;\r
+      }\r
+\r
+      else if (stretchGroup != null && stretchGroup.getStartRes() == res)\r
+      {\r
+        // Edit end res position of selected group\r
+        changeStartRes = true;\r
+      }\r
+    }\r
   }\r
 \r
   public void doMouseReleasedDefineMode(MouseEvent evt)\r