JAL-2838 start on sorting
[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 import java.util.Set;
20
21 import javax.swing.JTabbedPane;
22 import javax.swing.SwingUtilities;
23 import javax.swing.event.ChangeEvent;
24 import javax.swing.event.ChangeListener;
25
26 import org.forester.archaeopteryx.MainFrame;
27 import org.forester.phylogeny.Phylogeny;
28 import org.forester.phylogeny.PhylogenyMethods;
29 import org.forester.phylogeny.PhylogenyNode;
30
31 /**
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.
35  * 
36  * @author kjvanderheide
37  *
38  */
39 public final class JalviewBinding
40         implements ExternalTreeViewerBindingI<PhylogenyNode>
41 {
42   private org.forester.archaeopteryx.TreePanel treeView;
43
44   private AlignmentViewport parentAvport;
45
46   private JTabbedPane treeTabs;
47
48   private final StructureSelectionManager ssm;
49
50   private Map<SequenceI, PhylogenyNode> sequencesBoundToNodes;
51
52   private Map<PhylogenyNode, SequenceI> nodesBoundToSequences;
53
54   /**
55    * 
56    * @param archaeopteryx
57    * 
58    * @param jalviewAlignmentViewport
59    *          alignment viewport from which the tree was calculated.
60    * 
61    * @param alignMappedToNodes
62    *          map with sequences used to calculate the tree and matching tree
63    *          nodes as key, value pair respectively.
64    * 
65    * @param nodesMappedToAlign
66    *          map with tree nodes and matching sequences used to calculate the
67    *          tree as key, value pair respectively.
68    */
69   public JalviewBinding(final MainFrame archaeopteryx,
70           final AlignmentViewport jalviewAlignmentViewport,
71           final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
72           final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
73   {
74     // deal with/prohibit null values here as that will cause problems
75     parentAvport = jalviewAlignmentViewport;
76     sequencesBoundToNodes = alignMappedToNodes;
77     nodesBoundToSequences = nodesMappedToAlign;
78
79     treeView = archaeopteryx.getMainPanel().getCurrentTreePanel();
80     treeTabs = archaeopteryx.getMainPanel().getTabbedPane();
81     ssm = parentAvport.getStructureSelectionManager();
82
83     // archaeopteryx.getMainPanel().getControlPanel().setColorBranches(true);
84     
85     ssm.addSelectionListener(this);
86     treeView.addMouseListener(this);
87     PaintRefresher.Register(treeView, parentAvport.getSequenceSetId());
88
89
90     treeTabs.addChangeListener(new ChangeListener()
91     {
92
93       @Override
94       public void stateChanged(ChangeEvent e)
95       {
96
97         SwingUtilities.invokeLater(new Runnable()
98         {
99
100           @Override
101           /**
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.
106            */
107           public void run()
108           {
109             parentAvport.sendSelection();
110             // PaintRefresher.Refresh(treeView,
111             // parentAvport.getSequenceSetId());
112
113           }
114         });
115
116       }
117       
118     });
119
120   }
121
122   @Override
123   public void actionPerformed(ActionEvent e)
124   {
125   }
126
127   @Override
128   public void mouseClicked(MouseEvent e)
129   {
130     SwingUtilities.invokeLater(new Runnable() {
131
132       @Override
133       /**
134        * invokeLater so that this always runs after Forester's mouseClicked
135        */
136       public void run()
137       {
138         final PhylogenyNode node = treeView.findNode(e.getX(), e.getY());
139         if (node != null)
140         {
141           if ((e.getModifiers() & InputEvent.SHIFT_MASK) == 0) // clear previous
142           // selection if shift
143           // IS NOT pressed
144           {
145             parentAvport.setSelectionGroup(null);
146             treeView.setFoundNodes0(null);
147
148           }
149           showNodeSelectionOnAlign(node);
150         }
151         else
152         {
153           partitionTree(e);
154         
155         
156       }
157       
158       }
159     });
160
161
162   }
163
164   @Override
165   public void mousePressed(final MouseEvent e)
166   {
167
168   }
169   @Override
170   public void mouseReleased(MouseEvent e)
171   {
172   }
173
174   @Override
175   public void mouseEntered(MouseEvent e)
176   {
177   }
178
179   @Override
180   public void mouseExited(MouseEvent e)
181   {
182   }
183
184
185   @Override
186   public void selection(final SequenceGroup seqsel,
187           final ColumnSelection colsel, final HiddenColumns hidden,
188           final SelectionSource source)
189   {
190     if (source == parentAvport) // check if source is alignment from where the
191     // tree originates
192     {
193       treeView.setFoundNodes0(
194               new HashSet<Long>(seqsel.getSequences().size()));
195
196       for (SequenceI selectedSequence : seqsel.getSequences())
197       {
198         PhylogenyNode matchingNode = sequencesBoundToNodes.get(selectedSequence);
199         if (matchingNode != null)
200         {
201           treeView.getFoundNodes0().add(matchingNode.getId());
202         }
203
204       }
205       PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
206
207     }
208
209
210   }
211
212   /**
213    * Partially refactored from TreeCanvas
214    */
215   public void partitionTree(final MouseEvent e)
216   {
217     int x = e.getX();
218     int lineLength = treeView.getHeight();
219
220     Phylogeny tree = treeView.getPhylogeny();
221     double treeHeight = tree.calculateHeight(true);
222
223
224
225     if (treeHeight != 0)
226     {
227       int viewWidth = treeView.getWidth();
228
229       // treeView.validate();
230
231       // System.out.println("selection");
232       // System.out.println(x);
233       // System.out.println("-------------");
234       // System.out.println("width");
235       // System.out.println(viewWidth);
236
237     }
238
239
240   }
241   
242
243
244   @Override
245   public void showNodeSelectionOnAlign(final PhylogenyNode node)
246   {
247     if (treeView.getFoundNodes0() == null)
248     {
249       treeView.setFoundNodes0(new HashSet<Long>());
250     }
251
252       if (node.isInternal())
253       {
254         showMatchingChildSequences(node);
255       }
256
257       else
258       {
259         showMatchingSequence(node);
260       }
261     treeView.repaint();
262     PaintRefresher.Refresh(treeView, parentAvport.getSequenceSetId());
263     }
264
265
266
267
268
269   @Override
270   public void showMatchingSequence(final PhylogenyNode nodeToMatch)
271   {
272     SequenceI matchingSequence = nodesBoundToSequences.get(nodeToMatch);
273     if (matchingSequence != null)
274     {
275       long nodeId = nodeToMatch.getId();
276       addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
277       treeSelectionChanged(matchingSequence);
278       // parentAvport.sendSelection(); // this shouldn't be needed
279
280     }
281   }
282
283   @Override
284   public void showMatchingChildSequences(final PhylogenyNode parentNode)
285   {
286     List<PhylogenyNode> childNodes = PhylogenyMethods
287             .getAllDescendants(parentNode);
288
289
290     for (PhylogenyNode childNode : childNodes)
291     {
292       // childNode.getBranchData().setBranchColor(new BranchColor(Color.BLUE));
293
294       SequenceI matchingSequence = nodesBoundToSequences.get(childNode);
295       if (matchingSequence != null)
296       {
297         long nodeId = childNode.getId();
298         addOrRemoveInSet(treeView.getFoundNodes0(), nodeId);
299
300         treeSelectionChanged(matchingSequence);
301
302       }
303
304     }
305     // parentAvport.sendSelection(); // this shouldn't be needed
306
307
308   }
309
310   /**
311    * Refactored from TreeCanvas.
312    * 
313    * @param sequence
314    *          of the node selected in the tree viewer.
315    */
316   @Override
317   public void treeSelectionChanged(final SequenceI sequence)
318   {
319     if (!parentAvport.isClosed()) // alignment view could be closed
320     {
321       SequenceGroup selected = parentAvport.getSelectionGroup();
322
323       if (selected == null)
324       {
325         selected = new SequenceGroup();
326         parentAvport.setSelectionGroup(selected);
327       }
328
329       selected.setEndRes(parentAvport.getAlignment().getWidth() - 1);
330         selected.addOrRemove(sequence, true);
331     }
332
333   }
334   public void sortByTree_actionPerformed() {
335     // parentAvport.mirrorCommand(command, undo, ssm, source);
336
337     // alignFrame
338     // .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
339     
340   }
341   
342
343   /**
344    * sort the associated alignment view by the current tree.
345    * 
346    * @param e
347    */
348   // @Override
349   // public void sortByTree_actionPerformed()// modify for Aptx
350   // {
351   //
352   // // if (treeCanvas.applyToAllViews)
353   //
354   // final ArrayList<CommandI> commands = new ArrayList<>();
355   // for (AlignmentPanel ap : PaintRefresher
356   // .getAssociatedPanels(parentAvport.getSequenceSetId()))
357   // {
358   // commands.add(sortAlignmentIn(ap.av.getAlignPanel()));
359   // }
360   // av.getAlignPanel().alignFrame.addHistoryItem(new CommandI()
361   // {
362   //
363   // @Override
364   // public void undoCommand(AlignmentI[] views)
365   // {
366   // for (CommandI tsort : commands)
367   // {
368   // tsort.undoCommand(views);
369   // }
370   // }
371   //
372   // @Override
373   // public int getSize()
374   // {
375   // return commands.size();
376   // }
377   //
378   // @Override
379   // public String getDescription()
380   // {
381   // return "Tree Sort (many views)";
382   // }
383   //
384   // @Override
385   // public void doCommand(AlignmentI[] views)
386   // {
387   //
388   // for (CommandI tsort : commands)
389   // {
390   // tsort.doCommand(views);
391   // }
392   // }
393   // });
394   // for (AlignmentPanel ap : PaintRefresher
395   // .getAssociatedPanels(av.getSequenceSetId()))
396   // {
397   // // ensure all the alignFrames refresh their GI after adding an undo item
398   // ap.alignFrame.updateEditMenuBar();
399   // }
400   // }
401   // else
402   // {
403   // treeCanvas.ap.alignFrame
404   // .addHistoryItem(sortAlignmentIn(treeCanvas.ap));
405   // }
406
407
408
409   /**
410    * TO BE MOVED
411    * 
412    * @param set
413    * @param objectToCheck
414    */
415   public static <E> void addOrRemoveInSet(Set<E> set, E objectToCheck)
416   {
417     if (set.contains(objectToCheck))
418     {
419       set.remove(objectToCheck);
420     }
421     else
422     {
423       set.add(objectToCheck);
424     }
425
426   }
427
428   public AlignmentViewport getParentAvport()
429   {
430     return parentAvport;
431   }
432
433   public void setParentAvport(final AlignmentViewport parentAvport)
434   {
435     this.parentAvport = parentAvport;
436   }
437 }
438
439
440