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