Merge branch 'bug/JAL-2934proportionalScrolling' into develop
[jalview.git] / src / jalview / gui / IdPanel.java
index 298d265..3fff67b 100755 (executable)
  */
 package jalview.gui;
 
-import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceGroup;
-import jalview.datamodel.SequenceI;
-import jalview.gui.SeqPanel.MousePos;
-import jalview.io.SequenceAnnotationReport;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.viewmodel.AlignmentViewport;
-import jalview.viewmodel.ViewportRanges;
-
 import java.awt.BorderLayout;
+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;
@@ -41,8 +31,20 @@ import java.util.List;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.SwingUtilities;
+import javax.swing.Timer;
 import javax.swing.ToolTipManager;
 
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.gui.SeqPanel.MousePos;
+import jalview.io.SequenceAnnotationReport;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
+
 /**
  * This panel hosts alignment sequence ids and responds to mouse clicks on them,
  * as well as highlighting ids matched by a search from the Find menu.
@@ -58,8 +60,6 @@ public class IdPanel extends JPanel
 
   ScrollThread scrollThread = null;
 
-  String linkImageURL;
-
   int offy;
 
   // int width;
@@ -80,8 +80,7 @@ public class IdPanel extends JPanel
     this.av = av;
     alignPanel = parent;
     setIdCanvas(new IdCanvas(av));
-    linkImageURL = getClass().getResource("/images/link.gif").toString();
-    seqAnnotReport = new SequenceAnnotationReport(linkImageURL);
+    seqAnnotReport = new SequenceAnnotationReport(true);
     setLayout(new BorderLayout());
     add(getIdCanvas(), BorderLayout.CENTER);
     addMouseListener(this);
@@ -127,8 +126,7 @@ public class IdPanel extends JPanel
 
         StringBuilder text = new StringBuilder();
         text.append("Sequence ").append(String.valueOf(seq + 1))
-                .append(" ID: ")
-                .append(sequence.getName());
+                .append(" ID: ").append(sequence.getName());
         alignPanel.alignFrame.setStatus(text.toString());
       }
     }
@@ -215,17 +213,25 @@ public class IdPanel extends JPanel
   }
 
   /**
-   * DOCUMENT ME!
+   * On (re-)entering the panel, stop any scrolling
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void mouseEntered(MouseEvent e)
   {
+    stopScrolling();
+  }
+
+  /**
+   * Interrupts the scroll thread if one is running
+   */
+  void stopScrolling()
+  {
     if (scrollThread != null)
     {
       scrollThread.stopScrolling();
+      scrollThread = null;
     }
   }
 
@@ -243,16 +249,72 @@ public class IdPanel extends JPanel
       return;
     }
 
-    if (mouseDragging && (e.getY() < 0)
-            && (av.getRanges().getStartSeq() > 0))
+    if (mouseDragging)
     {
-      scrollThread = new ScrollThread(true);
+      /*
+       * on mouse drag above or below the panel, start 
+       * scrolling if there are more sequences to show
+       */
+      ViewportRanges ranges = av.getRanges();
+      if (e.getY() < 0 && ranges.getStartSeq() > 0)
+      {
+        startScrolling(true);
+      }
+      else if (e.getY() >= getHeight()
+              && ranges.getEndSeq() <= av.getAlignment().getHeight())
+      {
+        startScrolling(false);
+      }
     }
+  }
 
-    if (mouseDragging && (e.getY() >= getHeight())
-            && (av.getAlignment().getHeight() > av.getRanges().getEndSeq()))
+  /**
+   * Starts scrolling either up or down
+   * 
+   * @param up
+   */
+  void startScrolling(boolean up)
+  {
+    scrollThread = new ScrollThread(up);
+    if (Platform.isJS())
     {
-      scrollThread = new ScrollThread(false);
+      /*
+       * for JalviewJS using Swing Timer
+       */
+      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)
+          {
+            // IdPanel.stopScrolling called
+            t.stop();
+          }
+        }
+      });
+      t.start();
+    }
+    else
+    /**
+     * Java only
+     * 
+     * @j2sIgnore
+     */
+    {
+      scrollThread.start();
     }
   }
 
@@ -278,7 +340,7 @@ public class IdPanel extends JPanel
     }
 
     MousePos pos = alignPanel.getSeqPanel().findMousePosition(e);
-    
+
     if (e.isPopupTrigger()) // Mac reports this in mousePressed
     {
       showPopupMenu(e, pos);
@@ -290,7 +352,7 @@ public class IdPanel extends JPanel
      * (where isPopupTrigger() will answer true)
      * NB isRightMouseButton is also true for Cmd-click on Mac
      */
-    if (SwingUtilities.isRightMouseButton(e) && !Platform.isAMac())
+    if (Platform.isWinRightButton(e))
     {
       return;
     }
@@ -332,28 +394,12 @@ public class IdPanel extends JPanel
     }
 
     Sequence sq = (Sequence) av.getAlignment().getSequenceAt(pos.seqIndex);
-
-    /*
-     *  build a new links menu based on the current links
-     *  and any non-positional features
-     */
-    List<SequenceFeature> features = null;
     if (sq != null)
     {
-    List<String> nlinks = Preferences.sequenceUrlLinks.getLinksForMenu();
-      features = sq.getFeatures().getNonPositionalFeatures();
-    for (SequenceFeature sf : features)
-    {
-      if (sf.links != null)
-      {
-        nlinks.addAll(sf.links);
-      }
-    }
+      PopupMenu pop = new PopupMenu(alignPanel, sq,
+              Preferences.getGroupURLLinks());
+      pop.show(this, e.getX(), e.getY());
     }
-
-    PopupMenu pop = new PopupMenu(alignPanel, sq, features,
-            Preferences.getGroupURLLinks());
-    pop.show(this, e.getX(), e.getY());
   }
 
   /**
@@ -448,7 +494,7 @@ public class IdPanel extends JPanel
   {
     if (scrollThread != null)
     {
-      scrollThread.stopScrolling();
+      stopScrolling();
     }
     MousePos pos = alignPanel.getSeqPanel().findMousePosition(e);
 
@@ -517,7 +563,6 @@ public class IdPanel extends JPanel
     {
       this.up = up;
       setName("IdPanel$ScrollThread$" + String.valueOf(up));
-      start();
     }
 
     /**
@@ -532,7 +577,7 @@ public class IdPanel extends JPanel
      * Scrolls the alignment either up or down, one row at a time, adding newly
      * visible sequences to the current selection. Speed is limited to a maximum
      * of ten rows per second. The thread exits when the end of the alignment is
-     * reached or a flag is set to stop it.
+     * reached or a flag is set to stop it by a call to stopScrolling.
      */
     @Override
     public void run()
@@ -541,25 +586,7 @@ public class IdPanel extends JPanel
 
       while (running)
       {
-        ViewportRanges ranges = IdPanel.this.av.getRanges();
-        if (ranges.scrollUp(up))
-        {
-          int toSeq = up ? ranges.getStartSeq() : ranges.getEndSeq();
-          int fromSeq = toSeq < lastid ? lastid - 1 : lastid + 1;
-          IdPanel.this.selectSeqs(fromSeq, toSeq);
-
-          lastid = toSeq;
-        }
-        else
-        {
-          /*
-           * scroll did nothing - reached limit of visible alignment
-           */
-          running = false;
-        }
-
-        alignPanel.paintAlignment(false, false);
-
+        running = scrollOnce();
         try
         {
           Thread.sleep(100);
@@ -567,6 +594,27 @@ public class IdPanel extends JPanel
         {
         }
       }
+      IdPanel.this.scrollThread = null;
+    }
+
+    /**
+     * Scrolls one row up or down. Answers true if a scroll could be done, false
+     * if not (top or bottom of alignment reached).
+     */
+    boolean scrollOnce()
+    {
+      ViewportRanges ranges = IdPanel.this.av.getRanges();
+      if (ranges.scrollUp(up))
+      {
+        int toSeq = up ? ranges.getStartSeq() : ranges.getEndSeq();
+        int fromSeq = toSeq < lastid ? lastid - 1 : lastid + 1;
+        IdPanel.this.selectSeqs(fromSeq, toSeq);
+        lastid = toSeq;
+        alignPanel.paintAlignment(false, false);
+        return true;
+      }
+
+      return false;
     }
   }
 }