Merge branch 'kjvdh/features/PhylogenyViewer' of
[jalview.git] / src / jalview / ext / archaeopteryx / JalviewBinding.java
1 package jalview.ext.archaeopteryx;
2
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;
12
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;
18 import java.util.Map;
19
20 import org.forester.archaeopteryx.MainFrame;
21 import org.forester.phylogeny.PhylogenyMethods;
22 import org.forester.phylogeny.PhylogenyNode;
23
24 /**
25  * Class for binding the Archaeopteryx tree viewer to the Jalview alignment that
26  * it originates from, meaning that selecting sequences in the tree viewer also
27  * selects them in the alignment view and vice versa.
28  * 
29  * @author kjvanderheide
30  *
31  */
32 public final class JalviewBinding
33         implements ExternalTreeViewerBindingI<PhylogenyNode>
34 {
35   private org.forester.archaeopteryx.TreePanel treeView;
36
37   private AlignmentViewport parentAvport;
38
39   private final StructureSelectionManager ssm;
40
41   private Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
42
43   private Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
44
45   /**
46    * 
47    * @param archaeopteryx
48    * 
49    * @param jalviewAlignmentViewport
50    *          alignment viewport from which the tree was calculated.
51    * 
52    * @param alignMappedToNodes
53    *          map with sequences used to calculate the tree and matching tree
54    *          nodes as key, value pair respectively.
55    * 
56    * @param nodesMappedToAlign
57    *          map with tree nodes and matching sequences used to calculate the
58    *          tree as key, value pair respectively.
59    */
60   public JalviewBinding(final MainFrame archaeopteryx,
61           final AlignmentViewport jalviewAlignmentViewport,
62           final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
63           final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
64   {
65     // deal with/prohibit null values here as that will cause problems
66     parentAvport = jalviewAlignmentViewport;
67     sequencesBoundToNodes = alignMappedToNodes;
68     nodesBoundToSequences = nodesMappedToAlign;
69     treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
70     ssm = parentAvport.getStructureSelectionManager();
71     ssm.addSelectionListener(this);
72     treeView.addMouseListener(this);
73     PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
74
75   }
76
77   @Override
78   public void actionPerformed(ActionEvent e)
79   {
80   }
81
82   @Override
83   public void mouseClicked(MouseEvent e)
84   {
85   }
86
87   @Override
88   public void mousePressed(final MouseEvent e)
89   {
90     showNodeSelectionOnAlign(e);
91   }
92
93   @Override
94   public void mouseReleased(MouseEvent e)
95   {
96   }
97
98   @Override
99   public void mouseEntered(MouseEvent e)
100   {
101   }
102
103   @Override
104   public void mouseExited(MouseEvent e)
105   {
106   }
107
108
109   @Override
110   public void selection(final SequenceGroup seqsel,
111           final ColumnSelection colsel, final HiddenColumns hidden,
112           final SelectionSource source)
113   {
114     if (source == parentAvport) // check if source is alignment from where the
115     // tree originates
116     {
117       treeView.setFoundNodes0(
118               new HashSet<Long>(seqsel.getSequences().size()));
119
120       for (SequenceI selectedSequence : seqsel.getSequences())
121       {
122         PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
123         if (matchingNode != null)
124         {
125           treeView.getFoundNodes0().add(matchingNode.getId());
126         }
127
128       }
129       PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
130
131     }
132
133
134   }
135
136
137   @Override
138   public void showNodeSelectionOnAlign(final MouseEvent e)
139   {
140     final PhylogenyNode node = treeView.findNode(e.getX(), e.getY());
141     if (node != null)
142     {
143       if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) // clear previous
144                                                            // selection if shift
145                                                            // IS NOT pressed
146       {
147         parentAvport.setSelectionGroup(null);
148       }
149
150       if (node.isInternal())
151       {
152         showMatchingChildSequences(node);
153       }
154
155       else
156       {
157         showMatchingSequence(node);
158       }
159
160     }
161   }
162
163
164
165
166   @Override
167   public void showMatchingSequence(final PhylogenyNode nodeToMatch)
168   {
169     SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
170     if (matchingSequence != null)
171     {
172       treeSelectionChanged(matchingSequence);
173       parentAvport.sendSelection();
174       PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
175     }
176   }
177
178   @Override
179   public void showMatchingChildSequences(final PhylogenyNode parentNode)
180   {
181     List<PhylogenyNode> childNodes = PhylogenyMethods
182             .getAllDescendants(parentNode);
183
184     for (PhylogenyNode childNode : childNodes)
185     {
186
187       SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
188       if (matchingSequence != null)
189       {
190         treeSelectionChanged(matchingSequence);
191
192       }
193     }
194
195     parentAvport.sendSelection();
196     PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
197   }
198
199   /**
200    * Refactored from TreeCanvas.
201    * 
202    * @param sequence
203    *          of the node selected in the tree viewer.
204    */
205   @Override
206   public void treeSelectionChanged(final SequenceI sequence)
207   {
208     SequenceGroup selected = parentAvport.getSelectionGroup();
209
210     if (selected == null)
211     {
212       selected = new SequenceGroup();
213       parentAvport.setSelectionGroup(selected);
214     }
215
216     selected.setEndRes(parentAvport.getAlignment().getWidth() - 1);
217     selected.addOrRemove(sequence, true);
218
219   }
220
221   public AlignmentViewport getParentAvport()
222   {
223     return parentAvport;
224   }
225
226   public void setParentAvport(final AlignmentViewport parentAvport)
227   {
228     this.parentAvport = parentAvport;
229   }
230   // av.setCurrentTree(tree);
231   //
232   // /*
233   // * isPopupTrigger is set for mousePressed (Mac)
234   // * or mouseReleased (Windows)
235   // */
236   // if (e.isPopupTrigger())
237   // {
238   // if (highlightNode != null)
239   // {
240   // chooseSubtreeColour();
241   // }
242   // return;
243   // }
244   //
245   // /*
246   // * defer right-click handling on Windows to
247   // * mouseClicked; note isRightMouseButton
248   // * also matches Cmd-click on Mac which should do
249   // * nothing here
250   // */
251   // if (SwingUtilities.isRightMouseButton(e))
252   // {
253   // return;
254   // }
255   //
256   // int x = e.getX();
257   // int y = e.getY();
258   //
259   // Object ob = findElement(x, y);
260   //
261   // if (ob instanceof SequenceI)
262   // {
263   // treeSelectionChanged((Sequence) ob);
264   // PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
265   // repaint();
266   // av.sendSelection();
267   // return;
268   // }
269   // else if (!(ob instanceof SequenceNode))
270   // {
271   // // Find threshold
272   // if (tree.getMaxHeight() != 0)
273   // {
274   // threshold = (float) (x - offx)
275   // / (float) (getWidth() - labelLength - (2 * offx));
276   //
277   // List<SequenceNode> groups = tree.groupNodes(threshold);
278   // setColor(tree.getTopNode(), Color.black);
279   //
280   // AlignmentPanel[] aps = getAssociatedPanels();
281   //
282   // // TODO push calls below into a single AlignViewportI method?
283   // // see also AlignViewController.deleteGroups
284   // for (int a = 0; a < aps.length; a++)
285   // {
286   // aps[a].av.setSelectionGroup(null);
287   // aps[a].av.getAlignment().deleteAllGroups();
288   // aps[a].av.clearSequenceColours();
289   // if (aps[a].av.getCodingComplement() != null)
290   // {
291   // aps[a].av.getCodingComplement().setSelectionGroup(null);
292   // aps[a].av.getCodingComplement().getAlignment()
293   // .deleteAllGroups();
294   // aps[a].av.getCodingComplement().clearSequenceColours();
295   // }
296   // }
297   // colourGroups(groups);
298   // }
299   //
300   // PaintRefresher.Refresh(tp, ap.av.getSequenceSetId());
301   // repaint();
302   // }
303 }
304
305
306