JAL-1137 JAL-975 simpler menu for the AACon service - allows user to switch calculati...
[jalview.git] / src / jalview / ws / jws2 / SequenceAnnotationWSClient.java
1 /**
2  * 
3  */
4 package jalview.ws.jws2;
5
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.util.List;
9
10 import javax.swing.JCheckBoxMenuItem;
11 import javax.swing.JMenu;
12 import javax.swing.JMenuItem;
13 import javax.swing.JOptionPane;
14 import javax.swing.event.AncestorEvent;
15 import javax.swing.event.AncestorListener;
16 import javax.swing.event.MenuEvent;
17 import javax.swing.event.MenuListener;
18
19 import compbio.metadata.Argument;
20
21 import jalview.api.AlignCalcWorkerI;
22 import jalview.bin.Cache;
23 import jalview.datamodel.AlignmentView;
24 import jalview.gui.AlignFrame;
25 import jalview.gui.Desktop;
26 import jalview.gui.JalviewDialog;
27 import jalview.gui.JvSwingUtils;
28 import jalview.ws.jws2.dm.AAConsSettings;
29 import jalview.ws.jws2.jabaws2.Jws2Instance;
30 import jalview.ws.params.WsParamSetI;
31
32 /**
33  * @author jprocter 
34  * 
35  */
36 public class SequenceAnnotationWSClient extends Jws2Client 
37 {
38
39   public static final String AAConsCalcId = "jabaws2.AACons";
40
41   /**
42    * initialise a client so its attachWSMenuEntry method can be called.
43    */
44   public SequenceAnnotationWSClient()
45   {
46     // TODO Auto-generated constructor stub
47   }
48
49   public SequenceAnnotationWSClient(final Jws2Instance sh,
50           AlignFrame alignFrame, WsParamSetI preset, boolean editParams)
51   {
52     super(alignFrame, preset, null);
53     initSequenceAnnotationWSClient(sh, alignFrame, preset, editParams);
54   }
55
56   public void initSequenceAnnotationWSClient(final Jws2Instance sh,
57           AlignFrame alignFrame, WsParamSetI preset, boolean editParams)
58   {
59     if (alignFrame.getViewport().getAlignment().isNucleotide())
60     {
61       JOptionPane.showMessageDialog(Desktop.desktop, sh.serviceType
62               + " can only be used\nfor amino acid alignments.",
63               "Wrong type of sequences!", JOptionPane.WARNING_MESSAGE);
64       return;
65
66     }
67     if (sh.action.toLowerCase().contains("conservation"))
68     {
69       // Build an AACons style client - take alignment, return annotation for
70       // columns
71
72       List<AlignCalcWorkerI> clnts = alignFrame.getViewport()
73               .getCalcManager()
74               .getRegisteredWorkersOfClass(AAConsClient.class);
75       if (clnts == null || clnts.size() == 0)
76       {
77         if (!processParams(sh, editParams))
78         {
79           return;
80         }
81         AAConsClient worker;
82         alignFrame
83                 .getViewport()
84                 .getCalcManager()
85                 .registerWorker(
86                         worker = new AAConsClient(sh, alignFrame,
87                                 this.preset, paramset));
88         alignFrame.getViewport().getCalcManager().startWorker(worker);
89
90       }
91       else
92       {
93         AAConsClient worker = (AAConsClient) clnts.get(0);
94         if (editParams)
95         {
96           paramset = worker.getArguments();
97           preset = worker.getPreset();
98         }
99
100         if (!processParams(sh, editParams, true))
101         {
102           return;
103         }
104         // reinstate worker if it was blacklisted (might have happened due to
105         // invalid parameters)
106         alignFrame.getViewport().getCalcManager().workerMayRun(worker);
107         worker.updateParameters(this.preset, paramset);
108
109       }
110     }
111     if (sh.action.toLowerCase().contains("disorder"))
112     {
113       // build IUPred style client. take sequences, returns annotation per
114       // sequence.
115       if (!processParams(sh, editParams))
116       {
117         return;
118       }
119
120       alignFrame
121               .getViewport()
122               .getCalcManager()
123               .startWorker(
124                       new AADisorderClient(sh, alignFrame, preset, paramset));
125     }
126
127   }
128
129   public SequenceAnnotationWSClient(AAConsSettings fave,
130           AlignFrame alignFrame, boolean b)
131   {
132     super(alignFrame, fave.getPreset(), fave.getJobArgset());
133     initSequenceAnnotationWSClient(fave.getService(), alignFrame,
134             fave.getPreset(), b);
135   }
136
137   /*
138    * (non-Javadoc)
139    * 
140    * @see jalview.ws.jws2.Jws2Client#attachWSMenuEntry(javax.swing.JMenu,
141    * jalview.ws.jws2.jabaws2.Jws2Instance, jalview.gui.AlignFrame)
142    */
143   public void attachWSMenuEntry(JMenu wsmenu, final Jws2Instance service,
144           final AlignFrame alignFrame)
145   {
146     if (service.serviceType.equals(compbio.ws.client.Services.AAConWS
147             .toString()))
148     {
149       registerAAConsWSInstance(wsmenu, service, alignFrame);
150       return;
151     }
152     boolean hasparams = service.hasParameters();
153     // Assume name ends in WS
154     String calcName = service.serviceType.substring(0,
155             service.serviceType.length() - 2);
156
157     JMenuItem aacons = new JMenuItem(calcName + " Defaults");
158     aacons.addActionListener(new ActionListener()
159     {
160
161       @Override
162       public void actionPerformed(ActionEvent e)
163       {
164         new SequenceAnnotationWSClient(service, alignFrame, null, false);
165       }
166     });
167     wsmenu.add(aacons);
168     if (hasparams)
169     {
170       // only add these menu options if the service has user-modifiable
171       // arguments
172       aacons = new JMenuItem("Edit settings and run ...");
173       aacons.setToolTipText("View and change parameters before running calculation");
174
175       aacons.addActionListener(new ActionListener()
176       {
177         public void actionPerformed(ActionEvent e)
178         {
179           new SequenceAnnotationWSClient(service, alignFrame, null, true);
180         }
181       });
182       wsmenu.add(aacons);
183       List<WsParamSetI> presets = service.getParamStore().getPresets();
184       if (presets != null && presets.size() > 0)
185       {
186         JMenu presetlist = new JMenu("Run " + calcName + "with preset");
187
188         for (final WsParamSetI preset : presets)
189         {
190           final JMenuItem methodR = new JMenuItem(preset.getName());
191           methodR.setToolTipText("<html><p>"
192                   + JvSwingUtils.wrapTooltip("<strong>"
193                           + (preset.isModifiable() ? "User Preset"
194                                   : "Service Preset") + "</strong><br/>"
195                           + preset.getDescription() + "</p>") + "</html>");
196           methodR.addActionListener(new ActionListener()
197           {
198             public void actionPerformed(ActionEvent e)
199             {
200               new SequenceAnnotationWSClient(service, alignFrame, preset,
201                       false);
202             }
203
204           });
205           presetlist.add(methodR);
206         }
207         wsmenu.add(presetlist);
208       }
209
210     }
211   }
212
213   private final String AAconsToggle = "AACons Calculations",
214           AAconsToggleTooltip = "When checked, AACons calculations are updated automatically.",
215           AAeditSettings = "Change AACons Settings...",
216           AAeditSettingsTooltip = "Modify settings for AACons calculations.";
217
218   // private final enableAAConsCalculation(final AlignFrame alignFrame, )
219   private void registerAAConsWSInstance(final JMenu wsmenu,
220           final Jws2Instance service, final AlignFrame alignFrame)
221   {
222     // register this in the AACons settings set
223     JCheckBoxMenuItem _aaConsEnabled = null;
224     for (int i = 0; i < wsmenu.getItemCount(); i++)
225     {
226       JMenuItem item = wsmenu.getItem(i);
227       if (item instanceof JCheckBoxMenuItem
228               && item.getText().equals(AAconsToggle))
229       {
230         _aaConsEnabled = (JCheckBoxMenuItem) item;
231       }
232     }
233     // is there an aaCons worker already present - if so, set it to use the
234     // given service handle
235     {
236       List<AlignCalcWorkerI> aaconsClient = alignFrame.getViewport()
237               .getCalcManager()
238               .getRegisteredWorkersOfClass(AAConsClient.class);
239       if (aaconsClient != null && aaconsClient.size() > 0)
240       {
241         AAConsClient worker = (AAConsClient) aaconsClient.get(0);
242         if (!worker.service.hosturl.equals(service.hosturl))
243         {
244          // javax.swing.SwingUtilities.invokeLater(new Runnable()
245           {
246          //   @Override
247          //   public void run()
248             {
249               removeCurrentAAConsWorkerFor(alignFrame);
250               buildCurrentAAConsWorkerFor(alignFrame, service);
251             }
252           }//);
253         }
254       }
255     }
256
257     // is there a service already registered ? there shouldn't be if we are
258     // being called correctly
259     if (_aaConsEnabled == null)
260     {
261       final JCheckBoxMenuItem aaConsEnabled = new JCheckBoxMenuItem(
262               AAconsToggle);
263       wsmenu.addMenuListener(new MenuListener()
264       {
265
266         @Override
267         public void menuSelected(MenuEvent arg0)
268         {
269           wsmenu.setEnabled(!alignFrame.getViewport().getAlignment()
270                   .isNucleotide());
271           List<AlignCalcWorkerI> aaconsClient = alignFrame.getViewport()
272                   .getCalcManager()
273                   .getRegisteredWorkersOfClass(AAConsClient.class);
274           if (aaconsClient != null && aaconsClient.size() > 0)
275           {
276             aaConsEnabled.setSelected(true);
277           }
278           else
279           {
280             aaConsEnabled.setSelected(false);
281           }
282         }
283
284         @Override
285         public void menuDeselected(MenuEvent arg0)
286         {
287           // TODO Auto-generated method stub
288
289         }
290
291         @Override
292         public void menuCanceled(MenuEvent arg0)
293         {
294           // TODO Auto-generated method stub
295
296         }
297       });
298       aaConsEnabled.setToolTipText("<html><p>"
299               + JvSwingUtils.wrapTooltip(AAconsToggleTooltip + "</p>")
300               + "</html>");
301       aaConsEnabled.addActionListener(new ActionListener()
302       {
303         @Override
304         public void actionPerformed(ActionEvent arg0)
305         {
306           // aaConsEnabled.setSelected(!aaConsEnabled.isSelected());
307           List<AlignCalcWorkerI> aaconsClient = alignFrame.getViewport()
308                   .getCalcManager()
309                   .getRegisteredWorkersOfClass(AAConsClient.class);
310           if (aaconsClient != null && aaconsClient.size() > 0)
311           {
312             removeCurrentAAConsWorkerFor(alignFrame);
313           }
314           else
315           {
316             buildCurrentAAConsWorkerFor(alignFrame);
317
318           }
319         }
320
321       });
322       wsmenu.add(aaConsEnabled);
323       JMenuItem modifyParams = new JMenuItem(AAeditSettings);
324       modifyParams.setToolTipText("<html><p>"
325               + JvSwingUtils.wrapTooltip(AAeditSettingsTooltip + "</p>")
326               + "</html>");
327       modifyParams.addActionListener(new ActionListener()
328       {
329
330         @Override
331         public void actionPerformed(ActionEvent arg0)
332         {
333           showAAConsAnnotationSettingsFor(alignFrame);
334         }
335       });
336       wsmenu.add(modifyParams);
337
338     }
339   }
340
341   private static void showAAConsAnnotationSettingsFor(AlignFrame alignFrame)
342   {
343     /*
344      * preferred settings Whether AACons is automatically recalculated Which
345      * AACons server to use What parameters to use
346      */
347     // could actually do a class search for this too
348     AAConsSettings fave = (AAConsSettings) alignFrame.getViewport()
349             .getCalcIdSettingsFor(AAConsCalcId);
350     if (fave == null)
351     {
352       fave = createDefaultAAConsSettings();
353     }
354     new SequenceAnnotationWSClient(fave, alignFrame, true);
355
356   }
357
358   private static void buildCurrentAAConsWorkerFor(AlignFrame alignFrame)
359   {
360     buildCurrentAAConsWorkerFor(alignFrame, null);
361   }
362
363   private static void buildCurrentAAConsWorkerFor(AlignFrame alignFrame,
364           Jws2Instance service)
365   {
366     /*
367      * preferred settings Whether AACons is automatically recalculated Which
368      * AACons server to use What parameters to use
369      */
370     AAConsSettings fave = (AAConsSettings) alignFrame.getViewport()
371             .getCalcIdSettingsFor(AAConsCalcId);
372     if (fave == null)
373     {
374       fave = createDefaultAAConsSettings(service);
375     }
376     else
377     {
378       if (service != null
379               && !fave.getService().hosturl.equals(service.hosturl))
380       {
381         Cache.log.debug("Changing AACons service to " + service.hosturl
382                 + " from " + fave.getService().hosturl);
383         fave.setService(service);
384       }
385     }
386     new SequenceAnnotationWSClient(fave, alignFrame, false);
387   }
388
389   private static AAConsSettings createDefaultAAConsSettings()
390   {
391     return createDefaultAAConsSettings(null);
392   }
393
394   private static AAConsSettings createDefaultAAConsSettings(
395           Jws2Instance service)
396   {
397     if (service != null)
398     {
399       if (!service.serviceType.toString().equals(
400               compbio.ws.client.Services.AAConWS.toString()))
401       {
402         Cache.log
403                 .warn("Ignoring invalid preferred service for AACons calculations (service type was "
404                         + service.serviceType + ")");
405         service = null;
406       }
407       else
408       {
409         // check service is actually in the list of currently avaialable
410         // services
411         if (!Jws2Discoverer.getDiscoverer().getServices().contains(service))
412         {
413           // it isn't ..
414           service = null;
415         }
416       }
417     }
418     if (service == null)
419     {
420       // get the default service for AACons
421       service = Jws2Discoverer.getDiscoverer().getPreferredServiceFor(null,
422               compbio.ws.client.Services.AAConWS.toString());
423       /*
424        * for (Jws2Instance sv : Jws2Discoverer.getDiscoverer().getServices()) {
425        * if (sv.serviceType.toString().equals(
426        * compbio.ws.client.Services.AAConWS.toString())) { service = sv; break;
427        * } }
428        */
429     }
430     if (service == null)
431     {
432       // TODO raise dialog box explaining error, and/or open the JABA
433       // preferences menu.
434       throw new Error("No AACons service found.");
435     }
436     return new AAConsSettings(true, service, null, null);
437   }
438
439   private static void removeCurrentAAConsWorkerFor(AlignFrame alignFrame)
440   {
441     alignFrame.getViewport().getCalcManager()
442             .removeRegisteredWorkersOfClass(AAConsClient.class);
443     // AAConsClient.removeAAConsAnnotation(alignFrame.alignPanel);
444
445   }
446 }