JAL-1358 jalview displays some RNA struture annotation but the format is very messed up
[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 //      if (!processParams(sh, editParams, true))
185 //      {
186 //              return;
187 //      }
188 //
189 //      alignFrame
190 //                      .getViewport()
191 //                      .getCalcManager()
192 //                      .startWorker(
193 //                                      new RNAalifoldClient(sh, alignFrame, preset, paramset));
194 //      
195     
196   }
197
198   public SequenceAnnotationWSClient(AAConSettings fave,
199           AlignFrame alignFrame, boolean b)
200   {
201     super(alignFrame, fave.getPreset(), fave.getJobArgset());
202     initSequenceAnnotationWSClient(fave.getService(), alignFrame,
203             fave.getPreset(), b);
204   }
205
206   /*
207    * (non-Javadoc)
208    * 
209    * @see jalview.ws.jws2.Jws2Client#attachWSMenuEntry(javax.swing.JMenu,
210    * jalview.ws.jws2.jabaws2.Jws2Instance, jalview.gui.AlignFrame)
211    */
212   public void attachWSMenuEntry(JMenu wsmenu, final Jws2Instance service,
213           final AlignFrame alignFrame)
214   {
215     if (service.serviceType.equals(compbio.ws.client.Services.AAConWS
216             .toString()))
217     {
218       registerAAConWSInstance(wsmenu, service, alignFrame);
219       return;
220     }
221     boolean hasparams = service.hasParameters();
222     // Assume name ends in WS
223     String calcName = service.serviceType.substring(0,
224             service.serviceType.length() - 2);
225
226     JMenuItem annotservice = new JMenuItem(calcName + " Defaults");
227     annotservice.addActionListener(new ActionListener()
228     {
229
230       @Override
231       public void actionPerformed(ActionEvent e)
232       {
233         new SequenceAnnotationWSClient(service, alignFrame, null, false);
234       }
235     });
236     wsmenu.add(annotservice);
237     if (hasparams)
238     {
239       // only add these menu options if the service has user-modifiable
240       // arguments
241       annotservice = new JMenuItem("Edit settings and run ...");
242       annotservice
243               .setToolTipText("View and change parameters before running calculation");
244
245       annotservice.addActionListener(new ActionListener()
246       {
247         public void actionPerformed(ActionEvent e)
248         {
249           new SequenceAnnotationWSClient(service, alignFrame, null, true);
250         }
251       });
252       wsmenu.add(annotservice);
253       List<WsParamSetI> presets = service.getParamStore().getPresets();
254       if (presets != null && presets.size() > 0)
255       {
256         JMenu presetlist = new JMenu("Run " + calcName + "with preset");
257
258         for (final WsParamSetI preset : presets)
259         {
260           final JMenuItem methodR = new JMenuItem(preset.getName());
261           methodR.setToolTipText("<html><p>"
262                   + JvSwingUtils.wrapTooltip("<strong>"
263                           + (preset.isModifiable() ? "User Preset"
264                                   : "Service Preset") + "</strong><br/>"
265                           + preset.getDescription() + "</p>") + "</html>");
266           methodR.addActionListener(new ActionListener()
267           {
268             public void actionPerformed(ActionEvent e)
269             {
270               new SequenceAnnotationWSClient(service, alignFrame, preset,
271                       false);
272             }
273
274           });
275           presetlist.add(methodR);
276         }
277         wsmenu.add(presetlist);
278       }
279
280     }
281     else
282     {
283       annotservice = new JMenuItem("View documentation");
284       if (service.docUrl != null)
285       {
286         annotservice.addActionListener(new ActionListener()
287         {
288
289           @Override
290           public void actionPerformed(ActionEvent arg0)
291           {
292             Desktop.instance.showUrl(service.docUrl);
293           }
294         });
295         annotservice.setToolTipText("<html>"
296                 + JvSwingUtils.wrapTooltip("View <a href=\""
297                         + service.docUrl + "\">" + service.docUrl + "</a>")
298                 + "</html>");
299         wsmenu.add(annotservice);
300       }
301     }
302   }
303
304   private final String AAconToggle = "AACon Calculations",
305           AAconToggleTooltip = "When checked, AACon calculations are updated automatically.",
306           AAeditSettings = "Change AACon Settings...",
307           AAeditSettingsTooltip = "Modify settings for AACon calculations.";
308
309   private void registerAAConWSInstance(final JMenu wsmenu,
310           final Jws2Instance service, final AlignFrame alignFrame)
311   {
312     // register this in the AACon settings set
313     JCheckBoxMenuItem _aaConEnabled = null;
314     for (int i = 0; i < wsmenu.getItemCount(); i++)
315     {
316       JMenuItem item = wsmenu.getItem(i);
317       if (item instanceof JCheckBoxMenuItem
318               && item.getText().equals(AAconToggle))
319       {
320         _aaConEnabled = (JCheckBoxMenuItem) item;
321       }
322     }
323     // is there an aaCon worker already present - if so, set it to use the
324     // given service handle
325     {
326       List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
327               .getCalcManager()
328               .getRegisteredWorkersOfClass(AAConClient.class);
329       if (aaconClient != null && aaconClient.size() > 0)
330       {
331         AAConClient worker = (AAConClient) aaconClient.get(0);
332         if (!worker.service.hosturl.equals(service.hosturl))
333         {
334           // javax.swing.SwingUtilities.invokeLater(new Runnable()
335           {
336             // @Override
337             // public void run()
338             {
339               removeCurrentAAConWorkerFor(alignFrame);
340               buildCurrentAAConWorkerFor(alignFrame, service);
341             }
342           }// );
343         }
344       }
345     }
346
347     // is there a service already registered ? there shouldn't be if we are
348     // being called correctly
349     if (_aaConEnabled == null)
350     {
351       final JCheckBoxMenuItem aaConEnabled = new JCheckBoxMenuItem(
352               AAconToggle);
353       wsmenu.addMenuListener(new MenuListener()
354       {
355
356         @Override
357         public void menuSelected(MenuEvent arg0)
358         {
359           wsmenu.setEnabled(!alignFrame.getViewport().getAlignment()
360                   .isNucleotide());
361           List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
362                   .getCalcManager()
363                   .getRegisteredWorkersOfClass(AAConClient.class);
364           if (aaconClient != null && aaconClient.size() > 0)
365           {
366             aaConEnabled.setSelected(true);
367           }
368           else
369           {
370             aaConEnabled.setSelected(false);
371           }
372         }
373
374         @Override
375         public void menuDeselected(MenuEvent arg0)
376         {
377           // TODO Auto-generated method stub
378
379         }
380
381         @Override
382         public void menuCanceled(MenuEvent arg0)
383         {
384           // TODO Auto-generated method stub
385
386         }
387       });
388       aaConEnabled.setToolTipText("<html><p>"
389               + JvSwingUtils.wrapTooltip(AAconToggleTooltip + "</p>")
390               + "</html>");
391       aaConEnabled.addActionListener(new ActionListener()
392       {
393         @Override
394         public void actionPerformed(ActionEvent arg0)
395         {
396           List<AlignCalcWorkerI> aaconClient = alignFrame.getViewport()
397                   .getCalcManager()
398                   .getRegisteredWorkersOfClass(AAConClient.class);
399           if (aaconClient != null && aaconClient.size() > 0)
400           {
401             removeCurrentAAConWorkerFor(alignFrame);
402           }
403           else
404           {
405             buildCurrentAAConWorkerFor(alignFrame);
406
407           }
408         }
409
410       });
411       wsmenu.add(aaConEnabled);
412       JMenuItem modifyParams = new JMenuItem(AAeditSettings);
413       modifyParams.setToolTipText("<html><p>"
414               + JvSwingUtils.wrapTooltip(AAeditSettingsTooltip + "</p>")
415               + "</html>");
416       modifyParams.addActionListener(new ActionListener()
417       {
418
419         @Override
420         public void actionPerformed(ActionEvent arg0)
421         {
422           showAAConAnnotationSettingsFor(alignFrame);
423         }
424       });
425       wsmenu.add(modifyParams);
426
427     }
428   }
429
430   private static void showAAConAnnotationSettingsFor(AlignFrame alignFrame)
431   {
432     /*
433      * preferred settings Whether AACon is automatically recalculated Which
434      * AACon server to use What parameters to use
435      */
436     // could actually do a class search for this too
437     AAConSettings fave = (AAConSettings) alignFrame.getViewport()
438             .getCalcIdSettingsFor(AAConCalcId);
439     if (fave == null)
440     {
441       fave = createDefaultAAConSettings();
442     }
443     new SequenceAnnotationWSClient(fave, alignFrame, true);
444
445   }
446
447   private static void buildCurrentAAConWorkerFor(AlignFrame alignFrame)
448   {
449     buildCurrentAAConWorkerFor(alignFrame, null);
450   }
451
452   private static void buildCurrentAAConWorkerFor(AlignFrame alignFrame,
453           Jws2Instance service)
454   {
455     /*
456      * preferred settings Whether AACon is automatically recalculated Which
457      * AACon server to use What parameters to use
458      */
459     AAConSettings fave = (AAConSettings) alignFrame.getViewport()
460             .getCalcIdSettingsFor(AAConCalcId);
461     if (fave == null)
462     {
463       fave = createDefaultAAConSettings(service);
464     }
465     else
466     {
467       if (service != null
468               && !fave.getService().hosturl.equals(service.hosturl))
469       {
470         Cache.log.debug("Changing AACon service to " + service.hosturl
471                 + " from " + fave.getService().hosturl);
472         fave.setService(service);
473       }
474     }
475     new SequenceAnnotationWSClient(fave, alignFrame, false);
476   }
477
478   private static AAConSettings createDefaultAAConSettings()
479   {
480     return createDefaultAAConSettings(null);
481   }
482
483   private static AAConSettings createDefaultAAConSettings(
484           Jws2Instance service)
485   {
486     if (service != null)
487     {
488       if (!service.serviceType.toString().equals(
489               compbio.ws.client.Services.AAConWS.toString()))
490       {
491         Cache.log
492                 .warn("Ignoring invalid preferred service for AACon calculations (service type was "
493                         + service.serviceType + ")");
494         service = null;
495       }
496       else
497       {
498         // check service is actually in the list of currently avaialable
499         // services
500         if (!Jws2Discoverer.getDiscoverer().getServices().contains(service))
501         {
502           // it isn't ..
503           service = null;
504         }
505       }
506     }
507     if (service == null)
508     {
509       // get the default service for AACon
510       service = Jws2Discoverer.getDiscoverer().getPreferredServiceFor(null,
511               compbio.ws.client.Services.AAConWS.toString());
512     }
513     if (service == null)
514     {
515       // TODO raise dialog box explaining error, and/or open the JABA
516       // preferences menu.
517       throw new Error("No AACon service found.");
518     }
519     return new AAConSettings(true, service, null, null);
520   }
521
522   private static void removeCurrentAAConWorkerFor(AlignFrame alignFrame)
523   {
524     alignFrame.getViewport().getCalcManager()
525             .removeRegisteredWorkersOfClass(AAConClient.class);
526   }
527 }