RNAalifoldClient updated to be more like AAConClient and now (attempts) to support...
[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   // dan think. Do I need to change this method to run RNAalifold through the GUI
65   
66   public void initSequenceAnnotationWSClient(final Jws2Instance sh,
67           AlignFrame alignFrame, WsParamSetI preset, boolean editParams)
68   {
69         // dan changed! dan test. comment out if conditional
70 //    if (alignFrame.getViewport().getAlignment().isNucleotide())
71 //    {
72 //      JOptionPane.showMessageDialog(Desktop.desktop, sh.serviceType
73 //              + " can only be used\nfor amino acid alignments.",
74 //              "Wrong type of sequences!", JOptionPane.WARNING_MESSAGE);
75 //      return;
76 //
77 //    }
78     if (sh.action.toLowerCase().contains("conservation"))
79     {
80       // Build an AACon style client - take alignment, return annotation for
81       // columns
82
83       List<AlignCalcWorkerI> clnts = alignFrame.getViewport()
84               .getCalcManager()
85               .getRegisteredWorkersOfClass(AAConClient.class);
86       if (clnts == null || clnts.size() == 0)
87       {
88         if (!processParams(sh, editParams))
89         {
90           return;
91         }
92         AAConClient worker;
93         alignFrame
94                 .getViewport()
95                 .getCalcManager()
96                 .registerWorker(
97                         worker = new AAConClient(sh, alignFrame,
98                                 this.preset, paramset));
99         alignFrame.getViewport().getCalcManager().startWorker(worker);
100
101       }
102       else
103       {
104         AAConClient worker = (AAConClient) clnts.get(0);
105         if (editParams)
106         {
107           paramset = worker.getArguments();
108           preset = worker.getPreset();
109         }
110
111         if (!processParams(sh, editParams, true))
112         {
113           return;
114         }
115         // reinstate worker if it was blacklisted (might have happened due to
116         // invalid parameters)
117         alignFrame.getViewport().getCalcManager().workerMayRun(worker);
118         worker.updateParameters(this.preset, paramset);
119
120       }
121     }
122     if (sh.action.toLowerCase().contains("disorder"))
123     {
124       // build IUPred style client. take sequences, returns annotation per
125       // sequence.
126       if (!processParams(sh, editParams))
127       {
128         return;
129       }
130
131       alignFrame
132               .getViewport()
133               .getCalcManager()
134               .startWorker(
135                       new AADisorderClient(sh, alignFrame, preset, paramset));
136     }
137     
138     
139     // dan test dan changed!
140     if (sh.action.toLowerCase().contains("rna structure prediction"))
141     {
142
143         List<AlignCalcWorkerI> clnts = alignFrame.getViewport()
144                         .getCalcManager()
145                         .getRegisteredWorkersOfClass(RNAalifoldClient.class);
146         if (clnts == null || clnts.size() == 0)
147         {
148                 if (!processParams(sh, editParams))
149                 {
150                         return;
151                 }
152                 RNAalifoldClient worker;
153                 alignFrame
154                                                 .getViewport()
155                                                 .getCalcManager()
156                                                 .registerWorker(
157                                                                         worker = new RNAalifoldClient(sh, alignFrame,
158                                                                                                         this.preset, paramset));
159                 alignFrame.getViewport().getCalcManager().startWorker(worker);
160         }
161         else 
162         {
163                 RNAalifoldClient worker = (RNAalifoldClient) clnts.get(0);
164                 if (editParams)
165                 {
166                         paramset = worker.getArguments();
167                         preset = worker.getPreset();
168                 }
169                 
170                 if (!processParams(sh, editParams, true))
171         {
172           return;
173         }
174                 
175                 // reinstate worker if it was blacklisted (might have happened due to
176         // invalid parameters)
177         alignFrame.getViewport().getCalcManager().workerMayRun(worker);
178         worker.updateParameters(this.preset, paramset);
179         }
180         
181     }
182   }
183
184   public SequenceAnnotationWSClient(AAConSettings fave,
185           AlignFrame alignFrame, boolean b)
186   {
187     super(alignFrame, fave.getPreset(), fave.getJobArgset());
188     initSequenceAnnotationWSClient(fave.getService(), alignFrame,
189             fave.getPreset(), b);
190   }
191
192   /*
193    * (non-Javadoc)
194    * 
195    * @see jalview.ws.jws2.Jws2Client#attachWSMenuEntry(javax.swing.JMenu,
196    * jalview.ws.jws2.jabaws2.Jws2Instance, jalview.gui.AlignFrame)
197    */
198   public void attachWSMenuEntry(JMenu wsmenu, final Jws2Instance service,
199           final AlignFrame alignFrame)
200   {
201     if (service.serviceType.equals(compbio.ws.client.Services.AAConWS
202             .toString()))
203     {
204       registerAAConWSInstance(wsmenu, service, alignFrame);
205       return;
206     }
207     boolean hasparams = service.hasParameters();
208     // Assume name ends in WS
209     String calcName = service.serviceType.substring(0,
210             service.serviceType.length() - 2);
211
212     JMenuItem annotservice = new JMenuItem(calcName + " Defaults");
213     annotservice.addActionListener(new ActionListener()
214     {
215
216       @Override
217       public void actionPerformed(ActionEvent e)
218       {
219         new SequenceAnnotationWSClient(service, alignFrame, null, false);
220       }
221     });
222     wsmenu.add(annotservice);
223     if (hasparams)
224     {
225       // only add these menu options if the service has user-modifiable
226       // arguments
227       annotservice = new JMenuItem("Edit settings and run ...");
228       annotservice
229               .setToolTipText("View and change parameters before running calculation");
230
231       annotservice.addActionListener(new ActionListener()
232       {
233         public void actionPerformed(ActionEvent e)
234         {
235           new SequenceAnnotationWSClient(service, alignFrame, null, true);
236         }
237       });
238       wsmenu.add(annotservice);
239       List<WsParamSetI> presets = service.getParamStore().getPresets();
240       if (presets != null && presets.size() > 0)
241       {
242         JMenu presetlist = new JMenu("Run " + calcName + "with preset");
243
244         for (final WsParamSetI preset : presets)
245         {
246           final JMenuItem methodR = new JMenuItem(preset.getName());
247           methodR.setToolTipText("<html><p>"
248                   + JvSwingUtils.wrapTooltip("<strong>"
249                           + (preset.isModifiable() ? "User Preset"
250                                   : "Service Preset") + "</strong><br/>"
251                           + preset.getDescription() + "</p>") + "</html>");
252           methodR.addActionListener(new ActionListener()
253           {
254             public void actionPerformed(ActionEvent e)
255             {
256               new SequenceAnnotationWSClient(service, alignFrame, preset,
257                       false);
258             }
259
260           });
261           presetlist.add(methodR);
262         }
263         wsmenu.add(presetlist);
264       }
265
266     }
267     else
268     {
269       annotservice = new JMenuItem("View documentation");
270       if (service.docUrl != null)
271       {
272         annotservice.addActionListener(new ActionListener()
273         {
274
275           @Override
276           public void actionPerformed(ActionEvent arg0)
277           {
278             Desktop.instance.showUrl(service.docUrl);
279           }
280         });
281         annotservice.setToolTipText("<html>"
282                 + JvSwingUtils.wrapTooltip("View <a href=\""
283                         + service.docUrl + "\">" + service.docUrl + "</a>")
284                 + "</html>");
285         wsmenu.add(annotservice);
286       }
287     }
288   }
289
290   private final String AAconToggle = "AACon Calculations",
291           AAconToggleTooltip = "When checked, AACon calculations are updated automatically.",
292           AAeditSettings = "Change AACon Settings...",
293           AAeditSettingsTooltip = "Modify settings for AACon calculations.";
294
295   private void registerAAConWSInstance(final JMenu wsmenu,
296           final Jws2Instance service, final AlignFrame alignFrame)
297   {
298     // register this in the AACon settings set
299     JCheckBoxMenuItem _aaConEnabled = null;
300     for (int i = 0; i < wsmenu.getItemCount(); i++)
301     {
302       JMenuItem item = wsmenu.getItem(i);
303       if (item instanceof JCheckBoxMenuItem
304               && item.getText().equals(AAconToggle))
305       {
306         _aaConEnabled = (JCheckBoxMenuItem) item;
307       }
308     }
309     // is there an aaCon worker already present - if so, set it to use the
310     // given service handle
311     {
312       List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
313               .getCalcManager()
314               .getRegisteredWorkersOfClass(AAConClient.class);
315       if (aaconClient != null && aaconClient.size() > 0)
316       {
317         AAConClient worker = (AAConClient) aaconClient.get(0);
318         if (!worker.service.hosturl.equals(service.hosturl))
319         {
320           // javax.swing.SwingUtilities.invokeLater(new Runnable()
321           {
322             // @Override
323             // public void run()
324             {
325               removeCurrentAAConWorkerFor(alignFrame);
326               buildCurrentAAConWorkerFor(alignFrame, service);
327             }
328           }// );
329         }
330       }
331     }
332
333     // is there a service already registered ? there shouldn't be if we are
334     // being called correctly
335     if (_aaConEnabled == null)
336     {
337       final JCheckBoxMenuItem aaConEnabled = new JCheckBoxMenuItem(
338               AAconToggle);
339       wsmenu.addMenuListener(new MenuListener()
340       {
341
342         @Override
343         public void menuSelected(MenuEvent arg0)
344         {
345           wsmenu.setEnabled(!alignFrame.getViewport().getAlignment()
346                   .isNucleotide());
347           List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
348                   .getCalcManager()
349                   .getRegisteredWorkersOfClass(AAConClient.class);
350           if (aaconClient != null && aaconClient.size() > 0)
351           {
352             aaConEnabled.setSelected(true);
353           }
354           else
355           {
356             aaConEnabled.setSelected(false);
357           }
358         }
359
360         @Override
361         public void menuDeselected(MenuEvent arg0)
362         {
363           // TODO Auto-generated method stub
364
365         }
366
367         @Override
368         public void menuCanceled(MenuEvent arg0)
369         {
370           // TODO Auto-generated method stub
371
372         }
373       });
374       aaConEnabled.setToolTipText("<html><p>"
375               + JvSwingUtils.wrapTooltip(AAconToggleTooltip + "</p>")
376               + "</html>");
377       aaConEnabled.addActionListener(new ActionListener()
378       {
379         @Override
380         public void actionPerformed(ActionEvent arg0)
381         {
382           List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
383                   .getCalcManager()
384                   .getRegisteredWorkersOfClass(AAConClient.class);
385           if (aaconClient != null && aaconClient.size() > 0)
386           {
387             removeCurrentAAConWorkerFor(alignFrame);
388           }
389           else
390           {
391             buildCurrentAAConWorkerFor(alignFrame);
392
393           }
394         }
395
396       });
397       wsmenu.add(aaConEnabled);
398       JMenuItem modifyParams = new JMenuItem(AAeditSettings);
399       modifyParams.setToolTipText("<html><p>"
400               + JvSwingUtils.wrapTooltip(AAeditSettingsTooltip + "</p>")
401               + "</html>");
402       modifyParams.addActionListener(new ActionListener()
403       {
404
405         @Override
406         public void actionPerformed(ActionEvent arg0)
407         {
408           showAAConAnnotationSettingsFor(alignFrame);
409         }
410       });
411       wsmenu.add(modifyParams);
412
413     }
414   }
415
416   private static void showAAConAnnotationSettingsFor(AlignFrame alignFrame)
417   {
418     /*
419      * preferred settings Whether AACon is automatically recalculated Which
420      * AACon server to use What parameters to use
421      */
422     // could actually do a class search for this too
423     AAConSettings fave = (AAConSettings) alignFrame.getViewport()
424             .getCalcIdSettingsFor(AAConCalcId);
425     if (fave == null)
426     {
427       fave = createDefaultAAConSettings();
428     }
429     new SequenceAnnotationWSClient(fave, alignFrame, true);
430
431   }
432
433   private static void buildCurrentAAConWorkerFor(AlignFrame alignFrame)
434   {
435     buildCurrentAAConWorkerFor(alignFrame, null);
436   }
437
438   private static void buildCurrentAAConWorkerFor(AlignFrame alignFrame,
439           Jws2Instance service)
440   {
441     /*
442      * preferred settings Whether AACon is automatically recalculated Which
443      * AACon server to use What parameters to use
444      */
445     AAConSettings fave = (AAConSettings) alignFrame.getViewport()
446             .getCalcIdSettingsFor(AAConCalcId);
447     if (fave == null)
448     {
449       fave = createDefaultAAConSettings(service);
450     }
451     else
452     {
453       if (service != null
454               && !fave.getService().hosturl.equals(service.hosturl))
455       {
456         Cache.log.debug("Changing AACon service to " + service.hosturl
457                 + " from " + fave.getService().hosturl);
458         fave.setService(service);
459       }
460     }
461     new SequenceAnnotationWSClient(fave, alignFrame, false);
462   }
463
464   private static AAConSettings createDefaultAAConSettings()
465   {
466     return createDefaultAAConSettings(null);
467   }
468
469   private static AAConSettings createDefaultAAConSettings(
470           Jws2Instance service)
471   {
472     if (service != null)
473     {
474       if (!service.serviceType.toString().equals(
475               compbio.ws.client.Services.AAConWS.toString()))
476       {
477         Cache.log
478                 .warn("Ignoring invalid preferred service for AACon calculations (service type was "
479                         + service.serviceType + ")");
480         service = null;
481       }
482       else
483       {
484         // check service is actually in the list of currently avaialable
485         // services
486         if (!Jws2Discoverer.getDiscoverer().getServices().contains(service))
487         {
488           // it isn't ..
489           service = null;
490         }
491       }
492     }
493     if (service == null)
494     {
495       // get the default service for AACon
496       service = Jws2Discoverer.getDiscoverer().getPreferredServiceFor(null,
497               compbio.ws.client.Services.AAConWS.toString());
498     }
499     if (service == null)
500     {
501       // TODO raise dialog box explaining error, and/or open the JABA
502       // preferences menu.
503       throw new Error("No AACon service found.");
504     }
505     return new AAConSettings(true, service, null, null);
506   }
507
508   private static void removeCurrentAAConWorkerFor(AlignFrame alignFrame)
509   {
510     alignFrame.getViewport().getCalcManager()
511             .removeRegisteredWorkersOfClass(AAConClient.class);
512   }
513 }