/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
*/
package jalview.gui;
-import jalview.commands.EditCommand;
-import jalview.commands.EditCommand.Action;
-import jalview.datamodel.ColumnSelection;
-import jalview.datamodel.SearchResults;
-import jalview.datamodel.Sequence;
-import jalview.datamodel.SequenceFeature;
-import jalview.datamodel.SequenceGroup;
-import jalview.datamodel.SequenceI;
-import jalview.io.SequenceAnnotationReport;
-import jalview.schemes.ResidueProperties;
-import jalview.structure.SelectionListener;
-import jalview.structure.SelectionSource;
-import jalview.structure.SequenceListener;
-import jalview.structure.StructureSelectionManager;
-import jalview.util.MessageManager;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JPanel;
import javax.swing.ToolTipManager;
+import jalview.api.AlignViewportI;
+import jalview.commands.EditCommand;
+import jalview.commands.EditCommand.Action;
+import jalview.commands.EditCommand.Edit;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SearchResults;
+import jalview.datamodel.SearchResults.Match;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceFeature;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.io.SequenceAnnotationReport;
+import jalview.schemes.ResidueProperties;
+import jalview.structure.SelectionListener;
+import jalview.structure.SelectionSource;
+import jalview.structure.SequenceListener;
+import jalview.structure.StructureSelectionManager;
+import jalview.structure.VamsasSource;
+import jalview.util.Comparison;
+import jalview.util.MappingUtils;
+import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
+
/**
* DOCUMENT ME!
*
int wrappedBlock = -1;
+ /**
+ * Returns the aligned sequence position (base 0) at the mouse position, or
+ * the closest visible one
+ *
+ * @param evt
+ * @return
+ */
int findRes(MouseEvent evt)
{
int res = 0;
int x = evt.getX();
- if (av.wrapAlignment)
+ if (av.getWrapAlignment())
{
- int hgap = av.charHeight;
- if (av.scaleAboveWrapped)
+ int hgap = av.getCharHeight();
+ if (av.getScaleAboveWrapped())
{
- hgap += av.charHeight;
+ hgap += av.getCharHeight();
}
- int cHeight = av.getAlignment().getHeight() * av.charHeight + hgap
+ int cHeight = av.getAlignment().getHeight() * av.getCharHeight()
+ + hgap
+ seqCanvas.getAnnotationHeight();
int y = evt.getY();
}
else
{
- if (x > seqCanvas.getWidth() + seqCanvas.getWidth())
+ 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()) + av.getStartRes();
+ if (res > av.getEndRes())
+ {
+ // moused off right
+ res = av.getEndRes();
+ }
}
if (av.hasHiddenColumns())
int seq = 0;
int y = evt.getY();
- if (av.wrapAlignment)
+ if (av.getWrapAlignment())
{
- int hgap = av.charHeight;
- if (av.scaleAboveWrapped)
+ int hgap = av.getCharHeight();
+ if (av.getScaleAboveWrapped())
{
- hgap += av.charHeight;
+ hgap += av.getCharHeight();
}
- int cHeight = av.getAlignment().getHeight() * av.charHeight + hgap
+ int cHeight = av.getAlignment().getHeight() * av.getCharHeight()
+ + hgap
+ seqCanvas.getAnnotationHeight();
y -= hgap;
return seq;
}
- SequenceFeature[] findFeaturesAtRes(SequenceI sequence, int res)
+ /**
+ * When all of a sequence of edits are complete, put the resulting edit list
+ * on the history stack (undo list), and reset flags for editing in progress.
+ */
+ void endEditing()
{
- Vector tmp = new Vector();
- SequenceFeature[] features = sequence.getSequenceFeatures();
- if (features != null)
+ try
{
- for (int i = 0; i < features.length; i++)
+ if (editCommand != null && editCommand.getSize() > 0)
{
- if (av.featuresDisplayed == null
- || !av.featuresDisplayed.containsKey(features[i].getType()))
- {
- continue;
- }
-
- if (features[i].featureGroup != null
- && seqCanvas.fr.featureGroups != null
- && seqCanvas.fr.featureGroups
- .containsKey(features[i].featureGroup)
- && !((Boolean) seqCanvas.fr.featureGroups
- .get(features[i].featureGroup)).booleanValue())
- {
- continue;
- }
-
- if ((features[i].getBegin() <= res)
- && (features[i].getEnd() >= res))
- {
- tmp.addElement(features[i]);
- }
+ ap.alignFrame.addHistoryItem(editCommand);
+ av.firePropertyChange("alignment", null, av.getAlignment()
+ .getSequences());
}
- }
-
- features = new SequenceFeature[tmp.size()];
- tmp.copyInto(features);
-
- return features;
- }
-
- void endEditing()
- {
- if (editCommand != null && editCommand.getSize() > 0)
+ } finally
{
- ap.alignFrame.addHistoryItem(editCommand);
- av.firePropertyChange("alignment", null, av.getAlignment()
- .getSequences());
+ /*
+ * Tidy up come what may...
+ */
+ startseq = -1;
+ lastres = -1;
+ editingSeqs = false;
+ groupEditing = false;
+ keyboardNo1 = null;
+ keyboardNo2 = null;
+ editCommand = null;
}
-
- startseq = -1;
- lastres = -1;
- editingSeqs = false;
- groupEditing = false;
- keyboardNo1 = null;
- keyboardNo2 = null;
- editCommand = null;
}
void setCursorRow()
}
endEditing();
- if (av.wrapAlignment)
+ if (av.getWrapAlignment())
{
ap.scrollToWrappedVisible(seqCanvas.cursorX);
}
{
ap.scrollUp(false);
}
- if (!av.wrapAlignment)
+ if (!av.getWrapAlignment())
{
while (seqCanvas.cursorX < av.getColumnSelection()
.adjustForHiddenColumns(av.startRes))
@Override
public void highlightSequence(SearchResults results)
{
- if (av.followHighlight)
- {
+ if (av.isFollowHighlight())
+ {
+ /*
+ * if scrollToPosition requires a scroll adjustment, this flag prevents
+ * another scroll event being propagated back to the originator
+ *
+ * @see AlignmentPanel#adjustmentValueChanged
+ */
+ ap.setFollowingComplementScroll(true);
if (ap.scrollToPosition(results, false))
{
seqCanvas.revalidate();
}
}
+ setStatusMessage(results);
seqCanvas.highlightSearchResults(results);
}
@Override
+ public VamsasSource getVamsasSource()
+ {
+ return this.ap == null ? null : this.ap.av;
+ }
+ @Override
public void updateColours(SequenceI seq, int index)
{
System.out.println("update the seqPanel colours");
}
// use aa to see if the mouse pointer is on a
- if (av.showSequenceFeatures)
+ if (av.isShowSequenceFeatures())
{
int rpos;
- SequenceFeature[] features = findFeaturesAtRes(
+ List<SequenceFeature> features = ap.getFeatureRenderer().findFeaturesAtRes(
sequence.getDatasetSequence(),
rpos = sequence.findPosition(res));
seqARep.appendFeatures(tooltipText, rpos, features,
- this.ap.seqPanel.seqCanvas.fr.minmax);
+ this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
}
if (tooltipText.length() == 6) // <html></html>
{
*/
int setStatusMessage(SequenceI sequence, int res, int seq)
{
- int pos = -1;
- StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: "
- + sequence.getName());
+ StringBuilder text = new StringBuilder(32);
+
+ /*
+ * Sequence number (if known), and sequence name.
+ */
+ String seqno = seq == -1 ? "" : " " + (seq + 1);
+ text.append("Sequence" + seqno + " ID: " + sequence.getName());
- Object obj = null;
+ String residue = null;
+ /*
+ * Try to translate the display character to residue name (null for gap).
+ */
+ final String displayChar = String.valueOf(sequence.getCharAt(res));
if (av.getAlignment().isNucleotide())
{
- obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res)
- + "");
- if (obj != null)
+ residue = ResidueProperties.nucleotideName.get(displayChar);
+ if (residue != null)
{
- text.append(" Nucleotide: ");
+ text.append(" Nucleotide: ").append(residue);
}
}
else
{
- obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");
- if (obj != null)
+ residue = "X".equalsIgnoreCase(displayChar) ? "X"
+ : ResidueProperties.aa2Triplet.get(displayChar);
+ if (residue != null)
{
- text.append(" Residue: ");
+ text.append(" Residue: ").append(residue);
}
}
- if (obj != null)
+ int pos = -1;
+ if (residue != null)
{
pos = sequence.findPosition(res);
- if (obj != "")
- {
- text.append(obj + " (" + pos + ")");
- }
+ text.append(" (").append(Integer.toString(pos)).append(")");
}
ap.alignFrame.statusBar.setText(text.toString());
return pos;
}
/**
+ * Set the status bar message to highlight the first matched position in
+ * search results.
+ *
+ * @param results
+ */
+ private void setStatusMessage(SearchResults results)
+ {
+ List<Match> matches = results.getResults();
+ if (!matches.isEmpty())
+ {
+ Match m = matches.get(0);
+ SequenceI seq = m.getSequence();
+ int sequenceIndex = this.av.getAlignment().findIndex(seq);
+
+ /*
+ * Convert position in sequence (base 1) to sequence character array index
+ * (base 0)
+ */
+ int start = m.getStart() - 1;
+ setStatusMessage(seq, start, sequenceIndex);
+ }
+ }
+
+ /**
* DOCUMENT ME!
*
* @param evt
{
if (mouseWheelPressed)
{
- int oldWidth = av.charWidth;
+ int oldWidth = av.getCharWidth();
// Which is bigger, left-right or up-down?
if (Math.abs(evt.getY() - lastMousePress.getY()) > Math.abs(evt
fontSize = 1;
}
- av.setFont(new Font(av.font.getName(), av.font.getStyle(), fontSize));
- av.charWidth = oldWidth;
+ av.setFont(
+ new Font(av.font.getName(), av.font.getStyle(), fontSize),
+ true);
+ av.setCharWidth(oldWidth);
ap.fontChanged();
}
else
{
- if (evt.getX() < lastMousePress.getX() && av.charWidth > 1)
+ if (evt.getX() < lastMousePress.getX() && av.getCharWidth() > 1)
{
- av.charWidth--;
+ av.setCharWidth(av.getCharWidth() - 1);
}
else if (evt.getX() > lastMousePress.getX())
{
- av.charWidth++;
+ av.setCharWidth(av.getCharWidth() + 1);
}
ap.paintAlignment(false);
}
FontMetrics fm = getFontMetrics(av.getFont());
- av.validCharWidth = fm.charWidth('M') <= av.charWidth;
+ av.validCharWidth = fm.charWidth('M') <= av.getCharWidth();
lastMousePress = evt.getPoint();
}
}
- StringBuffer message = new StringBuffer();
+ StringBuilder message = new StringBuilder(64);
if (groupEditing)
{
message.append("Edit group:");
}
else
{
- editCommand.appendEdit(Action.INSERT_GAP, groupSeqs,
- startres, startres - lastres, av.getAlignment(), true);
+ appendEdit(Action.INSERT_GAP, groupSeqs, startres, startres
+ - lastres);
}
}
else
}
else
{
- editCommand.appendEdit(Action.DELETE_GAP, groupSeqs,
- startres, lastres - startres, av.getAlignment(), true);
+ appendEdit(Action.DELETE_GAP, groupSeqs, startres, lastres
+ - startres);
}
}
}
else
{
- editCommand.appendEdit(Action.INSERT_GAP, new SequenceI[]
- { seq }, lastres, startres - lastres, av.getAlignment(), true);
+ appendEdit(Action.INSERT_GAP, new SequenceI[]
+ { seq }, lastres, startres - lastres);
}
}
else
{
for (int j = lastres; j > startres; j--)
{
- if (!jalview.util.Comparison.isGap(seq.getCharAt(startres)))
+ if (!Comparison.isGap(seq.getCharAt(startres)))
{
endEditing();
break;
int max = 0;
for (int m = startres; m < lastres; m++)
{
- if (!jalview.util.Comparison.isGap(seq.getCharAt(m)))
+ if (!Comparison.isGap(seq.getCharAt(m)))
{
break;
}
if (max > 0)
{
- editCommand.appendEdit(Action.DELETE_GAP,
- new SequenceI[]
- { seq }, startres, max, av.getAlignment(), true);
+ appendEdit(Action.DELETE_GAP, new SequenceI[]
+ { seq }, startres, max);
}
}
}
}
else
{
- editCommand.appendEdit(Action.INSERT_NUC, new SequenceI[]
- { seq }, lastres, startres - lastres, av.getAlignment(), true);
+ appendEdit(Action.INSERT_NUC, new SequenceI[]
+ { seq }, lastres, startres - lastres);
}
}
}
}
}
- editCommand.appendEdit(Action.DELETE_GAP, seq, blankColumn, 1,
- av.getAlignment(), true);
+ appendEdit(Action.DELETE_GAP, seq, blankColumn, 1);
- editCommand.appendEdit(Action.INSERT_GAP, seq, j, 1,
- av.getAlignment(), true);
+ appendEdit(Action.INSERT_GAP, seq, j, 1);
}
+ /**
+ * Helper method to add and perform one edit action.
+ *
+ * @param action
+ * @param seq
+ * @param pos
+ * @param count
+ */
+ protected void appendEdit(Action action, SequenceI[] seq, int pos,
+ int count)
+ {
+
+ final Edit edit = new EditCommand().new Edit(action, seq, pos, count,
+ av.getAlignment().getGapCharacter());
+
+ editCommand.appendEdit(edit, av.getAlignment(),
+ true, null);
+ }
+
void deleteChar(int j, SequenceI[] seq, int fixedColumn)
{
- editCommand.appendEdit(Action.DELETE_GAP, seq, j, 1,
- av.getAlignment(), true);
+ appendEdit(Action.DELETE_GAP, seq, j, 1);
- editCommand.appendEdit(Action.INSERT_GAP, seq, fixedColumn, 1,
- av.getAlignment(), true);
+ appendEdit(Action.INSERT_GAP, seq, fixedColumn, 1);
}
/**
av.setSelectionGroup(null);
}
- SequenceFeature[] features = findFeaturesAtRes(
+ List<SequenceFeature> features = seqCanvas.getFeatureRenderer().findFeaturesAtRes(
sequence.getDatasetSequence(),
sequence.findPosition(findRes(evt)));
- if (features != null && features.length > 0)
+ if (features != null && features.size()> 0)
{
SearchResults highlight = new SearchResults();
- highlight.addResult(sequence, features[0].getBegin(),
- features[0].getEnd());
+ highlight.addResult(sequence, features.get(0).getBegin(),
+ features.get(0).getEnd());
seqCanvas.highlightSearchResults(highlight);
}
- if (features != null && features.length > 0)
+ if (features != null && features.size()> 0)
{
seqCanvas.getFeatureRenderer().amendFeatures(new SequenceI[]
- { sequence }, features, false, ap);
+ { sequence }, features.toArray(new SequenceFeature[features.size()]), false, ap);
seqCanvas.highlightSearchResults(null);
}
startWrapBlock = wrappedBlock;
- if (av.wrapAlignment && seq > av.getAlignment().getHeight())
+ if (av.getWrapAlignment() && seq > av.getAlignment().getHeight())
{
JOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
.getString("label.cannot_edit_annotations_in_wrapped_view"),
if (javax.swing.SwingUtilities.isRightMouseButton(evt))
{
- SequenceFeature[] allFeatures = findFeaturesAtRes(
+ List<SequenceFeature> allFeatures = ap.getFeatureRenderer().findFeaturesAtRes(
sequence.getDatasetSequence(), sequence.findPosition(res));
Vector links = new Vector();
- for (int i = 0; i < allFeatures.length; i++)
+ for (SequenceFeature sf:allFeatures)
{
- if (allFeatures[i].links != null)
+ if (sf.links != null)
{
- for (int j = 0; j < allFeatures[i].links.size(); j++)
+ for (int j = 0; j < sf.links.size(); j++)
{
- links.addElement(allFeatures[i].links.elementAt(j));
+ links.addElement(sf.links.elementAt(j));
}
}
}
// handles selection messages...
// TODO: extend config options to allow user to control if selections may be
// shared between viewports.
- if (av == source
- || !av.followSelection
- || (av.isSelectionGroupChanged(false) || av
- .isColSelChanged(false))
- || (source instanceof AlignViewport && ((AlignViewport) source)
- .getSequenceSetId().equals(av.getSequenceSetId())))
+ boolean iSentTheSelection = (av == source
+ || (source instanceof AlignViewport && ((AlignmentViewport) source)
+ .getSequenceSetId().equals(av.getSequenceSetId())));
+ if (iSentTheSelection || !av.followSelection)
+ {
+ return;
+ }
+
+ /*
+ * Ignore the selection if there is one of our own pending.
+ */
+ if (av.isSelectionGroupChanged(false) || av.isColSelChanged(false))
{
return;
}
+
+ /*
+ * Check for selection in a view of which this one is a dna/protein
+ * complement.
+ */
+ if (selectionFromTranslation(seqsel, colsel, source))
+ {
+ return;
+ }
+
// do we want to thread this ? (contention with seqsel and colsel locks, I
// suspect)
// rules are: colsel is copied if there is a real intersection between
// sequence selection
- boolean repaint = false, copycolsel = true;
- // if (!av.isSelectionGroupChanged(false))
+ boolean repaint = false;
+ boolean copycolsel = true;
+
+ SequenceGroup sgroup = null;
+ if (seqsel != null && seqsel.getSize() > 0)
{
- SequenceGroup sgroup = null;
- if (seqsel != null && seqsel.getSize() > 0)
+ if (av.getAlignment() == null)
{
- if (av.getAlignment() == null)
- {
- jalview.bin.Cache.log.warn("alignviewport av SeqSetId="
- + av.getSequenceSetId() + " ViewId=" + av.getViewId()
- + " 's alignment is NULL! returning immediatly.");
- return;
- }
- sgroup = seqsel.intersect(av.getAlignment(),
- (av.hasHiddenRows()) ? av.getHiddenRepSequences() : null);
- if ((sgroup == null || sgroup.getSize() == 0)
- || (colsel == null || colsel.size() == 0))
- {
- // don't copy columns if the region didn't intersect.
- copycolsel = false;
- }
- }
- if (sgroup != null && sgroup.getSize() > 0)
- {
- av.setSelectionGroup(sgroup);
+ jalview.bin.Cache.log.warn("alignviewport av SeqSetId="
+ + av.getSequenceSetId() + " ViewId=" + av.getViewId()
+ + " 's alignment is NULL! returning immediately.");
+ return;
}
- else
+ sgroup = seqsel.intersect(av.getAlignment(),
+ (av.hasHiddenRows()) ? av.getHiddenRepSequences() : null);
+ if ((sgroup == null || sgroup.getSize() == 0)
+ || (colsel == null || colsel.size() == 0))
{
- av.setSelectionGroup(null);
+ // don't copy columns if the region didn't intersect.
+ copycolsel = false;
}
- av.isSelectionGroupChanged(true);
- repaint = true;
}
+ if (sgroup != null && sgroup.getSize() > 0)
+ {
+ av.setSelectionGroup(sgroup);
+ }
+ else
+ {
+ av.setSelectionGroup(null);
+ }
+ av.isSelectionGroupChanged(true);
+ repaint = true;
+
if (copycolsel)
{
// the current selection is unset or from a previous message
av.isColSelChanged(true);
repaint = true;
}
+
if (copycolsel
&& av.hasHiddenColumns()
&& (av.getColumnSelection() == null || av.getColumnSelection()
{
System.err.println("Bad things");
}
- if (repaint)
+ if (repaint) // always true!
{
// probably finessing with multiple redraws here
PaintRefresher.Refresh(this, av.getSequenceSetId());
// ap.paintAlignment(false);
}
}
+
+ /**
+ * If this panel is a cdna/protein translation view of the selection source,
+ * tries to map the source selection to a local one, and returns true. Else
+ * returns false.
+ *
+ * @param seqsel
+ * @param colsel
+ * @param source
+ */
+ protected boolean selectionFromTranslation(SequenceGroup seqsel,
+ ColumnSelection colsel, SelectionSource source)
+ {
+ if (!(source instanceof AlignViewportI)) {
+ return false;
+ }
+ final AlignViewportI sourceAv = (AlignViewportI) source;
+ if (sourceAv.getCodingComplement() != av && av.getCodingComplement() != sourceAv)
+ {
+ return false;
+ }
+
+ /*
+ * Map sequence selection
+ */
+ SequenceGroup sg = MappingUtils.mapSequenceGroup(seqsel, sourceAv, av);
+ av.setSelectionGroup(sg);
+ av.isSelectionGroupChanged(true);
+
+ /*
+ * Map column selection
+ */
+ ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, sourceAv,
+ av);
+ av.setColumnSelection(cs);
+ av.isColSelChanged(true);
+
+ PaintRefresher.Refresh(this, av.getSequenceSetId());
+
+ return true;
+ }
}