JAL-3583 consistent last[Formatted]Tooltip, show once only per residue
[jalview.git] / src / jalview / gui / SeqPanel.java
index 18e9365..f433aec 100644 (file)
  */
 package jalview.gui;
 
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JToolTip;
+import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import javax.swing.ToolTipManager;
+
 import jalview.api.AlignViewportI;
 import jalview.bin.Cache;
 import jalview.commands.EditCommand;
@@ -53,29 +76,6 @@ import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Point;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
-import java.awt.event.MouseWheelEvent;
-import java.awt.event.MouseWheelListener;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JToolTip;
-import javax.swing.SwingUtilities;
-import javax.swing.Timer;
-import javax.swing.ToolTipManager;
-
 /**
  * DOCUMENT ME!
  * 
@@ -216,9 +216,19 @@ public class SeqPanel extends JPanel
 
   private final SequenceAnnotationReport seqARep;
 
-  StringBuilder tooltipText = new StringBuilder();
+  /*
+   * the last tooltip on mousing over the alignment (or annotation in wrapped mode)
+   * - the tooltip is not set again if unchanged
+   * - this is the tooltip text _before_ formatting as html
+   */
+  private String lastTooltip;
 
-  String tmpString;
+  /*
+   * the last tooltip on mousing over the alignment (or annotation in wrapped mode)
+   * - used to decide where to place the tooltip in getTooltipLocation() 
+   * - this is the tooltip text _after_ formatting as html
+   */
+  private String lastFormattedTooltip;
 
   EditCommand editCommand;
 
@@ -822,8 +832,6 @@ public class SeqPanel extends JPanel
 
   String lastMessage;
 
-  private String formattedTooltipText;
-
   @Override
   public void mouseOverSequence(SequenceI sequence, int index, int pos)
   {
@@ -984,8 +992,10 @@ public class SeqPanel extends JPanel
       /*
        * just a pixel move without change of 'cell'
        */
+      moveTooltip = false;
       return;
     }
+    moveTooltip = true;
     lastMousePosition = mousePos;
 
     if (mousePos.isOverAnnotation())
@@ -1001,6 +1011,7 @@ public class SeqPanel extends JPanel
       lastMousePosition = null;
       setToolTipText(null);
       lastTooltip = null;
+      lastFormattedTooltip = null;
       ap.alignFrame.setStatus("");
       return;
     }
@@ -1022,7 +1033,7 @@ public class SeqPanel extends JPanel
       mouseOverSequence(sequence, column, pos);
     }
 
-    tooltipText.setLength(6); // "<html>"
+    StringBuilder tooltipText = new StringBuilder(64);
 
     SequenceGroup[] groups = av.getAlignment().findAllGroups(sequence);
     if (groups != null)
@@ -1083,7 +1094,7 @@ public class SeqPanel extends JPanel
         }
       }
     }
-    if (tooltipText.length() == 6) // "<html>"
+    if (tooltipText.length() == 0) // nothing added
     {
       setToolTipText(null);
       lastTooltip = null;
@@ -1103,12 +1114,12 @@ public class SeqPanel extends JPanel
                 .append("</i>");
       }
       String textString = tooltipText.toString();
-      if (lastTooltip == null || !lastTooltip.equals(textString))
+      if (!textString.equals(lastTooltip))
       {
-        formattedTooltipText = JvSwingUtils.wrapTooltip(true,
-                textString);
-        setToolTipText(formattedTooltipText);        
         lastTooltip = textString;
+        lastFormattedTooltip = JvSwingUtils.wrapTooltip(true,
+                textString);
+        setToolTipText(lastFormattedTooltip);
       }
     }
   }
@@ -1134,16 +1145,35 @@ public class SeqPanel extends JPanel
 
     String tooltip = AnnotationPanel.buildToolTip(anns[rowIndex], column,
             anns);
-    setToolTipText(tooltip);
-    lastTooltip = tooltip;
+    if (true || !tooltip.equals(lastTooltip))
+    {
+      System.out.println("wrapped tooltip set");
+      lastTooltip = tooltip;
+      lastFormattedTooltip = tooltip == null ? null
+              : JvSwingUtils.wrapTooltip(true, tooltip);
+      setToolTipText(lastFormattedTooltip);
+    }
 
     String msg = AnnotationPanel.getStatusMessage(av.getAlignment(), column,
             anns[rowIndex]);
     ap.alignFrame.setStatus(msg);
   }
 
-  private Point lastp = null;
+  /*
+   * if Shift key is held down while moving the mouse, 
+   * the tooltip location is not changed once shown
+   */
+  private Point lastTooltipLocation = null;
+
+  /*
+   * this flag is false for pixel moves within a residue,
+   * to reduce tooltip flicker
+   */
+  private boolean moveTooltip = true;
 
+  /*
+   * a dummy tooltip used to estimate where to position tooltips
+   */
   private JToolTip tempTip = new JLabel().createToolTip();
 
   /*
@@ -1156,33 +1186,30 @@ public class SeqPanel extends JPanel
   {
     // BH 2018
 
-    if (tooltipText == null || tooltipText.length() <= 6)
+    if (lastTooltip == null || !moveTooltip)
     {
       return null;
     }
 
-    if (lastp != null && event.isShiftDown())
+    if (lastTooltipLocation != null && event.isShiftDown())
     {
-      return lastp;
+      return lastTooltipLocation;
     }
 
-    Point p = lastp;
     int x = event.getX();
     int y = event.getY();
     int w = getWidth();
 
-    tempTip.setTipText(formattedTooltipText);
+    tempTip.setTipText(lastFormattedTooltip);
     int tipWidth = (int) tempTip.getPreferredSize().getWidth();
     
     // was      x += (w - x < 200) ? -(w / 2) : 5;
     x = (x + tipWidth < w ? x + 10 : w - tipWidth);
-    p = new Point(x, y + 20); // BH 2018 was - 20?
+    Point p = new Point(x, y + av.getCharHeight()); // BH 2018 was - 20?
 
-    return lastp = p;
+    return lastTooltipLocation = p;
   }
 
-  String lastTooltip;
-
   /**
    * set when the current UI interaction has resulted in a change that requires
    * shading in overviews and structures to be recalculated. this could be