final timing checks for optimization
[jalview.git] / src / jalview / gui / SeqPanel.java
index 5050150..59f239f 100644 (file)
@@ -55,6 +55,8 @@ 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;
@@ -67,6 +69,7 @@ import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JToolTip;
 import javax.swing.SwingUtilities;
+import javax.swing.Timer;
 import javax.swing.ToolTipManager;
 
 /**
@@ -820,7 +823,7 @@ public class SeqPanel extends JPanel
       mouseOverSequence(sequence, column, pos);
     }
 
-    tooltipText.setLength(6); // Cuts the buffer back to <html>
+    tooltipText.setLength(0);
 
     SequenceGroup[] groups = av.getAlignment().findAllGroups(sequence);
     if (groups != null)
@@ -856,7 +859,7 @@ public class SeqPanel extends JPanel
       seqARep.appendFeatures(tooltipText, pos, features,
               this.ap.getSeqPanel().seqCanvas.fr);
     }
-    if (tooltipText.length() == 6) // <html>
+    if (tooltipText.length() == 0) // <html>
     {
       setToolTipText(null);
       lastTooltip = null;
@@ -873,8 +876,7 @@ public class SeqPanel extends JPanel
       {
         formattedTooltipText = JvSwingUtils.wrapTooltip(true,
                 textString);
-        setToolTipText(formattedTooltipText);
-        
+        setToolTipText(formattedTooltipText);        
         lastTooltip = textString;
       }
     }
@@ -1021,7 +1023,7 @@ public class SeqPanel extends JPanel
 
       text.append(" (").append(Integer.toString(residuePos)).append(")");
     }
-    ap.alignFrame.statusBar.setText(text.toString());
+    ap.alignFrame.setStatus(text.toString());
   }
 
   /**
@@ -1248,7 +1250,7 @@ public class SeqPanel extends JPanel
     }
 
     message.append(Math.abs(startres - lastres) + " gaps.");
-    ap.alignFrame.statusBar.setText(message.toString());
+    ap.alignFrame.setStatus(message.toString());
 
     // Are we editing within a selection group?
     if (groupEditing || (sg != null
@@ -1623,9 +1625,9 @@ public class SeqPanel extends JPanel
   @Override
   public void mouseExited(MouseEvent e)
   {
-    if (!av.getWrapAlignment() && mouseDragging && scrollThread == null)
+    if (mouseDragging)
     {
-      scrollThread = new ScrollThread();
+      startScrolling(e.getPoint());
     }
   }
 
@@ -1763,22 +1765,22 @@ public class SeqPanel extends JPanel
       }
     }
 
-    if (evt.isPopupTrigger()) // Mac: mousePressed
-    {
-      showPopupMenu(evt);
-      return;
-    }
-
     /*
      * defer right-mouse click handling to mouseReleased on Windows
      * (where isPopupTrigger() will answer true)
      * NB isRightMouseButton is also true for Cmd-click on Mac
      */
-    if (SwingUtilities.isRightMouseButton(evt) && !Platform.isAMac())
+    if (Platform.isWinRightButton(evt))
     {
       return;
     }
 
+    if (evt.isPopupTrigger()) // Mac: mousePressed
+    {
+      showPopupMenu(evt);
+      return;
+    }
+
     if (av.cursorMode)
     {
       seqCanvas.cursorX = findColumn(evt);
@@ -2036,29 +2038,87 @@ public class SeqPanel extends JPanel
 
   /**
    * Starts a thread to scroll the alignment, towards a given mouse position
-   * outside the panel bounds
+   * outside the panel bounds, unless the alignment is in wrapped mode
    * 
    * @param mousePos
    */
   void startScrolling(Point mousePos)
   {
-    if (scrollThread == null)
+    /*
+     * set this.mouseDragging in case this was called from 
+     * a drag in ScalePanel or AnnotationPanel
+     */
+    mouseDragging = true;
+    if (!av.getWrapAlignment() && scrollThread == null)
     {
       scrollThread = new ScrollThread();
+      scrollThread.setMousePosition(mousePos);
+      if (!Platform.isJS())
+      {
+        /*
+         * Java - run in a new thread
+         */
+        scrollThread.start();
+      }
+      else
+      {
+        /*
+         * Javascript - run every 20ms until scrolling stopped
+         * or reaches the limit of scrollable alignment
+         */
+        // java.util.Timer version:
+        // Timer t = new Timer("ScrollThreadTimer", true);
+        // TimerTask task = new TimerTask()
+        // {
+        // @Override
+        // public void run()
+        // {
+        // if (!scrollThread.scrollOnce())
+        // {
+        // cancel();
+        // }
+        // }
+        // };
+        // t.schedule(task, 20, 20);
+        Timer t = new Timer(20, new ActionListener()
+        {
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            if (scrollThread != null)
+            {
+              // if (!scrollOnce() {t.stop();}) gives compiler error :-(
+              scrollThread.scrollOnce();
+            }
+          }
+        });
+        t.addActionListener(new ActionListener()
+        {
+          @Override
+          public void actionPerformed(ActionEvent e)
+          {
+            if (scrollThread == null)
+            {
+              // finished and nulled itself
+              t.stop();
+            }
+          }
+        });
+        t.start();
+      }
     }
-
-    mouseDragging = true;
-    scrollThread.setMousePosition(mousePos);
   }
 
   /**
-   * Performs scrolling of the visible alignment left, right, up or down
+   * Performs scrolling of the visible alignment left, right, up or down, until
+   * scrolling is stopped by calling stopScrolling, mouse drag is ended, or the
+   * limit of the alignment is reached
    */
   class ScrollThread extends Thread
   {
     private Point mousePos;
 
-    private volatile boolean threadRunning = true;
+    private volatile boolean keepRunning = true;
 
     /**
      * Constructor
@@ -2066,12 +2126,14 @@ public class SeqPanel extends JPanel
     public ScrollThread()
     {
       setName("SeqPanel$ScrollThread");
-      start();
     }
 
     /**
      * Sets the position of the mouse that determines the direction of the
-     * scroll to perform
+     * scroll to perform. If this is called as the mouse moves, scrolling should
+     * respond accordingly. For example, if the mouse is dragged right, scroll
+     * right should start; if the drag continues down, scroll down should also
+     * happen.
      * 
      * @param p
      */
@@ -2085,7 +2147,7 @@ public class SeqPanel extends JPanel
      */
     public void stopScrolling()
     {
-      threadRunning = false;
+      keepRunning = false;
     }
 
     /**
@@ -2096,48 +2158,12 @@ public class SeqPanel extends JPanel
     @Override
     public void run()
     {
-      while (threadRunning && mouseDragging)
+      while (keepRunning)
       {
         if (mousePos != null)
         {
-          boolean scrolled = false;
-          ViewportRanges ranges = SeqPanel.this.av.getRanges();
-
-          /*
-           * scroll up or down
-           */
-          if (mousePos.y < 0)
-          {
-            // mouse is above this panel - try scroll up
-            scrolled = ranges.scrollUp(true);
-          }
-          else if (mousePos.y >= getHeight())
-          {
-            // mouse is below this panel - try scroll down
-            scrolled = ranges.scrollUp(false);
-          }
-
-          /*
-           * scroll left or right
-           */
-          if (mousePos.x < 0)
-          {
-            scrolled |= ranges.scrollRight(false);
-          }
-          else if (mousePos.x >= getWidth())
-          {
-            scrolled |= ranges.scrollRight(true);
-          }
-          if (!scrolled)
-          {
-            /*
-             * we have reached the limit of the visible alignment - quit
-             */
-            threadRunning = false;
-            SeqPanel.this.ap.repaint();
-          }
+          keepRunning = scrollOnce();
         }
-
         try
         {
           Thread.sleep(20);
@@ -2145,6 +2171,60 @@ public class SeqPanel extends JPanel
         {
         }
       }
+      SeqPanel.this.scrollThread = null;
+    }
+
+    /**
+     * Scrolls
+     * <ul>
+     * <li>one row up, if the mouse is above the panel</li>
+     * <li>one row down, if the mouse is below the panel</li>
+     * <li>one column left, if the mouse is left of the panel</li>
+     * <li>one column right, if the mouse is right of the panel</li>
+     * </ul>
+     * Answers true if a scroll was performed, false if not - meaning either
+     * that the mouse position is within the panel, or the edge of the alignment
+     * has been reached.
+     */
+    boolean scrollOnce()
+    {
+      /*
+       * quit after mouseUp ensures interrupt in JalviewJS
+       */
+      if (!mouseDragging)
+      {
+        return false;
+      }
+
+      boolean scrolled = false;
+      ViewportRanges ranges = SeqPanel.this.av.getRanges();
+
+      /*
+       * scroll up or down
+       */
+      if (mousePos.y < 0)
+      {
+        // mouse is above this panel - try scroll up
+        scrolled = ranges.scrollUp(true);
+      }
+      else if (mousePos.y >= getHeight())
+      {
+        // mouse is below this panel - try scroll down
+        scrolled = ranges.scrollUp(false);
+      }
+
+      /*
+       * scroll left or right
+       */
+      if (mousePos.x < 0)
+      {
+        scrolled |= ranges.scrollRight(false);
+      }
+      else if (mousePos.x >= getWidth())
+      {
+        scrolled |= ranges.scrollRight(true);
+      }
+      return scrolled;
     }
   }