JAL-3878 Add multiple sequence operation.
[jalview.git] / src / jalview / ws2 / gui / AlignmentMenuBuilder.java
1 package jalview.ws2.gui;
2
3 import static java.lang.String.format;
4
5 import java.awt.event.MouseAdapter;
6 import java.awt.event.MouseEvent;
7 import java.util.Collections;
8 import java.util.List;
9 import java.util.Objects;
10 import java.util.concurrent.CompletionStage;
11 import javax.swing.JMenu;
12 import javax.swing.JMenuItem;
13 import javax.swing.ToolTipManager;
14
15 import jalview.datamodel.AlignmentView;
16 import jalview.gui.AlignFrame;
17 import jalview.gui.AlignViewport;
18 import jalview.gui.JvSwingUtils;
19 import jalview.gui.WebserviceInfo;
20 import jalview.gui.WsJobParameters;
21 import jalview.util.MessageManager;
22 import jalview.ws.params.ArgumentI;
23 import jalview.ws.params.ParamDatastoreI;
24 import jalview.ws.params.WsParamSetI;
25 import jalview.ws2.PollingTaskExecutor;
26 import jalview.ws2.operations.AlignmentOperation;
27 import jalview.ws2.operations.AlignmentWorker;
28
29 public class AlignmentMenuBuilder implements MenuEntryProviderI
30 {
31   AlignmentOperation operation;
32
33   public AlignmentMenuBuilder(AlignmentOperation operation)
34   {
35     this.operation = operation;
36   }
37
38   public void buildMenu(JMenu parent, AlignFrame frame)
39   {
40     if (operation.canSubmitGaps())
41     {
42       var alignSubmenu = new JMenu(operation.getName());
43       buildMenu(alignSubmenu, frame, false);
44       parent.add(alignSubmenu);
45       var realignSubmenu = new JMenu(MessageManager.formatMessage(
46           "label.realign_with_params", operation.getName()));
47       realignSubmenu.setToolTipText(MessageManager
48           .getString("label.align_sequences_to_existing_alignment"));
49       buildMenu(realignSubmenu, frame, true);
50       parent.add(realignSubmenu);
51     }
52     else
53     {
54       buildMenu(parent, frame, false);
55     }
56   }
57
58   protected void buildMenu(JMenu parent, AlignFrame frame,
59       boolean submitGaps)
60   {
61     final String action = submitGaps ? "Align" : "Realign";
62     final var calcName = operation.getName();
63
64     {
65       var item = new JMenuItem(MessageManager.formatMessage(
66           "label.calcname_with_default_settings", calcName));
67       item.setToolTipText(MessageManager
68           .formatMessage("label.action_with_default_settings", action));
69       item.addActionListener((event) -> {
70         final AlignmentView msa = frame.gatherSequencesForAlignment();
71         if (msa != null)
72         {
73           startWorker(frame, msa, Collections.emptyList(), submitGaps);
74         }
75       });
76       parent.add(item);
77     }
78
79     if (operation.hasParameters())
80     {
81       var item = new JMenuItem(
82           MessageManager.getString("label.edit_settings_and_run"));
83       item.setToolTipText(MessageManager.getString(
84           "label.view_and_change_parameters_before_alignment"));
85       item.addActionListener((event) -> {
86         AlignmentView msa = frame.gatherSequencesForAlignment();
87         if (msa != null)
88         {
89           openEditParamsDialog(operation.getParamStore(), null, null)
90               .thenAcceptAsync((arguments) -> {
91                 if (arguments != null)
92                 {
93                   startWorker(frame, msa, arguments, submitGaps);
94                 }
95               });
96         }
97       });
98       parent.add(item);
99     }
100
101     var presets = operation.getParamStore().getPresets();
102     if (presets != null && presets.size() > 0)
103     {
104       final var presetList = new JMenu(MessageManager
105           .formatMessage("label.run_with_preset_params", calcName));
106       final var showToolTipFor = ToolTipManager.sharedInstance()
107           .getDismissDelay();
108       for (final var preset : presets)
109       {
110         var item = new JMenuItem(preset.getName());
111         final int QUICK_TOOLTIP = 1500;
112         item.addMouseListener(new MouseAdapter()
113         {
114           @Override
115           public void mouseEntered(MouseEvent e)
116           {
117             ToolTipManager.sharedInstance().setDismissDelay(QUICK_TOOLTIP);
118           }
119
120           @Override
121           public void mouseExited(MouseEvent e)
122           {
123             ToolTipManager.sharedInstance().setDismissDelay(showToolTipFor);
124           }
125         });
126         String tooltip = JvSwingUtils.wrapTooltip(true,
127             format("<strong>%s</strong><br/>%s",
128                 MessageManager.getString(
129                     preset.isModifiable() ? "label.user_preset"
130                         : "label.service_preset"),
131                 preset.getDescription()));
132         item.setToolTipText(tooltip);
133         item.addActionListener((event) -> {
134           AlignmentView msa = frame.gatherSequencesForAlignment();
135           startWorker(frame, msa, preset.getArguments(), submitGaps);
136         });
137         presetList.add(item);
138       }
139       parent.add(presetList);
140     }
141   }
142
143   private CompletionStage<List<ArgumentI>> openEditParamsDialog(
144       ParamDatastoreI paramStore, WsParamSetI preset,
145       List<ArgumentI> arguments)
146   {
147     WsJobParameters jobParams;
148     if (preset == null && arguments != null && arguments.size() > 0)
149       jobParams = new WsJobParameters(paramStore, preset, arguments);
150     else
151       jobParams = new WsJobParameters(paramStore, preset, null);
152     if (preset != null)
153     {
154       jobParams.setName(MessageManager.getString(
155           "label.adjusting_parameters_for_calculation"));
156     }
157     var stage = jobParams.showRunDialog();
158     return stage.thenApply((startJob) -> {
159       if (startJob)
160       {
161         if (jobParams.getPreset() == null)
162         {
163           return jobParams.getJobParams();
164         }
165         else
166         {
167           return jobParams.getPreset().getArguments();
168         }
169       }
170       else
171       {
172         return null;
173       }
174     });
175   }
176
177   private void startWorker(AlignFrame frame, AlignmentView msa,
178       List<ArgumentI> arguments, boolean submitGaps)
179   {
180     AlignViewport viewport = frame.getViewport();
181     PollingTaskExecutor executor = frame.getViewport().getWSExecutor();
182     if (msa != null)
183     {
184
185       String panelInfo = String.format("%s using service hosted at %s%n%s",
186           operation.getName(), operation.getHostName(),
187           Objects.requireNonNullElse(operation.getDescription(), ""));
188       var wsInfo = new WebserviceInfo(operation.getName(), panelInfo, false);
189
190       final String alnTitle = frame.getTitle();
191       AlignmentWorker worker = new AlignmentWorker(operation, msa,
192           arguments, submitGaps, true, viewport);
193       String outputHeader = String.format("%s of %s%nJob details%n",
194           submitGaps ? "Re-alignment" : "Alignment", alnTitle);
195
196       var awl = new AlignmentProgressUpdater(worker, wsInfo, frame,
197           outputHeader);
198       worker.setResultConsumer(awl);
199       worker.addListener(awl);
200
201       executor.submit(worker);
202     }
203
204   }
205
206 }