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