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