JAL-2847 small things, filled in actionperformeds
[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 javax.swing.JTabbedPane;
21 import javax.swing.SwingUtilities;
22 import javax.swing.event.ChangeEvent;
23 import javax.swing.event.ChangeListener;
24
25 import org.forester.archaeopteryx.MainFrame;
26 import org.forester.phylogeny.PhylogenyMethods;
27 import org.forester.phylogeny.PhylogenyNode;
28
29 /**
30  * Class for binding the Archaeopteryx tree viewer to the Jalview alignment that
31  * it originates from, meaning that selecting sequences in the tree viewer also
32  * selects them in the alignment view and vice versa.
33  * 
34  * @author kjvanderheide
35  *
36  */
37 public final class JalviewBinding
38         implements ExternalTreeViewerBindingI<PhylogenyNode>
39 {
40   private org.forester.archaeopteryx.TreePanel treeView;
41
42   private AlignmentViewport parentAvport;
43
44   private JTabbedPane treeTabs;
45
46   private final StructureSelectionManager ssm;
47
48   private Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
49
50   private Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
51
52   /**
53    * 
54    * @param archaeopteryx
55    * 
56    * @param jalviewAlignmentViewport
57    *          alignment viewport from which the tree was calculated.
58    * 
59    * @param alignMappedToNodes
60    *          map with sequences used to calculate the tree and matching tree
61    *          nodes as key, value pair respectively.
62    * 
63    * @param nodesMappedToAlign
64    *          map with tree nodes and matching sequences used to calculate the
65    *          tree as key, value pair respectively.
66    */
67   public JalviewBinding(final MainFrame archaeopteryx,
68           final AlignmentViewport jalviewAlignmentViewport,
69           final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
70           final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
71   {
72     // deal with/prohibit null values here as that will cause problems
73     parentAvport = jalviewAlignmentViewport;
74     sequencesBoundToNodes = alignMappedToNodes;
75     nodesBoundToSequences = nodesMappedToAlign;
76
77     treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
78     treeTabs = archaeopteryx.getMainPanel().getTabbedPane();
79     ssm = parentAvport.getStructureSelectionManager();
80
81    // archaeopteryx.getMainPanel().getControlPanel().setColorBranches(true);
82     
83     ssm.addSelectionListener(this);
84     treeView.addMouseListener(this);
85     PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
86
87
88     treeTabs.addChangeListener(new ChangeListener()
89     {
90
91       @Override
92       public void stateChanged(ChangeEvent e)
93       {
94
95         SwingUtilities.invokeLater(new Runnable()
96         {
97
98           @Override
99           /**
100            * Resend the selection to the tree view when tabs get switched, this
101            * has to be buried in invokeLater as Forester first resets the tree
102            * view on switching tabs, without invokeLater this would get called
103            * before Forester resets which would nullify the selection.
104            */
105           public void run()
106           {
107             parentAvport.sendSelection();
108             // PaintRefresher.Refresh(treeView,
109             // parentAvport.getSequenceSetId());
110
111           }
112         });
113
114       }
115       
116     });
117
118   }
119
120   @Override
121   public void actionPerformed(ActionEvent e)
122   {
123   }
124
125   @Override
126   public void mouseClicked(MouseEvent e)
127   {
128   }
129
130   @Override
131   public void mousePressed(final MouseEvent e)
132   {
133     showNodeSelectionOnAlign(e);
134   }
135
136   @Override
137   public void mouseReleased(MouseEvent e)
138   {
139   }
140
141   @Override
142   public void mouseEntered(MouseEvent e)
143   {
144   }
145
146   @Override
147   public void mouseExited(MouseEvent e)
148   {
149   }
150
151
152   @Override
153   public void selection(final SequenceGroup seqsel,
154           final ColumnSelection colsel, final HiddenColumns hidden,
155           final SelectionSource source)
156   {
157     if (source == parentAvport) // check if source is alignment from where the
158     // tree originates
159     {
160       treeView.setFoundNodes0(
161               new HashSet<Long>(seqsel.getSequences().size()));
162
163       for (SequenceI selectedSequence : seqsel.getSequences())
164       {
165         PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
166         if (matchingNode != null)
167         {
168           treeView.getFoundNodes0().add(matchingNode.getId());
169         }
170
171       }
172       PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
173
174     }
175
176
177   }
178
179
180   @Override
181   public void showNodeSelectionOnAlign(final MouseEvent e)
182   {
183     final PhylogenyNode node = treeView.findNode(e.getX(), e.getY());
184     if (node != null)
185     {
186       if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) // clear previous
187                                                            // selection if shift
188                                                            // IS NOT pressed
189       {
190         parentAvport.setSelectionGroup(null);
191       }
192
193       if (node.isInternal())
194       {
195         showMatchingChildSequences(node);
196       }
197
198       else
199       {
200         showMatchingSequence(node);
201       }
202
203     }
204   }
205
206
207
208
209   @Override
210   public void showMatchingSequence(final PhylogenyNode nodeToMatch)
211   {
212     SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
213     if (matchingSequence != null)
214     {
215       treeSelectionChanged(matchingSequence);
216       parentAvport.sendSelection();
217       PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId()); // redundant?
218     }
219   }
220
221   @Override
222   public void showMatchingChildSequences(final PhylogenyNode parentNode)
223   {
224     List<PhylogenyNode> childNodes = PhylogenyMethods
225             .getAllDescendants(parentNode);
226
227     for (PhylogenyNode childNode : childNodes)
228     {
229       // childNode.getBranchData().setBranchColor(new BranchColor(Color.BLUE));
230
231       SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
232       if (matchingSequence != null)
233       {
234         treeSelectionChanged(matchingSequence);
235
236       }
237     }
238     parentAvport.sendSelection();
239     PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId()); // redundant?
240   }
241
242   /**
243    * Refactored from TreeCanvas.
244    * 
245    * @param sequence
246    *          of the node selected in the tree viewer.
247    */
248   @Override
249   public void treeSelectionChanged(final SequenceI sequence)
250   {
251     SequenceGroup selected = parentAvport.getSelectionGroup();
252
253     if (selected == null)
254     {
255       selected = new SequenceGroup();
256       parentAvport.setSelectionGroup(selected);
257     }
258
259     selected.setEndRes(parentAvport.getAlignment().getWidth() - 1);
260     selected.addOrRemove(sequence, true);
261
262   }
263
264   public AlignmentViewport getParentAvport()
265   {
266     return parentAvport;
267   }
268
269   public void setParentAvport(final AlignmentViewport parentAvport)
270   {
271     this.parentAvport = parentAvport;
272   }
273 }
274
275
276