c5433e5b9fed44c7e8fb11c869661deb937e54dc
[jalview.git] / src / jalview / gui / ViewSelectionMenu.java
1 package jalview.gui;
2
3 import java.awt.Component;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.ItemEvent;
7 import java.awt.event.ItemListener;
8 import java.awt.event.MouseEvent;
9 import java.awt.event.MouseListener;
10 import java.util.List;
11
12 import javax.swing.JCheckBoxMenuItem;
13 import javax.swing.JMenu;
14 import javax.swing.JMenuItem;
15 import javax.swing.event.MenuEvent;
16 import javax.swing.event.MenuListener;
17
18 /**
19  * this is an implementation of an abstract Jalview GUI class that provides a
20  * dialog/menu which allows the user to select/deselect specific views from a
21  * list of associated views.
22  * 
23  * Includes patches related to JAL-641
24  * 
25  * @author JimP
26  * 
27  */
28 public class ViewSelectionMenu extends JMenu
29 {
30   public interface ViewSetProvider
31   {
32     public AlignmentPanel[] getAllAlignmentPanels();
33   }
34
35   private ViewSetProvider _allviews;
36
37   private List<AlignmentPanel> _selectedviews;
38
39   private ItemListener _handler;
40
41   @Override
42   protected void finalize() throws Throwable
43   {
44     _selectedviews = null;
45     _handler = null;
46     _allviews = null;
47     super.finalize();
48   }
49
50   /**
51    * create a new view selection menu. This menu has some standard entries
52    * (select all, invert selection), and a checkbox for every view. Mousing over
53    * a view entry will cause it to be raised/selected in the Desktop, allowing
54    * the user to easily identify which view is being referred to.
55    * 
56    * @param title
57    *          Name of menu
58    * @param allviews
59    *          all the views that might be selected
60    * @param selectedviews
61    *          the list of selected views which will be updated when
62    *          selection/deselections occur
63    * @param handler
64    *          a handler called for each selection/deselection - use this to
65    *          update any gui elements which need to reflect current
66    *          selection/deselection state
67    */
68   public ViewSelectionMenu(String title, final ViewSetProvider allviews,
69           final List<AlignmentPanel> selectedviews,
70           final ItemListener handler)
71   {
72     super(title);
73     this._allviews = allviews;
74     this._selectedviews = selectedviews;
75     this._handler = handler;
76     addMenuListener(new MenuListener()
77     {
78
79       @Override
80       public void menuSelected(MenuEvent e)
81       {
82         rebuild();
83
84       }
85
86       @Override
87       public void menuDeselected(MenuEvent e)
88       {
89         // TODO Auto-generated method stub
90
91       }
92
93       @Override
94       public void menuCanceled(MenuEvent e)
95       {
96         // TODO Auto-generated method stub
97
98       }
99     });
100   }
101
102   /**
103    * view selection modifier flag - indicates if an action key is pressed when
104    * menu selection event occurred.
105    */
106   private boolean append = false;
107   /**
108    * flag indicating if the itemStateChanged listener for view associated menu items is currently enabled 
109    */
110   private boolean enabled = true;
111   private JMenuItem selectAll, invertSel;
112   private JCheckBoxMenuItem toggleview=null;
113   private void rebuild()
114   {
115     removeAll();
116     AlignmentPanel[] allviews = _allviews.getAllAlignmentPanels();
117     if (allviews == null)
118     {
119       setVisible(false);
120       return;
121     }
122     if (allviews.length >= 2)
123     {
124       // ensure we update menu state to reflect external selection list state
125       append = append || _selectedviews.size()>1;
126       toggleview = new JCheckBoxMenuItem("Select many views",append);
127       toggleview.setToolTipText("When enabled, allows many views to be selected.");
128       toggleview.addItemListener(new ItemListener() {
129
130         @Override
131         public void itemStateChanged(ItemEvent arg0)
132         {
133           if (enabled)
134           {
135             append = !append;
136             selectAll.setEnabled(append);
137             invertSel.setEnabled(append);
138           }
139           
140         }
141         
142       });
143       add(toggleview);
144       add(selectAll= new JMenuItem("Select all views"));
145       selectAll.addActionListener(new ActionListener()
146       {
147
148         @Override
149         public void actionPerformed(ActionEvent e)
150         {
151           for (Component c : getMenuComponents())
152           {
153             boolean t=append;
154             append=true;
155             if (c instanceof JCheckBoxMenuItem)
156             {
157               if (toggleview!=c && !((JCheckBoxMenuItem) c).isSelected())
158               {
159                 ((JCheckBoxMenuItem) c).doClick();
160               }
161             }
162             append=t;
163           }
164         }
165       });
166       add(invertSel = new JMenuItem("Invert selection"));
167       invertSel.addActionListener(new ActionListener()
168       {
169
170         @Override
171         public void actionPerformed(ActionEvent e)
172         {
173           boolean t=append;
174           append=true;
175           for (Component c : getMenuComponents())
176           {
177             if (toggleview!=c && c instanceof JCheckBoxMenuItem)
178             {
179               ((JCheckBoxMenuItem) c).doClick();
180             }
181           }
182           append=t;
183         }
184       });
185       invertSel.setEnabled(append);
186       selectAll.setEnabled(append);
187     }
188     for (AlignmentPanel ap : allviews)
189     {
190       String nm = ((ap.getViewName() == null || ap.getViewName().length() == 0) ? ""
191               : ap.getViewName() + " for ")
192               + ap.alignFrame.getTitle();
193       final JCheckBoxMenuItem a = new JCheckBoxMenuItem(nm,
194               _selectedviews.contains(ap));
195       final AlignmentPanel p = ap;
196       a.addItemListener(new ItemListener()
197       {
198         @Override
199         public void itemStateChanged(ItemEvent e)
200         {
201           if (enabled)
202           {
203           if (append)
204           {
205             enabled=false;
206             // toggle the inclusion state
207             if (_selectedviews.indexOf(p)==-1)
208             {
209               _selectedviews.add(p);
210               a.setSelected(true);
211             }
212             else
213             {
214               _selectedviews.remove(p);
215               a.setSelected(false);
216             }
217             enabled=true;
218             _handler.itemStateChanged(e);
219           }
220           else
221           {
222             // Deselect everything and select this item only
223             _selectedviews.clear();
224             _selectedviews.add(p);
225             enabled=false;
226             for (Component c : getMenuComponents())
227             {
228               if (c instanceof JCheckBoxMenuItem)
229               {
230                 ((JCheckBoxMenuItem) c).setSelected(a == c);
231               }
232             }
233             enabled=true;
234             // only fire event if we weren't selected before
235             _handler.itemStateChanged(e);
236           }
237           }
238         }
239       });
240       a.addMouseListener(new MouseListener()
241       {
242
243         @Override
244         public void mouseReleased(MouseEvent e)
245         {
246           // TODO Auto-generated method stub
247
248         }
249
250         @Override
251         public void mousePressed(MouseEvent e)
252         {
253           // TODO Auto-generated method stub
254
255         }
256
257         @Override
258         public void mouseExited(MouseEvent e)
259         {
260           try
261           {
262             p.setSelected(false);
263           } catch (Exception ex)
264           {
265           }
266           ;
267         }
268
269         @Override
270         public void mouseEntered(MouseEvent e)
271         {
272
273           try
274           {
275             p.setSelected(true);
276           } catch (Exception ex)
277           {
278           }
279           ;
280         }
281
282         @Override
283         public void mouseClicked(MouseEvent e)
284         {
285         }
286       });
287       add(a);
288     }
289   }
290
291 }