X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqPanel.java;h=2caea17d01aabf8bb9af9bd7c6d5935f0486412e;hb=HEAD;hp=f433aec15eca757c2b91c5d609bf19c382ccc8d0;hpb=d281dbb95856e0796188c810b819519878235e36;p=jalview.git diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index f433aec..845004b 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -44,7 +44,7 @@ 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; @@ -137,7 +137,7 @@ public class SeqPanel extends JPanel MousePos o = (MousePos) obj; boolean b = (column == o.column && seqIndex == o.seqIndex && annotationIndex == o.annotationIndex); - // System.out.println(obj + (b ? "= " : "!= ") + this); + // jalview.bin.Console.outPrintln(obj + (b ? "= " : "!= ") + this); return b; } @@ -212,8 +212,6 @@ public class SeqPanel extends JPanel StringBuffer keyboardNo2; - java.net.URL linkImageURL; - private final SequenceAnnotationReport seqARep; /* @@ -244,13 +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); @@ -278,6 +274,9 @@ public class SeqPanel extends JPanel /** * 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 @@ -342,15 +341,39 @@ public class SeqPanel extends JPanel return new MousePos(col, seqIndex, annIndex); } + + /** + * @param evt + * @return absolute column in alignment nearest to the mouse pointer + */ + int findAlignmentColumn(MouseEvent evt) + { + return findNearestColumn(evt, true); + } + /** * 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 */ int findColumn(MouseEvent evt) { + return findNearestColumn(evt, false); + } + + /** + * @param nearestColumn + * when false returns negative values for out of bound positions - -1 + * for scale left/right, <-1 if far to right + * @return nearest absolute column to mouse pointer + */ + private int findNearestColumn(MouseEvent evt, boolean nearestColumn) + { int res = 0; int x = evt.getX(); @@ -374,7 +397,14 @@ public class SeqPanel extends JPanel if (x < 0) { // mouse is over left scale - return -1; + if (!nearestColumn) + { + return -1; + } + else + { + x = 0; + } } int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth()); @@ -384,8 +414,15 @@ public class SeqPanel extends JPanel } if (x >= cwidth * charWidth) { - // mouse is over right scale - return -1; + if (!nearestColumn) + { + // mouse is over right scale + return -1; + } + else + { + x = cwidth * charWidth - 1; + } } wrappedBlock = y / cHeight; @@ -402,8 +439,14 @@ public class SeqPanel extends JPanel * rather than right-hand gutter */ x = Math.min(x, seqCanvas.getX() + seqCanvas.getWidth()); + if (nearestColumn) + { + x = Math.max(x, 0); + } + res = (x / charWidth) + startRes; res = Math.min(res, av.getRanges().getEndRes()); + } if (av.hasHiddenColumns()) @@ -480,45 +523,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); + } - 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; } /** @@ -576,7 +659,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) @@ -585,7 +668,6 @@ public class SeqPanel extends JPanel } } - void setSelectionAreaAtCursor(boolean topLeft) { SequenceI sequence = av.getAlignment().getSequenceAt(seqCanvas.cursorY); @@ -839,7 +921,7 @@ public class SeqPanel extends JPanel if (lastMessage == null || !lastMessage.equals(tmp)) { - // System.err.println("mouseOver Sequence: "+tmp); + // jalview.bin.Console.errPrintln("mouseOver Sequence: "+tmp); ssm.mouseOverSequence(sequence, index, pos, av); } lastMessage = tmp; @@ -912,19 +994,19 @@ public class SeqPanel extends JPanel AlignFrame af = Desktop.getAlignFrameFor(complement); FeatureRendererModel fr2 = af.getFeatureRenderer(); - int j = results.getSize(); + List matches = results.getResults(); + int j = matches.size(); List infos = new ArrayList<>(); for (int i = 0; i < j; i++) { - SearchResultMatchI match = results.getResults().get(i); + SearchResultMatchI match = matches.get(i); int pos = match.getStart(); if (pos == match.getEnd()) { SequenceI seq = match.getSequence(); SequenceI ds = seq.getDatasetSequence() == null ? seq : seq.getDatasetSequence(); - MappedFeatures mf = fr2 - .findComplementFeaturesAtResidue(ds, pos); + MappedFeatures mf = fr2.findComplementFeaturesAtResidue(ds, pos); if (mf != null) { for (SequenceFeature sf : mf.features) @@ -964,7 +1046,7 @@ public class SeqPanel extends JPanel @Override public void updateColours(SequenceI seq, int index) { - System.out.println("update the seqPanel colours"); + jalview.bin.Console.outPrintln("update the seqPanel colours"); // repaint(); } @@ -1067,8 +1149,7 @@ public class SeqPanel extends JPanel { List features = ap.getFeatureRenderer() .findFeaturesAtColumn(sequence, column + 1); - unshownFeatures = seqARep.appendFeaturesLengthLimit(tooltipText, pos, - features, + unshownFeatures = seqARep.appendFeatures(tooltipText, pos, features, this.ap.getSeqPanel().seqCanvas.fr, MAX_TOOLTIP_LENGTH); /* @@ -1087,9 +1168,8 @@ public class SeqPanel extends JPanel pos); if (mf != null) { - unshownFeatures = seqARep.appendFeaturesLengthLimit( - tooltipText, pos, mf, fr2, - MAX_TOOLTIP_LENGTH); + unshownFeatures += seqARep.appendFeatures(tooltipText, pos, mf, + fr2, MAX_TOOLTIP_LENGTH); } } } @@ -1117,8 +1197,7 @@ public class SeqPanel extends JPanel if (!textString.equals(lastTooltip)) { lastTooltip = textString; - lastFormattedTooltip = JvSwingUtils.wrapTooltip(true, - textString); + lastFormattedTooltip = JvSwingUtils.wrapTooltip(true, textString); setToolTipText(lastFormattedTooltip); } } @@ -1136,6 +1215,7 @@ public class SeqPanel extends JPanel final int column = pos.column; final int rowIndex = pos.annotationIndex; + // TODO - get yOffset for annotation, too if (column < 0 || !av.getWrapAlignment() || !av.isShowAnnotation() || rowIndex < 0) { @@ -1144,10 +1224,10 @@ public class SeqPanel extends JPanel AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation(); String tooltip = AnnotationPanel.buildToolTip(anns[rowIndex], column, - anns); - if (true || !tooltip.equals(lastTooltip)) + anns, 0, av, ap); + if (tooltip == null ? tooltip != lastTooltip + : !tooltip.equals(lastTooltip)) { - System.out.println("wrapped tooltip set"); lastTooltip = tooltip; lastFormattedTooltip = tooltip == null ? null : JvSwingUtils.wrapTooltip(true, tooltip); @@ -1155,7 +1235,7 @@ public class SeqPanel extends JPanel } String msg = AnnotationPanel.getStatusMessage(av.getAlignment(), column, - anns[rowIndex]); + anns[rowIndex], 0, av); ap.alignFrame.setStatus(msg); } @@ -1202,8 +1282,8 @@ public class SeqPanel extends JPanel tempTip.setTipText(lastFormattedTooltip); int tipWidth = (int) tempTip.getPreferredSize().getWidth(); - - // was x += (w - x < 200) ? -(w / 2) : 5; + + // was x += (w - x < 200) ? -(w / 2) : 5; x = (x + tipWidth < w ? x + 10 : w - tipWidth); Point p = new Point(x, y + av.getCharHeight()); // BH 2018 was - 20? @@ -1217,7 +1297,8 @@ public class SeqPanel extends JPanel * changed, so selective redraws can be applied (ie. only structures, only * overview, etc) */ - private boolean updateOverviewAndStructs = false; // TODO: refactor to avcontroller + private boolean updateOverviewAndStructs = false; // TODO: refactor to + // avcontroller /** * set if av.getSelectionGroup() refers to a group that is defined on the @@ -1246,7 +1327,7 @@ public class SeqPanel extends JPanel { char sequenceChar = sequence.getCharAt(column); int pos = sequence.findPosition(column); - setStatusMessage(sequence, seqIndex, sequenceChar, pos); + setStatusMessage(sequence.getName(), seqIndex, sequenceChar, pos); return pos; } @@ -1262,7 +1343,7 @@ public class SeqPanel extends JPanel * Sequence 6 ID: O.niloticus.3 Nucleotide: Uracil (2) * * - * @param sequence + * @param seqName * @param seqIndex * sequence position in the alignment (1..) * @param sequenceChar @@ -1270,7 +1351,7 @@ public class SeqPanel extends JPanel * @param residuePos * the sequence residue position (if not over a gap) */ - protected void setStatusMessage(SequenceI sequence, int seqIndex, + protected void setStatusMessage(String seqName, int seqIndex, char sequenceChar, int residuePos) { StringBuilder text = new StringBuilder(32); @@ -1279,8 +1360,7 @@ public class SeqPanel extends JPanel * Sequence number (if known), and sequence name. */ String seqno = seqIndex == -1 ? "" : " " + (seqIndex + 1); - text.append("Sequence").append(seqno).append(" ID: ") - .append(sequence.getName()); + text.append("Sequence").append(seqno).append(" ID: ").append(seqName); String residue = null; @@ -1325,7 +1405,8 @@ public class SeqPanel extends JPanel { return; } - SequenceI ds = al.getSequenceAt(sequenceIndex).getDatasetSequence(); + SequenceI alignedSeq = al.getSequenceAt(sequenceIndex); + SequenceI ds = alignedSeq.getDatasetSequence(); for (SearchResultMatchI m : results.getResults()) { SequenceI seq = m.getSequence(); @@ -1337,8 +1418,8 @@ public class SeqPanel extends JPanel if (seq == ds) { int start = m.getStart(); - setStatusMessage(seq, sequenceIndex, seq.getCharAt(start - 1), - start); + setStatusMessage(alignedSeq.getName(), sequenceIndex, + seq.getCharAt(start - 1), start); return; } } @@ -1538,12 +1619,12 @@ public class SeqPanel extends JPanel String label = null; if (groupEditing) { - message.append("Edit group:"); + message.append("Edit group:"); label = MessageManager.getString("action.edit_group"); } else { - message.append("Edit sequence: " + seq.getName()); + message.append("Edit sequence: " + seq.getName()); label = seq.getName(); if (label.length() > 10) { @@ -1735,8 +1816,7 @@ public class SeqPanel extends JPanel { for (int j = 0; j < startres - editLastRes; j++) { - if (!Comparison - .isGap(groupSeqs[g].getCharAt(fixedRight - j))) + if (!Comparison.isGap(groupSeqs[g].getCharAt(fixedRight - j))) { blank = false; break; @@ -2128,8 +2208,8 @@ public class SeqPanel extends JPanel * highlight the first feature at the position on the alignment */ SearchResultsI highlight = new SearchResults(); - highlight.addResult(sequence, features.get(0).getBegin(), features - .get(0).getEnd()); + highlight.addResult(sequence, features.get(0).getBegin(), + features.get(0).getEnd()); seqCanvas.highlightSearchResults(highlight, true); /* @@ -2141,32 +2221,85 @@ public class SeqPanel extends JPanel } } + /** + * Responds to a mouse wheel movement by scrolling the alignment + *

+ * Note that this method may also be fired by scrolling with a gesture on a + * trackpad. + */ @Override public void mouseWheelMoved(MouseWheelEvent e) { e.consume(); double wheelRotation = e.getPreciseWheelRotation(); + + /* + * scroll more for large (fast) mouse movements + */ + int size = 1 + (int) Math.abs(wheelRotation); + if (wheelRotation > 0) { if (e.isShiftDown()) { - av.getRanges().scrollRight(true); - + /* + * scroll right + * stop trying to scroll right when limit is reached (saves + * expensive calls to Alignment.getWidth()) + */ + while (size-- > 0 && !ap.isScrolledFullyRight()) + { + if (!av.getRanges().scrollRight(true)) + { + break; + } + } } else { - av.getRanges().scrollUp(false); + /* + * scroll down + */ + while (size-- > 0) + { + if (!av.getRanges().scrollUp(false)) + { + break; + } + } } } else if (wheelRotation < 0) { if (e.isShiftDown()) { - av.getRanges().scrollRight(false); + /* + * scroll left + */ + while (size-- > 0) + { + if (!av.getRanges().scrollRight(false)) + { + break; + } + } } else { - av.getRanges().scrollUp(true); + /* + * scroll up + */ + while (size-- > 0) + { + if (!av.getRanges().scrollUp(true)) + { + break; + } + } } } @@ -2393,7 +2526,7 @@ public class SeqPanel extends JPanel return; } - res = Math.min(res, av.getAlignment().getWidth()-1); + res = Math.min(res, av.getAlignment().getWidth() - 1); if (stretchGroup.getEndRes() == res) { @@ -2766,7 +2899,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; @@ -2821,7 +2954,7 @@ public class SeqPanel extends JPanel if (copycolsel && av.hasHiddenColumns() && (av.getAlignment().getHiddenColumns() == null)) { - System.err.println("Bad things"); + jalview.bin.Console.errPrintln("Bad things"); } if (repaint) // always true! { @@ -2891,6 +3024,8 @@ public class SeqPanel extends JPanel * if hidden column selection has changed */ ap.paintAlignment(hiddenChanged, hiddenChanged); + // propagate any selection changes + PaintRefresher.Refresh(ap, av.getSequenceSetId()); return true; }