Merge branch 'alpha/origin_2022_JAL-3066_Jalview_212_slivka-integration' into spike...
[jalview.git] / src / jalview / ws / jws2 / MsaWSClient.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.ws.jws2;
22
23 import jalview.datamodel.AlignmentI;
24 import jalview.datamodel.AlignmentView;
25 import jalview.gui.AlignFrame;
26 import jalview.gui.Desktop;
27 import jalview.gui.JvOptionPane;
28 import jalview.gui.JvSwingUtils;
29 import jalview.util.MessageManager;
30 import jalview.ws.WSMenuEntryProviderI;
31 import jalview.ws.api.JalviewServiceEndpointProviderI;
32 import jalview.ws.api.MultipleSequenceAlignmentI;
33 import jalview.ws.api.ServiceWithParameters;
34 import jalview.ws.gui.MsaWSThread;
35 import jalview.ws.params.ArgumentI;
36 import jalview.ws.params.WsParamSetI;
37
38 import java.awt.event.ActionEvent;
39 import java.awt.event.ActionListener;
40 import java.awt.event.MouseAdapter;
41 import java.awt.event.MouseEvent;
42 import java.util.List;
43 import java.util.Locale;
44
45 import javax.swing.JMenu;
46 import javax.swing.JMenuItem;
47 import javax.swing.ToolTipManager;
48
49
50 /**
51  * MsaWSClient
52  * 
53  * Instantiates web service menu items for multiple alignment services, and
54  * holds logic for constructing a web service thread.
55  * 
56  * TODO remove dependency on Jws2Client methods for creating AACon service UI
57  * elements.
58  * 
59  * @author Jim Procter et al
60  * @version $Revision$
61  */
62 public class MsaWSClient extends Jws2Client implements WSMenuEntryProviderI
63 {
64   /**
65    * server is a proxy class implementing the core methods for submitting,
66    * monitoring and retrieving results from a multiple sequence alignment
67    * service
68    */
69   MultipleSequenceAlignmentI server;
70
71   public MsaWSClient(ServiceWithParameters sh, String altitle,
72           jalview.datamodel.AlignmentView msa, boolean submitGaps,
73           boolean preserveOrder, AlignmentI seqdataset,
74           AlignFrame _alignFrame)
75   {
76     this(sh, null, null, false, altitle, msa, submitGaps, preserveOrder,
77             seqdataset, _alignFrame);
78     // TODO Auto-generated constructor stub
79   }
80
81   public MsaWSClient(ServiceWithParameters sh, WsParamSetI preset,
82           String altitle,
83           jalview.datamodel.AlignmentView msa, boolean submitGaps,
84           boolean preserveOrder, AlignmentI seqdataset,
85           AlignFrame _alignFrame)
86   {
87     this(sh, preset, null, false, altitle, msa, submitGaps, preserveOrder,
88             seqdataset, _alignFrame);
89     // TODO Auto-generated constructor stub
90   }
91
92   /**
93    * Creates a new MsaWSClient object that uses a service given by an externally
94    * retrieved ServiceHandle
95    * 
96    * @param sh
97    *          service handle of type AbstractName(MsaWS)
98    * @param altitle
99    *          DOCUMENT ME!
100    * @param msa
101    *          DOCUMENT ME!
102    * @param submitGaps
103    *          DOCUMENT ME!
104    * @param preserveOrder
105    *          DOCUMENT ME!
106    */
107
108   public MsaWSClient(ServiceWithParameters sh, WsParamSetI preset,
109           List<ArgumentI> arguments, boolean editParams, String altitle,
110           jalview.datamodel.AlignmentView msa, boolean submitGaps,
111           boolean preserveOrder, AlignmentI seqdataset,
112           AlignFrame _alignFrame)
113   {
114     super(_alignFrame, preset, arguments);
115     processParams(sh, editParams).thenAccept((startJob) -> {
116       if (!startJob)
117         return;
118       
119       if (!(sh instanceof JalviewServiceEndpointProviderI
120               && ((JalviewServiceEndpointProviderI) sh)
121                       .getEndpoint() instanceof MultipleSequenceAlignmentI))
122       {
123         // redundant at mo - but may change
124         JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
125                 MessageManager.formatMessage(
126                         "label.service_called_is_not_msa_service",
127                         new String[]
128                         { sh.getName() }),
129                 MessageManager.getString("label.internal_jalview_error"),
130                 JvOptionPane.WARNING_MESSAGE);
131   
132         return;
133       }
134       serviceHandle = sh;
135       server = (MultipleSequenceAlignmentI) ((JalviewServiceEndpointProviderI) sh)
136               .getEndpoint();
137       if ((wsInfo = setWebService(sh, false)) == null)
138       {
139         JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), MessageManager
140                 .formatMessage("label.msa_service_is_unknown", new String[]
141                 { sh.getName() }),
142                 MessageManager.getString("label.internal_jalview_error"),
143                 JvOptionPane.WARNING_MESSAGE);
144   
145         return;
146       }
147   
148       startMsaWSClient(altitle, msa, submitGaps, preserveOrder, seqdataset);
149     });
150
151   }
152
153   public MsaWSClient()
154   {
155     super();
156     // add a class reference to the list
157   }
158
159   private void startMsaWSClient(String altitle, AlignmentView msa,
160           boolean submitGaps, boolean preserveOrder, AlignmentI seqdataset)
161   {
162     // if (!locateWebService())
163     // {
164     // return;
165     // }
166
167     wsInfo.setProgressText(((submitGaps) ? "Re-alignment" : "Alignment")
168             + " of " + altitle + "\nJob details\n");
169     String jobtitle = WebServiceName.toLowerCase(Locale.ROOT);
170     if (jobtitle.endsWith("alignment"))
171     {
172       if (submitGaps && (!jobtitle.endsWith("realignment")
173               || jobtitle.indexOf("profile") == -1))
174       {
175         int pos = jobtitle.indexOf("alignment");
176         jobtitle = WebServiceName.substring(0, pos) + "re-alignment of "
177                 + altitle;
178       }
179       else
180       {
181         jobtitle = WebServiceName + " of " + altitle;
182       }
183     }
184     else
185     {
186       jobtitle = WebServiceName + (submitGaps ? " re" : " ")
187               + "alignment of " + altitle;
188     }
189
190     MsaWSThread msathread = new MsaWSThread(server, preset, paramset, WsURL,
191             wsInfo, alignFrame, WebServiceName, jobtitle, msa, submitGaps,
192             preserveOrder, seqdataset);
193     if (msathread.hasValidInput())
194     {
195       wsInfo.setthisService(msathread);
196       wsInfo.setVisible(true);
197       msathread.start();
198     }
199     else
200     {
201       wsInfo.setVisible(false);
202       JvOptionPane.showMessageDialog(alignFrame,
203               MessageManager.getString("info.invalid_msa_input_mininfo"),
204               MessageManager.getString("info.invalid_msa_notenough"),
205               JvOptionPane.INFORMATION_MESSAGE);
206     }
207   }
208
209   protected String getServiceActionKey()
210   {
211     return "MsaWS";
212   }
213
214   protected String getServiceActionDescription()
215   {
216     return "Multiple Sequence Alignment";
217   }
218
219   /**
220    * look at ourselves and work out if we are a service that can take a profile
221    * and align to it
222    * 
223    * @return true if we can send gapped sequences to the alignment service
224    */
225   private boolean canSubmitGaps()
226   {
227     // TODO: query service or extract service handle props to check if we can
228     // realign
229     return (WebServiceName.indexOf("lustal") > -1); // cheat!
230   }
231
232   @Override
233   public void attachWSMenuEntry(JMenu rmsawsmenu,
234           final Jws2Instance service, final AlignFrame alignFrame)
235   {
236     if (registerAAConWSInstance(rmsawsmenu, service, alignFrame))
237     {
238       // Alignment dependent analysis calculation WS gui
239       return;
240     }
241     serviceHandle = service;
242     setWebService(service, true); // headless
243     attachWSMenuEntry(rmsawsmenu, alignFrame);
244   }
245
246   @Override
247   public void attachWSMenuEntry(JMenu wsmenu, AlignFrame alignFrame)
248   {
249     boolean finished = true, submitGaps = false;
250     /**
251      * temp variables holding msa service submenu or root service menu
252      */
253     JMenu msawsmenu = wsmenu;
254     JMenu rmsawsmenu = wsmenu;
255     String svcname = WebServiceName;
256     if (svcname.endsWith("WS"))
257     {
258       svcname = svcname.substring(0, svcname.length() - 2);
259     }
260     String calcName = svcname + " ";
261     if (canSubmitGaps())
262     {
263       msawsmenu = new JMenu(svcname);
264       rmsawsmenu.add(msawsmenu);
265       calcName = "";
266     }
267     boolean hasparams = serviceHandle.hasParameters();
268     ServiceWithParameters service = (ServiceWithParameters) serviceHandle;
269     do
270     {
271       String action = "Align ";
272       if (submitGaps == true)
273       {
274         action = "Realign ";
275         msawsmenu = new JMenu(MessageManager
276                 .formatMessage("label.realign_with_params", new String[]
277                 { svcname }));
278         msawsmenu.setToolTipText(MessageManager
279                 .getString("label.align_sequences_to_existing_alignment"));
280         rmsawsmenu.add(msawsmenu);
281       }
282       final boolean withGaps = submitGaps;
283
284       JMenuItem method = new JMenuItem(MessageManager.formatMessage(
285               "label.calcname_with_default_settings", new String[]
286               { calcName }));
287       method.setToolTipText(MessageManager.formatMessage(
288               "label.action_with_default_settings", new String[]
289               { action }));
290
291       method.addActionListener(new ActionListener()
292       {
293         @Override
294         public void actionPerformed(ActionEvent e)
295         {
296           AlignmentView msa = alignFrame.gatherSequencesForAlignment();
297
298           if (msa != null)
299           {
300             new MsaWSClient(service, alignFrame.getTitle(), msa, withGaps,
301                     true,
302                     alignFrame.getViewport().getAlignment().getDataset(),
303                     alignFrame);
304           }
305
306         }
307       });
308       msawsmenu.add(method);
309       if (hasparams)
310       {
311         // only add these menu options if the service has user-modifiable
312         // arguments
313         method = new JMenuItem(
314                 MessageManager.getString("label.edit_settings_and_run"));
315         method.setToolTipText(MessageManager.getString(
316                 "label.view_and_change_parameters_before_alignment"));
317
318         method.addActionListener(new ActionListener()
319         {
320           @Override
321           public void actionPerformed(ActionEvent e)
322           {
323             AlignmentView msa = alignFrame.gatherSequencesForAlignment();
324             if (msa != null)
325             {
326               new MsaWSClient(service, null, null, true,
327                       alignFrame.getTitle(), msa, withGaps, true,
328                       alignFrame.getViewport().getAlignment().getDataset(),
329                       alignFrame);
330             }
331
332           }
333         });
334         msawsmenu.add(method);
335         List<WsParamSetI> presets = service.getParamStore().getPresets();
336         if (presets != null && presets.size() > 0)
337         {
338           JMenu presetlist = new JMenu(MessageManager.formatMessage(
339                   "label.run_with_preset_params", new String[]
340                   { calcName }));
341
342           final int showToolTipFor = ToolTipManager.sharedInstance()
343                   .getDismissDelay();
344           for (final WsParamSetI preset : presets)
345           {
346             final JMenuItem methodR = new JMenuItem(preset.getName());
347             final int QUICK_TOOLTIP = 1500;
348             // JAL-1582 shorten tooltip display time in these menu items as
349             // they can obscure other options
350             methodR.addMouseListener(new MouseAdapter()
351             {
352               @Override
353               public void mouseEntered(MouseEvent e)
354               {
355                 ToolTipManager.sharedInstance()
356                         .setDismissDelay(QUICK_TOOLTIP);
357               }
358
359               @Override
360               public void mouseExited(MouseEvent e)
361               {
362                 ToolTipManager.sharedInstance()
363                         .setDismissDelay(showToolTipFor);
364               }
365
366             });
367             String tooltip = JvSwingUtils.wrapTooltip(true, "<strong>"
368                     + (preset.isModifiable()
369                             ? MessageManager.getString("label.user_preset")
370                             : MessageManager
371                                     .getString("label.service_preset"))
372                     + "</strong><br/>" + preset.getDescription());
373             methodR.setToolTipText(tooltip);
374             methodR.addActionListener(new ActionListener()
375             {
376               @Override
377               public void actionPerformed(ActionEvent e)
378               {
379                 AlignmentView msa = alignFrame
380                         .gatherSequencesForAlignment();
381
382                 if (msa != null)
383                 {
384                   MsaWSClient msac = new MsaWSClient(service, preset,
385                           alignFrame.getTitle(), msa, false, true,
386                           alignFrame.getViewport().getAlignment()
387                                   .getDataset(),
388                           alignFrame);
389                 }
390
391               }
392
393             });
394             presetlist.add(methodR);
395           }
396           msawsmenu.add(presetlist);
397         }
398       }
399       if (!submitGaps && canSubmitGaps())
400       {
401         submitGaps = true;
402         finished = false;
403       }
404       else
405       {
406         finished = true;
407       }
408     } while (!finished);
409   }
410 }