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);
146 treeView.setFoundNodes0(null);
149 showNodeSelectionOnAlign(node);
165 public void mousePressed(final MouseEvent e)
170 public void mouseReleased(MouseEvent e)
175 public void mouseEntered(MouseEvent e)
180 public void mouseExited(MouseEvent e)
186 public void selection(final SequenceGroup seqsel,
187 final ColumnSelection colsel, final HiddenColumns hidden,
188 final SelectionSource source)
190 if (source == parentAvport) // check if source is alignment from where the
193 treeView.setFoundNodes0(
194 new HashSet<Long>(seqsel.getSequences().size()));
196 for (SequenceI selectedSequence : seqsel.getSequences())
198 PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
199 if (matchingNode != null)
201 treeView.getFoundNodes0().add(matchingNode.getId());
205 PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
213 * Partially refactored from TreeCanvas
215 public void partitionTree(final MouseEvent e)
218 int lineLength = treeView.getHeight();
220 Phylogeny tree = treeView.getPhylogeny();
221 double treeHeight = tree.calculateHeight(true);
227 int viewWidth = treeView.getWidth();
229 // treeView.validate();
231 // System.out.println("selection");
232 // System.out.println(x);
233 // System.out.println("-------------");
234 // System.out.println("width");
235 // System.out.println(viewWidth);
245 public void showNodeSelectionOnAlign(final PhylogenyNode node)
247 if (treeView.getFoundNodes0() == null)
249 treeView.setFoundNodes0(new HashSet<Long>());
252 if (node.isInternal())
254 showMatchingChildSequences(node);
259 showMatchingSequence(node);
262 PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
270 public void showMatchingSequence(final PhylogenyNode nodeToMatch)
272 SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
273 if (matchingSequence != null)
275 long nodeId = nodeToMatch.getId();
276 addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
277 treeSelectionChanged(matchingSequence);
278 // parentAvport.sendSelection(); // this shouldn't be needed
284 public void showMatchingChildSequences(final PhylogenyNode parentNode)
286 List<PhylogenyNode> childNodes = PhylogenyMethods
287 .getAllDescendants(parentNode);
290 for (PhylogenyNode childNode : childNodes)
292 // childNode.getBranchData().setBranchColor(new BranchColor(Color.BLUE));
294 SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
295 if (matchingSequence != null)
297 long nodeId = childNode.getId();
298 addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
300 treeSelectionChanged(matchingSequence);
305 // parentAvport.sendSelection(); // this shouldn't be needed
311 * Refactored from TreeCanvas.
314 * of the node selected in the tree viewer.
317 public void treeSelectionChanged(final SequenceI sequence)
319 if (!parentAvport.isClosed()) // alignment view could be closed
321 SequenceGroup selected = parentAvport.getSelectionGroup();
323 if (selected == null)
325 selected = new SequenceGroup();
326 parentAvport.setSelectionGroup(selected);
329 selected.setEndRes(parentAvport.getAlignment().getWidth() - 1);
330 selected.addOrRemove(sequence, true);
334 public void sortByTree_actionPerformed() {
335 // parentAvport.mirrorCommand(command, undo, ssm, source);
338 // .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
344 * sort the associated alignment view by the current tree.
349 // public void sortByTree_actionPerformed()// modify for Aptx
352 // // if (treeCanvas.applyToAllViews)
354 // final ArrayList<CommandI> commands = new ArrayList<>();
355 // for (AlignmentPanel ap : PaintRefresher
356 // .getAssociatedPanels(parentAvport.getSequenceSetId()))
358 // commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
360 // av.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
364 // public void undoCommand(AlignmentI[] views)
366 // for (CommandI tsort : commands)
368 // tsort.undoCommand(views);
373 // public int getSize()
375 // return commands.size();
379 // public String getDescription()
381 // return "Tree Sort (many views)";
385 // public void doCommand(AlignmentI[] views)
388 // for (CommandI tsort : commands)
390 // tsort.doCommand(views);
394 // for (AlignmentPanel ap : PaintRefresher
395 // .getAssociatedPanels(av.getSequenceSetId()))
397 // // ensure all the alignFrames refresh their GI after adding an undo item
398 // ap.alignFrame.updateEditMenuBar();
403 // treeCanvas.ap.alignFrame
404 // .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
413 * @param objectToCheck
415 public static <E> void addOrRemoveInSet(Set<E> set, E objectToCheck)
417 if (set.contains(objectToCheck))
419 set.remove(objectToCheck);
423 set.add(objectToCheck);
428 public AlignmentViewport getParentAvport()
433 public void setParentAvport(final AlignmentViewport parentAvport)
435 this.parentAvport = parentAvport;