View Javadoc

1   /*
2   
3       dsh-venn-cytoscape3-app  Cytoscape3 app for venn and euler diagrams.
4       Copyright (c) 2012-2013 held jointly by the individual authors.
5   
6       This library is free software; you can redistribute it and/or modify it
7       under the terms of the GNU Lesser General Public License as published
8       by the Free Software Foundation; either version 3 of the License, or (at
9       your option) any later version.
10  
11      This library is distributed in the hope that it will be useful, but WITHOUT
12      ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13      FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14      License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public License
17      along with this library;  if not, write to the Free Software Foundation,
18      Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
19  
20      > http://www.fsf.org/licensing/licenses/lgpl.html
21      > http://www.opensource.org/licenses/lgpl-license.php
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  * Groups view.
124  */
125 final class GroupsView
126     extends JPanel
127     implements GroupAboutToBeDestroyedListener, GroupAboutToBeRemovedListener, GroupAddedListener, GroupAddedToNetworkListener
128 {
129     /** List of groups. */
130     private final EventList<CyGroup> groups;
131 
132     /** List selection. */
133     private final EventList<CyGroup> selected;
134 
135     /** List of groups. */
136     private final JList groupList;
137 
138     /** Context menu. */
139     private final JPopupMenu contextMenu;
140 
141     /** Euler diagram action icon bundle. */
142     private final IconBundle eulerDiagramIconBundle = new CachingIconBundle(new PNGIconBundle("/org/dishevelled/venn/cytoscape3/internal/eulerDiagram"));
143 
144     /** Euler diagram action. */
145     private final IdentifiableAction eulerDiagram = new IdentifiableAction("Euler Diagram...", eulerDiagramIconBundle) // i18n
146         {
147             /** {@inheritDoc} */
148             public void actionPerformed(final ActionEvent event)
149             {
150                 if (selected.size() > 1)
151                 {
152                     eulerDiagram();
153                 }
154             }
155         };
156 
157     /** Venn diagram action icon bundle. */
158     private final IconBundle vennDiagramIconBundle = new CachingIconBundle(new PNGIconBundle("/org/dishevelled/venn/cytoscape3/internal/vennDiagram"));
159 
160     /** Venn diagram action. */
161     private final IdentifiableAction vennDiagram = new IdentifiableAction("Venn Diagram...", vennDiagramIconBundle) // i18n
162         {
163             /** {@inheritDoc} */
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     /** Details action icon bundle. */
184     private final IconBundle detailsIconBundle = new CachingIconBundle(new PNGIconBundle("/org/dishevelled/venn/cytoscape3/internal/details"));
185 
186     /** Details action. */
187     private final IdentifiableAction details = new IdentifiableAction("Details...", detailsIconBundle) // i18n
188         {
189             /** {@inheritDoc} */
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     /** Done action. */
210     private final Action done = new AbstractAction("Done") // i18n
211         {
212             /** {@inheritDoc} */
213             public void actionPerformed(final ActionEvent event)
214             {
215                 done();
216             }
217         };
218 
219     /** Rename group action. */
220     private final Action renameGroup = new AbstractAction("Rename group...")
221         {
222             /** {@inheritDoc} */
223             public void actionPerformed(final ActionEvent event)
224             {
225                 renameGroup();
226             }
227         };
228 
229     /** List selection listener. */
230     private final ListSelectionListener listSelectionListener = new ListSelectionListener()
231         {
232             /** {@inheritDoc} */
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     /** Application manager. */
244     private final CyApplicationManager applicationManager;
245 
246     /** Venn euler layouter. */
247     private final VennLayouter<CyNode> vennLayouter = new VennEulerLayouter<CyNode>();
248 
249 
250     /**
251      * Create a new groups view.
252      *
253      * @param applicationManager application manager, must not be null
254      * @param groupManager group manager, must not be null
255      * @param serviceRegistrar service registrar, must not be null
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); // or use event list listener
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         // todo: serviceRegistrar.unregisterAllServices(this); when closing
329     }
330 
331     /**
332      * Layout components.
333      */
334     private void layoutComponents()
335     {
336         LabelFieldPanel mainPanel = new LabelFieldPanel();
337         mainPanel.setBorder(new EmptyBorder(12, 12, 0, 12));
338         mainPanel.addLabel("Groups:"); // i18n
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      * Done.
374      */
375     private void done()
376     {
377         windowForComponent(this).setVisible(false);
378         // todo:  unregister listeners and dispose?
379     }
380 
381     /**
382      * Show a euler diagram.
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         // add ctr that takes List<String> labels as parameter?
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         // todo: offset per parent dialog
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         // run in a cytoscape task?
416         SwingUtilities.invokeLater(new Runnable()
417             {
418                 /** {@inheritDoc} */
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      * Show a binary venn diagram.
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         // todo: offset per parent dialog
450         dialog.setBounds(100, 100, 400, 400);
451         dialog.setVisible(true);
452     }
453 
454     /**
455      * Show a ternary venn diagram.
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         // todo: offset per parent dialog
474         dialog.setBounds(100, 100, 400, 400);
475         dialog.setVisible(true);
476     }
477 
478     /**
479      * Show a quaternary venn diagram.
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         // todo: offset per parent dialog
500         dialog.setBounds(100, 100, 600, 600);
501         dialog.setVisible(true);
502     }
503 
504     /**
505      * Show binary venn details.
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         // todo: offset per parent dialog
522         dialog.setBounds(100, 100, 600, 450);
523         dialog.setVisible(true);
524     }
525 
526     /**
527      * Show ternary venn details.
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         // todo: offset per parent dialog
546         dialog.setBounds(100, 100, 747, 669);
547         dialog.setVisible(true);
548     }
549 
550     /**
551      * Show quaternary venn details.
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         // todo: offset per parent dialog
572         dialog.setBounds(100, 100, 894, 888);
573         dialog.setVisible(true);
574     }
575 
576     /**
577      * Rename the selected group if any.
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 }