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.Desktop;
9 import jalview.gui.JvOptionPane;
10 import jalview.gui.PaintRefresher;
11 import jalview.structure.SelectionSource;
12 import jalview.structure.StructureSelectionManager;
13 import jalview.util.MessageManager;
14 import jalview.viewmodel.AlignmentViewport;
16 import java.awt.Graphics;
17 import java.awt.event.ActionEvent;
18 import java.awt.event.InputEvent;
19 import java.awt.event.MouseEvent;
20 import java.util.HashSet;
21 import java.util.List;
25 import javax.swing.SwingUtilities;
27 import org.forester.archaeopteryx.MainFrame;
28 import org.forester.phylogeny.Phylogeny;
29 import org.forester.phylogeny.PhylogenyMethods;
30 import org.forester.phylogeny.PhylogenyNode;
33 * Class for binding the Archaeopteryx tree viewer to the Jalview alignment that
34 * it originates from, meaning that selecting sequences in the tree viewer also
35 * selects them in the alignment view and vice versa.
37 * @author kjvanderheide
40 public final class JalviewBinding
41 implements ExternalTreeViewerBindingI<PhylogenyNode>
43 private org.forester.archaeopteryx.TreePanel treeView;
45 private AlignmentViewport parentAvport;
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)
75 if (archaeopteryx.getMainPanel().getTabbedPane().getTabCount() > 1)
77 JvOptionPane.showMessageDialog(Desktop.desktop,
78 MessageManager.getString("label.tabs_detected_archaeopteryx"),
79 MessageManager.getString("label.problem_reading_tree_file"),
80 JvOptionPane.WARNING_MESSAGE);
84 // deal with/prohibit null values here as that will cause problems
85 parentAvport = jalviewAlignmentViewport;
86 sequencesBoundToNodes = alignMappedToNodes;
87 nodesBoundToSequences = nodesMappedToAlign;
89 treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
90 ssm = parentAvport.getStructureSelectionManager();
93 // archaeopteryx.getMainPanel().getControlPanel().setColorBranches(true);
95 ssm.addSelectionListener(this);
96 treeView.addMouseListener(this);
97 PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
100 // treeTabs.addChangeListener(new ChangeListener()
104 // public void stateChanged(ChangeEvent e)
107 // SwingUtilities.invokeLater(new Runnable()
112 // * Resend the selection to the tree view when tabs get switched, this
113 // * has to be buried in invokeLater as Forester first resets the tree
114 // * view on switching tabs, without invokeLater this would get called
115 // * before Forester resets which would nullify the selection.
119 // treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
120 // parentAvport.sendSelection();
121 // // PaintRefresher.Refresh(treeView,
122 // // parentAvport.getSequenceSetId());
134 public void actionPerformed(ActionEvent e)
139 public void mouseClicked(MouseEvent e)
141 SwingUtilities.invokeLater(new Runnable() {
145 * invokeLater so that this always runs after Forester's mouseClicked
149 final PhylogenyNode node = treeView.findNode(e.getX(), e.getY());
152 if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) // clear previous
153 // selection if shift
156 parentAvport.setSelectionGroup(null);
159 showNodeSelectionOnAlign(node);
163 partitionTree(e.getX());
167 PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
175 public void mousePressed(final MouseEvent e)
180 public void mouseReleased(MouseEvent e)
185 public void mouseEntered(MouseEvent e)
190 public void mouseExited(MouseEvent e)
196 public void selection(final SequenceGroup seqsel,
197 final ColumnSelection colsel, final HiddenColumns hidden,
198 final SelectionSource source)
200 if (source == parentAvport) // check if source is alignment from where the
203 treeView.setFoundNodes0(
204 new HashSet<Long>(seqsel.getSequences().size()));
206 for (SequenceI selectedSequence : seqsel.getSequences())
208 PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
209 if (matchingNode != null)
211 treeView.getFoundNodes0().add(matchingNode.getId());
223 * Partially refactored from TreeCanvas
225 public void partitionTree(final int x)
227 Phylogeny tree = treeView.getPhylogeny();
230 double treeDepth = tree.calculateHeight(true);
233 Graphics g = treeView.getGraphics();
234 int panelHeight = treeView.getHeight();
235 g.drawLine(x, 0, x, panelHeight);
238 // int viewWidth = treeView.getWidth();
240 // System.out.println("selection");
241 // System.out.println(x);
242 // System.out.println("-------------");
243 // System.out.println("width");
244 // System.out.println(viewWidth);
253 * may or may not need an extra repaint on the alignment view (check what kira
257 public void showNodeSelectionOnAlign(final PhylogenyNode node)
260 if (node.isInternal())
262 showMatchingChildSequences(node);
267 showMatchingSequence(node);
278 public void showMatchingSequence(final PhylogenyNode nodeToMatch)
280 SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
281 if (matchingSequence != null)
283 long nodeId = nodeToMatch.getId();
284 addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
285 treeSelectionChanged(matchingSequence);
286 parentAvport.sendSelection();
292 public void showMatchingChildSequences(final PhylogenyNode parentNode)
294 List<PhylogenyNode> childNodes = PhylogenyMethods
295 .getAllDescendants(parentNode);
298 for (PhylogenyNode childNode : childNodes)
300 // childNode.getBranchData().setBranchColor(new BranchColor(Color.BLUE));
302 SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
303 if (matchingSequence != null)
305 long nodeId = childNode.getId();
306 addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
308 treeSelectionChanged(matchingSequence);
313 parentAvport.sendSelection();
319 * Refactored from TreeCanvas.
322 * of the node selected in the tree viewer.
325 public void treeSelectionChanged(final SequenceI sequence)
327 if (!parentAvport.isClosed()) // alignment view could be closed
329 SequenceGroup selected = parentAvport.getSelectionGroup();
331 if (selected == null)
333 selected = new SequenceGroup();
334 parentAvport.setSelectionGroup(selected);
337 selected.setEndRes(parentAvport.getAlignment().getWidth() - 1);
338 selected.addOrRemove(sequence, true);
342 public void sortByTree_actionPerformed() {
343 // parentAvport.mirrorCommand(command, undo, ssm, source);
346 // .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
352 * sort the associated alignment view by the current tree.
357 // public void sortByTree_actionPerformed()// modify for Aptx
360 // // if (treeCanvas.applyToAllViews)
362 // final ArrayList<CommandI> commands = new ArrayList<>();
363 // for (AlignmentPanel ap : PaintRefresher
364 // .getAssociatedPanels(parentAvport.getSequenceSetId()))
366 // commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
368 // av.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
372 // public void undoCommand(AlignmentI[] views)
374 // for (CommandI tsort : commands)
376 // tsort.undoCommand(views);
381 // public int getSize()
383 // return commands.size();
387 // public String getDescription()
389 // return "Tree Sort (many views)";
393 // public void doCommand(AlignmentI[] views)
396 // for (CommandI tsort : commands)
398 // tsort.doCommand(views);
402 // for (AlignmentPanel ap : PaintRefresher
403 // .getAssociatedPanels(av.getSequenceSetId()))
405 // // ensure all the alignFrames refresh their GI after adding an undo item
406 // ap.alignFrame.updateEditMenuBar();
411 // treeCanvas.ap.alignFrame
412 // .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
421 * @param objectToCheck
423 public static <E> void addOrRemoveInSet(Set<E> set, E objectToCheck)
425 if (set.contains(objectToCheck))
427 set.remove(objectToCheck);
431 set.add(objectToCheck);
436 public AlignmentViewport getParentAvport()
441 public void setParentAvport(final AlignmentViewport parentAvport)
443 this.parentAvport = parentAvport;