JAL-2844 mouse press code rearranged to prepare for tree partitioning
[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     final PhylogenyNode node = treeView.findNode(e.getX(), e.getY());
134     if (node != null)
135     {
136       if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) // clear previous
137       // selection if shift
138       // IS NOT pressed
139       {
140         parentAvport.setSelectionGroup(null);
141
142       }
143       showNodeSelectionOnAlign(node);
144     }
145     else
146     {
147       partitionTree();
148     }
149   }
150   @Override
151   public void mouseReleased(MouseEvent e)
152   {
153   }
154
155   @Override
156   public void mouseEntered(MouseEvent e)
157   {
158   }
159
160   @Override
161   public void mouseExited(MouseEvent e)
162   {
163   }
164
165
166   @Override
167   public void selection(final SequenceGroup seqsel,
168           final ColumnSelection colsel, final HiddenColumns hidden,
169           final SelectionSource source)
170   {
171     if (source == parentAvport) // check if source is alignment from where the
172     // tree originates
173     {
174       treeView.setFoundNodes0(
175               new HashSet<Long>(seqsel.getSequences().size()));
176
177       for (SequenceI selectedSequence : seqsel.getSequences())
178       {
179         PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
180         if (matchingNode != null)
181         {
182           treeView.getFoundNodes0().add(matchingNode.getId());
183         }
184
185       }
186       PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
187
188     }
189
190
191   }
192
193   public void partitionTree()
194   {
195
196   }
197
198
199   @Override
200   public void showNodeSelectionOnAlign(final PhylogenyNode node)
201   {
202       if (node.isInternal())
203       {
204         showMatchingChildSequences(node);
205       }
206
207       else
208       {
209         showMatchingSequence(node);
210       }
211
212     }
213
214
215
216
217
218   @Override
219   public void showMatchingSequence(final PhylogenyNode nodeToMatch)
220   {
221     SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
222     if (matchingSequence != null)
223     {
224       treeSelectionChanged(matchingSequence);
225       parentAvport.sendSelection();
226       PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId()); // redundant?
227     }
228   }
229
230   @Override
231   public void showMatchingChildSequences(final PhylogenyNode parentNode)
232   {
233     List<PhylogenyNode> childNodes = PhylogenyMethods
234             .getAllDescendants(parentNode);
235
236     for (PhylogenyNode childNode : childNodes)
237     {
238       // childNode.getBranchData().setBranchColor(new BranchColor(Color.BLUE));
239
240       SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
241       if (matchingSequence != null)
242       {
243         treeSelectionChanged(matchingSequence);
244
245       }
246     }
247     parentAvport.sendSelection();
248     PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId()); // redundant?
249   }
250
251   /**
252    * Refactored from TreeCanvas.
253    * 
254    * @param sequence
255    *          of the node selected in the tree viewer.
256    */
257   @Override
258   public void treeSelectionChanged(final SequenceI sequence)
259   {
260     SequenceGroup selected = parentAvport.getSelectionGroup();
261
262     if (selected == null)
263     {
264       selected = new SequenceGroup();
265       parentAvport.setSelectionGroup(selected);
266     }
267
268     selected.setEndRes(parentAvport.getAlignment().getWidth() - 1);
269     selected.addOrRemove(sequence, true);
270
271   }
272
273   public AlignmentViewport getParentAvport()
274   {
275     return parentAvport;
276   }
277
278   public void setParentAvport(final AlignmentViewport parentAvport)
279   {
280     this.parentAvport = parentAvport;
281   }
282 }
283
284
285