View Javadoc

1   /*
2   
3       dsh-venn-cytoscape-plugin  Cytoscape plugin for venn diagrams.
4       Copyright (c) 2010-2012 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.cytoscape;
25  
26  import java.awt.BorderLayout;
27  import java.awt.Toolkit;
28  
29  import java.awt.event.ActionEvent;
30  import java.awt.event.InputEvent;
31  import java.awt.event.KeyEvent;
32  
33  import javax.swing.AbstractAction;
34  import javax.swing.Action;
35  import javax.swing.InputMap;
36  import javax.swing.KeyStroke;
37  import javax.swing.JComponent;
38  import javax.swing.JMenuItem;
39  import javax.swing.JPanel;
40  import javax.swing.JPopupMenu;
41  
42  import javax.swing.border.EmptyBorder;
43  
44  import cytoscape.CyNode;
45  import cytoscape.CyNetwork;
46  import cytoscape.Cytoscape;
47  
48  import org.dishevelled.identify.ContextMenuListener;
49  import org.dishevelled.identify.IdToolBar;
50  
51  import org.dishevelled.observable.event.SetChangeEvent;
52  import org.dishevelled.observable.event.SetChangeListener;
53  
54  import org.dishevelled.venn.cytoscape.CyNodeListCellRenderer;
55  import org.dishevelled.venn.swing.BinaryVennList;
56  import org.dishevelled.venn.swing.TernaryVennList;
57  import org.dishevelled.venn.swing.QuaternaryVennList;
58  
59  /**
60   * Details view.
61   *
62   * @author  Michael Heuer
63   */
64  final class DetailsView
65      extends JPanel
66  {
67      /** Maximum number of nodes above which selection sync should be disabled for binary details views. */
68      private final int BINARY_SELECTION_SYNC_MAXIMUM = Integer.MAX_VALUE;
69  
70      /** Maximum number of nodes above which selection sync should be disabled for ternary details views. */
71      private final int TERNARY_SELECTION_SYNC_MAXIMUM = 2000000;
72  
73      /** Maximum number of nodes above which selection sync should be disabled for quaternary details views. */
74      private final int QUATERNARY_SELECTION_SYNC_MAXIMUM = 20000;
75  
76      /** Binary venn list. */
77      private final BinaryVennList<CyNode> binaryVennList;
78  
79      /** Ternary venn list. */
80      private final TernaryVennList<CyNode> ternaryVennList;
81  
82      /** Quaternary venn list. */
83      private final QuaternaryVennList<CyNode> quaternaryVennList;
84  
85      /** Update Cytoscape selection. */
86      private final SetChangeListener<CyNode> updateCytoscapeSelection = new SetChangeListener<CyNode>()
87          {
88              /** {@inheritDoc} */
89              public void setChanged(final SetChangeEvent<CyNode> event)
90              {
91                  // ick.  wholesale update every time
92                  CyNetwork currentNetwork = Cytoscape.getCurrentNetwork();
93                  currentNetwork.unselectAllNodes();
94                  currentNetwork.setSelectedNodeState(event.getObservableSet(), true);
95                  Cytoscape.getCurrentNetworkView().updateView();
96              }
97          };
98  
99      // todo: use identifiable actions for these, if a clear selection icon can be found
100     //   ...there is EDIT_SELECT_ALL but 24x24 is not one of the tango icon sizes
101     /** Select all action. */
102     private final Action selectAll = new AbstractAction("Select all") // i18n
103         {
104             /** {@inheritDoc} */
105             public void actionPerformed(final ActionEvent event)
106             {
107                 if (binaryVennList != null)
108                 {
109                     binaryVennList.selectAll();
110                 }
111                 if (ternaryVennList != null)
112                 {
113                     ternaryVennList.selectAll();
114                 }
115                 if (quaternaryVennList != null)
116                 {
117                     quaternaryVennList.selectAll();
118                 }
119             }
120         };
121 
122     /** Clear selection action. */
123     private final Action clearSelection = new AbstractAction("Clear selection") // i18n
124         {
125             /** {@inheritDoc} */
126             public void actionPerformed(final ActionEvent event)
127             {
128                 if (binaryVennList != null)
129                 {
130                     binaryVennList.clearSelection();
131                 }
132                 if (ternaryVennList != null)
133                 {
134                     ternaryVennList.clearSelection();
135                 }
136                 if (quaternaryVennList != null)
137                 {
138                     quaternaryVennList.clearSelection();
139                 }
140             }
141         };
142 
143 
144     /**
145      * Create a new details view.
146      *
147      * @param binaryVennList binary venn list
148      * @param ternaryVennList ternary venn list
149      * @param quaternaryVennList quaternary venn list
150      */
151     private DetailsView(final BinaryVennList<CyNode> binaryVennList,
152                         final TernaryVennList<CyNode> ternaryVennList,
153                         final QuaternaryVennList<CyNode> quaternaryVennList)
154     {
155         super();
156         this.binaryVennList = binaryVennList;
157         this.ternaryVennList = ternaryVennList;
158         this.quaternaryVennList = quaternaryVennList;
159 
160         // suck.
161         if (this.binaryVennList != null)
162         {
163             this.binaryVennList.getFirst().setCellRenderer(new CyNodeListCellRenderer());
164             this.binaryVennList.getFirstOnly().setCellRenderer(new CyNodeListCellRenderer());
165             this.binaryVennList.getIntersection().setCellRenderer(new CyNodeListCellRenderer());
166             this.binaryVennList.getSecond().setCellRenderer(new CyNodeListCellRenderer());
167             this.binaryVennList.getSecondOnly().setCellRenderer(new CyNodeListCellRenderer());
168             this.binaryVennList.getUnion().setCellRenderer(new CyNodeListCellRenderer());
169         }
170         if (this.ternaryVennList != null)
171         {
172             this.ternaryVennList.getFirst().setCellRenderer(new CyNodeListCellRenderer());
173             this.ternaryVennList.getFirstOnly().setCellRenderer(new CyNodeListCellRenderer());
174             this.ternaryVennList.getFirstSecond().setCellRenderer(new CyNodeListCellRenderer());
175             this.ternaryVennList.getFirstThird().setCellRenderer(new CyNodeListCellRenderer());
176             this.ternaryVennList.getIntersection().setCellRenderer(new CyNodeListCellRenderer());
177             this.ternaryVennList.getSecond().setCellRenderer(new CyNodeListCellRenderer());
178             this.ternaryVennList.getSecondOnly().setCellRenderer(new CyNodeListCellRenderer());
179             this.ternaryVennList.getSecondThird().setCellRenderer(new CyNodeListCellRenderer());
180             this.ternaryVennList.getThird().setCellRenderer(new CyNodeListCellRenderer());
181             this.ternaryVennList.getThirdOnly().setCellRenderer(new CyNodeListCellRenderer());
182             this.ternaryVennList.getUnion().setCellRenderer(new CyNodeListCellRenderer());
183         }
184         if (this.quaternaryVennList != null)
185         {
186             this.quaternaryVennList.getFirst().setCellRenderer(new CyNodeListCellRenderer());
187             this.quaternaryVennList.getFirstFourth().setCellRenderer(new CyNodeListCellRenderer());
188             this.quaternaryVennList.getFirstOnly().setCellRenderer(new CyNodeListCellRenderer());
189             this.quaternaryVennList.getFirstSecond().setCellRenderer(new CyNodeListCellRenderer());
190             this.quaternaryVennList.getFirstSecondFourth().setCellRenderer(new CyNodeListCellRenderer());
191             this.quaternaryVennList.getFirstSecondThird().setCellRenderer(new CyNodeListCellRenderer());
192             this.quaternaryVennList.getFirstThird().setCellRenderer(new CyNodeListCellRenderer());
193             this.quaternaryVennList.getFirstThirdFourth().setCellRenderer(new CyNodeListCellRenderer());
194             this.quaternaryVennList.getFourth().setCellRenderer(new CyNodeListCellRenderer());
195             this.quaternaryVennList.getFourthOnly().setCellRenderer(new CyNodeListCellRenderer());
196             this.quaternaryVennList.getIntersection().setCellRenderer(new CyNodeListCellRenderer());
197             this.quaternaryVennList.getSecond().setCellRenderer(new CyNodeListCellRenderer());
198             this.quaternaryVennList.getSecondFourth().setCellRenderer(new CyNodeListCellRenderer());
199             this.quaternaryVennList.getSecondOnly().setCellRenderer(new CyNodeListCellRenderer());
200             this.quaternaryVennList.getSecondThird().setCellRenderer(new CyNodeListCellRenderer());
201             this.quaternaryVennList.getSecondThirdFourth().setCellRenderer(new CyNodeListCellRenderer());
202             this.quaternaryVennList.getThird().setCellRenderer(new CyNodeListCellRenderer());
203             this.quaternaryVennList.getThirdFourth().setCellRenderer(new CyNodeListCellRenderer());
204             this.quaternaryVennList.getThirdOnly().setCellRenderer(new CyNodeListCellRenderer());
205             this.quaternaryVennList.getUnion().setCellRenderer(new CyNodeListCellRenderer());
206         }
207 
208         InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
209         int menuKeyMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
210         KeyStroke ctrlShiftA = KeyStroke.getKeyStroke(KeyEvent.VK_A, menuKeyMask | InputEvent.SHIFT_DOWN_MASK);
211         KeyStroke ctrlShiftC = KeyStroke.getKeyStroke(KeyEvent.VK_C, menuKeyMask | InputEvent.SHIFT_DOWN_MASK);
212         inputMap.put(ctrlShiftA, "selectAll");
213         inputMap.put(ctrlShiftC, "clearSelection");
214         getActionMap().put("selectAll", selectAll);
215         getActionMap().put("clearSelection", clearSelection);
216 
217         JMenuItem selectAllMenuItem = new JMenuItem(selectAll);
218         selectAllMenuItem.setAccelerator(ctrlShiftA);
219         JMenuItem clearSelectionMenuItem = new JMenuItem(clearSelection);
220         clearSelectionMenuItem.setAccelerator(ctrlShiftC);
221 
222         JPopupMenu contextMenu = new JPopupMenu();
223         contextMenu.add(selectAllMenuItem);
224         contextMenu.add(clearSelectionMenuItem);
225 
226         IdToolBar toolBar = new IdToolBar();
227         // todo:  odd border decorations on Win L&F
228         toolBar.add(selectAll);
229         toolBar.add(clearSelection);
230         toolBar.displayText();
231 
232         setLayout(new BorderLayout());
233         add("North", toolBar);
234         addMouseListener(new ContextMenuListener(contextMenu));
235     }
236 
237     /**
238      * Create a new details view with the specified binary venn list.
239      *
240      * @param binaryVennList binary venn list
241      */
242     DetailsView(final BinaryVennList<CyNode> binaryVennList)
243     {
244         this(binaryVennList, null, null);
245         binaryVennList.setBorder(new EmptyBorder(12, 12, 12, 12));
246         if (binaryVennList.getModel().union().size() > BINARY_SELECTION_SYNC_MAXIMUM)
247         {
248             selectAll.setEnabled(false);
249             clearSelection.setEnabled(false);
250         }
251         else
252         {
253             binaryVennList.getModel().selection().addSetChangeListener(updateCytoscapeSelection);
254         }
255         add("Center", binaryVennList);
256     }
257 
258     /**
259      * Create a new details view with the specified ternary venn list.
260      *
261      * @param ternaryVennList ternary venn list
262      */
263     DetailsView(final TernaryVennList<CyNode> ternaryVennList)
264     {
265         this(null, ternaryVennList, null);
266         ternaryVennList.setBorder(new EmptyBorder(12, 12, 12, 12));
267         if (ternaryVennList.getModel().union().size() > TERNARY_SELECTION_SYNC_MAXIMUM)
268         {
269             selectAll.setEnabled(false);
270             clearSelection.setEnabled(false);
271         }
272         else
273         {
274             ternaryVennList.getModel().selection().addSetChangeListener(updateCytoscapeSelection);
275         }
276         add("Center", ternaryVennList);
277     }
278 
279     /**
280      * Create a new details view with the specified quaternary venn list.
281      *
282      * @param quaternaryVennList quaternary venn list
283      */
284     DetailsView(final QuaternaryVennList<CyNode> quaternaryVennList)
285     {
286         this(null, null, quaternaryVennList);
287         quaternaryVennList.setBorder(new EmptyBorder(12, 12, 12, 12));
288         if (quaternaryVennList.getModel().union().size() > QUATERNARY_SELECTION_SYNC_MAXIMUM)
289         {
290             selectAll.setEnabled(false);
291             clearSelection.setEnabled(false);
292         }
293         else
294         {
295             quaternaryVennList.getModel().selection().addSetChangeListener(updateCytoscapeSelection);
296         }
297         add("Center", quaternaryVennList);
298     }
299 }