X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqPanel.java;h=454a73051a77a8330cb266217aae401a950931b7;hb=9d2408483e451285fd555c3cd6e0273977acbaa7;hp=14ec6e9508e8bfd2a5793351285ce5364248d79a;hpb=c735d0c34c8315c3bd86a7f6bf3c28a21c69b1fb;p=jalview.git diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 14ec6e9..454a730 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -20,6 +20,29 @@ */ 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; @@ -29,6 +52,7 @@ import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; +import jalview.datamodel.MappedFeatures; import jalview.datamodel.SearchResultMatchI; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; @@ -49,23 +73,8 @@ import jalview.util.MappingUtils; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.viewmodel.AlignmentViewport; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Point; -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.Collections; -import java.util.List; - -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.ToolTipManager; +import jalview.viewmodel.ViewportRanges; +import jalview.viewmodel.seqfeatures.FeatureRendererModel; /** * DOCUMENT ME! @@ -113,6 +122,11 @@ public class SeqPanel extends JPanel annotationIndex = ann; } + boolean isOverAnnotation() + { + return annotationIndex != -1; + } + @Override public boolean equals(Object obj) { @@ -159,9 +173,9 @@ public class SeqPanel extends JPanel */ private MousePos lastMousePosition; - protected int lastres; + protected int editLastRes; - protected int startseq; + protected int editStartSeq; protected AlignViewport av; @@ -198,13 +212,21 @@ public class SeqPanel extends JPanel StringBuffer keyboardNo2; - java.net.URL linkImageURL; - 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; @@ -220,11 +242,12 @@ public class SeqPanel extends JPanel */ public SeqPanel(AlignViewport viewport, AlignmentPanel alignPanel) { - linkImageURL = getClass().getResource("/images/link.gif"); - seqARep = new SequenceAnnotationReport(linkImageURL.toString()); + seqARep = new SequenceAnnotationReport(true); ToolTipManager.sharedInstance().registerComponent(this); ToolTipManager.sharedInstance().setInitialDelay(0); ToolTipManager.sharedInstance().setDismissDelay(10000); + + this.av = viewport; setBackground(Color.white); @@ -250,8 +273,11 @@ public class SeqPanel extends JPanel int wrappedBlock = -1; /** - * Computes the column and sequence row (or possibly annotation row when in + * Computes the column and sequence row (and possibly annotation row when in * wrapped mode) for the given mouse position + *
+ * Mouse position is not set if in wrapped mode with the cursor either between + * sequences, or over the left or right vertical scale. * * @param evt * @return @@ -259,7 +285,7 @@ public class SeqPanel extends JPanel MousePos findMousePosition(MouseEvent evt) { int col = findColumn(evt); - int seq = -1; + int seqIndex = -1; int annIndex = -1; int y = evt.getY(); @@ -267,51 +293,61 @@ public class SeqPanel extends JPanel int alignmentHeight = av.getAlignment().getHeight(); if (av.getWrapAlignment()) { - int hgap = charHeight; - if (av.getScaleAboveWrapped()) - { - hgap += charHeight; - } + seqCanvas.calculateWrappedGeometry(seqCanvas.getWidth(), + seqCanvas.getHeight()); - final int alignmentHeightPixels = alignmentHeight * charHeight + hgap; - final int annotationHeight = seqCanvas.getAnnotationHeight(); - final int cHeight = alignmentHeightPixels + annotationHeight; + /* + * yPos modulo height of repeating width + */ + int yOffsetPx = y % seqCanvas.wrappedRepeatHeightPx; - int yOffsetPx = y % cHeight; // yPos below repeating width(s) - if (yOffsetPx > alignmentHeightPixels) + /* + * height of sequences plus space / scale above, + * plus gap between sequences and annotations + */ + int alignmentHeightPixels = seqCanvas.wrappedSpaceAboveAlignment + + alignmentHeight * charHeight + + SeqCanvas.SEQS_ANNOTATION_GAP; + if (yOffsetPx >= alignmentHeightPixels) { /* - * mouse is over annotations + * mouse is over annotations; find annotation index, also set + * last sequence above (for backwards compatible behaviour) */ AlignmentAnnotation[] anns = av.getAlignment() .getAlignmentAnnotation(); int rowOffsetPx = yOffsetPx - alignmentHeightPixels; annIndex = AnnotationPanel.getRowIndex(rowOffsetPx, anns); + seqIndex = alignmentHeight - 1; } else { /* * mouse is over sequence (or the space above sequences) */ - yOffsetPx -= hgap; - if (yOffsetPx > 0) + yOffsetPx -= seqCanvas.wrappedSpaceAboveAlignment; + if (yOffsetPx >= 0) { - seq = Math.min(yOffsetPx / charHeight, alignmentHeight - 1); + seqIndex = Math.min(yOffsetPx / charHeight, alignmentHeight - 1); } } } else { - seq = Math.min((y / charHeight) + av.getRanges().getStartSeq(), + ViewportRanges ranges = av.getRanges(); + seqIndex = Math.min((y / charHeight) + ranges.getStartSeq(), alignmentHeight - 1); + seqIndex = Math.min(seqIndex, ranges.getEndSeq()); } - int seqIndex = seq; return new MousePos(col, seqIndex, annIndex); } /** * Returns the aligned sequence position (base 0) at the mouse position, or * the closest visible one + *
+ * Returns -1 if in wrapped mode with the mouse over either left or right + * vertical scale. * * @param evt * @return @@ -321,10 +357,11 @@ public class SeqPanel extends JPanel int res = 0; int x = evt.getX(); - int startRes = av.getRanges().getStartRes(); + final int startRes = av.getRanges().getStartRes(); + final int charWidth = av.getCharWidth(); + if (av.getWrapAlignment()) { - int hgap = av.getCharHeight(); if (av.getScaleAboveWrapped()) { @@ -336,35 +373,40 @@ public class SeqPanel extends JPanel int y = evt.getY(); y = Math.max(0, y - hgap); - x = Math.max(0, x - seqCanvas.getLabelWidthWest()); + x -= seqCanvas.getLabelWidthWest(); + if (x < 0) + { + // mouse is over left scale + return -1; + } int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth()); if (cwidth < 1) { return 0; } + if (x >= cwidth * charWidth) + { + // mouse is over right scale + return -1; + } wrappedBlock = y / cHeight; wrappedBlock += startRes / cwidth; // allow for wrapped view scrolled right (possible from Overview) int startOffset = startRes % cwidth; res = wrappedBlock * cwidth + startOffset - + +Math.min(cwidth - 1, x / av.getCharWidth()); + + Math.min(cwidth - 1, x / charWidth); } else { - if (x > seqCanvas.getX() + seqCanvas.getWidth()) - { - // make sure we calculate relative to visible alignment, rather than - // right-hand gutter - x = seqCanvas.getX() + seqCanvas.getWidth(); - } - res = (x / av.getCharWidth()) + startRes; - if (res > av.getRanges().getEndRes()) - { - // moused off right - res = av.getRanges().getEndRes(); - } + /* + * make sure we calculate relative to visible alignment, + * rather than right-hand gutter + */ + x = Math.min(x, seqCanvas.getX() + seqCanvas.getWidth()); + res = (x / charWidth) + startRes; + res = Math.min(res, av.getRanges().getEndRes()); } if (av.hasHiddenColumns()) @@ -374,55 +416,6 @@ public class SeqPanel extends JPanel } return res; - - } - - /** - * Answers the index in the alignment (0...) of the sequence under the mouse - * position. If the mouse is below the alignment (say, over annotations), - * answers the index of the last sequence. - * - * @param evt - * @return - */ - int findSeq(MouseEvent evt) - { - int seq = 0; - int y = evt.getY(); - - int charHeight = av.getCharHeight(); - int alignmentHeight = av.getAlignment().getHeight(); - if (av.getWrapAlignment()) - { - int hgap = charHeight; - if (av.getScaleAboveWrapped()) - { - hgap += charHeight; - } - - int alignmentHeightPixels = alignmentHeight * charHeight; - int cHeight = alignmentHeightPixels + hgap - + seqCanvas.getAnnotationHeight(); - - y -= hgap; - - int yOffsetPx = y % cHeight; // yPos below repeating width(s) -// if (yOffsetPx > alignmentHeightPixels) -// { -// seq = -1; // cursor is over annotation or below alignment entirely -// } -// else - // { - seq = Math.min(yOffsetPx / charHeight, alignmentHeight - 1); -// } - } - else - { - seq = Math.min((y / charHeight) + av.getRanges().getStartSeq(), - alignmentHeight - 1); - } - - return seq; } /** @@ -444,8 +437,8 @@ public class SeqPanel extends JPanel /* * Tidy up come what may... */ - startseq = -1; - lastres = -1; + editStartSeq = -1; + editLastRes = -1; editingSeqs = false; groupEditing = false; keyboardNo1 = null; @@ -490,47 +483,80 @@ public class SeqPanel extends JPanel void moveCursor(int dx, int dy) { - seqCanvas.cursorX += dx; - seqCanvas.cursorY += dy; - + moveCursor(dx, dy,false); + } + void moveCursor(int dx, int dy, boolean nextWord) + { HiddenColumns hidden = av.getAlignment().getHiddenColumns(); - if (av.hasHiddenColumns() && !hidden.isVisible(seqCanvas.cursorX)) + if (nextWord) { - int original = seqCanvas.cursorX - dx; int maxWidth = av.getAlignment().getWidth(); - - if (!hidden.isVisible(seqCanvas.cursorX)) - { - int visx = hidden.absoluteToVisibleColumn(seqCanvas.cursorX - dx); - int[] region = hidden.getRegionWithEdgeAtRes(visx); - - if (region != null) // just in case + int maxHeight=av.getAlignment().getHeight(); + SequenceI seqAtRow = av.getAlignment().getSequenceAt(seqCanvas.cursorY); + // look for next gap or residue + boolean isGap = Comparison.isGap(seqAtRow.getCharAt(seqCanvas.cursorX)); + int p = seqCanvas.cursorX,lastP,r=seqCanvas.cursorY,lastR; + do + { + lastP = p; + lastR = r; + if (dy != 0) { - if (dx == 1) + r += dy; + if (r < 0) { - // moving right - seqCanvas.cursorX = region[1] + 1; + r = 0; } - else if (dx == -1) + if (r >= maxHeight) { - // moving left - seqCanvas.cursorX = region[0] - 1; + r = maxHeight - 1; } + seqAtRow = av.getAlignment().getSequenceAt(r); } - seqCanvas.cursorX = (seqCanvas.cursorX < 0) ? 0 : seqCanvas.cursorX; - } + p = nextVisible(hidden, maxWidth, p, dx); + } while ((dx != 0 ? p != lastP : r != lastR) + && isGap == Comparison.isGap(seqAtRow.getCharAt(p))); + seqCanvas.cursorX=p; + seqCanvas.cursorY=r; + } else { + int maxWidth = av.getAlignment().getWidth(); + seqCanvas.cursorX = nextVisible(hidden, maxWidth, seqCanvas.cursorX, dx); + seqCanvas.cursorY += dy; + } + scrollToVisible(false); + } - if (seqCanvas.cursorX >= maxWidth - || !hidden.isVisible(seqCanvas.cursorX)) + private int nextVisible(HiddenColumns hidden,int maxWidth, int original, int dx) + { + int newCursorX=original+dx; + if (av.hasHiddenColumns() && !hidden.isVisible(newCursorX)) + { + int visx = hidden.absoluteToVisibleColumn(newCursorX - dx); + int[] region = hidden.getRegionWithEdgeAtRes(visx); + + if (region != null) // just in case { - seqCanvas.cursorX = original; + if (dx == 1) + { + // moving right + newCursorX = region[1] + 1; + } + else if (dx == -1) + { + // moving left + newCursorX = region[0] - 1; + } } } - - scrollToVisible(false); + newCursorX = (newCursorX < 0) ? 0 : newCursorX; + if (newCursorX >= maxWidth + || !hidden.isVisible(newCursorX)) + { + newCursorX = original; + } + return newCursorX; } - /** * Scroll to make the cursor visible in the viewport. * @@ -673,8 +699,8 @@ public class SeqPanel extends JPanel void insertGapAtCursor(boolean group) { groupEditing = group; - startseq = seqCanvas.cursorY; - lastres = seqCanvas.cursorX; + editStartSeq = seqCanvas.cursorY; + editLastRes = seqCanvas.cursorX; editSequence(true, false, seqCanvas.cursorX + getKeyboardNo1()); endEditing(); } @@ -682,8 +708,8 @@ public class SeqPanel extends JPanel void deleteGapAtCursor(boolean group) { groupEditing = group; - startseq = seqCanvas.cursorY; - lastres = seqCanvas.cursorX + getKeyboardNo1(); + editStartSeq = seqCanvas.cursorY; + editLastRes = seqCanvas.cursorX + getKeyboardNo1(); editSequence(false, false, seqCanvas.cursorX); endEditing(); } @@ -692,8 +718,8 @@ public class SeqPanel extends JPanel { // TODO not called - delete? groupEditing = group; - startseq = seqCanvas.cursorY; - lastres = seqCanvas.cursorX; + editStartSeq = seqCanvas.cursorY; + editLastRes = seqCanvas.cursorX; editSequence(false, true, seqCanvas.cursorX + getKeyboardNo1()); endEditing(); } @@ -758,24 +784,31 @@ public class SeqPanel extends JPanel @Override public void mouseReleased(MouseEvent evt) { + MousePos pos = findMousePosition(evt); + if (pos.isOverAnnotation() || pos.seqIndex == -1 || pos.column == -1) + { + return; + } + boolean didDrag = mouseDragging; // did we come here after a drag mouseDragging = false; mouseWheelPressed = false; if (evt.isPopupTrigger()) // Windows: mouseReleased { - showPopupMenu(evt); + showPopupMenu(evt, pos); evt.consume(); return; } - if (!editingSeqs) + if (editingSeqs) + { + endEditing(); + } + else { doMouseReleasedDefineMode(evt, didDrag); - return; } - - endEditing(); } /** @@ -788,6 +821,11 @@ public class SeqPanel extends JPanel public void mousePressed(MouseEvent evt) { lastMousePress = evt.getPoint(); + MousePos pos = findMousePosition(evt); + if (pos.isOverAnnotation() || pos.seqIndex == -1 || pos.column == -1) + { + return; + } if (SwingUtilities.isMiddleMouseButton(evt)) { @@ -806,28 +844,23 @@ public class SeqPanel extends JPanel } else { - doMousePressedDefineMode(evt); + doMousePressedDefineMode(evt, pos); return; } - int seq = findSeq(evt); - int res = findColumn(evt); - - if (seq < 0 || res < 0) - { - return; - } + int seq = pos.seqIndex; + int res = pos.column; if ((seq < av.getAlignment().getHeight()) && (res < av.getAlignment().getSequenceAt(seq).getLength())) { - startseq = seq; - lastres = res; + editStartSeq = seq; + editLastRes = res; } else { - startseq = -1; - lastres = -1; + editStartSeq = -1; + editLastRes = -1; } return; @@ -855,11 +888,11 @@ public class SeqPanel extends JPanel * the start of the highlighted region. */ @Override - public void highlightSequence(SearchResultsI results) + public String highlightSequence(SearchResultsI results) { if (results == null || results.equals(lastSearchResults)) { - return; + return null; } lastSearchResults = results; @@ -872,7 +905,7 @@ public class SeqPanel extends JPanel // over residue to change abruptly, causing highlighted residue in panel 2 // to change, causing a scroll in panel 1 etc) ap.setToScrollComplementPanel(false); - wasScrolled = ap.scrollToPosition(results, false); + wasScrolled = ap.scrollToPosition(results); if (wasScrolled) { seqCanvas.revalidate(); @@ -880,11 +913,83 @@ public class SeqPanel extends JPanel 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); } + return results.isEmpty() ? null : getHighlightInfo(results); + } + + /** + * temporary hack: answers a message suitable to show on structure hover + * label. This is normally null. It is a peptide variation description if + *
+ * Delete gaps is limited to the number of gaps left of the cursor position + * (mouse drag), or at or right of the cursor position (cursor mode). + *
+ * In group editing mode (Ctrl or Cmd down), the edit acts on all sequences in + * the current selection group. + *
+ * In locked editing mode (with a selection group present), inserts/deletions
+ * within the selection group are limited to its boundaries (and edits outside
+ * the group stop at its border).
+ *
+ * @param insertGap
+ * true to insert gaps, false to delete gaps
+ * @param editSeq
+ * (unused parameter)
+ * @param startres
+ * the column at which to perform the action; the number of columns
+ * affected depends on this.editLastRes
(cursor column
+ * position)
+ */
synchronized void editSequence(boolean insertGap, boolean editSeq,
- int startres)
+ final int startres)
{
int fixedLeft = -1;
int fixedRight = -1;
boolean fixedColumns = false;
SequenceGroup sg = av.getSelectionGroup();
- SequenceI seq = av.getAlignment().getSequenceAt(startseq);
+ final SequenceI seq = av.getAlignment().getSequenceAt(editStartSeq);
// No group, but the sequence may represent a group
if (!groupEditing && av.hasHiddenRows())
@@ -1365,30 +1565,38 @@ public class SeqPanel extends JPanel
}
}
- StringBuilder message = new StringBuilder(64);
+ StringBuilder message = new StringBuilder(64); // for status bar
+
+ /*
+ * make a name for the edit action, for
+ * status bar message and Undo/Redo menu
+ */
+ String label = null;
if (groupEditing)
{
- message.append("Edit group:");
- if (editCommand == null)
- {
- editCommand = new EditCommand(
- MessageManager.getString("action.edit_group"));
- }
+ message.append("Edit group:");
+ label = MessageManager.getString("action.edit_group");
}
else
{
- message.append("Edit sequence: " + seq.getName());
- String label = seq.getName();
+ message.append("Edit sequence: " + seq.getName());
+ label = seq.getName();
if (label.length() > 10)
{
label = label.substring(0, 10);
}
- if (editCommand == null)
- {
- editCommand = new EditCommand(MessageManager
- .formatMessage("label.edit_params", new String[]
- { label }));
- }
+ label = MessageManager.formatMessage("label.edit_params",
+ new String[]
+ { label });
+ }
+
+ /*
+ * initialise the edit command if there is not
+ * already one being extended
+ */
+ if (editCommand == null)
+ {
+ editCommand = new EditCommand(label);
}
if (insertGap)
@@ -1400,12 +1608,17 @@ public class SeqPanel extends JPanel
message.append(" delete ");
}
- message.append(Math.abs(startres - lastres) + " gaps.");
- ap.alignFrame.statusBar.setText(message.toString());
+ message.append(Math.abs(startres - editLastRes) + " gaps.");
+ ap.alignFrame.setStatus(message.toString());
- // Are we editing within a selection group?
- if (groupEditing || (sg != null
- && sg.getSequences(av.getHiddenRepSequences()).contains(seq)))
+ /*
+ * is there a selection group containing the sequence being edited?
+ * if so the boundary of the group is the limit of the edit
+ * (but the edit may be inside or outside the selection group)
+ */
+ boolean inSelectionGroup = sg != null
+ && sg.getSequences(av.getHiddenRepSequences()).contains(seq);
+ if (groupEditing || inSelectionGroup)
{
fixedColumns = true;
@@ -1424,10 +1637,10 @@ public class SeqPanel extends JPanel
fixedLeft = sg.getStartRes();
fixedRight = sg.getEndRes();
- if ((startres < fixedLeft && lastres >= fixedLeft)
- || (startres >= fixedLeft && lastres < fixedLeft)
- || (startres > fixedRight && lastres <= fixedRight)
- || (startres <= fixedRight && lastres > fixedRight))
+ if ((startres < fixedLeft && editLastRes >= fixedLeft)
+ || (startres >= fixedLeft && editLastRes < fixedLeft)
+ || (startres > fixedRight && editLastRes <= fixedRight)
+ || (startres <= fixedRight && editLastRes > fixedRight))
{
endEditing();
return;
@@ -1453,8 +1666,8 @@ public class SeqPanel extends JPanel
int y2 = av.getAlignment().getHiddenColumns()
.getNextHiddenBoundary(false, startres);
- if ((insertGap && startres > y1 && lastres < y1)
- || (!insertGap && startres < y2 && lastres > y2))
+ if ((insertGap && startres > y1 && editLastRes < y1)
+ || (!insertGap && startres < y2 && editLastRes > y2))
{
endEditing();
return;
@@ -1475,6 +1688,54 @@ public class SeqPanel extends JPanel
}
}
+ boolean success = doEditSequence(insertGap, editSeq, startres,
+ fixedRight, fixedColumns, sg);
+
+ /*
+ * report what actually happened (might be less than
+ * what was requested), by inspecting the edit commands added
+ */
+ String msg = getEditStatusMessage(editCommand);
+ ap.alignFrame.setStatus(msg == null ? " " : msg);
+ if (!success)
+ {
+ endEditing();
+ }
+
+ editLastRes = startres;
+ seqCanvas.repaint();
+ }
+
+ /**
+ * A helper method that performs the requested editing to insert or delete
+ * gaps (if possible). Answers true if the edit was successful, false if could
+ * only be performed in part or not at all. Failure may occur in 'locked edit'
+ * mode, when an insertion requires a matching gapped position (or column) to
+ * delete, and deletion requires an adjacent gapped position (or column) to
+ * remove.
+ *
+ * @param insertGap
+ * true if inserting gap(s), false if deleting
+ * @param editSeq
+ * (unused parameter, currently always false)
+ * @param startres
+ * the column at which to perform the edit
+ * @param fixedRight
+ * fixed right boundary column of a locked edit (within or to the
+ * left of a selection group)
+ * @param fixedColumns
+ * true if this is a locked edit
+ * @param sg
+ * the sequence group (if group edit is being performed)
+ * @return
+ */
+ protected boolean doEditSequence(final boolean insertGap,
+ final boolean editSeq, final int startres, int fixedRight,
+ final boolean fixedColumns, final SequenceGroup sg)
+ {
+ final SequenceI seq = av.getAlignment().getSequenceAt(editStartSeq);
+ SequenceI[] seqs = new SequenceI[] { seq };
+
if (groupEditing)
{
List
+ *
+ * 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;
}
}
@@ -2445,7 +2902,7 @@ public class SeqPanel extends JPanel
* Map sequence selection
*/
SequenceGroup sg = MappingUtils.mapSequenceGroup(seqsel, sourceAv, av);
- av.setSelectionGroup(sg);
+ av.setSelectionGroup(sg != null && sg.getSize() > 0 ? sg : null);
av.isSelectionGroupChanged(true);
/*
@@ -2457,7 +2914,7 @@ public class SeqPanel extends JPanel
HiddenColumns hs = new HiddenColumns();
MappingUtils.mapColumnSelection(colsel, hidden, sourceAv, av, cs, hs);
av.setColumnSelection(cs);
- av.getAlignment().setHiddenColumns(hs);
+ boolean hiddenChanged = av.getAlignment().setHiddenColumns(hs);
// lastly, update any dependent dialogs
if (ap.getCalculationDialog() != null)
@@ -2465,7 +2922,11 @@ public class SeqPanel extends JPanel
ap.getCalculationDialog().validateCalcTypes();
}
- PaintRefresher.Refresh(this, av.getSequenceSetId());
+ /*
+ * repaint alignment, and also Overview or Structure
+ * if hidden column selection has changed
+ */
+ ap.paintAlignment(hiddenChanged, hiddenChanged);
return true;
}