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