JAL-2360 ColourMenuHelper now builds and selects items in colour menu
[jalview.git] / src / jalview / gui / ColourMenuHelper.java
1 package jalview.gui;
2
3 import jalview.datamodel.AnnotatedCollectionI;
4 import jalview.schemes.ColourSchemeI;
5 import jalview.schemes.ColourSchemes;
6 import jalview.schemes.ResidueColourScheme;
7 import jalview.schemes.UserColourScheme;
8 import jalview.util.MessageManager;
9
10 import java.awt.Component;
11 import java.awt.event.ActionEvent;
12 import java.awt.event.ActionListener;
13 import java.awt.event.MouseAdapter;
14 import java.awt.event.MouseEvent;
15
16 import javax.swing.ButtonGroup;
17 import javax.swing.JMenu;
18 import javax.swing.JRadioButtonMenuItem;
19
20 public class ColourMenuHelper
21 {
22   public interface ColourChangeListener
23   {
24     void changeColour_actionPerformed(String name);
25   }
26
27   /**
28    * Adds items to the colour menu, as mutually exclusive members of a button
29    * group. The callback handler is responsible for the action on selecting any
30    * of these options. It is returned the name of the selected colour, or "None"
31    * or "User Defined".
32    * <ul>
33    * <li>None</li>
34    * <li>Clustal</li>
35    * <li>...other 'built-in' colours</li>
36    * <li>...any user-defined colours</li>
37    * <li>User Defined..</li>
38    * </ul>
39    * 
40    * @param colourMenu
41    *          the menu to attach items to
42    * @param client
43    *          a callback to handle menu selection
44    * @param coll
45    *          the data the menu is being built for
46    */
47   public static void addMenuItems(final JMenu colourMenu,
48           final ColourChangeListener client, AnnotatedCollectionI coll)
49   {
50     /*
51      * ButtonGroup groups those items whose 
52      * selection is mutually exclusive
53      */
54     ButtonGroup colours = new ButtonGroup();
55     JRadioButtonMenuItem noColourmenuItem = new JRadioButtonMenuItem(
56             MessageManager.getString("label.none"));
57     noColourmenuItem.setName(ResidueColourScheme.NONE);
58     noColourmenuItem.addActionListener(new ActionListener()
59     {
60       @Override
61       public void actionPerformed(ActionEvent e)
62       {
63         client.changeColour_actionPerformed(ResidueColourScheme.NONE);
64       }
65     });
66     colourMenu.add(noColourmenuItem);
67     colours.add(noColourmenuItem);
68
69     /*
70      * scan registered colour schemes (built-in or user-defined
71      * and add them to the menu (in the order they were added)
72      */
73     Iterable<ColourSchemeI> colourSchemes = ColourSchemes.getInstance()
74             .getColourSchemes();
75     for (ColourSchemeI scheme : colourSchemes)
76     {
77       /*
78        * button text is i18n'd but the name is the canonical name of
79        * the colour scheme (inspected in changeColour_actionPerformed)
80        */
81       final String name = scheme.getSchemeName();
82       String label = MessageManager.getStringOrReturn("label.colourScheme_"
83               + name.toLowerCase().replace(" ", "_"), name);
84       final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(label);
85       radioItem.setName(name);
86       radioItem.setEnabled(scheme.isApplicableTo(coll));
87       if (scheme instanceof UserColourScheme)
88       {
89         /*
90          * user-defined colour scheme loaded on startup or during the
91          * Jalview session; right-click on this offers the option to
92          * remove it as a colour choice
93          */
94         radioItem.addMouseListener(new MouseAdapter()
95         {
96           @Override
97           public void mousePressed(MouseEvent evt)
98           {
99             if (evt.isPopupTrigger()) // Mac
100             {
101               offerRemoval();
102             }
103           }
104
105           @Override
106           public void mouseReleased(MouseEvent evt)
107           {
108             if (evt.isPopupTrigger()) // Windows
109             {
110               offerRemoval();
111             }
112           }
113
114           void offerRemoval()
115           {
116             ActionListener al = radioItem.getActionListeners()[0];
117             radioItem.removeActionListener(al);
118             int option = JvOptionPane.showInternalConfirmDialog(
119                     Desktop.desktop, MessageManager
120                             .getString("label.remove_from_default_list"),
121                     MessageManager
122                             .getString("label.remove_user_defined_colour"),
123                     JvOptionPane.YES_NO_OPTION);
124             if (option == JvOptionPane.YES_OPTION)
125             {
126               UserDefinedColours.removeColourFromDefaults(radioItem
127                       .getName());
128               ColourSchemes.getInstance().removeColourScheme(
129                       radioItem.getName());
130               colourMenu.remove(radioItem);
131             }
132             else
133             {
134               radioItem.addActionListener(al);
135             }
136           }
137         });
138       }
139       radioItem.addActionListener(new ActionListener()
140       {
141         @Override
142         public void actionPerformed(ActionEvent evt)
143         {
144           client.changeColour_actionPerformed(name);
145         }
146       });
147       colourMenu.add(radioItem);
148       colours.add(radioItem);
149     }
150
151     final String label = MessageManager.getString("action.user_defined");
152     JRadioButtonMenuItem userDefinedColour = new JRadioButtonMenuItem(label);
153     userDefinedColour.addActionListener(new ActionListener()
154     {
155       @Override
156       public void actionPerformed(ActionEvent e)
157       {
158         client.changeColour_actionPerformed(ResidueColourScheme.USER_DEFINED);
159       }
160     });
161     colourMenu.add(userDefinedColour);
162     colours.add(userDefinedColour);
163   }
164
165   /**
166    * Marks as selected the colour menu item matching the given name, or the
167    * first item ('None') if no match is found
168    * 
169    * @param colourMenu
170    * @param colourName
171    */
172   public static void setColourSelected(JMenu colourMenu, String colourName)
173   {
174     if (colourName == null)
175     {
176       return;
177     }
178
179     JRadioButtonMenuItem none = null;
180
181     /*
182      * select the radio button whose name matches the colour name
183      * (not the button text, as it may be internationalised)
184      */
185     for (Component menuItem : colourMenu.getMenuComponents())
186     {
187       if (menuItem instanceof JRadioButtonMenuItem)
188       {
189         String buttonName = ((JRadioButtonMenuItem) menuItem).getName();
190         if (colourName.equals(buttonName))
191         {
192           ((JRadioButtonMenuItem) menuItem).setSelected(true);
193           return;
194         }
195         if (ResidueColourScheme.NONE.equals(buttonName))
196         {
197           none = (JRadioButtonMenuItem) menuItem;
198         }
199       }
200     }
201     if (none != null)
202     {
203       none.setSelected(true);
204     }
205   }
206
207   /**
208    * Marks as selected the colour menu item matching the given colour scheme, or
209    * the first item ('None') if no match is found
210    * 
211    * @param colourMenu
212    * @param cs
213    */
214   public static void setColourSelected(JMenu colourMenu, ColourSchemeI cs)
215   {
216     setColourSelected(colourMenu, cs == null ? ResidueColourScheme.NONE
217             : cs.getSchemeName());
218   }
219 }