X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqPanel.java;h=d7d4af038de27a9b4f2f91f61a728d5523c1dc9a;hb=c1e22e204c48fe7fc30dbb95be46e5a04808898a;hp=7abbd7d440a289204aa576e6ec579f0e9caeade5;hpb=f36251d568f123f14631d4839362355a058dc673;p=jalview.git diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index 7abbd7d..d7d4af0 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -20,6 +20,24 @@ */ 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.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.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; + import jalview.api.AlignViewportI; import jalview.bin.Cache; import jalview.commands.EditCommand; @@ -29,6 +47,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 +68,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! @@ -203,8 +207,6 @@ public class SeqPanel extends JPanel StringBuffer keyboardNo2; - java.net.URL linkImageURL; - private final SequenceAnnotationReport seqARep; StringBuilder tooltipText = new StringBuilder(); @@ -225,8 +227,7 @@ 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); @@ -313,8 +314,10 @@ public class SeqPanel extends JPanel } else { - seqIndex = 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()); } return new MousePos(col, seqIndex, annIndex); @@ -742,13 +745,14 @@ public class SeqPanel extends JPanel return; } - if (!editingSeqs) + if (editingSeqs) + { + endEditing(); + } + else { doMouseReleasedDefineMode(evt, didDrag); - return; } - - endEditing(); } /** @@ -828,11 +832,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; @@ -858,6 +862,77 @@ public class SeqPanel extends JPanel { 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 + * + * in which case the answer is of the format (e.g.) "p.Glu388Asp" + * + * @param results + * @return + */ + private String getHighlightInfo(SearchResultsI results) + { + /* + * ideally, just find mapped CDS (as we don't care about render style here); + * for now, go via split frame complement's FeatureRenderer + */ + AlignViewportI complement = ap.getAlignViewport().getCodingComplement(); + if (complement == null) + { + return null; + } + AlignFrame af = Desktop.getAlignFrameFor(complement); + FeatureRendererModel fr2 = af.getFeatureRenderer(); + + int j = results.getSize(); + List infos = new ArrayList<>(); + for (int i = 0; i < j; i++) + { + SearchResultMatchI match = results.getResults().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); + if (mf != null) + { + for (SequenceFeature sf : mf.features) + { + String pv = mf.findProteinVariants(sf); + if (pv.length() > 0 && !infos.contains(pv)) + { + infos.add(pv); + } + } + } + } + } + + if (infos.isEmpty()) + { + return null; + } + StringBuilder sb = new StringBuilder(); + for (String info : infos) + { + if (sb.length() > 0) + { + sb.append("|"); + } + sb.append(info); + } + return sb.toString(); } @Override @@ -964,25 +1039,56 @@ public class SeqPanel extends JPanel * add features that straddle the gap (pos may be the residue before or * after the gap) */ + int unshownFeatures = 0; if (av.isShowSequenceFeatures()) { List features = ap.getFeatureRenderer() .findFeaturesAtColumn(sequence, column + 1); - seqARep.appendFeatures(tooltipText, pos, features, - this.ap.getSeqPanel().seqCanvas.fr); + unshownFeatures = seqARep.appendFeatures(tooltipText, pos, + features, this.ap.getSeqPanel().seqCanvas.fr, + MAX_TOOLTIP_LENGTH); + + /* + * add features in CDS/protein complement at the corresponding + * position if configured to do so + */ + if (av.isShowComplementFeatures()) + { + if (!Comparison.isGap(sequence.getCharAt(column))) + { + AlignViewportI complement = ap.getAlignViewport() + .getCodingComplement(); + AlignFrame af = Desktop.getAlignFrameFor(complement); + FeatureRendererModel fr2 = af.getFeatureRenderer(); + MappedFeatures mf = fr2.findComplementFeaturesAtResidue(sequence, + pos); + if (mf != null) + { + unshownFeatures = seqARep.appendFeatures(tooltipText, + pos, mf, fr2, MAX_TOOLTIP_LENGTH); + } + } + } } - if (tooltipText.length() == 6) // + if (tooltipText.length() == 6) // "" { setToolTipText(null); lastTooltip = null; } else { - if (tooltipText.length() > MAX_TOOLTIP_LENGTH) // constant + if (tooltipText.length() > MAX_TOOLTIP_LENGTH) { tooltipText.setLength(MAX_TOOLTIP_LENGTH); tooltipText.append("..."); } + if (unshownFeatures > 0) + { + tooltipText.append("
").append("... ").append("") + .append(MessageManager.formatMessage( + "label.features_not_shown", unshownFeatures)) + .append(""); + } String textString = tooltipText.toString(); if (lastTooltip == null || !lastTooltip.equals(textString)) { @@ -1093,7 +1199,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; } @@ -1109,7 +1215,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 @@ -1117,7 +1223,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); @@ -1127,7 +1233,7 @@ public class SeqPanel extends JPanel */ String seqno = seqIndex == -1 ? "" : " " + (seqIndex + 1); text.append("Sequence").append(seqno).append(" ID: ") - .append(sequence.getName()); + .append(seqName); String residue = null; @@ -1172,7 +1278,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(); @@ -1184,8 +1291,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; } } @@ -1325,9 +1432,9 @@ public class SeqPanel extends JPanel } mouseDragging = true; - if ((scrollThread != null) && (scrollThread.isRunning())) + if (scrollThread != null) { - scrollThread.setEvent(evt); + scrollThread.setMousePosition(evt.getPoint()); } } @@ -1898,10 +2005,10 @@ public class SeqPanel extends JPanel } /** - * 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) @@ -1910,23 +2017,19 @@ public class SeqPanel extends JPanel { 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) { + lastMousePosition = null; ap.alignFrame.setStatus(" "); if (av.getWrapAlignment()) { @@ -1954,7 +2057,7 @@ public class SeqPanel extends JPanel return; } - if (evt.getClickCount() > 1) + if (evt.getClickCount() > 1 && av.isShowSequenceFeatures()) { sg = av.getSelectionGroup(); if (sg != null && sg.getSize() == 1 @@ -2159,11 +2262,11 @@ public class SeqPanel extends JPanel final int column = pos.column; final int seq = pos.seqIndex; SequenceI sequence = av.getAlignment().getSequenceAt(seq); - List features = ap.getFeatureRenderer() - .findFeaturesAtColumn(sequence, column + 1); - - PopupMenu pop = new PopupMenu(ap, null, features); - pop.show(this, evt.getX(), evt.getY()); + if (sequence != null) + { + PopupMenu pop = new PopupMenu(ap, sequence, column); + pop.show(this, evt.getX(), evt.getY()); + } } /** @@ -2248,10 +2351,7 @@ public class SeqPanel extends JPanel return; } - if (res >= av.getAlignment().getWidth()) - { - res = av.getAlignment().getWidth() - 1; - } + res = Math.min(res, av.getAlignment().getWidth()-1); if (stretchGroup.getEndRes() == res) { @@ -2337,9 +2437,9 @@ public class SeqPanel extends JPanel mouseDragging = true; - if ((scrollThread != null) && (scrollThread.isRunning())) + if (scrollThread != null) { - scrollThread.setEvent(evt); + scrollThread.setMousePosition(evt.getPoint()); } /* @@ -2369,83 +2469,120 @@ public class SeqPanel extends JPanel ap.alignFrame.setStatus(status.toString()); } - 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 - { - if (scrollThread == null) - { - scrollThread = new ScrollThread(); - } + mouseDragging = false; + } - mouseDragging = true; - scrollThread.setEvent(evt); + /** + * Starts a thread to scroll the alignment, towards a given mouse position + * outside the panel bounds + * + * @param mousePos + */ + void startScrolling(Point mousePos) + { + if (scrollThread == null) + { + scrollThread = new ScrollThread(); } + mouseDragging = true; + scrollThread.setMousePosition(mousePos); } - // this class allows scrolling off the bottom of the visible alignment + /** + * Performs scrolling of the visible alignment left, right, up or down + */ class ScrollThread extends Thread { - MouseEvent evt; + private Point mousePos; private volatile boolean threadRunning = true; + /** + * Constructor + */ public ScrollThread() { + setName("SeqPanel$ScrollThread"); start(); } - public void setEvent(MouseEvent e) + /** + * Sets the position of the mouse that determines the direction of the + * scroll to perform + * + * @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; - } - + /** + * 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 (threadRunning && mouseDragging) { - if (evt != null) + if (mousePos != null) { - if (mouseDragging && (evt.getY() < 0) - && (av.getRanges().getStartSeq() > 0)) + boolean scrolled = false; + ViewportRanges ranges = SeqPanel.this.av.getRanges(); + + /* + * scroll up or down + */ + if (mousePos.y < 0) { - av.getRanges().scrollUp(true); + // mouse is above this panel - try scroll up + scrolled = ranges.scrollUp(true); } - - if (mouseDragging && (evt.getY() >= getHeight()) && (av - .getAlignment().getHeight() > av.getRanges().getEndSeq())) + else if (mousePos.y >= getHeight()) { - av.getRanges().scrollUp(false); + // mouse is below this panel - try scroll down + scrolled = ranges.scrollUp(false); } - if (mouseDragging && (evt.getX() < 0)) + /* + * scroll left or right + */ + if (mousePos.x < 0) + { + scrolled |= ranges.scrollRight(false); + } + else if (mousePos.x >= getWidth()) { - av.getRanges().scrollRight(false); + scrolled |= ranges.scrollRight(true); } - else if (mouseDragging && (evt.getX() >= getWidth())) + if (!scrolled) { - av.getRanges().scrollRight(true); + /* + * we have reached the limit of the visible alignment - quit + */ + threadRunning = false; + SeqPanel.this.ap.repaint(); } } @@ -2623,7 +2760,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); /*