import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import org.forester.archaeopteryx.MainFrame;
+import org.forester.phylogeny.PhylogenyMethods;
import org.forester.phylogeny.PhylogenyNode;
-public class JalviewAptxBinding implements JalviewTreeViewerBindingI
+/**
+ * Class for binding the Archaeopteryx tree viewer to the Jalview alignment that
+ * it originates from, meaning that selecting sequences in the tree viewer also
+ * selects them in the alignment view and vice versa.
+ *
+ * @author kjvanderheide
+ *
+ */
+public final class JalviewAptxBinding implements JalviewTreeViewerBindingI
{
- org.forester.archaeopteryx.TreePanel treeView;
+ private org.forester.archaeopteryx.TreePanel treeView;
- AlignmentViewport parentAvport;
+ private AlignmentViewport parentAvport;
- StructureSelectionManager ssm;
+ private final StructureSelectionManager ssm;
- Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
+ private Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
- Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
+ private Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
- public JalviewAptxBinding(MainFrame archaeopteryx,
- AlignmentViewport jalviewAlignmentViewport,
- Map<SequenceI, PhylogenyNode> alignMappedToNodes,
- Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
+ /**
+ *
+ * @param archaeopteryx
+ *
+ * @param jalviewAlignmentViewport
+ * alignment viewport from which the tree was calculated.
+ *
+ * @param alignMappedToNodes
+ * map with sequences used to calculate the tree and matching tree
+ * nodes as key, value pair respectively.
+ *
+ * @param nodesMappedToAlign
+ * map with tree nodes and matching sequences used to calculate the
+ * tree as key, value pair respectively.
+ */
+ public JalviewAptxBinding(final MainFrame archaeopteryx,
+ final AlignmentViewport jalviewAlignmentViewport,
+ final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
+ final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
{
+ // deal with/prohibit null values here as that will cause problems
parentAvport = jalviewAlignmentViewport;
sequencesBoundToNodes = alignMappedToNodes;
nodesBoundToSequences = nodesMappedToAlign;
ssm.addSelectionListener(this);
treeView.addMouseListener(this);
PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
+
}
@Override
}
@Override
- public void mousePressed(MouseEvent e)
+ public void mousePressed(final MouseEvent e)
{
showNodeSelectionOnAlign(e);
}
{
}
+
@Override
- public void selection(SequenceGroup seqsel, ColumnSelection colsel,
- HiddenColumns hidden, SelectionSource source)
+ public void selection(final SequenceGroup seqsel,
+ final ColumnSelection colsel, final HiddenColumns hidden,
+ final SelectionSource source)
{
if (source == parentAvport) // check if source is alignment from where the
- // tree originates
+ // tree originates
{
treeView.setFoundNodes0(
new HashSet<Long>(seqsel.getSequences().size()));
}
/**
- * Note that this currently only checks external nodes
+ * If a node is selected in the tree panel this method highlights the
+ * corresponding sequence in the Jalview alignment view. If an internal node
+ * is selected all child sequences get highlighted as well.
*/
@Override
- public void showNodeSelectionOnAlign(MouseEvent e)
+ public void showNodeSelectionOnAlign(final MouseEvent e)
{
final PhylogenyNode node = treeView.findNode(e.getX(), e.getY());
if (node != null)
{
- SequenceI matchingSequence = nodesBoundToSequences.get(node);
- if (matchingSequence != null)
+ if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) // clear previous
+ // selection if shift
+ // IS NOT pressed
{
+ parentAvport.setSelectionGroup(null);
+ }
- if ((e.getModifiers() & InputEvent.SHIFT_MASK) != 0) // shift is pressed
- // (so multiple nodes
- // can be selected)
- {
- // something?
+ if (node.isInternal())
+ {
+ showMatchingChildSequences(node);
- }
- else
- {
- parentAvport.setSelectionGroup(null); // reset selection if shift
- // isn't
- // pressed
- }
+ }
+ else
+ {
+ showMatchingSequence(node);
- treeSelectionChanged(matchingSequence);
- parentAvport.sendSelection(); // not actually needed?
+ }
- PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
+ }
+ }
+
+
+
+
+ public void showMatchingSequence(final PhylogenyNode nodeToMatch)
+ {
+ SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
+ if (matchingSequence != null)
+ {
+ treeSelectionChanged(matchingSequence);
+ parentAvport.sendSelection();
+ PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
+ }
+ }
+
+ public void showMatchingChildSequences(final PhylogenyNode parentNode)
+ {
+ final List<PhylogenyNode> childNodes = PhylogenyMethods
+ .getAllDescendants(parentNode);
+
+ for (PhylogenyNode childNode : childNodes)
+ {
+ SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
+ if (matchingSequence != null)
+ {
+ treeSelectionChanged(matchingSequence);
}
}
+ parentAvport.sendSelection();
+ PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
}
/**
- * Refactored from TreeCanvas
+ * Refactored from TreeCanvas.
*
* @param sequence
+ * of the node selected in the tree viewer.
*/
- public void treeSelectionChanged(SequenceI sequence)
+ public void treeSelectionChanged(final SequenceI sequence)
{
SequenceGroup selected = parentAvport.getSelectionGroup();
return parentAvport;
}
- public void setParentAvport(AlignmentViewport parentAvport)
+ public void setParentAvport(final AlignmentViewport parentAvport)
{
this.parentAvport = parentAvport;
}