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