1 package jalview.ext.archaeopteryx;
3 import jalview.datamodel.ColumnSelection;
4 import jalview.datamodel.HiddenColumns;
5 import jalview.datamodel.SequenceGroup;
6 import jalview.datamodel.SequenceI;
7 import jalview.ext.treeviewer.ExternalTreeViewerBindingI;
8 import jalview.gui.PaintRefresher;
9 import jalview.structure.SelectionSource;
10 import jalview.structure.StructureSelectionManager;
11 import jalview.viewmodel.AlignmentViewport;
13 import java.awt.event.ActionEvent;
14 import java.awt.event.InputEvent;
15 import java.awt.event.MouseEvent;
16 import java.util.HashSet;
17 import java.util.List;
21 import javax.swing.JTabbedPane;
22 import javax.swing.SwingUtilities;
23 import javax.swing.event.ChangeEvent;
24 import javax.swing.event.ChangeListener;
26 import org.forester.archaeopteryx.MainFrame;
27 import org.forester.phylogeny.Phylogeny;
28 import org.forester.phylogeny.PhylogenyMethods;
29 import org.forester.phylogeny.PhylogenyNode;
32 * Class for binding the Archaeopteryx tree viewer to the Jalview alignment that
33 * it originates from, meaning that selecting sequences in the tree viewer also
34 * selects them in the alignment view and vice versa.
36 * @author kjvanderheide
39 public final class JalviewBinding
40 implements ExternalTreeViewerBindingI<PhylogenyNode>
42 private org.forester.archaeopteryx.TreePanel treeView;
44 private AlignmentViewport parentAvport;
46 private JTabbedPane treeTabs;
48 private final StructureSelectionManager ssm;
50 private Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
52 private Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
56 * @param archaeopteryx
58 * @param jalviewAlignmentViewport
59 * alignment viewport from which the tree was calculated.
61 * @param alignMappedToNodes
62 * map with sequences used to calculate the tree and matching tree
63 * nodes as key, value pair respectively.
65 * @param nodesMappedToAlign
66 * map with tree nodes and matching sequences used to calculate the
67 * tree as key, value pair respectively.
69 public JalviewBinding(final MainFrame archaeopteryx,
70 final AlignmentViewport jalviewAlignmentViewport,
71 final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
72 final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
74 // deal with/prohibit null values here as that will cause problems
75 parentAvport = jalviewAlignmentViewport;
76 sequencesBoundToNodes = alignMappedToNodes;
77 nodesBoundToSequences = nodesMappedToAlign;
79 treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
80 treeTabs = archaeopteryx.getMainPanel().getTabbedPane();
81 ssm = parentAvport.getStructureSelectionManager();
83 // archaeopteryx.getMainPanel().getControlPanel().setColorBranches(true);
85 ssm.addSelectionListener(this);
86 treeView.addMouseListener(this);
87 PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
90 treeTabs.addChangeListener(new ChangeListener()
94 public void stateChanged(ChangeEvent e)
97 SwingUtilities.invokeLater(new Runnable()
102 * Resend the selection to the tree view when tabs get switched, this
103 * has to be buried in invokeLater as Forester first resets the tree
104 * view on switching tabs, without invokeLater this would get called
105 * before Forester resets which would nullify the selection.
109 parentAvport.sendSelection();
110 // PaintRefresher.Refresh(treeView,
111 // parentAvport.getSequenceSetId());
123 public void actionPerformed(ActionEvent e)
128 public void mouseClicked(MouseEvent e)
130 SwingUtilities.invokeLater(new Runnable() {
134 * invokeLater so that this always runs after Forester's mouseClicked
138 final PhylogenyNode node = treeView.findNode(e.getX(), e.getY());
141 if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) // clear previous
142 // selection if shift
145 parentAvport.setSelectionGroup(null);
148 showNodeSelectionOnAlign(node);
164 public void mousePressed(final MouseEvent e)
169 public void mouseReleased(MouseEvent e)
174 public void mouseEntered(MouseEvent e)
179 public void mouseExited(MouseEvent e)
185 public void selection(final SequenceGroup seqsel,
186 final ColumnSelection colsel, final HiddenColumns hidden,
187 final SelectionSource source)
189 if (source == parentAvport) // check if source is alignment from where the
192 treeView.setFoundNodes0(
193 new HashSet<Long>(seqsel.getSequences().size()));
195 for (SequenceI selectedSequence : seqsel.getSequences())
197 PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
198 if (matchingNode != null)
200 treeView.getFoundNodes0().add(matchingNode.getId());
212 * Partially refactored from TreeCanvas
214 public void partitionTree(final MouseEvent e)
218 Phylogeny tree = treeView.getPhylogeny();
219 double treeHeight = tree.calculateHeight(true);
224 int viewWidth = treeView.getWidth();
226 // treeView.validate();
228 // System.out.println("selection");
229 // System.out.println(x);
230 // System.out.println("-------------");
231 // System.out.println("width");
232 // System.out.println(viewWidth);
241 public void showNodeSelectionOnAlign(final PhylogenyNode node)
244 if (node.isInternal())
246 showMatchingChildSequences(node);
251 showMatchingSequence(node);
261 public void showMatchingSequence(final PhylogenyNode nodeToMatch)
263 SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
264 if (matchingSequence != null)
266 long nodeId = nodeToMatch.getId();
267 addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
268 treeSelectionChanged(matchingSequence);
269 parentAvport.sendSelection();
275 public void showMatchingChildSequences(final PhylogenyNode parentNode)
277 List<PhylogenyNode> childNodes = PhylogenyMethods
278 .getAllDescendants(parentNode);
281 for (PhylogenyNode childNode : childNodes)
283 // childNode.getBranchData().setBranchColor(new BranchColor(Color.BLUE));
285 SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
286 if (matchingSequence != null)
288 long nodeId = childNode.getId();
289 addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
291 treeSelectionChanged(matchingSequence);
296 parentAvport.sendSelection();
302 * Refactored from TreeCanvas.
305 * of the node selected in the tree viewer.
308 public void treeSelectionChanged(final SequenceI sequence)
310 if (!parentAvport.isClosed()) // alignment view could be closed
312 SequenceGroup selected = parentAvport.getSelectionGroup();
314 if (selected == null)
316 selected = new SequenceGroup();
317 parentAvport.setSelectionGroup(selected);
320 selected.setEndRes(parentAvport.getAlignment().getWidth() - 1);
321 selected.addOrRemove(sequence, true);
330 * @param objectToCheck
332 public <E> void addOrRemoveInSet(Set<E> set, E objectToCheck)
334 if (set.contains(objectToCheck))
336 set.remove(objectToCheck);
340 set.add(objectToCheck);
345 public AlignmentViewport getParentAvport()
350 public void setParentAvport(final AlignmentViewport parentAvport)
352 this.parentAvport = parentAvport;