1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.dishevelled.venn.cytoscape3.internal;
25
26 import static javax.swing.SwingUtilities.windowForComponent;
27 import static org.dishevelled.venn.cytoscape3.internal.VennDiagramsUtils.installCloseKeyBinding;
28 import static org.dishevelled.venn.cytoscape3.internal.VennDiagramsUtils.nameOf;
29 import static org.dishevelled.venn.cytoscape3.internal.VennDiagramsUtils.rename;
30
31 import java.awt.BorderLayout;
32 import java.awt.Toolkit;
33
34 import java.awt.event.ActionEvent;
35 import java.awt.event.InputEvent;
36 import java.awt.event.KeyEvent;
37
38 import java.awt.geom.Rectangle2D;
39
40 import java.util.ArrayList;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Properties;
44 import java.util.Set;
45
46 import javax.swing.AbstractAction;
47 import javax.swing.Action;
48 import javax.swing.InputMap;
49 import javax.swing.KeyStroke;
50 import javax.swing.JCheckBoxMenuItem;
51 import javax.swing.JComponent;
52 import javax.swing.JDialog;
53 import javax.swing.JList;
54 import javax.swing.JMenuItem;
55 import javax.swing.JOptionPane;
56 import javax.swing.JPanel;
57 import javax.swing.JPopupMenu;
58 import javax.swing.JScrollPane;
59 import javax.swing.SwingUtilities;
60
61 import javax.swing.border.EmptyBorder;
62
63 import javax.swing.event.ListSelectionEvent;
64 import javax.swing.event.ListSelectionListener;
65
66 import ca.odell.glazedlists.EventList;
67 import ca.odell.glazedlists.GlazedLists;
68
69 import ca.odell.glazedlists.swing.EventListModel;
70 import ca.odell.glazedlists.swing.EventSelectionModel;
71
72 import com.google.common.base.Joiner;
73
74 import org.cytoscape.application.CyApplicationManager;
75 import org.cytoscape.group.CyGroup;
76 import org.cytoscape.group.CyGroupManager;
77 import org.cytoscape.group.events.GroupAboutToBeDestroyedEvent;
78 import org.cytoscape.group.events.GroupAboutToBeDestroyedListener;
79 import org.cytoscape.group.events.GroupAboutToBeRemovedEvent;
80 import org.cytoscape.group.events.GroupAboutToBeRemovedListener;
81 import org.cytoscape.group.events.GroupAddedEvent;
82 import org.cytoscape.group.events.GroupAddedListener;
83 import org.cytoscape.group.events.GroupAddedToNetworkEvent;
84 import org.cytoscape.group.events.GroupAddedToNetworkListener;
85 import org.cytoscape.model.CyNetwork;
86 import org.cytoscape.model.CyNode;
87 import org.cytoscape.service.util.CyServiceRegistrar;
88
89 import org.dishevelled.iconbundle.IconBundle;
90 import org.dishevelled.iconbundle.IconSize;
91
92 import org.dishevelled.iconbundle.impl.CachingIconBundle;
93 import org.dishevelled.iconbundle.impl.PNGIconBundle;
94
95 import org.dishevelled.identify.ContextMenuListener;
96 import org.dishevelled.identify.IdentifiableAction;
97 import org.dishevelled.identify.IdButton;
98 import org.dishevelled.identify.IdMenuItem;
99 import org.dishevelled.identify.IdToolBar;
100
101 import org.dishevelled.layout.ButtonPanel;
102 import org.dishevelled.layout.LabelFieldPanel;
103
104 import org.dishevelled.piccolo.venn.BinaryVennNode;
105 import org.dishevelled.piccolo.venn.TernaryVennNode;
106 import org.dishevelled.piccolo.venn.QuaternaryVennNode;
107 import org.dishevelled.piccolo.venn.VennNode;
108
109 import org.dishevelled.venn.VennModel;
110 import org.dishevelled.venn.VennLayout;
111 import org.dishevelled.venn.VennLayouter;
112 import org.dishevelled.venn.VennLayouter.PerformanceHint;
113
114 import org.dishevelled.venn.model.VennModels;
115
116 import org.dishevelled.venn.swing.BinaryVennList;
117 import org.dishevelled.venn.swing.TernaryVennList;
118 import org.dishevelled.venn.swing.QuaternaryVennList;
119
120 import org.cytoscape.venneuler.VennEulerLayouter;
121
122
123
124
125 final class GroupsView
126 extends JPanel
127 implements GroupAboutToBeDestroyedListener, GroupAboutToBeRemovedListener, GroupAddedListener, GroupAddedToNetworkListener
128 {
129
130 private final EventList<CyGroup> groups;
131
132
133 private final EventList<CyGroup> selected;
134
135
136 private final JList groupList;
137
138
139 private final JPopupMenu contextMenu;
140
141
142 private final IconBundle eulerDiagramIconBundle = new CachingIconBundle(new PNGIconBundle("/org/dishevelled/venn/cytoscape3/internal/eulerDiagram"));
143
144
145 private final IdentifiableAction eulerDiagram = new IdentifiableAction("Euler Diagram...", eulerDiagramIconBundle)
146 {
147
148 public void actionPerformed(final ActionEvent event)
149 {
150 if (selected.size() > 1)
151 {
152 eulerDiagram();
153 }
154 }
155 };
156
157
158 private final IconBundle vennDiagramIconBundle = new CachingIconBundle(new PNGIconBundle("/org/dishevelled/venn/cytoscape3/internal/vennDiagram"));
159
160
161 private final IdentifiableAction vennDiagram = new IdentifiableAction("Venn Diagram...", vennDiagramIconBundle)
162 {
163
164 public void actionPerformed(final ActionEvent event)
165 {
166 switch (selected.size())
167 {
168 case 2:
169 binaryDiagram();
170 break;
171 case 3:
172 ternaryDiagram();
173 break;
174 case 4:
175 quaternaryDiagram();
176 break;
177 default:
178 break;
179 }
180 }
181 };
182
183
184 private final IconBundle detailsIconBundle = new CachingIconBundle(new PNGIconBundle("/org/dishevelled/venn/cytoscape3/internal/details"));
185
186
187 private final IdentifiableAction details = new IdentifiableAction("Details...", detailsIconBundle)
188 {
189
190 public void actionPerformed(final ActionEvent event)
191 {
192 switch (selected.size())
193 {
194 case 2:
195 binaryDetails();
196 break;
197 case 3:
198 ternaryDetails();
199 break;
200 case 4:
201 quaternaryDetails();
202 break;
203 default:
204 break;
205 }
206 }
207 };
208
209
210 private final Action done = new AbstractAction("Done")
211 {
212
213 public void actionPerformed(final ActionEvent event)
214 {
215 done();
216 }
217 };
218
219
220 private final Action renameGroup = new AbstractAction("Rename group...")
221 {
222
223 public void actionPerformed(final ActionEvent event)
224 {
225 renameGroup();
226 }
227 };
228
229
230 private final ListSelectionListener listSelectionListener = new ListSelectionListener()
231 {
232
233 public void valueChanged(final ListSelectionEvent event)
234 {
235 int size = selected.size();
236 eulerDiagram.setEnabled(size > 1);
237 vennDiagram.setEnabled(size > 1 && size < 5);
238 details.setEnabled(size > 1 && size < 5);
239 renameGroup.setEnabled(size == 1);
240 }
241 };
242
243
244 private final CyApplicationManager applicationManager;
245
246
247 private final VennLayouter<CyNode> vennLayouter = new VennEulerLayouter<CyNode>();
248
249
250
251
252
253
254
255
256
257 GroupsView(final CyApplicationManager applicationManager, final CyGroupManager groupManager, final CyServiceRegistrar serviceRegistrar)
258 {
259 super();
260 if (applicationManager == null)
261 {
262 throw new IllegalArgumentException("applicationManager must not be null");
263 }
264 if (groupManager == null)
265 {
266 throw new IllegalArgumentException("groupManager must not be null");
267 }
268 if (serviceRegistrar == null)
269 {
270 throw new IllegalArgumentException("serviceRegistrar must not be null");
271 }
272 this.applicationManager = applicationManager;
273
274 Set<CyGroup> groupSet = groupManager.getGroupSet(applicationManager.getCurrentNetwork());
275 groups = GlazedLists.eventList(new ArrayList<CyGroup>(groupSet));
276 EventListModel<CyGroup> listModel = new EventListModel<CyGroup>(groups);
277 EventSelectionModel<CyGroup> selectionModel = new EventSelectionModel<CyGroup>(groups);
278 selected = selectionModel.getSelected();
279 selectionModel.addListSelectionListener(listSelectionListener);
280 groupList = new JList(listModel);
281 groupList.setSelectionModel(selectionModel);
282 groupList.setCellRenderer(new CyGroupListCellRenderer(applicationManager));
283
284 InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
285 int menuKeyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
286 KeyStroke ctrlShiftE = KeyStroke.getKeyStroke(KeyEvent.VK_E, menuKeyMask | InputEvent.SHIFT_DOWN_MASK);
287 KeyStroke ctrlShiftV = KeyStroke.getKeyStroke(KeyEvent.VK_V, menuKeyMask | InputEvent.SHIFT_DOWN_MASK);
288 KeyStroke ctrlShiftD = KeyStroke.getKeyStroke(KeyEvent.VK_D, menuKeyMask | InputEvent.SHIFT_DOWN_MASK);
289 KeyStroke ctrlShiftR = KeyStroke.getKeyStroke(KeyEvent.VK_R, menuKeyMask | InputEvent.SHIFT_DOWN_MASK);
290 inputMap.put(ctrlShiftE, "eulerDiagram");
291 inputMap.put(ctrlShiftV, "vennDiagram");
292 inputMap.put(ctrlShiftD, "details");
293 inputMap.put(ctrlShiftR, "renameGroup");
294 getActionMap().put("eulerDiagram", eulerDiagram);
295 getActionMap().put("vennDiagram", vennDiagram);
296 getActionMap().put("details", details);
297 getActionMap().put("renameGroup", renameGroup);
298
299 IdMenuItem eulerDiagramMenuItem = new IdMenuItem(eulerDiagram);
300 eulerDiagramMenuItem.setAccelerator(ctrlShiftE);
301 IdMenuItem vennDiagramMenuItem = new IdMenuItem(vennDiagram);
302 vennDiagramMenuItem.setAccelerator(ctrlShiftV);
303 IdMenuItem detailsMenuItem = new IdMenuItem(details);
304 detailsMenuItem.setAccelerator(ctrlShiftD);
305 JMenuItem renameGroupMenuItem = new JMenuItem(renameGroup);
306 renameGroupMenuItem.setAccelerator(ctrlShiftR);
307
308 contextMenu = new JPopupMenu();
309 contextMenu.add(eulerDiagramMenuItem);
310 contextMenu.add(vennDiagramMenuItem);
311 contextMenu.add(detailsMenuItem);
312 contextMenu.addSeparator();
313 contextMenu.add(renameGroupMenuItem);
314 groupList.addMouseListener(new ContextMenuListener(contextMenu));
315
316 eulerDiagram.setEnabled(false);
317 vennDiagram.setEnabled(false);
318 details.setEnabled(false);
319 renameGroup.setEnabled(false);
320
321 layoutComponents();
322
323 Properties properties = new Properties();
324 serviceRegistrar.registerService(this, GroupAboutToBeDestroyedListener.class, properties);
325 serviceRegistrar.registerService(this, GroupAboutToBeRemovedListener.class, properties);
326 serviceRegistrar.registerService(this, GroupAddedListener.class, properties);
327 serviceRegistrar.registerService(this, GroupAddedToNetworkListener.class, properties);
328
329 }
330
331
332
333
334 private void layoutComponents()
335 {
336 LabelFieldPanel mainPanel = new LabelFieldPanel();
337 mainPanel.setBorder(new EmptyBorder(12, 12, 0, 12));
338 mainPanel.addLabel("Groups:");
339 mainPanel.addFinalField(new JScrollPane(groupList));
340
341 IdToolBar toolBar = new IdToolBar();
342 IdButton eulerDiagramButton = toolBar.add(eulerDiagram);
343 eulerDiagramButton.setBorderPainted(false);
344 eulerDiagramButton.setFocusPainted(false);
345 IdButton vennDiagramButton = toolBar.add(vennDiagram);
346 vennDiagramButton.setBorderPainted(false);
347 vennDiagramButton.setFocusPainted(false);
348 IdButton detailsButton = toolBar.add(details);
349 detailsButton.setBorderPainted(false);
350 detailsButton.setFocusPainted(false);
351
352 toolBar.displayIcons();
353 toolBar.setIconSize(IconSize.DEFAULT_24X24);
354
355 JPopupMenu toolBarContextMenu = new JPopupMenu();
356 for (Object menuItem : toolBar.getDisplayMenuItems())
357 {
358 toolBarContextMenu.add((JCheckBoxMenuItem) menuItem);
359 }
360 toolBar.addMouseListener(new ContextMenuListener(toolBarContextMenu));
361
362 ButtonPanel buttonPanel = new ButtonPanel();
363 buttonPanel.setBorder(new EmptyBorder(24, 12, 12, 12));
364 buttonPanel.add(done);
365
366 setLayout(new BorderLayout());
367 add("North", toolBar);
368 add("Center", mainPanel);
369 add("South", buttonPanel);
370 }
371
372
373
374
375 private void done()
376 {
377 windowForComponent(this).setVisible(false);
378
379 }
380
381
382
383
384 private void eulerDiagram()
385 {
386 CyNetwork network = applicationManager.getCurrentNetwork();
387 List<String> labels = new ArrayList<String>(selected.size());
388 List<Set<CyNode>> sets = new ArrayList<Set<CyNode>>(selected.size());
389 for (CyGroup selectedGroup : selected)
390 {
391 labels.add(nameOf(selectedGroup, network));
392 sets.add(new HashSet<CyNode>(selectedGroup.getNodeList()));
393 }
394 final VennModel<CyNode> model = VennModels.createVennModel(sets);
395 final VennNode<CyNode> vennNode = new VennNode<CyNode>(model);
396
397 for (int i = 0, size = labels.size(); i < size; i++)
398 {
399 vennNode.setLabelText(i, labels.get(i));
400 }
401
402 JDialog dialog = new JDialog(windowForComponent(this), Joiner.on(", ").join(labels) + " Euler Diagram");
403 dialog.setContentPane(new DiagramView(vennNode, applicationManager));
404 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
405 installCloseKeyBinding(dialog);
406
407
408 dialog.setBounds(100, 100, 600, 600);
409 if (model.size() > 4)
410 {
411 dialog.setBounds(100, 100, 800, 800);
412 }
413 dialog.setVisible(true);
414
415
416 SwingUtilities.invokeLater(new Runnable()
417 {
418
419 public void run()
420 {
421 Rectangle2D.Double boundingRectangle = new Rectangle2D.Double(0.0d, 0.0d, 400.0d, 400.0d);
422 if (model.size() > 4)
423 {
424 boundingRectangle.setRect(0.0d, 0.0d, 600.0d, 600.0d);
425 }
426 VennLayout layout = vennLayouter.layout(model, boundingRectangle, PerformanceHint.OPTIMIZE_FOR_SPEED);
427 vennNode.setLayout(layout);
428 }
429 });
430 }
431
432
433
434
435 private void binaryDiagram()
436 {
437 CyNetwork network = applicationManager.getCurrentNetwork();
438 String firstLabel = nameOf(selected.get(0), network);
439 String secondLabel = nameOf(selected.get(1), network);
440 Set<CyNode> first = new HashSet<CyNode>(selected.get(0).getNodeList());
441 Set<CyNode> second = new HashSet<CyNode>(selected.get(1).getNodeList());
442 BinaryVennNode<CyNode> binaryVennNode = new BinaryVennNode<CyNode>(firstLabel, first, secondLabel, second);
443
444 JDialog dialog = new JDialog(windowForComponent(this), firstLabel + ", " + secondLabel + " Venn Diagram");
445 dialog.setContentPane(new DiagramView(binaryVennNode, applicationManager));
446 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
447 installCloseKeyBinding(dialog);
448
449
450 dialog.setBounds(100, 100, 400, 400);
451 dialog.setVisible(true);
452 }
453
454
455
456
457 private void ternaryDiagram()
458 {
459 CyNetwork network = applicationManager.getCurrentNetwork();
460 String firstLabel = nameOf(selected.get(0), network);
461 String secondLabel = nameOf(selected.get(1), network);
462 String thirdLabel = nameOf(selected.get(2), network);
463 Set<CyNode> first = new HashSet<CyNode>(selected.get(0).getNodeList());
464 Set<CyNode> second = new HashSet<CyNode>(selected.get(1).getNodeList());
465 Set<CyNode> third = new HashSet<CyNode>(selected.get(2).getNodeList());
466 TernaryVennNode<CyNode> ternaryVennNode = new TernaryVennNode<CyNode>(firstLabel, first, secondLabel, second, thirdLabel, third);
467
468 JDialog dialog = new JDialog(windowForComponent(this), firstLabel + ", " + secondLabel + ", " + thirdLabel + " Venn Diagram");
469 dialog.setContentPane(new DiagramView(ternaryVennNode, applicationManager));
470 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
471 installCloseKeyBinding(dialog);
472
473
474 dialog.setBounds(100, 100, 400, 400);
475 dialog.setVisible(true);
476 }
477
478
479
480
481 private void quaternaryDiagram()
482 {
483 CyNetwork network = applicationManager.getCurrentNetwork();
484 String firstLabel = nameOf(selected.get(0), network);
485 String secondLabel = nameOf(selected.get(1), network);
486 String thirdLabel = nameOf(selected.get(2), network);
487 String fourthLabel = nameOf(selected.get(3), network);
488 Set<CyNode> first = new HashSet<CyNode>(selected.get(0).getNodeList());
489 Set<CyNode> second = new HashSet<CyNode>(selected.get(1).getNodeList());
490 Set<CyNode> third = new HashSet<CyNode>(selected.get(2).getNodeList());
491 Set<CyNode> fourth = new HashSet<CyNode>(selected.get(3).getNodeList());
492 QuaternaryVennNode<CyNode> quaternaryVennNode = new QuaternaryVennNode<CyNode>(firstLabel, first, secondLabel, second, thirdLabel, third, fourthLabel, fourth);
493
494 JDialog dialog = new JDialog(windowForComponent(this), firstLabel + ", " + secondLabel + ", " + thirdLabel + ", " + fourthLabel + " Venn Diagram");
495 dialog.setContentPane(new DiagramView(quaternaryVennNode, applicationManager));
496 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
497 installCloseKeyBinding(dialog);
498
499
500 dialog.setBounds(100, 100, 600, 600);
501 dialog.setVisible(true);
502 }
503
504
505
506
507 private void binaryDetails()
508 {
509 CyNetwork network = applicationManager.getCurrentNetwork();
510 String firstLabel = nameOf(selected.get(0), network);
511 String secondLabel = nameOf(selected.get(1), network);
512 Set<CyNode> first = new HashSet<CyNode>(selected.get(0).getNodeList());
513 Set<CyNode> second = new HashSet<CyNode>(selected.get(1).getNodeList());
514 final BinaryVennList<CyNode> binaryVennList = new BinaryVennList<CyNode>(firstLabel, first, secondLabel, second);
515
516 JDialog dialog = new JDialog(windowForComponent(this), firstLabel + ", " + secondLabel + " Details");
517 dialog.setContentPane(new DetailsView(binaryVennList, applicationManager));
518 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
519 installCloseKeyBinding(dialog);
520
521
522 dialog.setBounds(100, 100, 600, 450);
523 dialog.setVisible(true);
524 }
525
526
527
528
529 private void ternaryDetails()
530 {
531 CyNetwork network = applicationManager.getCurrentNetwork();
532 String firstLabel = nameOf(selected.get(0), network);
533 String secondLabel = nameOf(selected.get(1), network);
534 String thirdLabel = nameOf(selected.get(2), network);
535 Set<CyNode> first = new HashSet<CyNode>(selected.get(0).getNodeList());
536 Set<CyNode> second = new HashSet<CyNode>(selected.get(1).getNodeList());
537 Set<CyNode> third = new HashSet<CyNode>(selected.get(2).getNodeList());
538 final TernaryVennList<CyNode> ternaryVennList = new TernaryVennList<CyNode>(firstLabel, first, secondLabel, second, thirdLabel, third);
539
540 JDialog dialog = new JDialog(windowForComponent(this), firstLabel + ", " + secondLabel + ", " + thirdLabel + " Details");
541 dialog.setContentPane(new DetailsView(ternaryVennList, applicationManager));
542 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
543 installCloseKeyBinding(dialog);
544
545
546 dialog.setBounds(100, 100, 747, 669);
547 dialog.setVisible(true);
548 }
549
550
551
552
553 private void quaternaryDetails()
554 {
555 CyNetwork network = applicationManager.getCurrentNetwork();
556 String firstLabel = nameOf(selected.get(0), network);
557 String secondLabel = nameOf(selected.get(1), network);
558 String thirdLabel = nameOf(selected.get(2), network);
559 String fourthLabel = nameOf(selected.get(3), network);
560 Set<CyNode> first = new HashSet<CyNode>(selected.get(0).getNodeList());
561 Set<CyNode> second = new HashSet<CyNode>(selected.get(1).getNodeList());
562 Set<CyNode> third = new HashSet<CyNode>(selected.get(2).getNodeList());
563 Set<CyNode> fourth = new HashSet<CyNode>(selected.get(3).getNodeList());
564 final QuaternaryVennList<CyNode> quaternaryVennList = new QuaternaryVennList<CyNode>(firstLabel, first, secondLabel, second, thirdLabel, third, fourthLabel, fourth);
565
566 JDialog dialog = new JDialog(windowForComponent(this), firstLabel + ", " + secondLabel + ", " + thirdLabel + ", " + fourthLabel + " Details");
567 dialog.setContentPane(new DetailsView(quaternaryVennList, applicationManager));
568 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
569 installCloseKeyBinding(dialog);
570
571
572 dialog.setBounds(100, 100, 894, 888);
573 dialog.setVisible(true);
574 }
575
576
577
578
579 private void renameGroup()
580 {
581 if (selected.size() == 1)
582 {
583 CyNetwork network = applicationManager.getCurrentNetwork();
584 CyGroup group = selected.get(0);
585 rename(group, network, JOptionPane.showInputDialog(windowForComponent(this), "Please enter a new name for this group:", nameOf(group, network)));
586 }
587 }
588
589 @Override
590 public void handleEvent(final GroupAboutToBeDestroyedEvent event)
591 {
592 groups.remove(event.getGroup());
593 }
594
595 @Override
596 public void handleEvent(final GroupAboutToBeRemovedEvent event)
597 {
598 if (event.getNetwork().equals(applicationManager.getCurrentNetwork())) {
599 groups.remove((CyGroup) event.getSource());
600 }
601 }
602
603 @Override
604 public void handleEvent(final GroupAddedEvent event)
605 {
606 groups.add(event.getGroup());
607 }
608
609 @Override
610 public void handleEvent(final GroupAddedToNetworkEvent event)
611 {
612 if (event.getNetwork().equals(applicationManager.getCurrentNetwork())) {
613 groups.add((CyGroup) event.getSource());
614 }
615 }
616 }