better tooltip display and placement, cope with linkOnly features (hack) and safer...
[jalview.git] / src / jalview / gui / SeqPanel.java
index bdfcef4..336532c 100755 (executable)
@@ -22,6 +22,7 @@ import java.util.*;
 
 import java.awt.*;
 import java.awt.event.*;
+
 import javax.swing.*;
 
 import jalview.commands.*;
@@ -36,7 +37,8 @@ import jalview.structure.*;
  * @version $Revision$
  */
 public class SeqPanel extends JPanel implements MouseListener,
-        MouseMotionListener, MouseWheelListener, SequenceListener
+        MouseMotionListener, MouseWheelListener, SequenceListener,
+        SelectionListener
 
 {
   /** DOCUMENT ME!! */
@@ -124,6 +126,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       addMouseWheelListener(this);
       ssm = StructureSelectionManager.getStructureSelectionManager();
       ssm.addStructureViewerListener(this);
+      ssm.addSelectionListener(this);
     }
   }
 
@@ -455,6 +458,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
 
     ap.paintAlignment(false);
+    av.sendSelection();
   }
 
   void insertGapAtCursor(boolean group)
@@ -605,6 +609,10 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   public void highlightSequence(SearchResults results)
   {
+    if (av.followHighlight)
+    {
+      ap.scrollToPosition(results, false);
+    }
     seqCanvas.highlightSearchResults(results);
   }
 
@@ -679,42 +687,98 @@ public class SeqPanel extends JPanel implements MouseListener,
     // use aa to see if the mouse pointer is on a
     if (av.showSequenceFeatures)
     {
+      int rpos;
       SequenceFeature[] features = findFeaturesAtRes(sequence
-              .getDatasetSequence(), sequence.findPosition(res));
+              .getDatasetSequence(), rpos = sequence.findPosition(res));
+      appendFeatures(tooltipText, linkImageURL.toString(), rpos, features);
+    }
+    if (tooltipText.length() == 6) // <html></html>
+    {
+      setToolTipText(null);
+      lastTooltip = null;
+    }
+    else
+    {
+      tooltipText.append("</html>");
+      if (lastTooltip == null
+              || !lastTooltip.equals(tooltipText.toString()))
+      {
+        setToolTipText(tooltipText.toString());
+        lastTooltip = tooltipText.toString();
+      }
+      
+    }
+    
+  }
 
-      if (features != null)
+  /* (non-Javadoc)
+   * @see javax.swing.JComponent#getToolTipLocation(java.awt.event.MouseEvent)
+   */
+  public Point getToolTipLocation(MouseEvent event)
+  {
+    int x=event.getX(),w=getWidth();
+    int wdth = (w-x<200) ? -(w/2) : 5; // switch sides when tooltip is too close to edge
+    Point p = (tooltipText!=null && tooltipText.length()>6) ?
+            new Point(event.getX()+wdth, event.getY()-20) : null; 
+        /* TODO: try to modify position region is not obcured by tooltip
+       */
+    return p;
+  }
+
+  /**
+   * appends the features at rpos to the given stringbuffer ready for display in
+   * a tooltip
+   * 
+   * @param tooltipText2
+   * @param linkImageURL
+   * @param rpos
+   * @param features
+   *                TODO refactor to Jalview 'utilities' somehow.
+   */
+  public static void appendFeatures(StringBuffer tooltipText2,
+          String linkImageURL, int rpos, SequenceFeature[] features)
+  {
+    String tmpString;
+    if (features != null)
+    {
+      for (int i = 0; i < features.length; i++)
       {
-        for (int i = 0; i < features.length; i++)
+        if (features[i].getType().equals("disulfide bond"))
         {
-          if (features[i].getType().equals("disulfide bond"))
+          if (features[i].getBegin() == rpos
+                  || features[i].getEnd() == rpos)
           {
-            if (features[i].getBegin() == sequence.findPosition(res)
-                    || features[i].getEnd() == sequence.findPosition(res))
+            if (tooltipText2.length() > 6)
             {
-              if (tooltipText.length() > 6)
-              {
-                tooltipText.append("<br>");
-              }
-              tooltipText.append("disulfide bond " + features[i].getBegin()
-                      + ":" + features[i].getEnd());
-              if (features[i].links != null)
-              {
-                tooltipText.append(" <img src=\"" + linkImageURL + "\">");
-              }
+              tooltipText2.append("<br>");
+            }
+            tooltipText2.append("disulfide bond " + features[i].getBegin()
+                    + ":" + features[i].getEnd());
+            if (features[i].links != null)
+            {
+              tooltipText2.append(" <img src=\"" + linkImageURL + "\">");
             }
           }
-          else
+        }
+        else
+        {
+          if (tooltipText2.length() > 6)
+          {
+            tooltipText2.append("<br>");
+          }
+          // TODO: remove this hack to display link only features
+          boolean linkOnly = features[i].getValue("linkonly") != null;
+          if (!linkOnly)
           {
-            if (tooltipText.length() > 6)
+            tooltipText2.append(features[i].getType() + " ");
+            if (rpos != 0)
             {
-              tooltipText.append("<br>");
+              // we are marking a positional feature
+              tooltipText2.append(features[i].begin);
             }
-
-            tooltipText.append(features[i].getType() + " "
-                    + features[i].begin);
             if (features[i].begin != features[i].end)
             {
-              tooltipText.append(" " + features[i].end);
+              tooltipText2.append(" " + features[i].end);
             }
 
             if (features[i].getDescription() != null
@@ -740,7 +804,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
               if (startTag > -1)
               {
-                tooltipText.append("; " + tmpString);
+                tooltipText2.append("; " + tmpString);
               }
               else
               {
@@ -752,50 +816,40 @@ public class SeqPanel extends JPanel implements MouseListener,
                   tmpString = tmpString.replaceAll("<", "&lt;");
                   tmpString = tmpString.replaceAll(">", "&gt;");
 
-                  tooltipText.append("; ");
-                  tooltipText.append(tmpString);
+                  tooltipText2.append("; ");
+                  tooltipText2.append(tmpString);
 
                 }
                 else
                 {
-                  tooltipText.append("; " + tmpString);
+                  tooltipText2.append("; " + tmpString);
                 }
               }
             }
+            // TODO: check min/max range for this feature type to decide if
+            // score should be shown
+            if (features[i].getScore() != Float.NaN)
+            {
+              tooltipText2.append(" Score=" + features[i].getScore());
+            }
             if (features[i].getValue("status") != null)
             {
               String status = features[i].getValue("status").toString();
               if (status.length() > 0)
               {
-                tooltipText.append("; (" + features[i].getValue("status")
+                tooltipText2.append("; (" + features[i].getValue("status")
                         + ")");
               }
             }
-
-            if (features[i].links != null)
-            {
-              tooltipText.append(" <img src=\"" + linkImageURL + "\">");
-            }
-
           }
+          if (features[i].links != null)
+          {
+            tooltipText2.append(" <img src=\"" + linkImageURL + "\">");
+          }
+
         }
       }
     }
-
-    if (tooltipText.length() == 6) // <html></html>
-    {
-      setToolTipText(null);
-    }
-    else
-    {
-      tooltipText.append("</html>");
-      if (lastTooltip == null
-              || !lastTooltip.equals(tooltipText.toString()))
-        setToolTipText(tooltipText.toString());
-
-      lastTooltip = tooltipText.toString();
-    }
-
   }
 
   String lastTooltip;
@@ -1514,6 +1568,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       sg.setEndRes(res);
       sg.addSequence(sequence, false);
       av.setSelectionGroup(sg);
+
       stretchGroup = sg;
 
       if (av.getConservationSelected())
@@ -1591,7 +1646,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     changeEndRes = false;
     changeStartRes = false;
     stretchGroup = null;
-
+    av.sendSelection();
   }
 
   /**
@@ -1791,4 +1846,58 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
     }
   }
+
+  /**
+   * modify current selection according to a received message.
+   */
+  public void selection(SequenceGroup seqsel, ColumnSelection colsel,
+          SelectionSource source)
+  {
+    // TODO: fix this hack - source of messages is align viewport, but SeqPanel
+    // handles selection messages...
+    if (av == source)
+    {
+      return;
+    }
+    // do we want to thread this ? (contention with seqsel and colsel locks, I
+    // suspect)
+    boolean repaint = false;
+    if (av.followSelection)
+    {
+      if (av.selectionGroup == null || !av.isSelectionGroupChanged())
+      {
+        SequenceGroup sgroup = (seqsel != null) ? seqsel.intersect(
+                av.alignment, (av.hasHiddenRows) ? av.hiddenRepSequences
+                        : null) : null;
+        if (sgroup != null && sgroup.getSize() > 0)
+        {
+          av.setSelectionGroup(sgroup);
+        }
+        else
+        {
+          av.setSelectionGroup(null);
+        }
+        repaint = av.isSelectionGroupChanged();
+      }
+      if (av.colSel == null || !av.isColSelChanged())
+      {
+        // Check to see if the current selection is from a previous message
+        if (colsel == null || colsel.size() == 0)
+        {
+          av.colSel.clear();
+        }
+        else
+        {
+          av.colSel = new ColumnSelection(colsel);
+        }
+        repaint |= av.isColSelChanged();
+      }
+    }
+    if (repaint)
+    {
+      // probably finessing with multiple redraws here
+      PaintRefresher.Refresh(this, av.getSequenceSetId());
+      // ap.paintAlignment(false);
+    }
+  }
 }