X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqPanel.java;h=54e3db731b9b6f6870e60d95276ff8dc18bcd31b;hb=7f3e371b7fbae94e9b731956cbdebc866742c692;hp=8b2e7bcfeb947a3ed7425bc686345ebe95454c76;hpb=9f1f7839cfd50555efd3af1ff4102348f950c563;p=jalview.git diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 8b2e7bc..54e3db7 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -20,14 +20,39 @@ */ 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.bin.Console; import jalview.commands.EditCommand; import jalview.commands.EditCommand.Action; import jalview.commands.EditCommand.Edit; +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; @@ -48,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! @@ -76,6 +86,82 @@ public class SeqPanel extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener, SequenceListener, SelectionListener { + /* + * a class that holds computed mouse position + * - column of the alignment (0...) + * - sequence offset (0...) + * - annotation row offset (0...) + * where annotation offset is -1 unless the alignment is shown + * in wrapped mode, annotations are shown, and the mouse is + * over an annnotation row + */ + static class MousePos + { + /* + * alignment column position of cursor (0...) + */ + final int column; + + /* + * index in alignment of sequence under cursor, + * or nearest above if cursor is not over a sequence + */ + final int seqIndex; + + /* + * index in annotations array of annotation under the cursor + * (only possible in wrapped mode with annotations shown), + * or -1 if cursor is not over an annotation row + */ + final int annotationIndex; + + MousePos(int col, int seq, int ann) + { + column = col; + seqIndex = seq; + annotationIndex = ann; + } + + boolean isOverAnnotation() + { + return annotationIndex != -1; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null || !(obj instanceof MousePos)) + { + return false; + } + MousePos o = (MousePos) obj; + boolean b = (column == o.column && seqIndex == o.seqIndex + && annotationIndex == o.annotationIndex); + // System.out.println(obj + (b ? "= " : "!= ") + this); + return b; + } + + /** + * A simple hashCode that ensures that instances that satisfy equals() have + * the same hashCode + */ + @Override + public int hashCode() + { + return column + seqIndex + annotationIndex; + } + + /** + * toString method for debug output purposes only + */ + @Override + public String toString() + { + return String.format("c%d:s%d:a%d", column, seqIndex, + annotationIndex); + } + } + private static final int MAX_TOOLTIP_LENGTH = 300; public SeqCanvas seqCanvas; @@ -83,18 +169,13 @@ public class SeqPanel extends JPanel public AlignmentPanel ap; /* - * last column position for mouseMoved event - */ - private int lastMouseColumn; - - /* - * last sequence offset for mouseMoved event + * last position for mouseMoved event */ - private int lastMouseSeq; + private MousePos lastMousePosition; - protected int lastres; + protected int editLastRes; - protected int startseq; + protected int editStartSeq; protected AlignViewport av; @@ -131,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; @@ -153,11 +242,11 @@ 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); @@ -176,9 +265,6 @@ public class SeqPanel extends JPanel ssm.addStructureViewerListener(this); ssm.addSelectionListener(this); } - - lastMouseColumn = -1; - lastMouseSeq = -1; } int startWrapBlock = -1; @@ -186,8 +272,82 @@ public class SeqPanel extends JPanel int wrappedBlock = -1; /** + * 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 + */ + MousePos findMousePosition(MouseEvent evt) + { + int col = findColumn(evt); + int seqIndex = -1; + int annIndex = -1; + int y = evt.getY(); + + int charHeight = av.getCharHeight(); + int alignmentHeight = av.getAlignment().getHeight(); + if (av.getWrapAlignment()) + { + seqCanvas.calculateWrappedGeometry(seqCanvas.getWidth(), + seqCanvas.getHeight()); + + /* + * yPos modulo height of repeating width + */ + int yOffsetPx = y % seqCanvas.wrappedRepeatHeightPx; + + /* + * 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; 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 -= seqCanvas.wrappedSpaceAboveAlignment; + if (yOffsetPx >= 0) + { + seqIndex = Math.min(yOffsetPx / charHeight, alignmentHeight - 1); + } + } + } + else + { + ViewportRanges ranges = av.getRanges(); + seqIndex = Math.min((y / charHeight) + ranges.getStartSeq(), + alignmentHeight - 1); + seqIndex = Math.min(seqIndex, ranges.getEndSeq()); + } + + 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 @@ -197,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()) { @@ -212,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()) @@ -250,38 +416,6 @@ public class SeqPanel extends JPanel } return res; - - } - - int findSeq(MouseEvent evt) - { - int seq = 0; - int y = evt.getY(); - - if (av.getWrapAlignment()) - { - int hgap = av.getCharHeight(); - if (av.getScaleAboveWrapped()) - { - hgap += av.getCharHeight(); - } - - int cHeight = av.getAlignment().getHeight() * av.getCharHeight() - + hgap + seqCanvas.getAnnotationHeight(); - - y -= hgap; - - seq = Math.min((y % cHeight) / av.getCharHeight(), - av.getAlignment().getHeight() - 1); - } - else - { - seq = Math.min( - (y / av.getCharHeight()) + av.getRanges().getStartSeq(), - av.getAlignment().getHeight() - 1); - } - - return seq; } /** @@ -303,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; @@ -349,45 +483,85 @@ 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); + } + + 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 (seqCanvas.cursorX >= maxWidth - || !hidden.isVisible(seqCanvas.cursorX)) + 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; } /** @@ -445,7 +619,7 @@ public class SeqPanel extends JPanel if (av.getAlignment().getHiddenColumns().isVisible(seqCanvas.cursorX)) { setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY), - seqCanvas.cursorX, seqCanvas.cursorY); + seqCanvas.cursorX, seqCanvas.cursorY); } if (repaintNeeded) @@ -454,7 +628,6 @@ public class SeqPanel extends JPanel } } - void setSelectionAreaAtCursor(boolean topLeft) { SequenceI sequence = av.getAlignment().getSequenceAt(seqCanvas.cursorY); @@ -532,8 +705,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(); } @@ -541,8 +714,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(); } @@ -551,8 +724,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(); } @@ -617,24 +790,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(); } /** @@ -647,6 +827,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)) { @@ -665,28 +850,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; @@ -714,11 +894,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; @@ -731,7 +911,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(); @@ -739,11 +919,82 @@ 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())
@@ -1188,30 +1568,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"));
- }
+ label = MessageManager.getString("action.edit_group");
}
else
{
message.append("Edit sequence: " + seq.getName());
- String label = 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)
@@ -1223,12 +1611,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;
@@ -1247,10 +1640,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;
@@ -1276,8 +1669,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;
@@ -1298,6 +1691,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;
}
}
@@ -2168,7 +2804,7 @@ public class SeqPanel extends JPanel
{
if (av.getAlignment() == null)
{
- Cache.log.warn("alignviewport av SeqSetId=" + av.getSequenceSetId()
+ Console.warn("alignviewport av SeqSetId=" + av.getSequenceSetId()
+ " ViewId=" + av.getViewId()
+ " 's alignment is NULL! returning immediately.");
return;
@@ -2268,7 +2904,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);
/*
@@ -2280,7 +2916,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)
@@ -2288,7 +2924,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;
}