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