JAL-2805 undid accidental double (buggy) binding, more interface support
[jalview.git] / src / jalview / ext / archaeopteryx / JalviewAptxBinding.java
index 9466924..f3305fd 100644 (file)
@@ -13,28 +13,54 @@ import java.awt.event.ActionEvent;
 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;
 
-  final StructureSelectionManager ssm;
+  private final StructureSelectionManager ssm;
 
-  Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
+  private Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
 
-  Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
+  private Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
 
+  /**
+   * 
+   * @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;
@@ -43,6 +69,7 @@ public class JalviewAptxBinding implements JalviewTreeViewerBindingI
     ssm.addSelectionListener(this);
     treeView.addMouseListener(this);
     PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
+
   }
 
   @Override
@@ -106,7 +133,8 @@ public class JalviewAptxBinding implements JalviewTreeViewerBindingI
 
   /**
    * If a node is selected in the tree panel this method highlights the
-   * corresponding sequence in the Jalview alignment view.
+   * corresponding sequence in the Jalview alignment view. If an internal node
+   * is selected all child sequences get highlighted as well.
    */
   @Override
   public void showNodeSelectionOnAlign(final MouseEvent e)
@@ -114,40 +142,66 @@ public class JalviewAptxBinding implements JalviewTreeViewerBindingI
     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.
    */
+  @Override
   public void treeSelectionChanged(final SequenceI sequence)
   {
     SequenceGroup selected = parentAvport.getSelectionGroup();