import jalview.api.AlignViewportI;
import jalview.bin.Cache;
+import jalview.bin.Jalview;
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.commands.EditCommand.Edit;
import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.viewmodel.AlignmentViewport;
+import jalview.viewmodel.ViewportRanges;
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 javax.swing.JPanel;
import javax.swing.JToolTip;
import javax.swing.SwingUtilities;
+import javax.swing.Timer;
import javax.swing.ToolTipManager;
/**
return;
}
- if (!editingSeqs)
+ if (editingSeqs)
+ {
+ endEditing();
+ }
+ else
{
doMouseReleasedDefineMode(evt, didDrag);
- return;
}
-
- endEditing();
}
/**
ap.setToScrollComplementPanel(true);
}
- boolean noFastPaint = wasScrolled && av.getWrapAlignment();
- if (seqCanvas.highlightSearchResults(results, noFastPaint))
+ boolean fastPaint = !(wasScrolled && av.getWrapAlignment());
+ if (seqCanvas.highlightSearchResults(results, fastPaint))
{
setStatusMessage(results);
}
}
mouseDragging = true;
- if ((scrollThread != null) && (scrollThread.isRunning()))
+ if (scrollThread != null)
{
- scrollThread.setEvent(evt);
+ scrollThread.setMousePosition(evt.getPoint());
}
}
}
/**
- * DOCUMENT ME!
+ * On reentering the panel, stops any scrolling that was started on dragging
+ * out of the panel
*
* @param e
- * DOCUMENT ME!
*/
@Override
public void mouseEntered(MouseEvent e)
{
oldSeq = 0;
}
-
- if ((scrollThread != null) && (scrollThread.isRunning()))
- {
- scrollThread.stopScrolling();
- scrollThread = null;
- }
+ stopScrolling();
}
/**
- * DOCUMENT ME!
+ * On leaving the panel, if the mouse is being dragged, starts a thread to
+ * scroll it until the mouse is released (in unwrapped mode only)
*
* @param e
- * DOCUMENT ME!
*/
@Override
public void mouseExited(MouseEvent e)
{
- if (av.getWrapAlignment())
+ if (mouseDragging)
{
- return;
- }
-
- if (mouseDragging && scrollThread == null)
- {
- scrollThread = new ScrollThread();
+ startScrolling(e.getPoint());
}
}
SearchResultsI highlight = new SearchResults();
highlight.addResult(sequence, features.get(0).getBegin(), features
.get(0).getEnd());
- seqCanvas.highlightSearchResults(highlight, false);
+ seqCanvas.highlightSearchResults(highlight, true);
/*
- * open the Amend Features dialog; clear highlighting afterwards,
- * whether changes were made or not
+ * open the Amend Features dialog
*/
- List<SequenceI> seqs = Collections.singletonList(sequence);
- seqCanvas.getFeatureRenderer().amendFeatures(seqs, features, false,
- ap, new Runnable() {@Override
- public void run()
- {
- av.setSearchResults(null); // clear highlighting
- seqCanvas.repaint(); // draw new/amended features
- }});
+ new FeatureEditor(ap, Collections.singletonList(sequence), features,
+ false).showDialog();
}
}
}
return;
}
- if (res >= av.getAlignment().getWidth())
- {
- res = av.getAlignment().getWidth() - 1;
- }
+ res = Math.min(res, av.getAlignment().getWidth()-1);
if (stretchGroup.getEndRes() == res)
{
mouseDragging = true;
- if ((scrollThread != null) && (scrollThread.isRunning()))
+ if (scrollThread != null)
{
- scrollThread.setEvent(evt);
+ scrollThread.setMousePosition(evt.getPoint());
}
}
- void scrollCanvas(MouseEvent evt)
+ /**
+ * Stops the scroll thread if it is running
+ */
+ void stopScrolling()
{
- if (evt == null)
+ if (scrollThread != null)
{
- if ((scrollThread != null) && (scrollThread.isRunning()))
- {
- scrollThread.stopScrolling();
- scrollThread = null;
- }
- mouseDragging = false;
+ scrollThread.stopScrolling();
+ scrollThread = null;
}
- else
+ mouseDragging = false;
+ }
+
+ /**
+ * Starts a thread to scroll the alignment, towards a given mouse position
+ * outside the panel bounds, unless the alignment is in wrapped mode
+ *
+ * @param mousePos
+ */
+ void startScrolling(Point mousePos)
+ {
+ /*
+ * set this.mouseDragging in case this was called from
+ * a drag in ScalePanel or AnnotationPanel
+ */
+ mouseDragging = true;
+ if (!av.getWrapAlignment() && scrollThread == null)
{
- if (scrollThread == null)
+ scrollThread = new ScrollThread();
+ scrollThread.setMousePosition(mousePos);
+ if (!Jalview.isJS())
{
- scrollThread = new ScrollThread();
+ /*
+ * 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.setEvent(evt);
}
-
}
- // this class allows scrolling off the bottom of the visible alignment
+ /**
+ * 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
{
- MouseEvent evt;
+ private Point mousePos;
- private volatile boolean threadRunning = true;
+ private volatile boolean keepRunning = true;
+ /**
+ * Constructor
+ */
public ScrollThread()
{
- start();
+ setName("SeqPanel$ScrollThread");
}
- public void setEvent(MouseEvent e)
+ /**
+ * Sets the position of the mouse that determines the direction of the
+ * 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
+ */
+ public void setMousePosition(Point p)
{
- evt = e;
+ mousePos = p;
}
+ /**
+ * Sets a flag that will cause the thread to exit
+ */
public void stopScrolling()
{
- threadRunning = false;
- }
-
- public boolean isRunning()
- {
- return threadRunning;
+ keepRunning = false;
}
+ /**
+ * Scrolls the alignment left or right, and/or up or down, depending on the
+ * last notified mouse position, until the limit of the alignment is
+ * reached, or a flag is set to stop the scroll
+ */
@Override
public void run()
{
- while (threadRunning)
+ while (keepRunning)
{
- if (evt != null)
+ if (mousePos != null)
{
- if (mouseDragging && (evt.getY() < 0)
- && (av.getRanges().getStartSeq() > 0))
- {
- av.getRanges().scrollUp(true);
- }
-
- if (mouseDragging && (evt.getY() >= getHeight()) && (av
- .getAlignment().getHeight() > av.getRanges().getEndSeq()))
- {
- av.getRanges().scrollUp(false);
- }
-
- if (mouseDragging && (evt.getX() < 0))
- {
- av.getRanges().scrollRight(false);
- }
- else if (mouseDragging && (evt.getX() >= getWidth()))
- {
- av.getRanges().scrollRight(true);
- }
+ keepRunning = scrollOnce();
}
-
try
{
Thread.sleep(20);
{
}
}
+ 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;
}
}