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